private void analyzeDfaWithNestedClosures( PsiElement scope, ProblemsHolder holder, StandardDataFlowRunner dfaRunner, Collection<DfaMemoryState> initialStates) { 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); MultiMap<PsiElement, DfaMemoryState> nestedClosures = dfaRunner.getNestedClosures(); for (PsiElement closure : nestedClosures.keySet()) { analyzeDfaWithNestedClosures(closure, holder, dfaRunner, nestedClosures.get(closure)); } } 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)) return; final StandardDataFlowRunner dfaRunner = new StandardDataFlowRunner(scope) { @Override protected boolean shouldCheckTimeLimit() { if (!onTheFly) return false; return super.shouldCheckTimeLimit(); } }; analyzeDfaWithNestedClosures( scope, holder, dfaRunner, Arrays.asList(dfaRunner.createMemoryState())); }
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); }
private static void reportNullableReturns( StandardDataFlowRunner runner, DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { for (PsiElement statement : visitor.getProblems(NullabilityProblem.nullableReturn)) { assert statement instanceof PsiExpression; final PsiExpression expr = (PsiExpression) statement; if (!reportedAnchors.add(expr)) continue; if (runner.isInNotNullMethod()) { final String text = isNullLiteralExpression(expr) ? InspectionsBundle.message("dataflow.message.return.null.from.notnull") : InspectionsBundle.message("dataflow.message.return.nullable.from.notnull"); holder.registerProblem(expr, text); } else if (AnnotationUtil.isAnnotatingApplicable(statement)) { final NullableNotNullManager manager = NullableNotNullManager.getInstance(expr.getProject()); final String defaultNullable = manager.getDefaultNullable(); final String presentableNullable = StringUtil.getShortName(defaultNullable); final String text = isNullLiteralExpression(expr) ? InspectionsBundle.message( "dataflow.message.return.null.from.notnullable", presentableNullable) : InspectionsBundle.message( "dataflow.message.return.nullable.from.notnullable", presentableNullable); holder.registerProblem( expr, text, new AnnotateMethodFix(defaultNullable, ArrayUtil.toStringArray(manager.getNotNulls())) { @Override public int shouldAnnotateBaseMethod( PsiMethod method, PsiMethod superMethod, Project project) { return 1; } }); } } }
@Override protected void onInstructionProducesCCE(TypeCastInstruction instruction) { myRunner.onInstructionProducesCCE(instruction); }
private void createDescription( StandardDataFlowRunner runner, ProblemsHolder holder, DataFlowInstructionVisitor visitor) { 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); } } reportNullableArguments(visitor, holder, reportedAnchors); reportNullableAssignments(visitor, holder, reportedAnchors); reportUnboxedNullables(visitor, holder, reportedAnchors); if (!runner.isInNullableMethod() && runner.isInMethod() && (runner.isInNotNullMethod() || SUGGEST_NULLABLE_ANNOTATIONS)) { reportNullableReturns(runner, visitor, holder, reportedAnchors); } if (SUGGEST_NULLABLE_ANNOTATIONS) { reportNullableArgumentsPassedToNonAnnotated(visitor, holder, reportedAnchors); } if (REPORT_CONSTANT_REFERENCE_VALUES) { reportConstantReferenceValues(holder, visitor, reportedAnchors); } }