From 2e8fa6eb9b372a269877fc608060cb5d2468d731 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 15 Dec 2010 17:50:14 +0300 Subject: [PATCH] Dummy Java element with pluggable parser --- .../lang/java/parser/JavaParserUtil.java | 10 ++- .../psi/impl/source/JavaDummyElement.java | 82 +++++++++++++++++++ .../psi/impl/source/tree/JavaElementType.java | 22 +++++ .../intellij/psi/impl/source/DummyHolder.java | 13 ++- 4 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 java/java-impl/src/com/intellij/psi/impl/source/JavaDummyElement.java diff --git a/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java b/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java index 99982aed1d3d..9313500b6149 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/JavaParserUtil.java @@ -184,13 +184,18 @@ public class JavaParserUtil { return builder; } + @Nullable public static ASTNode parseFragment(final ASTNode chameleon, final ParserWrapper wrapper) { + return parseFragment(chameleon, wrapper, true, LanguageLevel.HIGHEST); + } + + @Nullable + public static ASTNode parseFragment(final ASTNode chameleon, final ParserWrapper wrapper, final boolean eatAll, final LanguageLevel level) { final PsiElement psi = (chameleon.getTreeParent() != null ? chameleon.getTreeParent().getPsi() : chameleon.getPsi()); assert psi != null : chameleon; final Project project = psi.getProject(); final PsiBuilderFactory factory = PsiBuilderFactory.getInstance(); - final LanguageLevel level = LanguageLevel.HIGHEST; final Lexer lexer = JavaParserDefinition.createLexer(level); final PsiBuilder builder = factory.createBuilder(project, chameleon, lexer, chameleon.getElementType().getLanguage(), chameleon.getChars()); setLanguageLevel(builder, level); @@ -198,6 +203,7 @@ public class JavaParserUtil { final PsiBuilder.Marker root = builder.mark(); wrapper.parse(builder); if (!builder.eof()) { + if (!eatAll) throw new AssertionError("Unexpected tokens"); final PsiBuilder.Marker extras = builder.mark(); while (!builder.eof()) builder.advanceLexer(); extras.error(JavaErrorMessages.message("unexpected.tokens")); @@ -389,4 +395,4 @@ public class JavaParserUtil { myDelegate.putUserDataUnprotected(key, value); } } -} +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/impl/source/JavaDummyElement.java b/java/java-impl/src/com/intellij/psi/impl/source/JavaDummyElement.java new file mode 100644 index 000000000000..c54c4e18eba8 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/impl/source/JavaDummyElement.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.impl.source; + +import com.intellij.lang.java.parser.JavaParserUtil; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.impl.source.tree.FileElement; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.impl.source.tree.TreeElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Dummy file element for using together with DummyHolder. + * See {@link com.intellij.psi.impl.PsiJavaParserFacadeImpl} for details. + */ +public class JavaDummyElement extends FileElement { + @NotNull private final JavaParserUtil.ParserWrapper myParser; + private final boolean myConsumeAll; + @NotNull private final LanguageLevel myLanguageLevel; + + public JavaDummyElement(@Nullable final CharSequence text, @NotNull final JavaParserUtil.ParserWrapper parser, final boolean consumeAll) { + this(text, parser, consumeAll, LanguageLevel.HIGHEST); + } + + public JavaDummyElement(@Nullable final CharSequence text, + @NotNull final JavaParserUtil.ParserWrapper parser, + final boolean consumeAll, + @NotNull final LanguageLevel level) { + super(JavaElementType.DUMMY_ELEMENT, text); + myParser = parser; + myConsumeAll = consumeAll; + myLanguageLevel = level; + } + + @NotNull + public JavaParserUtil.ParserWrapper getParser() { + return myParser; + } + + public boolean consumeAll() { + return myConsumeAll; + } + + @NotNull + public LanguageLevel getLanguageLevel() { + return myLanguageLevel; + } + + @Override + public TreeElement getFirstChildNode() { + try { + return super.getFirstChildNode(); + } + catch (AssertionError e) { + return null; // masquerade parser errors + } + } + + @Override + public TreeElement getLastChildNode() { + try { + return super.getLastChildNode(); + } + catch (AssertionError e) { + return null; // masquerade parser errors + } + } +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java index 0af5952b0e1a..6fb19b8624c9 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java @@ -28,6 +28,7 @@ import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.JavaTokenType; import com.intellij.psi.PsiManager; import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; +import com.intellij.psi.impl.source.JavaDummyElement; import com.intellij.psi.impl.source.parsing.JavaParsingContext; import com.intellij.psi.impl.source.parsing.Parsing; import com.intellij.psi.impl.source.tree.java.PsiCodeBlockImpl; @@ -40,6 +41,7 @@ import com.intellij.psi.tree.java.IJavaElementType; import com.intellij.psi.util.PsiUtil; import com.intellij.util.CharTable; import com.intellij.util.diff.FlyweightCapableTreeStructure; +import org.jetbrains.annotations.Nullable; import static com.intellij.lang.PsiBuilderUtil.expect; @@ -158,6 +160,7 @@ public interface JavaElementType { seq, 0, seq.length(), 0).getFirstChildNode(); } + @Override public int getErrorsCount(final CharSequence seq, final Project project) { final Lexer lexer = new JavaLexer(LanguageLevel.HIGHEST); @@ -184,6 +187,7 @@ public interface JavaElementType { class ICodeBlockNewElementType extends ICodeBlockElementType implements ILightLazyParseableElementType { private ICodeBlockNewElementType() { } + @Override public FlyweightCapableTreeStructure parseContents(final LighterLazyParseableNode chameleon) { final PsiBuilder builder = JavaParserUtil.createBuilder(chameleon); StatementParser.parseCodeBlockDeep(builder, true); @@ -194,6 +198,8 @@ public interface JavaElementType { ILazyParseableElementType CODE_BLOCK = JavaParserDefinition.USE_NEW_PARSER ? new ICodeBlockNewElementType() : new ICodeBlockElementType(); IElementType STATEMENTS = new ICodeFragmentElementType("STATEMENTS", StdLanguages.JAVA) { + @Nullable + @Override public ASTNode parseContents(final ASTNode chameleon) { if (JavaParserDefinition.USE_NEW_PARSER) { return JavaParserUtil.parseFragment(chameleon, @@ -213,6 +219,8 @@ public interface JavaElementType { }; IElementType EXPRESSION_TEXT = new ICodeFragmentElementType("EXPRESSION_TEXT", StdLanguages.JAVA) { + @Nullable + @Override public ASTNode parseContents(final ASTNode chameleon) { if (JavaParserDefinition.USE_NEW_PARSER) { return JavaParserUtil.parseFragment(chameleon, @@ -231,6 +239,8 @@ public interface JavaElementType { }; IElementType REFERENCE_TEXT = new ICodeFragmentElementType("REFERENCE_TEXT", StdLanguages.JAVA) { + @Nullable + @Override public ASTNode parseContents(final ASTNode chameleon) { if (JavaParserDefinition.USE_NEW_PARSER) { return JavaParserUtil.parseFragment(chameleon, @@ -248,6 +258,8 @@ public interface JavaElementType { }; IElementType TYPE_TEXT = new ICodeFragmentElementType("TYPE_TEXT", StdLanguages.JAVA) { + @Nullable + @Override public ASTNode parseContents(final ASTNode chameleon) { if (JavaParserDefinition.USE_NEW_PARSER) { return JavaParserUtil.parseFragment(chameleon, @@ -264,4 +276,14 @@ public interface JavaElementType { SharedImplUtil.findCharTableByTree(chameleon)); } }; + + IElementType DUMMY_ELEMENT = new ILazyParseableElementType("DUMMY_ELEMENT", StdLanguages.JAVA) { + @Nullable + @Override + public ASTNode parseContents(final ASTNode chameleon) { + assert chameleon instanceof JavaDummyElement : chameleon; + final JavaDummyElement dummyElement = (JavaDummyElement)chameleon; + return JavaParserUtil.parseFragment(chameleon, dummyElement.getParser(), dummyElement.consumeAll(), dummyElement.getLanguageLevel()); + } + }; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/DummyHolder.java b/platform/lang-impl/src/com/intellij/psi/impl/source/DummyHolder.java index b6009113df3c..f6d4d1e28b54 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/DummyHolder.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/DummyHolder.java @@ -56,7 +56,12 @@ public class DummyHolder extends PsiFileImpl { ((DummyHolderViewProvider)getViewProvider()).setDummyHolder(this); myContext = context; myTable = table != null ? table : IdentityCharTable.INSTANCE; - if(contentElement != null) { + if (contentElement instanceof FileElement) { + myFileElement = (FileElement)contentElement; + myFileElement.setPsi(this); + if (myTable != null) myFileElement.setCharTable(myTable); + } + else if (contentElement != null) { getTreeElement().rawAddChildren(contentElement); clearCaches(); } @@ -81,7 +86,7 @@ public class DummyHolder extends PsiFileImpl { } public boolean isValid() { - if(myExplicitlyValid != null) return myExplicitlyValid.booleanValue(); + if (myExplicitlyValid != null) return myExplicitlyValid.booleanValue(); return super.isValid() && !(myContext != null && !myContext.isValid()); } @@ -112,10 +117,10 @@ public class DummyHolder extends PsiFileImpl { } public FileElement getTreeElementNoLock() { - if(myFileElement == null){ + if (myFileElement == null) { myFileElement = new FileElement(TokenType.DUMMY_HOLDER, null); myFileElement.setPsi(this); - if(myTable != null) myFileElement.setCharTable(myTable); + if (myTable != null) myFileElement.setCharTable(myTable); clearCaches(); } return myFileElement;