Skip to content

Commit 0fcd983

Browse files
committed
GROOVY-1736, GROOVY-6097, GROOVY-7300, GROOVY-7924
1 parent 35c908e commit 0fcd983

File tree

10 files changed

+670
-8
lines changed

10 files changed

+670
-8
lines changed

base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/basic/GroovySimpleTests.java

+70
Original file line numberDiff line numberDiff line change
@@ -5226,6 +5226,31 @@ public void testGroovyBug2() {
52265226
runConformTest(sources, "a");
52275227
}
52285228

5229+
@Test // https://issues.apache.org/jira/browse/GROOVY-1736
5230+
public void testGroovy1736() {
5231+
for (String vis : new String[] {"", "public", "protected", "@groovy.transform.PackageScope"}) {
5232+
//@formatter:off
5233+
String[] sources = {
5234+
"Script.groovy",
5235+
"abstract class A {\n" +
5236+
vis + " def getX() { 'A' }\n" +
5237+
"}\n" +
5238+
"class C extends A {\n" +
5239+
" def getX() { super.x + 'C' }\n" + // no stack overflow
5240+
" void m() {\n" +
5241+
" print x\n" +
5242+
" print this.x\n" +
5243+
" print super.x\n" + // TODO: test safe and spread
5244+
" }\n" +
5245+
"}\n" +
5246+
"new C().m()\n",
5247+
};
5248+
//@formatter:on
5249+
5250+
runConformTest(sources, "ACACA");
5251+
}
5252+
}
5253+
52295254
@Test // https://issues.apache.org/jira/browse/GROOVY-3311
52305255
public void testGroovy3311() {
52315256
//@formatter:off
@@ -5274,6 +5299,51 @@ public void testGroovy6045() {
52745299
runConformTest(sources, "");
52755300
}
52765301

5302+
@Test // https://issues.apache.org/jira/browse/GROOVY-6097
5303+
public void testGroovy6097() {
5304+
for (String vis : new String[] {"", "public", "protected", "@groovy.transform.PackageScope"}) {
5305+
//@formatter:off
5306+
String[] sources = {
5307+
"Script.groovy",
5308+
"abstract class A {\n" +
5309+
vis + " boolean isX() { true }\n" +
5310+
vis + " boolean getX() { false }\n" +
5311+
"}\n" +
5312+
"class C extends A {\n" +
5313+
" void m() {\n" +
5314+
" print x\n" +
5315+
" print this.x\n" +
5316+
" print super.x\n" + // hardwired to "super.getX()"
5317+
" }\n" +
5318+
"}\n" +
5319+
"new C().m()\n",
5320+
};
5321+
//@formatter:on
5322+
5323+
runConformTest(sources, "truetruefalse");
5324+
}
5325+
}
5326+
5327+
@Test // https://issues.apache.org/jira/browse/GROOVY-7924
5328+
public void testGroovy7924() {
5329+
//@formatter:off
5330+
String[] sources = {
5331+
"Script.groovy",
5332+
"abstract class A {\n" +
5333+
" def getFoo() { 'works' }\n" +
5334+
"}\n" +
5335+
"class C extends A {\n" +
5336+
" void m(String name) {\n" +
5337+
" print super.\"$name\"\n" +
5338+
" }\n" +
5339+
"}\n" +
5340+
"new C().m('foo')\n",
5341+
};
5342+
//@formatter:on
5343+
5344+
runConformTest(sources, "works");
5345+
}
5346+
52775347
@Test // https://issues.apache.org/jira/browse/GROOVY-8311
52785348
public void testGroovy8311() {
52795349
//@formatter:off

base/org.codehaus.groovy25/.checkstyle

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
<file-match-pattern match-pattern="groovy/transform/sc/transformers/(Binary|MethodCall)ExpressionTransformer.java" include-pattern="false" />
8484
<file-match-pattern match-pattern="groovy/transform/sc/transformers/ConstructorCallTransformer.java" include-pattern="false" />
8585
<file-match-pattern match-pattern="groovy/transform/sc/transformers/CompareToNullExpression.java" include-pattern="false" />
86+
<file-match-pattern match-pattern="groovy/transform/sc/transformers/StaticCompilationTransformer.java" include-pattern="false" />
8687
<file-match-pattern match-pattern="groovy/transform/stc/StaticTypeCheckingSupport.java" include-pattern="false" />
8788
<file-match-pattern match-pattern="groovy/transform/stc/StaticTypeCheckingVisitor.java" include-pattern="false" />
8889
<file-match-pattern match-pattern="groovy/transform/trait/SuperCallTraitTransformer.java" include-pattern="false" />

base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,22 @@ protected boolean makeDirectCall(final Expression origin, final Expression recei
119119
if (origin instanceof MethodCallExpression &&
120120
receiver instanceof VariableExpression &&
121121
((VariableExpression) receiver).isSuperExpression()) {
122+
/* GRECLIPSE edit -- GROOVY-6097, GROOVY-7300, et al.
122123
ClassNode superClass = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
123124
if (superClass!=null && !controller.getCompileStack().isLHS()) {
124-
// GROOVY-7300
125125
MethodCallExpression mce = (MethodCallExpression) origin;
126126
MethodNode node = superClass.getDeclaredMethod(mce.getMethodAsString(), Parameter.EMPTY_ARRAY);
127127
mce.setMethodTarget(node);
128128
}
129+
*/
130+
MethodCallExpression mce = (MethodCallExpression) origin;
131+
if (mce.getMethodTarget() == null && !controller.getCompileStack().isLHS()) {
132+
ClassNode owner = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
133+
if (owner != null) {
134+
mce.setMethodTarget(owner.getDeclaredMethod(mce.getMethodAsString(), Parameter.EMPTY_ARRAY));
135+
}
136+
}
137+
// GRECLIPSE end
129138
}
130139
return super.makeDirectCall(origin, receiver, message, arguments, adapter, implicitThis, containsSpreadExpression);
131140
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.codehaus.groovy.transform.sc.transformers;
20+
21+
import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
22+
import org.codehaus.groovy.ast.ClassHelper;
23+
import org.codehaus.groovy.ast.ClassNode;
24+
import org.codehaus.groovy.ast.InnerClassNode;
25+
import org.codehaus.groovy.ast.MethodNode;
26+
import org.codehaus.groovy.ast.expr.BinaryExpression;
27+
import org.codehaus.groovy.ast.expr.BooleanExpression;
28+
import org.codehaus.groovy.ast.expr.CastExpression;
29+
import org.codehaus.groovy.ast.expr.ClosureExpression;
30+
import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
31+
import org.codehaus.groovy.ast.expr.Expression;
32+
import org.codehaus.groovy.ast.expr.ListExpression;
33+
import org.codehaus.groovy.ast.expr.MethodCallExpression;
34+
import org.codehaus.groovy.ast.expr.PropertyExpression;
35+
import org.codehaus.groovy.ast.expr.RangeExpression;
36+
import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
37+
import org.codehaus.groovy.ast.expr.VariableExpression;
38+
import org.codehaus.groovy.ast.stmt.Statement;
39+
import org.codehaus.groovy.classgen.asm.sc.StaticTypesTypeChooser;
40+
import org.codehaus.groovy.control.SourceUnit;
41+
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
42+
import org.codehaus.groovy.syntax.Types;
43+
import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor;
44+
45+
import java.util.Collections;
46+
import java.util.HashMap;
47+
import java.util.Iterator;
48+
import java.util.Map;
49+
50+
/**
51+
* Some expressions use symbols as aliases to method calls (&lt;&lt;, +=, ...). In static compilation,
52+
* if such a method call is found, we transform the original binary expression into a method
53+
* call expression so that the call gets statically compiled.
54+
*/
55+
public class StaticCompilationTransformer extends ClassCodeExpressionTransformer {
56+
57+
protected static final ClassNode BYTECODE_ADAPTER_CLASS = ClassHelper.make(ScriptBytecodeAdapter.class);
58+
protected static final Map<Integer, MethodNode> BYTECODE_BINARY_ADAPTERS = Collections.unmodifiableMap(new HashMap<Integer, MethodNode>() {
59+
private static final long serialVersionUID = -9117028399464862605L;
60+
61+
{
62+
put(Types.COMPARE_EQUAL, BYTECODE_ADAPTER_CLASS.getMethods("compareEqual").get(0));
63+
put(Types.COMPARE_GREATER_THAN, BYTECODE_ADAPTER_CLASS.getMethods("compareGreaterThan").get(0));
64+
put(Types.COMPARE_GREATER_THAN_EQUAL, BYTECODE_ADAPTER_CLASS.getMethods("compareGreaterThanEqual").get(0));
65+
put(Types.COMPARE_LESS_THAN, BYTECODE_ADAPTER_CLASS.getMethods("compareLessThan").get(0));
66+
put(Types.COMPARE_LESS_THAN_EQUAL, BYTECODE_ADAPTER_CLASS.getMethods("compareLessThanEqual").get(0));
67+
put(Types.COMPARE_NOT_EQUAL, BYTECODE_ADAPTER_CLASS.getMethods("compareNotEqual").get(0));
68+
put(Types.COMPARE_TO, BYTECODE_ADAPTER_CLASS.getMethods("compareTo").get(0));
69+
70+
}});
71+
72+
73+
private ClassNode classNode;
74+
private final SourceUnit unit;
75+
76+
private final StaticTypesTypeChooser typeChooser = new StaticTypesTypeChooser();
77+
private final StaticTypeCheckingVisitor staticCompilationVisitor;
78+
79+
// various helpers in order to avoid a potential very big class
80+
private final StaticMethodCallExpressionTransformer staticMethodCallExpressionTransformer = new StaticMethodCallExpressionTransformer(this);
81+
private final ConstructorCallTransformer constructorCallTransformer = new ConstructorCallTransformer(this);
82+
private final MethodCallExpressionTransformer methodCallExpressionTransformer = new MethodCallExpressionTransformer(this);
83+
private final BinaryExpressionTransformer binaryExpressionTransformer = new BinaryExpressionTransformer(this);
84+
private final ClosureExpressionTransformer closureExpressionTransformer = new ClosureExpressionTransformer(this);
85+
private final BooleanExpressionTransformer booleanExpressionTransformer = new BooleanExpressionTransformer(this);
86+
private final VariableExpressionTransformer variableExpressionTransformer = new VariableExpressionTransformer();
87+
private final RangeExpressionTransformer rangeExpressionTransformer = new RangeExpressionTransformer(this);
88+
private final ListExpressionTransformer listExpressionTransformer = new ListExpressionTransformer(this);
89+
private final CastExpressionOptimizer castExpressionTransformer = new CastExpressionOptimizer(this);
90+
91+
public StaticCompilationTransformer(final SourceUnit unit, final StaticTypeCheckingVisitor visitor) {
92+
this.unit = unit;
93+
this.staticCompilationVisitor = visitor;
94+
}
95+
96+
@Override
97+
protected SourceUnit getSourceUnit() {
98+
return unit;
99+
}
100+
101+
public StaticTypesTypeChooser getTypeChooser() {
102+
return typeChooser;
103+
}
104+
105+
public ClassNode getClassNode() {
106+
return classNode;
107+
}
108+
109+
@Override
110+
public void visitClassCodeContainer(final Statement code) {
111+
super.visitClassCodeContainer(code);
112+
}
113+
114+
@Override
115+
public Expression transform(Expression expr) {
116+
// GRECLIPSE add -- GROOVY-6097, GROOVY-7300, et al.
117+
if (expr instanceof PropertyExpression) {
118+
MethodNode dmct = expr.getNodeMetaData(org.codehaus.groovy.transform.stc.StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
119+
// NOTE: BinaryExpressionTransformer handles the setter
120+
if (dmct != null && dmct.getParameters().length == 0) {
121+
PropertyExpression pe = (PropertyExpression) expr;
122+
123+
MethodCallExpression mce = new MethodCallExpression(transform(pe.getObjectExpression()), dmct.getName(), MethodCallExpression.NO_ARGUMENTS);
124+
mce.setImplicitThis(pe.isImplicitThis());
125+
mce.setSpreadSafe(pe.isSpreadSafe());
126+
mce.setMethodTarget(dmct);
127+
mce.setSourcePosition(pe);
128+
mce.copyNodeMetaData(pe);
129+
mce.setSafe(pe.isSafe());
130+
return mce;
131+
}
132+
return super.transform(expr);
133+
}
134+
// GRECLIPSE end
135+
if (expr instanceof StaticMethodCallExpression) {
136+
return staticMethodCallExpressionTransformer.transformStaticMethodCallExpression((StaticMethodCallExpression) expr);
137+
}
138+
if (expr instanceof BinaryExpression) {
139+
return binaryExpressionTransformer.transformBinaryExpression((BinaryExpression)expr);
140+
}
141+
if (expr instanceof MethodCallExpression) {
142+
return methodCallExpressionTransformer.transformMethodCallExpression((MethodCallExpression) expr);
143+
}
144+
if (expr instanceof ClosureExpression) {
145+
return closureExpressionTransformer.transformClosureExpression((ClosureExpression) expr);
146+
}
147+
if (expr instanceof ConstructorCallExpression) {
148+
return constructorCallTransformer.transformConstructorCall((ConstructorCallExpression) expr);
149+
}
150+
if (expr instanceof BooleanExpression) {
151+
return booleanExpressionTransformer.transformBooleanExpression((BooleanExpression)expr);
152+
}
153+
if (expr instanceof VariableExpression) {
154+
return variableExpressionTransformer.transformVariableExpression((VariableExpression)expr);
155+
}
156+
if (expr instanceof RangeExpression) {
157+
return rangeExpressionTransformer.transformRangeExpression(((RangeExpression)expr));
158+
}
159+
if (expr instanceof ListExpression) {
160+
return listExpressionTransformer.transformListExpression((ListExpression) expr);
161+
}
162+
if (expr instanceof CastExpression) {
163+
return castExpressionTransformer.transformCastExpression(((CastExpression)expr));
164+
}
165+
return super.transform(expr);
166+
}
167+
168+
/**
169+
* Called by helpers when super.transform() is needed.
170+
*/
171+
final Expression superTransform(Expression expr) {
172+
return super.transform(expr);
173+
}
174+
175+
@Override
176+
public void visitClass(final ClassNode node) {
177+
ClassNode prec = classNode;
178+
classNode = node;
179+
super.visitClass(node);
180+
Iterator<InnerClassNode> innerClasses = classNode.getInnerClasses();
181+
while (innerClasses.hasNext()) {
182+
InnerClassNode innerClassNode = innerClasses.next();
183+
visitClass(innerClassNode);
184+
}
185+
classNode = prec;
186+
}
187+
188+
@Override
189+
protected void visitConstructorOrMethod(final MethodNode node, final boolean isConstructor) {
190+
if (staticCompilationVisitor.isSkipMode(node)) {
191+
// method has already been visited by a static type checking visitor
192+
return;
193+
}
194+
super.visitConstructorOrMethod(node, isConstructor);
195+
}
196+
}

base/org.codehaus.groovy30/.checkstyle

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
<file-match-pattern match-pattern="groovy/transform/sc/TemporaryVariableExpression.java" include-pattern="false" />
7171
<file-match-pattern match-pattern="groovy/transform/sc/transformers/(Binary|MethodCall)ExpressionTransformer.java" include-pattern="false" />
7272
<file-match-pattern match-pattern="groovy/transform/sc/transformers/CompareIdentityExpression.java" include-pattern="false" />
73+
<file-match-pattern match-pattern="groovy/transform/sc/transformers/StaticCompilationTransformer.java" include-pattern="false" />
7374
<file-match-pattern match-pattern="groovy/transform/stc/AbstractExtensionMethodCache.java" include-pattern="false" />
7475
<file-match-pattern match-pattern="groovy/transform/stc/StaticTypeCheckingSupport.java" include-pattern="false" />
7576
<file-match-pattern match-pattern="groovy/transform/stc/StaticTypeCheckingVisitor.java" include-pattern="false" />

base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,22 @@ public StaticInvocationWriter(final WriterController wc) {
122122
@Override
123123
protected boolean makeDirectCall(final Expression origin, final Expression receiver, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean implicitThis, final boolean containsSpreadExpression) {
124124
if (origin instanceof MethodCallExpression && isSuperExpression(receiver)) {
125+
/* GRECLIPSE edit -- GROOVY-6097, GROOVY-7300, et al.
125126
ClassNode superClass = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
126127
if (superClass != null && !controller.getCompileStack().isLHS()) {
127-
// GROOVY-7300
128128
MethodCallExpression mce = (MethodCallExpression) origin;
129129
MethodNode node = superClass.getDeclaredMethod(mce.getMethodAsString(), Parameter.EMPTY_ARRAY);
130130
mce.setMethodTarget(node);
131131
}
132+
*/
133+
MethodCallExpression mce = (MethodCallExpression) origin;
134+
if (mce.getMethodTarget() == null && !controller.getCompileStack().isLHS()) {
135+
ClassNode owner = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
136+
if (owner != null) {
137+
mce.setMethodTarget(owner.getDeclaredMethod(mce.getMethodAsString(), Parameter.EMPTY_ARRAY));
138+
}
139+
}
140+
// GRECLIPSE end
132141
}
133142
return super.makeDirectCall(origin, receiver, message, arguments, adapter, implicitThis, containsSpreadExpression);
134143
}

0 commit comments

Comments
 (0)