diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java
index 91b0a5303e..25e76192fc 100644
--- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java
+++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java
@@ -763,6 +763,31 @@ public void testCompileStatic6276() {
runConformTest(sources, "");
}
+ @Test
+ public void testCompileStatic6610() {
+ //@formatter:off
+ String[] sources = {
+ "Main.groovy",
+ "@groovy.transform.CompileStatic\n" +
+ "class Outer {\n" +
+ " private static Integer VALUE = 42\n" +
+ " static class Inner {\n" +
+ " public final String value\n" +
+ " Inner(String string) {\n" +
+ " value = string\n" +
+ " }\n" +
+ " Inner() {\n" +
+ " this(VALUE.toString())\n" +
+ " }\n" +
+ " }\n" +
+ "}\n" +
+ "print new Outer.Inner().value\n",
+ };
+ //@formatter:on
+
+ runConformTest(sources, "42");
+ }
+
@Test
public void testCompileStatic6904() {
//@formatter:off
diff --git a/base/org.codehaus.groovy25/.checkstyle b/base/org.codehaus.groovy25/.checkstyle
index 2a14e9b9d9..fd01c99290 100644
--- a/base/org.codehaus.groovy25/.checkstyle
+++ b/base/org.codehaus.groovy25/.checkstyle
@@ -78,10 +78,8 @@
-
+
-
-
diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
new file mode 100644
index 0000000000..2f445df4cb
--- /dev/null
+++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.transform.sc.transformers;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
+import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.*;
+
+/**
+ * Transformer for VariableExpression the bytecode backend wouldn't be able to
+ * handle otherwise.
+ */
+public class VariableExpressionTransformer {
+
+ public Expression transformVariableExpression(VariableExpression expr) {
+ Expression trn = tryTransformDelegateToProperty(expr);
+ if (trn != null) {
+ return trn;
+ }
+ trn = tryTransformPrivateFieldAccess(expr);
+ if (trn != null) {
+ return trn;
+ }
+ return expr;
+ }
+
+ private static Expression tryTransformDelegateToProperty(VariableExpression expr) {
+ // we need to transform variable expressions that go to a delegate
+ // to a property expression, as ACG would lose the information in
+ // processClassVariable before it reaches any makeCall, that could handle it
+ Object val = expr.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
+ if (val == null || val.equals(expr.getName())) return null;
+
+ // TODO handle the owner and delegate cases better for nested scenarios and potentially remove the need for the implicit this case
+ VariableExpression receiver = new VariableExpression("owner".equals(val) ? (String) val : "delegate".equals(val) ? (String) val : "this");
+ // GROOVY-9136 -- object expression should not overlap source range of property; property stands in for original variable expression
+ receiver.setLineNumber(expr.getLineNumber());
+ receiver.setColumnNumber(expr.getColumnNumber());
+
+ PropertyExpression pexp = new PropertyExpression(receiver, expr.getName());
+ pexp.getProperty().setSourcePosition(expr);
+ pexp.copyNodeMetaData(expr);
+ pexp.setImplicitThis(true);
+
+ ClassNode owner = expr.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
+ if (owner != null) {
+ receiver.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, owner);
+ receiver.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, val);
+ }
+ pexp.removeNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
+
+ return pexp;
+ }
+
+ private static Expression tryTransformPrivateFieldAccess(VariableExpression expr) {
+ FieldNode field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
+ if (field == null) {
+ field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION);
+ }
+ if (field != null) {
+ // 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
+ /* GRECLIPSE edit -- GROOVY-6610
+ VariableExpression receiver = new VariableExpression("this");
+ PropertyExpression pexp = new PropertyExpression(
+ receiver,
+ expr.getName()
+ );
+ pexp.setImplicitThis(true);
+ pexp.getProperty().setSourcePosition(expr);
+ */
+ PropertyExpression pexp = !field.isStatic() ? thisPropX(true, expr.getName())
+ : (PropertyExpression) propX(classX(field.getDeclaringClass()), expr.getName());
+ pexp.getProperty().setSourcePosition(expr);
+ // GRECLIPSE end
+ // put the receiver inferred type so that the class writer knows that it will have to call a bridge method
+ pexp.getObjectExpression().putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getDeclaringClass());
+ // add inferred type information
+ pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getOriginType());
+ return pexp;
+ }
+ return null;
+ }
+}
diff --git a/base/org.codehaus.groovy30/.checkstyle b/base/org.codehaus.groovy30/.checkstyle
index e0eb9214a1..27bfd5759a 100644
--- a/base/org.codehaus.groovy30/.checkstyle
+++ b/base/org.codehaus.groovy30/.checkstyle
@@ -72,7 +72,7 @@
-
+
diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
new file mode 100644
index 0000000000..4e2281046e
--- /dev/null
+++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.transform.sc.transformers;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
+import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.*;
+
+/**
+ * Transformer for VariableExpression the bytecode backend wouldn't be able to
+ * handle otherwise.
+ */
+public class VariableExpressionTransformer {
+
+ public Expression transformVariableExpression(final VariableExpression expr) {
+ Expression trn = tryTransformDelegateToProperty(expr);
+ if (trn == null) {
+ trn = tryTransformPrivateFieldAccess(expr);
+ }
+ return trn != null ? trn : expr;
+ }
+
+ private static Expression tryTransformDelegateToProperty(final VariableExpression expr) {
+ // we need to transform variable expressions that go to a delegate
+ // to a property expression, as ACG would lose the information in
+ // processClassVariable before it reaches any makeCall, that could handle it
+ Object val = expr.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
+ if (val == null || val.equals(expr.getName())) return null;
+
+ // TODO: handle the owner and delegate cases better for nested scenarios and potentially remove the need for the implicit this case
+ Expression receiver = varX("owner".equals(val) ? (String) val : "delegate".equals(val) ? (String) val : "this");
+ // GROOVY-9136 -- object expression should not overlap source range of property; property stands in for original variable expression
+ receiver.setLineNumber(expr.getLineNumber());
+ receiver.setColumnNumber(expr.getColumnNumber());
+
+ PropertyExpression pexp = propX(receiver, expr.getName());
+ pexp.getProperty().setSourcePosition(expr);
+ pexp.copyNodeMetaData(expr);
+ pexp.setImplicitThis(true);
+
+ ClassNode owner = expr.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
+ if (owner != null) {
+ receiver.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, owner);
+ receiver.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, val);
+ }
+ pexp.removeNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
+
+ return pexp;
+ }
+
+ private static Expression tryTransformPrivateFieldAccess(final VariableExpression expr) {
+ FieldNode field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
+ if (field == null) {
+ field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION);
+ }
+ if (field != null) {
+ // 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
+ PropertyExpression pexp = thisPropX(true, expr.getName());
+ // GRECLIPSE add -- GROOVY-6610
+ if (field.isStatic()) pexp = propX(classX(field.getDeclaringClass()), expr.getName());
+ // GRECLIPSE end
+ // store the declaring class so that the class writer knows that it will have to call a bridge method
+ pexp.getObjectExpression().putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getDeclaringClass());
+ pexp.putNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE, field.getOriginType());
+ pexp.getProperty().setSourcePosition(expr);
+ return pexp;
+ }
+ return null;
+ }
+}
diff --git a/base/org.codehaus.groovy40/.checkstyle b/base/org.codehaus.groovy40/.checkstyle
index b24763ed63..08b65984c5 100644
--- a/base/org.codehaus.groovy40/.checkstyle
+++ b/base/org.codehaus.groovy40/.checkstyle
@@ -70,7 +70,7 @@
-
+
diff --git a/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
new file mode 100644
index 0000000000..4e2281046e
--- /dev/null
+++ b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.transform.sc.transformers;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
+import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.*;
+
+/**
+ * Transformer for VariableExpression the bytecode backend wouldn't be able to
+ * handle otherwise.
+ */
+public class VariableExpressionTransformer {
+
+ public Expression transformVariableExpression(final VariableExpression expr) {
+ Expression trn = tryTransformDelegateToProperty(expr);
+ if (trn == null) {
+ trn = tryTransformPrivateFieldAccess(expr);
+ }
+ return trn != null ? trn : expr;
+ }
+
+ private static Expression tryTransformDelegateToProperty(final VariableExpression expr) {
+ // we need to transform variable expressions that go to a delegate
+ // to a property expression, as ACG would lose the information in
+ // processClassVariable before it reaches any makeCall, that could handle it
+ Object val = expr.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
+ if (val == null || val.equals(expr.getName())) return null;
+
+ // TODO: handle the owner and delegate cases better for nested scenarios and potentially remove the need for the implicit this case
+ Expression receiver = varX("owner".equals(val) ? (String) val : "delegate".equals(val) ? (String) val : "this");
+ // GROOVY-9136 -- object expression should not overlap source range of property; property stands in for original variable expression
+ receiver.setLineNumber(expr.getLineNumber());
+ receiver.setColumnNumber(expr.getColumnNumber());
+
+ PropertyExpression pexp = propX(receiver, expr.getName());
+ pexp.getProperty().setSourcePosition(expr);
+ pexp.copyNodeMetaData(expr);
+ pexp.setImplicitThis(true);
+
+ ClassNode owner = expr.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
+ if (owner != null) {
+ receiver.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, owner);
+ receiver.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, val);
+ }
+ pexp.removeNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
+
+ return pexp;
+ }
+
+ private static Expression tryTransformPrivateFieldAccess(final VariableExpression expr) {
+ FieldNode field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
+ if (field == null) {
+ field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION);
+ }
+ if (field != null) {
+ // 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
+ PropertyExpression pexp = thisPropX(true, expr.getName());
+ // GRECLIPSE add -- GROOVY-6610
+ if (field.isStatic()) pexp = propX(classX(field.getDeclaringClass()), expr.getName());
+ // GRECLIPSE end
+ // store the declaring class so that the class writer knows that it will have to call a bridge method
+ pexp.getObjectExpression().putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getDeclaringClass());
+ pexp.putNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE, field.getOriginType());
+ pexp.getProperty().setSourcePosition(expr);
+ return pexp;
+ }
+ return null;
+ }
+}