groovy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pascalschumac...@apache.org
Subject groovy git commit: GROOVY-7793: Compiler compiles class with private abstract method (closes #328)
Date Sat, 07 May 2016 17:48:32 GMT
Repository: groovy
Updated Branches:
  refs/heads/GROOVY_2_4_X fa790d1aa -> f282d21d8


GROOVY-7793: Compiler compiles class with private abstract method (closes #328)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/f282d21d
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/f282d21d
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/f282d21d

Branch: refs/heads/GROOVY_2_4_X
Commit: f282d21d87d563440ad5c65c1554fdc7f35f56c4
Parents: fa790d1
Author: Andre Steingress <me@andresteingress.com>
Authored: Wed May 4 23:17:03 2016 +0200
Committer: pascalschumacher <pascalschumacher@gmx.net>
Committed: Sat May 7 19:48:26 2016 +0200

----------------------------------------------------------------------
 .../classgen/ClassCompletionVerifier.java       | 16 +++++
 .../groovy/AbstractClassAndInterfaceTest.groovy | 63 ++++++++++++++++++++
 .../classgen/ClassCompletionVerifierTest.java   |  9 +++
 3 files changed, 88 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/f282d21d/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java b/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
index 2867c0a..47e3175 100644
--- a/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
+++ b/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
@@ -68,6 +68,7 @@ public class ClassCompletionVerifier extends ClassCodeVisitorSupport {
         if (source != null && !source.getErrorCollector().hasErrors()) {
             checkClassForIncorrectModifiers(node);
             checkInterfaceMethodVisibility(node);
+            checkAbstractMethodVisibility(node);
             checkClassForOverwritingFinal(node);
             checkMethodsForIncorrectModifiers(node);
             checkMethodsForWeakerAccess(node);
@@ -127,6 +128,21 @@ public class ClassCompletionVerifier extends ClassCodeVisitorSupport
{
         }
     }
 
+    private void checkAbstractMethodVisibility(ClassNode node) {
+        // we only do check abstract classes (including enums), no interfaces or non-abstract
classes
+        if (!isAbstract(node.getModifiers()) || isInterface(node.getModifiers())) return;
+
+        List<MethodNode> abstractMethods = node.getAbstractMethods();
+        if (abstractMethods == null || abstractMethods.isEmpty()) return;
+
+        for (MethodNode method : abstractMethods) {
+            if (method.isPrivate()) {
+                addError("Method '" + method.getName() + "' from " + getDescription(node)
+
+                        " must not be private as it is declared as an abstract method.",
method);
+            }
+        }
+    }
+
     private void checkNoAbstractMethodsNonabstractClass(ClassNode node) {
         if (isAbstract(node.getModifiers())) return;
         List<MethodNode> abstractMethods = node.getAbstractMethods();

http://git-wip-us.apache.org/repos/asf/groovy/blob/f282d21d/src/test/groovy/AbstractClassAndInterfaceTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/AbstractClassAndInterfaceTest.groovy b/src/test/groovy/AbstractClassAndInterfaceTest.groovy
index 5cdcc32..92440ff 100644
--- a/src/test/groovy/AbstractClassAndInterfaceTest.groovy
+++ b/src/test/groovy/AbstractClassAndInterfaceTest.groovy
@@ -260,4 +260,67 @@ class AbstractClassAndInterfaceTest extends CompilableTestSupport {
         """
         shouldNotCompile scriptStr
     }
+
+    void testAbstractClassWithPrivateAbstractMethod() {
+        def msg = shouldNotCompile """
+            abstract class X {
+                private abstract void y()
+            }
+        """
+        assert msg.contains("Method 'y' from class 'X' must not be private as it is declared
as an abstract method.")
+    }
+
+    void testAbstractClassWithPrivateAbstractMethods() {
+        def msg = shouldNotCompile """
+            abstract class X {
+                private abstract void y()
+                private abstract void z()
+            }
+        """
+        assert msg.contains("Method 'y' from class 'X' must not be private as it is declared
as an abstract method.")
+        assert msg.contains("Method 'z' from class 'X' must not be private as it is declared
as an abstract method.")
+    }
+
+    void testAbstractNestedClassWithPrivateAbstractMethod() {
+        def msg = shouldNotCompile """
+            class Z {
+                abstract class X {
+                    private abstract void y()
+                }
+            }
+        """
+        assert msg.contains("Method 'y' from class 'Z\$X' must not be private as it is declared
as an abstract method.")
+    }
+
+    void testClassWithPrivateAbstractMethod() {
+        def msg = shouldNotCompile """
+            class X {
+                private abstract void y()
+            }
+        """
+        assert !msg.contains("Method 'y' from class 'X' must not be private as it is declared
as an abstract method.")
+        assert msg.contains("Can't have an abstract method in a non-abstract class. The class
'X' must be declared abstract or the method 'void y()' must be implemented.")
+    }
+
+    void testEnumWithPrivateAbstractMethod() {
+        def msg = shouldNotCompile """
+            enum X {
+                CONST {
+                    private void y() { }
+                }
+
+                private abstract void y()
+            }
+        """
+        assert msg.contains("Method 'y' from class 'X' must not be private as it is declared
as an abstract method.")
+    }
+
+    void testInterfaceWithPrivateAbstractMethod() {
+        def msg = shouldNotCompile """
+            interface X {
+                private abstract void y()
+            }
+        """
+        assert msg.contains("Method 'y' is private but should be public in interface 'X'.")
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/f282d21d/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java b/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java
index d3eaae0..5233cb2 100644
--- a/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java
+++ b/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java
@@ -73,6 +73,8 @@ public class ClassCompletionVerifierTest extends TestSupport {
             "Method 'prom' is protected but should be public in interface 'zzz'.";
     private static final String EXPECTED_PRIVATE_METHOD_ERROR_MESSAGE =
             "Method 'prim' is private but should be public in interface 'zzz'.";
+    private static final String EXPECTED_ABSTRACT_PRIVATE_METHOD_ERROR_MESSAGE =
+            "Method 'y' from class 'X' must not be private as it is declared as an abstract
method.";
 
     protected void setUp() throws Exception {
         super.setUp();
@@ -80,6 +82,13 @@ public class ClassCompletionVerifierTest extends TestSupport {
         verifier = new ClassCompletionVerifier(source);
     }
 
+    public void testDetectsAbstractPrivateMethod() throws Exception {
+        ClassNode node = new ClassNode("X", ACC_ABSTRACT, ClassHelper.OBJECT_TYPE);
+        node.addMethod(new MethodNode("y", ACC_PRIVATE | ACC_ABSTRACT, ClassHelper.VOID_TYPE,
new Parameter[0], ClassNode.EMPTY_ARRAY, null));
+        verifier.visitClass(node);
+        checkErrorMessage(EXPECTED_ABSTRACT_PRIVATE_METHOD_ERROR_MESSAGE);
+    }
+
     public void testDetectsFinalAbstractClass() throws Exception {
         checkVisitErrors("FinalClass", ACC_FINAL, false);
         checkVisitErrors("AbstractClass", ACC_ABSTRACT, false);


Mime
View raw message