DfaAssist: support while and do-while loops

GitOrigin-RevId: 2061e3ea64f9091060770c5bfa08c70f6921ad54
This commit is contained in:
Tagir Valeev
2020-01-30 13:25:22 +07:00
committed by intellij-monorepo-bot
parent 6e12ae7e93
commit eb1143abcf
4 changed files with 37 additions and 9 deletions

View File

@@ -40,14 +40,14 @@ class DebuggerDfaRunner extends DataFlowRunner {
CommonClassNames.JAVA_UTIL_LINKED_LIST,
CommonClassNames.JAVA_UTIL_HASH_MAP,
"java.util.TreeMap");
private final @NotNull PsiCodeBlock myBody;
private final @NotNull PsiElement myBody;
private final @NotNull PsiStatement myStatement;
private final @NotNull Project myProject;
private final @Nullable ControlFlow myFlow;
private final @Nullable DfaInstructionState myStartingState;
private final long myModificationStamp;
DebuggerDfaRunner(@NotNull PsiCodeBlock body, @NotNull PsiStatement statement, @NotNull StackFrame frame) {
DebuggerDfaRunner(@NotNull PsiElement body, @NotNull PsiStatement statement, @NotNull StackFrame frame) {
super(body.getProject(), body.getParent() instanceof PsiClassInitializer ? ((PsiClassInitializer)body.getParent()).getContainingClass() : body);
myBody = body;
myStatement = statement;

View File

@@ -5,6 +5,7 @@ import com.intellij.codeInsight.hints.presentation.MenuOnClickPresentation;
import com.intellij.codeInsight.hints.presentation.PresentationFactory;
import com.intellij.codeInsight.hints.presentation.PresentationRenderer;
import com.intellij.codeInspection.dataFlow.RunnerResult;
import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.SuspendContextImpl;
@@ -185,7 +186,7 @@ public class DfaAssist implements DebuggerContextListener {
if (!locationMatches(element, frame.location())) return null;
PsiStatement statement = getAnchorStatement(element);
if (statement == null) return null;
PsiCodeBlock body = getCodeBlock(statement);
PsiElement body = getCodeBlock(statement);
if (body == null) return null;
DebuggerDfaRunner runner = new DebuggerDfaRunner(body, statement, frame);
return runner.isValid() ? runner : null;
@@ -233,7 +234,10 @@ public class DfaAssist implements DebuggerContextListener {
}
@Nullable
private static PsiCodeBlock getCodeBlock(@NotNull PsiStatement statement) {
private static PsiElement getCodeBlock(@NotNull PsiStatement statement) {
if (statement instanceof PsiWhileStatement || statement instanceof PsiDoWhileStatement) {
return statement;
}
PsiElement e = statement;
while (e != null && !(e instanceof PsiClass) && !(e instanceof PsiFileSystemItem)) {
e = e.getParent();
@@ -243,9 +247,15 @@ public class DfaAssist implements DebuggerContextListener {
// We cannot properly restore context if we started from finally, so let's analyze just finally block
parent instanceof PsiTryStatement && ((PsiTryStatement)parent).getFinallyBlock() == e ||
parent instanceof PsiBlockStatement && parent.getParent() instanceof PsiLoopStatement) {
return (PsiCodeBlock)e;
if (parent.getParent() instanceof PsiDoWhileStatement) {
return parent.getParent();
}
return e;
}
}
if (e instanceof PsiDoWhileStatement) {
return e;
}
}
return null;
}
@@ -254,7 +264,8 @@ public class DfaAssist implements DebuggerContextListener {
private final DebuggerContextImpl myContext;
private TurnOffDfaProcessorAction(DebuggerContextImpl context) {
super("Turn Off Dataflow Assist", "Switch off dataflow aided debugging for this session", AllIcons.Actions.Cancel);
super(DebuggerBundle.message("action.TurnOffDfaAssist.text"),
DebuggerBundle.message("action.TurnOffDfaAssist.description"), AllIcons.Actions.Cancel);
myContext = context;
}
@Override

View File

@@ -61,6 +61,15 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
private final Map<String, ExceptionTransfer> myExceptionCache;
private ExpressionBlockContext myExpressionBlockContext;
/**
* @param valueFactory factory to create values
* @param codeFragment code fragment to analyze:
* normally a PsiCodeBlock or PsiExpression.
* If PsiWhileStatement or PsiDoWhileStatement then only one loop iteration will be analyzed
* (similar to analyzing the loop body, but condition is analyzed as well).
* If PsiClass then class initializers + field initializers will be analyzed
* @param inlining if true inlining is performed for known method calls
*/
ControlFlowAnalyzer(final DfaValueFactory valueFactory, @NotNull PsiElement codeFragment, boolean inlining) {
myInlining = inlining;
myFactory = valueFactory;
@@ -429,7 +438,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
@Override public void visitContinueStatement(PsiContinueStatement statement) {
startElement(statement);
PsiStatement continuedStatement = statement.findContinuedStatement();
if (continuedStatement instanceof PsiLoopStatement && PsiTreeUtil.isAncestor(myCodeFragment, continuedStatement, false)) {
if (continuedStatement instanceof PsiLoopStatement && PsiTreeUtil.isAncestor(myCodeFragment, continuedStatement, true)) {
PsiStatement body = ((PsiLoopStatement)continuedStatement).getBody();
controlTransfer(new InstructionTransfer(getEndOffset(body), getVariablesInside(body)), getTrapsInsideElement(body));
} else {
@@ -449,7 +458,11 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
if (condition != null) {
condition.accept(this);
generateBoxingUnboxingInstructionFor(condition, PsiType.BOOLEAN);
addInstruction(new ConditionalGotoInstruction(getStartOffset(statement), false, condition));
if (statement == myCodeFragment) {
addInstruction(new PopInstruction());
} else {
addInstruction(new ConditionalGotoInstruction(getStartOffset(statement), false, condition));
}
}
}
@@ -1172,7 +1185,9 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
body.accept(this);
}
addInstruction(new GotoInstruction(getStartOffset(statement)));
if (statement != myCodeFragment) {
addInstruction(new GotoInstruction(getStartOffset(statement)));
}
finishElement(statement);
}

View File

@@ -536,3 +536,5 @@ action.AnActionButton.text.import=Import
action.AnActionButton.description.import=Import
action.AnActionButton.text.export=Export
action.AnActionButton.description.export=Export
action.TurnOffDfaAssist.text=Turn Off Data Flow Assist
action.TurnOffDfaAssist.description=Switch off data flow aided debugging for this session