This commit is contained in:
Alexey Kudravtsev
2015-11-12 17:04:34 +03:00
parent 89b362ef96
commit 1fbf3699e4
12 changed files with 161 additions and 116 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -63,6 +63,7 @@ public class ExpressionTypeMemoryState extends DfaMemoryStateImpl {
super(toCopy);
}
@NotNull
@Override
public DfaMemoryStateImpl createCopy() {
final ExpressionTypeMemoryState copy = new ExpressionTypeMemoryState(this);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,10 +17,10 @@ package com.intellij.codeInsight.guess.impl;
import com.intellij.codeInsight.guess.GuessManager;
import com.intellij.codeInspection.dataFlow.*;
import com.intellij.codeInspection.dataFlow.instructions.PushInstruction;
import com.intellij.codeInspection.dataFlow.instructions.TypeCastInstruction;
import com.intellij.codeInspection.dataFlow.instructions.InstanceofInstruction;
import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction;
import com.intellij.codeInspection.dataFlow.instructions.PushInstruction;
import com.intellij.codeInspection.dataFlow.instructions.TypeCastInstruction;
import com.intellij.codeInspection.dataFlow.value.DfaInstanceofValue;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
@@ -31,8 +31,8 @@ import com.intellij.psi.search.PsiElementProcessorAdapter;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
@@ -151,6 +151,7 @@ public class GuessManagerImpl extends GuessManager {
}
DataFlowRunner runner = new DataFlowRunner() {
@NotNull
@Override
protected DfaMemoryState createMemoryState() {
return new ExpressionTypeMemoryState(getFactory());
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.psi.*;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@@ -39,7 +40,7 @@ class ContractChecker extends DataFlowRunner {
private final Set<PsiElement> myNonViolations = ContainerUtil.newHashSet();
private final Set<PsiElement> myFailures = ContainerUtil.newHashSet();
ContractChecker(PsiMethod method, MethodContract contract, final boolean onTheFly) {
private ContractChecker(PsiMethod method, MethodContract contract, final boolean onTheFly) {
myMethod = method;
myContract = contract;
myOnTheFly = onTheFly;
@@ -77,8 +78,9 @@ class ContractChecker extends DataFlowRunner {
return super.shouldCheckTimeLimit();
}
@NotNull
@Override
protected DfaInstructionState[] acceptInstruction(InstructionVisitor visitor, DfaInstructionState instructionState) {
protected DfaInstructionState[] acceptInstruction(@NotNull InstructionVisitor visitor, @NotNull DfaInstructionState instructionState) {
DfaMemoryState memState = instructionState.getMemoryState();
if (memState.isEphemeral()) {
return DfaInstructionState.EMPTY_ARRAY;
@@ -52,11 +52,12 @@ public class DataFlowRunner {
private Instruction[] myInstructions;
private final MultiMap<PsiElement, DfaMemoryState> myNestedClosures = new MultiMap<PsiElement, DfaMemoryState>();
@NotNull
private final DfaValueFactory myValueFactory;
// Maximum allowed attempts to process instruction. Fail as too complex to process if certain instruction
// is executed more than this limit times.
public static final int MAX_STATES_PER_BRANCH = 300;
static final int MAX_STATES_PER_BRANCH = 300;
protected DataFlowRunner() {
this(false, true);
@@ -66,12 +67,13 @@ public class DataFlowRunner {
myValueFactory = new DfaValueFactory(honorFieldInitializers, unknownMembersAreNullable);
}
@NotNull
public DfaValueFactory getFactory() {
return myValueFactory;
}
@Nullable
private Collection<DfaMemoryState> createInitialStates(@NotNull PsiElement psiBlock, InstructionVisitor visitor) {
private Collection<DfaMemoryState> createInitialStates(@NotNull PsiElement psiBlock, @NotNull InstructionVisitor visitor) {
PsiClass containingClass = PsiTreeUtil.getParentOfType(psiBlock, PsiClass.class);
if (containingClass != null && PsiUtil.isLocalOrAnonymousClass(containingClass)) {
final PsiElement parent = containingClass.getParent();
@@ -91,16 +93,17 @@ public class DataFlowRunner {
return Collections.singletonList(createMemoryState());
}
public final RunnerResult analyzeMethod(@NotNull PsiElement psiBlock, InstructionVisitor visitor) {
@NotNull
public final RunnerResult analyzeMethod(@NotNull PsiElement psiBlock, @NotNull InstructionVisitor visitor) {
Collection<DfaMemoryState> initialStates = createInitialStates(psiBlock, visitor);
return initialStates == null ? RunnerResult.NOT_APPLICABLE : analyzeMethod(psiBlock, visitor, false, initialStates);
}
@NotNull
public final RunnerResult analyzeMethod(@NotNull PsiElement psiBlock,
InstructionVisitor visitor,
boolean ignoreAssertions,
@NotNull Collection<DfaMemoryState> initialStates) {
final RunnerResult analyzeMethod(@NotNull PsiElement psiBlock,
@NotNull InstructionVisitor visitor,
boolean ignoreAssertions,
@NotNull Collection<DfaMemoryState> initialStates) {
if (PsiTreeUtil.findChildOfType(psiBlock, OuterLanguageElement.class) != null) return RunnerResult.NOT_APPLICABLE;
try {
@@ -127,7 +130,7 @@ public class DataFlowRunner {
if (LOG.isDebugEnabled()) {
LOG.debug("Analyzing code block: " + psiBlock.getText());
for (int i = 0; i < myInstructions.length; i++) {
LOG.debug(i + ": " + myInstructions[i].toString());
LOG.debug(i + ": " + myInstructions[i]);
}
}
//for (int i = 0; i < myInstructions.length; i++) System.out.println(i + ": " + myInstructions[i].toString());
@@ -220,10 +223,11 @@ public class DataFlowRunner {
private void handleStepOutOfLoop(@NotNull final Instruction prevInstruction,
@NotNull Instruction nextInstruction,
@NotNull final int[] loopNumber,
MultiMap<BranchingInstruction, DfaMemoryState> processedStates,
MultiMap<BranchingInstruction, DfaMemoryState> incomingStates,
List<DfaInstructionState> inFlightStates,
DfaInstructionState[] afterStates, StateQueue queue) {
@NotNull MultiMap<BranchingInstruction, DfaMemoryState> processedStates,
@NotNull MultiMap<BranchingInstruction, DfaMemoryState> incomingStates,
@NotNull List<DfaInstructionState> inFlightStates,
@NotNull DfaInstructionState[] afterStates,
@NotNull StateQueue queue) {
if (loopNumber[prevInstruction.getIndex()] == 0 || inSameLoop(prevInstruction, nextInstruction, loopNumber)) {
return;
}
@@ -247,10 +251,7 @@ public class DataFlowRunner {
@Override
public boolean process(DfaInstructionState state) {
Instruction instruction = state.getInstruction();
if (inSameLoop(prevInstruction, instruction, loopNumber)) {
return false;
}
return true;
return !inSameLoop(prevInstruction, instruction, loopNumber);
}
})) return;
@@ -276,7 +277,8 @@ public class DataFlowRunner {
return !ApplicationManager.getApplication().isUnitTestMode();
}
protected DfaInstructionState[] acceptInstruction(InstructionVisitor visitor, DfaInstructionState instructionState) {
@NotNull
protected DfaInstructionState[] acceptInstruction(@NotNull InstructionVisitor visitor, @NotNull DfaInstructionState instructionState) {
Instruction instruction = instructionState.getInstruction();
PsiElement closure = DfaUtil.getClosureInside(instruction);
if (closure instanceof PsiClass) {
@@ -288,7 +290,7 @@ public class DataFlowRunner {
return instruction.accept(this, instructionState.getMemoryState(), visitor);
}
private void registerNestedClosures(DfaInstructionState instructionState, PsiClass nestedClass) {
private void registerNestedClosures(@NotNull DfaInstructionState instructionState, @NotNull PsiClass nestedClass) {
DfaMemoryState state = instructionState.getMemoryState();
for (PsiMethod method : nestedClass.getMethods()) {
PsiCodeBlock body = method.getBody();
@@ -304,7 +306,7 @@ public class DataFlowRunner {
}
}
private void registerNestedClosures(DfaInstructionState instructionState, PsiLambdaExpression expr) {
private void registerNestedClosures(@NotNull DfaInstructionState instructionState, @NotNull PsiLambdaExpression expr) {
DfaMemoryState state = instructionState.getMemoryState();
PsiElement body = expr.getBody();
if (body != null) {
@@ -312,22 +314,27 @@ public class DataFlowRunner {
}
}
@NotNull
protected DfaMemoryState createMemoryState() {
return new DfaMemoryStateImpl(myValueFactory);
}
@NotNull
public Instruction[] getInstructions() {
return myInstructions;
}
@NotNull
public Instruction getInstruction(int index) {
return myInstructions[index];
}
public MultiMap<PsiElement, DfaMemoryState> getNestedClosures() {
@NotNull
MultiMap<PsiElement, DfaMemoryState> getNestedClosures() {
return new MultiMap<PsiElement, DfaMemoryState>(myNestedClosures);
}
@NotNull
public Pair<Set<Instruction>,Set<Instruction>> getConstConditionalExpressions() {
Set<Instruction> trueSet = new HashSet<Instruction>();
Set<Instruction> falseSet = new HashSet<Instruction>();
@@ -362,7 +369,8 @@ public class DataFlowRunner {
return Pair.create(trueSet, falseSet);
}
private static DfaMemoryStateImpl createClosureState(DfaMemoryState memState) {
@NotNull
private static DfaMemoryStateImpl createClosureState(@NotNull DfaMemoryState memState) {
DfaMemoryStateImpl copy = (DfaMemoryStateImpl)memState.createCopy();
copy.flushFields();
Set<DfaVariableValue> vars = new HashSet<DfaVariableValue>(copy.getVariableStates().keySet());
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ import org.jetbrains.annotations.Nullable;
* To change this template use Options | File Templates.
*/
public interface DfaMemoryState {
@NotNull
DfaMemoryState createCopy();
DfaValue pop();
@@ -40,7 +41,7 @@ public interface DfaMemoryState {
void setVarValue(DfaVariableValue var, DfaValue value);
boolean applyInstanceofOrNull(DfaRelationValue dfaCond);
boolean applyInstanceofOrNull(@NotNull DfaRelationValue dfaCond);
boolean applyCondition(DfaValue dfaCond);
@@ -55,7 +56,7 @@ public interface DfaMemoryState {
boolean isNotNull(DfaValue dfaVar);
@Nullable
DfaConstValue getConstantValue(DfaVariableValue value);
DfaConstValue getConstantValue(@NotNull DfaVariableValue value);
/**
* Ephemeral means a state that was created when considering a method contract and checking if one of its arguments is null.
@@ -59,7 +59,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
private final LinkedHashSet<DfaVariableValue> myUnknownVariables;
private boolean myEphemeral;
public DfaMemoryStateImpl(final DfaValueFactory factory) {
protected DfaMemoryStateImpl(final DfaValueFactory factory) {
myFactory = factory;
myDefaultVariableStates = ContainerUtil.newTroveMap();
myEqClasses = ContainerUtil.newArrayList();
@@ -95,10 +95,12 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
myCachedHash = toCopy.myCachedHash;
}
@NotNull
public DfaValueFactory getFactory() {
return myFactory;
}
@NotNull
@Override
public DfaMemoryStateImpl createCopy() {
return new DfaMemoryStateImpl(this);
@@ -112,7 +114,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return equalsSuperficially(that) && equalsByUnknownVariables(that) && equalsByRelations(that) && equalsByVariableStates(that);
}
boolean equalsByUnknownVariables(DfaMemoryStateImpl that) {
private boolean equalsByUnknownVariables(DfaMemoryStateImpl that) {
return myUnknownVariables.equals(that.myUnknownVariables);
}
@@ -178,7 +180,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return hash;
}
@SuppressWarnings({"HardCodedStringLiteral"})
@SuppressWarnings("HardCodedStringLiteral")
public String toString() {
StringBuilder result = new StringBuilder();
result.append('<');
@@ -285,7 +287,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
}
@Nullable("for boxed values which can't be compared by ==")
private Integer getOrCreateEqClassIndex(DfaValue dfaValue) {
private Integer getOrCreateEqClassIndex(@NotNull DfaValue dfaValue) {
int i = getEqClassIndex(dfaValue);
if (i != -1) return i;
if (!canBeInRelation(dfaValue) ||
@@ -340,7 +342,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
}
private static boolean canBeInRelation(DfaValue dfaValue) {
private static boolean canBeInRelation(@NotNull DfaValue dfaValue) {
DfaValue unwrapped = unwrap(dfaValue);
return unwrapped instanceof DfaVariableValue || unwrapped instanceof DfaConstValue;
}
@@ -393,7 +395,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return result;
}
private boolean canBeReused(final DfaValue dfaValue) {
private boolean canBeReused(@NotNull DfaValue dfaValue) {
if (dfaValue instanceof DfaBoxedValue) {
DfaValue valueToWrap = ((DfaBoxedValue)dfaValue).getWrappedValue();
if (valueToWrap instanceof DfaConstValue) {
@@ -410,12 +412,12 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return true;
}
private static boolean cacheable(DfaConstValue dfaConstValue) {
private static boolean cacheable(@NotNull DfaConstValue dfaConstValue) {
Object value = dfaConstValue.getValue();
return box(value) == box(value);
}
@SuppressWarnings({"UnnecessaryBoxing"})
@SuppressWarnings("UnnecessaryBoxing")
private static Object box(final Object value) {
Object newBoxedValue;
if (value instanceof Integer) {
@@ -577,7 +579,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
@Override
@Nullable
public DfaConstValue getConstantValue(DfaVariableValue value) {
public DfaConstValue getConstantValue(@NotNull DfaVariableValue value) {
int index = getEqClassIndex(value);
EqClass ec = index == -1 ? null : myEqClasses.get(index);
return ec == null ? null : (DfaConstValue)unwrap(ec.findConstant(true));
@@ -594,7 +596,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
}
@Override
public boolean applyInstanceofOrNull(DfaRelationValue dfaCond) {
public boolean applyInstanceofOrNull(@NotNull DfaRelationValue dfaCond) {
DfaValue left = unwrap(dfaCond.getLeftOperand());
if (!(left instanceof DfaVariableValue)) return true;
@@ -648,7 +650,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return applyRelationCondition((DfaRelationValue)dfaCond);
}
private boolean applyRelationCondition(DfaRelationValue dfaRelation) {
private boolean applyRelationCondition(@NotNull DfaRelationValue dfaRelation) {
DfaValue dfaLeft = dfaRelation.getLeftOperand();
DfaValue dfaRight = dfaRelation.getRightOperand();
if (dfaLeft instanceof DfaUnknownValue || dfaRight instanceof DfaUnknownValue) return true;
@@ -702,7 +704,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return applyEquivalenceRelation(dfaRelation, dfaLeft, dfaRight);
}
private void updateVarStateOnComparison(DfaVariableValue dfaVar, DfaValue value) {
private void updateVarStateOnComparison(@NotNull DfaVariableValue dfaVar, DfaValue value) {
if (!isUnknownState(dfaVar)) {
if (value instanceof DfaConstValue && ((DfaConstValue)value).getValue() == null) {
setVariableState(dfaVar, getVariableState(dfaVar).withNullability(Nullness.NULLABLE));
@@ -713,7 +715,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
}
}
private boolean applyEquivalenceRelation(DfaRelationValue dfaRelation, DfaValue dfaLeft, DfaValue dfaRight) {
private boolean applyEquivalenceRelation(@NotNull DfaRelationValue dfaRelation, DfaValue dfaLeft, DfaValue dfaRight) {
boolean isNegated = dfaRelation.isNonEquality();
if (!isNegated && !dfaRelation.isEquality()) {
return true;
@@ -761,7 +763,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return true;
}
private boolean applyBoxedRelation(DfaVariableValue dfaLeft, DfaValue dfaRight, boolean negated) {
private boolean applyBoxedRelation(@NotNull DfaVariableValue dfaLeft, DfaValue dfaRight, boolean negated) {
if (!TypeConversionUtil.isPrimitiveAndNotNull(dfaLeft.getVariableType())) return true;
DfaBoxedValue.Factory boxedFactory = myFactory.getBoxedFactory();
@@ -770,7 +772,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return boxedLeft == null || boxedRight == null || applyRelation(boxedLeft, boxedRight, negated);
}
private boolean applyUnboxedRelation(DfaVariableValue dfaLeft, DfaValue dfaRight, boolean negated) {
private boolean applyUnboxedRelation(@NotNull DfaVariableValue dfaLeft, DfaValue dfaRight, boolean negated) {
PsiType type = dfaLeft.getVariableType();
if (!TypeConversionUtil.isPrimitiveWrapper(type)) {
return true;
@@ -912,7 +914,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
myCachedHash = null;
}
public DfaVariableState getVariableState(DfaVariableValue dfaVar) {
DfaVariableState getVariableState(DfaVariableValue dfaVar) {
DfaVariableState state = myVariableStates.get(dfaVar);
if (state == null) {
@@ -935,11 +937,13 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return state;
}
protected Map<DfaVariableValue, DfaVariableState> getVariableStates() {
@NotNull
Map<DfaVariableValue, DfaVariableState> getVariableStates() {
return myVariableStates;
}
protected DfaVariableState createVariableState(final DfaVariableValue var) {
@NotNull
protected DfaVariableState createVariableState(@NotNull DfaVariableValue var) {
return new DfaVariableState(var);
}
@@ -958,7 +962,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
}
}
private boolean shouldMarkUnknown(DfaVariableValue value) {
private boolean shouldMarkUnknown(@NotNull DfaVariableValue value) {
int eqClassIndex = getEqClassIndex(value);
if (eqClassIndex < 0) return false;
@@ -975,6 +979,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return false;
}
@NotNull
Set<DfaVariableValue> getChangedVariables() {
return myVariableStates.keySet();
}
@@ -999,17 +1004,18 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
myCachedHash = null;
}
public void flushDependencies(DfaVariableValue variable) {
void flushDependencies(@NotNull DfaVariableValue variable) {
for (DfaVariableValue dependent : myFactory.getVarFactory().getAllQualifiedBy(variable)) {
doFlush(dependent, false);
}
}
@NotNull
Set<DfaVariableValue> getUnknownVariables() {
return myUnknownVariables;
}
void doFlush(DfaVariableValue varPlain, boolean markUnknown) {
void doFlush(@NotNull DfaVariableValue varPlain, boolean markUnknown) {
DfaVariableValue varNegated = varPlain.getNegatedValue();
final int idPlain = varPlain.getID();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -155,8 +155,9 @@ public class DfaPsiUtil {
return false;
}
@NotNull
@Override
protected DfaInstructionState[] acceptInstruction(InstructionVisitor visitor, DfaInstructionState instructionState) {
protected DfaInstructionState[] acceptInstruction(@NotNull InstructionVisitor visitor, @NotNull DfaInstructionState instructionState) {
Instruction instruction = instructionState.getInstruction();
if (isCallExposingNonInitializedFields(instruction) ||
instruction instanceof ReturnInstruction && !((ReturnInstruction)instruction).isViaException()) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,18 +40,19 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DfaVariableState {
protected final Set<DfaPsiType> myInstanceofValues;
protected final Set<DfaPsiType> myNotInstanceofValues;
protected final Nullness myNullability;
class DfaVariableState {
@NotNull final Set<DfaPsiType> myInstanceofValues;
@NotNull final Set<DfaPsiType> myNotInstanceofValues;
@NotNull final Nullness myNullability;
private final int myHash;
public DfaVariableState(@NotNull DfaVariableValue dfaVar) {
DfaVariableState(@NotNull DfaVariableValue dfaVar) {
this(Collections.<DfaPsiType>emptySet(), Collections.<DfaPsiType>emptySet(), dfaVar.getInherentNullability());
}
protected DfaVariableState(Set<DfaPsiType> instanceofValues,
Set<DfaPsiType> notInstanceofValues, Nullness nullability) {
DfaVariableState(@NotNull Set<DfaPsiType> instanceofValues,
@NotNull Set<DfaPsiType> notInstanceofValues,
@NotNull Nullness nullability) {
myInstanceofValues = instanceofValues;
myNotInstanceofValues = notInstanceofValues;
myNullability = nullability;
@@ -62,7 +63,7 @@ public class DfaVariableState {
return myNullability == Nullness.NULLABLE;
}
private boolean checkInstanceofValue(DfaPsiType dfaType) {
private boolean checkInstanceofValue(@NotNull DfaPsiType dfaType) {
if (myInstanceofValues.contains(dfaType)) return true;
for (DfaPsiType dfaTypeValue : myNotInstanceofValues) {
@@ -77,7 +78,7 @@ public class DfaVariableState {
}
@Nullable
public DfaVariableState withInstanceofValue(DfaTypeValue dfaType) {
DfaVariableState withInstanceofValue(@NotNull DfaTypeValue dfaType) {
if (dfaType.getDfaType().getPsiType() instanceof PsiPrimitiveType) return this;
if (checkInstanceofValue(dfaType.getDfaType())) {
@@ -103,7 +104,7 @@ public class DfaVariableState {
}
@Nullable
public DfaVariableState withNotInstanceofValue(DfaTypeValue dfaType) {
DfaVariableState withNotInstanceofValue(@NotNull DfaTypeValue dfaType) {
if (myNotInstanceofValues.contains(dfaType.getDfaType())) return this;
for (DfaPsiType dfaTypeValue : myInstanceofValues) {
@@ -126,7 +127,8 @@ public class DfaVariableState {
return createCopy(myInstanceofValues, newNotInstanceof, myNullability);
}
DfaVariableState withoutType(DfaPsiType type) {
@NotNull
DfaVariableState withoutType(@NotNull DfaPsiType type) {
if (myInstanceofValues.contains(type)) {
HashSet<DfaPsiType> newInstanceof = ContainerUtil.newHashSet(myInstanceofValues);
newInstanceof.remove(type);
@@ -154,7 +156,8 @@ public class DfaVariableState {
myNotInstanceofValues.equals(aState.myNotInstanceofValues);
}
protected DfaVariableState createCopy(Set<DfaPsiType> instanceofValues, Set<DfaPsiType> notInstanceofValues, Nullness nullability) {
@NotNull
protected DfaVariableState createCopy(@NotNull Set<DfaPsiType> instanceofValues, @NotNull Set<DfaPsiType> notInstanceofValues, @NotNull Nullness nullability) {
return new DfaVariableState(instanceofValues, notInstanceofValues, nullability);
}
@@ -172,7 +175,8 @@ public class DfaVariableState {
return buf.toString();
}
public Nullness getNullability() {
@NotNull
Nullness getNullability() {
return myNullability;
}
@@ -180,14 +184,17 @@ public class DfaVariableState {
return myNullability == Nullness.NOT_NULL;
}
@NotNull
DfaVariableState withNullability(@NotNull Nullness nullness) {
return myNullability == nullness ? this : createCopy(myInstanceofValues, myNotInstanceofValues, nullness);
}
public DfaVariableState withNullable(final boolean nullable) {
@NotNull
DfaVariableState withNullable(final boolean nullable) {
return myNullability != Nullness.NOT_NULL ? withNullability(nullable ? Nullness.NULLABLE : Nullness.UNKNOWN) : this;
}
@NotNull
public DfaVariableState withValue(DfaValue value) {
return this;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,11 +32,11 @@ import java.util.*;
* @author peter
*/
class StateMerger {
private final Map<DfaMemoryStateImpl, LinkedHashSet<Fact>> myFacts = ContainerUtil.newIdentityHashMap();
private final Map<DfaMemoryStateImpl, Set<Fact>> myFacts = ContainerUtil.newIdentityHashMap();
private final Map<DfaMemoryState, Map<DfaVariableValue, DfaMemoryStateImpl>> myCopyCache = ContainerUtil.newIdentityHashMap();
@Nullable
List<DfaMemoryStateImpl> mergeByFacts(List<DfaMemoryStateImpl> states) {
List<DfaMemoryStateImpl> mergeByFacts(@NotNull List<DfaMemoryStateImpl> states) {
MultiMap<Fact, DfaMemoryStateImpl> statesByFact = MultiMap.createLinked();
for (DfaMemoryStateImpl state : states) {
ProgressManager.checkCanceled();
@@ -84,8 +84,8 @@ class StateMerger {
}
@NotNull
private MultiMap<Set<Fact>, DfaMemoryStateImpl> mapByUnrelatedFacts(Fact fact,
Collection<DfaMemoryStateImpl> states1) {
private MultiMap<Set<Fact>, DfaMemoryStateImpl> mapByUnrelatedFacts(@NotNull Fact fact,
@NotNull Collection<DfaMemoryStateImpl> states1) {
MultiMap<Set<Fact>, DfaMemoryStateImpl> statesByUnrelatedFacts1 = MultiMap.createLinked();
for (DfaMemoryStateImpl state : states1) {
statesByUnrelatedFacts1.putValue(getUnrelatedFacts(fact, state), state);
@@ -93,7 +93,8 @@ class StateMerger {
return statesByUnrelatedFacts1;
}
private LinkedHashSet<Fact> getUnrelatedFacts(final Fact fact, DfaMemoryStateImpl state) {
@NotNull
private LinkedHashSet<Fact> getUnrelatedFacts(@NotNull final Fact fact, @NotNull DfaMemoryStateImpl state) {
return new LinkedHashSet<Fact>(ContainerUtil.filter(getFacts(state), new Condition<Fact>() {
@Override
public boolean value(Fact another) {
@@ -102,10 +103,10 @@ class StateMerger {
}));
}
private void restoreOtherInequalities(Fact removedFact, Collection<DfaMemoryStateImpl> mergedGroup, DfaMemoryStateImpl state) {
private void restoreOtherInequalities(@NotNull Fact removedFact, @NotNull Collection<DfaMemoryStateImpl> mergedGroup, @NotNull DfaMemoryStateImpl state) {
Set<DfaConstValue> inequalitiesToRestore = null;
for (DfaMemoryStateImpl member : mergedGroup) {
LinkedHashSet<Fact> memberFacts = getFacts(member);
Set<Fact> memberFacts = getFacts(member);
if (memberFacts.contains(removedFact)) {
Set<DfaConstValue> otherInequalities = getOtherInequalities(removedFact, memberFacts, member);
if (inequalitiesToRestore == null) {
@@ -123,7 +124,8 @@ class StateMerger {
}
}
private static Set<DfaConstValue> getOtherInequalities(Fact removedFact, LinkedHashSet<Fact> memberFacts, DfaMemoryStateImpl state) {
@NotNull
private static Set<DfaConstValue> getOtherInequalities(@NotNull Fact removedFact, @NotNull Set<Fact> memberFacts, @NotNull DfaMemoryStateImpl state) {
Set<DfaConstValue> otherInequalities = ContainerUtil.newLinkedHashSet();
Set<DfaValue> eqValues = ContainerUtil.newHashSet(state.getEquivalentValues((DfaValue)removedFact.myArg));
for (Fact candidate : memberFacts) {
@@ -136,7 +138,8 @@ class StateMerger {
return otherInequalities;
}
private static Set<DfaVariableValue> getAllUnknownVariables(Collection<DfaMemoryStateImpl> complementary) {
@NotNull
private static Set<DfaVariableValue> getAllUnknownVariables(@NotNull Collection<DfaMemoryStateImpl> complementary) {
final Set<DfaVariableValue> toFlush = ContainerUtil.newLinkedHashSet();
for (DfaMemoryStateImpl removedState : complementary) {
toFlush.addAll(removedState.getUnknownVariables());
@@ -144,7 +147,8 @@ class StateMerger {
return toFlush;
}
private static DfaMemoryStateImpl withUnknownVariables(DfaMemoryStateImpl original, Set<DfaVariableValue> toFlush) {
@NotNull
private static DfaMemoryStateImpl withUnknownVariables(@NotNull DfaMemoryStateImpl original, @NotNull Set<DfaVariableValue> toFlush) {
DfaMemoryStateImpl copy = original.createCopy();
for (DfaVariableValue value : toFlush) {
copy.doFlush(value, true);
@@ -153,7 +157,7 @@ class StateMerger {
}
@Nullable
public List<DfaMemoryStateImpl> mergeByUnknowns(List<DfaMemoryStateImpl> states) {
List<DfaMemoryStateImpl> mergeByUnknowns(@NotNull List<DfaMemoryStateImpl> states) {
MultiMap<Integer, DfaMemoryStateImpl> byHash = new MultiMap<Integer, DfaMemoryStateImpl>();
for (DfaMemoryStateImpl state : states) {
ProgressManager.checkCanceled();
@@ -181,7 +185,7 @@ class StateMerger {
}
@Nullable
public List<DfaMemoryStateImpl> mergeByNullability(List<DfaMemoryStateImpl> states) {
List<DfaMemoryStateImpl> mergeByNullability(List<DfaMemoryStateImpl> states) {
MultiMap<Integer, DfaMemoryStateImpl> byHash = new MultiMap<Integer, DfaMemoryStateImpl>();
for (DfaMemoryStateImpl state : states) {
ProgressManager.checkCanceled();
@@ -217,7 +221,7 @@ class StateMerger {
return replacements.getMergeResult();
}
private static boolean mergeUnknowns(Replacements replacements, List<DfaMemoryStateImpl> complementary) {
private static boolean mergeUnknowns(@NotNull Replacements replacements, @NotNull List<DfaMemoryStateImpl> complementary) {
if (complementary.size() < 2) return false;
final Set<DfaVariableValue> toFlush = getAllUnknownVariables(complementary);
@@ -231,13 +235,14 @@ class StateMerger {
});
}
private boolean areEquivalentModuloVar(DfaMemoryStateImpl state1, DfaMemoryStateImpl state2, DfaVariableValue var) {
private boolean areEquivalentModuloVar(@NotNull DfaMemoryStateImpl state1, @NotNull DfaMemoryStateImpl state2, @NotNull DfaVariableValue var) {
DfaMemoryStateImpl copy1 = copyWithoutVar(state1, var);
DfaMemoryStateImpl copy2 = copyWithoutVar(state2, var);
return copy2.equalsByRelations(copy1) && copy2.equalsByVariableStates(copy1);
}
private DfaMemoryStateImpl copyWithoutVar(DfaMemoryStateImpl state, DfaVariableValue var) {
@NotNull
private DfaMemoryStateImpl copyWithoutVar(@NotNull DfaMemoryStateImpl state, @NotNull DfaVariableValue var) {
Map<DfaVariableValue, DfaMemoryStateImpl> map = myCopyCache.get(state);
if (map == null) {
myCopyCache.put(state, map = ContainerUtil.newIdentityHashMap());
@@ -251,12 +256,13 @@ class StateMerger {
return copy;
}
private static boolean areVarStatesEqualModuloNullability(DfaMemoryStateImpl state1, DfaMemoryStateImpl state2, DfaVariableValue var) {
private static boolean areVarStatesEqualModuloNullability(@NotNull DfaMemoryStateImpl state1, @NotNull DfaMemoryStateImpl state2, @NotNull DfaVariableValue var) {
return state1.getVariableState(var).withNullability(Nullness.UNKNOWN).equals(state2.getVariableState(var).withNullability(Nullness.UNKNOWN));
}
private LinkedHashSet<Fact> getFacts(DfaMemoryStateImpl state) {
LinkedHashSet<Fact> result = myFacts.get(state);
@NotNull
private Set<Fact> getFacts(@NotNull DfaMemoryStateImpl state) {
Set<Fact> result = myFacts.get(state);
if (result != null) {
return result;
}
@@ -317,12 +323,13 @@ class StateMerger {
private enum FactType { equality, instanceOf }
private static class Fact {
final FactType myType;
final DfaVariableValue myVar;
final boolean myPositive;
final Object myArg; // DfaValue for equality fact, DfaPsiType for instanceOf fact
@NotNull final FactType myType;
@NotNull private final DfaVariableValue myVar;
private final boolean myPositive;
@NotNull
private final Object myArg; // DfaValue for equality fact, DfaPsiType for instanceOf fact
private Fact(FactType type, DfaVariableValue var, boolean positive, Object arg) {
private Fact(@NotNull FactType type, @NotNull DfaVariableValue var, boolean positive, @NotNull Object arg) {
myType = type;
myVar = var;
myPositive = positive;
@@ -358,18 +365,20 @@ class StateMerger {
return myVar + " " + (myPositive ? "" : "!") + myType + " " + myArg;
}
static Fact createEqualityFact(DfaVariableValue var, DfaValue val, boolean equal) {
@NotNull
private static Fact createEqualityFact(@NotNull DfaVariableValue var, @NotNull DfaValue val, boolean equal) {
if (val instanceof DfaVariableValue && val.getID() < var.getID()) {
return new Fact(FactType.equality, (DfaVariableValue)val, equal, var);
}
return new Fact(FactType.equality, var, equal, val);
}
Fact getPositiveCounterpart() {
@NotNull
private Fact getPositiveCounterpart() {
return new Fact(myType, myVar, true, myArg);
}
boolean invalidatesFact(Fact another) {
boolean invalidatesFact(@NotNull Fact another) {
if (another.myType != myType) return false;
if (myType == FactType.equality) {
return aboutSame(myVar, another.myVar) || aboutSame(myVar, another.myArg);
@@ -377,18 +386,18 @@ class StateMerger {
return aboutSame(myVar, another.myVar) && aboutSame(myArg, another.myArg);
}
static boolean aboutSame(Object v1, Object v2) {
private static boolean aboutSame(Object v1, Object v2) {
return normalize(v1) == normalize(v2);
}
static Object normalize(Object value) {
private static Object normalize(Object value) {
if (value instanceof DfaVariableValue && ((DfaVariableValue)value).isNegated()) {
return ((DfaVariableValue)value).createNegated();
}
return value;
}
void removeFromState(DfaMemoryStateImpl state) {
void removeFromState(@NotNull DfaMemoryStateImpl state) {
DfaVariableState varState = state.getVariableState(myVar);
if (myType == FactType.equality) {
state.flushVariable(myVar);
@@ -400,18 +409,18 @@ class StateMerger {
}
private static class Replacements {
private final List<DfaMemoryStateImpl> myAllStates;
@NotNull private final List<DfaMemoryStateImpl> myAllStates;
private final Set<DfaMemoryStateImpl> myRemovedStates = ContainerUtil.newIdentityTroveSet();
private final List<DfaMemoryStateImpl> myMerged = ContainerUtil.newArrayList();
Replacements(List<DfaMemoryStateImpl> allStates) {
private Replacements(@NotNull List<DfaMemoryStateImpl> allStates) {
myAllStates = allStates;
}
boolean hasMerges() { return !myMerged.isEmpty(); }
private boolean hasMerges() { return !myMerged.isEmpty(); }
@Nullable
List<DfaMemoryStateImpl> getMergeResult() {
private List<DfaMemoryStateImpl> getMergeResult() {
if (hasMerges()) {
List<DfaMemoryStateImpl> result = ContainerUtil.newArrayList(myMerged);
for (DfaMemoryStateImpl state : myAllStates) {
@@ -424,15 +433,15 @@ class StateMerger {
return null;
}
boolean stripAndMerge(Collection<DfaMemoryStateImpl> group,
Function<DfaMemoryStateImpl, DfaMemoryStateImpl> stripper) {
private boolean stripAndMerge(@NotNull Collection<DfaMemoryStateImpl> group,
@NotNull Function<DfaMemoryStateImpl, DfaMemoryStateImpl> stripper) {
if (group.size() <= 1) return false;
boolean hasMerges = false;
MultiMap<DfaMemoryStateImpl, DfaMemoryStateImpl> strippedToOriginals = MultiMap.create();
for (DfaMemoryStateImpl original : group) {
strippedToOriginals.putValue(stripper.fun(original), original);
}
boolean hasMerges = false;
for (Map.Entry<DfaMemoryStateImpl, Collection<DfaMemoryStateImpl>> entry : strippedToOriginals.entrySet()) {
Collection<DfaMemoryStateImpl> merged = entry.getValue();
if (merged.size() > 1) {
@@ -35,19 +35,21 @@ import java.util.Map;
public class DfaTypeValue extends DfaValue {
public static class Factory {
private final Map<DfaPsiType,ArrayList<DfaTypeValue>> myCache = ContainerUtil.newHashMap();
@NotNull
private final DfaValueFactory myFactory;
Factory(DfaValueFactory factory) {
Factory(@NotNull DfaValueFactory factory) {
myFactory = factory;
}
@NotNull
public DfaTypeValue createTypeValue(@NotNull DfaPsiType type, @NotNull Nullness nullness) {
DfaTypeValue createTypeValue(@NotNull DfaPsiType type, @NotNull Nullness nullness) {
ArrayList<DfaTypeValue> conditions = myCache.get(type);
if (conditions == null) {
conditions = new ArrayList<DfaTypeValue>();
myCache.put(type, conditions);
} else {
}
else {
for (DfaTypeValue aType : conditions) {
if (aType.myNullness == nullness) return aType;
}
@@ -60,15 +62,18 @@ public class DfaTypeValue extends DfaValue {
}
@NotNull
private final DfaPsiType myType;
@NotNull
private final Nullness myNullness;
private DfaTypeValue(DfaPsiType type, Nullness nullness, DfaValueFactory factory) {
private DfaTypeValue(@NotNull DfaPsiType type, @NotNull Nullness nullness, @NotNull DfaValueFactory factory) {
super(factory);
myType = type;
myNullness = nullness;
}
@NotNull
public DfaPsiType getDfaType() {
return myType;
}
@@ -81,6 +86,7 @@ public class DfaTypeValue extends DfaValue {
return myNullness == Nullness.NOT_NULL;
}
@NotNull
public Nullness getNullness() {
return myNullness;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -64,7 +64,8 @@ public class DfaValueFactory {
return myUnknownMembersAreNullable;
}
public DfaValue createTypeValue(@Nullable PsiType type, Nullness nullability) {
@NotNull
public DfaValue createTypeValue(@Nullable PsiType type, @NotNull Nullness nullability) {
type = TypeConversionUtil.erasure(type);
if (type == null) return DfaUnknownValue.getInstance();
return getTypeFactory().createTypeValue(internType(type), nullability);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,10 +81,10 @@ public class DfaVariableValue extends DfaValue {
return result;
}
public List<DfaVariableValue> getAllQualifiedBy(DfaVariableValue value) {
@NotNull
public List<DfaVariableValue> getAllQualifiedBy(@NotNull DfaVariableValue value) {
return value.myDependents;
}
}
private final PsiModifierListOwner myVariable;
@@ -159,6 +159,7 @@ public class DfaVariableValue extends DfaValue {
return myQualifier;
}
@NotNull
public Nullness getInherentNullability() {
if (myInherentNullability != null) {
return myInherentNullability;
@@ -167,6 +168,7 @@ public class DfaVariableValue extends DfaValue {
return myInherentNullability = calcInherentNullability();
}
@NotNull
private Nullness calcInherentNullability() {
PsiModifierListOwner var = getPsiVariable();
Nullness nullability = DfaPsiUtil.getElementNullability(getVariableType(), var);