From aa298337dadd8a10053897e397cd83377127ca27 Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Mon, 30 Sep 2024 09:21:51 -0500 Subject: [PATCH] GROOVY-11274: STC: check implicit super class constrctor call --- .../stc/StaticTypeCheckingVisitor.java | 7 ++++ .../transform/stc/ConstructorsSTCTest.groovy | 33 ++++++++++++++++--- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index 1fbaef6a7a4..abbc6331ee8 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -222,6 +222,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.castX; import static org.codehaus.groovy.ast.tools.GeneralUtils.classX; import static org.codehaus.groovy.ast.tools.GeneralUtils.constX; +import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorSuperX; import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX; import static org.codehaus.groovy.ast.tools.GeneralUtils.defaultValueX; import static org.codehaus.groovy.ast.tools.GeneralUtils.elvisX; @@ -2840,6 +2841,12 @@ protected void visitConstructorOrMethod(final MethodNode node, final boolean isC } if (!isConstructor) { returnAdder.visitMethod(node); // GROOVY-7753: we cannot count these auto-generated return statements, see `typeCheckingContext.pushEnclosingReturnStatement` + } else if (!((ConstructorNode) node).firstStatementIsSpecialConstructorCall()) { + ClassNode superClass = node.getDeclaringClass().getSuperClass(); // GROOVY-11274: check implicit "super()" + boolean isInnerClass = superClass.getOuterClass() != null && !Modifier.isStatic(superClass.getModifiers()); + Expression superCall = ctorSuperX(args(isInnerClass ? List.of(castX(superClass.getOuterClass(), nullX())) : List.of())); + if (node.getCode() != null) superCall.setSourcePosition(node.getCode()); + superCall.visit(this); } typeCheckingContext.popEnclosingMethod(); } diff --git a/src/test/groovy/transform/stc/ConstructorsSTCTest.groovy b/src/test/groovy/transform/stc/ConstructorsSTCTest.groovy index 2e79c75995f..6e207b152f1 100644 --- a/src/test/groovy/transform/stc/ConstructorsSTCTest.groovy +++ b/src/test/groovy/transform/stc/ConstructorsSTCTest.groovy @@ -245,7 +245,8 @@ class ConstructorsSTCTest extends StaticTypeCheckingTestCase { int y } A a = [x:100, y:200, z: 300] - ''', 'No such property: z for class: A' + ''', + 'No such property: z for class: A' } void testConstructWithNamedParamsAndMissingProperty() { @@ -255,7 +256,8 @@ class ConstructorsSTCTest extends StaticTypeCheckingTestCase { int y } A a = new A(x:100, y:200, z: 300) - ''', 'No such property: z for class: A' + ''', + 'No such property: z for class: A' } void testConstructFromValuedMapAndIncorrectTypes() { @@ -265,7 +267,8 @@ class ConstructorsSTCTest extends StaticTypeCheckingTestCase { int y } A a = [x:'100', y:200] - ''', 'Cannot assign value of type java.lang.String to variable of type int' + ''', + 'Cannot assign value of type java.lang.String to variable of type int' } void testConstructFromValuedMapAndDynamicKey() { @@ -275,7 +278,8 @@ class ConstructorsSTCTest extends StaticTypeCheckingTestCase { int y } A a = ["${'x'}":'100'] - ''', 'Dynamic keys in map-style constructors are unsupported' + ''', + 'Dynamic keys in map-style constructors are unsupported' } void testConstructWithMapAndInheritance() { @@ -434,7 +438,8 @@ class ConstructorsSTCTest extends StaticTypeCheckingTestCase { ByteArrayOutputStream out } void m(OutputStream o) { new Foo(out:o) } - ''', 'Cannot assign value of type java.io.OutputStream to variable of type java.io.ByteArrayOutputStream' + ''', + 'Cannot assign value of type java.io.OutputStream to variable of type java.io.ByteArrayOutputStream' } void testTypeCheckingInfoShouldNotBeAddedToConstructor() { @@ -590,4 +595,22 @@ class ConstructorsSTCTest extends StaticTypeCheckingTestCase { assert new A().test() == ['value'] ''' } + + // GROOVY-11274 + void testPrivateDefaultConstructor() { + shouldFailWithMessages ''' + class C { + private C() { + } + C(String s) { + } + } + class D extends C { + D() { + //super() + } + } + ''', + 'Cannot find matching constructor C()' + } }