Skip to content

Commit 4aaf8f7

Browse files
committed
GROOVY-9955, GROOVY-9967
1 parent ccc3896 commit 4aaf8f7

4 files changed

Lines changed: 250 additions & 1 deletion

File tree

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

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,35 @@ public void testCompileStatic6095() {
734734
runConformTest(sources, "123.0");
735735
}
736736

737+
@Test
738+
public void testCompileStatic6276() {
739+
//@formatter:off
740+
String[] sources = {
741+
"Main.groovy",
742+
"@groovy.transform.CompileStatic\n" +
743+
"class Outer {\n" +
744+
" private int outerField = 1\n" +
745+
" private int outerMethod() { 2 }\n" +
746+
" int outerProperty = 3\n" +
747+
" class Inner {\n" +
748+
" void test() {\n" +
749+
" assert outerField == 1\n" +
750+
" assert outerMethod() == 2\n" +
751+
" assert outerProperty == 3\n" +
752+
" assert getOuterProperty() == 3\n" +
753+
" }\n" +
754+
" }\n" +
755+
" void test() {\n" +
756+
" new Inner().test()\n" +
757+
" }\n" +
758+
"}\n" +
759+
"new Outer().test()\n",
760+
};
761+
//@formatter:on
762+
763+
runConformTest(sources, "");
764+
}
765+
737766
@Test
738767
public void testCompileStatic6904() {
739768
//@formatter:off
@@ -5909,4 +5938,90 @@ public void testCompileStatic9938b() {
59095938

59105939
runConformTest(sources, "works");
59115940
}
5941+
5942+
@Test
5943+
public void testCompileStatic9955() {
5944+
//@formatter:off
5945+
String[] sources = {
5946+
"Main.groovy",
5947+
"import p.Types.Public\n" +
5948+
"@groovy.transform.CompileStatic\n" +
5949+
"void test() {\n" +
5950+
" assert Public.CONST == 'XX'\n" +
5951+
" assert Public.VALUE == null\n" +
5952+
" Public.VALUE = 'YY'\n" +
5953+
" assert Public.VALUE == 'YY'\n" +
5954+
" Public.@VALUE = 'ZZ'\n" +
5955+
" assert Public.@VALUE == 'ZZ'\n" +
5956+
"}\n" +
5957+
"test()\n",
5958+
5959+
"p/Types.groovy",
5960+
"package p\n" +
5961+
"class Types {\n" +
5962+
" @groovy.transform.PackageScope static class PackagePrivate {\n" +
5963+
" public static final String CONST = 'XX'\n" +
5964+
" public static String VALUE\n" +
5965+
" }\n" +
5966+
" public static class Public extends PackagePrivate {\n" +
5967+
" }\n" +
5968+
"}",
5969+
};
5970+
//@formatter:on
5971+
5972+
runConformTest(sources, "");
5973+
}
5974+
5975+
@Test
5976+
public void testCompileStatic9967() {
5977+
//@formatter:off
5978+
String[] sources = {
5979+
"Main.groovy",
5980+
"class A {\n" +
5981+
"}\n" +
5982+
"class B extends A {\n" +
5983+
" String p = 'foo'\n" +
5984+
"}\n" +
5985+
"@groovy.transform.CompileStatic\n" +
5986+
"class C {\n" +
5987+
" String scenario1(x) {\n" +
5988+
" (x instanceof String) ? x.toLowerCase() : 'bar'\n" +
5989+
" }\n" +
5990+
" String scenario2(B x) {\n" +
5991+
" x.p\n" +
5992+
" }\n" +
5993+
" String scenario2a(B x) {\n" +
5994+
" x.getP()\n" +
5995+
" }\n" +
5996+
" String scenario3(B x) {\n" +
5997+
" (x instanceof B) ? x.p : 'bar'\n" +
5998+
" }\n" +
5999+
" String scenario3a(B x) {\n" +
6000+
" (x instanceof B) ? x.getP() : 'bar'\n" +
6001+
" }\n" +
6002+
" String scenario4(A x) {\n" +
6003+
" (x instanceof B) ? x.p : 'bar'\n" + // Access to A#p is forbidden
6004+
" }\n" +
6005+
" String scenario4a(A x) {\n" +
6006+
" (x instanceof B) ? x.getP() : 'bar'\n" +
6007+
" }\n" +
6008+
"}\n" +
6009+
"new C().with {\n" +
6010+
" assert scenario1(null) == 'bar'\n" +
6011+
" assert scenario1('Foo') == 'foo'\n" +
6012+
" assert scenario2(new B()) == 'foo'\n" +
6013+
" assert scenario2a(new B()) == 'foo'\n" +
6014+
" assert scenario3(new B()) == 'foo'\n" +
6015+
" assert scenario3a(new B()) == 'foo'\n" +
6016+
6017+
" assert scenario4(new A()) == 'bar'\n" +
6018+
" assert scenario4(new B()) == 'foo'\n" +
6019+
" assert scenario4a(new A()) == 'bar'\n" +
6020+
" assert scenario4a(new B()) == 'foo'\n" +
6021+
"}\n",
6022+
};
6023+
//@formatter:on
6024+
6025+
runConformTest(sources, "");
6026+
}
59126027
}

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

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,10 +445,17 @@ private boolean makeGetPrivateFieldWithBridgeMethod(final Expression receiver, f
445445
public void makeGroovyObjectGetPropertySite(final Expression receiver, final String methodName, final boolean safe, final boolean implicitThis) {
446446
TypeChooser typeChooser = controller.getTypeChooser();
447447
ClassNode classNode = controller.getClassNode();
448+
/* GRECLIPSE edit -- GROOVY-9967
448449
ClassNode receiverType = typeChooser.resolveType(receiver, classNode);
449450
if (receiver instanceof VariableExpression && ((VariableExpression) receiver).isThisExpression() && !controller.isInClosure()) {
450451
receiverType = classNode;
451452
}
453+
*/
454+
ClassNode receiverType = controller.getClassNode();
455+
if (!isThisExpression(receiver) || controller.isInClosure()) {
456+
receiverType = getPropertyOwnerType(receiver);
457+
}
458+
// GRECLIPSE edit
452459

453460
String propertyName = methodName;
454461
if (implicitThis) {
@@ -574,7 +581,11 @@ boolean makeGetField(final Expression receiver, final ClassNode receiverType, fi
574581
ClassNode replacementType = field.getOriginType();
575582
OperandStack operandStack = controller.getOperandStack();
576583
if (field.isStatic()) {
584+
/* GRECLIPSE edit -- GROOVY-9955
577585
mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(field.getOwner()), fieldName, BytecodeHelper.getTypeDescription(replacementType));
586+
*/
587+
mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(receiverType), fieldName, BytecodeHelper.getTypeDescription(replacementType));
588+
// GRECLIPSE end
578589
operandStack.push(replacementType);
579590
} else {
580591
if (implicitThis) {
@@ -890,7 +901,7 @@ public void fallbackAttributeOrPropertySite(PropertyExpression expression, Expre
890901
*/
891902
if (name != null && controller.getCompileStack().isLHS()) {
892903
ClassNode classNode = controller.getClassNode();
893-
ClassNode receiverType = controller.getTypeChooser().resolveType(objectExpression, classNode);
904+
ClassNode receiverType = getPropertyOwnerType(objectExpression);
894905
if (adapter == AsmClassGenerator.setField || adapter == AsmClassGenerator.setGroovyObjectField) {
895906
if (setField(expression, objectExpression, receiverType, name)) return;
896907
} else if (isThisExpression(objectExpression)) {
@@ -924,6 +935,36 @@ public void fallbackAttributeOrPropertySite(PropertyExpression expression, Expre
924935
super.fallbackAttributeOrPropertySite(expression, objectExpression, name, adapter);
925936
}
926937

938+
// GRECLIPSE add -- GROOVY-9955, GROOVY-9967
939+
private ClassNode getPropertyOwnerType(final Expression receiver) {
940+
Object inferredType = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
941+
if (inferredType == null && receiver instanceof VariableExpression) {
942+
Variable variable = ((VariableExpression) receiver).getAccessedVariable();
943+
if (variable instanceof Expression) {
944+
inferredType = ((Expression) variable).getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
945+
}
946+
}
947+
ClassNode receiverType;
948+
if (inferredType instanceof ClassNode) {
949+
// in case a "flow type" is found, it is preferred to use it instead of the declaration type
950+
receiverType = (ClassNode) inferredType;
951+
} else {
952+
receiverType = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
953+
if (receiverType == null) {
954+
receiverType = controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
955+
}
956+
}
957+
if (isClassClassNodeWrappingConcreteType(receiverType)) {
958+
receiverType = receiverType.getGenericsTypes()[0].getType();
959+
}
960+
if (isPrimitiveType(receiverType)) {
961+
// GROOVY-6590: wrap primitive types
962+
receiverType = getWrapper(receiverType);
963+
}
964+
return receiverType;
965+
}
966+
// GRECLIPSE end
967+
927968
// this is just a simple set field handling static and non-static, but not Closure and inner classes
928969
private boolean setField(PropertyExpression expression, Expression objectExpression, ClassNode rType, String name) {
929970
if (expression.isSafe()) return false;
@@ -946,6 +987,9 @@ private boolean setField(PropertyExpression expression, Expression objectExpress
946987
mv.visitFieldInsn(PUTFIELD, ownerName, name, BytecodeHelper.getTypeDescription(fn.getType()));
947988
stack.remove(1);
948989
} else {
990+
// GRECLIPSE add -- GROOVY-9955
991+
ownerName = BytecodeHelper.getClassInternalName(rType);
992+
// GRECLIPSE end
949993
mv.visitFieldInsn(PUTSTATIC, ownerName, name, BytecodeHelper.getTypeDescription(fn.getType()));
950994
}
951995

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,11 @@ private boolean makeGetPrivateFieldWithBridgeMethod(final Expression receiver, f
427427
public void makeGroovyObjectGetPropertySite(final Expression receiver, final String propertyName, final boolean safe, final boolean implicitThis) {
428428
ClassNode receiverType = controller.getClassNode();
429429
if (!isThisExpression(receiver) || controller.isInGeneratedFunction()) {
430+
/* GRECLIPSE edit -- GROOVY-9967
430431
receiverType = controller.getTypeChooser().resolveType(receiver, receiverType);
432+
*/
433+
receiverType = getPropertyOwnerType(receiver);
434+
// GRECLIPSE end
431435
}
432436

433437
if (implicitThis && controller.getInvocationWriter() instanceof StaticInvocationWriter) {
@@ -535,7 +539,11 @@ boolean makeGetField(final Expression receiver, final ClassNode receiverType, fi
535539
ClassNode replacementType = field.getOriginType();
536540
OperandStack operandStack = controller.getOperandStack();
537541
if (field.isStatic()) {
542+
/* GRECLIPSE edit -- GROOVY-9955
538543
mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(field.getOwner()), fieldName, BytecodeHelper.getTypeDescription(replacementType));
544+
*/
545+
mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(receiverType), fieldName, BytecodeHelper.getTypeDescription(replacementType));
546+
// GRECLIPSE end
539547
operandStack.push(replacementType);
540548
} else {
541549
if (implicitThis) {
@@ -791,7 +799,11 @@ private void writeNumberNumberCall(final Expression receiver, final String messa
791799
public void fallbackAttributeOrPropertySite(final PropertyExpression expression, final Expression objectExpression, final String name, final MethodCallerMultiAdapter adapter) {
792800
if (name != null && controller.getCompileStack().isLHS()) {
793801
ClassNode classNode = controller.getClassNode();
802+
/* GRECLIPSE edit -- GROOVY-9955
794803
ClassNode receiverType = controller.getTypeChooser().resolveType(objectExpression, classNode);
804+
*/
805+
ClassNode receiverType = getPropertyOwnerType(objectExpression);
806+
// GRECLIPSE end
795807
if (adapter == AsmClassGenerator.setField || adapter == AsmClassGenerator.setGroovyObjectField) {
796808
if (setField(expression, objectExpression, receiverType, name)) return;
797809
} else if (isThisExpression(objectExpression)) {
@@ -826,6 +838,36 @@ public void fallbackAttributeOrPropertySite(final PropertyExpression expression,
826838
super.fallbackAttributeOrPropertySite(expression, objectExpression, name, adapter);
827839
}
828840

841+
// GRECLIPSE add -- GROOVY-9955, GROOVY-9967
842+
private ClassNode getPropertyOwnerType(final Expression receiver) {
843+
Object inferredType = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
844+
if (inferredType == null && receiver instanceof VariableExpression) {
845+
Variable variable = ((VariableExpression) receiver).getAccessedVariable();
846+
if (variable instanceof Expression) {
847+
inferredType = ((Expression) variable).getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
848+
}
849+
}
850+
ClassNode receiverType;
851+
if (inferredType instanceof ClassNode) {
852+
// in case a "flow type" is found, it is preferred to use it instead of the declaration type
853+
receiverType = (ClassNode) inferredType;
854+
} else {
855+
receiverType = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
856+
if (receiverType == null) {
857+
receiverType = controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
858+
}
859+
}
860+
if (isClassClassNodeWrappingConcreteType(receiverType)) {
861+
receiverType = receiverType.getGenericsTypes()[0].getType();
862+
}
863+
if (isPrimitiveType(receiverType)) {
864+
// GROOVY-6590: wrap primitive types
865+
receiverType = getWrapper(receiverType);
866+
}
867+
return receiverType;
868+
}
869+
// GRECLIPSE end
870+
829871
// this is just a simple set field handling static and non-static, but not Closure and inner classes
830872
private boolean setField(final PropertyExpression expression, final Expression objectExpression, final ClassNode rType, final String name) {
831873
if (expression.isSafe()) return false;
@@ -848,6 +890,9 @@ private boolean setField(final PropertyExpression expression, final Expression o
848890
mv.visitFieldInsn(PUTFIELD, ownerName, name, BytecodeHelper.getTypeDescription(fn.getType()));
849891
stack.remove(1);
850892
} else {
893+
// GRECLIPSE add -- GROOVY-9955
894+
ownerName = BytecodeHelper.getClassInternalName(rType);
895+
// GRECLIPSE end
851896
mv.visitFieldInsn(PUTSTATIC, ownerName, name, BytecodeHelper.getTypeDescription(fn.getType()));
852897
}
853898

base/org.codehaus.groovy40/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,11 @@ private boolean makeGetPrivateFieldWithBridgeMethod(final Expression receiver, f
447447
public void makeGroovyObjectGetPropertySite(final Expression receiver, final String propertyName, final boolean safe, final boolean implicitThis) {
448448
ClassNode receiverType = controller.getClassNode();
449449
if (!isThisExpression(receiver) || controller.isInGeneratedFunction()) {
450+
/* GRECLIPSE edit -- GROOVY-9967
450451
receiverType = controller.getTypeChooser().resolveType(receiver, receiverType);
452+
*/
453+
receiverType = getPropertyOwnerType(receiver);
454+
// GRECLIPSE end
451455
}
452456

453457
if (implicitThis && controller.getInvocationWriter() instanceof StaticInvocationWriter) {
@@ -560,7 +564,11 @@ boolean makeGetField(final Expression receiver, final ClassNode receiverType, fi
560564
ClassNode replacementType = field.getOriginType();
561565
OperandStack operandStack = controller.getOperandStack();
562566
if (field.isStatic()) {
567+
/* GRECLIPSE edit -- GROOVY-9955
563568
mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(field.getOwner()), fieldName, BytecodeHelper.getTypeDescription(replacementType));
569+
*/
570+
mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(receiverType), fieldName, BytecodeHelper.getTypeDescription(replacementType));
571+
// GRECLIPSE end
564572
operandStack.push(replacementType);
565573
} else {
566574
if (implicitThis) {
@@ -816,7 +824,11 @@ private void writeNumberNumberCall(final Expression receiver, final String messa
816824
public void fallbackAttributeOrPropertySite(final PropertyExpression expression, final Expression objectExpression, final String name, final MethodCallerMultiAdapter adapter) {
817825
if (name != null && controller.getCompileStack().isLHS()) {
818826
ClassNode classNode = controller.getClassNode();
827+
/* GRECLIPSE edit -- GROOVY-9955
819828
ClassNode receiverType = controller.getTypeChooser().resolveType(objectExpression, classNode);
829+
*/
830+
ClassNode receiverType = getPropertyOwnerType(objectExpression);
831+
// GRECLIPSE end
820832
if (adapter == AsmClassGenerator.setField || adapter == AsmClassGenerator.setGroovyObjectField) {
821833
if (setField(expression, objectExpression, receiverType, name)) return;
822834
} else if (isThisExpression(objectExpression)) {
@@ -851,6 +863,36 @@ public void fallbackAttributeOrPropertySite(final PropertyExpression expression,
851863
super.fallbackAttributeOrPropertySite(expression, objectExpression, name, adapter);
852864
}
853865

866+
// GRECLIPSE add -- GROOVY-9955, GROOVY-9967
867+
private ClassNode getPropertyOwnerType(final Expression receiver) {
868+
Object inferredType = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
869+
if (inferredType == null && receiver instanceof VariableExpression) {
870+
Variable variable = ((VariableExpression) receiver).getAccessedVariable();
871+
if (variable instanceof Expression) {
872+
inferredType = ((Expression) variable).getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
873+
}
874+
}
875+
ClassNode receiverType;
876+
if (inferredType instanceof ClassNode) {
877+
// in case a "flow type" is found, it is preferred to use it instead of the declaration type
878+
receiverType = (ClassNode) inferredType;
879+
} else {
880+
receiverType = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
881+
if (receiverType == null) {
882+
receiverType = controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
883+
}
884+
}
885+
if (isClassClassNodeWrappingConcreteType(receiverType)) {
886+
receiverType = receiverType.getGenericsTypes()[0].getType();
887+
}
888+
if (isPrimitiveType(receiverType)) {
889+
// GROOVY-6590: wrap primitive types
890+
receiverType = getWrapper(receiverType);
891+
}
892+
return receiverType;
893+
}
894+
// GRECLIPSE end
895+
854896
// this is just a simple set field handling static and non-static, but not Closure and inner classes
855897
private boolean setField(final PropertyExpression expression, final Expression objectExpression, final ClassNode rType, final String name) {
856898
if (expression.isSafe()) return false;
@@ -873,6 +915,9 @@ private boolean setField(final PropertyExpression expression, final Expression o
873915
mv.visitFieldInsn(PUTFIELD, ownerName, name, BytecodeHelper.getTypeDescription(fn.getType()));
874916
stack.remove(1);
875917
} else {
918+
// GRECLIPSE add -- GROOVY-9955
919+
ownerName = BytecodeHelper.getClassInternalName(rType);
920+
// GRECLIPSE end
876921
mv.visitFieldInsn(PUTSTATIC, ownerName, name, BytecodeHelper.getTypeDescription(fn.getType()));
877922
}
878923

0 commit comments

Comments
 (0)