You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/02/23 11:02:42 UTC

[groovy] branch danielsun/tweak-classdecl-rule updated (fc1f360 -> a896b3f)

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a change to branch danielsun/tweak-classdecl-rule
in repository https://gitbox.apache.org/repos/asf/groovy.git.


 discard fc1f360  Tweak rule `classDeclaration`
     new a896b3f  Tweak `classDeclaration` rule

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (fc1f360)
            \
             N -- N -- N   refs/heads/danielsun/tweak-classdecl-rule (a896b3f)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/test/gls/generics/GenericsUsageTest.groovy | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)


[groovy] 01/01: Tweak `classDeclaration` rule

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch danielsun/tweak-classdecl-rule
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit a896b3f05c8778a837047a60cf4ac4b036c0d004
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Feb 23 19:02:18 2020 +0800

    Tweak `classDeclaration` rule
---
 src/antlr/GroovyParser.g4                          |  35 +------
 src/test/gls/generics/GenericsUsageTest.groovy     |   4 +-
 .../apache/groovy/parser/antlr4/AstBuilder.java    |  53 +++++++++-
 .../groovy/parser/antlr4/SyntaxErrorTest.groovy    | 107 +++++++++++++++++++++
 4 files changed, 162 insertions(+), 37 deletions(-)

diff --git a/src/antlr/GroovyParser.g4 b/src/antlr/GroovyParser.g4
index f075237..ef6cd79 100644
--- a/src/antlr/GroovyParser.g4
+++ b/src/antlr/GroovyParser.g4
@@ -221,36 +221,11 @@ locals[ int t ]
         |   AT INTERFACE { $t = 3; }
         |   TRAIT { $t = 4; }
         )
-        identifier nls
-
-        (
-            { 3 != $t }?
-            (typeParameters nls)?
-            (
-                { 2 != $t }?
-                EXTENDS nls
-                    (
-                        // Only interface can extend more than one super class
-                        {1 == $t}? scs=typeList
-                    |
-                        sc=type
-                    )
-                nls
-            |
-                /* enum should not have type parameters and extends */
-            )
-
-            (
-                {1 != $t}?
-                IMPLEMENTS nls is=typeList nls
-            |
-                /* interface should not implement other interfaces */
-            )
-        |
-            /* annotation should not have implements and extends*/
-        )
-
-        classBody[$t]
+        identifier
+        (nls typeParameters)?
+        (nls EXTENDS nls scs=typeList)?
+        (nls IMPLEMENTS nls is=typeList)?
+        nls classBody[$t]
     ;
 
 // t    see the comment of classDeclaration
