diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index 54e23dd156b3..939a0a5b2c1d 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -710,7 +710,7 @@ public class DeclarationParser { IElementType tokenType = builder.getTokenType(); if (tokenType != JavaTokenType.LBRACKET && tokenType != JavaTokenType.AT) return true; - PsiBuilder.Marker marker = errorKey != null ? builder.mark() : null; + PsiBuilder.Marker marker = builder.mark(); int count = 0; while (true) { @@ -725,11 +725,21 @@ public class DeclarationParser { ++count; } - boolean paired = count % 2 == 0; - if (marker != null) { + if (count == 0) { + // just annotation, most probably belongs to a next declaration + marker.rollbackTo(); + return true; + } + + if (errorKey != null) { marker.error(JavaErrorMessages.message(errorKey)); } - else if (!paired) { + else { + marker.drop(); + } + + boolean paired = count % 2 == 0; + if (!paired) { error(builder, JavaErrorMessages.message("expected.rbracket")); } return paired; diff --git a/java/java-tests/testData/psi/parser-partial/declarations/UnclosedField1.txt b/java/java-tests/testData/psi/parser-partial/declarations/UnclosedField1.txt new file mode 100644 index 000000000000..60f2aefdec44 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/UnclosedField1.txt @@ -0,0 +1,37 @@ +PsiJavaFile:UnclosedField1.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:f1 + PsiModifierList: + + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:f1('f1') + PsiErrorElement:';' expected + + PsiWhiteSpace('\n\n ') + PsiField:f2 + PsiModifierList:@Anno + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Anno + PsiIdentifier:Anno('Anno') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiWhiteSpace(' ') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:f2('f2') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/declarations/UnclosedField2.txt b/java/java-tests/testData/psi/parser-partial/declarations/UnclosedField2.txt new file mode 100644 index 000000000000..18afb0228483 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/declarations/UnclosedField2.txt @@ -0,0 +1,37 @@ +PsiJavaFile:UnclosedField2.java + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiField:f1 + PsiModifierList: + + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:f1('f1') + PsiErrorElement:';' expected + + PsiWhiteSpace('\n\n ') + PsiField:f2 + PsiModifierList:@Anno + PsiAnnotation + PsiJavaToken:AT('@') + PsiJavaCodeReferenceElement:Anno + PsiIdentifier:Anno('Anno') + PsiReferenceParameterList + + PsiAnnotationParameterList + + PsiWhiteSpace('\n ') + PsiTypeElement:String + PsiJavaCodeReferenceElement:String + PsiIdentifier:String('String') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:f2('f2') + PsiJavaToken:SEMICOLON(';') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java index 5570590a19f6..deed3fc4a4a8 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/DeclarationParserTest.java @@ -73,6 +73,8 @@ public class DeclarationParserTest extends JavaParsingTestCase { public void testUnclosedSemicolon() { doParserTest("{ int field }", false, false); } public void testMissingInitializerExpression() { doParserTest("{ int field=; }", false, false); } public void testMultiLineUnclosed() { doParserTest("{ int \n Object o; }", false, false); } + public void testUnclosedField1() { doParserTest("{ String f1\n\n @Anno String f2; }", false, false); } + public void testUnclosedField2() { doParserTest("{ String f1\n\n @Anno\n String f2; }", false, false); } public void testMethodNormal0() { doParserTest("{ void f() {} }", false, false); } public void testMethodNormal1() { doParserTest("{ void f(); }", false, false); }