[debugger] CodeFragmentFactory can produce PsiCodeFragment

* broaden code fragment type to be able to implement non-java evaluators


Merge-request: IJ-MR-145790
Merged-by: Maksim Zuev <Maksim.Zuev@jetbrains.com>

GitOrigin-RevId: 096badbd7e76b2c8065867349e0839452b683ab4
This commit is contained in:
Maksim Zuev
2024-10-02 17:36:00 +00:00
committed by intellij-monorepo-bot
parent 08b5c4605c
commit e046e5c6a5
15 changed files with 100 additions and 50 deletions
@@ -0,0 +1,42 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.debugger.engine
import com.intellij.debugger.engine.evaluation.CodeFragmentFactory
import com.intellij.debugger.engine.evaluation.TextWithImports
import com.intellij.debugger.impl.DebuggerUtilsImpl
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil
abstract class JavaDebuggerCodeFragmentFactory : CodeFragmentFactory() {
final override fun createPsiCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment? {
val codeFragment = createPsiCodeFragmentImpl(item, context, project) ?: return null
if (context != null) {
setThisType(context, codeFragment)
}
return codeFragment
}
final override fun createPresentationPsiCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment? {
val codeFragment = createPresentationPsiCodeFragmentImpl(item, context, project) ?: return null
if (context != null) {
setThisType(context, codeFragment)
}
return codeFragment
}
protected abstract fun createPresentationPsiCodeFragmentImpl(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment?
protected abstract fun createPsiCodeFragmentImpl(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment?
private fun setThisType(context: PsiElement, codeFragment: JavaCodeFragment) {
var contextType = context.getUserData(DebuggerUtilsImpl.PSI_TYPE_KEY)
if (contextType == null) {
val contextClass = PsiTreeUtil.getNonStrictParentOfType(context, PsiClass::class.java)
if (contextClass != null) {
contextType = JavaPsiFacade.getElementFactory(codeFragment.getProject()).createType(contextClass)
}
}
codeFragment.setThisType(contextType)
}
}
@@ -148,7 +148,7 @@ public class JavaDebuggerEvaluator extends XDebuggerEvaluator implements XDebugg
catch (UnsupportedExpressionException ex) {
PsiElement context = PositionUtil.getContextElement(debuggerContext);
ExpressionEvaluator eval = CompilingEvaluatorImpl.create(project, context, e ->
factory.createCodeFragment(text.get(), context, project));
factory.createPsiCodeFragment(text.get(), context, project));
if (eval != null) {
return eval;
}
@@ -28,13 +28,13 @@ public class CodeFragmentFactoryContextWrapper extends CodeFragmentFactory {
}
@Override
public JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, Project project) {
return prepareResolveScope(myDelegate.createCodeFragment(item, wrapContext(project, context), project));
public PsiCodeFragment createPsiCodeFragment(TextWithImports item, PsiElement context, Project project) {
return prepareResolveScope(myDelegate.createPsiCodeFragment(item, wrapContext(project, context), project));
}
@Override
public JavaCodeFragment createPresentationCodeFragment(TextWithImports item, PsiElement context, Project project) {
return prepareResolveScope(myDelegate.createPresentationCodeFragment(item, wrapContext(project, context), project));
public PsiCodeFragment createPresentationPsiCodeFragment(TextWithImports item, PsiElement context, Project project) {
return prepareResolveScope(myDelegate.createPresentationPsiCodeFragment(item, wrapContext(project, context), project));
}
@Override
@@ -53,7 +53,7 @@ public class CodeFragmentFactoryContextWrapper extends CodeFragmentFactory {
return myDelegate.getEvaluatorBuilder();
}
private static JavaCodeFragment prepareResolveScope(JavaCodeFragment codeFragment) {
private static PsiCodeFragment prepareResolveScope(PsiCodeFragment codeFragment) {
GlobalSearchScope originalResolveScope = codeFragment.getResolveScope();
codeFragment.forceResolveScope(new DelegatingGlobalSearchScope(GlobalSearchScope.allScope(codeFragment.getProject())) {
final Comparator<VirtualFile> myScopeComparator = Comparator.comparing(originalResolveScope::contains).thenComparing(super::compare);
@@ -6,6 +6,7 @@ import com.intellij.codeInsight.completion.JavaCompletionUtil;
import com.intellij.debugger.DebuggerManagerEx;
import com.intellij.debugger.JavaDebuggerBundle;
import com.intellij.debugger.codeinsight.RuntimeTypeEvaluator;
import com.intellij.debugger.engine.JavaDebuggerCodeFragmentFactory;
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilder;
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
@@ -27,7 +28,7 @@ import java.util.concurrent.atomic.AtomicReference;
/**
* @author Eugene Zhuravlev
*/
public class DefaultCodeFragmentFactory extends CodeFragmentFactory {
public class DefaultCodeFragmentFactory extends JavaDebuggerCodeFragmentFactory {
private static final class SingletonHolder {
public static final DefaultCodeFragmentFactory ourInstance = new DefaultCodeFragmentFactory();
}
@@ -37,12 +38,14 @@ public class DefaultCodeFragmentFactory extends CodeFragmentFactory {
}
@Override
public JavaCodeFragment createPresentationCodeFragment(final TextWithImports item, final PsiElement context, final Project project) {
return createCodeFragment(item, context, project);
protected JavaCodeFragment createPresentationPsiCodeFragmentImpl(final @NotNull TextWithImports item,
final PsiElement context,
final @NotNull Project project) {
return createPsiCodeFragment(item, context, project);
}
@Override
public JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, final Project project) {
public JavaCodeFragment createPsiCodeFragmentImpl(TextWithImports item, PsiElement context, final @NotNull Project project) {
final JavaCodeFragmentFactory factory = JavaCodeFragmentFactory.getInstance(project);
final String text = item.getText();
@@ -60,7 +60,7 @@ public final class EvaluatorBuilderImpl implements EvaluatorBuilder {
@Nullable final SourcePosition position,
@NotNull Project project) throws EvaluateException {
CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, contextElement);
PsiCodeFragment codeFragment = factory.createCodeFragment(text, contextElement, project);
PsiCodeFragment codeFragment = factory.createPsiCodeFragment(text, contextElement, project);
if (codeFragment == null) {
throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.invalid.expression", text.getText()));
}
@@ -1516,7 +1516,7 @@ public final class EvaluatorBuilderImpl implements EvaluatorBuilder {
private Evaluator buildFromJavaCode(String code, String imports, @NotNull PsiElement context) {
TextWithImportsImpl text = new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK, code, imports, JavaFileType.INSTANCE);
JavaCodeFragment codeFragment = DefaultCodeFragmentFactory.getInstance().createCodeFragment(text, context, context.getProject());
JavaCodeFragment codeFragment = DefaultCodeFragmentFactory.getInstance().createPsiCodeFragment(text, context, context.getProject());
return accept(codeFragment);
}
@@ -555,7 +555,7 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
}
private static PsiCodeFragment createCodeFragment(Project project, TextWithImports text, PsiElement context) {
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, context).createCodeFragment(text, context, project);
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, context).createPsiCodeFragment(text, context, project);
}
protected String calculateEventClass(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException {
@@ -70,7 +70,7 @@ public abstract class CompilingEvaluator implements ExpressionEvaluator {
TextWithImports callCode = getCallCode();
PsiElement copyContext = myData.getAnchor();
CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(callCode, copyContext);
return factory.getEvaluatorBuilder().build(factory.createCodeFragment(callCode, copyContext, myProject),
return factory.getEvaluatorBuilder().build(factory.createPsiCodeFragment(callCode, copyContext, myProject),
// can not use evaluation position here, it does not match classes then
SourcePosition.createFromElement(copyContext));
}
@@ -54,7 +54,7 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl {
public PsiCodeFragment createCodeFragment(PsiElement context) {
TextWithImports text = getEvaluationText();
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, context).createCodeFragment(text, context, myProject);
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, context).createPsiCodeFragment(text, context, myProject);
}
@ApiStatus.Experimental
@@ -54,8 +54,7 @@ public abstract class CachedEvaluator {
throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.cannot.find.source", className));
}
CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(myReferenceExpression, context);
JavaCodeFragment codeFragment = factory.createCodeFragment(myReferenceExpression, overrideContext(context), project);
codeFragment.setThisType(psiClassAndType.second);
PsiCodeFragment codeFragment = factory.createPsiCodeFragment(myReferenceExpression, overrideContext(context), project);
DebuggerUtils.checkSyntax(codeFragment);
cache.myPsiChildrenExpression = codeFragment instanceof PsiExpressionCodeFragment ? ((PsiExpressionCodeFragment)codeFragment).getExpression() : null;
@@ -5,7 +5,6 @@ import com.intellij.debugger.engine.evaluation.CodeFragmentFactory;
import com.intellij.debugger.engine.evaluation.TextWithImports;
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.impl.DebuggerUtilsImpl;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Document;
@@ -13,7 +12,6 @@ import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xdebugger.XExpression;
import com.intellij.xdebugger.XSourcePosition;
@@ -74,20 +72,7 @@ public class JavaDebuggerEditorsProvider extends XDebuggerEditorsProviderBase {
TextWithImports text = TextWithImportsImpl.fromXExpression(expression);
if (text != null) {
CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, context);
JavaCodeFragment codeFragment = factory.createPresentationCodeFragment(text, context, project);
if (context != null) {
PsiType contextType = context.getUserData(DebuggerUtilsImpl.PSI_TYPE_KEY);
if (contextType == null) {
PsiClass contextClass = PsiTreeUtil.getNonStrictParentOfType(context, PsiClass.class);
if (contextClass != null) {
contextType = JavaPsiFacade.getElementFactory(codeFragment.getProject()).createType(contextClass);
}
}
codeFragment.setThisType(contextType);
}
return codeFragment;
return factory.createPresentationPsiCodeFragment(text, context, project);
}
else {
return super.createExpressionCodeFragment(project, expression, context, isPhysical);
@@ -6,6 +6,7 @@ import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.project.Project;
import com.intellij.psi.JavaCodeFragment;
import com.intellij.psi.PsiCodeFragment;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@@ -17,9 +18,29 @@ public abstract class CodeFragmentFactory {
public static final ExtensionPointName<CodeFragmentFactory> EXTENSION_POINT_NAME =
ExtensionPointName.create("com.intellij.debugger.codeFragmentFactory");
public abstract JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, Project project);
/**
* @deprecated Use {@link CodeFragmentFactory#createPsiCodeFragment} instead
*/
@Deprecated
public JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, Project project) {
throw new AbstractMethodError();
}
public abstract JavaCodeFragment createPresentationCodeFragment(TextWithImports item, PsiElement context, Project project);
/**
* @deprecated Use {@link CodeFragmentFactory#createPresentationPsiCodeFragment(TextWithImports, PsiElement, Project)} instead
*/
@Deprecated
public JavaCodeFragment createPresentationCodeFragment(TextWithImports item, PsiElement context, Project project) {
throw new AbstractMethodError();
}
public PsiCodeFragment createPsiCodeFragment(TextWithImports item, PsiElement context, Project project) {
return createCodeFragment(item, context, project);
}
public PsiCodeFragment createPresentationPsiCodeFragment(TextWithImports item, PsiElement context, Project project) {
return createPresentationCodeFragment(item, context, project);
}
public abstract boolean isContextAccepted(PsiElement contextElement);