diff --git a/src/test/gls/generics/GenericsUsageTest.groovy b/src/test/gls/generics/GenericsUsageTest.groovy
index 3b07463..8ef2e56 100644
--- a/src/test/gls/generics/GenericsUsageTest.groovy
+++ b/src/test/gls/generics/GenericsUsageTest.groovy
@@ -214,7 +214,7 @@ final class GenericsUsageTest extends CompilableTestSupport {
 
             shouldFailCompilationWithMessage """
                 abstract class ArrayList2<E> extends AbstractList<E implements List<E> {}
-            """, "Unexpected input: 'AbstractList<E implements'"
+            """, "Unexpected input: '<'"
 
             shouldFailCompilationWithMessage """
                 abstract class ArrayList3<E> extends AbstractList<E> implements List<E {}
@@ -312,7 +312,7 @@ final class GenericsUsageTest extends CompilableTestSupport {
         } else {
             shouldFailCompilationWithMessages '''
                 class MyList extends ArrayList<> {}
-            ''', ['Unexpected input: \'ArrayList<>\'']
+            ''', ['Unexpected input: \'<\'']
         }
 
         shouldFailCompilationWithMessages '''
diff --git a/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java b/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
index 9b2780e..82baee7 100644
--- a/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -1082,6 +1082,39 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
             throw createParsingFailedException("var cannot be used for type declarations", ctx.identifier());
         }
 
+        boolean isAnnotation = asBoolean(ctx.AT());
+        if (isAnnotation) {
+            if (asBoolean(ctx.typeParameters())) {
+                throw createParsingFailedException("annotation declaration cannot have type parameters", ctx.typeParameters());
+            }
+
+            if (asBoolean(ctx.EXTENDS())) {
+                throw createParsingFailedException("No extends clause allowed for annotation declaration", ctx.EXTENDS());
+            }
+
+            if (asBoolean(ctx.IMPLEMENTS())) {
+                throw createParsingFailedException("No implements clause allowed for annotation declaration", ctx.IMPLEMENTS());
+            }
+        }
+
+        boolean isEnum = asBoolean(ctx.ENUM());
+        if (isEnum) {
+            if (asBoolean(ctx.typeParameters())) {
+                throw createParsingFailedException("enum declaration cannot have type parameters", ctx.typeParameters());
+            }
+
+            if (asBoolean(ctx.EXTENDS())) {
+                throw createParsingFailedException("No extends clause allowed for enum declaration", ctx.EXTENDS());
+            }
+        }
+
+        boolean isInterface = (asBoolean(ctx.INTERFACE()) && !isAnnotation);
+        if (isInterface) {
+            if (asBoolean(ctx.IMPLEMENTS())) {
+                throw createParsingFailedException("No implements clause allowed for interface declaration", ctx.IMPLEMENTS());
+            }
+        }
+
         List<ModifierNode> modifierNodeList = ctx.getNodeMetaData(TYPE_DECLARATION_MODIFIERS);
         Objects.requireNonNull(modifierNodeList, "modifierNodeList should not be null");
         ModifierManager modifierManager = new ModifierManager(this, modifierNodeList);
@@ -1091,7 +1124,8 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
         modifiers &= ~Opcodes.ACC_SYNTHETIC;
 
         ClassNode classNode, outerClass = classNodeStack.peek();
-        if (asBoolean(ctx.ENUM())) {
+
+        if (isEnum) {
             classNode = EnumHelper.makeEnumNode(
                     asBoolean(outerClass) ? className : packageName + className,
                     modifiers,
@@ -1117,7 +1151,6 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
         configureAST(classNode, ctx);
         classNode.setSyntheticPublic(syntheticPublic);
         classNode.setGenericsTypes(this.visitTypeParameters(ctx.typeParameters()));
-        boolean isInterface = (asBoolean(ctx.INTERFACE()) && !asBoolean(ctx.AT()));
         boolean isInterfaceWithDefaultMethods = (isInterface && this.containsDefaultMethods(ctx));
 
         if (isInterfaceWithDefaultMethods || asBoolean(ctx.TRAIT())) {
@@ -1131,7 +1164,17 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
         classNode.putNodeMetaData(CLASS_NAME, className);
 
         if (asBoolean(ctx.CLASS()) || asBoolean(ctx.TRAIT()) || isInterfaceWithDefaultMethods) {
-            classNode.setSuperClass(this.visitType(ctx.sc));
+            ClassNode superClass;
+            if (asBoolean(ctx.scs)) {
+                ClassNode[] scs = this.visitTypeList(ctx.scs);
+                if (scs.length > 1) {
+                    throw createParsingFailedException("Cannot extend multiple classes", ctx.EXTENDS());
+                }
+                superClass = scs[0];
+            } else {
+                superClass = ClassHelper.OBJECT_TYPE;
+            }
+            classNode.setSuperClass(superClass);
             classNode.setInterfaces(this.visitTypeList(ctx.is));
             this.initUsingGenerics(classNode);
 
@@ -1142,12 +1185,12 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
             this.initUsingGenerics(classNode);
             this.hackMixins(classNode);
 
-        } else if (asBoolean(ctx.ENUM())) {
+        } else if (isEnum) {
             classNode.setModifiers(classNode.getModifiers() | Opcodes.ACC_ENUM | Opcodes.ACC_FINAL);
             classNode.setInterfaces(this.visitTypeList(ctx.is));
             this.initUsingGenerics(classNode);
 
-        } else if (asBoolean(ctx.AT())) {
+        } else if (isAnnotation) {
             classNode.setModifiers(classNode.getModifiers() | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_ANNOTATION);
             classNode.addInterface(ClassHelper.Annotation_TYPE);
             this.hackMixins(classNode);
diff --git a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
index 98d2a1c..fc7cebd 100644
--- a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
+++ b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
@@ -284,6 +284,113 @@ test.groovy: 2: Missing ')' @ line 2, column 22.
 '''
     }
 
+
+    void "test groovy core - AnnotationDeclaration 1"() {
+        def err = expectFail '''\
+@interface A<T> {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: annotation declaration cannot have type parameters @ line 1, column 13.
+   @interface A<T> {}
+               ^
+
+1 error
+'''
+    }
+
+    void "test groovy core - AnnotationDeclaration 2"() {
+        def err = expectFail '''\
+@interface A extends Object {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: No extends clause allowed for annotation declaration @ line 1, column 14.
+   @interface A extends Object {}
+                ^
+
+1 error
+'''
+    }
+
+    void "test groovy core - AnnotationDeclaration 3"() {
+        def err = expectFail '''\
+@interface A implements Serializable {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: No implements clause allowed for annotation declaration @ line 1, column 14.
+   @interface A implements Serializable {}
+                ^
+
+1 error
+'''
+    }
+
+    void "test groovy core - EnumDeclaration 1"() {
+        def err = expectFail '''\
+enum E<T> {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: enum declaration cannot have type parameters @ line 1, column 7.
+   enum E<T> {}
+         ^
+
+1 error
+'''
+    }
+
+    void "test groovy core - EnumDeclaration 2"() {
+        def err = expectFail '''\
+enum E extends Object {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: No extends clause allowed for enum declaration @ line 1, column 8.
+   enum E extends Object {}
+          ^
+
+1 error
+'''
+    }
+
+    void "test groovy core - InterfaceDeclaration 1"() {
+        def err = expectFail '''\
+interface I implements Serializable {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: No implements clause allowed for interface declaration @ line 1, column 13.
+   interface I implements Serializable {}
+               ^
+
+1 error
+'''
+    }
+
+    void "test test groovy core - ClassDeclaration 1"() {
+        def err = expectFail '''\
+class C extends Object, Number {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: Cannot extend multiple classes @ line 1, column 9.
+   class C extends Object, Number {}
+           ^
+
+1 error
+'''
+    }
+
+
     //--------------------------------------------------------------------------
     def expectFail(String code) {
         try {