diff --git a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index 698ae3e21fd6..e485d89ae8c3 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -158,7 +158,7 @@ public class DeclarationParser { continue; } - final PsiBuilder.Marker declaration = parseDeclaration(builder, context); + final PsiBuilder.Marker declaration = parse(builder, context); if (declaration != null) { if (invalidElements != null) { invalidElements.errorBefore(JavaErrorMessages.message("unexpected.token"), declaration); @@ -184,7 +184,7 @@ public class DeclarationParser { } @Nullable - public static PsiBuilder.Marker parseDeclaration(final PsiBuilder builder, final Context context) { + public static PsiBuilder.Marker parse(final PsiBuilder builder, final Context context) { final IElementType tokenType = builder.getTokenType(); if (tokenType == null) return null; @@ -229,7 +229,7 @@ public class DeclarationParser { while (builder.getTokenType() != null && builder.getTokenType() != JavaTokenType.RBRACE) { final PsiBuilder.Marker position = builder.mark(); - final PsiBuilder.Marker element = parseDeclaration(builder, Context.CLASS); + final PsiBuilder.Marker element = parse(builder, Context.CLASS); if (element != null && AFTER_END_DECLARATION_SET.contains(exprType(element))) { if (!declarationsAfterEnd) { element.precede().error(JavaErrorMessages.message("expected.class.or.interface")); diff --git a/java/java-impl/src/com/intellij/lang/java/parser/FileParser.java b/java/java-impl/src/com/intellij/lang/java/parser/FileParser.java new file mode 100644 index 000000000000..c29ffef181ad --- /dev/null +++ b/java/java-impl/src/com/intellij/lang/java/parser/FileParser.java @@ -0,0 +1,152 @@ +/* + * 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.lang.java.parser; + +import com.intellij.codeInsight.daemon.JavaErrorMessages; +import com.intellij.lang.PsiBuilder; +import com.intellij.psi.JavaTokenType; +import com.intellij.psi.impl.source.tree.ElementType; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static com.intellij.lang.PsiBuilderUtil.expect; +import static com.intellij.lang.java.parser.JavaParserUtil.semicolon; + + +public class FileParser { + private static final TokenSet IMPORT_LIST_STOPPER_SET = TokenSet.orSet( + ElementType.MODIFIER_BIT_SET, + TokenSet.create(JavaTokenType.CLASS_KEYWORD, JavaTokenType.INTERFACE_KEYWORD, JavaTokenType.ENUM_KEYWORD, JavaTokenType.AT)); + + private FileParser() { } + + public static void parse(final PsiBuilder builder) { + parsePackageStatement(builder); + + parseImportList(builder); + + PsiBuilder.Marker invalidElements = null; + while (!builder.eof()) { + if (builder.getTokenType() == JavaTokenType.SEMICOLON) { + if (invalidElements != null) { + invalidElements.error(JavaErrorMessages.message("expected.class.or.interface")); + invalidElements = null; + } + builder.advanceLexer(); + continue; + } + + final PsiBuilder.Marker decl = DeclarationParser.parse(builder, DeclarationParser.Context.FILE); + if (decl != null) { + if (invalidElements != null) { + invalidElements.errorBefore(JavaErrorMessages.message("expected.class.or.interface"), decl); + invalidElements = null; + } + continue; + } + + if (invalidElements == null) { + invalidElements = builder.mark(); + } + builder.advanceLexer(); + } + + if (invalidElements != null) { + invalidElements.error(JavaErrorMessages.message("expected.class.or.interface")); + } + } + + @Nullable + private static PsiBuilder.Marker parsePackageStatement(final PsiBuilder builder) { + final PsiBuilder.Marker statement = builder.mark(); + + if (!expect(builder, JavaTokenType.PACKAGE_KEYWORD)) { + final PsiBuilder.Marker modList = builder.mark(); + DeclarationParser.parseAnnotations(builder); + modList.done(JavaElementType.MODIFIER_LIST); + if (!expect(builder, JavaTokenType.PACKAGE_KEYWORD)) { + statement.rollbackTo(); + return null; + } + } + + final PsiBuilder.Marker ref = ReferenceParser.parseJavaCodeReference(builder, true, false, false); + if (ref == null) { + statement.rollbackTo(); + return null; + } + + semicolon(builder); + + statement.done(JavaElementType.PACKAGE_STATEMENT); + return statement; + } + + @NotNull + private static PsiBuilder.Marker parseImportList(final PsiBuilder builder) { + final PsiBuilder.Marker list = builder.mark(); + + if (builder.getTokenType() == JavaTokenType.IMPORT_KEYWORD) { + PsiBuilder.Marker invalidElements = null; + while (!builder.eof()) { + if (IMPORT_LIST_STOPPER_SET.contains(builder.getTokenType())) break; + + final PsiBuilder.Marker statement = parseImportStatement(builder); + if (statement != null) { + if (invalidElements != null) { + invalidElements.errorBefore(JavaErrorMessages.message("unexpected.token"), statement); + invalidElements = null; + } + continue; + } + + if (invalidElements == null) { + invalidElements = builder.mark(); + } + builder.advanceLexer(); + } + + if (invalidElements != null) { + invalidElements.error(JavaErrorMessages.message("unexpected.token")); + } + } + + list.done(JavaElementType.IMPORT_LIST); + return list; + } + + @Nullable + private static PsiBuilder.Marker parseImportStatement(final PsiBuilder builder) { + if (builder.getTokenType() != JavaTokenType.IMPORT_KEYWORD) return null; + + final PsiBuilder.Marker statement = builder.mark(); + builder.advanceLexer(); + + final boolean isStatic = expect(builder, JavaTokenType.STATIC_KEYWORD); + final IElementType type = isStatic ? JavaElementType.IMPORT_STATIC_STATEMENT : JavaElementType.IMPORT_STATEMENT; + + final boolean isOk = ReferenceParser.parseImportCodeReference(builder, isStatic); + if (isOk) { + semicolon(builder); + } + + statement.done(type); + return statement; + } +} diff --git a/java/java-impl/src/com/intellij/lang/java/parser/JavaParser.java b/java/java-impl/src/com/intellij/lang/java/parser/JavaParser.java index b06bf223d085..9d1e8a49cea7 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/JavaParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/JavaParser.java @@ -37,7 +37,7 @@ public class JavaParser implements PsiParser { final PsiBuilder.Marker root = builder.mark(); setLanguageLevel(builder, myLanguageLevel); - // parse + FileParser.parse(builder); root.done(rootType); return builder.getTreeBuilt(); 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 2aa5b8da3976..6f949120096a 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 @@ -15,6 +15,7 @@ */ package com.intellij.lang.java.parser; +import com.intellij.codeInsight.daemon.JavaErrorMessages; import com.intellij.lang.*; import com.intellij.openapi.util.Key; import com.intellij.pom.java.LanguageLevel; @@ -83,6 +84,10 @@ public class JavaParserUtil { before.precede().doneBefore(type, before); } + public static void semicolon(final PsiBuilder builder) { + expectOrError(builder, JavaTokenType.SEMICOLON, JavaErrorMessages.message("expected.semicolon")); + } + public static PsiBuilder braceMatchingBuilder(final PsiBuilder builder) { return new PsiBuilderAdapter(builder) { private int braceCount = 1; diff --git a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java index 4f06c802e8e2..ba3a01062f72 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java @@ -35,6 +35,7 @@ public class ReferenceParser { public boolean isPrimitive = false; public boolean isParameterized = false; public boolean isArray = false; + public boolean hasErrors = false; public PsiBuilder.Marker marker = null; } @@ -85,7 +86,7 @@ public class ReferenceParser { typeInfo.isPrimitive = true; } else if (tokenType == JavaTokenType.IDENTIFIER) { - parseJavaCodeReference(builder, eatLastDot, true, annotationsSupported, typeInfo); + parseJavaCodeReference(builder, eatLastDot, true, annotationsSupported, false, false, typeInfo); } else if (wildcard && tokenType == JavaTokenType.QUEST) { type.drop(); @@ -137,12 +138,19 @@ public class ReferenceParser { @Nullable public static PsiBuilder.Marker parseJavaCodeReference(final PsiBuilder builder, final boolean eatLastDot, final boolean parameterList, final boolean annotations) { - return parseJavaCodeReference(builder, eatLastDot, parameterList, annotations, new TypeInfo()); + return parseJavaCodeReference(builder, eatLastDot, parameterList, annotations, false, false, new TypeInfo()); + } + + public static boolean parseImportCodeReference(final PsiBuilder builder, final boolean isStatic) { + final TypeInfo typeInfo = new TypeInfo(); + parseJavaCodeReference(builder, true, false, false, true, isStatic, typeInfo); + return !typeInfo.hasErrors; } @Nullable private static PsiBuilder.Marker parseJavaCodeReference(final PsiBuilder builder, final boolean eatLastDot, final boolean parameterList, final boolean annotations, + final boolean isImport, final boolean isStaticImport, final TypeInfo typeInfo) { PsiBuilder.Marker refElement = builder.mark(); @@ -152,6 +160,10 @@ public class ReferenceParser { if (!expect(builder, JavaTokenType.IDENTIFIER)) { refElement.rollbackTo(); + if (isImport) { + error(builder, JavaErrorMessages.message("expected.identifier")); + } + typeInfo.hasErrors = true; return null; } @@ -173,6 +185,10 @@ public class ReferenceParser { if (expect(builder, JavaTokenType.IDENTIFIER)) { hasIdentifier = true; } + else if (isImport && expect(builder, JavaTokenType.ASTERISK)) { + dotPos.drop(); + return refElement; + } else { if (!eatLastDot) { dotPos.rollbackTo(); @@ -185,20 +201,28 @@ public class ReferenceParser { refElement = refElement.precede(); if (!hasIdentifier) { - error(builder, JavaErrorMessages.message("expected.identifier")); - break; + typeInfo.hasErrors = true; + if (isImport) { + error(builder, JavaErrorMessages.message("import.statement.identifier.or.asterisk.expected.")); + refElement.drop(); + return refElement; + } + else { + error(builder, JavaErrorMessages.message("expected.identifier")); + break; + } } if (parameterList) { typeInfo.isParameterized = (builder.getTokenType() == JavaTokenType.LT); parseReferenceParameterList(builder, true); } - else { + else if (!isStaticImport || builder.getTokenType() == JavaTokenType.DOT) { emptyElement(builder, JavaElementType.REFERENCE_PARAMETER_LIST); } } - refElement.done(JavaElementType.JAVA_CODE_REFERENCE); + refElement.done(isStaticImport ? JavaElementType.IMPORT_STATIC_REFERENCE : JavaElementType.JAVA_CODE_REFERENCE); return refElement; } diff --git a/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java index 9e9ba6bd6e68..a390554731f7 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/StatementParser.java @@ -218,7 +218,7 @@ public class StatementParser { refPos.rollbackTo(); if (suspectedLT == JavaTokenType.LT) { final PsiBuilder.Marker declStatement = builder.mark(); - final PsiBuilder.Marker decl = DeclarationParser.parseDeclaration(builder, DeclarationParser.Context.CODE_BLOCK); + final PsiBuilder.Marker decl = DeclarationParser.parse(builder, DeclarationParser.Context.CODE_BLOCK); if (decl == null) { error(builder, JavaErrorMessages.message("expected.identifier")); } @@ -264,7 +264,7 @@ public class StatementParser { pos.drop(); } - final PsiBuilder.Marker decl = DeclarationParser.parseDeclaration(builder, DeclarationParser.Context.CODE_BLOCK); + final PsiBuilder.Marker decl = DeclarationParser.parse(builder, DeclarationParser.Context.CODE_BLOCK); if (decl != null) { final PsiBuilder.Marker statement = decl.precede(); statement.done(JavaElementType.DECLARATION_STATEMENT); @@ -297,10 +297,6 @@ public class StatementParser { } } - private static void semicolon(final PsiBuilder builder) { - expectOrError(builder, JavaTokenType.SEMICOLON, JavaErrorMessages.message("expected.semicolon")); - } - @NotNull private static PsiBuilder.Marker parseIfStatement(final PsiBuilder builder) { final PsiBuilder.Marker statement = builder.mark(); diff --git a/java/java-tests/testData/psi/parser-partial/files/AnnotatedPackage.txt b/java/java-tests/testData/psi/parser-partial/files/AnnotatedPackage.txt new file mode 100644 index 000000000000..e60c2eb1f41c --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/AnnotatedPackage.txt @@ -0,0 +1,31 @@ +PsiJavaFile:AnnotatedPackage.java + PsiPackageStatement:a.b.c + PsiModifierList:@Anno + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Anno + PsiIdentifier:Anno('Anno') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiWhiteSpace(' ') + PsiKeyword:package('package') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:a.b.c + PsiJavaCodeReferenceElement:a.b + PsiJavaCodeReferenceElement:a + PsiIdentifier:a('a') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:b('b') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:c('c') + PsiReferenceParameterList + + PsiJavaToken:SEMICOLON(';') + PsiImportList + \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/EmptyFile.txt b/java/java-tests/testData/psi/parser-partial/files/EmptyFile.txt new file mode 100644 index 000000000000..3034524d047d --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/EmptyFile.txt @@ -0,0 +1,3 @@ +PsiJavaFile:EmptyFile.java + PsiImportList + \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/FileWithClass.txt b/java/java-tests/testData/psi/parser-partial/files/FileWithClass.txt new file mode 100644 index 000000000000..3f71aea86d25 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/FileWithClass.txt @@ -0,0 +1,54 @@ +PsiJavaFile:FileWithClass.java + PsiPackageStatement:a + PsiKeyword:package('package') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:a + PsiIdentifier:a('a') + PsiReferenceParameterList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n') + PsiImportList + PsiImportStatement + PsiKeyword:import('import') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:b + PsiIdentifier:b('b') + PsiReferenceParameterList + + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace('\n') + PsiClass:C + PsiModifierList:public + PsiKeyword:public('public') + PsiWhiteSpace(' ') + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:C('C') + PsiTypeParameterList + + PsiReferenceList + + PsiReferenceList + + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') + PsiWhiteSpace('\n') + PsiClass:D + PsiModifierList: + + PsiKeyword:class('class') + PsiWhiteSpace(' ') + PsiIdentifier:D('D') + PsiTypeParameterList + + PsiReferenceList + + PsiReferenceList + + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/Import0.txt b/java/java-tests/testData/psi/parser-partial/files/Import0.txt new file mode 100644 index 000000000000..94334720cced --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/Import0.txt @@ -0,0 +1,17 @@ +PsiJavaFile:Import0.java + PsiImportList + PsiImportStatement + PsiKeyword:import('import') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:java.util + PsiJavaCodeReferenceElement:java + PsiIdentifier:java('java') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:util('util') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiJavaToken:ASTERISK('*') + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/Import1.txt b/java/java-tests/testData/psi/parser-partial/files/Import1.txt new file mode 100644 index 000000000000..1831107feff3 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/Import1.txt @@ -0,0 +1,20 @@ +PsiJavaFile:Import1.java + PsiImportList + PsiImportStatement + PsiKeyword:import('import') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:java.util.Arrays + PsiJavaCodeReferenceElement:java.util + PsiJavaCodeReferenceElement:java + PsiIdentifier:java('java') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:util('util') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:Arrays('Arrays') + PsiReferenceParameterList + + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/Package.txt b/java/java-tests/testData/psi/parser-partial/files/Package.txt new file mode 100644 index 000000000000..a3fedef93d7b --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/Package.txt @@ -0,0 +1,21 @@ +PsiJavaFile:Package.java + PsiPackageStatement:a.b.c + PsiKeyword:package('package') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:a.b.c + PsiJavaCodeReferenceElement:a.b + PsiJavaCodeReferenceElement:a + PsiIdentifier:a('a') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:b('b') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:c('c') + PsiReferenceParameterList + + PsiJavaToken:SEMICOLON(';') + PsiImportList + \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/StaticImport0.txt b/java/java-tests/testData/psi/parser-partial/files/StaticImport0.txt new file mode 100644 index 000000000000..114f1a9bd0f5 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/StaticImport0.txt @@ -0,0 +1,24 @@ +PsiJavaFile:StaticImport0.java + PsiImportList + PsiImportStaticStatement + PsiKeyword:import('import') + PsiWhiteSpace(' ') + PsiKeyword:static('static') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:java.util.Arrays + PsiJavaCodeReferenceElement:java.util + PsiJavaCodeReferenceElement:java + PsiIdentifier:java('java') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:util('util') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:Arrays('Arrays') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiJavaToken:ASTERISK('*') + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/StaticImport1.txt b/java/java-tests/testData/psi/parser-partial/files/StaticImport1.txt new file mode 100644 index 000000000000..cdc45d1611c3 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/StaticImport1.txt @@ -0,0 +1,25 @@ +PsiJavaFile:StaticImport1.java + PsiImportList + PsiImportStaticStatement + PsiKeyword:import('import') + PsiWhiteSpace(' ') + PsiKeyword:static('static') + PsiWhiteSpace(' ') + PsiImportStaticReferenceElement:java.util.Arrays.sort + PsiJavaCodeReferenceElement:java.util.Arrays + PsiJavaCodeReferenceElement:java.util + PsiJavaCodeReferenceElement:java + PsiIdentifier:java('java') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:util('util') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:Arrays('Arrays') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:sort('sort') + PsiJavaToken:SEMICOLON(';') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/UnclosedImport0.txt b/java/java-tests/testData/psi/parser-partial/files/UnclosedImport0.txt new file mode 100644 index 000000000000..b30c120e520b --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/UnclosedImport0.txt @@ -0,0 +1,6 @@ +PsiJavaFile:UnclosedImport0.java + PsiImportList + PsiImportStatement + PsiKeyword:import('import') + PsiErrorElement:Identifier expected + \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/UnclosedImport1.txt b/java/java-tests/testData/psi/parser-partial/files/UnclosedImport1.txt new file mode 100644 index 000000000000..ff2b67f0efe8 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/UnclosedImport1.txt @@ -0,0 +1,18 @@ +PsiJavaFile:UnclosedImport1.java + PsiImportList + PsiImportStatement + PsiKeyword:import('import') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:java.awt + PsiJavaCodeReferenceElement:java + PsiIdentifier:java('java') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:awt('awt') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiJavaToken:ASTERISK('*') + PsiErrorElement:';' expected + \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/UnclosedImport2.txt b/java/java-tests/testData/psi/parser-partial/files/UnclosedImport2.txt new file mode 100644 index 000000000000..1a49c9250d9d --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/UnclosedImport2.txt @@ -0,0 +1,17 @@ +PsiJavaFile:UnclosedImport2.java + PsiImportList + PsiImportStatement + PsiKeyword:import('import') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:java.awt + PsiJavaCodeReferenceElement:java + PsiIdentifier:java('java') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiIdentifier:awt('awt') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiErrorElement:Identifier or '*' expected + \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/UnclosedPackage0.txt b/java/java-tests/testData/psi/parser-partial/files/UnclosedPackage0.txt new file mode 100644 index 000000000000..cc9866bf1040 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/UnclosedPackage0.txt @@ -0,0 +1,5 @@ +PsiJavaFile:UnclosedPackage0.java + PsiImportList + + PsiErrorElement:'class' or 'interface' expected + PsiKeyword:package('package') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/files/UnclosedPackage1.txt b/java/java-tests/testData/psi/parser-partial/files/UnclosedPackage1.txt new file mode 100644 index 000000000000..5f8fe8f51214 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/files/UnclosedPackage1.txt @@ -0,0 +1,16 @@ +PsiJavaFile:UnclosedPackage1.java + PsiPackageStatement:a. + PsiKeyword:package('package') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:a. + PsiJavaCodeReferenceElement:a + PsiIdentifier:a('a') + PsiReferenceParameterList + + PsiJavaToken:DOT('.') + PsiErrorElement:Identifier expected + + PsiErrorElement:';' expected + + PsiImportList + \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/FileParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/FileParserTest.java new file mode 100644 index 000000000000..cd41c779d578 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/FileParserTest.java @@ -0,0 +1,55 @@ +/* + * 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.lang.java.parser.partial; + +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.java.parser.FileParser; +import com.intellij.lang.java.parser.JavaParsingTestCase; + + +public class FileParserTest extends JavaParsingTestCase { + public FileParserTest() { + super("parser-partial/files"); + } + + public void testEmptyFile() { doParserTest(""); } + + public void testPackage() { doParserTest("package a.b.c;"); } + public void testAnnotatedPackage() { doParserTest("@Anno package a.b.c;"); } + public void testUnclosedPackage0() { doParserTest("package"); } + public void testUnclosedPackage1() { doParserTest("package a."); } + + public void testImport0() { doParserTest("import java.util.*;"); } + public void testImport1() { doParserTest("import java.util.Arrays;"); } + public void testStaticImport0() { doParserTest("import static java.util.Arrays.*;"); } + public void testStaticImport1() { doParserTest("import static java.util.Arrays.sort;"); } + public void testUnclosedImport0() { doParserTest("import"); } + public void testUnclosedImport1() { doParserTest("import java.awt.*"); } + public void testUnclosedImport2() { doParserTest("import java.awt."); } + + public void testFileWithClass() { doParserTest("package a;\n" + + "import b;\n" + + "public class C { }\n" + + "class D { }"); } + + private void doParserTest(final String text) { + doParserTest(text, new Parser() { + public void parse(final PsiBuilder builder) { + FileParser.parse(builder); + } + }); + } +}