diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index dda0cc99980..12b8547410f 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -1550,8 +1550,7 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re queue.addFirst(current.getSuperClass()); Collections.addAll(queue, current.getInterfaces()); } - - field = allowStaticAccessToMember(field, staticOnly); + else field = allowStaticAccessToMember(field, staticOnly); // skip property/accessor checks for "x.@field" if (pexp instanceof AttributeExpression) { @@ -1572,7 +1571,7 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re property = allowStaticAccessToMember(property, staticOnly); MethodNode getter = null; - if (!isMapProperty(pexp)) { // GROOVY-11369: map entry before getter + if (!isMapProperty(pexp, receiverType)) { // GROOVY-11369: map entry before getter getter = findGetter(current, getterName, pexp.isImplicitThis()); getter = allowStaticAccessToMember(getter, staticOnly); if (getter == null) { @@ -1633,8 +1632,8 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re foundGetterOrSetter = (foundGetterOrSetter || getter != null || !setters.isEmpty()); } - if (readMode && !isMapProperty(pexp)) { // GROOVY-11369, GROOVY-11370, GROOVY-11372 - // GROOVY-5568, GROOVY-9115, GROOVY-9123: the property may be defined by an extension + if (readMode && !isMapProperty(pexp, receiverType)) { // GROOVY-11369, GROOVY-11370, GROOVY-11372 + // GROOVY-5568, GROOVY-9115, GROOVY-9123: the property may be provided by an extension method for (ClassNode dgmReceiver : isPrimitiveType(receiverType) ? new ClassNode[]{receiverType, getWrapper(receiverType)} : new ClassNode[]{receiverType}) { Set methods = findDGMMethodsForClassNode(getSourceUnit().getClassLoader(), dgmReceiver, getterName); for (MethodNode method : findDGMMethodsForClassNode(getSourceUnit().getClassLoader(), dgmReceiver, isserName)) { @@ -1695,8 +1694,8 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re continue; if (visitor != null) { // TODO: type inference on maps and lists, if possible - PropertyNode node = new PropertyNode(propertyName, Opcodes.ACC_PUBLIC, propertyType, receiver.getType(), null, null, null); - node.setDeclaringClass(receiver.getType()); + PropertyNode node = new PropertyNode(propertyName, Opcodes.ACC_PUBLIC, propertyType, receiverType, null, null, null); + node.setDeclaringClass(receiverType); visitor.visitProperty(node); } storeType(pexp, propertyType); @@ -1794,13 +1793,14 @@ private ClassNode getTypeForMapPropertyExpression(final ClassNode testClass, fin return null; } - private boolean isMapProperty(final PropertyExpression pexp) { - final Expression objectExpression = pexp.getObjectExpression(); + private boolean isMapProperty(final PropertyExpression pexp, final ClassNode receiverType) { + Expression objectExpression = pexp.getObjectExpression(); if (isSuperExpression(objectExpression) || (isThisExpression(objectExpression) + && (!pexp.isImplicitThis() || typeCheckingContext.getEnclosingClosure() == null) && Arrays.asList(getTypeCheckingAnnotations()).contains(COMPILESTATIC_CLASSNODE))) { return false; } - return isOrImplements(getType(objectExpression), MAP_TYPE); + return isOrImplements(receiverType, MAP_TYPE); } /** diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy index e548125340c..3f7fa122024 100644 --- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy +++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy @@ -164,7 +164,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { c.@x = '1' ''', 'Cannot assign value of type java.lang.String to variable of type int' - } + } void testInferenceFromAttributeType() { assertScript ''' @@ -699,7 +699,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { ''' } - // GROOVY-11369 + // GROOVY-11369, GROOVY-11384 void testMapPropertyAccess5() { assertScript ''' def map = [:] @@ -721,6 +721,17 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { assert !map.containsKey('metaClass') assert map.containsKey('properties') ''' + assertScript ''' + void test(Map map) { + def str = '' + str += map.empty + str += map.with{ empty } + str += map.with{ delegate.empty } + str += map.with{ {->owner.empty}() } + assert str == 'entryentryentryentry' + } + test( [:].withDefault{ 'entry' } ) + ''' } // GROOVY-11369 diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy index 2ec83bad4eb..0f8d1a46d5c 100644 --- a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy +++ b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy @@ -21,6 +21,9 @@ package org.codehaus.groovy.classgen.asm.sc import groovy.test.NotYetImplemented import groovy.transform.stc.FieldsAndPropertiesSTCTest +/** + * Unit tests for static compilation : fields and properties. + */ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCTest implements StaticCompilationTestSupport { // GROOVY-5561 @@ -41,7 +44,7 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT } // GROOVY-5579 - void testUseSetterAndNotSetProperty() { + void testUseSetterNotSetProperty() { assertScript ''' Date d = new Date() d.time = 1 @@ -236,8 +239,8 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT } assert new D().m() == 0 """ - def b = astTrees['D'][1] - assert b.contains('GETFIELD C.x') + def d = astTrees['D'][1] + assert d.contains('GETFIELD C.x') } } @@ -280,9 +283,9 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT } assert D.m() == 0 ''' - def b = astTrees['D'][1] - assert b.contains('GETSTATIC D.x') - assert !b.contains('INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.getGroovyObjectProperty') + def d = astTrees['D'][1] + assert d.contains('GETSTATIC D.x') + assert !d.contains('INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.getGroovyObjectProperty') } void testReadPropertyFromSuperClass() { @@ -299,9 +302,9 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT } assert new D().m() == 0 """ - def b = astTrees['D'][1] - assert !b.contains('GETFIELD C.x') : 'no GETFIELD in D' - assert b.contains('INVOKEVIRTUAL D.getX') : 'getX() in D' + def d = astTrees['D'][1] + assert !d.contains('GETFIELD C.x') : 'no GETFIELD in D' + assert d.contains('INVOKEVIRTUAL D.getX') : 'getX() in D' } } @@ -325,8 +328,8 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT d.m() assert d.isGetterCalled() == false ''' - def b = astTrees['D'][1] - assert b.contains('GETFIELD C.x') + def d = astTrees['D'][1] + assert d.contains('GETFIELD C.x') } void testUseAttributeExternal() { @@ -548,7 +551,6 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT class C { void setOut(int a) {} } - def c = new C() try { } finally { @@ -569,7 +571,6 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT void setOut(int a) {} void setOut(String a) {} } - def c = new C() try { } finally { @@ -580,8 +581,8 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT } finally { assert astTrees.values().any { def code = it.toString() - code.contains('INVOKEVIRTUAL C.setOut (I)V') && - code.contains('INVOKEVIRTUAL C.setOut (Ljava/lang/String;)V') + code.contains('INVOKEVIRTUAL C.setOut (I)V') + && code.contains('INVOKEVIRTUAL C.setOut (Ljava/lang/String;)V') } } } @@ -777,7 +778,6 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT println accessedAndMutated accessedAndMutated = 'def' } - void test() { cl() assert mutated == 'abc' @@ -804,7 +804,7 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT void testPropertyAccessOnEnumClass() { assertScript ''' enum E { } - assert E.getModifiers() == E.modifiers + assert E.modifiers == E.getModifiers() ''' }