@@ -315,53 +315,53 @@ private void checkAbstractDeclaration(final MethodNode methodNode) {
315315 }
316316
317317 private void checkClassForExtendingFinalOrSealed (final ClassNode cn ) {
318- boolean sealed = Boolean .TRUE .equals (cn .getNodeMetaData (groovy .transform .Sealed .class ));
319- if (sealed && cn .getPermittedSubclasses ().isEmpty ()) {
320- addError ("Sealed " + getDescription (cn ) + " has no explicit or implicit permitted subclasses." , cn );
321- return ;
322- }
323318 boolean isFinal = isFinal (cn .getModifiers ());
324- if (sealed && isFinal ) {
325- addError ("The " + getDescription (cn ) + " cannot be both final and sealed." , cn );
326- return ;
319+ boolean isSealed = Boolean .TRUE .equals (cn .getNodeMetaData (groovy .transform .Sealed .class ));
320+ boolean isNonSealed = cn .getAnnotations ().stream ().anyMatch (an -> an .getClassNode ().getName ().equals ("groovy.transform.NonSealed" )); // GROOVY-11768
321+
322+ ClassNode sc = cn .getSuperClass ();
323+ if (sc != null && isFinal (sc .getModifiers ())) {
324+ addError ("You are not allowed to extend the final " + getDescription (sc ) + "." , cn );
327325 }
328- boolean explicitNonSealed = nonSealed (cn );
329- ClassNode superCN = cn .getSuperClass ();
330- boolean sealedSuper = superCN != null && superCN .isSealed ();
331- boolean sealedInterface = Arrays .stream (cn .getInterfaces ()).anyMatch (ClassNode ::isSealed );
332- boolean nonSealedSuper = superCN != null && nonSealed (superCN );
333- boolean nonSealedInterface = Arrays .stream (cn .getInterfaces ()).anyMatch (this ::nonSealed );
334326
335- if (explicitNonSealed && !(sealedSuper || sealedInterface || nonSealedSuper || nonSealedInterface )) {
336- addError ("The " + getDescription (cn ) + " cannot be non-sealed as it has no sealed parent." , cn );
337- return ;
327+ if (isFinal && isNonSealed ) {
328+ addError ("The " + getDescription (cn ) + " cannot be both final and non-sealed." , cn );
338329 }
339- if (sealedSuper || sealedInterface ) {
340- if (sealed && explicitNonSealed ) {
341- addError ("The " + getDescription (cn ) + " cannot be both sealed and non-sealed." , cn );
342- return ;
330+ if (isSealed ) {
331+ if (isFinal ) {
332+ addError ("The " + getDescription (cn ) + " cannot be both final and sealed." , cn );
343333 }
344- if (isFinal && explicitNonSealed ) {
345- addError ("The " + getDescription (cn ) + " cannot be both final and non-sealed." , cn );
346- return ;
334+ if (isNonSealed ) {
335+ addError ("The " + getDescription (cn ) + " cannot be both sealed and non-sealed." , cn );
347336 }
348- if (sealedSuper ) {
349- checkSealedParent ( cn , superCN );
337+ if (cn . getPermittedSubclasses (). isEmpty () ) {
338+ addError ( "Sealed " + getDescription ( cn ) + " has no explicit or implicit permitted subclasses." , cn );
350339 }
351- if (sealedInterface ) {
352- for (ClassNode candidate : cn .getInterfaces ()) {
353- if (candidate .isSealed ()) {
354- checkSealedParent (cn , candidate );
355- }
340+ }
341+
342+ boolean sealedSuper = sc != null && sc .isSealed ();
343+ boolean nonSealedSuper = sc != null && isNonSealed (sc );
344+ boolean sealedInterface = Arrays .stream (cn .getInterfaces ()).anyMatch (ClassNode ::isSealed );
345+ boolean nonSealedInterface = Arrays .stream (cn .getInterfaces ()).anyMatch (this ::isNonSealed );
346+
347+ if (isNonSealed && !(sealedSuper || sealedInterface || nonSealedSuper || nonSealedInterface )) {
348+ addError ("The " + getDescription (cn ) + " cannot be non-sealed as it has no sealed parent." , cn );
349+ }
350+ if (sealedSuper ) {
351+ checkSealedParent (cn , sc );
352+ }
353+ if (sealedInterface ) {
354+ for (ClassNode si : cn .getInterfaces ()) {
355+ if (si .isSealed ()) {
356+ checkSealedParent (cn , si );
356357 }
357358 }
358359 }
359- if (superCN == null || !isFinal (superCN .getModifiers ())) return ;
360- addError ("You are not allowed to extend the final " + getDescription (superCN ) + "." , cn );
361360 }
362361
363- private boolean nonSealed (final ClassNode cn ) {
364- if (Boolean .TRUE .equals (cn .getNodeMetaData (groovy .transform .NonSealed .class ))) {
362+ private boolean isNonSealed (final ClassNode cn ) {
363+ if (cn .isPrimaryClassNode ()
364+ && Boolean .TRUE .equals (cn .getNodeMetaData (groovy .transform .NonSealed .class ))) {
365365 return true ;
366366 }
367367 ClassNode sc = cn .getSuperClass (); // GROOVY-11292, GROOVY-11750: check super class
0 commit comments