This is an automated email from the ASF dual-hosted git repository. paulk pushed a commit to branch GROOVY_2_5_X in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 65323180504cba18d50e5474f6496a810641ba66 Author: Eric Milles <[email protected]> AuthorDate: Fri Oct 23 20:53:03 2020 -0500 GROOVY-9093: SC: add compile-time error for inaccessible field or getter (port to 2_5_X) --- .../classgen/asm/sc/StaticTypesCallSiteWriter.java | 35 +++++--- src/test/groovy/bugs/Groovy7165.groovy | 97 ++++++++++++++++++++++ 2 files changed, 121 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java index 575a365..ac6862c 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java @@ -81,6 +81,9 @@ import static org.codehaus.groovy.ast.ClassHelper.getWrapper; import static org.codehaus.groovy.ast.ClassHelper.int_TYPE; import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType; import static org.codehaus.groovy.ast.ClassHelper.make; +import static org.codehaus.groovy.ast.tools.GeneralUtils.args; +import static org.codehaus.groovy.ast.tools.GeneralUtils.callX; +import static org.codehaus.groovy.ast.tools.GeneralUtils.constX; import static org.codehaus.groovy.classgen.AsmClassGenerator.samePackages; import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.chooseBestMethod; import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDGMMethodsByNameAndArguments; @@ -451,13 +454,13 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes receiverType = classNode; } - String property = methodName; + String propertyName = methodName; if (implicitThis) { if (controller.getInvocationWriter() instanceof StaticInvocationWriter) { MethodCallExpression currentCall = ((StaticInvocationWriter) controller.getInvocationWriter()).getCurrentCall(); if (currentCall != null && currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER) != null) { - property = currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER); - String[] props = property.split("\\."); + propertyName = currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER); + String[] props = propertyName.split("\\."); BytecodeExpression thisLoader = new BytecodeExpression() { @Override public void visit(final MethodVisitor mv) { @@ -477,15 +480,16 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes } } - if (makeGetPropertyWithGetter(receiver, receiverType, property, safe, implicitThis)) return; - if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, property, safe, implicitThis)) return; - if (makeGetField(receiver, receiverType, property, safe, implicitThis)) return; + if (makeGetPropertyWithGetter(receiver, receiverType, propertyName, safe, implicitThis)) return; + if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, propertyName, safe, implicitThis)) return; + if (makeGetField(receiver, receiverType, propertyName, safe, implicitThis)) return; - MethodCallExpression call = new MethodCallExpression( - receiver, - "getProperty", - new ArgumentListExpression(new ConstantExpression(property)) - ); + boolean isScriptVariable = (receiverType.isScript() && receiver instanceof VariableExpression && ((VariableExpression) receiver).getAccessedVariable() == null); + if (!isScriptVariable && controller.getClassNode().getOuterClass() == null) { // inner class still needs dynamic property sequence + addPropertyAccessError(receiver, propertyName, receiverType); + } + + MethodCallExpression call = callX(receiver, "getProperty", args(constX(propertyName))); call.setImplicitThis(implicitThis); call.setSafe(safe); call.setMethodTarget(GROOVYOBJECT_GETPROPERTY_METHOD); @@ -939,5 +943,14 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes return true; } return false; +<<<<<<< HEAD +======= + }*/ + + private void addPropertyAccessError(final Expression receiver, final String propertyName, final ClassNode receiverType) { + String receiverName = (receiver instanceof ClassExpression ? receiver.getType() : receiverType).toString(false); + String message = "Access to " + receiverName + "#" + propertyName + " is forbidden"; + controller.getSourceUnit().addError(new SyntaxException(message, receiver)); +>>>>>>> c27b2c3e51... GROOVY-9093: SC: add compile-time error for inaccessible field or getter (port to 3_0_X) } } diff --git a/src/test/groovy/bugs/Groovy7165.groovy b/src/test/groovy/bugs/Groovy7165.groovy new file mode 100644 index 0000000..5880057 --- /dev/null +++ b/src/test/groovy/bugs/Groovy7165.groovy @@ -0,0 +1,97 @@ +/* + * 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 groovy.bugs + +import groovy.transform.CompileStatic +import org.junit.Test + +import static groovy.test.GroovyAssert.assertScript +import static groovy.test.GroovyAssert.shouldFail + +@CompileStatic +final class Groovy7165 { + + @Test + void testPrivateStaticSuperField1() { + assertScript ''' + import java.util.function.Function + + @groovy.transform.CompileStatic + class Bug { + private static List<String> staticfield = [] + + def test() { + List<Function<List<String>, String>> runners = [] + runners.add(new Called()) + List<String> results = ['hello'] + runners.each { + results.addAll(it.apply(staticfield)) + } + return results.join(' ') + } + + static class Called implements Function<List<String>, String> { + @Override + String apply(List<String> args) { + 'world' + } + } + } + + def out = new Bug().test() + assert out == 'hello world' + ''' + } + + @Test + void testPrivateStaticSuperField2() { + def err = shouldFail ''' + class A { + private static final String CONST = 'value' + } + class B extends A { + @groovy.transform.CompileStatic + def test() { + return CONST // search excludes private members from supers + } + } + new B().test() + ''' + + assert err =~ /Access to B#CONST is forbidden/ + } + + @Test + void testPrivateStaticSuperField3() { + def err = shouldFail ''' + class A { + private static final String CONST = 'value' + } + class B extends A { + @groovy.transform.CompileStatic + def test() { + return A.CONST + } + } + assert false : 'compilation should fail' + ''' + + assert err =~ /Access to A#CONST is forbidden/ + } +}
