IDEA-376846 allow overriding of PsiSyntaxBuilderFactory in plugins

This is necessary for plugin authors who want to override language support.

In case a plugin overrides PsiSyntaxBuilderFactory service, there is still
an option to construct the default implementation PsiSyntaxBuilderFactoryImpl
via `defaultBuilderFactory` method.

GitOrigin-RevId: ac6d401bb502ee7971d3ca90e454d03360f15f97
This commit is contained in:
Max Medvedev
2025-09-05 21:11:57 +00:00
committed by intellij-monorepo-bot
parent 373376197a
commit 50097a068a
5 changed files with 51 additions and 20 deletions
@@ -25,6 +25,8 @@ import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.platform.syntax.psi.ElementTypeConverters;
import com.intellij.platform.syntax.psi.LanguageSyntaxDefinitions;
import com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory;
import com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactoryImpl;
import com.intellij.psi.*;
import com.intellij.psi.compiled.ClassFileDecompilers;
import com.intellij.psi.impl.LanguageConstantExpressionEvaluator;
@@ -89,6 +91,8 @@ public class JavaCoreApplicationEnvironment extends CoreApplicationEnvironment {
addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiLocalVariable.class, new VariablePresentationProvider<>());
addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiParameter.class, new VariablePresentationProvider<>());
registerApplicationService(PsiSyntaxBuilderFactory.class, new PsiSyntaxBuilderFactoryImpl());
registerApplicationService(JavaCodeFoldingSettings.class, new JavaCodeFoldingSettingsBase());
addExplicitExtension(LanguageFolding.INSTANCE, JavaLanguage.INSTANCE, new JavaFoldingBuilderBase() {
@Override
@@ -40,15 +40,15 @@
- a:getTreeBuilt():com.intellij.lang.ASTNode
- a:setCustomComparator(com.intellij.util.TripleFunction):V
- a:setDebugMode(Z):V
*f:com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory
*:com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory
- *sf:Companion:com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory$Companion
- <init>():V
- f:createBuilder(com.intellij.lang.ASTNode,com.intellij.platform.syntax.lexer.Lexer,com.intellij.lang.Language,java.lang.CharSequence):com.intellij.platform.syntax.psi.PsiSyntaxBuilder
- f:createBuilder(com.intellij.lang.LighterLazyParseableNode,com.intellij.platform.syntax.lexer.Lexer,com.intellij.lang.Language,java.lang.CharSequence):com.intellij.platform.syntax.psi.PsiSyntaxBuilder
- a:createBuilder(com.intellij.lang.ASTNode,com.intellij.platform.syntax.lexer.Lexer,com.intellij.lang.Language,java.lang.CharSequence):com.intellij.platform.syntax.psi.PsiSyntaxBuilder
- a:createBuilder(com.intellij.lang.LighterLazyParseableNode,com.intellij.platform.syntax.lexer.Lexer,com.intellij.lang.Language,java.lang.CharSequence):com.intellij.platform.syntax.psi.PsiSyntaxBuilder
- bs:createBuilder$default(com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory,com.intellij.lang.ASTNode,com.intellij.platform.syntax.lexer.Lexer,com.intellij.lang.Language,java.lang.CharSequence,I,java.lang.Object):com.intellij.platform.syntax.psi.PsiSyntaxBuilder
- bs:createBuilder$default(com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory,com.intellij.lang.LighterLazyParseableNode,com.intellij.platform.syntax.lexer.Lexer,com.intellij.lang.Language,java.lang.CharSequence,I,java.lang.Object):com.intellij.platform.syntax.psi.PsiSyntaxBuilder
- sf:getInstance():com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory
- s:getInstance():com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory
*f:com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory$Companion
- f:defaultBuilderFactory():com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory
- f:getInstance():com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory
*f:com.intellij.platform.syntax.psi.extensions.IntelliJSyntaxLanguageSupportKt
- sf:asIntelliJLanguage(com.intellij.platform.syntax.SyntaxLanguage):com.intellij.lang.Language
@@ -18,5 +18,7 @@
<syntax.elementTypeConverter language="any" implementationClass="com.intellij.platform.syntax.psi.CommonElementTypeConverterFactory"/>
<syntax.cancellationProviderExtension implementation="com.intellij.platform.syntax.psi.IntelliJCancellationProvider"/>
<syntax.logProvider implementation="com.intellij.platform.syntax.psi.IntelliJLogProvider"/>
<applicationService serviceInterface="com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory"
serviceImplementation="com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactoryImpl"/>
</extensions>
</idea-plugin>
@@ -8,6 +8,7 @@ import com.intellij.openapi.util.Pair
import com.intellij.platform.syntax.SyntaxElementType
import com.intellij.platform.syntax.lexer.Lexer
import com.intellij.platform.syntax.parser.WhitespaceOrCommentBindingPolicy
import com.intellij.platform.syntax.psi.PsiSyntaxBuilderFactory.Companion.getInstance
import com.intellij.platform.syntax.psi.impl.LazyParseableToken
import com.intellij.platform.syntax.psi.impl.PsiSyntaxBuilderImpl
import com.intellij.platform.syntax.psi.impl.extractCachedLexemes
@@ -16,13 +17,44 @@ import com.intellij.psi.impl.source.tree.SharedImplUtil
import com.intellij.psi.text.BlockSupport
import com.intellij.psi.tree.IElementType
@Service(Service.Level.APP)
class PsiSyntaxBuilderFactory {
interface PsiSyntaxBuilderFactory {
fun createBuilder(
chameleon: ASTNode,
lexer: Lexer? = null,
lang: Language = chameleon.elementType.language,
text: CharSequence = chameleon.chars,
): PsiSyntaxBuilder
fun createBuilder(
chameleon: LighterLazyParseableNode,
lexer: Lexer? = null,
lang: Language = chameleon.tokenType.language,
text: CharSequence = chameleon.text,
): PsiSyntaxBuilder
companion object {
@JvmStatic
fun getInstance(): PsiSyntaxBuilderFactory = service<PsiSyntaxBuilderFactory>()
/**
* Use this method to access the default [PsiSyntaxBuilderFactory] implementation if [PsiSyntaxBuilderFactory] service is overridden.
* Otherwise, please use [getInstance].
*/
fun defaultBuilderFactory(): PsiSyntaxBuilderFactory = service<DefaultBuilderFactoryHolder>().factory
}
}
@Service(Service.Level.APP)
private class DefaultBuilderFactoryHolder {
val factory = PsiSyntaxBuilderFactoryImpl()
}
internal class PsiSyntaxBuilderFactoryImpl : PsiSyntaxBuilderFactory {
override fun createBuilder(
chameleon: ASTNode,
lexer: Lexer?,
lang: Language,
text: CharSequence,
): PsiSyntaxBuilder {
val parserDefinition = getParserDefinition(lang, chameleon.getElementType())
val tokenConverter = getConverter(lang, chameleon.getElementType())
@@ -49,11 +81,11 @@ class PsiSyntaxBuilderFactory {
)
}
fun createBuilder(
override fun createBuilder(
chameleon: LighterLazyParseableNode,
lexer: Lexer? = null,
lang: Language = chameleon.tokenType.language,
text: CharSequence = chameleon.text,
lexer: Lexer?,
lang: Language,
text: CharSequence,
): PsiSyntaxBuilder {
val parserDefinition = getParserDefinition(null, chameleon.getTokenType())
val tokenConverter = getConverter(lang, chameleon.getTokenType())
@@ -91,11 +123,6 @@ class PsiSyntaxBuilderFactory {
val adjusted = language ?: tokenType.language
return ElementTypeConverters.getConverter(adjusted)
}
companion object {
@JvmStatic
fun getInstance(): PsiSyntaxBuilderFactory = service<PsiSyntaxBuilderFactory>()
}
}
private class DefaultWhitespaceOrCommentPolicy(val tokenConverter: ElementTypeConverter) : WhitespaceOrCommentBindingPolicy {
@@ -30,10 +30,7 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.platform.syntax.psi.CommonElementTypeConverterFactory;
import com.intellij.platform.syntax.psi.ElementTypeConverters;
import com.intellij.platform.syntax.psi.IntelliJCancellationProvider;
import com.intellij.platform.syntax.psi.IntelliJLogProvider;
import com.intellij.platform.syntax.psi.*;
import com.intellij.platform.syntax.util.cancellation.CancellationProviderExtension;
import com.intellij.platform.syntax.util.log.LogProvider;
import com.intellij.pom.PomModel;
@@ -127,6 +124,7 @@ public abstract class ParsingTestCase extends UsefulTestCase {
app.registerService(PsiBuilderFactory.class, new PsiBuilderFactoryImpl());
app.registerService(DefaultASTFactory.class, new DefaultASTFactoryImpl());
app.registerService(ReferenceProvidersRegistry.class, new ReferenceProvidersRegistryImpl());
app.registerService(PsiSyntaxBuilderFactory.class, new PsiSyntaxBuilderFactoryImpl());
project.registerService(PsiDocumentManager.class, new MockPsiDocumentManager());
project.registerService(PsiManager.class, myPsiManager);
project.registerService(TreeAspect.class, new TreeAspect());