sonatype-lift[bot] commented on a change in pull request #1606:
URL: https://github.com/apache/groovy/pull/1606#discussion_r680271839



##########
File path: 
src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
##########
@@ -309,23 +313,79 @@ private void checkAbstractDeclaration(MethodNode 
methodNode) {
                 methodNode.getTypeDescriptor() + "' must not be abstract.", 
methodNode);
     }
 
-    private void checkClassForOverwritingFinal(ClassNode cn) {
+    private void checkClassForExtendingFinalOrSealed(ClassNode cn) {
+        boolean sealed = Boolean.TRUE.equals(cn.getNodeMetaData(Sealed.class));
+        if (sealed && cn.getPermittedSubclasses().isEmpty()) {
+            addError("Sealed " + getDescription(cn) + " has no explicit or 
implicit permitted classes.", cn);
+            return;
+        }
+        boolean isFinal = isFinal(cn.getModifiers());
+        if (sealed && isFinal) {
+            addError("The " + getDescription(cn) + " cannot be both final and 
sealed.", cn);
+            return;
+        }
+        boolean nonSealed = 
Boolean.TRUE.equals(cn.getNodeMetaData(NonSealed.class));
         ClassNode superCN = cn.getSuperClass();
-        if (superCN == null) return;
-        if (!isFinal(superCN.getModifiers())) return;
-        String msg = "You are not allowed to overwrite the final " + 
getDescription(superCN) + ".";
-        addError(msg, cn);
+        boolean sealedSuper = superCN != null && superCN.isSealed();
+        boolean sealedInterface = 
Arrays.stream(cn.getInterfaces()).anyMatch(ClassNode::isSealed);
+        if (nonSealed && !(sealedSuper || sealedInterface)) {
+            addError("The " + getDescription(cn) + " cannot be non-sealed as 
it has no sealed parent.", cn);
+            return;
+        }
+        if (sealedSuper || sealedInterface) {
+            if (sealed && nonSealed) {
+                addError("The " + getDescription(cn) + " cannot be both sealed 
and non-sealed.", cn);
+                return;
+            }
+            if (isFinal && nonSealed) {
+                addError("The " + getDescription(cn) + " cannot be both final 
and non-sealed.", cn);
+                return;
+            }
+            if (sealedSuper) {
+                checkSealedParent(cn, superCN, isFinal, nonSealed);
+            }
+            if (sealedInterface) {
+                for (ClassNode candidate : cn.getInterfaces()) {
+                    if (candidate.isSealed()) {
+                        checkSealedParent(cn, candidate, isFinal, nonSealed);
+                    }
+                }
+            }
+        }
+        if (superCN == null || !isFinal(superCN.getModifiers())) return;
+        addError("You are not allowed to extend the final " + 
getDescription(superCN) + ".", cn);
+    }
+
+    private void checkSealedParent(ClassNode cn, ClassNode parent, boolean 
isFinal, boolean nonSealed) {
+        boolean found = false;
+        for (ClassNode permitted : parent.getPermittedSubclasses()) {
+            if (permitted.equals(cn)) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            addError("The " + getDescription(cn) + " is not a permitted 
subclass of the sealed " + getDescription(parent) + ".", cn);
+            return;
+        }
+        boolean explicitlyMarked = nonSealed || cn.isSealed() || isFinal;
+        if (!explicitlyMarked) {
+            addError("The " + getDescription(cn) + " being a child of sealed " 
+ getDescription(parent) + " must be marked final, sealed, or non-sealed.", cn);
+        }
     }
 
     private void checkImplementsAndExtends(ClassNode node) {
-        ClassNode cn = node.getSuperClass();
-        if (cn.isInterface() && !node.isInterface()) {
-            addError("You are not allowed to extend the " + getDescription(cn) 
+ ", use implements instead.", node);
+        ClassNode sn = node.getSuperClass();
+        if (sn.isInterface() && !node.isInterface()) {

Review comment:
       *NULL_DEREFERENCE:*  object `sn` last assigned on line 378 could be null 
and is dereferenced at line 379.
   (at-me [in a reply](https://help.sonatype.com/lift) with `help` or `ignore`)




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@groovy.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to