diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/basic/ErrorRecoveryTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/basic/ErrorRecoveryTests.java index a74032c8f3..2c464009c9 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/basic/ErrorRecoveryTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/basic/ErrorRecoveryTests.java @@ -77,6 +77,415 @@ public void testParsingRecovery_BasicBlock() { "}\n"); } + @Test + public void testParsingRecovery_IncompleteAnnotation1() { + //@formatter:off + String[] sources = { + "X.groovy", + "@ package p\n", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy (at line 1)\n" + + "\t@ package p\n" + + "\t^^\n" + + "Groovy:class ? is not an annotation in @?\n" + + "----------\n" + + "2. ERROR in X.groovy (at line 1)\n" + + "\t@ package p\n" + + "\t ^\n" + + "Groovy:unable to resolve class ? for annotation\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "package p;\n" + + "public class X extends groovy.lang.Script {\n" + + " public X() {\n" + + " }\n" + + " public X(final groovy.lang.Binding context) {\n" + + " }\n" + + " public static void main(final java.lang.String... args) {\n" + + " }\n" + + " public @java.lang.Override java.lang.Object run() {\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation2() { + //@formatter:off + String[] sources = { + "X.groovy", + "@ import java.lang.Object\n", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy (at line 1)\n" + + "\t@ import java.lang.Object\n" + + "\t ^\n" + + "Groovy:unable to resolve class ? for annotation\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "import java.lang.Object;\n" + + "public class X extends groovy.lang.Script {\n" + + " public X() {\n" + + " }\n" + + " public X(final groovy.lang.Binding context) {\n" + + " }\n" + + " public static void main(final java.lang.String... args) {\n" + + " }\n" + + " public @java.lang.Override java.lang.Object run() {\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation3() { + //@formatter:off + String[] sources = { + "X.groovy", + "@ int x", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy (at line 1)\n" + + "\t@ int x\n" + + "\t^^\n" + + "Groovy:class ? is not an annotation in @?\n" + + "----------\n" + + "2. ERROR in X.groovy (at line 1)\n" + + "\t@ int x\n" + + "\t ^\n" + + "Groovy:unable to resolve class ? for annotation\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "public class X extends groovy.lang.Script {\n" + + " public X() {\n" + + " }\n" + + " public X(final groovy.lang.Binding context) {\n" + + " }\n" + + " public static void main(final java.lang.String... args) {\n" + + " }\n" + + " public @java.lang.Override java.lang.Object run() {\n" + + " int x;\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation4() { + //@formatter:off + String[] sources = { + "X.groovy", + "@ class X {}", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy (at line 1)\n" + + "\t@ class X {}\n" + + "\t^^\n" + + "Groovy:class ? is not an annotation in @?\n" + + "----------\n" + + "2. ERROR in X.groovy (at line 1)\n" + + "\t@ class X {}\n" + + "\t ^\n" + + "Groovy:unable to resolve class ? for annotation\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "public @? class X {\n" + + " public @groovy.transform.Generated X() {\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation5() { + //@formatter:off + String[] sources = { + "X.groovy", + "@Deprecated @ class X {}", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy (at line 1)\n" + + "\t@Deprecated @ class X {}\n" + + "\t ^^\n" + + "Groovy:class ? is not an annotation in @?\n" + + "----------\n" + + "2. ERROR in X.groovy (at line 1)\n" + + "\t@Deprecated @ class X {}\n" + + "\t ^\n" + + "Groovy:unable to resolve class ? for annotation\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "public @Deprecated @? class X {\n" + + " public @groovy.transform.Generated X() {\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation6() { + //@formatter:off + String[] sources = { + "X.groovy", + "@ @Deprecated class X {}", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy (at line 1)\n" + + "\t@ @Deprecated class X {}\n" + + "\t^^\n" + + "Groovy:class ? is not an annotation in @?\n" + + "----------\n" + + "2. ERROR in X.groovy (at line 1)\n" + + "\t@ @Deprecated class X {}\n" + + "\t ^\n" + + "Groovy:unable to resolve class ? for annotation\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "public @? @Deprecated class X {\n" + + " public @groovy.transform.Generated X() {\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation7() { + //@formatter:off + String[] sources = { + "X.groovy", + "@Deprecated @ @SuppressWarnings('nls') class X {}", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy (at line 1)\n" + + "\t@Deprecated @ @SuppressWarnings('nls') class X {}\n" + + "\t ^^\n" + + "Groovy:class ? is not an annotation in @?\n" + + "----------\n" + + "2. ERROR in X.groovy (at line 1)\n" + + "\t@Deprecated @ @SuppressWarnings('nls') class X {}\n" + + "\t ^\n" + + "Groovy:unable to resolve class ? for annotation\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "public @Deprecated @? @SuppressWarnings(\"nls\") class X {\n" + + " public @groovy.transform.Generated X() {\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation8() { + //@formatter:off + String[] sources = { + "X.groovy", + "class X {\n" + + " @ def x\n" + + "}\n", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy (at line 2)\n" + + "\t@ def x\n" + + "\t^^\n" + + "Groovy:class ? is not an annotation in @?\n" + + "----------\n" + + "2. ERROR in X.groovy (at line 2)\n" + + "\t@ def x\n" + + "\t ^\n" + + "Groovy:unable to resolve class ? for annotation\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "public class X {\n" + + " private @? java.lang.Object x;\n" + + " public @groovy.transform.Generated X() {\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation9() { + //@formatter:off + String[] sources = { + "X.groovy", + "class X {\n" + + " @ void x() {}\n" + + "}\n", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy (at line 2)\n" + + "\t@ void x() {}\n" + + "\t^^\n" + + "Groovy:class ? is not an annotation in @?\n" + + "----------\n" + + "2. ERROR in X.groovy (at line 2)\n" + + "\t@ void x() {}\n" + + "\t ^\n" + + "Groovy:unable to resolve class ? for annotation\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "public class X {\n" + + " public @groovy.transform.Generated X() {\n" + + " }\n" + + " public @? void x() {\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation10() { + //@formatter:off + String[] sources = { + "X.groovy", + "@A(foo='1',)\n" + + "class X {\n" + + "}\n", + + "A.groovy", + "@interface A {\n" + + " String foo()\n" + + " String bar()\n" + + "}\n", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy (at line 1)\n" + + "\t@A(foo='1',)\n" + + "\t^^\n" + + "Groovy:No explicit/default value found for annotation attribute 'bar' in @A\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "public @A(foo = \"1\") class X {\n" + + " public @groovy.transform.Generated X() {\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation11() { + //@formatter:off + String[] sources = { + "X.groovy", + "@A(foo=['1','2'],)\n" + + "class X {\n" + + "}\n", + + "A.groovy", + "@interface A {\n" + + " String[] foo()\n" + + " String bar()\n" + + "}\n", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy (at line 1)\n" + + "\t@A(foo=['1','2'],)\n" + + "\t^^\n" + + "Groovy:No explicit/default value found for annotation attribute 'bar' in @A\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "public @A(foo = {\"1\", \"2\"}) class X {\n" + + " public @groovy.transform.Generated X() {\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation12() { + //@formatter:off + String[] sources = { + "X.groovy", + "@A(foo='1', b)\n" + + "class X {\n" + + "}\n", + + "A.groovy", + "@interface A {\n" + + " String foo()\n" + + " String bar()\n" + + "}\n", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in X.groovy\n" + + "The attribute b is undefined for the annotation type A\n" + + "----------\n" + + "2. ERROR in X.groovy (at line 1)\n" + + "\t@A(foo='1', b)\n" + + "\t^^\n" + + "Groovy:No explicit/default value found for annotation attribute 'bar' in @A\n" + + "----------\n"); + + checkGCUDeclaration("X.groovy", + "public @A(foo = \"1\",b = \"ERROR\") class X {\n" + + " public @groovy.transform.Generated X() {\n" + + " }\n" + + "}\n"); + } + + @Test + public void testParsingRecovery_IncompleteAnnotation13() { + //@formatter:off + String[] sources = { + "X.groovy", + "@A(foo='1', bar=)\n" + + "class X {\n" + + "}\n", + + "A.groovy", + "@interface A {\n" + + " String foo()\n" + + " String bar()\n" + + "}\n", + }; + //@formatter:on + + runNegativeTest(sources, ""); + + checkGCUDeclaration("X.groovy", + "public @A(foo = \"1\",bar = \"ERROR\") class X {\n" + + " public @groovy.transform.Generated X() {\n" + + " }\n" + + "}\n"); + } + @Test public void testParsingRecovery_IncompleteAssignment1() { //@formatter:off diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/groovy.g b/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/groovy.g index 06d2f79fc9..deebed7073 100644 --- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/groovy.g +++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/groovy.g @@ -1171,8 +1171,8 @@ annotationMemberValuePair! {Token first = LT(1);} // GRECLIPSE edit -- allow pair with no value initializer //: i:annotationIdent ASSIGN! nls! v:annotationMemberValueInitializer : i:annotationIdent ( ASSIGN! nls! ( v:annotationMemberValueInitializer )? )? - {#annotationMemberValuePair = #(create(ANNOTATION_MEMBER_VALUE_PAIR,"ANNOTATION_MEMBER_VALUE_PAIR",first,LT(1)), i, v);} // GRECLIPSE end + {#annotationMemberValuePair = #(create(ANNOTATION_MEMBER_VALUE_PAIR,"ANNOTATION_MEMBER_VALUE_PAIR",first,LT(1)), i, v);} ; annotationIdent diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/parser/GroovyRecognizer.smap b/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/parser/GroovyRecognizer.smap index 962edb6fd7..0c392f9914 100644 --- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/parser/GroovyRecognizer.smap +++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/parser/GroovyRecognizer.smap @@ -2390,12 +2390,12 @@ groovy.g 1173:4849 1173:4850 1173:4851 -1174:4853 -1174:4854 -1174:4855 -1174:4856 -1174:4858 -1174:4859 +1175:4853 +1175:4854 +1175:4855 +1175:4856 +1175:4858 +1175:4859 1178:4864 1178:4866 1178:4867