Skip to content

Commit

Permalink
GROOVY-11195: STC: static context reference to Class instance method
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Oct 16, 2023
1 parent 8ad9575 commit 26af4c1
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3555,25 +3555,14 @@ public void visitMethodCallExpression(final MethodCallExpression call) {
if (!mn.isEmpty() && currentReceiver.getData() == null
&& (isThisExpression(objectExpression) || call.isImplicitThis())
&& (typeCheckingContext.isInStaticContext || Modifier.isStatic(receiverType.getModifiers()))) {
// we create separate method lists just to be able to print out
// a nice error message to the user
// a method is accessible if it is static, or if we are not in a static context and it is
// declared by the current receiver or a superclass
List<MethodNode> accessibleMethods = new LinkedList<>();
List<MethodNode> inaccessibleMethods = new LinkedList<>();
for (final MethodNode node : mn) {
if (node.isStatic()
|| (!typeCheckingContext.isInStaticContext && implementsInterfaceOrIsSubclassOf(receiverType, node.getDeclaringClass()))) {
accessibleMethods.add(node);
} else {
inaccessibleMethods.add(node);
}
}
mn = accessibleMethods;
if (accessibleMethods.isEmpty()) {
// choose an arbitrary method to display an error message
MethodNode inaccessibleMethod = inaccessibleMethods.get(0);
addStaticTypeError("Non-static method " + prettyPrintTypeName(inaccessibleMethod.getDeclaringClass()) + "#" + inaccessibleMethod.getName() + " cannot be called from static context", call);
MethodNode first = mn.get(0);
// a method is accessible if it is static, we are in static context and it is declared by Class
// or we are in a non-static context and it is declared by the current receiver or a superclass
mn.removeIf(node -> !(node.isStatic() || (typeCheckingContext.isInStaticContext
? node.getDeclaringClass().equals(CLASS_Type) // GROOVY-11195: Class method
: implementsInterfaceOrIsSubclassOf(receiverType, node.getDeclaringClass()))));
if (mn.isEmpty()) {
addStaticTypeError("Non-static method " + prettyPrintTypeName(first.getDeclaringClass()) + "#" + first.getName() + " cannot be called from static context", call);
}
}

Expand Down
34 changes: 22 additions & 12 deletions src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -945,7 +945,6 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
}

void testBoxingShouldCostMore() {
if (config.indyEnabled) return;
assertScript '''
int foo(int x) { 1 }
int foo(Integer x) { 2 }
Expand Down Expand Up @@ -1235,6 +1234,7 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
assert a( 'tim' ) { 0 } == 0
'''
}

// GROOVY-5743
void testClosureAsParameterWithDefaultValue() {
assertScript '''
Expand Down Expand Up @@ -1283,25 +1283,35 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {

void testShouldFindSetProperty() {
assertScript '''
class A {
int x
void foo() {
this.setProperty('x', 1)
class C {
int p
void m() {
this.setProperty('p', 1)
}
}
def a = new A()
a.foo()
assert a.x == 1
def c = new C()
c.m()
assert c.p == 1
'''
}

// GROOVY-5888
void testStaticContextScoping() {
void testStaticContext1() {
assertScript '''
class A {
static List foo = 'a,b,c'.split(/,/)*.trim()
class C {
static List p = 'a,b,c'.split(/,/)*.trim()
}
assert C.p == ['a','b','c']
'''
}

// GROOVY-11195
void testStaticContext2() {
assertScript '''
class C {
static String p = this.getName() // instance method of Class
}
assert A.foo == ['a','b','c']
assert C.p == 'C'
'''
}

Expand Down

0 comments on commit 26af4c1

Please sign in to comment.