You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by sh...@apache.org on 2016/05/01 22:35:40 UTC
groovy git commit: GROOVY-7813: Calling a non-static outer class
method from a static class should fail STC (Closes #310)
Repository: groovy
Updated Branches:
refs/heads/master 6968113f4 -> cf8d2338e
GROOVY-7813: Calling a non-static outer class method from a static class should fail STC (Closes #310)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/cf8d2338
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/cf8d2338
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/cf8d2338
Branch: refs/heads/master
Commit: cf8d2338eff4424cc1c0b0ef80d7648f79b57774
Parents: 6968113
Author: Shil Sinha <sh...@apache.org>
Authored: Sat Apr 9 15:54:08 2016 -0400
Committer: Shil Sinha <sh...@apache.org>
Committed: Sun May 1 16:05:14 2016 -0400
----------------------------------------------------------------------
.../stc/StaticTypeCheckingVisitor.java | 31 ++++++++-----
.../transform/stc/MethodCallsSTCTest.groovy | 46 ++++++++++++++++++++
2 files changed, 65 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/cf8d2338/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index ae86961..6d3afb7 100644
--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2897,27 +2897,34 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
List<MethodNode> mn = null;
Receiver<String> chosenReceiver = null;
for (Receiver<String> currentReceiver : receivers) {
- mn = findMethod(currentReceiver.getType(), name, args);
+ ClassNode receiverType = currentReceiver.getType();
+ mn = findMethod(receiverType, name, args);
// if the receiver is "this" or "implicit this", then we must make sure that the compatible
// methods are only static if we are in a static context
- if (!mn.isEmpty() && typeCheckingContext.isInStaticContext && (call.isImplicitThis()
- || (objectExpression instanceof VariableExpression && ((VariableExpression) objectExpression).isThisExpression()))) {
- // we create a separate method list just to be able to print out
+ // if we are not in a static context but the the current receiver is a static class, we must
+ // ensure that all methods are either static or declared by the current receiver or a superclass
+ if (!mn.isEmpty()
+ && (typeCheckingContext.isInStaticContext || (receiverType.getModifiers() & Opcodes.ACC_STATIC) != 0)
+ && (call.isImplicitThis() || (objectExpression instanceof VariableExpression && ((VariableExpression) objectExpression).isThisExpression()))) {
+ // we create separate method lists just to be able to print out
// a nice error message to the user
- List<MethodNode> staticMethods = new LinkedList<MethodNode>();
- List<MethodNode> nonStaticMethods = new LinkedList<MethodNode>();
+ // 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<MethodNode>();
+ List<MethodNode> inaccessibleMethods = new LinkedList<MethodNode>();
for (final MethodNode node : mn) {
- if (node.isStatic()) {
- staticMethods.add(node);
+ if (node.isStatic()
+ || (!typeCheckingContext.isInStaticContext && implementsInterfaceOrIsSubclassOf(receiverType, node.getDeclaringClass()))) {
+ accessibleMethods.add(node);
} else {
- nonStaticMethods.add(node);
+ inaccessibleMethods.add(node);
}
}
- mn = staticMethods;
- if (staticMethods.isEmpty()) {
+ mn = accessibleMethods;
+ if (accessibleMethods.isEmpty()) {
// choose an arbitrary method to display an error message
- MethodNode node = nonStaticMethods.get(0);
+ MethodNode node = inaccessibleMethods.get(0);
ClassNode owner = node.getDeclaringClass();
addStaticTypeError("Non static method " + owner.getName() + "#" + node.getName() + " cannot be called from static context", call);
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/cf8d2338/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
index b62909b..aa37ecf 100644
--- a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
@@ -1040,6 +1040,52 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ //GROOVY-7813
+ void testNonStaticOuterMethodCannotBeCalledFromStaticClass() {
+ shouldFailWithMessages '''
+ class Foo {
+ def bar() { 2 }
+
+ static class Baz {
+ def doBar() { bar() }
+ }
+ }
+ null
+ ''', 'Non static method Foo#bar cannot be called from static context'
+ }
+
+ void testStaticOuterMethodCanBeCalledFromStaticClass() {
+ assertScript '''
+ class Foo {
+ static def bar() { 2 }
+
+ static class Baz {
+ def doBar() {
+ bar()
+ }
+ }
+ }
+ assert new Foo.Baz().doBar() == 2
+ '''
+ }
+
+ void testInheritedMethodCanBeCalledFromStaticClass() {
+ assertScript '''
+ class Bar {
+ def bar() { 1 }
+ }
+
+ class Foo {
+ static class Baz extends Bar {
+ def doBar() {
+ bar()
+ }
+ }
+ }
+ assert new Foo.Baz().doBar() == 1
+ '''
+ }
+
static class MyMethodCallTestClass {
static int mul(int... args) { args.toList().inject(1) { x,y -> x*y } }