PsiElementVisitor (@NotNull final ProblemsHolder holder, boolean isOnTheFly) { if (!JavaFeature.ADVANCED_COLLECTIONS_API.isFeatureSupported(holder.getFile())) { return PsiElementVisitor.EMPTY_VISITOR; } return new JavaElementVisitor() { void handleIteratorLoop(PsiLoopStatement statement, PsiJavaToken endToken, IteratorDeclaration declaration) { if (endToken == null || declaration == null || !declaration.isCollection()) return; PsiStatement[] statements = ControlFlowUtils.unwrapBlock(statement.getBody()); if (statements.length == 2 && statements[1] instanceof PsiIfStatement) { PsiVariable element = declaration.getNextElementVariable(statements[0]); if (element == null) return; PsiIfStatement ifStatement = (PsiIfStatement)statements[1]; if(checkAndExtractCondition(declaration, ifStatement) == null) return; registerProblem(statement); } else if (statements.length == 1 && statements[0] instanceof PsiIfStatement){ PsiIfStatement ifStatement = (PsiIfStatement)statements[0]; PsiExpression condition = checkAndExtractCondition(declaration, ifStatement); if (condition == null) return; PsiElement ref = declaration.findOnlyIteratorRef(condition); if (ref != null && declaration.isIteratorMethodCall(ref.getParent().getParent(), "next") && isAlwaysExecuted(condition, ref)) { registerProblem(statement); } } } private static boolean isAlwaysExecuted(PsiExpression condition, PsiElement ref) { while(ref != condition) { PsiElement parent = ref.getParent(); if(parent instanceof PsiPolyadicExpression polyadicExpression) { IElementType type = polyadicExpression.getOperationTokenType(); if ((type.equals(JavaTokenType.ANDAND) || type.equals(JavaTokenType.OROR)) && polyadicExpression.getOperands()[0] != ref) { return false; } } if(parent instanceof PsiConditionalExpression && ((PsiConditionalExpression)parent).getCondition() != ref) { return false; } ref = parent; } return true; } private void registerProblem(PsiLoopStatement statement) { holder.registerProblem(statement.getFirstChild(), QuickFixBundle.message("java.8.collection.removeif.inspection.description"), new ReplaceWithRemoveIfQuickFix()); } @Nullable private static PsiExpression checkAndExtractCondition(IterableTraversal traversal, PsiIfStatement ifStatement) { PsiExpression condition = ifStatement.getCondition(); if (condition == null || ifStatement.getElseBranch() != null) return null; PsiStatement thenStatement = ControlFlowUtils.stripBraces(ifStatement.getThenBranch()); if (!(thenStatement instanceof PsiExpressionStatement)) return null; if (!traversal.isRemoveCall(((PsiExpressionStatement)thenStatement).getExpression())) return null; if (!LambdaGenerationUtil.canBeUncheckedLambda(condition)) return null; PsiReferenceExpression iterable = tryCast(PsiUtil.skipParenthesizedExprDown(traversal.getIterable()), PsiReferenceExpression.class); PsiVariable iterableVariable = iterable != null ? tryCast(iterable.resolve(), PsiVariable.class) : null; if (iterableVariable != null && VariableAccessUtils.variableIsUsed(iterableVariable, condition)) return null; return condition; } @Override public void visitForStatement(@NotNull PsiForStatement statement) { super.visitForStatement(statement); IteratorDeclaration declaration = IteratorDeclaration.fromLoop(statement); handleIteratorLoop(statement, statement.getRParenth(), declaration); } @Override public void visitWhileStatement(@NotNull PsiWhileStatement statement) { super.visitWhileStatement(statement); IteratorDeclaration declaration = IteratorDeclaration.fromLoop(statement); handleIteratorLoop(statement, statement.getRParenth(), declaration); } @Override public void visitForeachStatement(@NotNull PsiForeachStatement statement) { super.visitForeachStatement(statement); ForEachCollectionTraversal traversal = ForEachCollectionTraversal.fromLoop(statement); if (traversal == null) return; PsiIfStatement ifStatement = tryCast(ControlFlowUtils.stripBraces(statement.getBody()), PsiIfStatement.class); if (ifStatement == null) return; PsiExpression condition = checkAndExtractCondition(traversal, ifStatement); if (condition == null) return; PsiJavaToken endToken = statement.getRParenth(); if (endToken == null) return; registerProblem(statement); } }; }