diff --git a/java/java-frontback-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java b/java/java-frontback-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java index da9d7023860e..f0160edd8914 100644 --- a/java/java-frontback-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java +++ b/java/java-frontback-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java @@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static com.intellij.psi.impl.source.BasicJavaDocElementType.*; +import static com.intellij.psi.impl.source.tree.JavaDocElementType.ALL_JAVADOC_ELEMENTS; import static com.intellij.util.text.CharArrayUtil.containsOnlyWhiteSpaces; /** @@ -192,8 +193,7 @@ public final class JavadocTypedHandler extends TypedHandlerDelegate { ASTNode node = element.getNode(); return node != null - && (JavaDocTokenType.ALL_JAVADOC_TOKENS.contains(node.getElementType()) - || BASIC_ALL_JAVADOC_ELEMENTS.contains(node.getElementType())); + && (JavaDocTokenType.ALL_JAVADOC_TOKENS.contains(node.getElementType())); } private static boolean isTypeParamBracketClosedAfterParamTag(PsiDocTag tag, int bracketOffset) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java index 355b10aab38c..808c3342e52f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java @@ -1,73 +1,81 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.psi.impl.source.tree; +import com.intellij.java.syntax.element.JavaDocSyntaxElementType; +import com.intellij.java.syntax.lexer.JavaDocLexer; +import com.intellij.java.syntax.lexer.JavaLexer; +import com.intellij.java.syntax.lexer.JavaTypeEscapeLexer; +import com.intellij.java.syntax.parser.JavaDocParser; +import com.intellij.java.syntax.parser.JavaParser; import com.intellij.lang.ASTNode; -import com.intellij.psi.impl.source.BasicJavaDocElementType; +import com.intellij.lang.Language; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.lang.java.parser.JavaParserUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.impl.source.javadoc.*; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.tree.ILazyParseableElementType; -import com.intellij.psi.tree.ParentProviderElementType; -import com.intellij.psi.tree.TokenSet; +import com.intellij.psi.tree.*; import com.intellij.psi.tree.java.IJavaDocElementType; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.Set; import java.util.function.Supplier; /** * @see com.intellij.java.syntax.element.JavaDocSyntaxElementType */ public interface JavaDocElementType { - final class JavaDocCompositeElementType extends BasicJavaDocElementType.JavaDocCompositeElementType { - private JavaDocCompositeElementType(@NonNls @NotNull String debugName, @NotNull Supplier nodeClass, IElementType parentElementType) { - super(debugName, nodeClass, parentElementType); - } - } + final class JavaDocCompositeElementType extends IJavaDocElementType implements + ICompositeElementType { + private final Supplier myConstructor; - final class JavaDocParentProviderElementType extends IJavaDocElementType implements ParentProviderElementType { - - private final Set myParentElementTypes; - - public JavaDocParentProviderElementType(@NotNull String debugName, @NotNull IElementType parentElementType) { + private JavaDocCompositeElementType(@NonNls @NotNull String debugName, @NotNull Supplier nodeClass) { super(debugName); - myParentElementTypes = Collections.singleton(parentElementType); + this.myConstructor = nodeClass; } @Override - public @NotNull Set getParents() { - return myParentElementTypes; + public @NotNull ASTNode createCompositeNode() { + return myConstructor.get(); } } - IElementType DOC_TAG = new JavaDocCompositeElementType("DOC_TAG", () -> new PsiDocTagImpl(), BasicJavaDocElementType.BASIC_DOC_TAG); - IElementType DOC_INLINE_TAG = new JavaDocCompositeElementType("DOC_INLINE_TAG", () -> new PsiInlineDocTagImpl(), BasicJavaDocElementType.BASIC_DOC_INLINE_TAG); - IElementType DOC_METHOD_OR_FIELD_REF = new JavaDocCompositeElementType("DOC_METHOD_OR_FIELD_REF", () -> new PsiDocMethodOrFieldRef(), BasicJavaDocElementType.BASIC_DOC_METHOD_OR_FIELD_REF); - IElementType DOC_FRAGMENT_REF = new JavaDocCompositeElementType("DOC_FRAGMENT_REF", () -> new PsiDocFragmentRefImpl(), BasicJavaDocElementType.BASIC_DOC_FRAGMENT_REF); - IElementType DOC_FRAGMENT_NAME = new JavaDocCompositeElementType("DOC_FRAGMENT_NAME", () -> new PsiDocFragmentNameImpl(), BasicJavaDocElementType.BASIC_DOC_FRAGMENT_NAME); - IElementType DOC_PARAMETER_REF = new JavaDocCompositeElementType("DOC_PARAMETER_REF", () -> new PsiDocParamRef(), BasicJavaDocElementType.BASIC_DOC_PARAMETER_REF); - IElementType DOC_TAG_VALUE_ELEMENT = new JavaDocParentProviderElementType("DOC_TAG_VALUE_ELEMENT", BasicJavaDocElementType.BASIC_DOC_TAG_VALUE_ELEMENT); - IElementType DOC_SNIPPET_TAG = new JavaDocCompositeElementType("DOC_SNIPPET_TAG", () -> new PsiSnippetDocTagImpl(), BasicJavaDocElementType.BASIC_DOC_SNIPPET_TAG); - IElementType DOC_SNIPPET_TAG_VALUE = new JavaDocCompositeElementType("DOC_SNIPPET_TAG_VALUE", () -> new PsiSnippetDocTagValueImpl(), BasicJavaDocElementType.BASIC_DOC_SNIPPET_TAG_VALUE); - IElementType DOC_SNIPPET_BODY = new JavaDocCompositeElementType("DOC_SNIPPET_BODY", () -> new PsiSnippetDocTagBodyImpl(), BasicJavaDocElementType.BASIC_DOC_SNIPPET_BODY); - IElementType DOC_SNIPPET_ATTRIBUTE = new JavaDocCompositeElementType("DOC_SNIPPET_ATTRIBUTE", () -> new PsiSnippetAttributeImpl(), BasicJavaDocElementType.BASIC_DOC_SNIPPET_ATTRIBUTE); - IElementType DOC_SNIPPET_ATTRIBUTE_LIST = - new JavaDocCompositeElementType("DOC_SNIPPET_ATTRIBUTE_LIST", () -> new PsiSnippetAttributeListImpl(), BasicJavaDocElementType.BASIC_DOC_SNIPPET_ATTRIBUTE_LIST); - IElementType DOC_SNIPPET_ATTRIBUTE_VALUE = new JavaDocParentProviderElementType("DOC_SNIPPET_ATTRIBUTE_VALUE", BasicJavaDocElementType.BASIC_DOC_SNIPPET_ATTRIBUTE_VALUE); - IElementType DOC_MARKDOWN_CODE_BLOCK = new JavaDocCompositeElementType("DOC_CODE_BLOCK", () -> new PsiMarkdownCodeBlockImpl(), BasicJavaDocElementType.BASIC_DOC_MARKDOWN_CODE_BLOCK); - IElementType DOC_MARKDOWN_REFERENCE_LINK = new JavaDocCompositeElementType("DOC_REFERENCE_LINK", () -> new PsiMarkdownReferenceLinkImpl(), BasicJavaDocElementType.BASIC_DOC_MARKDOWN_REFERENCE_LINK); - IElementType DOC_MARKDOWN_REFERENCE_LABEL = new JavaDocCompositeElementType("DOC_REFERENCE_LABEL", () -> new PsiMarkdownReferenceLabelImpl(), BasicJavaDocElementType.BASIC_DOC_MARKDOWN_REFERENCE_LABEL); + final class JavaDocParentProviderElementType extends IJavaDocElementType { + public JavaDocParentProviderElementType(@NotNull String debugName) { + super(debugName); + } + } - ILazyParseableElementType DOC_REFERENCE_HOLDER = new BasicJavaDocElementType.DocReferenceHolderElementType(); - ILazyParseableElementType DOC_TYPE_HOLDER = new BasicJavaDocElementType.DocTypeHolderElementType(); - ILazyParseableElementType DOC_COMMENT = new BasicJavaDocElementType.DocCommentElementType("DOC_COMMENT") { + IElementType DOC_TAG = new JavaDocCompositeElementType("DOC_TAG", () -> new PsiDocTagImpl()); + IElementType DOC_INLINE_TAG = new JavaDocCompositeElementType("DOC_INLINE_TAG", () -> new PsiInlineDocTagImpl()); + IElementType DOC_METHOD_OR_FIELD_REF = new JavaDocCompositeElementType("DOC_METHOD_OR_FIELD_REF", () -> new PsiDocMethodOrFieldRef()); + IElementType DOC_FRAGMENT_REF = new JavaDocCompositeElementType("DOC_FRAGMENT_REF", () -> new PsiDocFragmentRefImpl()); + IElementType DOC_FRAGMENT_NAME = new JavaDocCompositeElementType("DOC_FRAGMENT_NAME", () -> new PsiDocFragmentNameImpl()); + IElementType DOC_PARAMETER_REF = new JavaDocCompositeElementType("DOC_PARAMETER_REF", () -> new PsiDocParamRef()); + IElementType DOC_TAG_VALUE_ELEMENT = new JavaDocParentProviderElementType("DOC_TAG_VALUE_ELEMENT"); + IElementType DOC_SNIPPET_TAG = new JavaDocCompositeElementType("DOC_SNIPPET_TAG", () -> new PsiSnippetDocTagImpl()); + IElementType DOC_SNIPPET_TAG_VALUE = new JavaDocCompositeElementType("DOC_SNIPPET_TAG_VALUE", () -> new PsiSnippetDocTagValueImpl()); + IElementType DOC_SNIPPET_BODY = new JavaDocCompositeElementType("DOC_SNIPPET_BODY", () -> new PsiSnippetDocTagBodyImpl()); + IElementType DOC_SNIPPET_ATTRIBUTE = new JavaDocCompositeElementType("DOC_SNIPPET_ATTRIBUTE", () -> new PsiSnippetAttributeImpl()); + IElementType DOC_SNIPPET_ATTRIBUTE_LIST = + new JavaDocCompositeElementType("DOC_SNIPPET_ATTRIBUTE_LIST", () -> new PsiSnippetAttributeListImpl()); + IElementType DOC_SNIPPET_ATTRIBUTE_VALUE = new JavaDocParentProviderElementType("DOC_SNIPPET_ATTRIBUTE_VALUE"); + IElementType DOC_MARKDOWN_CODE_BLOCK = new JavaDocCompositeElementType("DOC_CODE_BLOCK", () -> new PsiMarkdownCodeBlockImpl()); + IElementType DOC_MARKDOWN_REFERENCE_LINK = new JavaDocCompositeElementType("DOC_REFERENCE_LINK", () -> new PsiMarkdownReferenceLinkImpl()); + IElementType DOC_MARKDOWN_REFERENCE_LABEL = new JavaDocCompositeElementType("DOC_REFERENCE_LABEL", () -> new PsiMarkdownReferenceLabelImpl()); + + ILazyParseableElementType DOC_REFERENCE_HOLDER = new DocReferenceHolderElementType(); + ILazyParseableElementType DOC_TYPE_HOLDER = new DocTypeHolderElementType(); + ILazyParseableElementType DOC_COMMENT = new DocCommentElementType("DOC_COMMENT") { @Override public ASTNode createNode(final CharSequence text) { return new PsiDocCommentImpl(text); } }; - ILazyParseableElementType DOC_MARKDOWN_COMMENT = new BasicJavaDocElementType.DocCommentElementType("DOC_MARKDOWN_COMMENT") { + ILazyParseableElementType DOC_MARKDOWN_COMMENT = new DocCommentElementType("DOC_MARKDOWN_COMMENT") { @Override public ASTNode createNode(final CharSequence text) { return new PsiDocCommentImpl(text, true); @@ -80,4 +88,87 @@ public interface JavaDocElementType { @SuppressWarnings("unused") // used in plugins TokenSet ALL_JAVADOC_ELEMENTS = TokenSet.create(DOC_TAG, DOC_INLINE_TAG, DOC_METHOD_OR_FIELD_REF, DOC_PARAMETER_REF, DOC_TAG_VALUE_ELEMENT, DOC_REFERENCE_HOLDER, DOC_TYPE_HOLDER, DOC_COMMENT, DOC_MARKDOWN_COMMENT); + + + + class JavaDocLazyElementType extends ILazyParseableElementType { + + private JavaDocLazyElementType(final @NonNls String debugName) { + super(debugName, JavaLanguage.INSTANCE); + } + + @Override + public ASTNode createNode(CharSequence text) { + return new LazyParseablePsiElement(this, text); + } + } + + + final class DocReferenceHolderElementType extends JavaDocLazyElementType { + public DocReferenceHolderElementType() { + super("DOC_REFERENCE_HOLDER"); + } + + @Override + public @Nullable ASTNode parseContents(final @NotNull ASTNode chameleon) { + return JavaParserUtil.parseFragment( + chameleon, + (builder, languageLevel) -> { + new JavaDocParser(builder, languageLevel).parseJavadocReference(new JavaParser(languageLevel)); + }, + false, + LanguageLevel.JDK_1_3); + } + } + + final class DocTypeHolderElementType extends JavaDocLazyElementType { + public DocTypeHolderElementType() { + super("DOC_TYPE_HOLDER"); + } + + @Override + public @Nullable ASTNode parseContents(final @NotNull ASTNode chameleon) { + return JavaParserUtil.parseFragment( + chameleon, + (builder, languageLevel) -> { + new JavaDocParser(builder, languageLevel).parseJavadocType(new JavaParser(languageLevel)); + }, + false, + LanguageLevel.JDK_1_3, + level -> new JavaTypeEscapeLexer(new JavaLexer(level)) + ); + } + } + + abstract class DocCommentElementType extends IReparseableElementType { + private final JavaParserUtil.ParserWrapper myParser; + + + public DocCommentElementType(String debugName) { + super(debugName, JavaLanguage.INSTANCE); + myParser = (builder, languageLevel) -> new JavaDocParser(builder, languageLevel).parseDocCommentText(); + } + + @Override + public @Nullable ASTNode parseContents(final @NotNull ASTNode chameleon) { + return JavaParserUtil.parseFragmentWithHighestLanguageLevel(chameleon, myParser, JavaDocLexer::new); + } + + @Override + public boolean isReparseable(@NotNull ASTNode currentNode, + @NotNull CharSequence newText, + @NotNull Language fileLanguage, + @NotNull Project project) { + if (!StringUtil.startsWith(newText, "/**") || !StringUtil.endsWith(newText, "*/")) return false; + + LanguageLevel level = LanguageLevelProjectExtension.getInstance(project).getLanguageLevel(); + JavaLexer lexer = new JavaLexer(level); + lexer.start(newText); + if (lexer.getTokenType() == JavaDocSyntaxElementType.DOC_COMMENT) { + lexer.advance(); + return lexer.getTokenType() == null; + } + return false; + } + } } \ No newline at end of file