@Override
  public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
    return new JavaElementVisitor() {
      @Override
      public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) {
        if (!LIST_REMOVE.test(call)) return;
        PsiExpression listExpression = call.getMethodExpression().getQualifierExpression();
        if (listExpression == null) return;
        PsiElement parent = call.getParent();
        if (!(parent instanceof PsiExpressionStatement)) return;
        PsiLoopStatement loop = PsiTreeUtil.getParentOfType(parent, PsiLoopStatement.class, true, PsiMember.class);
        if (loop == null) return;
        if (ControlFlowUtils.stripBraces(loop.getBody()) != parent) return;
        PsiExpression arg = call.getArgumentList().getExpressions()[0];

        ProblemHighlightType type;
        if (isRemoveInCountingLoop(loop, arg)) {
          type = ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
        } else if (isRemoveInWhileLoop(loop, listExpression, arg)) {
          // while-loop scenario is not so bad (always the last element is removed which is usually fast),
          // the replacement is often longer and harder to read
          // and such loop is often used to remove at most one element which is faster than using subList().clear()
          if (!isOnTheFly) return;
          type = ProblemHighlightType.INFORMATION;
        } else {
          return;
        }
        holder.registerProblem(loop.getFirstChild(), InspectionGadgetsBundle.message("inspection.list.remove.in.loop.message"),
                               type, new ListRemoveInLoopFix());
      }

      /**
       * Looks for pattern like
       * <pre>{@code
       * while (list.size() > smth) {
       *   list.remove(list.size() - 1);
       * }}</pre>
       */
      private static boolean isRemoveInWhileLoop(PsiLoopStatement loop, PsiExpression listExpression, PsiExpression arg) {
        if (!(loop instanceof PsiWhileStatement)) return false;
        PsiBinaryExpression condition =
          tryCast(PsiUtil.skipParenthesizedExprDown(((PsiWhileStatement)loop).getCondition()), PsiBinaryExpression.class);
        if (condition == null) return false;
        RelationType relationType = DfaPsiUtil.getRelationByToken(condition.getOperationTokenType());
        if (relationType == null) return false;
        PsiExpression sizeExpression;
        switch (relationType) {
          case GE, GT -> sizeExpression = condition.getLOperand();
          case LE, LT -> sizeExpression = condition.getROperand();
          default -> {
            return false;
          }
        }
        PsiMethodCallExpression sizeCall = tryCast(PsiUtil.skipParenthesizedExprDown(sizeExpression), PsiMethodCallExpression.class);
        if (!LIST_SIZE.test(sizeCall)) return false;
        PsiExpression sizeQualifier = sizeCall.getMethodExpression().getQualifierExpression();
        if (sizeQualifier == null || !PsiEquivalenceUtil.areElementsEquivalent(sizeQualifier, listExpression)) return false;
        PsiBinaryExpression diff = tryCast(PsiUtil.skipParenthesizedExprDown(arg), PsiBinaryExpression.class);
        if (diff == null || !diff.getOperationTokenType().equals(JavaTokenType.MINUS)) return false;
        if (!ExpressionUtils.isLiteral(diff.getROperand(), 1)) return false;
        return PsiEquivalenceUtil.areElementsEquivalent(sizeCall, diff.getLOperand());
      }

      /**
       * Looks for pattern like
       * <pre>{@code
       * for (int i=from; i<to; i++) {
       *   list.remove(from);
       * }}</pre> or
       * <pre>{@code
       * for (int i=to-1; i>=from; i--) {
       *   list.remove(i);
       * }}</pre>
       */
      private static boolean isRemoveInCountingLoop(PsiLoopStatement forLoop, PsiExpression arg) {
        if (!(forLoop instanceof PsiForStatement)) return false;
        CountingLoop loop = CountingLoop.from((PsiForStatement)forLoop);
        if (loop == null) return false;
        if (loop.isDescending()) {
          return ExpressionUtils.isReferenceTo(arg, loop.getCounter());
        }
        return PsiEquivalenceUtil.areElementsEquivalent(arg, loop.getInitializer());
      }
    };
  }
@Override
  public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly)