mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
restore classes merge with fix of foreach processing
This commit is contained in:
+133
-103
@@ -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<String> COLLECTIONS_QUERIES =
|
||||
ContainerUtil.newHashSet("binarySearch", "disjoint", "frequency", "indexOfSubList", "lastIndexOfSubList", "max", "min", "nCopies",
|
||||
"unmodifiableList", "unmodifiableMap", "unmodifiableNavigableMap", "unmodifiableNavigableSet",
|
||||
"unmodifiableSet", "unmodifiableSortedMap", "unmodifiableSortedSet");
|
||||
|
||||
static final HashSet<String> COLLECTIONS_TRANSFORMS =
|
||||
private static final HashSet<String> 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<String> myQueryUpdateNames;
|
||||
private final boolean myCheckForQuery;
|
||||
|
||||
|
||||
@NonNls private final Set<String> queryNames;
|
||||
|
||||
private boolean queried = false;
|
||||
private boolean myQueriedUpdated = false;
|
||||
private final PsiVariable variable;
|
||||
|
||||
CollectionQueryCalledVisitor(PsiVariable variable, Set<String> queryNames) {
|
||||
CollectionQueryUpdateCalledVisitor(@Nullable PsiVariable variable, Set<String> 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<HierarchicalMethodSignature> 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<HierarchicalMethodSignature> 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;
|
||||
}
|
||||
}
|
||||
|
||||
-174
@@ -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<String> updateNames;
|
||||
|
||||
private boolean updated = false;
|
||||
private final PsiVariable variable;
|
||||
|
||||
CollectionUpdateCalledVisitor(@Nullable PsiVariable variable, Set<String> 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);
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user