Skip to content

Commit 1f25ee5

Browse files
committed
GROOVY-6610
1 parent 91c08da commit 1f25ee5

File tree

7 files changed

+318
-5
lines changed

7 files changed

+318
-5
lines changed

base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java

+25
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,31 @@ public void testCompileStatic6276() {
763763
runConformTest(sources, "");
764764
}
765765

766+
@Test
767+
public void testCompileStatic6610() {
768+
//@formatter:off
769+
String[] sources = {
770+
"Main.groovy",
771+
"@groovy.transform.CompileStatic\n" +
772+
"class Outer {\n" +
773+
" private static Integer VALUE = 42\n" +
774+
" static class Inner {\n" +
775+
" public final String value\n" +
776+
" Inner(String string) {\n" +
777+
" value = string\n" +
778+
" }\n" +
779+
" Inner() {\n" +
780+
" this(VALUE.toString())\n" +
781+
" }\n" +
782+
" }\n" +
783+
"}\n" +
784+
"print new Outer.Inner().value\n",
785+
};
786+
//@formatter:on
787+
788+
runConformTest(sources, "42");
789+
}
790+
766791
@Test
767792
public void testCompileStatic6904() {
768793
//@formatter:off

base/org.codehaus.groovy25/.checkstyle

+1-3
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,8 @@
7878
<file-match-pattern match-pattern="groovy/transform/LogASTTransformation.java" include-pattern="false" />
7979
<file-match-pattern match-pattern="groovy/transform/NewifyASTTransformation.java" include-pattern="false" />
8080
<file-match-pattern match-pattern="groovy/transform/sc/StaticCompilationVisitor.java" include-pattern="false" />
81-
<file-match-pattern match-pattern="groovy/transform/sc/transformers/BinaryExpressionTransformer.java" include-pattern="false" />
81+
<file-match-pattern match-pattern="groovy/transform/sc/transformers/(Binary|ConstructorCall|MethodCall|Variable)ExpressionTransformer.java" include-pattern="false" />
8282
<file-match-pattern match-pattern="groovy/transform/sc/transformers/CompareToNullExpression.java" include-pattern="false" />
83-
<file-match-pattern match-pattern="groovy/transform/sc/transformers/ConstructorCallTransformer.java" include-pattern="false" />
84-
<file-match-pattern match-pattern="groovy/transform/sc/transformers/MethodCallExpressionTransformer.java" include-pattern="false" />
8583
<file-match-pattern match-pattern="groovy/transform/stc/StaticTypeCheckingSupport.java" include-pattern="false" />
8684
<file-match-pattern match-pattern="groovy/transform/stc/StaticTypeCheckingVisitor.java" include-pattern="false" />
8785
<file-match-pattern match-pattern="groovy/transform/trait/SuperCallTraitTransformer.java" include-pattern="false" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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.ClassNode;
22+
import org.codehaus.groovy.ast.FieldNode;
23+
import org.codehaus.groovy.ast.expr.Expression;
24+
import org.codehaus.groovy.ast.expr.PropertyExpression;
25+
import org.codehaus.groovy.ast.expr.VariableExpression;
26+
import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
27+
import org.codehaus.groovy.transform.stc.StaticTypesMarker;
28+
29+
import static org.codehaus.groovy.ast.tools.GeneralUtils.*;
30+
31+
/**
32+
* Transformer for VariableExpression the bytecode backend wouldn't be able to
33+
* handle otherwise.
34+
*/
35+
public class VariableExpressionTransformer {
36+
37+
public Expression transformVariableExpression(VariableExpression expr) {
38+
Expression trn = tryTransformDelegateToProperty(expr);
39+
if (trn != null) {
40+
return trn;
41+
}
42+
trn = tryTransformPrivateFieldAccess(expr);
43+
if (trn != null) {
44+
return trn;
45+
}
46+
return expr;
47+
}
48+
49+
private static Expression tryTransformDelegateToProperty(VariableExpression expr) {
50+
// we need to transform variable expressions that go to a delegate
51+
// to a property expression, as ACG would lose the information in
52+
// processClassVariable before it reaches any makeCall, that could handle it
53+
Object val = expr.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
54+
if (val == null || val.equals(expr.getName())) return null;
55+
56+
// TODO handle the owner and delegate cases better for nested scenarios and potentially remove the need for the implicit this case
57+
VariableExpression receiver = new VariableExpression("owner".equals(val) ? (String) val : "delegate".equals(val) ? (String) val : "this");
58+
// GROOVY-9136 -- object expression should not overlap source range of property; property stands in for original variable expression
59+
receiver.setLineNumber(expr.getLineNumber());
60+
receiver.setColumnNumber(expr.getColumnNumber());
61+
62+
PropertyExpression pexp = new PropertyExpression(receiver, expr.getName());
63+
pexp.getProperty().setSourcePosition(expr);
64+
pexp.copyNodeMetaData(expr);
65+
pexp.setImplicitThis(true);
66+
67+
ClassNode owner = expr.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
68+
if (owner != null) {
69+
receiver.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, owner);
70+
receiver.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, val);
71+
}
72+
pexp.removeNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
73+
74+
return pexp;
75+
}
76+
77+
private static Expression tryTransformPrivateFieldAccess(VariableExpression expr) {
78+
FieldNode field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
79+
if (field == null) {
80+
field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION);
81+
}
82+
if (field != null) {
83+
// access to a private field from a section of code that normally doesn't have access to it, like a
84+
// closure or an inner class
85+
/* GRECLIPSE edit -- GROOVY-6610
86+
VariableExpression receiver = new VariableExpression("this");
87+
PropertyExpression pexp = new PropertyExpression(
88+
receiver,
89+
expr.getName()
90+
);
91+
pexp.setImplicitThis(true);
92+
pexp.getProperty().setSourcePosition(expr);
93+
*/
94+
PropertyExpression pexp = !field.isStatic() ? thisPropX(true, expr.getName())
95+
: (PropertyExpression) propX(classX(field.getDeclaringClass()), expr.getName());
96+
pexp.getProperty().setSourcePosition(expr);
97+
// GRECLIPSE end
98+
// put the receiver inferred type so that the class writer knows that it will have to call a bridge method
99+
pexp.getObjectExpression().putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getDeclaringClass());
100+
// add inferred type information
101+
pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getOriginType());
102+
return pexp;
103+
}
104+
return null;
105+
}
106+
}

