diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java index 06dd5e9f32af..a3a0f1fea90e 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java @@ -503,24 +503,19 @@ public class DataFlowInspectionBase extends AbstractBaseJavaLocalInspectionTool } private void reportConstantReferenceValues(ProblemsHolder holder, DataFlowInstructionVisitor visitor, Set reportedAnchors) { - for (Pair pair : visitor.getConstantReferenceValues()) { - PsiReferenceExpression ref = pair.first; - if (ref.getParent() instanceof PsiReferenceExpression || !reportedAnchors.add(ref)) { - continue; - } + visitor.getConstantReferenceValues().forEach((ref, dfaConst) -> { + if (ref.getParent() instanceof PsiReferenceExpression || DfaConstValue.isSentinel(dfaConst)) return; + if (!reportedAnchors.add(ref)) return; - final Object value = pair.second.getValue(); - PsiVariable constant = pair.second.getConstant(); - final String presentableName = constant != null ? constant.getName() : String.valueOf(value); + final Object value = dfaConst.getValue(); + PsiVariable constant = dfaConst.getConstant(); final String exprText = String.valueOf(value); - if (presentableName == null || exprText == null) { - continue; - } + final String presentableName = constant != null ? constant.getName() : exprText; List fixes = new SmartList<>(); fixes.add(new ReplaceWithConstantValueFix(presentableName, exprText)); boolean isAssertion = value instanceof Boolean && isAssertionEffectively(ref, (Boolean)value); - if (isAssertion && DONT_REPORT_TRUE_ASSERT_STATEMENTS) continue; + if (isAssertion && DONT_REPORT_TRUE_ASSERT_STATEMENTS) return; if (holder.isOnTheFly()) { fixes.add(new SetInspectionOptionFix(this, "REPORT_CONSTANT_REFERENCE_VALUES", InspectionsBundle.message("inspection.data.flow.turn.off.constant.references.quickfix"), @@ -532,9 +527,8 @@ public class DataFlowInspectionBase extends AbstractBaseJavaLocalInspectionTool } holder.registerProblem(ref, "Value #ref #loc is always '" + presentableName + "'", - ProblemHighlightType.WEAK_WARNING, - fixes.toArray(LocalQuickFix.EMPTY_ARRAY)); - } + ProblemHighlightType.WEAK_WARNING, fixes.toArray(LocalQuickFix.EMPTY_ARRAY)); + }); } private void reportNullableArgumentsPassedToNonAnnotated(DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set reportedAnchors) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInstructionVisitor.java index 8fbc0f9bbda6..bff41c52aa5a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInstructionVisitor.java @@ -9,10 +9,8 @@ import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTypesUtil; -import com.intellij.util.ObjectUtils; import com.intellij.util.ThreeState; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.MultiMap; import com.siyeh.ig.psiutils.ExpressionUtils; import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; @@ -25,7 +23,6 @@ import static com.intellij.util.ObjectUtils.tryCast; final class DataFlowInstructionVisitor extends StandardInstructionVisitor { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.DataFlowInstructionVisitor"); - private static final Object ANY_VALUE = ObjectUtils.sentinel("ANY_VALUE"); private final Map, StateInfo> myStateInfos = new LinkedHashMap<>(); private final Set myCCEInstructions = ContainerUtil.newHashSet(); private final Map myFailingCalls = new HashMap<>(); @@ -34,7 +31,7 @@ final class DataFlowInstructionVisitor extends StandardInstructionVisitor { private final Map> myArrayStoreProblems = new HashMap<>(); private final Map myMethodReferenceResults = new HashMap<>(); private final Map myOutOfBoundsArrayAccesses = new HashMap<>(); - private final MultiMap myPossibleVariableValues = MultiMap.createSet(); + private final Map myValues = new HashMap<>(); private final Set myReceiverMutabilityViolation = new HashSet<>(); private final Set myArgumentMutabilityViolation = new HashSet<>(); private final Map mySameValueAssigned = new HashMap<>(); @@ -206,20 +203,6 @@ final class DataFlowInstructionVisitor extends StandardInstructionVisitor { } } - @Override - public DfaInstructionState[] visitPush(PushInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) { - PsiExpression place = instruction.getExpression(); - if (!instruction.isReferenceWrite() && place instanceof PsiReferenceExpression) { - DfaValue dfaValue = instruction.getValue(); - if (dfaValue instanceof DfaVariableValue) { - DfaConstValue constValue = memState.getConstantValue((DfaVariableValue)dfaValue); - boolean report = constValue != null && shouldReportConstValue(constValue.getValue()); - myPossibleVariableValues.putValue(instruction, report ? constValue : ANY_VALUE); - } - } - return super.visitPush(instruction, runner, memState); - } - @Override public DfaInstructionState[] visitEndOfInitializer(EndOfInitializerInstruction instruction, DataFlowRunner runner, DfaMemoryState state) { if (!instruction.isStatic()) { @@ -228,18 +211,8 @@ final class DataFlowInstructionVisitor extends StandardInstructionVisitor { return super.visitEndOfInitializer(instruction, runner, state); } - public List> getConstantReferenceValues() { - List> result = ContainerUtil.newArrayList(); - for (PushInstruction instruction : myPossibleVariableValues.keySet()) { - Collection values = myPossibleVariableValues.get(instruction); - if (values.size() == 1) { - Object singleValue = values.iterator().next(); - if (singleValue != ANY_VALUE) { - result.add(Pair.create((PsiReferenceExpression)instruction.getExpression(), (DfaConstValue)singleValue)); - } - } - } - return result; + public Map getConstantReferenceValues() { + return myValues; } private static boolean hasNonTrivialFailingContracts(PsiCallExpression call) { @@ -329,6 +302,24 @@ final class DataFlowInstructionVisitor extends StandardInstructionVisitor { } } + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + DfaConstValue oldValue = myValues.get(expression); + if (DfaConstValue.isSentinel(oldValue)) return; + if (myValue instanceof DfaVariableValue) { + DfaConstValue constValue = myMemState.getConstantValue((DfaVariableValue)myValue); + boolean report = constValue != null && shouldReportConstValue(constValue.getValue()); + if (!report) { + constValue = null; + } + DfaConstValue newValue = constValue != null && (oldValue == null || oldValue == constValue) + ? constValue + : myValue.getFactory().getConstFactory().getSentinel(); + myValues.put(expression, newValue); + } + } + private void handleBooleanCalls(PsiMethodCallExpression call) { ThreeState curState = myBooleanCalls.get(call); if (curState == ThreeState.UNSURE) return; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaConstValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaConstValue.java index 513914ff8dc1..193ad45ba12d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaConstValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaConstValue.java @@ -202,4 +202,14 @@ public class DfaConstValue extends DfaValue { public static boolean isContractFail(DfaValue value) { return value instanceof DfaConstValue && ((DfaConstValue)value).getValue() == ourThrowable; } + + /** + * Checks whether given value is a special internal sentinel value returned by {@link Factory#getSentinel()}. + * + * @param value value to check + * @return true if specified value is a sentinel value + */ + public static boolean isSentinel(DfaValue value) { + return value instanceof DfaConstValue && ((DfaConstValue)value).getValue() == SENTINEL; + } }