rename: remember 'Search for text occurrences' checkbox state (IDEA-21328)
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / ExpectedTypesProvider.java
blob3284d52ce5004c9e3d6721c64e45fc169b356072
1 /*
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;
43 import java.util.*;
45 /**
46 * @author ven
48 public class ExpectedTypesProvider {
49 private static final ExpectedTypeInfo VOID_EXPECTED = new ExpectedTypeInfoImpl(PsiType.VOID, ExpectedTypeInfo.TYPE_OR_SUBTYPE, 0, PsiType.VOID,
50 TailType.SEMICOLON);
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) {
77 int dims = 0;
78 while (type instanceof PsiArrayType) {
79 type = ((PsiArrayType) type).getComponentType();
80 LOG.assertTrue(defaultType instanceof PsiArrayType);
81 defaultType = ((PsiArrayType) defaultType).getComponentType();
82 dims++;
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);
127 else {
128 processType(infoImpl.getDefaultType(), visitor, set);
131 else {
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);
175 else{
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) {
205 myExpr = expr;
206 myForCompletion = forCompletion;
207 myClassProvider = classProvider;
208 myVoidable = voidable;
211 public ExpectedTypeInfo[] getResult() {
212 return myResult;
215 @Override
216 public void visitAnnotationMethod(final PsiAnnotationMethod method) {
217 if (myExpr == method.getDefaultValue()) {
218 final PsiType type = method.getReturnType();
219 if (type != null) {
220 myResult = new ExpectedTypeInfo[]{createInfoImpl(type, ExpectedTypeInfo.TYPE_OR_SUBTYPE, type, TailType.SEMICOLON)};
225 @Override
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();
231 return;
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();
245 else {
246 myResult = findClassesWithDeclaredField(expression);
252 @Override
253 public void visitExpressionStatement(PsiExpressionStatement statement) {
254 if (myVoidable) {
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)};
277 } else {
278 myResult = new ExpectedTypeInfo[] {info};
282 @Nullable
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();
291 return null;
294 @Override public void visitReturnStatement(PsiReturnStatement statement) {
295 PsiMethod scopeMethod = PsiTreeUtil.getParentOfType(statement, PsiMethod.class);
296 if (scopeMethod != null) {
297 PsiType type = scopeMethod.getReturnType();
298 if (type != null) {
299 ExpectedTypeInfoImpl info = createInfoImpl(type, ExpectedTypeInfo.TYPE_OR_SUBTYPE, type,
300 TailType.SEMICOLON);
301 if (PropertyUtil.isSimplePropertyAccessor(scopeMethod)) {
302 info.expectedName = PropertyUtil.getPropertyName(scopeMethod);
305 myResult = new ExpectedTypeInfo[]{info};
307 else {
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};
339 @Override
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};
360 } else {
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,
375 TailType.NONE);
376 if (!PsiUtil.isLanguageLevel5OrHigher(statement)) {
377 myResult = new ExpectedTypeInfo[]{info};
378 return;
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};
387 @Override
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();
394 if (type != null) {
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,
410 TailType.SEMICOLON);
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();
419 if (type != null) {
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};
430 else {
431 myResult = ExpectedTypeInfo.EMPTY_ARRAY;
434 else {
435 if (myForCompletion) {
436 myExpr = (PsiExpression)myExpr.getParent();
437 assignment.getParent().accept(this);
438 return;
441 PsiExpression rExpr = assignment.getRExpression();
442 if (rExpr != null) {
443 PsiType type = rExpr.getType();
444 if (type != null) {
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,
452 TailType.NONE);
453 myResult = new ExpectedTypeInfo[]{info};
454 return;
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();
518 else {
519 return;
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;
555 return;
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;
572 else {
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;
582 else {
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,
586 TailType.NONE);
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,
591 TailType.NONE);
592 myResult = new ExpectedTypeInfo[]{info, info1, info2};
594 else {
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;
607 else {
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);
617 else {
618 info = createInfoImpl(PsiType.DOUBLE, ExpectedTypeInfo.TYPE_OR_SUBTYPE, anotherType, TailType.NONE);
621 else {
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;
639 else {
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;
654 else {
655 ExpectedTypeInfoImpl info;
656 if (PsiType.BOOLEAN.equals(anotherType)) {
657 info = createInfoImpl(anotherType, ExpectedTypeInfo.TYPE_STRICTLY, anotherType, TailType.NONE);
659 else {
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()) :
672 TailType.NONE;
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};
729 return;
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);
744 return;
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();
755 else {
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) {
769 myExpr = expr;
770 myExpr.getParent().accept(this);
771 return;
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);
780 if (types != null) {
781 for (ExpectedTypeInfo info : types) {
782 ExpectedTypeInfoImpl infoImpl = (ExpectedTypeInfoImpl)info;
783 infoImpl.setInsertExplicitTypeParams(true);
784 infoImpl.myTailType = TailType.COND_EXPR_COLON;
787 myResult = types;
789 else {
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 ?
820 throwsTypes[i] :
821 throwableType,
822 ExpectedTypeInfo.TYPE_OR_SUBTYPE,
823 throwsTypes[i],
824 TailType.SEMICOLON
827 myResult = infos;
831 @Override public void visitCodeFragment(JavaCodeFragment codeFragment) {
832 if (codeFragment instanceof PsiExpressionCodeFragment) {
833 final PsiType type = ((PsiExpressionCodeFragment)codeFragment).getExpectedType();
834 if (type != null) {
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);
855 } else {
856 leftArgs = null;
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;
868 else {
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,
890 tailType);
891 info.expectedName = getPropertyName(parm);
892 info.setCalledMethod(method);
893 array.add(info);
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,
922 final int index,
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)],
930 substitutor);
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;
945 array.add(info);
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;
954 array.add(info1);
958 @Nullable
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;
968 return null;
971 @Nullable
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);
985 return null;
988 @Nullable
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);
1026 return null;
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;
1055 @Nullable
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);
1073 addedSuper = true;
1077 if (!addedSuper) {
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,
1085 TailType.NONE);
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,
1090 TailType.NONE);
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));
1113 else {
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!
1138 types.add(info);
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);