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
.components
.ServiceManager
;
19 import com
.intellij
.openapi
.diagnostic
.Logger
;
20 import com
.intellij
.openapi
.project
.Project
;
21 import com
.intellij
.psi
.*;
22 import com
.intellij
.psi
.codeStyle
.JavaCodeStyleManager
;
23 import com
.intellij
.psi
.codeStyle
.VariableKind
;
24 import com
.intellij
.psi
.impl
.source
.jsp
.jspJava
.JspMethodCall
;
25 import com
.intellij
.psi
.infos
.CandidateInfo
;
26 import com
.intellij
.psi
.infos
.MethodCandidateInfo
;
27 import com
.intellij
.psi
.search
.GlobalSearchScope
;
28 import com
.intellij
.psi
.search
.PsiShortNamesCache
;
29 import com
.intellij
.psi
.search
.searches
.DeepestSuperMethodsSearch
;
30 import com
.intellij
.psi
.tree
.IElementType
;
31 import com
.intellij
.psi
.util
.PropertyUtil
;
32 import com
.intellij
.psi
.util
.PsiTreeUtil
;
33 import com
.intellij
.psi
.util
.PsiUtil
;
34 import com
.intellij
.psi
.util
.TypeConversionUtil
;
35 import com
.intellij
.util
.ArrayUtil
;
36 import com
.intellij
.util
.NullableFunction
;
37 import com
.intellij
.util
.containers
.HashMap
;
38 import gnu
.trove
.THashSet
;
39 import org
.jetbrains
.annotations
.NonNls
;
40 import org
.jetbrains
.annotations
.NotNull
;
41 import org
.jetbrains
.annotations
.Nullable
;
48 public class ExpectedTypesProvider
{
49 private static final ExpectedTypeInfo VOID_EXPECTED
= new ExpectedTypeInfoImpl(PsiType
.VOID
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, 0, PsiType
.VOID
,
52 private static final Logger LOG
= Logger
.getInstance("#com.intellij.codeInsight.ExpectedTypesProvider");
53 public static ExpectedTypesProvider
getInstance(Project project
) {
54 return ServiceManager
.getService(project
, ExpectedTypesProvider
.class);
57 private static final ExpectedClassProvider ourGlobalScopeClassProvider
= new ExpectedClassProvider() {
58 public PsiField
[] findDeclaredFields(final PsiManager manager
, String name
) {
59 final PsiShortNamesCache cache
= JavaPsiFacade
.getInstance(manager
.getProject()).getShortNamesCache();
60 GlobalSearchScope scope
= GlobalSearchScope
.allScope(manager
.getProject());
61 return cache
.getFieldsByName(name
, scope
);
64 public PsiMethod
[] findDeclaredMethods(final PsiManager manager
, String name
) {
65 final PsiShortNamesCache cache
= JavaPsiFacade
.getInstance(manager
.getProject()).getShortNamesCache();
66 GlobalSearchScope scope
= GlobalSearchScope
.allScope(manager
.getProject());
67 return cache
.getMethodsByName(name
, scope
);
70 private static final PsiType
[] PRIMITIVE_TYPES
= {PsiType
.BYTE
, PsiType
.CHAR
, PsiType
.SHORT
, PsiType
.INT
, PsiType
.LONG
, PsiType
.FLOAT
, PsiType
.DOUBLE
};
72 public static ExpectedTypeInfo
createInfo(@NotNull PsiType type
, int kind
, PsiType defaultType
, TailType tailType
) {
73 return createInfoImpl(type
, kind
, defaultType
, tailType
);
76 private static ExpectedTypeInfoImpl
createInfoImpl(@NotNull PsiType type
, int kind
, PsiType defaultType
, TailType tailType
) {
78 while (type
instanceof PsiArrayType
) {
79 type
= ((PsiArrayType
) type
).getComponentType();
80 LOG
.assertTrue(defaultType
instanceof PsiArrayType
);
81 defaultType
= ((PsiArrayType
) defaultType
).getComponentType();
84 return new ExpectedTypeInfoImpl(type
, kind
, dims
, defaultType
, tailType
);
87 public ExpectedTypeInfo
[] getExpectedTypes(PsiExpression expr
, boolean forCompletion
) {
88 return getExpectedTypes(expr
, forCompletion
, false);
91 public ExpectedTypeInfo
[] getExpectedTypes(PsiExpression expr
, boolean forCompletion
, final boolean voidable
) {
92 return getExpectedTypes(expr
, forCompletion
, ourGlobalScopeClassProvider
, voidable
);
95 public ExpectedTypeInfo
[] getExpectedTypes(PsiExpression expr
,
96 boolean forCompletion
,
97 ExpectedClassProvider classProvider
) {
98 return getExpectedTypes(expr
, forCompletion
, classProvider
, false);
101 public ExpectedTypeInfo
[] getExpectedTypes(PsiExpression expr
, boolean forCompletion
, ExpectedClassProvider classProvider
,
102 final boolean voidable
) {
103 if (expr
== null) return null;
104 PsiElement parent
= expr
.getParent();
105 while (parent
instanceof PsiParenthesizedExpression
) {
106 expr
= (PsiExpression
)parent
;
107 parent
= parent
.getParent();
109 MyParentVisitor visitor
= new MyParentVisitor(expr
, forCompletion
, classProvider
, voidable
);
110 parent
.accept(visitor
);
111 return visitor
.getResult();
114 public static PsiType
[] processExpectedTypes(ExpectedTypeInfo
[] infos
,
115 final PsiTypeVisitor
<PsiType
> visitor
, Project project
) {
116 Set
<PsiType
> set
= new LinkedHashSet
<PsiType
>();
117 for (ExpectedTypeInfo info
: infos
) {
118 ExpectedTypeInfoImpl infoImpl
= (ExpectedTypeInfoImpl
)info
;
120 if (infoImpl
.getDefaultType() instanceof PsiClassType
&& infoImpl
.getDimCount() == 0) {
121 JavaResolveResult result
= ((PsiClassType
)infoImpl
.getDefaultType()).resolveGenerics();
122 PsiClass aClass
= (PsiClass
)result
.getElement();
123 if (aClass
instanceof PsiAnonymousClass
) {
124 processType(((PsiAnonymousClass
)aClass
).getBaseClassType(), visitor
, set
);
125 ((PsiAnonymousClass
)aClass
).getBaseClassType().accept(visitor
);
128 processType(infoImpl
.getDefaultType(), visitor
, set
);
132 processType(infoImpl
.getDefaultType(), visitor
, set
);
135 if (infoImpl
.kind
== ExpectedTypeInfo
.TYPE_OR_SUPERTYPE
) {
136 processAllSuperTypes(infoImpl
.getType(), infoImpl
.getDimCount(), visitor
, project
, set
);
138 else if (infoImpl
.getKind() == ExpectedTypeInfo
.TYPE_OR_SUBTYPE
) {
139 if (infoImpl
.getType() instanceof PsiPrimitiveType
&& infoImpl
.getDimCount() == 0) {
140 processPrimitiveTypeAndSubtypes((PsiPrimitiveType
)infoImpl
.getType(), visitor
, set
);
141 } //else too expensive to search
145 return set
.toArray(new PsiType
[set
.size()]);
148 private static void processType(@NotNull PsiType type
, PsiTypeVisitor
<PsiType
> visitor
, Set
<PsiType
> typeSet
) {
149 PsiType accepted
= type
.accept(visitor
);
150 if (accepted
!= null) typeSet
.add(accepted
);
153 public static void processPrimitiveTypeAndSubtypes(PsiPrimitiveType type
, PsiTypeVisitor
<PsiType
> visitor
, Set
<PsiType
> set
) {
154 if (type
.equals(PsiType
.BOOLEAN
) || type
.equals(PsiType
.VOID
) || type
.equals(PsiType
.NULL
)) return;
156 for (int i
= 0; ; i
++) {
157 final PsiType primitive
= PRIMITIVE_TYPES
[i
];
158 processType(primitive
, visitor
, set
);
159 if (primitive
.equals(type
)) return;
163 public static void processAllSuperTypes(PsiType type
, int dimCount
, PsiTypeVisitor
<PsiType
> visitor
, Project project
, Set
<PsiType
> set
) {
164 if (type
instanceof PsiPrimitiveType
) {
165 if (type
.equals(PsiType
.BOOLEAN
) || type
.equals(PsiType
.VOID
) || type
.equals(PsiType
.NULL
)) return;
167 Stack
<PsiType
> stack
= new Stack
<PsiType
>();
168 for (int i
= PRIMITIVE_TYPES
.length
- 1; !PRIMITIVE_TYPES
[i
].equals(type
); i
--) {
169 stack
.push(PRIMITIVE_TYPES
[i
]);
171 while(!stack
.empty()) {
172 processType(stack
.pop(), visitor
, set
);
176 PsiManager manager
= PsiManager
.getInstance(project
);
177 GlobalSearchScope resolveScope
= type
.getResolveScope();
178 if (resolveScope
== null) resolveScope
= GlobalSearchScope
.allScope(project
);
179 PsiClassType objectType
= PsiType
.getJavaLangObject(manager
, resolveScope
);
180 processType(objectType
, visitor
, set
);
182 if (type
instanceof PsiClassType
) {
183 PsiType
[] superTypes
= type
.getSuperTypes();
184 for (PsiType superType
: superTypes
) {
185 PsiType wrappedType
= superType
;
186 for (int j
= 0; j
< dimCount
; j
++) {
187 wrappedType
= wrappedType
.createArrayType();
189 processType(wrappedType
, visitor
, set
);
190 processAllSuperTypes(superType
, dimCount
, visitor
, project
, set
);
196 private class MyParentVisitor
extends JavaElementVisitor
{
197 private PsiExpression myExpr
;
198 private final boolean myForCompletion
;
199 private final ExpectedClassProvider myClassProvider
;
200 private boolean myVoidable
;
201 private ExpectedTypeInfo
[] myResult
= ExpectedTypeInfo
.EMPTY_ARRAY
;
202 @NonNls private static final String LENGTH_SYNTHETIC_ARRAY_FIELD
= "length";
204 private MyParentVisitor(PsiExpression expr
, boolean forCompletion
, ExpectedClassProvider classProvider
, boolean voidable
) {
206 myForCompletion
= forCompletion
;
207 myClassProvider
= classProvider
;
208 myVoidable
= voidable
;
211 public ExpectedTypeInfo
[] getResult() {
216 public void visitAnnotationMethod(final PsiAnnotationMethod method
) {
217 if (myExpr
== method
.getDefaultValue()) {
218 final PsiType type
= method
.getReturnType();
220 myResult
= new ExpectedTypeInfo
[]{createInfoImpl(type
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, type
, TailType
.SEMICOLON
)};
226 public void visitReferenceExpression(PsiReferenceExpression expression
) {
227 if (myForCompletion
) {
228 final MyParentVisitor visitor
= new MyParentVisitor(expression
, myForCompletion
, myClassProvider
, myVoidable
);
229 expression
.getParent().accept(visitor
);
230 myResult
= visitor
.getResult();
234 String referenceName
= expression
.getReferenceName();
235 if (referenceName
!= null) {
236 final PsiElement parent
= expression
.getParent();
237 if (parent
instanceof PsiMethodCallExpression
) {
238 myResult
= findClassesWithDeclaredMethod((PsiMethodCallExpression
)parent
, myForCompletion
);
240 else if (parent
instanceof PsiReferenceExpression
|| parent
instanceof PsiVariable
||
241 parent
instanceof PsiExpression
) {
242 if (LENGTH_SYNTHETIC_ARRAY_FIELD
.equals(referenceName
)) {
243 myResult
= anyArrayType();
246 myResult
= findClassesWithDeclaredField(expression
);
253 public void visitExpressionStatement(PsiExpressionStatement statement
) {
255 myResult
= new ExpectedTypeInfo
[]{VOID_EXPECTED
};
259 @Override public void visitMethodCallExpression(PsiMethodCallExpression expression
) {
260 myExpr
= (PsiExpression
)myExpr
.getParent();
261 expression
.getParent().accept(this);
264 @Override public void visitAnnotationArrayInitializer(PsiArrayInitializerMemberValue initializer
) {
265 final PsiType type
= getAnnotationMethodType((PsiNameValuePair
)initializer
.getParent());
266 if (type
instanceof PsiArrayType
) {
267 myResult
= new ExpectedTypeInfo
[]{createInfoImpl(((PsiArrayType
)type
).getComponentType(), ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, type
, TailType
.UNKNOWN
)};
271 @Override public void visitNameValuePair(PsiNameValuePair pair
) {
272 final PsiType type
= getAnnotationMethodType(pair
);
273 if (type
== null) return;
274 final ExpectedTypeInfoImpl info
= createInfoImpl(type
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, type
, TailType
.UNKNOWN
);
275 if (type
instanceof PsiArrayType
) {
276 myResult
= new ExpectedTypeInfo
[]{info
, createInfoImpl(((PsiArrayType
)type
).getComponentType(), ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, type
, TailType
.UNKNOWN
)};
278 myResult
= new ExpectedTypeInfo
[] {info
};
283 private PsiType
getAnnotationMethodType(final PsiNameValuePair pair
) {
284 final PsiReference reference
= pair
.getReference();
285 if (reference
!= null) {
286 final PsiElement method
= reference
.resolve();
287 if (method
instanceof PsiMethod
) {
288 return ((PsiMethod
)method
).getReturnType();
294 @Override public void visitReturnStatement(PsiReturnStatement statement
) {
295 PsiMethod scopeMethod
= PsiTreeUtil
.getParentOfType(statement
, PsiMethod
.class);
296 if (scopeMethod
!= null) {
297 PsiType type
= scopeMethod
.getReturnType();
299 ExpectedTypeInfoImpl info
= createInfoImpl(type
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, type
,
301 if (PropertyUtil
.isSimplePropertyAccessor(scopeMethod
)) {
302 info
.expectedName
= PropertyUtil
.getPropertyName(scopeMethod
);
305 myResult
= new ExpectedTypeInfo
[]{info
};
308 myResult
= ExpectedTypeInfo
.EMPTY_ARRAY
;
313 @Override public void visitIfStatement(PsiIfStatement statement
) {
314 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.BOOLEAN
, ExpectedTypeInfo
.TYPE_STRICTLY
,
315 PsiType
.BOOLEAN
, TailTypes
.IF_RPARENTH
);
316 myResult
= new ExpectedTypeInfo
[]{info
};
319 @Override public void visitWhileStatement(PsiWhileStatement statement
) {
320 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.BOOLEAN
, ExpectedTypeInfo
.TYPE_STRICTLY
,
321 PsiType
.BOOLEAN
, TailTypes
.WHILE_RPARENTH
);
322 myResult
= new ExpectedTypeInfo
[]{info
};
325 @Override public void visitDoWhileStatement(PsiDoWhileStatement statement
) {
326 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.BOOLEAN
, ExpectedTypeInfo
.TYPE_STRICTLY
,
327 PsiType
.BOOLEAN
, TailTypes
.WHILE_RPARENTH
);
328 myResult
= new ExpectedTypeInfo
[]{info
};
331 @Override public void visitForStatement(PsiForStatement statement
) {
332 if (myExpr
.equals(statement
.getCondition())) {
333 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.BOOLEAN
, ExpectedTypeInfo
.TYPE_STRICTLY
,
334 PsiType
.BOOLEAN
, TailType
.SEMICOLON
);
335 myResult
= new ExpectedTypeInfo
[]{info
};
340 public void visitAssertStatement(PsiAssertStatement statement
) {
341 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.BOOLEAN
, ExpectedTypeInfo
.TYPE_STRICTLY
,
342 PsiType
.BOOLEAN
, TailType
.SEMICOLON
);
343 myResult
= new ExpectedTypeInfo
[]{info
};
346 @Override public void visitForeachStatement(PsiForeachStatement statement
) {
347 if (myExpr
.equals(statement
.getIteratedValue())) {
348 PsiType type
= statement
.getIterationParameter().getType();
350 PsiType arrayType
= type
.createArrayType();
351 ExpectedTypeInfoImpl info1
= createInfoImpl(arrayType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
352 arrayType
, TailType
.NONE
);
354 PsiManager manager
= statement
.getManager();
355 PsiElementFactory factory
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory();
356 PsiClass iterableClass
=
357 JavaPsiFacade
.getInstance(manager
.getProject()).findClass("java.lang.Iterable", statement
.getResolveScope());
358 if (iterableClass
== null || iterableClass
.getTypeParameters().length
!= 1) {
359 myResult
= new ExpectedTypeInfo
[]{info1
};
361 Map
<PsiTypeParameter
, PsiType
> map
= new HashMap
<PsiTypeParameter
, PsiType
>();
362 map
.put(iterableClass
.getTypeParameters()[0], PsiWildcardType
.createExtends(manager
, type
));
363 PsiSubstitutor substitutor
= factory
.createSubstitutor(map
);
364 PsiType iterableType
= factory
.createType(iterableClass
, substitutor
);
365 ExpectedTypeInfoImpl info2
= createInfoImpl(iterableType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
366 iterableType
, TailType
.NONE
);
368 myResult
= new ExpectedTypeInfo
[]{info1
, info2
};
373 @Override public void visitSwitchStatement(PsiSwitchStatement statement
) {
374 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.LONG
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, PsiType
.INT
,
376 if (!PsiUtil
.isLanguageLevel5OrHigher(statement
)) {
377 myResult
= new ExpectedTypeInfo
[]{info
};
381 PsiManager manager
= statement
.getManager();
382 PsiClassType enumType
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory().createTypeByFQClassName("java.lang.Enum", statement
.getResolveScope());
383 ExpectedTypeInfoImpl enumInfo
= createInfoImpl(enumType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, enumType
, TailType
.NONE
);
384 myResult
= new ExpectedTypeInfo
[] {info
, enumInfo
};
388 public void visitSwitchLabelStatement(final PsiSwitchLabelStatement statement
) {
389 final PsiSwitchStatement switchStatement
= statement
.getEnclosingSwitchStatement();
390 if (switchStatement
!= null) {
391 final PsiExpression expression
= switchStatement
.getExpression();
392 if (expression
!= null) {
393 final PsiType type
= expression
.getType();
395 myResult
= new ExpectedTypeInfo
[]{createInfoImpl(type
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, type
, TailType
.CASE_COLON
)};
401 @Override public void visitSynchronizedStatement(PsiSynchronizedStatement statement
) {
402 PsiElementFactory factory
= JavaPsiFacade
.getInstance(statement
.getProject()).getElementFactory();
403 PsiType objectType
= factory
.createTypeByFQClassName("java.lang.Object", myExpr
.getResolveScope());
404 myResult
= new ExpectedTypeInfo
[]{createInfoImpl(objectType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, objectType
, TailType
.NONE
)};
407 @Override public void visitVariable(PsiVariable variable
) {
408 PsiType type
= variable
.getType();
409 ExpectedTypeInfoImpl info
= createInfoImpl(type
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, type
,
411 info
.expectedName
= getPropertyName(variable
);
412 myResult
= new ExpectedTypeInfo
[]{info
};
415 @Override public void visitAssignmentExpression(PsiAssignmentExpression assignment
) {
416 if (myExpr
.equals(assignment
.getRExpression())) {
417 PsiExpression lExpr
= assignment
.getLExpression();
418 PsiType type
= lExpr
.getType();
420 TailType tailType
= getAssignmentRValueTailType(assignment
);
421 ExpectedTypeInfoImpl info
= createInfoImpl(type
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, type
, tailType
);
422 if (lExpr
instanceof PsiReferenceExpression
) {
423 PsiElement refElement
= ((PsiReferenceExpression
)lExpr
).resolve();
424 if (refElement
instanceof PsiVariable
) {
425 info
.expectedName
= getPropertyName((PsiVariable
)refElement
);
428 myResult
= new ExpectedTypeInfo
[]{info
};
431 myResult
= ExpectedTypeInfo
.EMPTY_ARRAY
;
435 if (myForCompletion
) {
436 myExpr
= (PsiExpression
)myExpr
.getParent();
437 assignment
.getParent().accept(this);
441 PsiExpression rExpr
= assignment
.getRExpression();
443 PsiType type
= rExpr
.getType();
445 if (type
instanceof PsiClassType
) {
446 final PsiClass resolved
= ((PsiClassType
)type
).resolve();
447 if (resolved
instanceof PsiAnonymousClass
) {
448 type
= ((PsiAnonymousClass
)resolved
).getBaseClassType();
451 ExpectedTypeInfoImpl info
= createInfoImpl(type
, ExpectedTypeInfo
.TYPE_OR_SUPERTYPE
, type
,
453 myResult
= new ExpectedTypeInfo
[]{info
};
457 myResult
= ExpectedTypeInfo
.EMPTY_ARRAY
;
461 private TailType
getAssignmentRValueTailType(PsiAssignmentExpression assignment
) {
462 if (assignment
.getParent() instanceof PsiExpressionStatement
) {
463 if (!(assignment
.getParent().getParent() instanceof PsiForStatement
)) {
464 return TailType
.SEMICOLON
;
467 PsiForStatement forStatement
= (PsiForStatement
)assignment
.getParent().getParent();
468 if (!assignment
.getParent().equals(forStatement
.getUpdate())) {
469 return TailType
.SEMICOLON
;
472 return TailType
.NONE
;
475 @Override public void visitExpressionList(PsiExpressionList list
) {
476 PsiResolveHelper helper
= JavaPsiFacade
.getInstance(list
.getProject()).getResolveHelper();
477 if (list
.getParent() instanceof PsiMethodCallExpression
) {
478 PsiMethodCallExpression methodCall
= (PsiMethodCallExpression
)list
.getParent();
479 CandidateInfo
[] candidates
= helper
.getReferencedMethodCandidates(methodCall
, false);
480 myResult
= getExpectedArgumentTypesForMethodCall(candidates
, list
, myExpr
, myForCompletion
);
482 else if (list
.getParent() instanceof PsiEnumConstant
) {
483 getExpectedArgumentsTypesForEnumConstant((PsiEnumConstant
)list
.getParent(), helper
, list
);
485 else if (list
.getParent() instanceof PsiNewExpression
) {
486 getExpectedArgumentsTypesForNewExpression((PsiNewExpression
)list
.getParent(), helper
, list
);
488 else if (list
.getParent() instanceof PsiAnonymousClass
) {
489 getExpectedArgumentsTypesForNewExpression((PsiNewExpression
)list
.getParent().getParent(), helper
, list
);
493 private void getExpectedArgumentsTypesForEnumConstant(final PsiEnumConstant enumConstant
,
494 final PsiResolveHelper helper
,
495 final PsiExpressionList list
) {
496 final PsiClass aClass
= enumConstant
.getContainingClass();
497 if (aClass
!= null) {
498 LOG
.assertTrue(aClass
.isEnum());
499 getExpectedTypesForConstructorCall(aClass
, helper
, list
, PsiSubstitutor
.EMPTY
);
503 private void getExpectedArgumentsTypesForNewExpression(final PsiNewExpression newExpr
, final PsiResolveHelper helper
, final PsiExpressionList list
) {
504 PsiType newType
= newExpr
.getType();
505 if (newType
instanceof PsiClassType
) {
506 JavaResolveResult resolveResult
= PsiUtil
.resolveGenericsClassInType(newType
);
507 PsiClass newClass
= (PsiClass
)resolveResult
.getElement();
508 final PsiSubstitutor substitutor
;
509 if (newClass
instanceof PsiAnonymousClass
) {
510 final PsiAnonymousClass anonymous
= (PsiAnonymousClass
)newClass
;
511 newClass
= anonymous
.getBaseClassType().resolve();
512 if (newClass
== null) return;
514 substitutor
= TypeConversionUtil
.getSuperClassSubstitutor(newClass
, anonymous
, PsiSubstitutor
.EMPTY
);
515 } else if (newClass
!= null) {
516 substitutor
= resolveResult
.getSubstitutor();
521 getExpectedTypesForConstructorCall(newClass
, helper
, list
, substitutor
);
525 private void getExpectedTypesForConstructorCall(final PsiClass referencedClass
,
526 final PsiResolveHelper helper
,
527 final PsiExpressionList argumentList
,
528 final PsiSubstitutor substitutor
) {
529 List
<CandidateInfo
> array
= new ArrayList
<CandidateInfo
>();
530 PsiMethod
[] constructors
= referencedClass
.getConstructors();
531 for (PsiMethod constructor
: constructors
) {
532 if (helper
.isAccessible(constructor
, argumentList
, null)) {
533 array
.add(new MethodCandidateInfo(constructor
, substitutor
, false, false, argumentList
, null, argumentList
.getExpressionTypes(), null));
536 CandidateInfo
[] candidates
= array
.toArray(new CandidateInfo
[array
.size()]);
537 myResult
= getExpectedArgumentTypesForMethodCall(candidates
, argumentList
, myExpr
, myForCompletion
);
540 @Override public void visitBinaryExpression(PsiBinaryExpression expr
) {
542 PsiExpression op1
= expr
.getLOperand();
543 PsiExpression op2
= expr
.getROperand();
544 PsiJavaToken sign
= expr
.getOperationSign();
545 if (myForCompletion
&& op1
.equals(myExpr
)) {
546 final MyParentVisitor visitor
= new MyParentVisitor(expr
, myForCompletion
, myClassProvider
, myVoidable
);
547 myExpr
= (PsiExpression
)myExpr
.getParent();
548 expr
.getParent().accept(visitor
);
549 myResult
= visitor
.getResult();
550 if (!(expr
.getParent() instanceof PsiExpressionList
)) {
551 for (final ExpectedTypeInfo info
: myResult
) {
552 ((ExpectedTypeInfoImpl
)info
).myTailType
= TailType
.NONE
;
557 PsiExpression anotherExpr
= op1
.equals(myExpr
) ? op2
: op1
;
558 PsiType anotherType
= anotherExpr
!= null ? anotherExpr
.getType() : null;
559 PsiElementFactory factory
= JavaPsiFacade
.getInstance(expr
.getProject()).getElementFactory();
560 IElementType i
= sign
.getTokenType();
561 if (i
== JavaTokenType
.MINUS
||
562 i
== JavaTokenType
.ASTERISK
||
563 i
== JavaTokenType
.DIV
||
564 i
== JavaTokenType
.PERC
||
565 i
== JavaTokenType
.LT
||
566 i
== JavaTokenType
.GT
||
567 i
== JavaTokenType
.LE
||
568 i
== JavaTokenType
.GE
) {
569 if (anotherType
== null) {
570 myResult
= ExpectedTypeInfo
.EMPTY_ARRAY
;
573 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.DOUBLE
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
574 anotherType
, TailType
.NONE
);
575 myResult
= new ExpectedTypeInfo
[]{info
};
578 else if (i
== JavaTokenType
.PLUS
) {
579 if (anotherType
== null) {
580 myResult
= ExpectedTypeInfo
.EMPTY_ARRAY
;
583 if (anotherType
.equalsToText("java.lang.String")) {
584 PsiType objType
= PsiType
.getJavaLangObject(myExpr
.getManager(), myExpr
.getResolveScope());
585 ExpectedTypeInfo info
= createInfoImpl(objType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, anotherType
,
587 ExpectedTypeInfo info1
= createInfoImpl(PsiType
.DOUBLE
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
588 PsiType
.INT
, TailType
.NONE
);
589 PsiType booleanType
= PsiType
.BOOLEAN
;
590 ExpectedTypeInfo info2
= createInfoImpl(booleanType
, ExpectedTypeInfo
.TYPE_STRICTLY
, booleanType
,
592 myResult
= new ExpectedTypeInfo
[]{info
, info1
, info2
};
595 if (PsiType
.DOUBLE
.isAssignableFrom(anotherType
)) {
596 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.DOUBLE
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
597 anotherType
, TailType
.NONE
);
598 myResult
= new ExpectedTypeInfo
[]{info
};
603 else if (i
== JavaTokenType
.EQEQ
|| i
== JavaTokenType
.NE
) {
604 if (anotherType
== null) {
605 myResult
= ExpectedTypeInfo
.EMPTY_ARRAY
;
608 ExpectedTypeInfoImpl info
;
609 if (anotherType
instanceof PsiPrimitiveType
) {
610 if (PsiType
.BOOLEAN
.equals(anotherType
)) {
611 info
= createInfoImpl(anotherType
, ExpectedTypeInfo
.TYPE_STRICTLY
, anotherType
, TailType
.NONE
);
613 else if (PsiType
.NULL
.equals(anotherType
)) {
614 PsiType objectType
= factory
.createTypeByFQClassName("java.lang.Object", myExpr
.getResolveScope());
615 info
= createInfoImpl(objectType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, objectType
, TailType
.NONE
);
618 info
= createInfoImpl(PsiType
.DOUBLE
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, anotherType
, TailType
.NONE
);
622 info
= createInfoImpl(anotherType
, ExpectedTypeInfo
.TYPE_STRICTLY
, anotherType
, TailType
.NONE
);
625 if (anotherExpr
instanceof PsiReferenceExpression
) {
626 PsiElement refElement
= ((PsiReferenceExpression
)anotherExpr
).resolve();
627 if (refElement
instanceof PsiVariable
) {
628 info
.expectedName
= getPropertyName((PsiVariable
)refElement
);
632 myResult
= new ExpectedTypeInfo
[]{info
};
635 else if (i
== JavaTokenType
.LTLT
|| i
== JavaTokenType
.GTGT
|| i
== JavaTokenType
.GTGTGT
) {
636 if (anotherType
== null) {
637 myResult
= ExpectedTypeInfo
.EMPTY_ARRAY
;
640 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.DOUBLE
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
641 anotherType
, TailType
.NONE
);
642 myResult
= new ExpectedTypeInfo
[]{info
};
645 else if (i
== JavaTokenType
.OROR
|| i
== JavaTokenType
.ANDAND
) {
646 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.BOOLEAN
, ExpectedTypeInfo
.TYPE_STRICTLY
,
647 PsiType
.BOOLEAN
, TailType
.NONE
);
648 myResult
= new ExpectedTypeInfo
[]{info
};
650 else if (i
== JavaTokenType
.OR
|| i
== JavaTokenType
.XOR
|| i
== JavaTokenType
.AND
) {
651 if (anotherType
== null) {
652 myResult
= ExpectedTypeInfo
.EMPTY_ARRAY
;
655 ExpectedTypeInfoImpl info
;
656 if (PsiType
.BOOLEAN
.equals(anotherType
)) {
657 info
= createInfoImpl(anotherType
, ExpectedTypeInfo
.TYPE_STRICTLY
, anotherType
, TailType
.NONE
);
660 info
= createInfoImpl(PsiType
.LONG
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, anotherType
, TailType
.NONE
);
662 myResult
= new ExpectedTypeInfo
[]{info
};
667 @Override public void visitPrefixExpression(PsiPrefixExpression expr
) {
668 PsiJavaToken sign
= expr
.getOperationSign();
669 IElementType i
= sign
.getTokenType();
670 final TailType tailType
= expr
.getParent() instanceof PsiAssignmentExpression
&& ((PsiAssignmentExpression
) expr
.getParent()).getRExpression() == expr ?
671 getAssignmentRValueTailType((PsiAssignmentExpression
) expr
.getParent()) :
673 if (i
== JavaTokenType
.PLUSPLUS
|| i
== JavaTokenType
.MINUSMINUS
|| i
== JavaTokenType
.TILDE
) {
674 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.LONG
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
675 PsiType
.INT
, tailType
);
676 myResult
= new ExpectedTypeInfo
[]{info
};
678 else if (i
== JavaTokenType
.PLUS
|| i
== JavaTokenType
.MINUS
) {
679 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.DOUBLE
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
680 PsiType
.INT
, tailType
);
681 myResult
= new ExpectedTypeInfo
[]{info
};
683 else if (i
== JavaTokenType
.EXCL
) {
684 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.BOOLEAN
, ExpectedTypeInfo
.TYPE_STRICTLY
,
685 PsiType
.BOOLEAN
, tailType
);
686 myResult
= new ExpectedTypeInfo
[]{info
};
690 @Override public void visitPostfixExpression(PsiPostfixExpression expr
) {
691 if (myForCompletion
) return;
693 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.LONG
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
694 PsiType
.INT
, TailType
.NONE
);
695 myResult
= new ExpectedTypeInfo
[]{info
};
698 @Override public void visitArrayInitializerExpression(PsiArrayInitializerExpression expr
) {
699 PsiElement pparent
= expr
.getParent();
700 PsiType arrayType
= null;
701 if (pparent
instanceof PsiVariable
) {
702 arrayType
= ((PsiVariable
)pparent
).getType();
704 else if (pparent
instanceof PsiNewExpression
) {
705 arrayType
= ((PsiNewExpression
)pparent
).getType();
707 else if (pparent
instanceof PsiArrayInitializerExpression
) {
708 PsiType type
= ((PsiArrayInitializerExpression
)pparent
).getType();
709 if (type
instanceof PsiArrayType
) {
710 arrayType
= ((PsiArrayType
)type
).getComponentType();
714 if (arrayType
instanceof PsiArrayType
) {
715 PsiType componentType
= ((PsiArrayType
)arrayType
).getComponentType();
716 ExpectedTypeInfoImpl info
= createInfoImpl(componentType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
717 componentType
, TailType
.NONE
);
718 myResult
= new ExpectedTypeInfo
[]{info
};
722 @Override public void visitNewExpression(PsiNewExpression expression
) {
723 PsiExpression
[] arrayDimensions
= expression
.getArrayDimensions();
724 for (PsiExpression dimension
: arrayDimensions
) {
725 if (myExpr
.equals(dimension
)) {
726 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.INT
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
727 PsiType
.INT
, TailType
.NONE
);
728 myResult
= new ExpectedTypeInfo
[]{info
};
734 @Override public void visitArrayAccessExpression(PsiArrayAccessExpression expr
) {
735 if (myExpr
.equals(expr
.getIndexExpression())) {
736 ExpectedTypeInfoImpl info
= createInfoImpl(PsiType
.INT
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, PsiType
.INT
, TailType
.NONE
)
737 ; //todo: special tail type
738 myResult
= new ExpectedTypeInfo
[]{info
};
740 else if (myExpr
.equals(expr
.getArrayExpression())) {
741 if (myForCompletion
) {
742 myExpr
= (PsiExpression
)myExpr
.getParent();
743 expr
.getParent().accept(this);
747 PsiElement parent
= expr
.getParent();
748 MyParentVisitor visitor
= new MyParentVisitor(expr
, myForCompletion
, myClassProvider
, myVoidable
);
749 myExpr
= (PsiExpression
)myExpr
.getParent();
750 parent
.accept(visitor
);
751 ExpectedTypeInfo
[] componentTypeInfo
= visitor
.getResult();
752 if (componentTypeInfo
.length
== 0) {
753 myResult
= anyArrayType();
756 myResult
= new ExpectedTypeInfoImpl
[componentTypeInfo
.length
];
757 for (int i
= 0; i
< componentTypeInfo
.length
; i
++) {
758 ExpectedTypeInfo compInfo
= componentTypeInfo
[i
];
759 PsiType expectedArrayType
= compInfo
.getType().createArrayType();
760 myResult
[i
] = createInfoImpl(expectedArrayType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, expectedArrayType
, TailType
.NONE
);
766 @Override public void visitConditionalExpression(PsiConditionalExpression expr
) {
767 if (myExpr
.equals(expr
.getCondition())) {
768 if (myForCompletion
) {
770 myExpr
.getParent().accept(this);
774 ExpectedTypeInfo info
= createInfoImpl(PsiType
.BOOLEAN
, ExpectedTypeInfo
.TYPE_STRICTLY
,
775 PsiType
.BOOLEAN
, TailType
.NONE
);
776 myResult
= new ExpectedTypeInfo
[]{info
};
778 else if (myExpr
.equals(expr
.getThenExpression())) {
779 ExpectedTypeInfo
[] types
= getExpectedTypes(expr
, myForCompletion
);
781 for (ExpectedTypeInfo info
: types
) {
782 ExpectedTypeInfoImpl infoImpl
= (ExpectedTypeInfoImpl
)info
;
783 infoImpl
.setInsertExplicitTypeParams(true);
784 infoImpl
.myTailType
= TailType
.COND_EXPR_COLON
;
790 LOG
.assertTrue(myExpr
.equals(expr
.getElseExpression()));
791 myResult
= getExpectedTypes(expr
, myForCompletion
);
792 if (myResult
!= null) {
793 for (ExpectedTypeInfo info
: myResult
) {
794 ((ExpectedTypeInfoImpl
)info
).setInsertExplicitTypeParams(true);
801 @Override public void visitThrowStatement(PsiThrowStatement statement
) {
802 if (statement
.getException() == myExpr
) {
803 PsiManager manager
= statement
.getManager();
804 PsiType throwableType
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory().createTypeByFQClassName("java.lang.Throwable", myExpr
.getResolveScope());
805 PsiMember container
= PsiTreeUtil
.getParentOfType(statement
, PsiMethod
.class, PsiClass
.class);
806 PsiType
[] throwsTypes
= PsiType
.EMPTY_ARRAY
;
807 if (container
instanceof PsiMethod
) {
808 throwsTypes
= ((PsiMethod
)container
).getThrowsList().getReferencedTypes();
811 if (throwsTypes
.length
== 0) {
812 final PsiClassType exceptionType
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory().createTypeByFQClassName("java.lang.Exception", myExpr
.getResolveScope());
813 throwsTypes
= new PsiClassType
[]{exceptionType
};
816 ExpectedTypeInfo
[] infos
= new ExpectedTypeInfo
[throwsTypes
.length
];
817 for (int i
= 0; i
< infos
.length
; i
++) {
818 infos
[i
] = createInfoImpl(
819 myExpr
instanceof PsiTypeCastExpression
&& myForCompletion ?
822 ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
831 @Override public void visitCodeFragment(JavaCodeFragment codeFragment
) {
832 if (codeFragment
instanceof PsiExpressionCodeFragment
) {
833 final PsiType type
= ((PsiExpressionCodeFragment
)codeFragment
).getExpectedType();
835 myResult
= new ExpectedTypeInfo
[] {createInfoImpl(type
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, type
, TailType
.NONE
)};
840 private ExpectedTypeInfo
[] getExpectedArgumentTypesForMethodCall(CandidateInfo
[] methodCandidates
,
841 PsiExpressionList argumentList
,
842 PsiExpression argument
,
843 boolean forCompletion
) {
844 if (methodCandidates
.length
== 0) {
845 return ExpectedTypeInfo
.EMPTY_ARRAY
;
847 final PsiExpression
[] args
= argumentList
.getExpressions();
848 final int index
= ArrayUtil
.indexOf(args
, argument
);
849 LOG
.assertTrue(index
>= 0);
851 final PsiExpression
[] leftArgs
;
852 if (index
<= args
.length
- 1) {
853 leftArgs
= new PsiExpression
[index
];
854 System
.arraycopy(args
, 0, leftArgs
, 0, index
);
859 Set
<ExpectedTypeInfo
> array
= new LinkedHashSet
<ExpectedTypeInfo
>();
860 for (CandidateInfo candidateInfo
: methodCandidates
) {
861 PsiMethod method
= (PsiMethod
)candidateInfo
.getElement();
862 PsiSubstitutor substitutor
;
863 if (candidateInfo
instanceof MethodCandidateInfo
) {
864 final MethodCandidateInfo info
= (MethodCandidateInfo
)candidateInfo
;
865 substitutor
= info
.inferTypeArguments(forCompletion
);
866 if (!info
.isStaticsScopeCorrect() && method
!= null && !method
.hasModifierProperty(PsiModifier
.STATIC
)) continue;
869 substitutor
= candidateInfo
.getSubstitutor();
871 inferMethodCallArgumentTypes(argument
, forCompletion
, args
, index
, method
, substitutor
, array
);
873 if (leftArgs
!= null && candidateInfo
instanceof MethodCandidateInfo
) {
874 substitutor
= ((MethodCandidateInfo
)candidateInfo
).inferTypeArguments(forCompletion
, leftArgs
);
875 inferMethodCallArgumentTypes(argument
, forCompletion
, leftArgs
, index
, method
, substitutor
, array
);
879 // try to find some variants without considering previous argument PRIMITIVE_TYPES
880 if (forCompletion
&& array
.isEmpty()) {
881 for (CandidateInfo candidate
: methodCandidates
) {
882 PsiMethod method
= (PsiMethod
)candidate
.getElement();
883 PsiSubstitutor substitutor
= candidate
.getSubstitutor();
884 PsiParameter
[] parms
= method
.getParameterList().getParameters();
885 if (parms
.length
<= index
) continue;
886 PsiParameter parm
= parms
[index
];
887 PsiType parmType
= getParameterType(parm
, substitutor
);
888 TailType tailType
= getMethodArgumentTailType(argument
, index
, method
, substitutor
, parms
);
889 ExpectedTypeInfoImpl info
= createInfoImpl(parmType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, parmType
,
891 info
.expectedName
= getPropertyName(parm
);
892 info
.setCalledMethod(method
);
897 return array
.toArray(new ExpectedTypeInfo
[array
.size()]);
900 private TailType
getMethodArgumentTailType(final PsiExpression argument
, final int index
, final PsiMethod method
, final PsiSubstitutor substitutor
,
901 final PsiParameter
[] parms
) {
902 if (index
>= parms
.length
) {
903 return TailType
.NONE
;
905 if (index
== parms
.length
- 1) {
906 //myTailType = CompletionUtil.NONE_TAIL;
907 final PsiElement call
= argument
.getParent().getParent();
908 if (call
instanceof JspMethodCall
) return TailType
.NONE
;
910 PsiType returnType
= method
.getReturnType();
911 if (returnType
!= null) returnType
= substitutor
.substitute(returnType
);
912 return (PsiType
.VOID
.equals(returnType
) || returnType
== null) && call
.getParent() instanceof PsiStatement
913 ? TailTypes
.CALL_RPARENTH_SEMICOLON
914 : TailTypes
.CALL_RPARENTH
;
916 return TailType
.COMMA
;
919 private void inferMethodCallArgumentTypes(final PsiExpression argument
,
920 final boolean forCompletion
,
921 final PsiExpression
[] args
,
923 final PsiMethod method
, final PsiSubstitutor substitutor
, final Set
<ExpectedTypeInfo
> array
) {
924 PsiParameter
[] parameters
= method
.getParameterList().getParameters();
925 if (!forCompletion
&& parameters
.length
!= args
.length
) return;
926 if (parameters
.length
<= index
&& !method
.isVarArgs()) return;
928 for (int j
= 0; j
< index
; j
++) {
929 PsiType paramType
= getParameterType(parameters
[Math
.min(parameters
.length
- 1, j
)],
931 PsiType argType
= args
[j
].getType();
932 if (argType
!= null && !paramType
.isAssignableFrom(argType
)) return;
934 PsiParameter parameter
= parameters
[Math
.min(parameters
.length
- 1, index
)];
935 PsiType parameterType
= getParameterType(parameter
, substitutor
);
937 TailType tailType
= getMethodArgumentTailType(argument
, index
, method
, substitutor
, parameters
);
938 PsiType defaultType
= getDefautType(method
, substitutor
, parameterType
, argument
);
940 ExpectedTypeInfoImpl info
= createInfoImpl(parameterType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, defaultType
, tailType
);
941 info
.setInsertExplicitTypeParams(true);
942 info
.setCalledMethod(method
);
943 String propertyName
= getPropertyName(parameter
);
944 if (propertyName
!= null) info
.expectedName
= propertyName
;
947 if (index
== parameters
.length
- 1 && parameter
.isVarArgs()) {
948 //Then we may still want to call with array argument
949 final PsiArrayType arrayType
= parameterType
.createArrayType();
950 ExpectedTypeInfoImpl info1
= createInfoImpl(arrayType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, arrayType
, tailType
);
951 info1
.setInsertExplicitTypeParams(true);
952 info1
.setCalledMethod(method
);
953 info1
.expectedName
= propertyName
;
959 private PsiType
getTypeParameterValue(PsiClass rootClass
, PsiClass derivedClass
, PsiSubstitutor substitutor
, int index
) {
960 final PsiTypeParameter
[] typeParameters
= rootClass
.getTypeParameters();
961 if (typeParameters
.length
> index
) {
962 final PsiSubstitutor psiSubstitutor
= TypeConversionUtil
.getClassSubstitutor(rootClass
, derivedClass
, substitutor
);
963 if (psiSubstitutor
!= null) {
964 PsiType type
= psiSubstitutor
.substitute(typeParameters
[index
]);
965 if (type
!= null) return type
;
972 protected PsiType
checkMethod(PsiMethod method
, @NonNls String className
, NullableFunction
<PsiClass
,PsiType
> function
) {
973 final PsiClass containingClass
= method
.getContainingClass();
974 if (containingClass
== null) return null;
976 if (className
.equals(containingClass
.getQualifiedName())) {
977 return function
.fun(containingClass
);
979 for (final PsiMethod psiMethod
: DeepestSuperMethodsSearch
.search(method
).findAll()) {
980 final PsiClass rootClass
= psiMethod
.getContainingClass();
981 if (className
.equals(rootClass
.getQualifiedName())) {
982 return function
.fun(rootClass
);
989 private PsiType
getDefautType(final PsiMethod method
, final PsiSubstitutor substitutor
, final PsiType parameterType
,
990 final PsiExpression argumentList
) {
991 final PsiClass containingClass
= method
.getContainingClass();
992 if (containingClass
== null) return parameterType
;
994 @NonNls final String name
= method
.getName();
995 if ("contains".equals(name
) || "remove".equals(name
)) {
996 final PsiType type
= checkMethod(method
, CommonClassNames
.JAVA_UTIL_COLLECTION
, new NullableFunction
<PsiClass
, PsiType
>() {
997 public PsiType
fun(final PsiClass psiClass
) {
998 return getTypeParameterValue(psiClass
, containingClass
, substitutor
, 0);
1001 if (type
!= null) return type
;
1003 if ("containsKey".equals(name
) || "remove".equals(name
) || "get".equals(name
) || "containsValue".equals(name
)) {
1004 final PsiType type
= checkMethod(method
, CommonClassNames
.JAVA_UTIL_MAP
, new NullableFunction
<PsiClass
, PsiType
>() {
1005 public PsiType
fun(final PsiClass psiClass
) {
1006 return getTypeParameterValue(psiClass
, containingClass
, substitutor
, name
.equals("containsValue") ?
1 : 0);
1009 if (type
!= null) return type
;
1011 if ("equals".equals(name
)) {
1012 final PsiType type
= checkMethod(method
, CommonClassNames
.JAVA_LANG_OBJECT
, new NullableFunction
<PsiClass
, PsiType
>() {
1013 public PsiType
fun(final PsiClass psiClass
) {
1014 final PsiElement parent
= argumentList
.getParent().getParent();
1015 if (parent
instanceof PsiMethodCallExpression
) {
1016 final PsiMethodCallExpression expression
= (PsiMethodCallExpression
)parent
;
1017 final PsiExpression qualifierExpression
= expression
.getMethodExpression().getQualifierExpression();
1018 if (qualifierExpression
!= null) {
1019 return qualifierExpression
.getType();
1021 final PsiClass aClass
= PsiTreeUtil
.getContextOfType(parent
, PsiClass
.class, true);
1022 if (aClass
!= null) {
1023 return JavaPsiFacade
.getInstance(aClass
.getProject()).getElementFactory().createType(aClass
);
1029 if (type
!= null) return type
;
1031 return parameterType
;
1034 private PsiType
getParameterType(PsiParameter parameter
, PsiSubstitutor substitutor
) {
1035 PsiType type
= parameter
.getType();
1036 if (parameter
.isVarArgs()) {
1037 type
= ((PsiArrayType
)type
).getComponentType();
1039 PsiType parameterType
= substitutor
.substitute(type
);
1040 if (parameterType
instanceof PsiCapturedWildcardType
) {
1041 parameterType
= ((PsiCapturedWildcardType
)parameterType
).getWildcard();
1043 if (parameterType
instanceof PsiWildcardType
) {
1044 final PsiWildcardType psiWildcardType
= (PsiWildcardType
)parameterType
;
1045 if (psiWildcardType
.isExtends()) {
1046 final PsiType superBound
= psiWildcardType
.getBound();
1047 if (superBound
!= null) {
1048 parameterType
= superBound
;
1052 return parameterType
;
1056 private String
getPropertyName(PsiVariable variable
) {
1057 final String name
= variable
.getName();
1058 if (name
== null) return null;
1059 JavaCodeStyleManager codeStyleManager
= JavaCodeStyleManager
.getInstance(variable
.getProject());
1060 VariableKind variableKind
= codeStyleManager
.getVariableKind(variable
);
1061 return codeStyleManager
.variableNameToPropertyName(name
, variableKind
);
1064 private void addBaseType(Set
<ExpectedTypeInfo
> types
, PsiClassType type
, PsiMethod method
) {
1065 PsiType
[] supers
= type
.getSuperTypes();
1066 boolean addedSuper
= false;
1067 for (PsiType aSuper
: supers
) {
1068 PsiClassType superType
= (PsiClassType
)aSuper
;
1069 PsiClass superClass
= superType
.resolve();
1070 if (superClass
!= null) {
1071 if (superClass
.findMethodBySignature(method
, false) != null) {
1072 addBaseType(types
, superType
, method
);
1078 types
.add(createInfoImpl(type
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, type
, TailType
.DOT
));
1082 private ExpectedTypeInfo
[] anyArrayType() {
1083 PsiType objType
= PsiType
.getJavaLangObject(myExpr
.getManager(), myExpr
.getResolveScope()).createArrayType();
1084 ExpectedTypeInfo info
= createInfoImpl(objType
, ExpectedTypeInfo
.TYPE_OR_SUBTYPE
, objType
,
1086 ExpectedTypeInfo info1
= createInfoImpl(PsiType
.DOUBLE
.createArrayType(), ExpectedTypeInfo
.TYPE_OR_SUBTYPE
,
1087 PsiType
.INT
.createArrayType(), TailType
.NONE
);
1088 PsiType booleanType
= PsiType
.BOOLEAN
.createArrayType();
1089 ExpectedTypeInfo info2
= createInfoImpl(booleanType
, ExpectedTypeInfo
.TYPE_STRICTLY
, booleanType
,
1091 return new ExpectedTypeInfo
[]{info
, info1
, info2
};
1094 private ExpectedTypeInfo
[] findClassesWithDeclaredMethod(final PsiMethodCallExpression methodCallExpr
, final boolean forCompletion
) {
1095 final PsiReferenceExpression reference
= methodCallExpr
.getMethodExpression();
1096 final PsiManager manager
= methodCallExpr
.getManager();
1097 final JavaPsiFacade facade
= JavaPsiFacade
.getInstance(manager
.getProject());
1098 final PsiMethod
[] methods
= myClassProvider
.findDeclaredMethods(reference
.getManager(), reference
.getReferenceName());
1099 Set
<ExpectedTypeInfo
> types
= new THashSet
<ExpectedTypeInfo
>();
1100 for (PsiMethod method
: methods
) {
1101 final PsiClass aClass
= method
.getContainingClass();
1102 if (aClass
== null || !facade
.getResolveHelper().isAccessible(method
, reference
, aClass
)) continue;
1104 final PsiSubstitutor substitutor
= ExpectedTypeUtil
.inferSubstitutor(method
, methodCallExpr
, forCompletion
);
1105 final PsiClassType type
=
1106 substitutor
== null ? facade
.getElementFactory().createType(aClass
) : facade
.getElementFactory().createType(aClass
, substitutor
);
1108 if (method
.hasModifierProperty(PsiModifier
.STATIC
) ||
1109 method
.hasModifierProperty(PsiModifier
.FINAL
) ||
1110 method
.hasModifierProperty(PsiModifier
.PRIVATE
)) {
1111 types
.add(createInfoImpl(type
, ExpectedTypeInfo
.TYPE_STRICTLY
, type
, TailType
.DOT
));
1114 addBaseType(types
, type
, method
);
1118 return types
.toArray(new ExpectedTypeInfo
[types
.size()]);
1121 private ExpectedTypeInfo
[] findClassesWithDeclaredField(PsiReferenceExpression expression
) {
1122 final JavaPsiFacade facade
= JavaPsiFacade
.getInstance(expression
.getProject());
1123 PsiField
[] fields
= myClassProvider
.findDeclaredFields(expression
.getManager(), expression
.getReferenceName());
1124 List
<ExpectedTypeInfo
> types
= new ArrayList
<ExpectedTypeInfo
>();
1125 for (PsiField field
: fields
) {
1126 final PsiClass aClass
= field
.getContainingClass();
1127 if (aClass
== null || !facade
.getResolveHelper().isAccessible(field
, expression
, aClass
)) continue;
1129 final PsiType type
= facade
.getElementFactory().createType(aClass
);
1131 int kind
= field
.hasModifierProperty(PsiModifier
.STATIC
) ||
1132 field
.hasModifierProperty(PsiModifier
.FINAL
) ||
1133 field
.hasModifierProperty(PsiModifier
.PRIVATE
)
1134 ? ExpectedTypeInfo
.TYPE_STRICTLY
1135 : ExpectedTypeInfo
.TYPE_OR_SUBTYPE
;
1136 ExpectedTypeInfo info
= createInfoImpl(type
, kind
, type
, TailType
.DOT
);
1137 //Do not filter inheritors!
1140 return types
.toArray(new ExpectedTypeInfo
[types
.size()]);
1145 * Finds fields and methods of specified name whenever corresponding reference has been encountered.
1146 * By default searhes in the global scope (see ourGlobalScopeClassProvider), but caller can provide its own algorithm e.g. to narrow search scope
1148 public interface ExpectedClassProvider
{
1149 PsiField
[] findDeclaredFields(final PsiManager manager
, String name
);
1151 PsiMethod
[] findDeclaredMethods(final PsiManager manager
, String name
);