From 4b80f8009aa53a3c8a1d34456b12c5ff5ee8af1d Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 20 Feb 2015 12:40:11 +0100 Subject: [PATCH] disable for->foreach inspection if iterator is used in method reference qualifier (IDEA-136642) --- .../ForCanBeForeachInspectionBase.java | 79 ++++++++----------- .../migration/foreach/ForCanBeForEach.java | 14 ++++ .../ForCanBeForeachInspectionTest.java | 8 ++ 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java index 64954449458b..1991167dca8f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java @@ -178,14 +178,12 @@ public class ForCanBeForeachInspectionBase extends BaseInspection { return visitor.isIndexVariableUsedOnlyAsIndex(); } - static boolean isCollectionLoopStatement( - PsiForStatement forStatement, boolean ignoreUntypedCollections) { + static boolean isCollectionLoopStatement(PsiForStatement forStatement, boolean ignoreUntypedCollections) { final PsiStatement initialization = forStatement.getInitialization(); if (!(initialization instanceof PsiDeclarationStatement)) { return false; } - final PsiDeclarationStatement declaration = - (PsiDeclarationStatement)initialization; + final PsiDeclarationStatement declaration = (PsiDeclarationStatement)initialization; final PsiElement[] declaredElements = declaration.getDeclaredElements(); if (declaredElements.length != 1) { return false; @@ -195,9 +193,7 @@ public class ForCanBeForeachInspectionBase extends BaseInspection { return false; } final PsiVariable variable = (PsiVariable)declaredElement; - if (!TypeUtils.variableHasTypeOrSubtype(variable, - CommonClassNames.JAVA_UTIL_ITERATOR, - "java.util.ListIterator")) { + if (!TypeUtils.variableHasTypeOrSubtype(variable, CommonClassNames.JAVA_UTIL_ITERATOR, "java.util.ListIterator")) { return false; } final PsiExpression initialValue = variable.getInitializer(); @@ -207,14 +203,10 @@ public class ForCanBeForeachInspectionBase extends BaseInspection { if (!(initialValue instanceof PsiMethodCallExpression)) { return false; } - final PsiMethodCallExpression initialCall = - (PsiMethodCallExpression)initialValue; - final PsiReferenceExpression initialMethodExpression = - initialCall.getMethodExpression(); - @NonNls final String initialCallName = - initialMethodExpression.getReferenceName(); - if (!HardcodedMethodConstants.ITERATOR.equals(initialCallName) && - !"listIterator".equals(initialCallName)) { + final PsiMethodCallExpression initialCall = (PsiMethodCallExpression)initialValue; + final PsiReferenceExpression initialMethodExpression = initialCall.getMethodExpression(); + @NonNls final String initialCallName = initialMethodExpression.getReferenceName(); + if (!HardcodedMethodConstants.ITERATOR.equals(initialCallName) && !"listIterator".equals(initialCallName)) { return false; } final PsiExpressionList argumentList = initialCall.getArgumentList(); @@ -222,12 +214,10 @@ public class ForCanBeForeachInspectionBase extends BaseInspection { if (arguments.length != 0) { return false; } - final PsiExpression qualifier = - initialMethodExpression.getQualifierExpression(); + final PsiExpression qualifier = initialMethodExpression.getQualifierExpression(); final PsiClass qualifierClass; if (qualifier == null) { - qualifierClass = - ClassUtils.getContainingClass(initialMethodExpression); + qualifierClass = ClassUtils.getContainingClass(initialMethodExpression); if (ignoreUntypedCollections) { final PsiClassType type = (PsiClassType)variable.getType(); final PsiType[] parameters = type.getParameters(); @@ -255,10 +245,8 @@ public class ForCanBeForeachInspectionBase extends BaseInspection { if (qualifierClass == null) { return false; } - if (!InheritanceUtil.isInheritor(qualifierClass, - CommonClassNames.JAVA_LANG_ITERABLE) && - !InheritanceUtil.isInheritor(qualifierClass, - CommonClassNames.JAVA_UTIL_COLLECTION)) { + if (!InheritanceUtil.isInheritor(qualifierClass, CommonClassNames.JAVA_LANG_ITERABLE) && + !InheritanceUtil.isInheritor(qualifierClass, CommonClassNames.JAVA_UTIL_COLLECTION)) { return false; } final PsiExpression condition = forStatement.getCondition(); @@ -289,16 +277,13 @@ public class ForCanBeForeachInspectionBase extends BaseInspection { if (body == null) { return 0; } - final NumCallsToIteratorNextVisitor visitor = - new NumCallsToIteratorNextVisitor(iterator); + final NumCallsToIteratorNextVisitor visitor = new NumCallsToIteratorNextVisitor(iterator); body.accept(visitor); return visitor.getNumCallsToIteratorNext(); } - private static boolean isIteratorMethodCalled(PsiVariable iterator, - PsiStatement body) { - final IteratorMethodCallVisitor visitor = - new IteratorMethodCallVisitor(iterator); + private static boolean isIteratorMethodCalled(PsiVariable iterator, PsiStatement body) { + final IteratorMethodCallVisitor visitor = new IteratorMethodCallVisitor(iterator); body.accept(visitor); return visitor.isMethodCalled(); } @@ -308,29 +293,25 @@ public class ForCanBeForeachInspectionBase extends BaseInspection { if (!(condition instanceof PsiMethodCallExpression)) { return false; } - final PsiMethodCallExpression call = - (PsiMethodCallExpression)condition; + final PsiMethodCallExpression call = (PsiMethodCallExpression)condition; final PsiExpressionList argumentList = call.getArgumentList(); final PsiExpression[] arguments = argumentList.getExpressions(); if (arguments.length != 0) { return false; } - final PsiReferenceExpression methodExpression = - call.getMethodExpression(); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); final String methodName = methodExpression.getReferenceName(); if (!HardcodedMethodConstants.HAS_NEXT.equals(methodName)) { return false; } - final PsiExpression qualifier = - methodExpression.getQualifierExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); if (qualifier == null) { return true; } if (!(qualifier instanceof PsiReferenceExpression)) { return false; } - final PsiReferenceExpression referenceExpression = - (PsiReferenceExpression)qualifier; + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier; final PsiElement target = referenceExpression.resolve(); return iterator.equals(target); } @@ -636,31 +617,39 @@ public class ForCanBeForeachInspectionBase extends BaseInspection { } @Override - public void visitMethodCallExpression( - @NotNull PsiMethodCallExpression expression) { + public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) { if (methodCalled) { return; } super.visitMethodCallExpression(expression); - final PsiReferenceExpression methodExpression = - expression.getMethodExpression(); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); final String name = methodExpression.getReferenceName(); if (HardcodedMethodConstants.NEXT.equals(name)) { return; } - final PsiExpression qualifier = - methodExpression.getQualifierExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); if (!(qualifier instanceof PsiReferenceExpression)) { return; } - final PsiReferenceExpression referenceExpression = - (PsiReferenceExpression)qualifier; + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier; final PsiElement target = referenceExpression.resolve(); if (iterator.equals(target)) { methodCalled = true; } } + @Override + public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { + if (methodCalled) { + return; + } + super.visitMethodReferenceExpression(expression); + final PsiExpression qualifierExpression = expression.getQualifierExpression(); + if (qualifierExpression instanceof PsiReferenceExpression && iterator.equals(((PsiReferenceExpression)qualifierExpression).resolve())) { + methodCalled = true; + } + } + public boolean isMethodCalled() { return methodCalled; } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/foreach/ForCanBeForEach.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/foreach/ForCanBeForEach.java index f742c291ad8a..eb06803e174a 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/foreach/ForCanBeForEach.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/foreach/ForCanBeForEach.java @@ -273,6 +273,20 @@ public class ForCanBeForEach { } } } + + static class WithMethodRefs { + private static final List STRINGS = new ArrayList<>(Arrays.asList("Hello", "World")); + + public void test3() { + for (ListIterator stringListIterator = STRINGS.listIterator(); stringListIterator.hasNext(); ) { + System.out.println(stringListIterator.next()); + + List strings2 = new ArrayList<>(Collections.singletonList("!")); + + strings2.forEach(stringListIterator::add); + } + } + } } class OuterClass { diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/ForCanBeForeachInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/ForCanBeForeachInspectionTest.java index fe513136456d..71a0cb977274 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/ForCanBeForeachInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/ForCanBeForeachInspectionTest.java @@ -1,7 +1,9 @@ package com.siyeh.ig.migration; import com.intellij.codeInspection.InspectionProfileEntry; +import com.intellij.testFramework.LightProjectDescriptor; import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.NotNull; public class ForCanBeForeachInspectionTest extends LightInspectionTestCase { @@ -18,4 +20,10 @@ public class ForCanBeForeachInspectionTest extends LightInspectionTestCase { protected String getBasePath() { return "/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/foreach"; } + + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return JAVA_8; + } } \ No newline at end of file