From a86d46d8687593d841dea2cfb64733923ff3bbe2 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 8 Mar 2017 13:40:37 +0100 Subject: [PATCH] [java] fixes parsing of imports in module-info.java files (IDEA-169208) --- .../intellij/lang/java/parser/FileParser.java | 24 ++++++++++---- .../psi/parser-partial/modules/Imports.txt | 32 +++++++++++++++++++ .../java/parser/partial/ModuleParserTest.java | 1 + 3 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 java/java-tests/testData/psi/parser-partial/modules/Imports.txt diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/FileParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/FileParser.java index 75547074b9b5..b322a971b69a 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/FileParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/FileParser.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.daemon.JavaErrorMessages; import com.intellij.lang.PsiBuilder; import com.intellij.openapi.util.Pair; import com.intellij.psi.JavaTokenType; +import com.intellij.psi.PsiKeyword; import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.tree.IElementType; @@ -27,6 +28,8 @@ import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.function.Predicate; + import static com.intellij.lang.PsiBuilderUtil.expect; import static com.intellij.lang.java.parser.JavaParserUtil.*; @@ -42,16 +45,16 @@ public class FileParser { } public void parse(@NotNull PsiBuilder builder) { - parseFile(builder, IMPORT_LIST_STOPPER_SET, JavaErrorMessages.INSTANCE, "expected.class.or.interface"); + parseFile(builder, FileParser::stopImportListParsing, JavaErrorMessages.INSTANCE, "expected.class.or.interface"); } public void parseFile(@NotNull PsiBuilder builder, - @NotNull TokenSet importListStoppers, + @NotNull Predicate importListStopper, @NotNull AbstractBundle bundle, @NotNull String errorMessageKey) { parsePackageStatement(builder); - Pair impListInfo = parseImportList(builder, importListStoppers); // (importList, isEmpty) + Pair impListInfo = parseImportList(builder, importListStopper); // (importList, isEmpty) Boolean firstDeclarationOk = null; PsiBuilder.Marker firstDeclaration = null; @@ -101,6 +104,14 @@ public class FileParser { } } + private static boolean stopImportListParsing(PsiBuilder b) { + IElementType type = b.getTokenType(); + String text = b.getTokenText(); + if (IMPORT_LIST_STOPPER_SET.contains(type)) return true; + if (type == JavaTokenType.IDENTIFIER && (PsiKeyword.OPEN.equals(text) || PsiKeyword.MODULE.equals(text))) return true; + return false; + } + @Nullable protected PsiBuilder.Marker parseInitial(PsiBuilder builder) { return myParser.getDeclarationParser().parse(builder, DeclarationParser.Context.FILE); @@ -131,7 +142,7 @@ public class FileParser { } @NotNull - private Pair parseImportList(PsiBuilder builder, TokenSet stoppers) { + private Pair parseImportList(PsiBuilder builder, Predicate stopper) { PsiBuilder.Marker list = builder.mark(); IElementType tokenType = builder.getTokenType(); @@ -139,11 +150,10 @@ public class FileParser { if (!isEmpty) { PsiBuilder.Marker invalidElements = null; while (!builder.eof()) { - tokenType = builder.getTokenType(); - if (stoppers.contains(tokenType)) { + if (stopper.test(builder)) { break; } - else if (tokenType == JavaTokenType.SEMICOLON) { + else if (builder.getTokenType() == JavaTokenType.SEMICOLON) { builder.advanceLexer(); continue; } diff --git a/java/java-tests/testData/psi/parser-partial/modules/Imports.txt b/java/java-tests/testData/psi/parser-partial/modules/Imports.txt new file mode 100644 index 000000000000..31ea96c45c57 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/modules/Imports.txt @@ -0,0 +1,32 @@ +PsiJavaFile:Imports.java + PsiImportList + PsiImportStatement + PsiKeyword:import('import') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:java.lang.Deprecated + PsiJavaCodeReferenceElement:java.lang + PsiJavaCodeReferenceElement:java + PsiIdentifier:java('java') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:lang('lang') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:Deprecated('Deprecated') + PsiReferenceParameterList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n') + PsiJavaModule:M + PsiModifierList: + + PsiKeyword:module('module') + PsiWhiteSpace(' ') + PsiJavaModuleReference + PsiIdentifier:M('M') + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ModuleParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ModuleParserTest.java index 7839be9c1231..d81a4f43abc4 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ModuleParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ModuleParserTest.java @@ -28,6 +28,7 @@ public class ModuleParserTest extends JavaParsingTestCase { public void testSimple2() { doParserTest("/* comment */\nmodule X { }"); } public void testPackaged() { doParserTest("package pkg;\nmodule M { }"); } + public void testImports() { doParserTest("import java.lang.Deprecated;\nmodule M { }"); } public void testModifierList0() { doParserTest("open module M { }"); } public void testModifierList1() { doParserTest("@Deprecated module M { }"); }