Skip to content

Commit 9a273d5

Browse files
committed
GROOVY-11663: STC: error for class or trait property expression
1 parent d51a0b6 commit 9a273d5

3 files changed

Lines changed: 34 additions & 18 deletions

File tree

src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -763,28 +763,39 @@ private boolean tryVariableExpressionAsProperty(final VariableExpression vexp, f
763763

764764
@Override
765765
public void visitPropertyExpression(final PropertyExpression expression) {
766-
if (existsProperty(expression, !typeCheckingContext.isTargetOfEnclosingAssignment(expression))) return;
767-
768-
if (!extension.handleUnresolvedProperty(expression)) {
769-
var objectExpression = expression.getObjectExpression();
770-
var objectExpressionType = (objectExpression instanceof ClassExpression
771-
? objectExpression.getType() : wrapTypeIfNecessary(getType(objectExpression)));
772-
objectExpressionType = findCurrentInstanceOfClass(objectExpression, objectExpressionType);
773-
addStaticTypeError("No such property: " + expression.getPropertyAsString() + " for class: " + prettyPrintTypeName(objectExpressionType), expression);
766+
boolean readOnly = !typeCheckingContext.isTargetOfEnclosingAssignment(expression);
767+
if (existsProperty(expression, readOnly)
768+
|| extension.handleUnresolvedProperty(expression)) {
769+
return; // resolved or excused
774770
}
771+
recordMissingProperty(expression);
775772
}
776773

777774
@Override
778775
public void visitAttributeExpression(final AttributeExpression expression) {
779-
if (existsProperty(expression, true)) return;
776+
boolean readOnly = true;
777+
if (existsProperty(expression, readOnly)
778+
|| extension.handleUnresolvedAttribute(expression)) {
779+
return; // resolved or excused
780+
}
781+
recordMissingProperty(expression);
782+
}
780783

781-
if (!extension.handleUnresolvedAttribute(expression)) {
782-
var objectExpression = expression.getObjectExpression();
783-
var objectExpressionType = (objectExpression instanceof ClassExpression
784-
? objectExpression.getType() : wrapTypeIfNecessary(getType(objectExpression)));
785-
objectExpressionType = findCurrentInstanceOfClass(objectExpression, objectExpressionType);
786-
addStaticTypeError("No such attribute: " + expression.getPropertyAsString() + " for class: " + prettyPrintTypeName(objectExpressionType), expression);
784+
private void recordMissingProperty(final PropertyExpression expression) {
785+
var objectExpression = expression.getObjectExpression();
786+
var objectExpressionType = findCurrentInstanceOfClass(objectExpression, getType(objectExpression));
787+
788+
String pattern;
789+
if (!isClassClassNodeWrappingConcreteType(objectExpressionType)) {
790+
pattern = "No such {0,choice,1#attribute|2#property}: {1} for class: {2}";
791+
} else {
792+
objectExpressionType = objectExpressionType.getGenericsTypes()[0].getType();
793+
pattern = "No such {0,choice,1#attribute|2#property}: {1} for Class or static {0,choice,1#field|2#property} for class: {2}";
787794
}
795+
796+
String error = java.text.MessageFormat.format(pattern, expression instanceof AttributeExpression ? 1 : 2, expression.getPropertyAsString(), prettyPrintTypeName(wrapTypeIfNecessary(objectExpressionType)));
797+
ASTNode node = expression.getLineNumber() > 0 ? expression : expression.getProperty(); // GROOVY-11663
798+
addStaticTypeError(error, node);
788799
}
789800

790801
@Override

src/test/groovy/org/codehaus/groovy/transform/packageScope/DifferentPackageTest.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,6 @@ final class DifferentPackageTest {
447447
'''
448448
)
449449
}
450-
assert err =~ /No such property: answer for class: p.One/ // TODO: Cannot access p.One#getAnswer?
450+
assert err =~ /No such property: answer for Class or static property for class: p.One/ // TODO: Cannot access p.One#getAnswer?
451451
}
452452
}

src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3710,10 +3710,10 @@ final class TraitASTTransformationTest {
37103710
"""
37113711
}
37123712

3713-
// GROOVY-11641
3713+
// GROOVY-11641, GROOVY-11663
37143714
@CompileModesTest
37153715
void testTraitAccessToInheritedStaticMethods4(String mode) {
3716-
shouldFail shell, """
3716+
var err = shouldFail shell, """
37173717
$mode
37183718
trait Foo {
37193719
public static final String BANG = '!'
@@ -3739,6 +3739,11 @@ final class TraitASTTransformationTest {
37393739
Main.test1()
37403740
new Main().test2()
37413741
"""
3742+
if (mode.endsWith('Dynamic')) {
3743+
assert err =~ /MissingPropertyException/
3744+
} else {
3745+
assert err =~ /\[Static type checking\] - No such property: BANG for Class or static property for class: Bar/
3746+
}
37423747
}
37433748

37443749
// GROOVY-9386

0 commit comments

Comments
 (0)