[java] fixes parsing of imports in module-info.java files (IDEA-169208)

This commit is contained in:
Roman Shevchenko
2017-03-08 13:41:21 +01:00
parent 7f4059541a
commit a86d46d868
3 changed files with 50 additions and 7 deletions
@@ -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<PsiBuilder> importListStopper,
@NotNull AbstractBundle bundle,
@NotNull String errorMessageKey) {
parsePackageStatement(builder);
Pair<PsiBuilder.Marker, Boolean> impListInfo = parseImportList(builder, importListStoppers); // (importList, isEmpty)
Pair<PsiBuilder.Marker, Boolean> 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<PsiBuilder.Marker, Boolean> parseImportList(PsiBuilder builder, TokenSet stoppers) {
private Pair<PsiBuilder.Marker, Boolean> parseImportList(PsiBuilder builder, Predicate<PsiBuilder> 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;
}
@@ -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
<empty list>
PsiJavaToken:DOT('.')
PsiIdentifier:lang('lang')
PsiReferenceParameterList
<empty list>
PsiJavaToken:DOT('.')
PsiIdentifier:Deprecated('Deprecated')
PsiReferenceParameterList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace('\n')
PsiJavaModule:M
PsiModifierList:
<empty list>
PsiKeyword:module('module')
PsiWhiteSpace(' ')
PsiJavaModuleReference
PsiIdentifier:M('M')
PsiWhiteSpace(' ')
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
@@ -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 { }"); }