2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.codeInsight
;
18 import com
.intellij
.openapi
.diagnostic
.Logger
;
19 import com
.intellij
.psi
.*;
20 import com
.intellij
.psi
.util
.PsiUtil
;
21 import org
.jetbrains
.annotations
.Nullable
;
25 public class ExpectedTypeUtil
{
26 private static final Logger LOG
= Logger
.getInstance("#com.intellij.codeInsight.ExpectedTypeUtil");
28 public static ExpectedTypeInfo
[] intersect(List
<ExpectedTypeInfo
[]> typeInfos
) {
29 if (typeInfos
.isEmpty()) return ExpectedTypeInfo
.EMPTY_ARRAY
;
31 ExpectedTypeInfos result
= new ExpectedTypeInfos(typeInfos
.get(0));
32 ExpectedTypeInfos acc
= new ExpectedTypeInfos();
34 for (int i
= 1; i
< typeInfos
.size(); i
++) {
35 ExpectedTypeInfo
[] next
= typeInfos
.get(i
);
37 for (ExpectedTypeInfo info
: next
) {
38 for (Iterator
<ExpectedTypeInfo
> iterator
= result
.iterator(); iterator
.hasNext();) {
39 ExpectedTypeInfo
[] intersection
= iterator
.next().intersect(info
);
40 for (ExpectedTypeInfo aIntersection
: intersection
) {
41 acc
.addInfo(aIntersection
);
46 return ExpectedTypeInfo
.EMPTY_ARRAY
;
51 return result
.toArray();
54 private static class ExpectedTypeInfos
{
55 List
<ExpectedTypeInfo
> myInfos
;
57 public ExpectedTypeInfos() {
58 myInfos
= new ArrayList
<ExpectedTypeInfo
>();
61 public ExpectedTypeInfos(ExpectedTypeInfo
[] infos
) {
62 myInfos
= new ArrayList
<ExpectedTypeInfo
>(Arrays
.asList(infos
));
65 public void clear () { myInfos
.clear(); }
67 public void addInfo (ExpectedTypeInfo info
) {
68 for (Iterator
<ExpectedTypeInfo
> iterator
= myInfos
.iterator(); iterator
.hasNext();) {
69 ExpectedTypeInfo sub
= iterator
.next();
70 int cmp
= contains(sub
, info
);
79 public boolean isEmpty() {
80 return myInfos
.isEmpty();
83 public Iterator
<ExpectedTypeInfo
> iterator() {
84 return myInfos
.iterator();
87 public ExpectedTypeInfo
[] toArray() {
88 return myInfos
.toArray(new ExpectedTypeInfo
[myInfos
.size()]);
93 * @return <0 if info2 contains info1 (or they are equal)
94 * >0 if info1 contains info2
97 public static int contains(ExpectedTypeInfo info1
, ExpectedTypeInfo info2
) {
98 int kind1
= info1
.getKind();
99 int kind2
= info2
.getKind();
100 if (kind1
== kind2
) {
101 if (matchesStrictly(info1
.getType(), info2
)) return -1;
102 if (matchesStrictly(info2
.getType(), info1
)) return 1;
104 } else if (kind1
== ExpectedTypeInfo
.TYPE_STRICTLY
) {
105 return matches(info1
.getType(), info2
) ?
-1 : 0;
106 } else if (kind2
== ExpectedTypeInfo
.TYPE_STRICTLY
) {
107 return matches(info2
.getType(), info1
) ?
1 : 0;
112 private static boolean matchesStrictly (PsiType type
, ExpectedTypeInfo info
) {
113 if ((type
instanceof PsiPrimitiveType
) != (info
.getType() instanceof PsiPrimitiveType
)) return false;
114 return matches(type
, info
);
117 public static boolean matches (PsiType type
, ExpectedTypeInfo info
) {
118 PsiType infoType
= info
.getType();
119 switch (info
.getKind()) {
120 case ExpectedTypeInfo
.TYPE_STRICTLY
:
121 return type
.equals(infoType
);
122 case ExpectedTypeInfo
.TYPE_OR_SUBTYPE
:
123 return infoType
.isAssignableFrom(type
);
124 case ExpectedTypeInfo
.TYPE_OR_SUPERTYPE
:
125 return type
.isAssignableFrom(infoType
);
128 LOG
.error("Unexpected ExpectedInfo kind");
132 public static class ExpectedClassesFromSetProvider
implements ExpectedTypesProvider
.ExpectedClassProvider
{
133 private final Set
<PsiClass
> myOccurrenceClasses
;
135 public ExpectedClassesFromSetProvider(Set
<PsiClass
> occurrenceClasses
) {
136 myOccurrenceClasses
= occurrenceClasses
;
139 public PsiField
[] findDeclaredFields(final PsiManager manager
, String name
) {
140 List
<PsiField
> fields
= new ArrayList
<PsiField
>();
141 for (PsiClass aClass
: myOccurrenceClasses
) {
142 final PsiField field
= aClass
.findFieldByName(name
, true);
143 if (field
!= null) fields
.add(field
);
145 return fields
.toArray(new PsiField
[fields
.size()]);
148 public PsiMethod
[] findDeclaredMethods(final PsiManager manager
, String name
) {
149 List
<PsiMethod
> methods
= new ArrayList
<PsiMethod
>();
150 for (PsiClass aClass
: myOccurrenceClasses
) {
151 final PsiMethod
[] occMethod
= aClass
.findMethodsByName(name
, true);
152 methods
.addAll(Arrays
.asList(occMethod
));
154 return methods
.toArray(new PsiMethod
[methods
.size()]);
159 public static PsiSubstitutor
inferSubstitutor(final PsiMethod method
, final PsiMethodCallExpression callExpr
, final boolean forCompletion
) {
160 final PsiResolveHelper helper
= JavaPsiFacade
.getInstance(method
.getProject()).getResolveHelper();
161 final PsiParameter
[] parameters
= method
.getParameterList().getParameters();
162 PsiExpression
[] args
= callExpr
.getArgumentList().getExpressions();
163 PsiSubstitutor result
= PsiSubstitutor
.EMPTY
;
164 for (PsiTypeParameter typeParameter
: PsiUtil
.typeParametersIterable(method
.getContainingClass())) {
165 PsiType type
= helper
.inferTypeForMethodTypeParameter(typeParameter
, parameters
, args
, PsiSubstitutor
.EMPTY
, callExpr
.getParent(), forCompletion
);
166 if (PsiType
.NULL
.equals(type
)) return null;
167 result
= result
.put(typeParameter
, type
);