[debugger] Refactoring: Prepare to support java instrumentation

Prepare for IDEA-370744

GitOrigin-RevId: d28b2941347a480037b92b917035b4b503083c09
This commit is contained in:
Alexey.Merkulov
2026-01-29 20:22:30 +00:00
committed by intellij-monorepo-bot
parent d21be53db5
commit b446b776e9
5 changed files with 72 additions and 21 deletions
@@ -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;
@@ -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<ClassObject> 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<ClassObject> compile(@Nullable JavaSdkVersion debuggeeVersion) throws EvaluateException;
public abstract @NotNull Collection<ClassObject> compile(@Nullable JavaSdkVersion debuggeeVersion) throws EvaluateException;
}
@@ -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<ClassObject> compile(@Nullable JavaSdkVersion debuggeeVersion) throws EvaluateException {
public @NotNull Collection<ClassObject> compile(@Nullable JavaSdkVersion debuggeeVersion) throws EvaluateException {
if (myCompiledClasses == null) {
List<String> 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<? super PsiElement, ? extends PsiCodeFragment> fragmentFactory)
public static @Nullable CompilingEvaluator create(@NotNull Project project,
@Nullable PsiElement psiContext,
@NotNull Function<? super PsiElement, ? extends PsiCodeFragment> 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<? super PsiElement, ? extends PsiCodeFragment> 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);
}
@@ -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;
@@ -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 {