private void analyzeDfaWithNestedClosures( PsiElement scope, ProblemsHolder holder, StandardDataFlowRunner dfaRunner, Collection<DfaMemoryState> initialStates, final boolean onTheFly) { final DataFlowInstructionVisitor visitor = new DataFlowInstructionVisitor(dfaRunner); final RunnerResult rc = dfaRunner.analyzeMethod(scope, visitor, IGNORE_ASSERT_STATEMENTS, initialStates); if (rc == RunnerResult.OK) { createDescription(dfaRunner, holder, visitor, onTheFly, scope); MultiMap<PsiElement, DfaMemoryState> nestedClosures = dfaRunner.getNestedClosures(); for (PsiElement closure : nestedClosures.keySet()) { analyzeDfaWithNestedClosures( closure, holder, dfaRunner, nestedClosures.get(closure), onTheFly); } } else if (rc == RunnerResult.TOO_COMPLEX) { if (scope.getParent() instanceof PsiMethod) { PsiMethod method = (PsiMethod) scope.getParent(); final PsiIdentifier name = method.getNameIdentifier(); if (name != null) { // Might be null for synthetic methods like JSP page. holder.registerProblem( name, InspectionsBundle.message("dataflow.too.complex"), ProblemHighlightType.WEAK_WARNING); } } } }
private void analyzeCodeBlock( @Nullable final PsiElement scope, ProblemsHolder holder, final boolean onTheFly) { if (scope == null) return; PsiClass containingClass = PsiTreeUtil.getParentOfType(scope, PsiClass.class); if (containingClass != null && PsiUtil.isLocalOrAnonymousClass(containingClass) && !(containingClass instanceof PsiEnumConstantInitializer)) return; final StandardDataFlowRunner dfaRunner = new StandardDataFlowRunner( TREAT_UNKNOWN_MEMBERS_AS_NULLABLE, !isInsideConstructorOrInitializer(scope)) { @Override protected boolean shouldCheckTimeLimit() { if (!onTheFly) return false; return super.shouldCheckTimeLimit(); } }; analyzeDfaWithNestedClosures( scope, holder, dfaRunner, Arrays.asList(dfaRunner.createMemoryState()), onTheFly); }
@Override protected void onInstructionProducesCCE(TypeCastInstruction instruction) { myRunner.onInstructionProducesCCE(instruction); }
private void createDescription( StandardDataFlowRunner runner, ProblemsHolder holder, DataFlowInstructionVisitor visitor, final boolean onTheFly, PsiElement scope) { Pair<Set<Instruction>, Set<Instruction>> constConditions = runner.getConstConditionalExpressions(); Set<Instruction> trueSet = constConditions.getFirst(); Set<Instruction> falseSet = constConditions.getSecond(); ArrayList<Instruction> allProblems = new ArrayList<Instruction>(); allProblems.addAll(trueSet); allProblems.addAll(falseSet); allProblems.addAll(runner.getCCEInstructions()); allProblems.addAll(StandardDataFlowRunner.getRedundantInstanceofs(runner, visitor)); HashSet<PsiElement> reportedAnchors = new HashSet<PsiElement>(); for (PsiElement element : visitor.getProblems(NullabilityProblem.callNPE)) { if (reportedAnchors.add(element)) { reportCallMayProduceNpe(holder, (PsiMethodCallExpression) element, holder.isOnTheFly()); } } for (PsiElement element : visitor.getProblems(NullabilityProblem.fieldAccessNPE)) { if (reportedAnchors.add(element)) { PsiElement parent = element.getParent(); PsiElement fieldAccess = parent instanceof PsiArrayAccessExpression || parent instanceof PsiReferenceExpression ? parent : element; reportFieldAccessMayProduceNpe(holder, element, (PsiExpression) fieldAccess); } } for (Instruction instruction : allProblems) { if (instruction instanceof TypeCastInstruction && reportedAnchors.add( ((TypeCastInstruction) instruction).getCastExpression().getCastType())) { reportCastMayFail(holder, (TypeCastInstruction) instruction); } else if (instruction instanceof BranchingInstruction) { handleBranchingInstruction( holder, visitor, trueSet, falseSet, reportedAnchors, (BranchingInstruction) instruction, onTheFly); } } reportNullableArguments(visitor, holder, reportedAnchors); reportNullableAssignments(visitor, holder, reportedAnchors); reportUnboxedNullables(visitor, holder, reportedAnchors); reportNullableReturns(visitor, holder, reportedAnchors, scope); if (SUGGEST_NULLABLE_ANNOTATIONS) { reportNullableArgumentsPassedToNonAnnotated(visitor, holder, reportedAnchors); } reportOptionalOfNullableImprovements(holder, reportedAnchors, runner.getInstructions()); if (REPORT_CONSTANT_REFERENCE_VALUES) { reportConstantReferenceValues(holder, visitor, reportedAnchors); } }