diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 1fb9cf75ef1b..d37d2dd0ea17 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -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) { diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index f1df3c2e932b..f7de8aa2b4c5 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -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); } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java index 7f5942a7590d..2a2b9005d819 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java @@ -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;