DfaVariableSource -> VariableDescriptor

This commit is contained in:
Tagir Valeev
2018-12-18 12:28:49 +07:00
parent ce2a2e4305
commit e9e06d06e5
17 changed files with 89 additions and 89 deletions
@@ -118,18 +118,18 @@ public class CFGBuilder {
}
/**
* Generate instructions to load a qualified field described by given source which qualifier is on the stack
* Generate instructions to load a qualified field described by given descriptor which qualifier is on the stack
* <p>
* Stack before: ... qualifier
* <p>
* Stack after: ... loaded_field
*
* @param source a {@link DfaVariableSource} which describes a field to load
* @param descriptor a {@link VariableDescriptor} which describes a field to load
* @param type a loaded field type
* @return this builder
*/
public CFGBuilder getField(@NotNull DfaVariableSource source, @Nullable PsiType type) {
return add(new GetFieldInstruction(source, type));
public CFGBuilder getField(@NotNull VariableDescriptor descriptor, @Nullable PsiType type) {
return add(new GetFieldInstruction(descriptor, type));
}
/**
@@ -179,9 +179,9 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
for (DfaValue value : myFactory.getValues()) {
if (value instanceof DfaVariableValue) {
DfaVariableValue var = (DfaVariableValue)value;
DfaVariableSource source = var.getSource();
if (source instanceof Synthetic) {
if (((Synthetic)source).myLocation >= startOffset) {
VariableDescriptor descriptor = var.getDescriptor();
if (descriptor instanceof Synthetic) {
if (((Synthetic)descriptor).myLocation >= startOffset) {
synthetics.add(var);
}
}
@@ -900,7 +900,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
}
if (syntheticVar) {
expressionValue = getFactory().getVarFactory().createVariableValue(new DfaVariableSource() {
expressionValue = getFactory().getVarFactory().createVariableValue(new VariableDescriptor() {
@Override
public boolean isStable() {
return true;
@@ -2114,7 +2114,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
* @return true if supplied variable is a temp variable.
*/
public static boolean isTempVariable(@NotNull DfaVariableValue variable) {
return variable.getSource() instanceof Synthetic;
return variable.getDescriptor() instanceof Synthetic;
}
/**
@@ -2125,7 +2125,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
return Arrays.stream(INLINERS).anyMatch(inliner -> inliner.mayInferPreciseType(expression));
}
private static final class Synthetic implements DfaVariableSource {
private static final class Synthetic implements VariableDescriptor {
private final int myLocation;
private Synthetic(int location) {
@@ -79,7 +79,7 @@ final class DataFlowInstructionVisitor extends StandardInstructionVisitor {
if (!(target instanceof DfaVariableValue)) return false;
DfaVariableValue var = (DfaVariableValue)target;
if (!(var.getPsiVariable() instanceof PsiField) || var.getQualifier() == null ||
!(var.getQualifier().getSource() instanceof DfaExpressionFactory.ThisSource)) {
!(var.getQualifier().getDescriptor() instanceof DfaExpressionFactory.ThisDescriptor)) {
return false;
}
@@ -402,8 +402,8 @@ public class DataFlowRunner {
@Nullable
private static DfaValue makeInitialValue(DfaVariableValue var, @NotNull PsiMethod method) {
DfaValueFactory factory = var.getFactory();
if (var.getSource() instanceof DfaExpressionFactory.ThisSource) {
PsiClass aClass = ((DfaExpressionFactory.ThisSource)var.getSource()).getPsiElement();
if (var.getDescriptor() instanceof DfaExpressionFactory.ThisDescriptor) {
PsiClass aClass = ((DfaExpressionFactory.ThisDescriptor)var.getDescriptor()).getPsiElement();
DfaValue value = factory.createTypeValue(var.getType(), Nullability.NOT_NULL);
if (method.getContainingClass() == aClass && MutationSignature.fromMethod(method).preservesThis()) {
// Unmodifiable view, because we cannot call mutating methods, but it's not guaranteed that all fields are stable
@@ -167,9 +167,9 @@ public abstract class DfaFactType<T> extends Key<T> {
@Nullable
@Override
LongRangeSet calcFromVariable(@NotNull DfaVariableValue var) {
DfaVariableSource source = var.getSource();
if(source instanceof SpecialField) {
DfaValue defaultValue = ((SpecialField)source).getDefaultValue(var.getFactory());
VariableDescriptor descriptor = var.getDescriptor();
if(descriptor instanceof SpecialField) {
DfaValue defaultValue = ((SpecialField)descriptor).getDefaultValue(var.getFactory());
LongRangeSet fromSpecialField = LongRangeSet.fromDfaValue(defaultValue);
if (fromSpecialField != null) {
return fromSpecialField;
@@ -1020,7 +1020,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
private boolean applyBooleanInequality(DfaValue var, DfaValue value) {
if (!(var instanceof DfaVariableValue) ||
!PsiType.BOOLEAN.equals(var.getType()) ||
((DfaVariableValue)var).getSource() == SpecialField.UNBOX) {
((DfaVariableValue)var).getDescriptor() == SpecialField.UNBOX) {
return false;
}
if (!(value instanceof DfaConstValue)) return false;
@@ -298,7 +298,7 @@ public class DfaUtil {
static boolean isEffectivelyUnqualified(DfaVariableValue variableValue) {
return variableValue.getQualifier() == null ||
variableValue.getQualifier().getSource() instanceof DfaExpressionFactory.ThisSource;
variableValue.getQualifier().getDescriptor() instanceof DfaExpressionFactory.ThisDescriptor;
}
public static boolean hasImplicitImpureSuperCall(PsiClass aClass, PsiMethod constructor) {
@@ -161,7 +161,7 @@ public abstract class InstructionVisitor {
public DfaInstructionState[] visitGetField(GetFieldInstruction instruction, DataFlowRunner runner, DfaMemoryState state) {
DfaValue value = state.pop();
DfaValue field = instruction.getSource().createValue(runner.getFactory(), value, instruction.getTargetType());
DfaValue field = instruction.getDescriptor().createValue(runner.getFactory(), value, instruction.getTargetType());
pushExpressionResult(field, instruction, state);
return nextInstruction(instruction, runner, state);
}
@@ -209,7 +209,7 @@ public class LiveVariablesAnalyzer {
for (FinishElementInstruction instruction : toFlush.keySet()) {
Collection<DfaVariableValue> values = toFlush.get(instruction);
// Do not flush special values and this value as they could be used implicitly
values.removeIf(var -> var.getSource() instanceof SpecialField || var.getSource() instanceof DfaExpressionFactory.ThisSource);
values.removeIf(var -> var.getDescriptor() instanceof SpecialField || var.getDescriptor() instanceof DfaExpressionFactory.ThisDescriptor);
instruction.getVarsToFlush().addAll(values);
}
}
@@ -26,7 +26,7 @@ import java.util.List;
public class NullabilityUtil {
static DfaNullability calcCanBeNull(DfaVariableValue value) {
if (value.getSource() instanceof DfaExpressionFactory.ThisSource) {
if (value.getDescriptor() instanceof DfaExpressionFactory.ThisDescriptor) {
return DfaNullability.NOT_NULL;
}
PsiModifierListOwner var = value.getPsiVariable();
@@ -25,7 +25,7 @@ import static com.intellij.psi.CommonClassNames.*;
*
* @author Tagir Valeev
*/
public enum SpecialField implements DfaVariableSource {
public enum SpecialField implements VariableDescriptor {
ARRAY_LENGTH(null, "length", true) {
@Override
boolean isMyQualifierType(PsiType type) {
@@ -189,7 +189,7 @@ public enum SpecialField implements DfaVariableSource {
}
}
}
return DfaVariableSource.super.createValue(factory, qualifier, targetType == null ? getType(variableValue) : targetType);
return VariableDescriptor.super.createValue(factory, qualifier, targetType == null ? getType(variableValue) : targetType);
}
if(qualifier instanceof DfaFactMapValue) {
SpecialFieldValue sfValue = ((DfaFactMapValue)qualifier).get(DfaFactType.SPECIAL_FIELD_VALUE);
@@ -512,9 +512,9 @@ public class StandardInstructionVisitor extends InstructionVisitor {
if (instruction.getContext() instanceof PsiMethodReferenceExpression && qualifierValue instanceof DfaVariableValue) {
PsiMethod method = instruction.getTargetMethod();
DfaVariableSource source = DfaExpressionFactory.getAccessedVariableOrGetter(method);
if (source != null) {
return source.createValue(factory, qualifierValue, instruction.getResultType());
VariableDescriptor descriptor = DfaExpressionFactory.getAccessedVariableOrGetter(method);
if (descriptor != null) {
return descriptor.createValue(factory, qualifierValue, instruction.getResultType());
}
}
@@ -5,7 +5,7 @@ import com.intellij.codeInspection.dataFlow.DataFlowRunner;
import com.intellij.codeInspection.dataFlow.DfaInstructionState;
import com.intellij.codeInspection.dataFlow.DfaMemoryState;
import com.intellij.codeInspection.dataFlow.InstructionVisitor;
import com.intellij.codeInspection.dataFlow.value.DfaVariableSource;
import com.intellij.codeInspection.dataFlow.value.VariableDescriptor;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
@@ -16,16 +16,16 @@ import org.jetbrains.annotations.Nullable;
*/
public class GetFieldInstruction extends Instruction implements ExpressionPushingInstruction {
@Nullable private final PsiType myTargetType;
@NotNull private final DfaVariableSource mySource;
@NotNull private final VariableDescriptor myDescriptor;
@Nullable private final PsiExpression myAnchor;
public GetFieldInstruction(@NotNull DfaVariableSource source, @Nullable PsiType targetType) {
this(null, source, targetType);
public GetFieldInstruction(@NotNull VariableDescriptor descriptor, @Nullable PsiType targetType) {
this(null, descriptor, targetType);
}
public GetFieldInstruction(@Nullable PsiExpression anchor, @NotNull DfaVariableSource source, @Nullable PsiType targetType) {
public GetFieldInstruction(@Nullable PsiExpression anchor, @NotNull VariableDescriptor descriptor, @Nullable PsiType targetType) {
myTargetType = targetType;
mySource = source;
myDescriptor = descriptor;
myAnchor = anchor;
}
@@ -35,8 +35,8 @@ public class GetFieldInstruction extends Instruction implements ExpressionPushin
}
@NotNull
public DfaVariableSource getSource() {
return mySource;
public VariableDescriptor getDescriptor() {
return myDescriptor;
}
@Nullable
@@ -46,7 +46,7 @@ public class GetFieldInstruction extends Instruction implements ExpressionPushin
@Override
public String toString() {
return "GET_FIELD " + mySource;
return "GET_FIELD " + myDescriptor;
}
@Nullable
@@ -63,7 +63,7 @@ public class DfaBoxedValue extends DfaValue {
@Nullable
public DfaValue createBoxed(DfaValue valueToWrap, @Nullable PsiType type) {
if (valueToWrap instanceof DfaVariableValue && ((DfaVariableValue)valueToWrap).getSource() == SpecialField.UNBOX) {
if (valueToWrap instanceof DfaVariableValue && ((DfaVariableValue)valueToWrap).getDescriptor() == SpecialField.UNBOX) {
return ((DfaVariableValue)valueToWrap).getQualifier();
}
if (valueToWrap instanceof DfaConstValue || valueToWrap instanceof DfaFactMapValue) {
@@ -65,7 +65,7 @@ public class DfaExpressionFactory {
}
private final DfaValueFactory myFactory;
private final Map<Integer, ArrayElementSource> myMockIndices = ContainerUtil.newHashMap();
private final Map<Integer, ArrayElementDescriptor> myArrayIndices = ContainerUtil.newHashMap();
DfaExpressionFactory(DfaValueFactory factory) {
myFactory = factory;
@@ -147,7 +147,7 @@ public class DfaExpressionFactory {
if (constValue != null && !maybeUninitializedConstant(constValue, refExpr, variable)) return constValue;
}
}
DfaVariableSource var = getAccessedVariableOrGetter(target);
VariableDescriptor var = getAccessedVariableOrGetter(target);
if (var == null) {
return null;
}
@@ -216,27 +216,27 @@ public class DfaExpressionFactory {
@Contract("null -> null")
@Nullable
public static DfaVariableSource getAccessedVariableOrGetter(final PsiElement target) {
public static VariableDescriptor getAccessedVariableOrGetter(final PsiElement target) {
SpecialField sf = SpecialField.findSpecialField(target);
if (sf != null) {
return sf;
}
if (target instanceof PsiVariable) {
return new PlainSource((PsiVariable)target);
return new PlainDescriptor((PsiVariable)target);
}
if (target instanceof PsiMethod) {
PsiMethod method = (PsiMethod)target;
if (PropertyUtilBase.isSimplePropertyGetter(method) && isContractAllowedForGetter(method)) {
String qName = PsiUtil.getMemberQualifiedName(method);
if (qName == null || !FALSE_GETTERS.value(qName)) {
return new GetterSource(method);
return new GetterDescriptor(method);
}
}
if (method.getParameterList().isEmpty()) {
if ((JavaMethodContractUtil.isPure(method) ||
AnnotationUtil.findAnnotation(method.getContainingClass(), "javax.annotation.concurrent.Immutable") != null) &&
isContractAllowedForGetter(method)) {
return new GetterSource(method);
return new GetterDescriptor(method);
}
}
}
@@ -315,23 +315,23 @@ public class DfaExpressionFactory {
return getAdvancedExpressionDfaValue(constantArrayElement, componentType);
}
}
ArrayElementSource indexVariable = getArrayIndexVariable(index);
ArrayElementDescriptor indexVariable = getArrayIndexVariable(index);
if (indexVariable == null) return null;
return indexVariable.createValue(myFactory, arrayDfaVar, componentType);
}
@Nullable
private ArrayElementSource getArrayIndexVariable(int index) {
private ArrayElementDescriptor getArrayIndexVariable(int index) {
if (index >= 0) {
return myMockIndices.computeIfAbsent(index, ArrayElementSource::new);
return myArrayIndices.computeIfAbsent(index, ArrayElementDescriptor::new);
}
return null;
}
static final class PlainSource implements DfaVariableSource {
static final class PlainDescriptor implements VariableDescriptor {
private final @NotNull PsiVariable myVariable;
PlainSource(@NotNull PsiVariable variable) {
PlainDescriptor(@NotNull PsiVariable variable) {
myVariable = variable;
}
@@ -367,19 +367,19 @@ public class DfaExpressionFactory {
(!myVariable.hasModifierProperty(PsiModifier.FINAL) || !DfaUtil.hasInitializationHacks((PsiField)myVariable)))) {
return factory.getVarFactory().createVariableValue(this, type);
}
return DfaVariableSource.super.createValue(factory, qualifier, type);
return VariableDescriptor.super.createValue(factory, qualifier, type);
}
@Override
public boolean equals(Object obj) {
return obj == this || obj instanceof PlainSource && ((PlainSource)obj).myVariable == myVariable;
return obj == this || obj instanceof PlainDescriptor && ((PlainDescriptor)obj).myVariable == myVariable;
}
}
private static final class GetterSource implements DfaVariableSource {
private static final class GetterDescriptor implements VariableDescriptor {
private final @NotNull PsiMethod myGetter;
GetterSource(@NotNull PsiMethod getter) {
GetterDescriptor(@NotNull PsiMethod getter) {
myGetter = getter;
}
@@ -411,19 +411,19 @@ public class DfaExpressionFactory {
if (myGetter.hasModifierProperty(PsiModifier.STATIC)) {
return factory.getVarFactory().createVariableValue(this, type);
}
return DfaVariableSource.super.createValue(factory, qualifier, type);
return VariableDescriptor.super.createValue(factory, qualifier, type);
}
@Override
public boolean equals(Object obj) {
return obj == this || (obj instanceof GetterSource && ((GetterSource)obj).myGetter == myGetter);
return obj == this || (obj instanceof GetterDescriptor && ((GetterDescriptor)obj).myGetter == myGetter);
}
}
private static final class ArrayElementSource implements DfaVariableSource {
private static final class ArrayElementDescriptor implements VariableDescriptor {
private final int myIndex;
ArrayElementSource(int index) {
ArrayElementDescriptor(int index) {
myIndex = index;
}
@@ -439,11 +439,11 @@ public class DfaExpressionFactory {
}
}
public static final class ThisSource implements DfaVariableSource {
public static final class ThisDescriptor implements VariableDescriptor {
@NotNull
private final PsiClass myQualifier;
ThisSource(@NotNull PsiClass qualifier) {
ThisDescriptor(@NotNull PsiClass qualifier) {
myQualifier = qualifier;
}
@@ -465,7 +465,7 @@ public class DfaExpressionFactory {
@Override
public boolean equals(Object obj) {
return this == obj || obj instanceof ThisSource && ((ThisSource)obj).myQualifier == myQualifier;
return this == obj || obj instanceof ThisDescriptor && ((ThisDescriptor)obj).myQualifier == myQualifier;
}
}
}
@@ -53,7 +53,7 @@ public final class DfaVariableValue extends DfaValue {
if (variable instanceof PsiField && !(variable.hasModifierProperty(PsiModifier.STATIC))) {
qualifier = createThisValue(((PsiField)variable).getContainingClass());
}
return createVariableValue(new DfaExpressionFactory.PlainSource(variable), varType, qualifier);
return createVariableValue(new DfaExpressionFactory.PlainDescriptor(variable), varType, qualifier);
}
/**
@@ -65,24 +65,24 @@ public final class DfaVariableValue extends DfaValue {
public DfaVariableValue createThisValue(@Nullable PsiClass aClass) {
if (aClass == null) return null;
PsiClassType type = JavaPsiFacade.getElementFactory(aClass.getProject()).createType(aClass);
return createVariableValue(new DfaExpressionFactory.ThisSource(aClass), type);
return createVariableValue(new DfaExpressionFactory.ThisDescriptor(aClass), type);
}
@NotNull
public DfaVariableValue createVariableValue(@NotNull DfaVariableSource source, @Nullable PsiType varType) {
return createVariableValue(source, varType, null);
public DfaVariableValue createVariableValue(@NotNull VariableDescriptor descriptor, @Nullable PsiType varType) {
return createVariableValue(descriptor, varType, null);
}
@NotNull
DfaVariableValue createVariableValue(@NotNull DfaVariableSource source,
DfaVariableValue createVariableValue(@NotNull VariableDescriptor descriptor,
@Nullable PsiType varType,
@Nullable DfaVariableValue qualifier) {
Pair<String, DfaVariableValue> key = Pair.create(source.toString(), qualifier);
Pair<String, DfaVariableValue> key = Pair.create(descriptor.toString(), qualifier);
for (DfaVariableValue aVar : myExistingVars.get(key)) {
if (aVar.hardEquals(source, varType, qualifier)) return aVar;
if (aVar.hardEquals(descriptor, varType, qualifier)) return aVar;
}
DfaVariableValue result = new DfaVariableValue(source, varType, myFactory, qualifier);
DfaVariableValue result = new DfaVariableValue(descriptor, varType, myFactory, qualifier);
myExistingVars.putValue(key, result);
while (qualifier != null) {
qualifier.myDependents.add(result);
@@ -92,24 +92,24 @@ public final class DfaVariableValue extends DfaValue {
}
}
@NotNull private final DfaVariableSource mySource;
@NotNull private final VariableDescriptor myDescriptor;
private final PsiType myVarType;
@Nullable private final DfaVariableValue myQualifier;
private DfaFactMap myInherentFacts;
private final DfaPsiType myDfaType;
private final List<DfaVariableValue> myDependents = new SmartList<>();
private DfaVariableValue(@NotNull DfaVariableSource source,
private DfaVariableValue(@NotNull VariableDescriptor descriptor,
@Nullable PsiType varType,
DfaValueFactory factory,
@Nullable DfaVariableValue qualifier) {
super(factory);
mySource = source;
myDescriptor = descriptor;
myQualifier = qualifier;
myVarType = varType;
myDfaType = varType == null ? null : myFactory.createDfaType(varType);
if (varType != null && !varType.isValid()) {
PsiUtil.ensureValidType(varType, "Variable: " + source + " of class " + source.getClass());
PsiUtil.ensureValidType(varType, "Variable: " + descriptor + " of class " + descriptor.getClass());
}
}
@@ -120,12 +120,12 @@ public final class DfaVariableValue extends DfaValue {
@Nullable
public PsiModifierListOwner getPsiVariable() {
return mySource.getPsiElement();
return myDescriptor.getPsiElement();
}
@NotNull
public DfaVariableSource getSource() {
return mySource;
public VariableDescriptor getDescriptor() {
return myDescriptor;
}
@Override
@@ -160,15 +160,15 @@ public final class DfaVariableValue extends DfaValue {
@NotNull
@Contract(pure = true)
public DfaVariableValue withQualifier(DfaVariableValue newQualifier) {
return newQualifier == myQualifier ? this : myFactory.getVarFactory().createVariableValue(mySource, myVarType, newQualifier);
return newQualifier == myQualifier ? this : myFactory.getVarFactory().createVariableValue(myDescriptor, myVarType, newQualifier);
}
public String toString() {
return (myQualifier == null ? "" : myQualifier + ".") + mySource;
return (myQualifier == null ? "" : myQualifier + ".") + myDescriptor;
}
private boolean hardEquals(DfaVariableSource source, PsiType varType, DfaVariableValue qualifier) {
return source.equals(mySource) && qualifier == myQualifier &&
private boolean hardEquals(VariableDescriptor descriptor, PsiType varType, DfaVariableValue qualifier) {
return descriptor.equals(myDescriptor) && qualifier == myQualifier &&
Comparing.equal(TypeConversionUtil.erasure(varType), TypeConversionUtil.erasure(myVarType));
}
@@ -191,10 +191,10 @@ public final class DfaVariableValue extends DfaValue {
}
public boolean isFlushableByCalls() {
return !mySource.isStable() || (myQualifier != null && myQualifier.isFlushableByCalls());
return !myDescriptor.isStable() || (myQualifier != null && myQualifier.isFlushableByCalls());
}
public boolean containsCalls() {
return mySource.isCall() || myQualifier != null && myQualifier.containsCalls();
return myDescriptor.isCall() || myQualifier != null && myQualifier.containsCalls();
}
}
@@ -8,15 +8,15 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a source of {@link DfaVariableValue}. Two variables are the same if they have the same source and qualifier.
* A source could be a PsiVariable, getter method, array element with given index, this expression, etc.
* Represents a descriptor of {@link DfaVariableValue}. Two variables are the same if they have the same descriptor and qualifier.
* A descriptor could be a PsiVariable, getter method, array element with given index, this expression, etc.
* <p>
* Subclasses must have proper {@link Object#equals(Object)} and implementation or instantiation must be controlled to prevent
* creating equal objects. Also {@link #toString()} must return sane representation of the source.
* creating equal objects. Also {@link #toString()} must return sane representation of the descriptor.
*/
public interface DfaVariableSource {
public interface VariableDescriptor {
/**
* @return a PSI element associated with given source or null if not applicable
* @return a PSI element associated with this descriptor or null if not applicable
*/
@Nullable
default PsiModifierListOwner getPsiElement() {
@@ -24,26 +24,26 @@ public interface DfaVariableSource {
}
/**
* @return true if the value stored in this source cannot be changed implicitly (e.g. inside the unknown method call)
* @return true if the value stored in this descriptor cannot be changed implicitly (e.g. inside the unknown method call)
*/
boolean isStable();
/**
* @return true if the value behind this source is a method call which result might be computed from other sources
* @return true if the value behind this descriptor is a method call which result might be computed from other sources
*/
default boolean isCall() {
return false;
}
/**
* Must be overridden to return stable string representation of the source.
* In particular {@code source1.equals(source2)} implies that {@code source1.toString().equals(source2.toString())}
* Must be overridden to return stable string representation of the descriptor.
* In particular {@code desc1.equals(desc2)} implies that {@code desc1.toString().equals(desc2.toString())}
*/
@Override
String toString();
/**
* Returns a value which describes the field qualified by given qualifier and described by this source
* Returns a value which describes the field qualified by given qualifier and described by this descriptor
* @param factory factory to use
* @param qualifier qualifier to use
* @param type field type