@Override public PsiType[] guessContainerElementType(PsiExpression containerExpr, TextRange rangeToIgnore) { HashSet<PsiType> typesSet = new HashSet<>(); PsiType type = containerExpr.getType(); PsiType elemType; if ((elemType = getGenericElementType(type)) != null) return new PsiType[] {elemType}; if (containerExpr instanceof PsiReferenceExpression) { PsiElement refElement = ((PsiReferenceExpression) containerExpr).resolve(); if (refElement instanceof PsiVariable) { PsiFile file = refElement.getContainingFile(); if (file == null) { file = containerExpr.getContainingFile(); // implicit variable in jsp } HashSet<PsiVariable> checkedVariables = new HashSet<>(); addTypesByVariable( typesSet, (PsiVariable) refElement, file, checkedVariables, CHECK_USAGE | CHECK_DOWN, rangeToIgnore); checkedVariables.clear(); addTypesByVariable( typesSet, (PsiVariable) refElement, file, checkedVariables, CHECK_UP, rangeToIgnore); } } return typesSet.toArray(PsiType.createArray(typesSet.size())); }
@Nullable private static Map<PsiExpression, PsiType> buildDataflowTypeMap(PsiExpression forPlace) { PsiElement scope = DfaPsiUtil.getTopmostBlockInSameClass(forPlace); if (scope == null) { PsiFile file = forPlace.getContainingFile(); if (!(file instanceof PsiCodeFragment)) { return Collections.emptyMap(); } scope = file; } DataFlowRunner runner = new DataFlowRunner() { @NotNull @Override protected DfaMemoryState createMemoryState() { return new ExpressionTypeMemoryState(getFactory()); } }; final ExpressionTypeInstructionVisitor visitor = new ExpressionTypeInstructionVisitor(forPlace); if (runner.analyzeMethod(scope, visitor) == RunnerResult.OK) { return visitor.getResult(); } return null; }
private static Map<PsiExpression, PsiType> getAllTypeCasts(PsiExpression forPlace) { assert forPlace.isValid(); final int start = forPlace.getTextRange().getStartOffset(); final Map<PsiExpression, PsiType> allCasts = new THashMap<>(ExpressionTypeMemoryState.EXPRESSION_HASHING_STRATEGY); getTopmostBlock(forPlace) .accept( new JavaRecursiveElementWalkingVisitor() { @Override public void visitTypeCastExpression(PsiTypeCastExpression expression) { final PsiType castType = expression.getType(); final PsiExpression operand = expression.getOperand(); if (operand != null && castType != null) { allCasts.put(operand, castType); } super.visitTypeCastExpression(expression); } @Override public void visitInstanceOfExpression(PsiInstanceOfExpression expression) { final PsiTypeElement castType = expression.getCheckType(); final PsiExpression operand = expression.getOperand(); if (castType != null) { allCasts.put(operand, castType.getType()); } super.visitInstanceOfExpression(expression); } @Override public void visitElement(PsiElement element) { if (element.getTextRange().getStartOffset() > start) { return; } super.visitElement(element); } }); return allCasts; }
private void addExprTypesByDerivedClasses(LinkedHashSet<PsiType> set, PsiExpression expr) { PsiType type = expr.getType(); if (!(type instanceof PsiClassType)) return; PsiClass refClass = PsiUtil.resolveClassInType(type); if (refClass == null) return; PsiManager manager = PsiManager.getInstance(myProject); PsiElementProcessor.CollectElementsWithLimit<PsiClass> processor = new PsiElementProcessor.CollectElementsWithLimit<>(5); ClassInheritorsSearch.search(refClass).forEach(new PsiElementProcessorAdapter<>(processor)); if (processor.isOverflow()) return; for (PsiClass derivedClass : processor.getCollection()) { if (derivedClass instanceof PsiAnonymousClass) continue; PsiType derivedType = JavaPsiFacade.getInstance(manager.getProject()) .getElementFactory() .createType(derivedClass); set.add(derivedType); } }
private void addTypesByVariable( HashSet<PsiType> typesSet, PsiVariable var, PsiFile scopeFile, HashSet<PsiVariable> checkedVariables, int flags, TextRange rangeToIgnore) { if (!checkedVariables.add(var)) return; // System.out.println("analyzing usages of " + var + " in file " + scopeFile); SearchScope searchScope = new LocalSearchScope(scopeFile); if (BitUtil.isSet(flags, CHECK_USAGE) || BitUtil.isSet(flags, CHECK_DOWN)) { for (PsiReference varRef : ReferencesSearch.search(var, searchScope, false)) { PsiElement ref = varRef.getElement(); if (BitUtil.isSet(flags, CHECK_USAGE)) { PsiType type = guessElementTypeFromReference(myMethodPatternMap, ref, rangeToIgnore); if (type != null && !(type instanceof PsiPrimitiveType)) { typesSet.add(type); } } if (BitUtil.isSet(flags, CHECK_DOWN)) { if (ref.getParent() instanceof PsiExpressionList && ref.getParent().getParent() instanceof PsiMethodCallExpression) { // TODO : new PsiExpressionList list = (PsiExpressionList) ref.getParent(); PsiExpression[] args = list.getExpressions(); int argIndex = -1; for (int j = 0; j < args.length; j++) { PsiExpression arg = args[j]; if (arg.equals(ref)) { argIndex = j; break; } } PsiMethodCallExpression methodCall = (PsiMethodCallExpression) list.getParent(); PsiMethod method = (PsiMethod) methodCall.getMethodExpression().resolve(); if (method != null) { PsiParameter[] parameters = method.getParameterList().getParameters(); if (argIndex < parameters.length) { addTypesByVariable( typesSet, parameters[argIndex], method.getContainingFile(), checkedVariables, flags | CHECK_USAGE, rangeToIgnore); } } } } } } if (BitUtil.isSet(flags, CHECK_UP)) { if (var instanceof PsiParameter && var.getParent() instanceof PsiParameterList && var.getParent().getParent() instanceof PsiMethod) { PsiParameterList list = (PsiParameterList) var.getParent(); PsiParameter[] parameters = list.getParameters(); int argIndex = -1; for (int i = 0; i < parameters.length; i++) { PsiParameter parameter = parameters[i]; if (parameter.equals(var)) { argIndex = i; break; } } PsiMethod method = (PsiMethod) var.getParent().getParent(); // System.out.println("analyzing usages of " + method + " in file " + scopeFile); for (PsiReference methodRef : ReferencesSearch.search(method, searchScope, false)) { PsiElement ref = methodRef.getElement(); if (ref.getParent() instanceof PsiMethodCallExpression) { PsiMethodCallExpression methodCall = (PsiMethodCallExpression) ref.getParent(); PsiExpression[] args = methodCall.getArgumentList().getExpressions(); if (args.length <= argIndex) continue; PsiExpression arg = args[argIndex]; if (arg instanceof PsiReferenceExpression) { PsiElement refElement = ((PsiReferenceExpression) arg).resolve(); if (refElement instanceof PsiVariable) { addTypesByVariable( typesSet, (PsiVariable) refElement, scopeFile, checkedVariables, flags | CHECK_USAGE, rangeToIgnore); } } // TODO : constructor } } } } }