This commit is contained in:
peter
2012-09-10 20:53:36 +02:00
parent 5cb12c39f1
commit d30abc644c
3 changed files with 68 additions and 70 deletions
@@ -1460,40 +1460,39 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
@Override public void visitReferenceExpression(PsiReferenceExpression expression) {
startElement(expression);
DfaValue dfaValue = myFactory.create(expression);
PsiElement resolved = expression.resolve();
if (dfaValue instanceof DfaVariableValue) {
DfaVariableValue dfaVariable = (DfaVariableValue)dfaValue;
PsiVariable psiVariable = dfaVariable.getPsiVariable();
if (psiVariable instanceof PsiField) {
addField(dfaVariable);
}
}
final PsiExpression qualifierExpression = expression.getQualifierExpression();
if (qualifierExpression != null) {
qualifierExpression.accept(this);
if (resolved instanceof PsiField) {
addInstruction(new FieldReferenceInstruction(expression, null));
}
else {
addInstruction(new PopInstruction());
}
addInstruction(expression.resolve() instanceof PsiField ? new FieldReferenceInstruction(expression, null) : new PopInstruction());
}
if (dfaValue == null && resolved instanceof PsiField) {
dfaValue = createDfaValueForAnotherInstanceMemberAccess(expression, (PsiField)resolved);
}
addInstruction(new PushInstruction(dfaValue, expression));
addInstruction(new PushInstruction(getExpressionDfaValue(expression), expression));
finishElement(expression);
}
@Nullable
private DfaValue getExpressionDfaValue(PsiReferenceExpression expression) {
DfaValue dfaValue = myFactory.create(expression);
if (dfaValue instanceof DfaVariableValue) {
DfaVariableValue dfaVariable = (DfaVariableValue)dfaValue;
if (dfaVariable.getPsiVariable() instanceof PsiField) {
myFields.add(dfaVariable);
}
}
if (dfaValue == null) {
PsiElement resolved = expression.resolve();
if (resolved instanceof PsiField) {
dfaValue = createDfaValueForAnotherInstanceMemberAccess(expression, (PsiField)resolved);
}
}
return dfaValue;
}
private DfaValue createDfaValueForAnotherInstanceMemberAccess(PsiReferenceExpression expression, PsiField field) {
DfaValue dfaValue = null;
if (expression.getQualifierExpression() != null) {
dfaValue = myFactory.getVarFactory().createFromReference(expression, field);
dfaValue = createChainedVariableValue(expression, field);
}
if (dfaValue == null) {
return myFactory.getTypeFactory().create(field.getType(), NullableNotNullManager.isNullable(field));
@@ -1501,8 +1500,22 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
return dfaValue;
}
private void addField(DfaVariableValue field) {
myFields.add(field);
@Nullable
private DfaVariableValue createChainedVariableValue(@NotNull PsiReferenceExpression expression, @NotNull PsiVariable target) {
PsiExpression qualifier = expression.getQualifierExpression();
if (qualifier == null) {
return myFactory.getVarFactory().createVariableValue(target, false, null);
}
if (qualifier instanceof PsiReferenceExpression && target instanceof PsiField && target.hasModifierProperty(PsiModifier.FINAL)) {
PsiElement qTarget = ((PsiReferenceExpression)qualifier).resolve();
if (qTarget instanceof PsiVariable) {
DfaVariableValue qualifierValue = createChainedVariableValue((PsiReferenceExpression)qualifier, (PsiVariable)qTarget);
return qualifierValue == null ? null : myFactory.getVarFactory().createVariableValue(target, false, qualifierValue);
}
}
return null;
}
@Override public void visitSuperExpression(PsiSuperExpression expression) {
@@ -189,48 +189,51 @@ public class StandardInstructionVisitor extends InstructionVisitor {
return nextInstruction(instruction, runner, memState);
}
finally {
pushResult(instruction, memState, qualifier, runner.getFactory());
memState.push(getMethodResultValue(instruction, qualifier, runner.getFactory()));
if (instruction.shouldFlushFields()) {
memState.flushFields(runner);
}
}
}
private void pushResult(MethodCallInstruction instruction, DfaMemoryState state, final DfaValue oldValue, DfaValueFactory factory) {
@NotNull
private DfaValue getMethodResultValue(MethodCallInstruction instruction, @NotNull DfaValue qualifierValue, DfaValueFactory factory) {
final PsiType type = instruction.getResultType();
final MethodCallInstruction.MethodType methodType = instruction.getMethodType();
DfaValue dfaValue = null;
if (type != null && (type instanceof PsiClassType || type.getArrayDimensions() > 0)) {
@Nullable final Boolean nullability = myCalleeNullability.get(instruction);
dfaValue = nullability == Boolean.FALSE ? factory.getNotNullFactory().create(type) : factory.getTypeFactory().create(type, nullability == Boolean.TRUE);
return nullability == Boolean.FALSE ? factory.getNotNullFactory().create(type) : factory.getTypeFactory().create(type, nullability == Boolean.TRUE);
}
else if (methodType == MethodCallInstruction.MethodType.UNBOXING) {
dfaValue = factory.getBoxedFactory().createUnboxed(oldValue);
}
else if (methodType == MethodCallInstruction.MethodType.BOXING) {
dfaValue = factory.getBoxedFactory().createBoxed(oldValue);
}
else if (methodType == MethodCallInstruction.MethodType.CAST) {
if (oldValue instanceof DfaConstValue) {
final DfaConstValue constValue = (DfaConstValue)oldValue;
Object o = constValue.getValue();
if (o instanceof Double || o instanceof Float) {
double dbVal = o instanceof Double ? ((Double)o).doubleValue() : ((Float)o).doubleValue();
// 5.0f == 5
if (Math.floor(dbVal) == dbVal) o = TypeConversionUtil.computeCastTo(o, PsiType.LONG);
}
else {
o = TypeConversionUtil.computeCastTo(o, PsiType.LONG);
}
dfaValue = factory.getConstFactory().createFromValue(o, type);
if (methodType == MethodCallInstruction.MethodType.UNBOXING) {
return factory.getBoxedFactory().createUnboxed(qualifierValue);
}
if (methodType == MethodCallInstruction.MethodType.BOXING) {
DfaValue boxed = factory.getBoxedFactory().createBoxed(qualifierValue);
return boxed == null ? DfaUnknownValue.getInstance() : boxed;
}
if (methodType == MethodCallInstruction.MethodType.CAST) {
if (qualifierValue instanceof DfaConstValue) {
return factory.getConstFactory().createFromValue(castConstValue((DfaConstValue)qualifierValue), type);
}
else {
dfaValue = oldValue;
return qualifierValue;
}
return DfaUnknownValue.getInstance();
}
private static Object castConstValue(DfaConstValue constValue) {
Object o = constValue.getValue();
if (o instanceof Double || o instanceof Float) {
double dbVal = o instanceof Double ? ((Double)o).doubleValue() : ((Float)o).doubleValue();
// 5.0f == 5
if (Math.floor(dbVal) != dbVal) {
return o;
}
}
state.push(dfaValue == null ? DfaUnknownValue.getInstance() : dfaValue);
return TypeConversionUtil.computeCastTo(o, PsiType.LONG);
}
@@ -24,10 +24,9 @@
*/
package com.intellij.codeInspection.dataFlow.value;
import com.intellij.psi.*;
import com.intellij.psi.PsiVariable;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@@ -49,7 +48,7 @@ public class DfaVariableValue extends DfaValue {
public DfaVariableValue createVariableValue(PsiVariable myVariable, boolean isNegated) {
return createVariableValue(myVariable, isNegated, null);
}
private DfaVariableValue createVariableValue(PsiVariable myVariable, boolean isNegated, @Nullable DfaVariableValue qualifier) {
public DfaVariableValue createVariableValue(PsiVariable myVariable, boolean isNegated, @Nullable DfaVariableValue qualifier) {
mySharedInstance.myVariable = myVariable;
mySharedInstance.myIsNegated = isNegated;
mySharedInstance.myQualifier = qualifier;
@@ -83,23 +82,6 @@ public class DfaVariableValue extends DfaValue {
return result;
}
@Nullable
public DfaVariableValue createFromReference(@NotNull PsiReferenceExpression expression, @NotNull PsiVariable target) {
PsiExpression qualifier = expression.getQualifierExpression();
if (qualifier == null) {
return createVariableValue(target, false, null);
}
if (qualifier instanceof PsiReferenceExpression && target instanceof PsiField && target.hasModifierProperty(PsiModifier.FINAL)) {
PsiElement qTarget = ((PsiReferenceExpression)qualifier).resolve();
if (qTarget instanceof PsiVariable) {
DfaVariableValue qualifierValue = createFromReference((PsiReferenceExpression)qualifier, (PsiVariable)qTarget);
return qualifierValue == null ? null : createVariableValue(target, false, qualifierValue);
}
}
return null;
}
}
private PsiVariable myVariable;