mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
better check for side effects in debugger value hint;
fix handling method call expressions on alt-click
This commit is contained in:
@@ -20,6 +20,7 @@ import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.debugger.DebuggerInvocationUtil;
|
||||
import com.intellij.debugger.DebuggerManagerEx;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.DebuggerUtils;
|
||||
import com.intellij.debugger.engine.evaluation.*;
|
||||
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
|
||||
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
|
||||
@@ -190,17 +191,8 @@ public class ValueHint extends AbstractValueHint {
|
||||
return tree;
|
||||
}
|
||||
|
||||
// call inside ReadAction only
|
||||
private static boolean canProcess(PsiExpression expression) {
|
||||
if (expression instanceof PsiReferenceExpression) {
|
||||
PsiExpression qualifier = ((PsiReferenceExpression)expression).getQualifierExpression();
|
||||
return qualifier == null || canProcess(qualifier);
|
||||
}
|
||||
return !(expression instanceof PsiMethodCallExpression);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Pair<PsiExpression, TextRange> findExpression(PsiElement element) {
|
||||
private static Pair<PsiExpression, TextRange> findExpression(PsiElement element, boolean allowMethodCalls) {
|
||||
if (!(element instanceof PsiIdentifier || element instanceof PsiKeyword)) {
|
||||
return null;
|
||||
}
|
||||
@@ -210,21 +202,30 @@ public class ValueHint extends AbstractValueHint {
|
||||
if (parent instanceof PsiVariable) {
|
||||
expression = element;
|
||||
}
|
||||
else if (parent instanceof PsiReferenceExpression && canProcess((PsiExpression)parent)) {
|
||||
else if (parent instanceof PsiReferenceExpression) {
|
||||
final PsiElement pparent = parent.getParent();
|
||||
if (pparent instanceof PsiMethodCallExpression) {
|
||||
parent = pparent;
|
||||
}
|
||||
if (allowMethodCalls || !DebuggerUtils.hasSideEffects(parent)) {
|
||||
expression = parent;
|
||||
}
|
||||
}
|
||||
else if (parent instanceof PsiThisExpression) {
|
||||
expression = parent;
|
||||
}
|
||||
if (parent instanceof PsiThisExpression) {
|
||||
expression = parent;
|
||||
}
|
||||
try {
|
||||
if (expression != null) {
|
||||
|
||||
if (expression != null) {
|
||||
try {
|
||||
PsiElement context = element;
|
||||
if(parent instanceof PsiParameter) {
|
||||
try {
|
||||
context = ((PsiMethod)((PsiParameter)parent).getDeclarationScope()).getBody();
|
||||
}
|
||||
catch (Throwable e) {}
|
||||
} else {
|
||||
catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
while(context != null && !(context instanceof PsiStatement) && !(context instanceof PsiClass)) {
|
||||
context = context.getParent();
|
||||
}
|
||||
@@ -233,8 +234,9 @@ public class ValueHint extends AbstractValueHint {
|
||||
PsiExpression psiExpression = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory().createExpressionFromText(expression.getText(), context);
|
||||
return Pair.create(psiExpression, textRange);
|
||||
}
|
||||
} catch (IncorrectOperationException e) {
|
||||
LOG.debug(e);
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -271,7 +273,7 @@ public class ValueHint extends AbstractValueHint {
|
||||
if(currentRange.get() == null) {
|
||||
PsiElement elementAtCursor = psiFile.findElementAt(offset);
|
||||
if (elementAtCursor == null) return;
|
||||
Pair<PsiExpression, TextRange> pair = findExpression(elementAtCursor);
|
||||
Pair<PsiExpression, TextRange> pair = findExpression(elementAtCursor, type == ValueHintType.MOUSE_CLICK_HINT || type == ValueHintType.MOUSE_ALT_OVER_HINT);
|
||||
if (pair == null) return;
|
||||
selectedExpression.set(pair.getFirst());
|
||||
currentRange.set(pair.getSecond());
|
||||
|
||||
@@ -47,7 +47,6 @@ import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import com.intellij.util.ui.tree.TreeModelAdapter;
|
||||
@@ -59,7 +58,6 @@ import javax.swing.event.TreeModelEvent;
|
||||
import javax.swing.tree.TreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class FrameDebuggerTree extends DebuggerTree {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.FrameDebuggerTree");
|
||||
@@ -457,7 +455,7 @@ public class FrameDebuggerTree extends DebuggerTree {
|
||||
|
||||
@Override public void visitMethodCallExpression(final PsiMethodCallExpression expression) {
|
||||
final PsiMethod psiMethod = expression.resolveMethod();
|
||||
if (psiMethod != null && !hasSideEffects(expression)) {
|
||||
if (psiMethod != null && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) {
|
||||
myExpressions.add(new TextWithImportsImpl(expression));
|
||||
}
|
||||
super.visitMethodCallExpression(expression);
|
||||
@@ -469,7 +467,7 @@ public class FrameDebuggerTree extends DebuggerTree {
|
||||
if (psiElement instanceof PsiVariable) {
|
||||
final PsiVariable var = (PsiVariable)psiElement;
|
||||
if (var instanceof PsiField) {
|
||||
if (!hasSideEffects(reference)) {
|
||||
if (!DebuggerUtils.hasSideEffectsOrReferencesMissingVars(reference, myVisibleLocals)) {
|
||||
if (var instanceof PsiEnumConstant && reference.getQualifier() == null) {
|
||||
final PsiClass enumClass = ((PsiEnumConstant)var).getContainingClass();
|
||||
if (enumClass != null) {
|
||||
@@ -497,7 +495,7 @@ public class FrameDebuggerTree extends DebuggerTree {
|
||||
}
|
||||
|
||||
@Override public void visitArrayAccessExpression(final PsiArrayAccessExpression expression) {
|
||||
if (!hasSideEffects(expression)) {
|
||||
if (!DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) {
|
||||
myExpressions.add(new TextWithImportsImpl(expression));
|
||||
}
|
||||
super.visitArrayAccessExpression(expression);
|
||||
@@ -519,61 +517,9 @@ public class FrameDebuggerTree extends DebuggerTree {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitClass(final PsiClass aClass) {
|
||||
@Override
|
||||
public void visitClass(final PsiClass aClass) {
|
||||
// Do not step in to local and anonymous classes...
|
||||
}
|
||||
|
||||
private boolean hasSideEffects(PsiElement element) {
|
||||
final AtomicBoolean rv = new AtomicBoolean(false);
|
||||
element.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override public void visitPostfixExpression(final PsiPostfixExpression expression) {
|
||||
rv.set(true);
|
||||
}
|
||||
|
||||
@Override public void visitReferenceExpression(final PsiReferenceExpression expression) {
|
||||
final PsiElement psiElement = expression.resolve();
|
||||
if (psiElement instanceof PsiLocalVariable) {
|
||||
if (!myVisibleLocals.contains(((PsiLocalVariable)psiElement).getName())) {
|
||||
rv.set(true);
|
||||
}
|
||||
}
|
||||
else if (psiElement instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)psiElement;
|
||||
if (!DebuggerUtils.isSimpleGetter(method)) {
|
||||
rv.set(true);
|
||||
}
|
||||
}
|
||||
if (!rv.get()) {
|
||||
super.visitReferenceExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitPrefixExpression(final PsiPrefixExpression expression) {
|
||||
final IElementType op = expression.getOperationTokenType();
|
||||
if (JavaTokenType.PLUSPLUS.equals(op) || JavaTokenType.MINUSMINUS.equals(op)) {
|
||||
rv.set(true);
|
||||
}
|
||||
else {
|
||||
super.visitPrefixExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitAssignmentExpression(final PsiAssignmentExpression expression) {
|
||||
rv.set(true);
|
||||
}
|
||||
|
||||
@Override public void visitCallExpression(final PsiCallExpression callExpression) {
|
||||
final PsiMethod method = callExpression.resolveMethod();
|
||||
if (method == null || !DebuggerUtils.isSimpleGetter(method)) {
|
||||
rv.set(true);
|
||||
}
|
||||
else {
|
||||
super.visitCallExpression(callExpression);
|
||||
}
|
||||
}
|
||||
});
|
||||
return rv.get();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -33,9 +33,11 @@ import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.StringBuilderSpinAllocator;
|
||||
@@ -368,6 +370,69 @@ public abstract class DebuggerUtils implements ApplicationComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasSideEffects(PsiElement element) {
|
||||
return hasSideEffectsOrReferencesMissingVars(element, null);
|
||||
}
|
||||
|
||||
public static boolean hasSideEffectsOrReferencesMissingVars(PsiElement element, @Nullable final Set<String> visibleLocalVariables) {
|
||||
final Ref<Boolean> rv = new Ref<Boolean>(Boolean.FALSE);
|
||||
element.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitPostfixExpression(final PsiPostfixExpression expression) {
|
||||
rv.set(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(final PsiReferenceExpression expression) {
|
||||
final PsiElement psiElement = expression.resolve();
|
||||
if (psiElement instanceof PsiLocalVariable) {
|
||||
if (visibleLocalVariables != null) {
|
||||
if (!visibleLocalVariables.contains(((PsiLocalVariable)psiElement).getName())) {
|
||||
rv.set(Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (psiElement instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)psiElement;
|
||||
if (!isSimpleGetter(method)) {
|
||||
rv.set(Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
if (!rv.get().booleanValue()) {
|
||||
super.visitReferenceExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPrefixExpression(final PsiPrefixExpression expression) {
|
||||
final IElementType op = expression.getOperationTokenType();
|
||||
if (JavaTokenType.PLUSPLUS.equals(op) || JavaTokenType.MINUSMINUS.equals(op)) {
|
||||
rv.set(Boolean.TRUE);
|
||||
}
|
||||
else {
|
||||
super.visitPrefixExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAssignmentExpression(final PsiAssignmentExpression expression) {
|
||||
rv.set(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCallExpression(final PsiCallExpression callExpression) {
|
||||
final PsiMethod method = callExpression.resolveMethod();
|
||||
if (method == null || !isSimpleGetter(method)) {
|
||||
rv.set(Boolean.TRUE);
|
||||
}
|
||||
else {
|
||||
super.visitCallExpression(callExpression);
|
||||
}
|
||||
}
|
||||
});
|
||||
return rv.get().booleanValue();
|
||||
}
|
||||
|
||||
public abstract String findAvailableDebugAddress(boolean useSockets) throws ExecutionException;
|
||||
|
||||
public static boolean isSynthetic(TypeComponent typeComponent) {
|
||||
|
||||
Reference in New Issue
Block a user