diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties index dd5964be48be..89801b5de43c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties @@ -364,3 +364,4 @@ cannot.assign.a.value.to.final.field.0=Cannot assign a value to final field ''{0 variable.0.might.not.have.been.initialized=Variable ''{0}'' might not have been initialized unexpected.symbol=Unexpected symbol statement.expected=Statement expected +annotation.attribute.expected=Annotation attribute expected diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index ff185ab4d5e2..9a53b540541c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -1390,6 +1390,17 @@ public class GroovyAnnotator extends GroovyElementVisitor { @Override public void visitAnnotationNameValuePair(GrAnnotationNameValuePair nameValuePair) { + final PsiElement identifier = nameValuePair.getNameIdentifierGroovy(); + if (identifier == null) { + final PsiElement parent = nameValuePair.getParent(); + if (parent instanceof GrAnnotationArgumentList) { + final int count = ((GrAnnotationArgumentList)parent).getAttributes().length; + if (count > 1) { + myHolder.createErrorAnnotation(nameValuePair, GroovyBundle.message("attribute.name.expected")); + } + } + } + final GrAnnotationMemberValue value = nameValuePair.getValue(); checkAnnotationAttributeValue(value, value); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/auxiliary/annotations/AnnotationArguments.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/auxiliary/annotations/AnnotationArguments.java index 5989f5f97735..89f14017cca8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/auxiliary/annotations/AnnotationArguments.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/auxiliary/annotations/AnnotationArguments.java @@ -43,18 +43,9 @@ public class AnnotationArguments implements GroovyElementTypes { return; } - if (checkIdentAndAssign(builder)) { + if (builder.getTokenType() != mRPAREN) { parsePairs(builder, parser); } - else { - PsiBuilder.Marker pairMarker = builder.mark(); - if (parseAnnotationMemberValueInitializer(builder, parser)) { - pairMarker.done(ANNOTATION_MEMBER_VALUE_PAIR); - } - else { - pairMarker.drop(); - } - } ParserUtils.getToken(builder, mNLS); ParserUtils.getToken(builder, mRPAREN, GroovyBundle.message("rparen.expected")); @@ -122,17 +113,29 @@ public class AnnotationArguments implements GroovyElementTypes { private static boolean parsePair(PsiBuilder builder, GroovyParser parser) { PsiBuilder.Marker marker = builder.mark(); + final PsiBuilder.Marker lfMarker; if (checkIdentAndAssign(builder)) { ParserUtils.getToken(builder, TokenSets.CODE_REFERENCE_ELEMENT_NAME_TOKENS); ParserUtils.getToken(builder, mASSIGN); + + lfMarker = builder.mark(); ParserUtils.getToken(builder, mNLS); } else { - builder.error(GroovyBundle.message("attribute.name.expected")); + lfMarker = null; } if (!parseAnnotationMemberValueInitializer(builder, parser)) { - builder.error(GroovyBundle.message("annotation.member.value.initializer.expected")); + if (lfMarker != null) { + lfMarker.rollbackTo(); + builder.error(GroovyBundle.message("annotation.member.value.initializer.expected")); + } + else { + builder.error(GroovyBundle.message("annotation.attribute.expected")); + } + } + else if (lfMarker != null) { + lfMarker.drop(); } marker.done(ANNOTATION_MEMBER_VALUE_PAIR); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java index 2446b3afe5b8..0c38554a6fae 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java @@ -315,7 +315,9 @@ public class GenerationUtil { while (i < parameters.length) { PsiParameter parameter = parameters[i]; if (parameter == null) continue; - if (parameter instanceof PsiCompiledElement) parameter = (PsiParameter)((PsiCompiledElement)parameter).getMirror(); + if (parameter instanceof PsiCompiledElement) { + parameter = (PsiParameter)((PsiCompiledElement)parameter).getMirror(); + } if (i > 0) text.append(", "); //append ',' if (!classNameProvider.forStubs()) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/AnnotationsParsingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/AnnotationsParsingTest.groovy index d0fbe70b021b..c9a968f187f5 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/AnnotationsParsingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/AnnotationsParsingTest.groovy @@ -34,4 +34,5 @@ public class AnnotationsParsingTest extends GroovyParsingTestCase { public void testDefAttribute() {doTest()} public void testLineFeedAfterRef() {doTest()} public void testKeywordsAttributes() {doTest()} + public void testMess() { doTest() } } diff --git a/plugins/groovy/testdata/parsing/groovy/annotations/mess.test b/plugins/groovy/testdata/parsing/groovy/annotations/mess.test new file mode 100644 index 000000000000..7029eb450f75 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/annotations/mess.test @@ -0,0 +1,52 @@ +@A(x = '5', 'foo', , x=, , 5) +def x +----- +Groovy script + Variable definitions + Modifiers + Annotation + PsiElement(@)('@') + Reference element + PsiElement(identifier)('A') + Annotation arguments + PsiElement(()('(') + Annotation member value pair + PsiElement(identifier)('x') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Literal + PsiElement(string)(''5'') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Annotation member value pair + Literal + PsiElement(string)(''foo'') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Annotation member value pair + PsiErrorElement:Annotation attribute expected + + PsiElement(,)(',') + PsiWhiteSpace(' ') + Annotation member value pair + PsiElement(identifier)('x') + PsiElement(=)('=') + PsiErrorElement:Annotation member value initializer expected + + PsiElement(,)(',') + PsiWhiteSpace(' ') + Annotation member value pair + PsiErrorElement:Annotation attribute expected + + PsiElement(,)(',') + PsiWhiteSpace(' ') + Annotation member value pair + Literal + PsiElement(Integer)('5') + PsiElement())(')') + PsiElement(new line)('\n') + PsiElement(def)('def') + PsiWhiteSpace(' ') + Variable + PsiElement(identifier)('x') \ No newline at end of file