mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
refactoring to prepare compiling evaluator caching
This commit is contained in:
@@ -32,7 +32,7 @@ import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
|
||||
import com.intellij.debugger.requests.ClassPrepareRequestor;
|
||||
import com.intellij.debugger.settings.DebuggerSettings;
|
||||
import com.intellij.debugger.ui.impl.watch.EvaluationDescriptor;
|
||||
import com.intellij.debugger.ui.impl.watch.CompilingEvaluatorImpl;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
@@ -245,7 +245,7 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
}
|
||||
|
||||
throw new EventProcessingException(title[0], ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -269,7 +269,7 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
SourcePosition position = ContextUtil.getSourcePosition(context);
|
||||
PsiElement element = ContextUtil.getContextElement(context, position);
|
||||
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, () ->
|
||||
createExpressionEvaluator(myProject, context, element, position, expressionToEvaluate, this::createLogMessageCodeFragment));
|
||||
createExpressionEvaluator(myProject, element, position, expressionToEvaluate, this::createLogMessageCodeFragment));
|
||||
Value eval = evaluator.evaluate(context);
|
||||
buf.append(eval instanceof VoidValue ? "void" : DebuggerUtils.getValueAsString(context, eval));
|
||||
}
|
||||
@@ -342,9 +342,8 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
}
|
||||
|
||||
try {
|
||||
Project project = context.getProject();
|
||||
SourcePosition contextSourcePosition = ContextUtil.getSourcePosition(context);
|
||||
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(project, () -> {
|
||||
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, () -> {
|
||||
// IMPORTANT: calculate context psi element basing on the location where the exception
|
||||
// has been hit, not on the location where it was set. (For line breakpoints these locations are the same, however,
|
||||
// for method, exception and field breakpoints these locations differ)
|
||||
@@ -352,7 +351,7 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
if (contextPsiElement == null) {
|
||||
contextPsiElement = getEvaluationElement(); // as a last resort
|
||||
}
|
||||
return createExpressionEvaluator(project, context, contextPsiElement, contextSourcePosition, getCondition(),
|
||||
return createExpressionEvaluator(myProject, contextPsiElement, contextSourcePosition, getCondition(),
|
||||
this::createConditionCodeFragment);
|
||||
});
|
||||
return DebuggerUtilsEx.evaluateBoolean(evaluator, context);
|
||||
@@ -368,7 +367,6 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
}
|
||||
|
||||
private static ExpressionEvaluator createExpressionEvaluator(Project project,
|
||||
EvaluationContextImpl context,
|
||||
PsiElement contextPsiElement,
|
||||
SourcePosition contextSourcePosition,
|
||||
TextWithImports text,
|
||||
@@ -378,7 +376,7 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
return EvaluatorBuilderImpl.build(text, contextPsiElement, contextSourcePosition, project);
|
||||
}
|
||||
catch (UnsupportedExpressionException ex) {
|
||||
ExpressionEvaluator eval = EvaluationDescriptor.createCompilingEvaluator(context, contextPsiElement, fragmentFactory);
|
||||
ExpressionEvaluator eval = CompilingEvaluatorImpl.create(project, contextPsiElement, fragmentFactory);
|
||||
if (eval != null) {
|
||||
return eval;
|
||||
}
|
||||
@@ -387,11 +385,11 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
}
|
||||
|
||||
private PsiCodeFragment createConditionCodeFragment(PsiElement context) {
|
||||
return createCodeFragment(getProject(), getCondition(), context);
|
||||
return createCodeFragment(myProject, getCondition(), context);
|
||||
}
|
||||
|
||||
private PsiCodeFragment createLogMessageCodeFragment(PsiElement context) {
|
||||
return createCodeFragment(getProject(), getLogMessage(), context);
|
||||
return createCodeFragment(myProject, getLogMessage(), context);
|
||||
}
|
||||
|
||||
private static PsiCodeFragment createCodeFragment(Project project, TextWithImports text, PsiElement context) {
|
||||
|
||||
@@ -51,10 +51,12 @@ import java.util.Collection;
|
||||
* @author egor
|
||||
*/
|
||||
public abstract class CompilingEvaluator implements ExpressionEvaluator {
|
||||
@NotNull protected final Project myProject;
|
||||
@NotNull protected final PsiElement myPsiContext;
|
||||
@NotNull protected final ExtractLightMethodObjectHandler.ExtractedData myData;
|
||||
|
||||
public CompilingEvaluator(@NotNull PsiElement context, @NotNull ExtractLightMethodObjectHandler.ExtractedData data) {
|
||||
public CompilingEvaluator(@NotNull Project project, @NotNull PsiElement context, @NotNull ExtractLightMethodObjectHandler.ExtractedData data) {
|
||||
myProject = project;
|
||||
myPsiContext = context;
|
||||
myData = data;
|
||||
}
|
||||
@@ -86,16 +88,15 @@ public abstract class CompilingEvaluator implements ExpressionEvaluator {
|
||||
|
||||
try {
|
||||
// invoke base evaluator on call code
|
||||
Project project = ApplicationManager.getApplication().runReadAction((Computable<Project>)myPsiContext::getProject);
|
||||
SourcePosition position = ContextUtil.getSourcePosition(evaluationContext);
|
||||
ExpressionEvaluator evaluator =
|
||||
DebuggerInvocationUtil.commitAndRunReadAction(project, new EvaluatingComputable<ExpressionEvaluator>() {
|
||||
DebuggerInvocationUtil.commitAndRunReadAction(myProject, new EvaluatingComputable<ExpressionEvaluator>() {
|
||||
@Override
|
||||
public ExpressionEvaluator compute() throws EvaluateException {
|
||||
TextWithImports callCode = getCallCode();
|
||||
PsiElement copyContext = myData.getAnchor();
|
||||
CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(callCode, copyContext);
|
||||
return factory.getEvaluatorBuilder().build(factory.createCodeFragment(callCode, copyContext, project), position);
|
||||
return factory.getEvaluatorBuilder().build(factory.createCodeFragment(callCode, copyContext, myProject), position);
|
||||
}
|
||||
});
|
||||
((EvaluationContextImpl)evaluationContext).setClassLoader(classLoader);
|
||||
@@ -148,12 +149,8 @@ public abstract class CompilingEvaluator implements ExpressionEvaluator {
|
||||
|
||||
|
||||
protected String getGenClassQName() {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
|
||||
@Override
|
||||
public String compute() {
|
||||
return JVMNameUtil.getNonAnonymousClassName(myData.getGeneratedInnerClass());
|
||||
}
|
||||
});
|
||||
return ApplicationManager.getApplication().runReadAction(
|
||||
(Computable<String>)() -> JVMNameUtil.getNonAnonymousClassName(myData.getGeneratedInnerClass()));
|
||||
}
|
||||
|
||||
///////////////// Compiler stuff
|
||||
|
||||
+56
-29
@@ -18,7 +18,7 @@ package com.intellij.debugger.ui.impl.watch;
|
||||
import com.intellij.compiler.CompilerConfiguration;
|
||||
import com.intellij.compiler.server.BuildManager;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.compiler.ClassObject;
|
||||
import com.intellij.openapi.compiler.CompilationException;
|
||||
@@ -26,15 +26,20 @@ import com.intellij.openapi.compiler.CompilerManager;
|
||||
import com.intellij.openapi.compiler.CompilerMessageCategory;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.JavaSdkVersion;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.PsiCodeFragment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.refactoring.extractMethod.PrepareFailedException;
|
||||
import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -44,35 +49,31 @@ import org.jetbrains.jps.model.java.compiler.AnnotationProcessingConfiguration;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
// todo: consider batching compilations in order not to start a separate process for every class that needs to be compiled
|
||||
public class CompilingEvaluatorImpl extends CompilingEvaluator {
|
||||
|
||||
private final EvaluationContextImpl myEvaluationContext;
|
||||
|
||||
public CompilingEvaluatorImpl(EvaluationContextImpl evaluationContext, @NotNull PsiElement context, @NotNull ExtractLightMethodObjectHandler.ExtractedData data) {
|
||||
super(context, data);
|
||||
myEvaluationContext = evaluationContext;
|
||||
public CompilingEvaluatorImpl(@NotNull Project project,
|
||||
@NotNull PsiElement context,
|
||||
@NotNull ExtractLightMethodObjectHandler.ExtractedData data) {
|
||||
super(project, context, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected Collection<ClassObject> compile(@Nullable JavaSdkVersion debuggeeVersion) throws EvaluateException {
|
||||
final Module module = ApplicationManager.getApplication().runReadAction(new Computable<Module>() {
|
||||
@Override
|
||||
public Module compute() {
|
||||
return ModuleUtilCore.findModuleForPsiElement(myPsiContext);
|
||||
}
|
||||
});
|
||||
final List<String> options = new ArrayList<>();
|
||||
Module module = ApplicationManager.getApplication().runReadAction(
|
||||
(Computable<Module>)() -> ModuleUtilCore.findModuleForPsiElement(myPsiContext));
|
||||
List<String> options = new ArrayList<>();
|
||||
options.add("-encoding");
|
||||
options.add("UTF-8");
|
||||
final List<File> platformClasspath = new ArrayList<>();
|
||||
final List<File> classpath = new ArrayList<>();
|
||||
List<File> platformClasspath = new ArrayList<>();
|
||||
List<File> classpath = new ArrayList<>();
|
||||
AnnotationProcessingConfiguration profile = null;
|
||||
if (module != null) {
|
||||
profile = CompilerConfiguration.getInstance(module.getProject()).getAnnotationProcessingConfiguration(module);
|
||||
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
|
||||
assert myProject.equals(module.getProject()) : module + " is from another project";
|
||||
profile = CompilerConfiguration.getInstance(myProject).getAnnotationProcessingConfiguration(module);
|
||||
ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
|
||||
for (String s : rootManager.orderEntries().compileOnly().recursively().exportedOnly().withoutSdk().getPathsList().getPathList()) {
|
||||
classpath.add(new File(s));
|
||||
}
|
||||
@@ -82,31 +83,31 @@ public class CompilingEvaluatorImpl extends CompilingEvaluator {
|
||||
}
|
||||
JavaBuilder.addAnnotationProcessingOptions(options, profile);
|
||||
|
||||
final Pair<Sdk, JavaSdkVersion> runtime = BuildManager.getJavacRuntimeSdk(myEvaluationContext.getProject());
|
||||
final JavaSdkVersion buildRuntimeVersion = runtime.getSecond();
|
||||
Pair<Sdk, JavaSdkVersion> runtime = BuildManager.getJavacRuntimeSdk(myProject);
|
||||
JavaSdkVersion buildRuntimeVersion = runtime.getSecond();
|
||||
// if compiler or debuggee version or both are unknown, let source and target be the compiler's defaults
|
||||
if (buildRuntimeVersion != null && debuggeeVersion != null) {
|
||||
final JavaSdkVersion minVersion = buildRuntimeVersion.ordinal() > debuggeeVersion.ordinal() ? debuggeeVersion : buildRuntimeVersion;
|
||||
final String sourceOption = getSourceOption(minVersion.getMaxLanguageLevel());
|
||||
JavaSdkVersion minVersion = buildRuntimeVersion.ordinal() > debuggeeVersion.ordinal() ? debuggeeVersion : buildRuntimeVersion;
|
||||
String sourceOption = getSourceOption(minVersion.getMaxLanguageLevel());
|
||||
options.add("-source");
|
||||
options.add(sourceOption);
|
||||
options.add("-target");
|
||||
options.add(sourceOption);
|
||||
}
|
||||
|
||||
final CompilerManager compilerManager = CompilerManager.getInstance(myEvaluationContext.getProject());
|
||||
CompilerManager compilerManager = CompilerManager.getInstance(myProject);
|
||||
|
||||
File sourceFile = null;
|
||||
try {
|
||||
sourceFile = generateTempSourceFile(compilerManager.getJavacCompilerWorkingDir());
|
||||
final File srcDir = sourceFile.getParentFile();
|
||||
final List<File> sourcePath = Collections.emptyList();
|
||||
final Set<File> sources = Collections.singleton(sourceFile);
|
||||
File srcDir = sourceFile.getParentFile();
|
||||
List<File> sourcePath = Collections.emptyList();
|
||||
Set<File> sources = Collections.singleton(sourceFile);
|
||||
|
||||
return compilerManager.compileJavaCode(options, platformClasspath, classpath, Collections.emptyList(), sourcePath, sources, srcDir);
|
||||
}
|
||||
catch (CompilationException e) {
|
||||
final StringBuilder res = new StringBuilder("Compilation failed:\n");
|
||||
StringBuilder res = new StringBuilder("Compilation failed:\n");
|
||||
for (CompilationException.Message m : e.getMessages()) {
|
||||
if (m.getCategory() == CompilerMessageCategory.ERROR) {
|
||||
res.append(m.getText()).append("\n");
|
||||
@@ -130,7 +131,7 @@ public class CompilingEvaluatorImpl extends CompilingEvaluator {
|
||||
}
|
||||
|
||||
private File generateTempSourceFile(File workingDir) throws IOException {
|
||||
final Pair<String, String> fileData = ApplicationManager.getApplication().runReadAction((Computable<Pair<String, String>>)() -> {
|
||||
Pair<String, String> fileData = ApplicationManager.getApplication().runReadAction((Computable<Pair<String, String>>)() -> {
|
||||
PsiFile file = myData.getGeneratedInnerClass().getContainingFile();
|
||||
return Pair.create(file.getName(), file.getText());
|
||||
});
|
||||
@@ -140,8 +141,34 @@ public class CompilingEvaluatorImpl extends CompilingEvaluator {
|
||||
if (fileData.second == null) {
|
||||
throw new IOException("Class source code not specified");
|
||||
}
|
||||
final File file = new File(workingDir, "debugger/src/"+fileData.first);
|
||||
File file = new File(workingDir, "debugger/src/" + fileData.first);
|
||||
FileUtil.writeToFile(file, fileData.second);
|
||||
return file;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ExpressionEvaluator create(@NotNull Project project,
|
||||
@Nullable PsiElement psiContext,
|
||||
@NotNull Function<PsiElement, PsiCodeFragment> fragmentFactory)
|
||||
throws EvaluateException {
|
||||
if (Registry.is("debugger.compiling.evaluator") && psiContext != null) {
|
||||
return ApplicationManager.getApplication().runReadAction((ThrowableComputable<ExpressionEvaluator, EvaluateException>)() -> {
|
||||
try {
|
||||
ExtractLightMethodObjectHandler.ExtractedData data = ExtractLightMethodObjectHandler.extractLightMethodObject(
|
||||
project,
|
||||
psiContext.getContainingFile(),
|
||||
fragmentFactory.apply(psiContext),
|
||||
getGeneratedClassName());
|
||||
if (data != null) {
|
||||
return new CompilingEvaluatorImpl(project, psiContext, data);
|
||||
}
|
||||
}
|
||||
catch (PrepareFailedException e) {
|
||||
NodeDescriptorImpl.LOG.info(e);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+17
-46
@@ -30,20 +30,16 @@ import com.intellij.debugger.engine.evaluation.expression.UnsupportedExpressionE
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.refactoring.extractMethod.PrepareFailedException;
|
||||
import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler;
|
||||
import com.intellij.psi.PsiCodeFragment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.psi.PsiExpressionCodeFragment;
|
||||
import com.intellij.xdebugger.frame.XValueModifier;
|
||||
import com.sun.jdi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author lex
|
||||
*/
|
||||
@@ -71,25 +67,26 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl {
|
||||
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, context).createCodeFragment(text, context, myProject);
|
||||
}
|
||||
|
||||
public final Value calcValue(final EvaluationContextImpl evaluationContext) throws EvaluateException {
|
||||
public final Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
|
||||
try {
|
||||
final EvaluationContextImpl thisEvaluationContext = getEvaluationContext(evaluationContext);
|
||||
EvaluationContextImpl thisEvaluationContext = getEvaluationContext(evaluationContext);
|
||||
SourcePosition position = ContextUtil.getSourcePosition(evaluationContext);
|
||||
PsiElement psiContext = ContextUtil.getContextElement(evaluationContext, position);
|
||||
|
||||
ExpressionEvaluator evaluator;
|
||||
try {
|
||||
evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, () ->
|
||||
DebuggerUtilsEx.findAppropriateCodeFragmentFactory(getEvaluationText(), psiContext)
|
||||
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, () -> {
|
||||
try {
|
||||
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(getEvaluationText(), psiContext)
|
||||
.getEvaluatorBuilder()
|
||||
.build(getEvaluationCode(thisEvaluationContext), position));
|
||||
}
|
||||
catch (UnsupportedExpressionException ex) {
|
||||
evaluator = createCompilingEvaluator(evaluationContext, psiContext, this::createCodeFragment);
|
||||
if (evaluator == null) {
|
||||
.build(getEvaluationCode(thisEvaluationContext), position);
|
||||
}
|
||||
catch (UnsupportedExpressionException ex) {
|
||||
ExpressionEvaluator eval = CompilingEvaluatorImpl.create(myProject, psiContext, this::createCodeFragment);
|
||||
if (eval != null) {
|
||||
return eval;
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!thisEvaluationContext.getDebugProcess().isAttached()) {
|
||||
throw EvaluateExceptionUtil.PROCESS_EXITED;
|
||||
@@ -115,32 +112,6 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ExpressionEvaluator createCompilingEvaluator(EvaluationContextImpl evaluationContext,
|
||||
@Nullable PsiElement psiContext,
|
||||
Function<PsiElement, PsiCodeFragment> fragmentFactory)
|
||||
throws EvaluateException {
|
||||
if (Registry.is("debugger.compiling.evaluator") && psiContext != null) {
|
||||
return ApplicationManager.getApplication().runReadAction((ThrowableComputable<ExpressionEvaluator, EvaluateException>)() -> {
|
||||
try {
|
||||
ExtractLightMethodObjectHandler.ExtractedData data = ExtractLightMethodObjectHandler.extractLightMethodObject(
|
||||
evaluationContext.getProject(),
|
||||
psiContext.getContainingFile(),
|
||||
fragmentFactory.apply(psiContext),
|
||||
CompilingEvaluator.getGeneratedClassName());
|
||||
if (data != null) {
|
||||
return new CompilingEvaluatorImpl(evaluationContext, psiContext, data);
|
||||
}
|
||||
}
|
||||
catch (PrepareFailedException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
|
||||
PsiElement evaluationCode = getEvaluationCode(context);
|
||||
if (evaluationCode instanceof PsiExpressionCodeFragment) {
|
||||
|
||||
Reference in New Issue
Block a user