You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2025/05/13 16:53:59 UTC
(groovy) 01/01: GROOVY-11663: STC: error for class or trait property expression
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY-11663
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 9a273d5a3e0c40be28a53f037182b2e6bb26e889
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue May 13 09:48:07 2025 -0500
GROOVY-11663: STC: error for class or trait property expression
---
.../transform/stc/StaticTypeCheckingVisitor.java | 41 ++++++++++++++--------
.../packageScope/DifferentPackageTest.groovy | 2 +-
.../traitx/TraitASTTransformationTest.groovy | 9 +++--
3 files changed, 34 insertions(+), 18 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 f375a1ea7d..fa7df3da1e 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -763,28 +763,39 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
@Override
public void visitPropertyExpression(final PropertyExpression expression) {
- if (existsProperty(expression, !typeCheckingContext.isTargetOfEnclosingAssignment(expression))) return;
-
- if (!extension.handleUnresolvedProperty(expression)) {
- var objectExpression = expression.getObjectExpression();
- var objectExpressionType = (objectExpression instanceof ClassExpression
- ? objectExpression.getType() : wrapTypeIfNecessary(getType(objectExpression)));
- objectExpressionType = findCurrentInstanceOfClass(objectExpression, objectExpressionType);
- addStaticTypeError("No such property: " + expression.getPropertyAsString() + " for class: " + prettyPrintTypeName(objectExpressionType), expression);
+ boolean readOnly = !typeCheckingContext.isTargetOfEnclosingAssignment(expression);
+ if (existsProperty(expression, readOnly)
+ || extension.handleUnresolvedProperty(expression)) {
+ return; // resolved or excused
}
+ recordMissingProperty(expression);
}
@Override
public void visitAttributeExpression(final AttributeExpression expression) {
- if (existsProperty(expression, true)) return;
+ boolean readOnly = true;
+ if (existsProperty(expression, readOnly)
+ || extension.handleUnresolvedAttribute(expression)) {
+ return; // resolved or excused
+ }
+ recordMissingProperty(expression);
+ }
- if (!extension.handleUnresolvedAttribute(expression)) {
- var objectExpression = expression.getObjectExpression();
- var objectExpressionType = (objectExpression instanceof ClassExpression
- ? objectExpression.getType() : wrapTypeIfNecessary(getType(objectExpression)));
- objectExpressionType = findCurrentInstanceOfClass(objectExpression, objectExpressionType);
- addStaticTypeError("No such attribute: " + expression.getPropertyAsString() + " for class: " + prettyPrintTypeName(objectExpressionType), expression);
+ private void recordMissingProperty(final PropertyExpression expression) {
+ var objectExpression = expression.getObjectExpression();
+ var objectExpressionType = findCurrentInstanceOfClass(objectExpression, getType(objectExpression));
+
+ String pattern;
+ if (!isClassClassNodeWrappingConcreteType(objectExpressionType)) {
+ pattern = "No such {0,choice,1#attribute|2#property}: {1} for class: {2}";
+ } else {
+ objectExpressionType = objectExpressionType.getGenericsTypes()[0].getType();
+ pattern = "No such {0,choice,1#attribute|2#property}: {1} for Class or static {0,choice,1#field|2#property} for class: {2}";
}
+
+ String error = java.text.MessageFormat.format(pattern, expression instanceof AttributeExpression ? 1 : 2, expression.getPropertyAsString(), prettyPrintTypeName(wrapTypeIfNecessary(objectExpressionType)));
+ ASTNode node = expression.getLineNumber() > 0 ? expression : expression.getProperty(); // GROOVY-11663
+ addStaticTypeError(error, node);
}
@Override
diff --git a/src/test/groovy/org/codehaus/groovy/transform/packageScope/DifferentPackageTest.groovy b/src/test/groovy/org/codehaus/groovy/transform/packageScope/DifferentPackageTest.groovy
index ba1644879e..135dd8d364 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/packageScope/DifferentPackageTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/packageScope/DifferentPackageTest.groovy
@@ -447,6 +447,6 @@ final class DifferentPackageTest {
'''
)
}
- assert err =~ /No such property: answer for class: p.One/ // TODO: Cannot access p.One#getAnswer?
+ assert err =~ /No such property: answer for Class or static property for class: p.One/ // TODO: Cannot access p.One#getAnswer?
}
}
diff --git a/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy b/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index e0bfd2b087..c1dd00f55e 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -3710,10 +3710,10 @@ final class TraitASTTransformationTest {
"""
}
- // GROOVY-11641
+ // GROOVY-11641, GROOVY-11663
@CompileModesTest
void testTraitAccessToInheritedStaticMethods4(String mode) {
- shouldFail shell, """
+ var err = shouldFail shell, """
$mode
trait Foo {
public static final String BANG = '!'
@@ -3739,6 +3739,11 @@ final class TraitASTTransformationTest {
Main.test1()
new Main().test2()
"""
+ if (mode.endsWith('Dynamic')) {
+ assert err =~ /MissingPropertyException/
+ } else {
+ assert err =~ /\[Static type checking\] - No such property: BANG for Class or static property for class: Bar/
+ }
}
// GROOVY-9386