summaryrefslogtreecommitdiff
path: root/java/debugger/impl/src/com/intellij/debugger/ui
diff options
context:
space:
mode:
Diffstat (limited to 'java/debugger/impl/src/com/intellij/debugger/ui')
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java2
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java2
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java217
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java23
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java15
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/LocalVariableDescriptorImpl.java12
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java1
7 files changed, 259 insertions, 13 deletions
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java
index b2b0091fc949..601ec7957849 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java
@@ -38,7 +38,7 @@ import java.util.Collections;
import java.util.List;
public class HotSwapProgressImpl extends HotSwapProgress{
- static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.toolWindowGroup("HotSwap", ToolWindowId.DEBUG, true);
+ static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.toolWindowGroup("HotSwap", ToolWindowId.DEBUG);
TIntObjectHashMap<List<String>> myMessages = new TIntObjectHashMap<List<String>>();
private final ProgressWindow myProgressWindow;
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java
index 20d95f8fff3d..ec2288fa7a57 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java
@@ -165,7 +165,7 @@ public class JavaDebuggerSupport extends DebuggerSupport {
@NotNull
@Override
public DebuggerActionHandler getAddToWatchesActionHandler() {
- return myAddToWatchedActionHandler;
+ return DISABLED;
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java
new file mode 100644
index 000000000000..042216c40f05
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.debugger.ui.impl.watch;
+
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.debugger.engine.evaluation.expression.Modifier;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.sun.jdi.*;
+
+import javax.tools.*;
+import java.io.ByteArrayOutputStream;
+import java.net.URI;
+import java.util.*;
+
+/**
+* @author egor
+*/
+class CompilingEvaluator implements ExpressionEvaluator {
+ private final TextWithImports myText;
+
+ public CompilingEvaluator(TextWithImports text) {
+ myText = text;
+ }
+
+ @Override
+ public Value getValue() {
+ return null;
+ }
+
+ @Override
+ public Modifier getModifier() {
+ return null;
+ }
+
+ @Override
+ public Value evaluate(EvaluationContext context) throws EvaluateException {
+ try {
+ DebugProcess process = context.getDebugProcess();
+ ThreadReference threadReference = context.getSuspendContext().getThread().getThreadReference();
+
+ ClassLoaderReference classLoader = getClassLoader(context);
+
+ Collection<OutputFileObject> classes = compile();
+
+ ClassType mainClass = defineClasses(classes, context, process, threadReference, classLoader);
+
+ Method foo = mainClass.methodsByName(GEN_METHOD_NAME).get(0);
+ return mainClass.invokeMethod(threadReference, foo, Collections.<Value>emptyList() ,ClassType.INVOKE_SINGLE_THREADED);
+ }
+ catch (Exception e) {
+ throw new EvaluateException(e.getMessage());
+ }
+ }
+
+ private static ClassLoaderReference getClassLoader(EvaluationContext context)
+ throws EvaluateException, InvocationException, InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException {
+ // TODO: cache
+ DebugProcess process = context.getDebugProcess();
+ ClassType loaderClass = (ClassType)process.findClass(context, "java.net.URLClassLoader", context.getClassLoader());
+ Method ctorMethod = loaderClass.concreteMethodByName("<init>", "([Ljava/net/URL;)V");
+ ThreadReference threadReference = context.getSuspendContext().getThread().getThreadReference();
+ return (ClassLoaderReference)loaderClass.newInstance(threadReference, ctorMethod,
+ Arrays.asList(createURLArray(context)), ClassType.INVOKE_SINGLE_THREADED);
+ }
+
+ private static ClassType defineClasses(Collection<OutputFileObject> classes,
+ EvaluationContext context,
+ DebugProcess process,
+ ThreadReference threadReference,
+ ClassLoaderReference classLoader)
+ throws EvaluateException, InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException {
+
+ VirtualMachineProxyImpl proxy = (VirtualMachineProxyImpl)process.getVirtualMachineProxy();
+ for (OutputFileObject cls : classes) {
+ Method defineMethod = ((ClassType)classLoader.referenceType()).concreteMethodByName("defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
+ byte[] bytes = cls.toByteArray();
+ ArrayList<Value> args = new ArrayList<Value>();
+ args.add(proxy.mirrorOf(cls.myOrigName));
+ args.add(mirrorOf(bytes, context, process));
+ args.add(proxy.mirrorOf(0));
+ args.add(proxy.mirrorOf(bytes.length));
+ classLoader.invokeMethod(threadReference, defineMethod, args, ClassType.INVOKE_SINGLE_THREADED);
+ }
+ return (ClassType)process.findClass(context, GEN_CLASS_FULL_NAME, classLoader);
+ }
+
+ private static ArrayReference mirrorOf(byte[] bytes, EvaluationContext context, DebugProcess process)
+ throws EvaluateException, InvalidTypeException, ClassNotLoadedException {
+ ArrayType arrayClass = (ArrayType)process.findClass(context, "byte[]", context.getClassLoader());
+ ArrayReference reference = process.newInstance(arrayClass, bytes.length);
+ reference.disableCollection();
+ for (int i = 0; i < bytes.length; i++) {
+ reference.setValue(i, ((VirtualMachineProxyImpl)process.getVirtualMachineProxy()).mirrorOf(bytes[i]));
+ }
+ return reference;
+ }
+
+ private static final String GEN_CLASS_NAME = "Evaluator";
+ private static final String GEN_CLASS_PACKAGE = "dummy";
+ private static final String GEN_CLASS_FULL_NAME = GEN_CLASS_PACKAGE + '.' + GEN_CLASS_NAME;
+ private static final String GEN_METHOD_NAME = "eval";
+
+ private static String createClassCode(TextWithImports body) {
+ StringBuilder text = new StringBuilder();
+ text.append("package " + GEN_CLASS_PACKAGE + ";");
+ String imports = body.getImports();
+ if (!imports.isEmpty()) {
+ for (String s : imports.split(",")) {
+ text.append("import " + s + ";");
+ }
+ }
+ String bodyText = body.getText();
+ if (!bodyText.endsWith(";")) {
+ bodyText += ';';
+ }
+ text.append("public class " + GEN_CLASS_NAME + " { public static Object " + GEN_METHOD_NAME + "() throws Exception {" + bodyText + "}}");
+ return text.toString();
+ }
+
+ private static ArrayReference createURLArray(EvaluationContext context)
+ throws EvaluateException, InvocationException, InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException {
+ DebugProcess process = context.getDebugProcess();
+ ArrayType arrayType = (ArrayType)process.findClass(context, "java.net.URL[]", context.getClassLoader());
+ ArrayReference arrayRef = arrayType.newInstance(1);
+ ClassType classType = (ClassType)process.findClass(context, "java.net.URL", context.getClassLoader());
+ VirtualMachineProxyImpl proxy = (VirtualMachineProxyImpl)process.getVirtualMachineProxy();
+ ThreadReference threadReference = context.getSuspendContext().getThread().getThreadReference();
+ ObjectReference reference = classType.newInstance(threadReference, classType.concreteMethodByName("<init>", "(Ljava/lang/String;)V"),
+ Arrays.asList(proxy.mirrorOf("file:a")), ClassType.INVOKE_SINGLE_THREADED);
+ arrayRef.setValues(Arrays.asList(reference));
+ return arrayRef;
+ }
+
+ ///////////////// Compiler stuff
+
+ private Collection<OutputFileObject> compile() throws EvaluateException {
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ MemoryFileManager manager = new MemoryFileManager(compiler);
+ DiagnosticCollector<JavaFileObject> diagnostic = new DiagnosticCollector<JavaFileObject>();
+ if (!compiler.getTask(null, manager, diagnostic, null, null, Arrays
+ .asList(new SourceFileObject(GEN_CLASS_NAME, JavaFileObject.Kind.SOURCE, createClassCode(myText)))).call()) {
+ // TODO: show only errors
+ throw new EvaluateException(diagnostic.getDiagnostics().get(0).getMessage(Locale.getDefault()));
+ }
+ return manager.classes;
+ }
+
+ private static URI getUri(String name, JavaFileObject.Kind kind) {
+ return URI.create("memo:///" + name.replace('.', '/') + kind.extension);
+ }
+
+ private static class SourceFileObject extends SimpleJavaFileObject {
+ private final String myContent;
+
+ SourceFileObject(String name, Kind kind, String content) {
+ super(getUri(name, kind), kind);
+ myContent = content;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignore) {
+ return myContent;
+ }
+ }
+
+ private static class OutputFileObject extends SimpleJavaFileObject {
+ private final ByteArrayOutputStream myStream = new ByteArrayOutputStream();
+ private final String myOrigName;
+
+ OutputFileObject(String name, Kind kind) {
+ super(getUri(name, kind), kind);
+ myOrigName = name;
+ }
+
+ byte[] toByteArray() {
+ return myStream.toByteArray();
+ }
+
+ @Override
+ public ByteArrayOutputStream openOutputStream() {
+ return myStream;
+ }
+ }
+
+ private static class MemoryFileManager extends ForwardingJavaFileManager {
+ private final Collection<OutputFileObject> classes = new ArrayList<OutputFileObject>();
+
+ MemoryFileManager(JavaCompiler compiler) {
+ super(compiler.getStandardFileManager(null, null, null));
+ }
+
+ @Override
+ public OutputFileObject getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject source) {
+ OutputFileObject mc = new OutputFileObject(name, kind);
+ classes.add(mc);
+ return mc;
+ }
+ }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java
index e09c17c979e5..1f880513cacd 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java
@@ -28,6 +28,7 @@ import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.impl.PositionUtil;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.PsiCodeFragment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
@@ -80,14 +81,20 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl{
try {
final EvaluationContextImpl thisEvaluationContext = getEvaluationContext(evaluationContext);
- final ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, new EvaluatingComputable<ExpressionEvaluator>() {
- public ExpressionEvaluator compute() throws EvaluateException {
- final PsiElement psiContext = PositionUtil.getContextElement(evaluationContext);
- return getEffectiveCodeFragmentFactory(psiContext).getEvaluatorBuilder().build(getEvaluationCode(thisEvaluationContext),
- ContextUtil.getSourcePosition(thisEvaluationContext));
- }
- });
-
+ final ExpressionEvaluator evaluator;
+ if (Registry.is("debugger.compiling.evaluator")) {
+ evaluator = new CompilingEvaluator(getEvaluationText());
+ }
+ else {
+ evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, new EvaluatingComputable<ExpressionEvaluator>() {
+ public ExpressionEvaluator compute() throws EvaluateException {
+ final PsiElement psiContext = PositionUtil.getContextElement(evaluationContext);
+ return getEffectiveCodeFragmentFactory(psiContext).getEvaluatorBuilder().build(getEvaluationCode(thisEvaluationContext),
+ ContextUtil
+ .getSourcePosition(thisEvaluationContext));
+ }
+ });
+ }
if (!thisEvaluationContext.getDebugProcess().isAttached()) {
throw EvaluateExceptionUtil.PROCESS_EXITED;
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java
index 6a7a57ba7670..c36630e3a973 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerContextUtil;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.debugger.impl.PositionUtil;
import com.intellij.debugger.settings.NodeRendererSettings;
@@ -73,6 +74,12 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes
@SuppressWarnings({"HardCodedStringLiteral"})
@Nullable
public SourcePosition getSourcePosition(final Project project, final DebuggerContextImpl context) {
+ return getSourcePosition(project, context, false);
+ }
+
+ @SuppressWarnings({"HardCodedStringLiteral"})
+ @Nullable
+ public SourcePosition getSourcePosition(final Project project, final DebuggerContextImpl context, boolean nearest) {
if (context.getFrameProxy() == null) {
return null;
}
@@ -95,6 +102,9 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes
if (psiVariable == null) {
return null;
}
+ if (nearest) {
+ return DebuggerContextUtil.findNearest(context, psiVariable, aClass.getContainingFile());
+ }
return SourcePosition.createFromOffset(psiVariable.getContainingFile(), psiVariable.getTextOffset());
}
else {
@@ -125,6 +135,9 @@ public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDes
aClass = (PsiClass) aClass.getNavigationElement();
for (PsiField field : aClass.getFields()) {
if (fieldName.equals(field.getName())) {
+ if (nearest) {
+ return DebuggerContextUtil.findNearest(context, field, aClass.getContainingFile());
+ }
return SourcePosition.createFromOffset(field.getContainingFile(), field.getTextOffset());
}
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/LocalVariableDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/LocalVariableDescriptorImpl.java
index d2109c54f1c4..f936d79a6725 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/LocalVariableDescriptorImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/LocalVariableDescriptorImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerContextUtil;
import com.intellij.debugger.impl.PositionUtil;
import com.intellij.debugger.jdi.LocalVariableProxyImpl;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
@@ -61,6 +62,11 @@ public class LocalVariableDescriptorImpl extends ValueDescriptorImpl implements
@Nullable
public SourcePosition getSourcePosition(final Project project, final DebuggerContextImpl context) {
+ return getSourcePosition(project, context, false);
+ }
+
+ @Nullable
+ public SourcePosition getSourcePosition(final Project project, final DebuggerContextImpl context, boolean nearest) {
StackFrameProxyImpl frame = context.getFrameProxy();
if (frame == null) return null;
@@ -77,7 +83,9 @@ public class LocalVariableDescriptorImpl extends ValueDescriptorImpl implements
PsiFile containingFile = psiVariable.getContainingFile();
if(containingFile == null) return null;
-
+ if (nearest) {
+ return DebuggerContextUtil.findNearest(context, psiVariable, containingFile);
+ }
return SourcePosition.createFromOffset(containingFile, psiVariable.getTextOffset());
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java
index f4da39f318a7..680d2ab424c3 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java
@@ -203,6 +203,7 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements
}
catch (EvaluateException e) {
myValueException = e;
+ setFailed(e);
myValue = getTargetExceptionWithStackTraceFilled(evaluationContext, e);
myIsExpandable = false;
}