From 7127e7b07ead803fb3c55546a46d713876621ada Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 14 Jun 2007 17:05:43 +0400 Subject: [PATCH] IDEADEV-17531 --- .../com/siyeh/InspectionGadgetsBundle.properties | 6 +- .../src/com/siyeh/ig/InspectionGadgetsPlugin.java | 3 +- ...WithImplicitTerminationConditionInspection.java | 77 +++++++++++++++++----- .../LoopWithImplicitTerminationCondition.html | 15 +++++ 4 files changed, 83 insertions(+), 18 deletions(-) create mode 100644 plugins/InspectionGadgets/src/inspectionDescriptions/LoopWithImplicitTerminationCondition.html diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 675958edfe..be0f8da15b 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1616,4 +1616,8 @@ type.may.be.weakened.quickfix=Weaken type to ''{0}'' ignore.guard.clauses=Ignore &guard clauses ignore.for.equals.methods=Ignore for &equals() methods caught.exception.immediately.rethrown.display.name=Caught exception is immediately rethrown -caught.exception.immediately.rethrown.problem.descriptor=Caught exception #ref is immediately rethrown \ No newline at end of file +caught.exception.immediately.rethrown.problem.descriptor=Caught exception #ref is immediately rethrown +loop.with.implicit.termination.condition.display.name=Loop with implicit termination condition +loop.with.implicit.termination.condition.dowhile.problem.descriptor=#ref-while loop with implicit termination condition +loop.with.implicit.termination.condition.problem.descriptor=#ref loop with implicit termination condition +loop.with.implicit.termination.condition.quickfix=Make condition explicit \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java index a9474aa160..a5e4783b85 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java @@ -90,7 +90,7 @@ import java.util.*; public class InspectionGadgetsPlugin implements ApplicationComponent, InspectionToolProvider { - private static final int NUM_INSPECTIONS = 587; + private static final int NUM_INSPECTIONS = 589; private final List> m_inspectionClasses = new ArrayList(NUM_INSPECTIONS); @NonNls private static final String DESCRIPTION_DIRECTORY_NAME = @@ -451,6 +451,7 @@ public class InspectionGadgetsPlugin implements ApplicationComponent, m_inspectionClasses.add(LabeledStatementInspection.class); m_inspectionClasses.add(LoopConditionNotUpdatedInsideLoopInspection.class); m_inspectionClasses.add(LoopStatementsThatDontLoopInspection.class); + m_inspectionClasses.add(LoopWithImplicitTerminationConditionInspection.class); m_inspectionClasses.add(NegatedConditionalInspection.class); m_inspectionClasses.add(NegatedIfElseInspection.class); m_inspectionClasses.add(NestedConditionalExpressionInspection.class); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/LoopWithImplicitTerminationConditionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/LoopWithImplicitTerminationConditionInspection.java index a364da55a7..00a8d25227 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/LoopWithImplicitTerminationConditionInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/LoopWithImplicitTerminationConditionInspection.java @@ -23,6 +23,7 @@ import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.BoolUtils; +import com.siyeh.InspectionGadgetsBundle; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,12 +33,18 @@ public class LoopWithImplicitTerminationConditionInspection @Nls @NotNull public String getDisplayName() { - return "Loop with implicit termination condition"; + return InspectionGadgetsBundle.message( + "loop.with.implicit.termination.condition.display.name"); } @NotNull protected String buildErrorString(Object... infos) { - return "#ref statement with implicit condition"; + if (Boolean.TRUE.equals(infos[0])) { + return InspectionGadgetsBundle.message( + "loop.with.implicit.termination.condition.dowhile.problem.descriptor"); + } + return InspectionGadgetsBundle.message( + "loop.with.implicit.termination.condition.problem.descriptor"); } @Nullable @@ -49,7 +56,8 @@ public class LoopWithImplicitTerminationConditionInspection extends InspectionGadgetsFix { @NotNull public String getName() { - return "Make while condition explicit"; + return InspectionGadgetsBundle.message( + "loop.with.implicit.termination.condition.quickfix"); } protected void doFix(Project project, ProblemDescriptor descriptor) @@ -58,20 +66,24 @@ public class LoopWithImplicitTerminationConditionInspection final PsiElement parent = element.getParent(); final PsiExpression loopCondition; final PsiStatement body; + final boolean firstStatement; if (parent instanceof PsiWhileStatement) { final PsiWhileStatement whileStatement = (PsiWhileStatement) parent; loopCondition = whileStatement.getCondition(); body = whileStatement.getBody(); + firstStatement = true; } else if (parent instanceof PsiDoWhileStatement) { final PsiDoWhileStatement doWhileStatement = (PsiDoWhileStatement) parent; loopCondition = doWhileStatement.getCondition(); body = doWhileStatement.getBody(); + firstStatement = false; } else if (parent instanceof PsiForStatement) { final PsiForStatement forStatement = (PsiForStatement) parent; loopCondition = forStatement.getCondition(); body = forStatement.getBody(); + firstStatement = true; } else { return; } @@ -86,7 +98,11 @@ public class LoopWithImplicitTerminationConditionInspection if (statements.length == 0) { return; } - statement = statements[0]; + if (firstStatement) { + statement = statements[0]; + } else { + statement = statements[statements.length - 1]; + } } else { statement = body; } @@ -104,18 +120,44 @@ public class LoopWithImplicitTerminationConditionInspection final String negatedExpressionText = BoolUtils.getNegatedExpressionText(ifCondition); replaceExpression(loopCondition, negatedExpressionText); - if (elseBranch == null) { - ifStatement.delete(); - } else { - ifStatement.replace(elseBranch); - } + replaceStatement(ifStatement, elseBranch); } else if (containsUnlabeledBreakStatement(elseBranch)) { loopCondition.replace(ifCondition); if (thenBranch == null) { ifStatement.delete(); } else { - ifStatement.replace(thenBranch); + replaceStatement(ifStatement, thenBranch); + } + } + } + + private static void replaceStatement( + @NotNull PsiStatement replacedStatement, + @Nullable PsiStatement replacingStatement) + throws IncorrectOperationException { + if (replacingStatement == null) { + replacedStatement.delete(); + return; + } + if (!(replacingStatement instanceof PsiBlockStatement)) { + replacedStatement.replace(replacingStatement); + return; + } + final PsiBlockStatement blockStatement = + (PsiBlockStatement)replacingStatement; + final PsiCodeBlock codeBlock = + blockStatement.getCodeBlock(); + final PsiElement[] children = codeBlock.getChildren(); + if (children.length > 2) { + final PsiElement receiver = replacedStatement.getParent(); + for (int i = children.length - 2; i > 0; i--) { + final PsiElement child = children[i]; + if (child instanceof PsiWhiteSpace) { + continue; + } + receiver.addAfter(child, replacedStatement); } + replacedStatement.delete(); } } } @@ -129,35 +171,38 @@ public class LoopWithImplicitTerminationConditionInspection public void visitWhileStatement(PsiWhileStatement statement) { super.visitWhileStatement(statement); - if (statement.getCondition() == null) { + final PsiExpression condition = statement.getCondition(); + if (!BoolUtils.isTrue(condition)) { return; } if (isLoopWithImplicitTerminationCondition(statement, true)) { return; } - registerStatementError(statement); + registerStatementError(statement, Boolean.FALSE); } public void visitDoWhileStatement(PsiDoWhileStatement statement) { super.visitDoWhileStatement(statement); - if (statement.getCondition() == null) { + final PsiExpression condition = statement.getCondition(); + if (!BoolUtils.isTrue(condition)) { return; } if (isLoopWithImplicitTerminationCondition(statement, false)) { return; } - registerStatementError(statement); + registerStatementError(statement, Boolean.TRUE); } public void visitForStatement(PsiForStatement statement) { super.visitForStatement(statement); - if (statement.getCondition() == null) { + final PsiExpression condition = statement.getCondition(); + if (!BoolUtils.isTrue(condition)) { return; } if (isLoopWithImplicitTerminationCondition(statement, true)) { return; } - registerStatementError(statement); + registerStatementError(statement, Boolean.FALSE); } private static boolean isLoopWithImplicitTerminationCondition( diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/LoopWithImplicitTerminationCondition.html b/plugins/InspectionGadgets/src/inspectionDescriptions/LoopWithImplicitTerminationCondition.html new file mode 100644 index 0000000000..7751de4e8f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/LoopWithImplicitTerminationCondition.html @@ -0,0 +1,15 @@ + +
+ +This inspection reports any while, +do-while and for +loops which have the constant true as their +only condition, but which still can be terminated by a containing +if statement which can break out of the loop. +This if statement must be the first or only statement +in a while or for +loops and the last or only statement in a do-while loop. +Such a loop would be clearer if the if statement was removed and its condition +was made an explicit loop condition. +
Powered by InspectionGadgets
+ \ No newline at end of file -- 2.11.4.GIT