diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CollectionQueryUpdateCalledVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CollectionQueryUpdateCalledVisitor.java index 6d3524821027..3de34fba65c2 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CollectionQueryUpdateCalledVisitor.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CollectionQueryUpdateCalledVisitor.java @@ -22,123 +22,45 @@ import com.siyeh.ig.psiutils.ExpectedTypeUtils; import com.siyeh.ig.psiutils.ParenthesesUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.HashSet; import java.util.List; import java.util.Set; -class CollectionQueryCalledVisitor extends JavaRecursiveElementVisitor { +class CollectionQueryUpdateCalledVisitor extends JavaRecursiveElementVisitor { private static final HashSet COLLECTIONS_QUERIES = ContainerUtil.newHashSet("binarySearch", "disjoint", "frequency", "indexOfSubList", "lastIndexOfSubList", "max", "min", "nCopies", "unmodifiableList", "unmodifiableMap", "unmodifiableNavigableMap", "unmodifiableNavigableSet", "unmodifiableSet", "unmodifiableSortedMap", "unmodifiableSortedSet"); - static final HashSet COLLECTIONS_TRANSFORMS = + private static final HashSet COLLECTIONS_TRANSFORMS = ContainerUtil.newHashSet("asLifoQueue", "checkedCollection", "checkedList", "checkedMap", "checkedNavigableMap", "checkedNavigableSet", "checkedQueue", "checkedSet", "checkedSortedMap", "checkedSortedSet", "enumeration", "newSetFromMap", "synchronizedCollection", "singleton", "singletonList", "singletonMap", "singletonSpliterator", "synchronizedList", "synchronizedMap", "synchronizedNavigableMap", "synchronizedNavigableSet", "synchronizedSet", "synchronizedSortedMap", "synchronizedSortedSet", "unmodifiableCollection"); + @NonNls private final Set myQueryUpdateNames; + private final boolean myCheckForQuery; - - @NonNls private final Set queryNames; - - private boolean queried = false; + private boolean myQueriedUpdated = false; private final PsiVariable variable; - CollectionQueryCalledVisitor(PsiVariable variable, Set queryNames) { + CollectionQueryUpdateCalledVisitor(@Nullable PsiVariable variable, Set queryUpdateNames, boolean checkForQuery) { this.variable = variable; - this.queryNames = queryNames; + myQueryUpdateNames = queryUpdateNames; + myCheckForQuery = checkForQuery; } @Override public void visitElement(@NotNull PsiElement element) { - if (!queried) { + if (!myQueriedUpdated) { super.visitElement(element); } } - @Override - public void visitForeachStatement(@NotNull PsiForeachStatement statement) { - if (queried) { - return; - } - super.visitForeachStatement(statement); - final PsiExpression qualifier = statement.getIteratedValue(); - checkExpression(qualifier); - } - - @Override - public void visitMethodCallExpression( - @NotNull PsiMethodCallExpression call) { - if (queried) { - return; - } - super.visitMethodCallExpression(call); - final PsiReferenceExpression methodExpression = - call.getMethodExpression(); - final boolean isStatement = call.getParent() instanceof PsiExpressionStatement; - if (isStatement && !isQueryMethodName(methodExpression.getReferenceName())) { - return; - } - final PsiExpression qualifier = methodExpression.getQualifierExpression(); - checkExpression(qualifier); - } - - @Override - public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { - if (queried) return; - final String methodName = expression.getReferenceName(); - if (!isQueryMethodName(methodName)) { - final PsiElement target = expression.resolve(); - if (!(target instanceof PsiMethod)) { - return; - } - final PsiMethod method = (PsiMethod)target; - final PsiType returnType = method.getReturnType(); - if (PsiType.VOID.equals(returnType)) { - return; - } - final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression, false); - if (!(expectedType instanceof PsiClassType)) { - return; - } - final PsiClassType classType = (PsiClassType)expectedType; - final PsiClass aClass = classType.resolve(); - if (aClass == null || LambdaHighlightingUtil.checkInterfaceFunctional(aClass) != null) { - return; - } - final List candidates = LambdaUtil.findFunctionCandidates(aClass); - if (candidates == null || candidates.size() != 1) { - return; - } - final HierarchicalMethodSignature signature = candidates.get(0); - final PsiMethod functionalMethod = signature.getMethod(); - if (PsiType.VOID.equals(functionalMethod.getReturnType())) { - return; - } - } - checkExpression(expression.getQualifierExpression()); - } - - private boolean isQueryMethodName(String methodName) { - if (methodName == null) { - return false; - } - if (queryNames.contains(methodName)) { - return true; - } - for (String queryName : queryNames) { - if (methodName.startsWith(queryName)) { - return true; - } - } - return false; - } - - @Override public void visitReferenceExpression(PsiReferenceExpression expression) { super.visitReferenceExpression(expression); @@ -154,19 +76,36 @@ class CollectionQueryCalledVisitor extends JavaRecursiveElementVisitor { final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)grandParent; final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); final String name = methodExpression.getReferenceName(); - if (COLLECTIONS_QUERIES.contains(name) || COLLECTIONS_TRANSFORMS.contains(name)) { - if (methodCallExpression.getParent() instanceof PsiExpressionStatement) { - return; + if (myCheckForQuery) { + if (COLLECTIONS_QUERIES.contains(name) || COLLECTIONS_TRANSFORMS.contains(name)) { + if (methodCallExpression.getParent() instanceof PsiExpressionStatement) { + return; + } } - } - else if ("addAll".equals(name) || "copy".equals(name) || "fill".equals(name) || "replaceAll".equals(name)) { - final PsiExpression[] arguments = expressionList.getExpressions(); - if (arguments.length < 2 || PsiTreeUtil.isAncestor(arguments[0], expression, false)) { + else if ("addAll".equals(name) || "copy".equals(name) || "fill".equals(name) || "replaceAll".equals(name)) { + final PsiExpression[] arguments = expressionList.getExpressions(); + if (arguments.length < 2 || PsiTreeUtil.isAncestor(arguments[0], expression, false)) { + return; + } + } + else { return; } } else { - return; + if ("addAll".equals(name) || "fill".equals(name) || "copy".equals(name) || "replaceAll".equals(name)) { + if (!PsiTreeUtil.isAncestor(expressionList.getExpressions()[0], expression, false)) { + return; + } + } + else if (COLLECTIONS_TRANSFORMS.contains(name)) { + if (methodCallExpression.getParent() instanceof PsiExpressionStatement) { + return; + } + } + else { + return; + } } final PsiMethod method = methodCallExpression.resolveMethod(); if (method == null) { @@ -183,11 +122,96 @@ class CollectionQueryCalledVisitor extends JavaRecursiveElementVisitor { checkExpression(expression); } - private void checkExpression(PsiExpression expression) { - if (queried) { + @Override + public void visitForeachStatement(@NotNull PsiForeachStatement statement) { + super.visitForeachStatement(statement); + if (myQueriedUpdated || !myCheckForQuery) { return; } - if (expression instanceof PsiReferenceExpression) { + final PsiExpression qualifier = statement.getIteratedValue(); + checkExpression(qualifier); + } + + @Override + public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { + super.visitMethodReferenceExpression(expression); + if (myQueriedUpdated) { + return; + } + final String methodName = expression.getReferenceName(); + if (!isQueryUpdateMethodName(methodName)) { + if (myCheckForQuery) { + final PsiElement target = expression.resolve(); + if (!(target instanceof PsiMethod)) { + return; + } + final PsiMethod method = (PsiMethod)target; + final PsiType returnType = method.getReturnType(); + if (PsiType.VOID.equals(returnType)) { + return; + } + final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression, false); + if (!(expectedType instanceof PsiClassType)) { + return; + } + final PsiClassType classType = (PsiClassType)expectedType; + final PsiClass aClass = classType.resolve(); + if (aClass == null || LambdaHighlightingUtil.checkInterfaceFunctional(aClass) != null) { + return; + } + final List candidates = LambdaUtil.findFunctionCandidates(aClass); + if (candidates == null || candidates.size() != 1) { + return; + } + final HierarchicalMethodSignature signature = candidates.get(0); + final PsiMethod functionalMethod = signature.getMethod(); + if (PsiType.VOID.equals(functionalMethod.getReturnType())) { + return; + } + } + else { + return; + } + } + checkExpression(expression.getQualifierExpression()); + } + + @Override + public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) { + if (myQueriedUpdated) { + return; + } + super.visitMethodCallExpression(call); + final PsiReferenceExpression methodExpression = + call.getMethodExpression(); + final boolean isStatement = call.getParent() instanceof PsiExpressionStatement; + if ((!myCheckForQuery || isStatement) && !isQueryUpdateMethodName(methodExpression.getReferenceName())) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + checkExpression(qualifier); + } + + private boolean isQueryUpdateMethodName(String methodName) { + if (methodName == null) { + return false; + } + if (myQueryUpdateNames.contains(methodName)) { + return true; + } + for (String updateName : myQueryUpdateNames) { + if (methodName.startsWith(updateName)) { + return true; + } + } + return false; + } + + private void checkExpression(PsiExpression expression) { + if (myQueriedUpdated) { + return; + } + if (variable != null && expression instanceof PsiReferenceExpression) { final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression; final PsiElement referent = referenceExpression.resolve(); @@ -195,7 +219,7 @@ class CollectionQueryCalledVisitor extends JavaRecursiveElementVisitor { return; } if (referent.equals(variable)) { - queried = true; + myQueriedUpdated = true; } } else if (expression instanceof PsiParenthesizedExpression) { @@ -209,12 +233,18 @@ class CollectionQueryCalledVisitor extends JavaRecursiveElementVisitor { final PsiExpression thenExpression = conditionalExpression.getThenExpression(); checkExpression(thenExpression); - final PsiExpression elseExpression = conditionalExpression.getElseExpression(); + final PsiExpression elseExpression = + conditionalExpression.getElseExpression(); checkExpression(elseExpression); } + else if (variable == null) { + if (expression == null || expression instanceof PsiThisExpression || expression instanceof PsiSuperExpression) { + myQueriedUpdated = true; + } + } } - public boolean isQueried() { - return queried; + public boolean isQueriedUpdated() { + return myQueriedUpdated; } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CollectionUpdateCalledVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CollectionUpdateCalledVisitor.java deleted file mode 100644 index 5f368b972e23..000000000000 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CollectionUpdateCalledVisitor.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.siyeh.ig.bugs; - -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; -import com.siyeh.ig.psiutils.ParenthesesUtils; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Set; - -class CollectionUpdateCalledVisitor extends JavaRecursiveElementVisitor { - - @NonNls private final Set updateNames; - - private boolean updated = false; - private final PsiVariable variable; - - CollectionUpdateCalledVisitor(@Nullable PsiVariable variable, Set updateNames) { - this.variable = variable; - this.updateNames = updateNames; - } - - @Override - public void visitElement(@NotNull PsiElement element) { - if (!updated) { - super.visitElement(element); - } - } - - @Override - public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { - super.visitMethodReferenceExpression(expression); - if (updated) return; - final String methodName = expression.getReferenceName(); - if (checkMethodName(methodName)) return; - checkQualifier(expression.getQualifierExpression()); - } - - @Override - public void visitMethodCallExpression( - @NotNull PsiMethodCallExpression call) { - super.visitMethodCallExpression(call); - if (updated) { - return; - } - final PsiReferenceExpression methodExpression = - call.getMethodExpression(); - final String methodName = methodExpression.getReferenceName(); - if (checkMethodName(methodName)) return; - final PsiExpression qualifier = methodExpression.getQualifierExpression(); - checkQualifier(qualifier); - } - - private boolean checkMethodName(String methodName) { - if (methodName == null) { - return true; - } - if (!updateNames.contains(methodName)) { - boolean found = false; - for (String updateName : updateNames) { - if (!methodName.startsWith(updateName)) { - continue; - } - found = true; - break; - } - if (!found) { - return true; - } - } - return false; - } - - private void checkQualifier(PsiExpression expression) { - if (updated) { - return; - } - if (variable != null && expression instanceof PsiReferenceExpression) { - final PsiReferenceExpression referenceExpression = - (PsiReferenceExpression)expression; - final PsiElement referent = referenceExpression.resolve(); - if (referent == null) { - return; - } - if (referent.equals(variable)) { - updated = true; - } - } - else if (expression instanceof PsiParenthesizedExpression) { - final PsiParenthesizedExpression parenthesizedExpression = - (PsiParenthesizedExpression)expression; - checkQualifier(parenthesizedExpression.getExpression()); - } - else if (expression instanceof PsiConditionalExpression) { - final PsiConditionalExpression conditionalExpression = - (PsiConditionalExpression)expression; - final PsiExpression thenExpression = - conditionalExpression.getThenExpression(); - checkQualifier(thenExpression); - final PsiExpression elseExpression = - conditionalExpression.getElseExpression(); - checkQualifier(elseExpression); - } - else if (variable == null) { - if (expression == null || expression instanceof PsiThisExpression || expression instanceof PsiSuperExpression) { - updated = true; - } - } - } - - public boolean isUpdated() { - return updated; - } - - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - final PsiElement parent = ParenthesesUtils.getParentSkipParentheses(expression); - if (!(parent instanceof PsiExpressionList)) { - return; - } - final PsiExpressionList expressionList = (PsiExpressionList)parent; - final PsiElement grandParent = expressionList.getParent(); - if (!(grandParent instanceof PsiMethodCallExpression)) { - return; - } - final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)grandParent; - final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); - final String name = methodExpression.getReferenceName(); - - if ("addAll".equals(name) || "fill".equals(name) || "copy".equals(name) || "replaceAll".equals(name)) { - if (!PsiTreeUtil.isAncestor(expressionList.getExpressions()[0], expression, false)) { - return; - } - } - else if (CollectionQueryCalledVisitor.COLLECTIONS_TRANSFORMS.contains(name)) { - if (methodCallExpression.getParent() instanceof PsiExpressionStatement) { - return; - } - } - else { - return; - } - final PsiMethod method = methodCallExpression.resolveMethod(); - if (method == null) { - return; - } - final PsiClass aClass = method.getContainingClass(); - if (aClass == null) { - return; - } - final String qualifiedName = aClass.getQualifiedName(); - if (!"java.util.Collections".equals(qualifiedName)) { - return; - } - checkQualifier(expression); - } -} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedCollectionQueryUpdateInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedCollectionQueryUpdateInspectionBase.java index 1099e2506d8c..147117c186f9 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedCollectionQueryUpdateInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedCollectionQueryUpdateInspectionBase.java @@ -273,16 +273,16 @@ public class MismatchedCollectionQueryUpdateInspectionBase extends BaseInspectio return collectionQueriedByAssignment(variable, context); } - private boolean collectionQueryCalled(PsiVariable variable, PsiElement context) { - final CollectionQueryCalledVisitor visitor = new CollectionQueryCalledVisitor(variable, queryNames); + private boolean collectionQueryCalled(PsiVariable variable, PsiElement context) { + final CollectionQueryUpdateCalledVisitor visitor = new CollectionQueryUpdateCalledVisitor(variable, queryNames, true); context.accept(visitor); - return visitor.isQueried(); + return visitor.isQueriedUpdated(); } private boolean collectionUpdateCalled(@Nullable PsiVariable variable, PsiElement context) { - final CollectionUpdateCalledVisitor visitor = new CollectionUpdateCalledVisitor(variable, updateNames); + final CollectionQueryUpdateCalledVisitor visitor = new CollectionQueryUpdateCalledVisitor(variable, updateNames, false); context.accept(visitor); - return visitor.isUpdated(); + return visitor.isQueriedUpdated(); } } }