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);
    }
  }