From b446b776e9b8dcabe19cfc7c7aaa7d5551a4381b Mon Sep 17 00:00:00 2001 From: "Alexey.Merkulov" Date: Fri, 27 Jun 2025 19:44:36 +0200 Subject: [PATCH] [debugger] Refactoring: Prepare to support java instrumentation Prepare for IDEA-370744 GitOrigin-RevId: d28b2941347a480037b92b917035b4b503083c09 --- .../compiler/CompilerManagerImpl.java | 6 ++-- .../ui/impl/watch/CompilingEvaluator.java | 29 +++++++++++++++---- .../ui/impl/watch/CompilingEvaluatorImpl.java | 24 ++++++++++----- .../ExtractGeneratedClassUtil.java | 21 ++++++++++---- .../ExtractLightMethodObjectHandler.java | 13 ++++++++- 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java index 1680f3579b27..288d0c45771a 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java @@ -41,6 +41,7 @@ import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.net.NetUtils; import com.intellij.util.ui.EDT; import kotlin.Unit; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -540,12 +541,13 @@ public class CompilerManagerImpl extends CompilerManager { return projectBuildDir; } - private static final class CompiledClass implements ClassObject { + @ApiStatus.Internal + public static final class CompiledClass implements ClassObject { private final String myPath; private final String myClassName; private final byte[] myBytes; - CompiledClass(String path, String className, byte[] bytes) { + public CompiledClass(String path, String className, byte[] bytes) { myPath = path; myClassName = className; myBytes = bytes; 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 index f8ff10d91dda..a32095798239 100644 --- 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 @@ -15,10 +15,13 @@ import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.compiler.ClassObject; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.psi.JavaRecursiveElementVisitor; +import com.intellij.psi.PsiCodeFragment; import com.intellij.psi.PsiElement; import com.intellij.refactoring.extractMethodObject.LightMethodObjectExtractedData; import com.sun.jdi.ClassLoaderReference; import com.sun.jdi.Value; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.org.objectweb.asm.ClassReader; @@ -39,12 +42,18 @@ public abstract class CompilingEvaluator implements ExpressionEvaluator { myData = data; } + @ApiStatus.Internal + public @NotNull LightMethodObjectExtractedData getLightMethodObjectExtractedData() { + return myData; + } + @Override public Modifier getModifier() { return null; } - private TextWithImports getCallCode() { + @ApiStatus.Internal + public @NotNull TextWithImports getCallCode() { return new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK, myData.getGeneratedCallText()); } @@ -88,18 +97,28 @@ public abstract class CompilingEvaluator implements ExpressionEvaluator { ClassLoaderReference classLoader) throws EvaluateException { boolean useMagicAccessorImpl = myData.useMagicAccessor(); + defineClassesForEvaluation(classes, context, process, classLoader, GEN_CLASS_NAME, useMagicAccessorImpl); + process.findClass(context, getGenClassQName(), classLoader); + } + + @ApiStatus.Internal + public static void defineClassesForEvaluation(@NotNull Collection classes, + EvaluationContextImpl context, + DebugProcess process, + ClassLoaderReference classLoader, + @NotNull String generatedClassName, + boolean useMagicAccessor) throws EvaluateException { for (ClassObject cls : classes) { - if (cls.getPath().contains(GEN_CLASS_NAME)) { + if (cls.getPath().contains(generatedClassName)) { byte[] bytes = cls.getContent(); if (bytes != null) { - if (useMagicAccessorImpl) { + if (useMagicAccessor) { bytes = changeSuperToMagicAccessor(bytes); } ClassLoadingUtils.defineClass(cls.getClassName(), bytes, context, classLoader); } } } - process.findClass(context, getGenClassQName(), classLoader); } private static byte[] changeSuperToMagicAccessor(byte[] bytes) { @@ -133,5 +152,5 @@ public abstract class CompilingEvaluator implements ExpressionEvaluator { ///////////////// Compiler stuff - protected abstract @NotNull Collection compile(@Nullable JavaSdkVersion debuggeeVersion) throws EvaluateException; + public abstract @NotNull Collection compile(@Nullable JavaSdkVersion debuggeeVersion) throws EvaluateException; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluatorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluatorImpl.java index e8fbe6386d91..f72718cec5aa 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluatorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluatorImpl.java @@ -6,7 +6,6 @@ import com.intellij.compiler.server.BuildManager; import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.IncorrectCodeFragmentException; -import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator; import com.intellij.execution.configurations.JavaParameters; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.compiler.ClassObject; @@ -33,6 +32,7 @@ import com.intellij.refactoring.extractMethodObject.LightMethodObjectExtractedDa import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.frame.XSuspendContext; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.incremental.java.JavaBuilder; @@ -60,7 +60,7 @@ public class CompilingEvaluatorImpl extends CompilingEvaluator { } @Override - protected @NotNull Collection compile(@Nullable JavaSdkVersion debuggeeVersion) throws EvaluateException { + public @NotNull Collection compile(@Nullable JavaSdkVersion debuggeeVersion) throws EvaluateException { if (myCompiledClasses == null) { List options = new ArrayList<>(); options.add("-encoding"); @@ -146,9 +146,18 @@ public class CompilingEvaluatorImpl extends CompilingEvaluator { return file; } - public static @Nullable ExpressionEvaluator create(@NotNull Project project, - @Nullable PsiElement psiContext, - @NotNull Function fragmentFactory) + public static @Nullable CompilingEvaluator create(@NotNull Project project, + @Nullable PsiElement psiContext, + @NotNull Function fragmentFactory) + throws EvaluateException { + return create(project, psiContext, null, fragmentFactory); + } + + @ApiStatus.Internal + public static @Nullable CompilingEvaluator create(@NotNull Project project, + @Nullable PsiElement psiContext, + @Nullable String generatedClassName, + @NotNull Function fragmentFactory) throws EvaluateException { if (Registry.is("debugger.compiling.evaluator") && psiContext != null) { return ReadAction.compute(() -> { @@ -160,8 +169,9 @@ public class CompilingEvaluatorImpl extends CompilingEvaluator { project, physicalContext != null ? physicalContext : psiContext, fragmentFactory.apply(psiContext), - getGeneratedClassName(), - javaVersion); + generatedClassName != null ? generatedClassName : getGeneratedClassName(), + javaVersion, + generatedClassName); if (data != null) { return new CompilingEvaluatorImpl(project, psiContext, data); } diff --git a/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethodObject/ExtractGeneratedClassUtil.java b/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethodObject/ExtractGeneratedClassUtil.java index b6f4d7225fbc..6ddd324c45d7 100644 --- a/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethodObject/ExtractGeneratedClassUtil.java +++ b/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethodObject/ExtractGeneratedClassUtil.java @@ -14,15 +14,25 @@ import org.jetbrains.annotations.Nullable; import java.util.List; final class ExtractGeneratedClassUtil { - private static final String GENERATED_CLASS_PACKAGE = "idea.debugger.rt"; private static final Logger LOG = Logger.getInstance(ExtractGeneratedClassUtil.class); static PsiClass extractGeneratedClass(@NotNull PsiClass generatedInnerClass, @NotNull PsiElementFactory elementFactory, - @NotNull PsiElement anchor) { + @NotNull PsiElement anchor, + @Nullable String explicitGeneratedEvaluationClassFullName) { Project project = generatedInnerClass.getProject(); - PsiClass extractedClass = elementFactory.createClass("GeneratedEvaluationClass"); + if (explicitGeneratedEvaluationClassFullName == null) { + explicitGeneratedEvaluationClassFullName = "idea.debugger.rt.GeneratedEvaluationClass"; + } + + int dotIndex = explicitGeneratedEvaluationClassFullName.lastIndexOf('.'); + + + String generatedEvaluationClass = dotIndex == -1 ? explicitGeneratedEvaluationClassFullName : explicitGeneratedEvaluationClassFullName.substring(dotIndex + 1); + String packageName = dotIndex == -1 ? "" : explicitGeneratedEvaluationClassFullName.substring(0, dotIndex); + + PsiClass extractedClass = elementFactory.createClass(generatedEvaluationClass); for (PsiField field : generatedInnerClass.getAllFields()) { extractedClass.add(elementFactory.createFieldFromText(field.getText(), anchor)); // TODO: check if null is OK @@ -34,9 +44,8 @@ final class ExtractGeneratedClassUtil { PsiJavaFile generatedFile = (PsiJavaFile)PsiFileFactory.getInstance(project) .createFileFromText(extractedClass.getName() + ".java", JavaFileType.INSTANCE, extractedClass.getContainingFile().getText()); - // copy.getModificationStamp(), - //false, false); - generatedFile.setPackageName(GENERATED_CLASS_PACKAGE); + + generatedFile.setPackageName(packageName); extractedClass = PsiTreeUtil.findChildOfType(generatedFile, PsiClass.class); copyStaticImports(generatedInnerClass, generatedFile, elementFactory); assert extractedClass != null; diff --git a/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java b/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java index 8cce8da745ea..17cc00ac5511 100644 --- a/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java +++ b/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java @@ -26,6 +26,7 @@ import com.intellij.util.CommonJavaRefactoringUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,6 +42,16 @@ public final class ExtractLightMethodObjectHandler { final @NotNull PsiCodeFragment fragment, @NotNull String methodName, @Nullable JavaSdkVersion javaVersion) throws PrepareFailedException { + return extractLightMethodObject(project, originalContext, fragment, methodName, javaVersion, null); + } + + @ApiStatus.Internal + public static @Nullable LightMethodObjectExtractedData extractLightMethodObject(final Project project, + @Nullable PsiElement originalContext, + final @NotNull PsiCodeFragment fragment, + @NotNull String methodName, + @Nullable JavaSdkVersion javaVersion, + @Nullable String explicitGeneratedEvaluationClassName) throws PrepareFailedException { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); PsiElement[] elements = completeToStatementArray(fragment, elementFactory); if (elements == null) { @@ -262,7 +273,7 @@ public final class ExtractLightMethodObjectHandler { new ReflectionAccessorToEverything(generatedClass, elementFactory).grantAccessThroughReflection(callExpression); boolean isJdkAtLeast11 = javaVersion == null || javaVersion.isAtLeast(JavaSdkVersion.JDK_11); if (isJdkAtLeast11 || Registry.is("debugger.compiling.evaluator.extract.generated.class")) { - generatedClass = ExtractGeneratedClassUtil.extractGeneratedClass(generatedClass, elementFactory, anchor); + generatedClass = ExtractGeneratedClassUtil.extractGeneratedClass(generatedClass, elementFactory, anchor, explicitGeneratedEvaluationClassName); } } else {