DFA instruction visitor refactoring wave#4

DataFlowInstructionVisitor#visitPush -> visitReferenceExpression
This commit is contained in:
Tagir Valeev
2018-06-15 15:24:18 +07:00
parent f9bfad8296
commit 7d782370e3
3 changed files with 40 additions and 45 deletions
@@ -503,24 +503,19 @@ public class DataFlowInspectionBase extends AbstractBaseJavaLocalInspectionTool
}
private void reportConstantReferenceValues(ProblemsHolder holder, DataFlowInstructionVisitor visitor, Set<PsiElement> reportedAnchors) {
for (Pair<PsiReferenceExpression, DfaConstValue> 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<LocalQuickFix> 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 <code>#ref</code> #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<PsiElement> reportedAnchors) {
@@ -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<NullabilityProblemKind.NullabilityProblem<?>, StateInfo> myStateInfos = new LinkedHashMap<>();
private final Set<Instruction> myCCEInstructions = ContainerUtil.newHashSet();
private final Map<PsiCallExpression, Boolean> myFailingCalls = new HashMap<>();
@@ -34,7 +31,7 @@ final class DataFlowInstructionVisitor extends StandardInstructionVisitor {
private final Map<PsiAssignmentExpression, Pair<PsiType, PsiType>> myArrayStoreProblems = new HashMap<>();
private final Map<PsiMethodReferenceExpression, DfaValue> myMethodReferenceResults = new HashMap<>();
private final Map<PsiArrayAccessExpression, ThreeState> myOutOfBoundsArrayAccesses = new HashMap<>();
private final MultiMap<PushInstruction, Object> myPossibleVariableValues = MultiMap.createSet();
private final Map<PsiReferenceExpression, DfaConstValue> myValues = new HashMap<>();
private final Set<PsiElement> myReceiverMutabilityViolation = new HashSet<>();
private final Set<PsiElement> myArgumentMutabilityViolation = new HashSet<>();
private final Map<PsiExpression, Boolean> 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<Pair<PsiReferenceExpression, DfaConstValue>> getConstantReferenceValues() {
List<Pair<PsiReferenceExpression, DfaConstValue>> result = ContainerUtil.newArrayList();
for (PushInstruction instruction : myPossibleVariableValues.keySet()) {
Collection<Object> 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<PsiReferenceExpression, DfaConstValue> 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;
@@ -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;
}
}