match slot names only once

This commit is contained in:
Egor.Ushakov
2015-09-16 20:03:15 +03:00
parent a2f7c2f948
commit 02a5ee5731
7 changed files with 81 additions and 79 deletions
@@ -324,9 +324,11 @@ public class JavaStackFrame extends XStackFrame {
children.add(new DummyMessageValueNode(MessageDescriptor.LOCAL_VARIABLES_INFO_UNAVAILABLE.getLabel(), XDebuggerUIConstants.INFORMATION_MESSAGE_ICON));
// trying to collect values from variable slots
try {
for (Map.Entry<DecompiledLocalVariable, Value> entry : LocalVariablesUtil.fetchValues(getStackFrameProxy()).entrySet()) {
for (Map.Entry<DecompiledLocalVariable, Value> entry : LocalVariablesUtil.fetchValues(getStackFrameProxy(), debugProcess).entrySet()) {
DecompiledLocalVariable var = entry.getKey();
children.add(createArgumentValue(var.getSlot(), entry.getValue(), var.isParam(), evaluationContext));
children.add(JavaValue.create(
myNodeManager.getArgumentValueDescriptor(null, var.getSlot(), entry.getValue(), var.isParam(), var.getDisplayName()),
evaluationContext, myNodeManager));
}
}
catch (Exception ex) {
@@ -389,13 +391,6 @@ public class JavaStackFrame extends XStackFrame {
}
}
private JavaValue createArgumentValue(int index, Value value, boolean isParam, EvaluationContextImpl evaluationContext) {
ArgumentValueDescriptorImpl descriptor = myNodeManager.getArgumentValueDescriptor(null, index, value, isParam);
// setContext is required to calculate correct name
descriptor.setContext(evaluationContext);
return JavaValue.create(null, descriptor, evaluationContext, myNodeManager, true);
}
protected void superBuildVariables(final EvaluationContextImpl evaluationContext, XValueChildrenList children) throws EvaluateException {
final StackFrameProxyImpl frame = getStackFrameProxy();
for (final LocalVariableProxyImpl local : frame.visibleVariables()) {
@@ -22,6 +22,7 @@ package com.intellij.debugger.engine.evaluation.expression;
import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.engine.DebugProcess;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
@@ -41,7 +42,6 @@ import com.intellij.psi.PsiVariable;
import com.sun.jdi.*;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -74,6 +74,7 @@ class LocalVariableEvaluator implements Evaluator {
ThreadReferenceProxyImpl threadProxy = null;
int lastFrameIndex = -1;
PsiVariable variable = null;
DebugProcessImpl process = context.getDebugProcess();
boolean topFrame = true;
@@ -82,7 +83,7 @@ class LocalVariableEvaluator implements Evaluator {
LocalVariableProxyImpl local = frameProxy.visibleVariableByName(myLocalVariableName);
if (local != null) {
if (topFrame ||
variable.equals(resolveVariable(frameProxy, myLocalVariableName, context.getProject(), context.getDebugProcess()))) {
variable.equals(resolveVariable(frameProxy, myLocalVariableName, context.getProject(), process))) {
myEvaluatedVariable = local;
myContext = context;
return frameProxy.getValue(local);
@@ -96,11 +97,10 @@ class LocalVariableEvaluator implements Evaluator {
// try to look in slots
try {
Map<DecompiledLocalVariable, Value> vars = LocalVariablesUtil.fetchValues(frameProxy);
Map<DecompiledLocalVariable, Value> vars = LocalVariablesUtil.fetchValues(frameProxy, process);
for (Map.Entry<DecompiledLocalVariable, Value> entry : vars.entrySet()) {
Collection<String> names =
LocalVariablesUtil.calcNames(new SimpleStackFrameContext(frameProxy, context.getDebugProcess()), entry.getKey().getSlot());
if (names.contains(myLocalVariableName) || entry.getKey().getName().equals(myLocalVariableName)) {
DecompiledLocalVariable var = entry.getKey();
if (var.getMatchedNames().contains(myLocalVariableName) || var.getDefaultName().equals(myLocalVariableName)) {
return entry.getValue();
}
}
@@ -123,7 +123,7 @@ class LocalVariableEvaluator implements Evaluator {
if (myCanScanFrames) {
if (topFrame) {
variable = resolveVariable(frameProxy, myLocalVariableName, context.getProject(), context.getDebugProcess());
variable = resolveVariable(frameProxy, myLocalVariableName, context.getProject(), process);
if (variable == null) break;
}
if (threadProxy == null /* initialize it lazily */) {
@@ -19,21 +19,25 @@ import com.intellij.debugger.ui.impl.watch.ArgumentValueDescriptorImpl;
import com.intellij.openapi.project.Project;
import com.sun.jdi.Value;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ArgValueData extends DescriptorData<ArgumentValueDescriptorImpl>{
private final int myIndex;
private final Value myValue;
private final boolean myIsParam;
@Nullable
private final String myDisplayName;
public ArgValueData(int index, Value value, boolean isParam) {
public ArgValueData(int index, Value value, boolean isParam, @Nullable String displayName) {
super();
myIndex = index;
myValue = value;
myIsParam = isParam;
myDisplayName = displayName;
}
protected ArgumentValueDescriptorImpl createDescriptorImpl(@NotNull Project project) {
return new ArgumentValueDescriptorImpl(project, myIndex, myValue, myIsParam);
return new ArgumentValueDescriptorImpl(project, myIndex, myValue, myIsParam, myDisplayName);
}
public boolean equals(Object object) {
@@ -15,8 +15,11 @@
*/
package com.intellij.debugger.jdi;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Comparator;
/**
@@ -34,11 +37,13 @@ public class DecompiledLocalVariable{
private final int mySlot;
private final String mySignature;
private final boolean myIsParam;
private final Collection<String> myMatchedNames;
public DecompiledLocalVariable(int slot, boolean isParam, @Nullable String signature) {
public DecompiledLocalVariable(int slot, boolean isParam, @Nullable String signature, @NotNull Collection<String> names) {
mySlot = slot;
myIsParam = isParam;
mySignature = signature;
myMatchedNames = names;
}
public int getSlot() {
@@ -50,20 +55,33 @@ public class DecompiledLocalVariable{
return mySignature;
}
public String getName() {
return getDefaultName(mySlot, myIsParam);
}
public static String getDefaultName(int slot, boolean isParam) {
return isParam ? "arg_" + slot : "slot_" + slot;
}
public boolean isParam() {
return myIsParam;
}
@NotNull
public String getDefaultName() {
return myIsParam ? "arg_" + mySlot : "slot_" + mySlot;
}
public String getDisplayName() {
String nameString = StringUtil.join(myMatchedNames, " | ");
if (myIsParam && myMatchedNames.size() == 1) {
return nameString;
}
else if (!myMatchedNames.isEmpty()) {
return nameString + ": " + getDefaultName();
}
return getDefaultName();
}
@NotNull
public Collection<String> getMatchedNames() {
return myMatchedNames;
}
@Override
public String toString() {
return getName() + " (" + mySignature + ")";
return getDisplayName() + " (slot " + mySlot + ", " + mySignature + ")";
}
}
@@ -17,13 +17,16 @@ package com.intellij.debugger.jdi;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.ContextUtil;
import com.intellij.debugger.engine.DebugProcess;
import com.intellij.debugger.engine.StackFrameContext;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.impl.SimpleStackFrameContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.util.containers.MultiMap;
import com.sun.jdi.*;
import org.jetbrains.annotations.NotNull;
@@ -116,13 +119,17 @@ public class LocalVariablesUtil {
ourInitializationOk = success;
}
public static Map<DecompiledLocalVariable, Value> fetchValues(StackFrameProxyImpl frameProxy) throws Exception {
public static Map<DecompiledLocalVariable, Value> fetchValues(StackFrameProxyImpl frameProxy, DebugProcess process) throws Exception {
Map<DecompiledLocalVariable, Value> map = new LinkedHashMap<DecompiledLocalVariable, Value>(); // LinkedHashMap for correct order
// gather code variables names
MultiMap<Integer, String> namesMap = calcNames(new SimpleStackFrameContext(frameProxy, process));
// first add arguments
int slot = 0;
for (Value value : frameProxy.getArgumentValues()) {
map.put(new DecompiledLocalVariable(slot++, true, null), value);
map.put(new DecompiledLocalVariable(slot, true, null, namesMap.get(slot)), value);
slot++;
}
if (!ourInitializationOk) {
@@ -130,7 +137,7 @@ public class LocalVariablesUtil {
}
// now try to fetch stack values
List<DecompiledLocalVariable> vars = collectVariablesFromBytecode(frameProxy);
List<DecompiledLocalVariable> vars = collectVariablesFromBytecode(frameProxy, namesMap);
StackFrame frame = frameProxy.getStackFrame();
int size = vars.size();
while (size > 0) {
@@ -201,7 +208,8 @@ public class LocalVariablesUtil {
}
@NotNull
private static List<DecompiledLocalVariable> collectVariablesFromBytecode(final StackFrameProxyImpl frame) throws EvaluateException {
private static List<DecompiledLocalVariable> collectVariablesFromBytecode(StackFrameProxyImpl frame,
final MultiMap<Integer, String> namesMap) throws EvaluateException {
if (!frame.getVirtualMachine().canGetBytecodes()) {
return Collections.emptyList();
}
@@ -225,7 +233,7 @@ public class LocalVariablesUtil {
if (slot >= firstLocalVariableSlot) {
DecompiledLocalVariable variable = usedVars.get(slot);
if (variable == null || !typeSignature.equals(variable.getSignature())) {
variable = new DecompiledLocalVariable(slot, false, typeSignature);
variable = new DecompiledLocalVariable(slot, false, typeSignature, namesMap.get(slot));
usedVars.put(slot, variable);
}
}
@@ -250,49 +258,45 @@ public class LocalVariablesUtil {
}
@NotNull
public static Collection<String> calcNames(@NotNull final StackFrameContext context, final int slotNumber) {
return ApplicationManager.getApplication().runReadAction(new Computable<Collection<String>>() {
private static MultiMap<Integer, String> calcNames(@NotNull final StackFrameContext context) {
return ApplicationManager.getApplication().runReadAction(new Computable<MultiMap<Integer, String>>() {
@Override
public Collection<String> compute() {
public MultiMap<Integer, String> compute() {
SourcePosition position = ContextUtil.getSourcePosition(context);
if (position != null) {
PsiElement method = DebuggerUtilsEx.getContainingMethod(position.getElementAt());
if (method != null) {
PsiParameterList params = DebuggerUtilsEx.getParameterList(method);
if (params != null) {
if (slotNumber < params.getParametersCount()) {
return Collections.singleton(params.getParameters()[slotNumber].getName());
MultiMap<Integer, String> res = new MultiMap<Integer, String>();
for (int i = 0; i < params.getParametersCount(); i++) {
res.putValue(i, params.getParameters()[i].getName());
}
else {
PsiElement body = DebuggerUtilsEx.getBody(method);
if (body != null) {
Set<String> res = new HashSet<String>();
try {
body.accept(new LocalVariableNameFinder(slotNumber, getFirstLocalsSlot(method), res));
}
catch (Exception e) {
LOG.info(e);
}
return res;
PsiElement body = DebuggerUtilsEx.getBody(method);
if (body != null) {
try {
body.accept(new LocalVariableNameFinder(getFirstLocalsSlot(method), res));
}
catch (Exception e) {
LOG.info(e);
}
}
return res;
}
}
}
return Collections.emptyList();
return MultiMap.empty();
}
});
}
private static class LocalVariableNameFinder extends JavaRecursiveElementVisitor {
private final int myStartSlot;
private final Collection<String> myNames;
private final MultiMap<Integer, String> myNames;
private int myCurrentSlotIndex;
private final Stack<Integer> myIndexStack;
private final int mySlotIndex;
public LocalVariableNameFinder(int slot, int startSlot, Set<String> names) {
mySlotIndex = slot;
public LocalVariableNameFinder(int startSlot, MultiMap<Integer, String> names) {
myStartSlot = startSlot;
myNames = names;
myCurrentSlotIndex = myStartSlot;
@@ -318,9 +322,7 @@ public class LocalVariablesUtil {
}
private void appendName(String varName) {
if (myCurrentSlotIndex == mySlotIndex) {
myNames.add(varName);
}
myNames.putValue(myCurrentSlotIndex, varName);
}
@Override
@@ -20,10 +20,7 @@ import com.intellij.debugger.DebuggerContext;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.impl.PositionUtil;
import com.intellij.debugger.jdi.DecompiledLocalVariable;
import com.intellij.debugger.jdi.LocalVariablesUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiExpression;
@@ -31,19 +28,17 @@ import com.intellij.util.IncorrectOperationException;
import com.sun.jdi.PrimitiveValue;
import com.sun.jdi.Value;
import java.util.Collection;
public class ArgumentValueDescriptorImpl extends ValueDescriptorImpl{
private final int myIndex;
private final Value myValue;
private String myName;
private final boolean myIsParam;
public ArgumentValueDescriptorImpl(Project project, int index, Value value, boolean isParam) {
super(project);
public ArgumentValueDescriptorImpl(Project project, int index, Value value, boolean isParam, String displayName) {
super(project, value);
myIndex = index;
myValue = value;
myName = getDefaultName();
myName = displayName;
myIsParam = isParam;
setLvalue(true);
}
@@ -58,21 +53,9 @@ public class ArgumentValueDescriptorImpl extends ValueDescriptorImpl{
}
public Value calcValue(final EvaluationContextImpl evaluationContext) throws EvaluateException {
Collection<String> names = LocalVariablesUtil.calcNames(evaluationContext, myIndex);
String nameString = StringUtil.join(names, " | ");
if (myIsParam && names.size() == 1) {
myName = nameString;
}
else if (!names.isEmpty()) {
myName = nameString + ": " + getDefaultName();
}
return myValue;
}
private String getDefaultName() {
return DecompiledLocalVariable.getDefaultName(myIndex, myIsParam);
}
public String getName() {
return myName;
}
@@ -162,8 +162,8 @@ public class NodeDescriptorFactoryImpl implements NodeDescriptorFactory {
return getDescriptor(parent, new LocalData((LocalVariableProxyImpl)local));
}
public ArgumentValueDescriptorImpl getArgumentValueDescriptor(NodeDescriptor parent, int index, Value value, boolean isParam) {
return getDescriptor(parent, new ArgValueData(index, value, isParam));
public ArgumentValueDescriptorImpl getArgumentValueDescriptor(NodeDescriptor parent, int index, Value value, boolean isParam, String name) {
return getDescriptor(parent, new ArgValueData(index, value, isParam, name));
}
public StackFrameDescriptorImpl getStackFrameDescriptor(@Nullable NodeDescriptorImpl parent, @NotNull StackFrameProxyImpl frameProxy) {