diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index fa0bf07ab766..dd623b0c42cc 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -1123,13 +1123,6 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (constValue != null) { return constValue; } - DfaVariableValue qualifier = var.getQualifier(); - if (qualifier != null) { - DfaValue value = SpecialField.tryCreateValue(qualifier, var.getPsiVariable()); - if (value != null) { - return value; - } - } return var; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/SpecialField.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/SpecialField.java index 024a621a8cd0..a74987affffa 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/SpecialField.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/SpecialField.java @@ -7,7 +7,10 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.MethodUtils; +import one.util.streamex.StreamEx; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.List; @@ -22,10 +25,10 @@ import static com.intellij.codeInspection.dataFlow.MethodContract.ValueConstrain public enum SpecialField implements DfaVariableSource { ARRAY_LENGTH(null, "length", true, LongRangeSet.indexRange()) { @Override - public boolean isMyAccessor(PsiModifierListOwner accessor) { - return accessor instanceof PsiField && "length".equals(((PsiField)accessor).getName()) && + boolean isMyAccessor(PsiMember accessor) { + return accessor instanceof PsiField && "length".equals(accessor.getName()) && JavaPsiFacade.getElementFactory(accessor.getProject()).getArrayClass(PsiUtil.getLanguageLevel(accessor)) == - ((PsiField)accessor).getContainingClass(); + accessor.getContainingClass(); } @Override @@ -98,21 +101,20 @@ public enum SpecialField implements DfaVariableSource { * @param accessor accessor to test to test * @return true if supplied accessor can be used to read this special field */ - public boolean isMyAccessor(PsiModifierListOwner accessor) { + boolean isMyAccessor(PsiMember accessor) { return accessor instanceof PsiMethod && MethodUtils.methodMatches((PsiMethod)accessor, myClassName, null, myMethodName); } - public static DfaValue tryCreateValue(DfaValue qualifier, PsiElement element) { - if (qualifier == null) return null; - DfaValueFactory factory = qualifier.getFactory(); - if (factory == null) return null; - if (!(element instanceof PsiVariable) && !(element instanceof PsiMethod)) return null; - for (SpecialField field : values()) { - if (field.isMyAccessor((PsiModifierListOwner)element)) { - return field.createValue(factory, qualifier); - } - } - return null; + /** + * Finds a special field which corresponds to given accessor (method or field) + * @param accessor accessor to find a special field for + * @return found special field or null if accessor cannot be used to access a special field + */ + @Contract("null -> null") + @Nullable + public static SpecialField findSpecialField(PsiElement accessor) { + if (!(accessor instanceof PsiMember)) return null; + return StreamEx.of(values()).findFirst(sf -> sf.isMyAccessor((PsiMember)accessor)).orElse(null); } /** diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 564fb251bc16..2067d11e4508 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -503,9 +503,9 @@ public class StandardInstructionVisitor extends InstructionVisitor { if (methodType == MethodCallInstruction.MethodType.METHOD_REFERENCE_CALL && qualifierValue instanceof DfaVariableValue) { PsiMethod method = instruction.getTargetMethod(); - DfaValue value = SpecialField.tryCreateValue(qualifierValue, method); - if (value != null) { - return value; + SpecialField field = SpecialField.findSpecialField(method); + if (field != null) { + return field.createValue(factory, qualifierValue); } DfaVariableSource source = DfaExpressionFactory.getAccessedVariableOrGetter(method); if (source != null) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java index af6716f73ff4..2a9ca0176e36 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java @@ -199,8 +199,7 @@ public class MethodCallInstruction extends Instruction { private boolean isPureCall() { if (myTargetMethod == null) return false; - return ControlFlowAnalyzer.isPure(myTargetMethod) || - Arrays.stream(SpecialField.values()).anyMatch(sf -> sf.isMyAccessor(myTargetMethod)); + return ControlFlowAnalyzer.isPure(myTargetMethod) || SpecialField.findSpecialField(myTargetMethod) != null; } @Nullable diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java index ae5fc1775345..498214a5a74b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java @@ -197,8 +197,11 @@ public class DfaExpressionFactory { private DfaValue createFromSpecialField(PsiReferenceExpression refExpr) { PsiElement target = refExpr.resolve(); if (!(target instanceof PsiModifierListOwner)) return null; + SpecialField sf = SpecialField.findSpecialField(target); + if (sf == null) return null; DfaVariableValue qualifier = getQualifierVariable(refExpr.getQualifierExpression()); - return SpecialField.tryCreateValue(qualifier, target); + if (qualifier == null) return null; + return sf.createValue(myFactory, qualifier); } @Contract("null -> null")