@NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
    return new JavaElementVisitor() {
      @Override
      public void visitForStatement(@NotNull PsiForStatement statement) {
        super.visitForStatement(statement);
        CountingLoop loop = CountingLoop.from(statement);
        if (loop == null || loop.isIncluding() || loop.isDescending()) return;
        if (!ExpressionUtils.isZero(loop.getInitializer())) return;
        PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(ControlFlowUtils.stripBraces(statement.getBody()));
        if (assignment == null) return;
        IndexedContainer container = getContainer(loop, assignment);
        if (container == null || !(container.getQualifier().getType() instanceof PsiArrayType)) return;
        PsiExpression index = container.extractIndexFromGetExpression(assignment.getLExpression());
        if (!ExpressionUtils.isReferenceTo(index, loop.getCounter())) return;
        PsiExpression rValue = assignment.getRExpression();
        if (rValue == null) return;
        if (!isChangedInLoop(loop, rValue)) {
          PsiType lType = container.getElementType();
          Object defaultValue = PsiTypesUtil.getDefaultValue(lType);
          if (isDefaultValue(rValue, defaultValue, lType) && isFilledWithDefaultValues(container.getQualifier(), statement, defaultValue)) {
            holder.registerProblem(statement, getRange(statement, ProblemHighlightType.WARNING),
                                   JavaBundle.message("inspection.explicit.array.filling.redundant.loop.description"),
                                   QuickFixFactory.getInstance()
                                     .createDeleteFix(statement, CommonQuickFixBundle.message("fix.remove.statement", PsiKeyword.FOR)));
            return;
          }
          registerProblem(statement, false);
          return;
        }
        if (!PsiUtil.isAvailable(JavaFeature.ADVANCED_COLLECTIONS_API, holder.getFile())) return;
        if (!StreamApiUtil.isSupportedStreamElement(container.getElementType())) return;
        if (!LambdaGenerationUtil.canBeUncheckedLambda(rValue, Predicate.isEqual(loop.getCounter()))) return;
        registerProblem(statement, true);
      }

      private static boolean isChangedInLoop(@NotNull CountingLoop loop, @NotNull PsiExpression rValue) {
        if (VariableAccessUtils.collectUsedVariables(rValue).contains(loop.getCounter()) ||
            SideEffectChecker.mayHaveSideEffects(rValue)) {
          return true;
        }
        return ExpressionUtils.nonStructuralChildren(rValue)
          .filter(c -> c instanceof PsiCallExpression)
          .anyMatch(call -> !ClassUtils.isImmutable(call.getType()) && !ConstructionUtils.isEmptyArrayInitializer(call));
      }

      private static boolean isDefaultValue(@NotNull PsiExpression expression, @Nullable Object defaultValue, @Nullable PsiType lType) {
        if (ExpressionUtils.isNullLiteral(expression) && defaultValue == null) return true;
        Object constantValue = ExpressionUtils.computeConstantExpression(expression);
        PsiType rType = expression.getType();
        if (rType instanceof PsiPrimitiveType && lType instanceof PsiPrimitiveType) {
          if (defaultValue instanceof Number && constantValue instanceof Number) {
            return ((Number)defaultValue).doubleValue() == ((Number)constantValue).doubleValue();
          }
        }
        return constantValue != null && constantValue.equals(defaultValue);
      }

      private static boolean isFilledWithDefaultValues(@NotNull PsiExpression expression,
                                                       @NotNull PsiForStatement statement,
                                                       @Nullable Object defaultValue) {
        PsiReferenceExpression arrayRef = tryCast(PsiUtil.skipParenthesizedExprDown(expression), PsiReferenceExpression.class);
        if (arrayRef == null) return false;
        PsiVariable arrayVar = tryCast(arrayRef.resolve(), PsiVariable.class);
        if (arrayVar == null) return false;
        PsiCodeBlock block = tryCast(PsiUtil.getVariableCodeBlock(arrayVar, null), PsiCodeBlock.class);
        if (block == null) return false;
        ControlFlow flow = createControlFlow(block);
        if (flow == null) return false;
        int statementStart = flow.getStartOffset(statement);
        if (statementStart == -1) return false;
        int statementEnd = flow.getEndOffset(statement);
        if (statementEnd == -1) return false;
        PsiElement[] defs = getDefs(block, arrayVar, arrayRef, defaultValue);
        if (defs == null) return false;
        Set<Integer> exclude = getDefsOffsets(flow, defs);
        if (exclude == null) return false;
        for (int i = statementStart; i < statementEnd; i++) {
          exclude.add(i);
        }
        return !ContainerUtil.exists(defs, def ->
          ControlFlowUtils.isVariableReferencedBeforeStatementEntry(flow, flow.getEndOffset(def) + 1, statement, arrayVar, exclude));
      }

      @Nullable
      private static ControlFlow createControlFlow(@NotNull PsiCodeBlock block) {
        try {
          return ControlFlowFactory.getInstance(block.getProject())
            .getControlFlow(block, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance());
        }
        catch (AnalysisCanceledException ignored) {
          return null;
        }
      }

      private static PsiElement @Nullable [] getDefs(@NotNull PsiCodeBlock block,
                                                     @NotNull PsiVariable arrayVar,
                                                     @NotNull PsiReferenceExpression arrayRef,
                                                     @Nullable Object defaultValue) {
        PsiElement[] defs = DefUseUtil.getDefs(block, arrayVar, arrayRef);
        PsiExpression[] expressions = new PsiExpression[defs.length];
        for (int i = 0; i < defs.length; i++) {
          PsiElement def = defs[i];
          PsiVariable variable = tryCast(def, PsiVariable.class);
          if (variable != null) {
            PsiExpression initializer = variable.getInitializer();
            if (!isNewArrayCreation(initializer, defaultValue)) return null;
            expressions[i] = initializer;
            continue;
          }
          PsiAssignmentExpression assignment = PsiTreeUtil.getParentOfType(def, PsiAssignmentExpression.class);
          if (assignment != null) {
            if (!isNewArrayCreation(assignment.getRExpression(), defaultValue)) return null;
            expressions[i] = assignment;
            continue;
          }
          return null;
        }
        return expressions;
      }

      private static boolean isNewArrayCreation(@Nullable PsiExpression expression, @Nullable Object defaultValue) {
        PsiExpression arrInitExpr = PsiUtil.skipParenthesizedExprDown(expression);
        PsiNewExpression newExpression = tryCast(arrInitExpr, PsiNewExpression.class);
        PsiArrayInitializerExpression initializer;
        if (newExpression == null) {
          initializer = tryCast(arrInitExpr, PsiArrayInitializerExpression.class);
          if (initializer == null) return false;
        }
        else {
          initializer = newExpression.getArrayInitializer();
        }
        if (initializer == null) return true;
        return ContainerUtil.and(initializer.getInitializers(), init -> isDefaultValue(init, defaultValue, init.getType()));
      }

      @Nullable
      private static Set<Integer> getDefsOffsets(@NotNull ControlFlow flow, PsiElement @NotNull [] defs) {
        Set<Integer> set = new HashSet<>();
        for (PsiElement def : defs) {
          int start = flow.getStartOffset(def);
          if (start == -1) return null;
          int end = flow.getEndOffset(def);
          if (end == -1) return null;
          for (int i = start; i < end; i++) {
            set.add(i);
          }
        }
        return set;
      }

      private void registerProblem(@NotNull PsiForStatement statement, boolean isSetAll) {
        String message = JavaBundle.message("inspection.explicit.array.filling.description", isSetAll ? "setAll" : "fill");
        ReplaceWithArraysCallFix fix = new ReplaceWithArraysCallFix(!isSetAll);
        ProblemHighlightType type = ProblemHighlightType.WARNING;
        if (isSetAll && !mySuggestSetAll) {
          if (!isOnTheFly) return;
          type = ProblemHighlightType.INFORMATION;
        }
        TextRange range = getRange(statement, type);

        if (isSetAll && mySuggestSetAll && isOnTheFly) {
          var disableForSetAllFix =
            new UpdateInspectionOptionFix(ExplicitArrayFillingInspection.this,
                                       "mySuggestSetAll",
                                       JavaBundle.message("inspection.explicit.array.filling.no.suggestion.for.set.all"),
                                       false);
          holder.problem(statement, message).highlight(type).range(range).fix(fix).fix(disableForSetAllFix).register();
          return;
        }

        holder.registerProblem(statement, message, type, range, fix);
      }

      @NotNull
      private TextRange getRange(@NotNull PsiForStatement statement, @NotNull ProblemHighlightType type) {
        PsiStatement initialization = statement.getInitialization();
        LOG.assertTrue(initialization != null);
        TextRange range = TextRange.from(initialization.getStartOffsetInParent(), initialization.getTextLength());
        boolean wholeStatement = isOnTheFly &&
                                 (InspectionProjectProfileManager.isInformationLevel(getShortName(), statement) ||
                                  type == ProblemHighlightType.INFORMATION);
        PsiJavaToken rParenth = statement.getRParenth();
        if (wholeStatement && rParenth != null) {
          range = new TextRange(0, rParenth.getStartOffsetInParent() + 1);
        }
        return range;
      }
    };
  }
@NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly)