summaryrefslogtreecommitdiff
path: root/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java')
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java185
1 files changed, 26 insertions, 159 deletions
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java
index 65e7fd7c859a..7ef19f2b73d0 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java
@@ -20,7 +20,6 @@ import com.intellij.codeInspection.dataFlow.instructions.*;
import com.intellij.codeInspection.dataFlow.value.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.tree.IElementType;
@@ -30,37 +29,15 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import com.siyeh.ig.numeric.UnnecessaryExplicitNumericCastInspection;
import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
-import java.util.regex.Pattern;
-import static com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint;
import static com.intellij.psi.CommonClassNames.*;
public class ControlFlowAnalyzer extends JavaElementVisitor {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer");
- private static final Condition<String> FALSE_GETTERS = parseFalseGetters();
-
- private static Condition<String> parseFalseGetters() {
- try {
- final Pattern pattern = Pattern.compile(Registry.stringValue("ide.dfa.getters.with.side.effects"));
- return new Condition<String>() {
- @Override
- public boolean value(String s) {
- return pattern.matcher(s).matches();
- }
- };
- }
- catch (Exception e) {
- LOG.error(e);
- //noinspection unchecked
- return Condition.FALSE;
- }
- }
-
public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
private boolean myIgnoreAssertions;
@@ -209,9 +186,23 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
addInstruction(new AssignInstruction(rExpr));
+
+ flushArrayElementsOnUnknownIndexAssignment(lExpr);
+
finishElement(expression);
}
+ private void flushArrayElementsOnUnknownIndexAssignment(PsiExpression lExpr) {
+ if (lExpr instanceof PsiArrayAccessExpression &&
+ myFactory.createValue(lExpr) == null // check for unknown index, otherwise AssignInstruction will flush only that element
+ ) {
+ DfaValue arrayVar = myFactory.createValue(((PsiArrayAccessExpression)lExpr).getArrayExpression());
+ if (arrayVar instanceof DfaVariableValue) {
+ addInstruction(new FlushVariableInstruction((DfaVariableValue)arrayVar));
+ }
+ }
+ }
+
private void generateDefaultAssignmentBinOp(PsiExpression lExpr, PsiExpression rExpr, final PsiType exprType) {
lExpr.accept(this);
addInstruction(new DupInstruction());
@@ -635,7 +626,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
((PsiReferenceExpression)caseExpression).getQualifierExpression() == null &&
JavaPsiFacade.getInstance(body.getProject()).getConstantEvaluationHelper().computeConstantExpression(caseValue) != null) {
- addInstruction(new PushInstruction(getExpressionDfaValue((PsiReferenceExpression)caseExpression), caseExpression));
+ addInstruction(new PushInstruction(myFactory.createValue(caseExpression), caseExpression));
caseValue.accept(this);
addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, caseExpression.getProject()));
}
@@ -1030,7 +1021,8 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
addInstruction(new PopInstruction());
}
- pushTypeOrUnknown(arrayExpression);
+ DfaValue toPush = myFactory.createValue(expression);
+ addInstruction(new PushInstruction(toPush != null ? toPush : myFactory.createTypeValue(expression.getType(), Nullness.UNKNOWN), null));
finishElement(expression);
}
@@ -1396,8 +1388,8 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
addConditionalRuntimeThrow();
- List<MethodContract> contracts = method instanceof PsiMethod ? getMethodContracts((PsiMethod)method) : Collections.<MethodContract>emptyList();
- addInstruction(new MethodCallInstruction(expression, createChainedVariableValue(expression), contracts));
+ List<MethodContract> contracts = method instanceof PsiMethod ? getMethodCallContracts((PsiMethod)method, expression) : Collections.<MethodContract>emptyList();
+ addInstruction(new MethodCallInstruction(expression, myFactory.createValue(expression), contracts));
if (!contracts.isEmpty()) {
// if a contract resulted in 'fail', handle it
addInstruction(new DupInstruction());
@@ -1431,6 +1423,11 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
finishElement(expression);
}
+ private static List<MethodContract> getMethodCallContracts(@NotNull final PsiMethod method, @NotNull PsiMethodCallExpression call) {
+ List<MethodContract> contracts = HardcodedContracts.getHardcodedContracts(method, call);
+ return !contracts.isEmpty() ? contracts : getMethodContracts(method);
+ }
+
static List<MethodContract> getMethodContracts(@NotNull final PsiMethod method) {
final PsiAnnotation contractAnno = findContractAnnotation(method);
final int paramCount = method.getParameterList().getParametersCount();
@@ -1458,45 +1455,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
});
}
- @NonNls String methodName = method.getName();
-
- PsiClass owner = method.getContainingClass();
- if (owner != null) {
- final String className = owner.getQualifiedName();
- if ("java.lang.System".equals(className)) {
- if ("exit".equals(methodName)) {
- return Collections.singletonList(new MethodContract(MethodContract.createConstraintArray(paramCount), ValueConstraint.THROW_EXCEPTION));
- }
- }
- else if ("junit.framework.Assert".equals(className) || "org.junit.Assert".equals(className) ||
- "junit.framework.TestCase".equals(className) || "org.testng.Assert".equals(className) || "org.testng.AssertJUnit".equals(className)) {
- boolean testng = className.startsWith("org.testng.");
- if ("fail".equals(methodName)) {
- return Collections.singletonList(new MethodContract(MethodContract.createConstraintArray(paramCount), ValueConstraint.THROW_EXCEPTION));
- }
-
- int checkedParam = testng ? 0 : paramCount - 1;
- ValueConstraint[] constraints = MethodContract.createConstraintArray(paramCount);
- if ("assertTrue".equals(methodName)) {
- constraints[checkedParam] = ValueConstraint.FALSE_VALUE;
- return Collections.singletonList(new MethodContract(constraints, ValueConstraint.THROW_EXCEPTION));
- }
- if ("assertFalse".equals(methodName)) {
- constraints[checkedParam] = ValueConstraint.TRUE_VALUE;
- return Collections.singletonList(new MethodContract(constraints, ValueConstraint.THROW_EXCEPTION));
- }
- if ("assertNull".equals(methodName)) {
- constraints[checkedParam] = ValueConstraint.NOT_NULL_VALUE;
- return Collections.singletonList(new MethodContract(constraints, ValueConstraint.THROW_EXCEPTION));
- }
- if ("assertNotNull".equals(methodName)) {
- constraints[checkedParam] = ValueConstraint.NULL_VALUE;
- return Collections.singletonList(new MethodContract(constraints, ValueConstraint.THROW_EXCEPTION));
- }
- return Collections.emptyList();
- }
- }
-
return Collections.emptyList();
}
@@ -1505,20 +1463,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
return AnnotationUtil.findAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
}
- private void pushTypeOrUnknown(PsiExpression expr) {
- PsiType type = expr.getType();
-
- final DfaValue dfaValue;
- if (type instanceof PsiClassType) {
- dfaValue = myFactory.createTypeValue(type, Nullness.UNKNOWN);
- }
- else {
- dfaValue = null;
- }
-
- addInstruction(new PushInstruction(dfaValue, null));
- }
-
@Override public void visitNewExpression(PsiNewExpression expression) {
startElement(expression);
@@ -1657,88 +1601,11 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
boolean referenceRead = PsiUtil.isAccessedForReading(expression) && !PsiUtil.isAccessedForWriting(expression);
- addInstruction(new PushInstruction(getExpressionDfaValue(expression), expression, referenceRead));
+ addInstruction(new PushInstruction(myFactory.createValue(expression), expression, referenceRead));
finishElement(expression);
}
- @Nullable
- private DfaValue getExpressionDfaValue(PsiReferenceExpression expression) {
- DfaValue dfaValue = myFactory.createReferenceValue(expression);
- if (dfaValue == null) {
- PsiElement resolved = expression.resolve();
- if (resolved instanceof PsiField) {
- dfaValue = createDfaValueForAnotherInstanceMemberAccess(expression, (PsiField)resolved);
- }
- }
- return dfaValue;
- }
-
- @NotNull
- private DfaValue createDfaValueForAnotherInstanceMemberAccess(PsiReferenceExpression expression, PsiField field) {
- DfaValue dfaValue = null;
- if (expression.getQualifierExpression() != null) {
- dfaValue = createChainedVariableValue(expression);
- }
- if (dfaValue == null) {
- PsiType type = expression.getType();
- return myFactory.createTypeValue(type, DfaPsiUtil.getElementNullability(type, field));
- }
- return dfaValue;
- }
-
- @Nullable
- private DfaVariableValue createChainedVariableValue(@Nullable PsiExpression expression) {
- if (expression instanceof PsiParenthesizedExpression) {
- return createChainedVariableValue(((PsiParenthesizedExpression)expression).getExpression());
- }
-
- PsiReferenceExpression refExpr;
- if (expression instanceof PsiMethodCallExpression) {
- refExpr = ((PsiMethodCallExpression)expression).getMethodExpression();
- }
- else if (expression instanceof PsiReferenceExpression) {
- refExpr = (PsiReferenceExpression)expression;
- }
- else {
- return null;
- }
-
- PsiElement target = refExpr.resolve();
- PsiModifierListOwner var = getAccessedVariable(target);
- if (var == null) {
- return null;
- }
-
- if (DfaValueFactory.isEffectivelyUnqualified(refExpr)) {
- return myFactory.getVarFactory().createVariableValue(var, refExpr.getType(), false, null);
- }
-
- if (!(var instanceof PsiField) || !var.hasModifierProperty(PsiModifier.TRANSIENT) && !var.hasModifierProperty(PsiModifier.VOLATILE)) {
- DfaVariableValue qualifierValue = createChainedVariableValue(refExpr.getQualifierExpression());
- if (qualifierValue != null) {
- return myFactory.getVarFactory().createVariableValue(var, refExpr.getType(), false, qualifierValue);
- }
- }
- return null;
- }
-
- @Nullable
- private static PsiModifierListOwner getAccessedVariable(final PsiElement target) {
- if (target instanceof PsiVariable) {
- return (PsiVariable)target;
- }
- if (target instanceof PsiMethod) {
- if (PropertyUtil.isSimplePropertyGetter((PsiMethod)target)) {
- String qName = PsiUtil.getMemberQualifiedName((PsiMethod)target);
- if (qName == null || !FALSE_GETTERS.value(qName)) {
- return (PsiMethod)target;
- }
- }
- }
- return null;
- }
-
@Override public void visitSuperExpression(PsiSuperExpression expression) {
startElement(expression);
addInstruction(new PushInstruction(myFactory.createTypeValue(expression.getType(), Nullness.NOT_NULL), null));
@@ -1769,7 +1636,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
generateBoxingUnboxingInstructionFor(operand, castExpression.getType());
}
else {
- pushTypeOrUnknown(castExpression);
+ addInstruction(new PushInstruction(myFactory.createTypeValue(castExpression.getType(), Nullness.UNKNOWN), null));
}
final PsiTypeElement typeElement = castExpression.getCastType();