base/org.codehaus.groovy30/.checkstyle

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
<file-match-pattern match-pattern="groovy/transform/LogASTTransformation.java" include-pattern="false" />
7373
<file-match-pattern match-pattern="groovy/transform/sc/StaticCompilationVisitor.java" include-pattern="false" />
7474
<file-match-pattern match-pattern="groovy/transform/sc/StaticCompileTransformation.java" include-pattern="false" />
75-
<file-match-pattern match-pattern="groovy/transform/sc/transformers/(Binary|MethodCall)ExpressionTransformer.java" include-pattern="false" />
75+
<file-match-pattern match-pattern="groovy/transform/sc/transformers/(Binary|MethodCall|Variable)ExpressionTransformer.java" include-pattern="false" />
7676
<file-match-pattern match-pattern="groovy/transform/sc/transformers/CompareToNullExpression.java" include-pattern="false" />
7777
<file-match-pattern match-pattern="groovy/transform/stc/AbstractExtensionMethodCache.java" include-pattern="false" />
7878
<file-match-pattern match-pattern="groovy/transform/stc/StaticTypeCheckingSupport.java" include-pattern="false" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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.ClassNode;
22+
import org.codehaus.groovy.ast.FieldNode;
23+
import org.codehaus.groovy.ast.expr.Expression;
24+
import org.codehaus.groovy.ast.expr.PropertyExpression;
25+
import org.codehaus.groovy.ast.expr.VariableExpression;
26+
import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
27+
import org.codehaus.groovy.transform.stc.StaticTypesMarker;
28+
29+
import static org.codehaus.groovy.ast.tools.GeneralUtils.*;
30+
31+
/**
32+
* Transformer for VariableExpression the bytecode backend wouldn't be able to
33+
* handle otherwise.
34+
*/
35+
public class VariableExpressionTransformer {
36+
37+
public Expression transformVariableExpression(final VariableExpression expr) {
38+
Expression trn = tryTransformDelegateToProperty(expr);
39+
if (trn == null) {
40+
trn = tryTransformPrivateFieldAccess(expr);
41+
}
42+
return trn != null ? trn : expr;
43+
}
44+
45+
private static Expression tryTransformDelegateToProperty(final VariableExpression expr) {
46+
// we need to transform variable expressions that go to a delegate
47+
// to a property expression, as ACG would lose the information in
48+
// processClassVariable before it reaches any makeCall, that could handle it
49+
Object val = expr.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
50+
if (val == null || val.equals(expr.getName())) return null;
51+
52+
// TODO: handle the owner and delegate cases better for nested scenarios and potentially remove the need for the implicit this case
53+
Expression receiver = varX("owner".equals(val) ? (String) val : "delegate".equals(val) ? (String) val : "this");
54+
// GROOVY-9136 -- object expression should not overlap source range of property; property stands in for original variable expression
55+
receiver.setLineNumber(expr.getLineNumber());
56+
receiver.setColumnNumber(expr.getColumnNumber());
57+
58+
PropertyExpression pexp = propX(receiver, expr.getName());
59+
pexp.getProperty().setSourcePosition(expr);
60+
pexp.copyNodeMetaData(expr);
61+
pexp.setImplicitThis(true);
62+
63+
ClassNode owner = expr.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
64+
if (owner != null) {
65+
receiver.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, owner);
66+
receiver.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, val);
67+
}
68+
pexp.removeNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
69+
70+
return pexp;
71+
}
72+
73+
private static Expression tryTransformPrivateFieldAccess(final VariableExpression expr) {
74+
FieldNode field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
75+
if (field == null) {
76+
field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION);
77+
}
78+
if (field != null) {
79+
// access to a private field from a section of code that normally doesn't have access to it, like a closure or an inner class
80+
PropertyExpression pexp = thisPropX(true, expr.getName());
81+
// GRECLIPSE add -- GROOVY-6610
82+
if (field.isStatic()) pexp = propX(classX(field.getDeclaringClass()), expr.getName());
83+
// GRECLIPSE end
84+
// store the declaring class so that the class writer knows that it will have to call a bridge method
85+
pexp.getObjectExpression().putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getDeclaringClass());
86+
pexp.putNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE, field.getOriginType());
87+
pexp.getProperty().setSourcePosition(expr);
88+
return pexp;
89+
}
90+
return null;
91+
}
92+
}

