/*
- * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2016 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.
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
import com.intellij.psi.*;
-import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.CloneUtils;
-import com.siyeh.ig.psiutils.VariableAccessUtils;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
return;
}
final PsiClass containingClass = PsiUtil.getTopLevelClass(field);
- if (!checkVariable(field, containingClass)) {
+ if (!shouldCheckVariable(field, containingClass)) {
return;
}
- final boolean written = arrayContentsAreWritten(field, containingClass);
- final boolean read = arrayContentsAreRead(field, containingClass);
- if (written == read) {
+ final ArrayReadWriteVisitor visitor = new ArrayReadWriteVisitor(field, !isSimpleArrayExpression(field.getInitializer()));
+ containingClass.accept(visitor);
+ final boolean written = visitor.isWritten();
+ if (!visitor.isReferenced() || written == visitor.isRead()) {
return;
}
registerFieldError(field, Boolean.valueOf(written));
public void visitLocalVariable(@NotNull PsiLocalVariable variable) {
super.visitLocalVariable(variable);
final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
- if (!checkVariable(variable, codeBlock)) {
+ if (!shouldCheckVariable(variable, codeBlock)) {
return;
}
- final boolean written = arrayContentsAreWritten(variable, codeBlock);
- final boolean read = arrayContentsAreRead(variable, codeBlock);
- if (written == read) {
+ final ArrayReadWriteVisitor visitor = new ArrayReadWriteVisitor(variable, !isSimpleArrayExpression(variable.getInitializer()));
+ codeBlock.accept(visitor);
+ final boolean written = visitor.isWritten();
+ if (!visitor.isReferenced() || written == visitor.isRead()) {
return;
}
registerVariableError(variable, Boolean.valueOf(written));
}
- private static boolean checkVariable(PsiVariable variable,
- PsiElement context) {
- if (context == null) {
- return false;
- }
- final PsiType type = variable.getType();
- if (type.getArrayDimensions() == 0) {
- return false;
- }
- if (VariableAccessUtils.variableIsAssigned(variable, context)) {
+ private static boolean shouldCheckVariable(PsiVariable variable, PsiElement context) {
+ return context != null && variable.getType().getArrayDimensions() != 0 && !isComplexArrayExpression(variable.getInitializer());
+ }
+
+ static boolean isComplexArrayExpression(PsiExpression expression) {
+ expression = ParenthesesUtils.stripParentheses(expression);
+ if (expression == null) {
return false;
}
- if (VariableAccessUtils.variableIsAssignedFrom(variable, context)) {
- return false;
+ if (expression instanceof PsiNewExpression) {
+ final PsiNewExpression newExpression = (PsiNewExpression)expression;
+ final PsiArrayInitializerExpression arrayInitializer = newExpression.getArrayInitializer();
+ return isComplexArrayExpression(arrayInitializer);
}
- if (VariableAccessUtils.variableIsReturned(variable, context)) {
+ else if (expression instanceof PsiArrayInitializerExpression) {
+ final PsiArrayInitializerExpression arrayInitializerExpression = (PsiArrayInitializerExpression)expression;
+ for (PsiExpression initializer : arrayInitializerExpression.getInitializers()) {
+ if (isComplexArrayExpression(initializer)) {
+ return true;
+ }
+ }
return false;
}
- return !VariableAccessUtils.variableIsUsedInArrayInitializer(variable, context);
- }
-
- private static boolean arrayContentsAreWritten(PsiVariable variable,
- PsiElement context) {
- if (VariableAccessUtils.arrayContentsAreAssigned(variable, context)) {
- return true;
- }
- if (!isDefaultArrayInitializer(variable.getInitializer())) {
- return true;
+ else if (expression instanceof PsiReferenceExpression) {
+ return expression.getType() instanceof PsiArrayType;
}
- return variableIsWritten(variable, context);
- }
-
- private static boolean arrayContentsAreRead(PsiVariable variable,
- PsiElement context) {
- if (VariableAccessUtils.arrayContentsAreAccessed(variable, context)) {
+ else if (expression instanceof PsiArrayAccessExpression) {
return true;
}
- if (isPossiblyReferenceThatIsReadLater(variable.getInitializer())) {
- return true;
+ else if (expression instanceof PsiTypeCastExpression) {
+ final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression)expression;
+ return isComplexArrayExpression(typeCastExpression.getOperand());
}
- return variableIsRead(variable, context);
- }
-
- private static boolean isPossiblyReferenceThatIsReadLater(PsiExpression initializer) {
- if (initializer == null || initializer instanceof PsiNewExpression || initializer instanceof PsiArrayInitializerExpression) {
- return false;
+ else if (expression instanceof PsiConditionalExpression) {
+ final PsiConditionalExpression conditionalExpression = (PsiConditionalExpression)expression;
+ return isComplexArrayExpression(conditionalExpression.getThenExpression()) ||
+ isComplexArrayExpression(conditionalExpression.getElseExpression());
}
- if (initializer instanceof PsiMethodCallExpression) {
- final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)initializer;
+ else if (expression instanceof PsiMethodCallExpression) {
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
final PsiMethod method = methodCallExpression.resolveMethod();
if (method == null) {
return true;
return false;
}
@NonNls final String name = method.getName();
- if (!"copyOf".equals(name) && !"copyOfRange".equals(name)) {
- return true;
+ if ("copyOf".equals(name) || "copyOfRange".equals(name)) {
+ final PsiClass aClass = method.getContainingClass();
+ if (aClass != null && CommonClassNames.JAVA_UTIL_ARRAYS.equals(aClass.getQualifiedName())) {
+ return false;
+ }
+ }
+ else if ("toArray".equals(name) && InheritanceUtil.isInheritor(method.getContainingClass(), "java.util.Collection")) {
+ return false;
}
- final PsiClass aClass = method.getContainingClass();
- return aClass == null || !CommonClassNames.JAVA_UTIL_ARRAYS.equals(aClass.getQualifiedName());
+ return true;
}
return true;
}
- private static boolean isDefaultArrayInitializer(PsiExpression initializer) {
+ static boolean isSimpleArrayExpression(PsiExpression initializer) {
if (initializer == null) {
return true;
}
if (initializer instanceof PsiNewExpression) {
final PsiNewExpression newExpression = (PsiNewExpression)initializer;
final PsiArrayInitializerExpression arrayInitializer = newExpression.getArrayInitializer();
- return arrayInitializer == null || isDefaultArrayInitializer(arrayInitializer);
+ return arrayInitializer == null || isSimpleArrayExpression(arrayInitializer);
}
if (initializer instanceof PsiArrayInitializerExpression) {
final PsiArrayInitializerExpression arrayInitializerExpression = (PsiArrayInitializerExpression)initializer;
return false;
}
- private static boolean variableIsWritten(@NotNull PsiVariable variable, @NotNull PsiElement context) {
- final VariableReadWriteVisitor visitor = new VariableReadWriteVisitor(variable, true);
- context.accept(visitor);
- return visitor.isPassed();
- }
-
- private static boolean variableIsRead(@NotNull PsiVariable variable, @NotNull PsiElement context) {
- final VariableReadWriteVisitor visitor =
- new VariableReadWriteVisitor(variable, false);
- context.accept(visitor);
- return visitor.isPassed();
- }
-
- private static class VariableReadWriteVisitor extends JavaRecursiveElementWalkingVisitor {
+ private static class ArrayReadWriteVisitor extends JavaRecursiveElementWalkingVisitor {
+ private final PsiVariable myVariable;
+ private boolean myWritten;
+ private boolean myRead = false;
+ private boolean myIsReferenced = false;
- @NotNull
- private final PsiVariable variable;
- private final boolean write;
- private boolean passed;
-
- private VariableReadWriteVisitor(@NotNull PsiVariable variable, boolean write) {
- this.variable = variable;
- this.write = write;
+ ArrayReadWriteVisitor(@NotNull PsiVariable variable, boolean written) {
+ myVariable = variable;
+ myWritten = written;
}
@Override
- public void visitElement(@NotNull PsiElement element) {
- if (!passed) {
- super.visitElement(element);
+ public void visitReferenceExpression(PsiReferenceExpression expression) {
+ if (myWritten && myRead) {
+ return;
}
- }
-
- @Override
- public void visitBinaryExpression(PsiBinaryExpression expression) {
- super.visitBinaryExpression(expression);
- if (write || passed) {
+ super.visitReferenceExpression(expression);
+ final PsiElement target = expression.resolve();
+ if (target != myVariable) {
return;
}
- final IElementType tokenType = expression.getOperationTokenType();
- if (!JavaTokenType.EQEQ.equals(tokenType) && !JavaTokenType.NE.equals(tokenType)) {
+ if (PsiUtil.isAccessedForWriting(expression)) {
+ final PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class);
+ if (parent instanceof PsiAssignmentExpression) {
+ final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent;
+ final PsiExpression rhs = assignmentExpression.getRExpression();
+ if (isComplexArrayExpression(rhs)) {
+ myWritten = true;
+ myRead = true;
+ }
+ else if (!isSimpleArrayExpression(rhs)) {
+ myWritten = true;
+ }
+ }
return;
}
- final PsiExpression lhs = expression.getLOperand();
- if (!(lhs instanceof PsiBinaryExpression)) {
- if (VariableAccessUtils.mayEvaluateToVariable(lhs, variable)) {
- passed = true;
+ myIsReferenced = true;
+ PsiElement parent = getParent(expression);
+ if (parent instanceof PsiArrayAccessExpression) {
+ PsiArrayAccessExpression arrayAccessExpression = (PsiArrayAccessExpression)parent;
+ parent = getParent(parent);
+ while (parent instanceof PsiArrayAccessExpression) {
+ arrayAccessExpression = (PsiArrayAccessExpression)parent;
+ parent = getParent(parent);
+ }
+ final PsiType type = arrayAccessExpression.getType();
+ if (type != null) {
+ final int dimensions = type.getArrayDimensions();
+ if (dimensions > 0 && dimensions != myVariable.getType().getArrayDimensions()) {
+ myWritten = true;
+ }
+ }
+ if (PsiUtil.isAccessedForWriting(arrayAccessExpression)) {
+ myWritten = true;
+ }
+ if (PsiUtil.isAccessedForReading(arrayAccessExpression)) {
+ myRead = true;
}
}
- final PsiExpression rhs = expression.getROperand();
- if (!(rhs instanceof PsiBinaryExpression)) {
- if (VariableAccessUtils.mayEvaluateToVariable(rhs, variable)) {
- passed = true;
+ else if (parent instanceof PsiReferenceExpression) {
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)parent;
+ final String name = referenceExpression.getReferenceName();
+ if ("length".equals(name) || ("clone".equals(name) && referenceExpression.getParent() instanceof PsiMethodCallExpression)) {
+ myRead = true;
}
}
- }
-
- @Override
- public void visitMethodCallExpression(
- @NotNull PsiMethodCallExpression call) {
- if (passed) {
- return;
+ else if (parent instanceof PsiForeachStatement) {
+ final PsiForeachStatement foreachStatement = (PsiForeachStatement)parent;
+ final PsiExpression iteratedValue = foreachStatement.getIteratedValue();
+ if (PsiTreeUtil.isAncestor(iteratedValue, expression, false)) {
+ myRead = true;
+ }
}
- super.visitMethodCallExpression(call);
- final PsiExpressionList argumentList = call.getArgumentList();
- final PsiExpression[] arguments = argumentList.getExpressions();
- for (int i = 0; i < arguments.length; i++) {
- final PsiExpression argument = arguments[i];
- if (VariableAccessUtils.mayEvaluateToVariable(argument, variable)) {
- if (write && i == 0 && isCallToSystemArraycopy(call)) {
- return;
- }
- if (!write && i == 2 && isCallToSystemArraycopy(call)) {
- return;
+ else if (parent instanceof PsiExpressionList) {
+ final PsiExpressionList expressionList = (PsiExpressionList)parent;
+ parent = parent.getParent();
+ if (parent instanceof PsiMethodCallExpression) {
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)parent;
+ final PsiMethod method = methodCallExpression.resolveMethod();
+ if (method != null) {
+ final PsiClass aClass = method.getContainingClass();
+ if (aClass != null) {
+ final String methodName = method.getName();
+ final String qualifiedName = aClass.getQualifiedName();
+ if ("java.lang.System".equals(qualifiedName)) {
+ if ("arraycopy".equals(methodName)) {
+ final PsiExpression[] expressions = expressionList.getExpressions();
+ if (expressions.length == 5) {
+ if (PsiTreeUtil.isAncestor(expressions[0], expression, false)) {
+ myRead = true;
+ return;
+ }
+ else if (PsiTreeUtil.isAncestor(expressions[2], expression, false)) {
+ myWritten = true;
+ return;
+ }
+ }
+ }
+ }
+ else if (CommonClassNames.JAVA_UTIL_ARRAYS.equals(qualifiedName)) {
+ if ("fill".equals(methodName) || "parallelPrefix".equals(methodName) || "parallelSetAll".equals(methodName) ||
+ "parallelSort".equals(methodName) || "setAll".equals(methodName) || "sort".equals(methodName)) {
+ myWritten = true;
+ }
+ else {
+ myRead = true;
+ }
+ return;
+ }
+ }
}
- passed = true;
}
+ myRead = true;
+ myWritten = true;
}
- }
-
- private static boolean isCallToSystemArraycopy(PsiMethodCallExpression call) {
- final PsiReferenceExpression methodExpression = call.getMethodExpression();
- @NonNls final String name = methodExpression.getReferenceName();
- if (!"arraycopy".equals(name)) {
- return false;
- }
- final PsiExpression qualifier = methodExpression.getQualifierExpression();
- if (!(qualifier instanceof PsiReferenceExpression)) {
- return false;
- }
- final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier;
- final PsiElement element = referenceExpression.resolve();
- if (!(element instanceof PsiClass)) {
- return false;
+ else {
+ myWritten = true;
+ myRead = true;
}
- return "java.lang.System".equals(((PsiClass)element).getQualifiedName());
}
- @Override
- public void visitNewExpression(@NotNull PsiNewExpression newExpression) {
- if (passed) {
- return;
+ private static PsiElement getParent(PsiElement element) {
+ PsiElement parent = element.getParent();
+ while (parent instanceof PsiParenthesizedExpression ||
+ parent instanceof PsiTypeCastExpression ||
+ parent instanceof PsiConditionalExpression) {
+ parent = parent.getParent();
}
- super.visitNewExpression(newExpression);
- visitPsiCall(newExpression);
+ return parent;
}
- @Override
- public void visitEnumConstant(PsiEnumConstant enumConstant) {
- if (passed) {
- return;
- }
- super.visitEnumConstant(enumConstant);
- visitPsiCall(enumConstant);
+ public boolean isRead() {
+ return myRead;
}
- private void visitPsiCall(PsiCall newExpression) {
- final PsiExpressionList argumentList = newExpression.getArgumentList();
- if (argumentList == null) {
- return;
- }
- final PsiExpression[] arguments = argumentList.getExpressions();
- for (final PsiExpression argument : arguments) {
- if (VariableAccessUtils.mayEvaluateToVariable(argument, variable)) {
- passed = true;
- }
- }
+ public boolean isWritten() {
+ return myWritten;
}
- public boolean isPassed() {
- return passed;
+ public boolean isReferenced() {
+ return myIsReferenced;
}
}
}
+++ /dev/null
-/*
- * 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.psiutils;
-
-import com.intellij.psi.*;
-import com.siyeh.HardcodedMethodConstants;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-
-class ArrayContentsAccessedVisitor extends JavaRecursiveElementWalkingVisitor {
-
- private boolean accessed;
- private final PsiVariable variable;
-
- ArrayContentsAccessedVisitor(@NotNull PsiVariable variable) {
- this.variable = variable;
- }
-
- @Override
- public void visitForeachStatement(
- @NotNull PsiForeachStatement statement) {
- if (accessed) {
- return;
- }
- super.visitForeachStatement(statement);
- final PsiExpression qualifier = statement.getIteratedValue();
- if (!(qualifier instanceof PsiReferenceExpression)) {
- return;
- }
- final PsiReferenceExpression referenceExpression =
- (PsiReferenceExpression)qualifier;
- final PsiElement target = referenceExpression.resolve();
- if (variable.equals(target)) {
- accessed = true;
- }
- }
-
- @Override
- public void visitArrayAccessExpression(
- PsiArrayAccessExpression arrayAccessExpression) {
- if (accessed) {
- return;
- }
- super.visitArrayAccessExpression(arrayAccessExpression);
- final PsiElement parent = arrayAccessExpression.getParent();
- if (parent instanceof PsiAssignmentExpression) {
- final PsiAssignmentExpression assignmentExpression =
- (PsiAssignmentExpression)parent;
- final PsiExpression lhs = assignmentExpression.getLExpression();
- if (lhs.equals(arrayAccessExpression)) {
- return;
- }
- }
- final PsiExpression arrayExpression =
- arrayAccessExpression.getArrayExpression();
- if (!(arrayExpression instanceof PsiReferenceExpression)) {
- return;
- }
- final PsiReferenceExpression referenceExpression =
- (PsiReferenceExpression)arrayExpression;
- final PsiElement target = referenceExpression.resolve();
- if (variable.equals(target)) {
- accessed = true;
- }
- }
-
- @Override
- public void visitReferenceExpression(PsiReferenceExpression expression) {
- if (accessed) {
- return;
- }
- super.visitReferenceExpression(expression);
- @NonNls final String referenceName = expression.getReferenceName();
- if (!"length".equals(referenceName)) {
- return;
- }
- final PsiExpression qualifier = expression.getQualifierExpression();
- if (!(qualifier instanceof PsiReferenceExpression)) {
- return;
- }
- final PsiReferenceExpression referenceExpression =
- (PsiReferenceExpression)qualifier;
- final PsiElement target = referenceExpression.resolve();
- if (variable.equals(target)) {
- accessed = true;
- }
- }
-
- @Override
- public void visitMethodCallExpression(PsiMethodCallExpression expression) {
- if (accessed) {
- return;
- }
- super.visitMethodCallExpression(expression);
- final PsiReferenceExpression methodExpression =
- expression.getMethodExpression();
- final String methodName = methodExpression.getReferenceName();
- if (!HardcodedMethodConstants.CLONE.equals(methodName)) {
- return;
- }
- final PsiExpressionList argumentList = expression.getArgumentList();
- if (argumentList.getExpressions().length != 0) {
- return;
- }
- final PsiExpression qualifier =
- methodExpression.getQualifierExpression();
- if (!(qualifier instanceof PsiReferenceExpression)) {
- return;
- }
- final PsiReferenceExpression referenceExpression =
- (PsiReferenceExpression)qualifier;
- final PsiElement target = referenceExpression.resolve();
- if (variable.equals(target)) {
- accessed = true;
- }
- }
-
- public boolean isAccessed() {
- return accessed;
- }
-}