DFA: make CFG independent on assertion status

GitOrigin-RevId: 4c81f96bb7d6108d4e74898bfc5f014e753132e1
This commit is contained in:
Tagir Valeev
2019-12-02 09:48:51 +07:00
committed by intellij-monorepo-bot
parent ebde07d923
commit 546d12c3f8
3 changed files with 42 additions and 9 deletions

View File

@@ -47,7 +47,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
static final int MAX_UNROLL_SIZE = 3;
private static final int MAX_ARRAY_INDEX_FOR_INITIALIZER = 32;
private final PsiElement myCodeFragment;
private final boolean myIgnoreAssertions;
private final boolean myInlining;
private final Project myProject;
@@ -60,12 +59,11 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
private final Map<String, ExceptionTransfer> myExceptionCache;
private ExpressionBlockContext myExpressionBlockContext;
ControlFlowAnalyzer(final DfaValueFactory valueFactory, @NotNull PsiElement codeFragment, boolean ignoreAssertions, boolean inlining) {
ControlFlowAnalyzer(final DfaValueFactory valueFactory, @NotNull PsiElement codeFragment, boolean inlining) {
myInlining = inlining;
myFactory = valueFactory;
myCodeFragment = codeFragment;
myProject = codeFragment.getProject();
myIgnoreAssertions = ignoreAssertions;
GlobalSearchScope scope = codeFragment.getResolveScope();
myExceptionCache = FactoryMap.create(fqn -> new ExceptionTransfer(myFactory.createDfaType(createClassType(scope, fqn))));
}
@@ -233,11 +231,10 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
@Override public void visitAssertStatement(PsiAssertStatement statement) {
if (myIgnoreAssertions) {
return;
}
startElement(statement);
addInstruction(new PushInstruction(myFactory.getExpressionFactory().getAssertionsDisabledVariable(), null));
ConditionalGotoInstruction jump = new ConditionalGotoInstruction(null, false, null);
addInstruction(jump);
final PsiExpression condition = statement.getAssertCondition();
final PsiExpression description = statement.getAssertDescription();
if (condition != null) {
@@ -250,6 +247,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
throwException(myExceptionCache.get(JAVA_LANG_ASSERTION_ERROR), statement);
}
jump.setOffset(getInstructionCount());
finishElement(statement);
}

View File

@@ -35,6 +35,7 @@ import java.lang.management.ThreadMXBean;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
public class DataFlowRunner {
private static final Logger LOG = Logger.getInstance(DataFlowRunner.class);
@@ -178,7 +179,7 @@ public class DataFlowRunner {
ControlFlow flow = null;
try {
myStats.reset();
flow = new ControlFlowAnalyzer(myValueFactory, psiBlock, myIgnoreAssertions, myInlining).buildControlFlow();
flow = new ControlFlowAnalyzer(myValueFactory, psiBlock, myInlining).buildControlFlow();
myStats.endFlow();
if (flow != null) {
@@ -435,6 +436,14 @@ public class DataFlowRunner {
private void initializeVariables(@NotNull PsiElement psiBlock,
@NotNull Collection<? extends DfaMemoryState> initialStates,
@NotNull ControlFlow flow) {
List<DfaVariableValue> vars = flow.accessedVariables().collect(Collectors.toList());
DfaVariableValue assertionStatus =
ContainerUtil.find(vars, v -> v.getDescriptor() instanceof DfaExpressionFactory.AssertionDisabledDescriptor);
if (assertionStatus != null) {
for (DfaMemoryState state : initialStates) {
state.applyCondition(assertionStatus.eq(myValueFactory.getBoolean(myIgnoreAssertions)));
}
}
if (psiBlock instanceof PsiClass) {
DfaVariableValue thisValue = getFactory().getVarFactory().createThisValue((PsiClass)psiBlock);
// In class initializer this variable is local until escaped
@@ -445,7 +454,7 @@ public class DataFlowRunner {
}
PsiElement parent = psiBlock.getParent();
if (parent instanceof PsiMethod && !(((PsiMethod)parent).isConstructor())) {
Map<DfaVariableValue, DfaValue> initialValues = StreamEx.of(flow.accessedVariables()).mapToEntry(
Map<DfaVariableValue, DfaValue> initialValues = StreamEx.of(vars).mapToEntry(
var -> makeInitialValue(var, (PsiMethod)parent)).nonNullValues().toMap();
for (DfaMemoryState state : initialStates) {
initialValues.forEach(state::setVarValue);

View File

@@ -299,6 +299,32 @@ public class DfaExpressionFactory {
}
return PsiSubstitutor.EMPTY;
}
public DfaVariableValue getAssertionsDisabledVariable() {
return myFactory.getVarFactory().createVariableValue(AssertionDisabledDescriptor.INSTANCE);
}
public static final class AssertionDisabledDescriptor implements VariableDescriptor {
static final AssertionDisabledDescriptor INSTANCE = new AssertionDisabledDescriptor();
private AssertionDisabledDescriptor() {}
@Override
public boolean isStable() {
return true;
}
@NotNull
@Override
public PsiType getType(@Nullable DfaVariableValue qualifier) {
return PsiType.BOOLEAN;
}
@Override
public String toString() {
return "$assertionsDisabled";
}
}
static final class PlainDescriptor implements VariableDescriptor {
private final @NotNull PsiVariable myVariable;