mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
purity inference: be more careful with array assignments
This commit is contained in:
+27
-8
@@ -18,10 +18,10 @@ package com.intellij.codeInspection.dataFlow;
|
||||
import com.intellij.openapi.util.RecursionManager;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PropertyUtil;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -57,7 +57,7 @@ public class PurityInference {
|
||||
body.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitAssignmentExpression(PsiAssignmentExpression expression) {
|
||||
if (!isLocalVarReference(expression.getLExpression())) {
|
||||
if (!isLocalVarReference(expression.getLExpression(), method)) {
|
||||
impureFound.set(true);
|
||||
}
|
||||
super.visitAssignmentExpression(expression);
|
||||
@@ -73,7 +73,7 @@ public class PurityInference {
|
||||
|
||||
@Override
|
||||
public void visitPrefixExpression(PsiPrefixExpression expression) {
|
||||
if (isMutatingOperation(expression.getOperationTokenType()) && !isLocalVarReference(expression.getOperand())) {
|
||||
if (isMutatingOperation(expression.getOperationTokenType()) && !isLocalVarReference(expression.getOperand(), method)) {
|
||||
impureFound.set(true);
|
||||
}
|
||||
super.visitPrefixExpression(expression);
|
||||
@@ -85,7 +85,7 @@ public class PurityInference {
|
||||
|
||||
@Override
|
||||
public void visitPostfixExpression(PsiPostfixExpression expression) {
|
||||
if (isMutatingOperation(expression.getOperationTokenType()) && !isLocalVarReference(expression.getOperand())) {
|
||||
if (isMutatingOperation(expression.getOperationTokenType()) && !isLocalVarReference(expression.getOperand(), method)) {
|
||||
impureFound.set(true);
|
||||
}
|
||||
super.visitPostfixExpression(expression);
|
||||
@@ -107,14 +107,33 @@ public class PurityInference {
|
||||
return called != null && ControlFlowAnalyzer.isPure(called);
|
||||
}
|
||||
|
||||
private static boolean isLocalVarReference(PsiExpression expression) {
|
||||
private static boolean isLocalVarReference(PsiExpression expression, PsiMethod scope) {
|
||||
if (expression instanceof PsiReferenceExpression) {
|
||||
PsiElement target = ((PsiReferenceExpression)expression).resolve();
|
||||
return target instanceof PsiLocalVariable || target instanceof PsiParameter;
|
||||
}
|
||||
if (expression instanceof PsiArrayAccessExpression) {
|
||||
return isLocalVarReference(((PsiArrayAccessExpression)expression).getArrayExpression());
|
||||
PsiExpression array = ((PsiArrayAccessExpression)expression).getArrayExpression();
|
||||
PsiElement target = array instanceof PsiReferenceExpression ? ((PsiReferenceExpression)array).resolve() : null;
|
||||
return target instanceof PsiLocalVariable && isLocallyCreatedArray(scope, (PsiLocalVariable)target);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isLocallyCreatedArray(PsiMethod scope, PsiLocalVariable target) {
|
||||
PsiExpression initializer = target.getInitializer();
|
||||
if (initializer != null && !(initializer instanceof PsiNewExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (PsiReference ref : ReferencesSearch.search(target, new LocalSearchScope(scope)).findAll()) {
|
||||
if (ref instanceof PsiReferenceExpression && PsiUtil.isAccessedForWriting((PsiReferenceExpression)ref)) {
|
||||
PsiAssignmentExpression assign = PsiTreeUtil.getParentOfType((PsiReferenceExpression)ref, PsiAssignmentExpression.class);
|
||||
if (assign == null || !(assign.getRExpression() instanceof PsiNewExpression)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -92,6 +92,18 @@ int random() { return 2; }
|
||||
"""
|
||||
}
|
||||
|
||||
public void "test field array assignment as local var"() {
|
||||
assertPure false, """
|
||||
int[] randomArray() {
|
||||
int[] local = i;
|
||||
local[0] = random();
|
||||
return local;
|
||||
}
|
||||
int random() { return 2; }
|
||||
int[] i = new int[0];
|
||||
"""
|
||||
}
|
||||
|
||||
public void "test use explicit pure contract"() {
|
||||
assertPure true, """
|
||||
int method() {
|
||||
|
||||
Reference in New Issue
Block a user