base/org.codehaus.groovy40/.checkstyle

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
<file-match-pattern match-pattern="groovy/transform/NotYetImplemented.java" include-pattern="false" />
7171
<file-match-pattern match-pattern="groovy/transform/sc/StaticCompilationVisitor.java" include-pattern="false" />
7272
<file-match-pattern match-pattern="groovy/transform/sc/StaticCompileTransformation.java" include-pattern="false" />
73-
<file-match-pattern match-pattern="groovy/transform/sc/transformers/(Binary|MethodCall)ExpressionTransformer.java" include-pattern="false" />
73+
<file-match-pattern match-pattern="groovy/transform/sc/transformers/(Binary|MethodCall|Variable)ExpressionTransformer.java" include-pattern="false" />
7474
<file-match-pattern match-pattern="groovy/transform/sc/transformers/CompareToNullExpression.java" include-pattern="false" />
7575
<file-match-pattern match-pattern="groovy/transform/stc/StaticTypeCheckingSupport.java" include-pattern="false" />
7676
<file-match-pattern match-pattern="groovy/transform/stc/StaticTypeCheckingVisitor.java" include-pattern="false" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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.ClassNode;
22+
import org.codehaus.groovy.ast.FieldNode;
23+
import org.codehaus.groovy.ast.expr.Expression;
24+
import org.codehaus.groovy.ast.expr.PropertyExpression;
25+
import org.codehaus.groovy.ast.expr.VariableExpression;
26+
import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
27+
import org.codehaus.groovy.transform.stc.StaticTypesMarker;
28+
29+
import static org.codehaus.groovy.ast.tools.GeneralUtils.*;
30+
31+
/**
32+
* Transformer for VariableExpression the bytecode backend wouldn't be able to
33+
* handle otherwise.
34+
*/
35+
public class VariableExpressionTransformer {
36+
37+
public Expression transformVariableExpression(final VariableExpression expr) {
38+
Expression trn = tryTransformDelegateToProperty(expr);
39+
if (trn == null) {
40+
trn = tryTransformPrivateFieldAccess(expr);
41+
}
42+
return trn != null ? trn : expr;
43+
}
44+
45+
private static Expression tryTransformDelegateToProperty(final VariableExpression expr) {
46+
// we need to transform variable expressions that go to a delegate
47+
// to a property expression, as ACG would lose the information in
48+
// processClassVariable before it reaches any makeCall, that could handle it
49+
Object val = expr.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
50+
if (val == null || val.equals(expr.getName())) return null;
51+
52+
// TODO: handle the owner and delegate cases better for nested scenarios and potentially remove the need for the implicit this case
53+
Expression receiver = varX("owner".equals(val) ? (String) val : "delegate".equals(val) ? (String) val : "this");
54+
// GROOVY-9136 -- object expression should not overlap source range of property; property stands in for original variable expression
55+
receiver.setLineNumber(expr.getLineNumber());
56+
receiver.setColumnNumber(expr.getColumnNumber());
57+
58+
PropertyExpression pexp = propX(receiver, expr.getName());
59+
pexp.getProperty().setSourcePosition(expr);
60+
pexp.copyNodeMetaData(expr);
61+
pexp.setImplicitThis(true);
62+
63+
ClassNode owner = expr.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
64+
if (owner != null) {
65+
receiver.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, owner);
66+
receiver.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, val);
67+
}
68+
pexp.removeNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
69+
70+
return pexp;
71+
}
72+
73+
private static Expression tryTransformPrivateFieldAccess(final VariableExpression expr) {
74+
FieldNode field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
75+
if (field == null) {
76+
field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION);
77+
}
78+
if (field != null) {
79+
// access to a private field from a section of code that normally doesn't have access to it, like a closure or an inner class
80+
PropertyExpression pexp = thisPropX(true, expr.getName());
81+
// GRECLIPSE add -- GROOVY-6610
82+
if (field.isStatic()) pexp = propX(classX(field.getDeclaringClass()), expr.getName());
83+
// GRECLIPSE end
84+
// store the declaring class so that the class writer knows that it will have to call a bridge method
85+
pexp.getObjectExpression().putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getDeclaringClass());
86+
pexp.putNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE, field.getOriginType());
87+
pexp.getProperty().setSourcePosition(expr);
88+
return pexp;
89+
}
90+
return null;
91+
}
92+
}

0 commit comments

Comments
 (0)