Skip to content

Commit 31c63d2

Browse files
committed
GROOVY-9821 pt.2
1 parent e0aab74 commit 31c63d2

File tree

4 files changed

+160
-48
lines changed

4 files changed

+160
-48
lines changed

base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/InferencingTests.java

+101-40
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ public void testLocalVar27() {
507507
" x = 3.14\n" +
508508
" break\n" +
509509
" default:\n" +
510+
" break" +
510511
" }\n" +
511512
" x\n" +
512513
"}";
@@ -647,124 +648,168 @@ public void testLocalMethod5() {
647648

648649
@Test
649650
public void testMatcher1() {
650-
String contents = "def x = \"\" =~ /pattern/\nx";
651+
String contents = "def x = ('' =~ /pattern/)";
651652
assertType(contents, "x", "java.util.regex.Matcher");
652653
}
653654

654655
@Test
655656
public void testMatcher2() {
656-
String contents = "(\"\" =~ /pattern/).hasGroup()";
657+
String contents = "('' =~ /pattern/).hasGroup()";
657658
assertType(contents, "hasGroup", "java.lang.Boolean");
658659
}
659660

660661
@Test
661662
public void testPattern1() {
662-
String contents = "def x = ~/pattern/\nx";
663+
String contents = "def x = ~/pattern/";
663664
assertType(contents, "x", "java.util.regex.Pattern");
664665
}
665666

666667
@Test
667668
public void testPattern2() {
668-
String contents = "def x = \"\" ==~ /pattern/\nx";
669+
String contents = "def x = \"\" ==~ /pattern/";
669670
assertType(contents, "x", "java.lang.Boolean");
670671
}
671672

672673
@Test
673674
public void testSpread1() {
674-
String contents = "def z = [1,2]*.value";
675-
assertType(contents, "value", "java.lang.Integer");
675+
String contents = "def x = ['1','2']*.bytes";
676+
assertType(contents, "x", "java.util.List<byte[]>");
676677
}
677678

678679
@Test
679680
public void testSpread2() {
680-
String contents = "[1,2,3]*.intValue()";
681-
assertType(contents, "intValue", "java.lang.Integer");
681+
String contents = "def x = [1,2,3]*.intValue()";
682+
assertType(contents, "x", "java.util.List<java.lang.Integer>");
682683
}
683684

684685
@Test
685686
public void testSpread3() {
686-
String contents = "[1,2,3]*.intValue()[0].value";
687-
assertType(contents, "value", "java.lang.Integer");
687+
String contents = "def x = [1,2,3]*.intValue()[0].intValue()";
688+
assertType(contents, "x", "java.lang.Integer");
688689
}
689690

690691
@Test
691692
public void testSpread4() {
692-
String contents = "[x:1,y:2,z:3]*.getKey()";
693-
assertType(contents, "getKey", "java.lang.String");
693+
String contents = "def x = [a:1,b:2,c:3]*.getKey()";
694+
assertType(contents, "x", "java.util.List<java.lang.String>");
694695
}
695696

696697
@Test
697698
public void testSpread5() {
698-
String contents = "[x:1,y:2,z:3]*.getValue()";
699-
assertType(contents, "getValue", "java.lang.Integer");
699+
String contents = "def x = [a:1,b:2,c:3]*.getValue()";
700+
assertType(contents, "x", "java.util.List<java.lang.Integer>");
700701
}
701702

702703
@Test
703704
public void testSpread6() {
704-
String contents = "[x:1,y:2,z:3]*.key";
705-
assertType(contents, "key", "java.lang.String");
705+
String contents = "def x = [a:1,b:2,c:3]*.key";
706+
assertType(contents, "x", "java.util.List<java.lang.String>");
706707
}
707708

708709
@Test
709710
public void testSpread7() {
710-
String contents = "[x:1,y:2,z:3]*.value";
711-
assertType(contents, "value", "java.lang.Integer");
711+
String contents = "def x = [a:1,b:2,c:3]*.value";
712+
assertType(contents, "x", "java.util.List<java.lang.Integer>");
712713
}
713714

714715
@Test
715716
public void testSpread8() {
716-
String contents = "[x:1,y:2,z:3]*.key[0].toLowerCase()";
717-
assertType(contents, "toLowerCase", "java.lang.String");
717+
String contents = "def x = [a:1,b:2,c:3]*.key[0].toLowerCase()";
718+
assertType(contents, "x", "java.lang.String");
718719
}
719720

720721
@Test
721722
public void testSpread9() {
722-
String contents = "[x:1,y:2,z:3]*.value[0].intValue()";
723-
assertType(contents, "intValue", "java.lang.Integer");
723+
String contents = "def x = [a:1,b:2,c:3]*.value[0].intValue()";
724+
assertType(contents, "x", "java.lang.Integer");
724725
}
725726

726727
@Test
727728
public void testSpread10() {
728-
String contents = "[1,2,3]*.value[0].value";
729-
assertType(contents, "value", "java.lang.Integer");
729+
String contents = "def x = ['1','2','3']*.bytes[0].length";
730+
assertType(contents, "x", "java.lang.Integer");
730731
}
731732

732733
@Test
733734
public void testSpread11() {
734-
String contents = "Set<String> strings = ['1','2','3'] as Set\n" +
735-
"strings*.bytes\n";
736-
assertType(contents, "bytes", "byte[]");
735+
String contents = "Set<String> strings = ['1','2','3']; def x = strings*.bytes";
736+
assertType(contents, "x", "java.util.List<byte[]>");
737737
}
738738

739739
@Test
740740
public void testSpread12() {
741-
String contents = "Set<String> strings = ['1','2','3'] as Set\n" +
742-
"strings*.length()\n";
743-
assertType(contents, "length", "java.lang.Integer");
741+
String contents = "Set<String> strings = ['1','2','3']; def x = strings*.length()";
742+
assertType(contents, "x", "java.util.List<java.lang.Integer>");
744743
}
745744

746745
@Test
747746
public void testSpread13() {
748-
String contents = "@groovy.transform.TypeChecked\n" +
749-
"class Foo {\n" +
750-
" static def meth() {\n" +
751-
" Set<java.beans.BeanInfo> beans = []\n" +
752-
" beans*.additionalBeanInfo\n" +
753-
" }\n" +
747+
String contents =
748+
"@groovy.transform.TypeChecked\n" +
749+
"void test(Set<java.beans.BeanInfo> beans) {\n" +
750+
" beans*.additionalBeanInfo\n" +
754751
"}\n";
755752
assertType(contents, "beans", "java.util.Set<java.beans.BeanInfo>");
756753
assertType(contents, "additionalBeanInfo", "java.beans.BeanInfo[]");
757754
}
758755

759-
@Test // https://github.com/groovy/groovy-eclipse/issues/763
756+
@Test // GROOVY-9021
760757
public void testSpread14() {
758+
createJavaUnit("Pojo",
759+
"interface Pojo {\n" +
760+
" java.util.Collection<? extends java.lang.String> getStrings();\n" +
761+
"}\n");
762+
763+
String contents =
764+
"@groovy.transform.TypeChecked\n" +
765+
"void test(Pojo pojo) {\n" +
766+
" def result = pojo.strings*.bytes\n" + // exercises StaticTypeCheckingVisitor#getTypeForSpreadExpression
767+
"}\n";
768+
assertType(contents, "strings", "java.util.Collection<? extends java.lang.String>");
769+
assertType(contents, "result", "java.util.List<byte[]>");
770+
}
771+
772+
@Test // GROOVY-9021
773+
public void testSpread15() {
774+
createJavaUnit("Pojo",
775+
"interface Pojo {\n" +
776+
" java.util.List<? extends java.lang.String> getStrings();\n" +
777+
"}\n");
778+
779+
String contents =
780+
"@groovy.transform.TypeChecked\n" +
781+
"void test(Pojo pojo) {\n" +
782+
" def result = pojo.strings*.bytes\n" + // exercises StaticTypeCheckingVisitor#getTypeForListExpression
783+
"}\n";
784+
assertType(contents, "strings", "java.util.List<? extends java.lang.String>");
785+
assertType(contents, "result", "java.util.List<byte[]>");
786+
}
787+
788+
@Test
789+
public void testSpread16() {
790+
createJavaUnit("Pojo",
791+
"interface Pojo {\n" +
792+
" java.util.Map<String, ? extends java.lang.String> getStrings();\n" +
793+
"}\n");
794+
795+
String contents =
796+
"@groovy.transform.TypeChecked\n" +
797+
"void test(Pojo pojo) {\n" +
798+
" def result = pojo.strings*.value\n" + // exercises StaticTypeCheckingVisitor#getTypeForMapExpression
799+
"}\n";
800+
assertType(contents, "strings", "java.util.Map<java.lang.String,? extends java.lang.String>");
801+
assertType(contents, "result", "java.util.List<? extends java.lang.String>");
802+
}
803+
804+
@Test // https://github.com/groovy/groovy-eclipse/issues/763
805+
public void testSpread17() {
761806
String contents = "def strings = [[['1','2','3']]]\n" +
762807
"def result = strings*.length()\n";
763808
assertType(contents, "result", "java.util.List<java.util.List>");
764809
}
765810

766811
@Test // CommandRegistry.iterator() lacks generics
767-
public void testSpread15() {
812+
public void testSpread18() {
768813
String contents =
769814
"import org.codehaus.groovy.tools.shell.CommandRegistry\n" +
770815
"def registry = new CommandRegistry()\n" +
@@ -773,7 +818,7 @@ public void testSpread15() {
773818
}
774819

775820
@Test
776-
public void testSpread16() {
821+
public void testSpread19() {
777822
String contents =
778823
"import java.util.regex.Matcher\n" +
779824
"Matcher matcher = ('abc' =~ /./)\n" +
@@ -782,7 +827,7 @@ public void testSpread16() {
782827
}
783828

784829
@Test
785-
public void testSpread17() {
830+
public void testSpread20() {
786831
String contents =
787832
"Reader reader = null\n" +
788833
"def result = reader*.with {it}\n";
@@ -794,6 +839,22 @@ public void testMapLiteral() {
794839
assertType("[:]", "java.util.Map<java.lang.Object,java.lang.Object>");
795840
}
796841

842+
@Test // GROOVY-9021
843+
public void testMapProperty() {
844+
createJavaUnit("Pojo",
845+
"interface Pojo {\n" +
846+
" java.util.Map<String, ? extends java.lang.Number> getMap();\n" +
847+
"}\n");
848+
849+
String contents =
850+
"@groovy.transform.TypeChecked\n" +
851+
"void test(Pojo pojo) {\n" +
852+
" def result = pojo.map.name\n" + // exercises StaticTypeCheckingVisitor#getTypeForMapExpression
853+
"}\n";
854+
assertType(contents, "map", "java.util.Map<java.lang.String,? extends java.lang.Number>");
855+
assertType(contents, "result", "java.lang.Number");
856+
}
857+
797858
@Test
798859
public void testBoolean1() {
799860
assertType("!x", "java.lang.Boolean");

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

+23
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,29 @@ public void testTypeChecked9821() {
550550
runNegativeTest(sources, "");
551551
}
552552

553+
@Test
554+
public void testTypeChecked9821a() {
555+
//@formatter:off
556+
String[] sources = {
557+
"Main.groovy",
558+
"@groovy.transform.TypeChecked\n" +
559+
"def test(A a) {\n" +
560+
" a.bees.c\n" +
561+
"}\n",
562+
563+
"Types.java",
564+
"interface A {\n" +
565+
" java.util.List<? extends B> getBees();\n" +
566+
"}\n" +
567+
"interface B {\n" +
568+
" Object getC();\n" +
569+
"}\n",
570+
};
571+
//@formatter:on
572+
573+
runNegativeTest(sources, "");
574+
}
575+
553576
@Test
554577
public void testTypeChecked9822() {
555578
//@formatter:off

base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+18-4
Original file line numberDiff line numberDiff line change
@@ -1768,24 +1768,30 @@ private ClassNode getTypeForSpreadExpression(ClassNode testClass, ClassNode obje
17681768
AtomicReference<ClassNode> result = new AtomicReference<ClassNode>();
17691769
if (existsProperty(subExp, true, new PropertyLookupVisitor(result))) {
17701770
ClassNode intf = LIST_TYPE.getPlainNodeReference();
1771-
intf.setGenericsTypes(new GenericsType[]{new GenericsType(getWrapper(result.get()))});
1771+
intf.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(result.get()))});
17721772
return intf;
17731773
}
17741774
return null;
17751775
}
17761776

17771777
private ClassNode getTypeForListPropertyExpression(ClassNode testClass, ClassNode objectExpressionType, PropertyExpression pexp) {
17781778
if (!implementsInterfaceOrIsSubclassOf(testClass, LIST_TYPE)) return null;
1779+
/* GRECLIPSE edit -- GROOVY-9821
17791780
ClassNode intf = GenericsUtils.parameterizeType(objectExpressionType, LIST_TYPE.getPlainNodeReference());
17801781
GenericsType[] types = intf.getGenericsTypes();
17811782
if (types == null || types.length != 1) return OBJECT_TYPE;
17821783
17831784
PropertyExpression subExp = new PropertyExpression(varX("{}", types[0].getType()), pexp.getPropertyAsString());
1785+
*/
1786+
GenericsType[] types = (testClass.equals(LIST_TYPE) ? testClass : GenericsUtils.parameterizeType(testClass, LIST_TYPE)).getGenericsTypes();
1787+
ClassNode itemType = (types != null && types.length == 1 ? getCombinedBoundType(types[0]) : OBJECT_TYPE);
1788+
1789+
PropertyExpression subExp = new PropertyExpression(varX("{}", itemType), pexp.getPropertyAsString());
1790+
// GRECLIPSE end
17841791
AtomicReference<ClassNode> result = new AtomicReference<ClassNode>();
17851792
if (existsProperty(subExp, true, new PropertyLookupVisitor(result))) {
1786-
intf = LIST_TYPE.getPlainNodeReference();
1787-
ClassNode itemType = result.get();
1788-
intf.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(itemType))});
1793+
ClassNode intf = LIST_TYPE.getPlainNodeReference();
1794+
intf.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(result.get()))});
17891795
return intf;
17901796
}
17911797
return null;
@@ -1794,11 +1800,15 @@ private ClassNode getTypeForListPropertyExpression(ClassNode testClass, ClassNod
17941800
private ClassNode getTypeForMapPropertyExpression(ClassNode testClass, ClassNode objectExpressionType, PropertyExpression pexp) {
17951801
if (!implementsInterfaceOrIsSubclassOf(testClass, MAP_TYPE)) return null;
17961802
ClassNode intf;
1803+
/* GRECLIPSE edit -- GROOVY-9821
17971804
if (objectExpressionType.getGenericsTypes() != null) {
17981805
intf = GenericsUtils.parameterizeType(objectExpressionType, MAP_TYPE.getPlainNodeReference());
17991806
} else {
18001807
intf = MAP_TYPE.getPlainNodeReference();
18011808
}
1809+
*/
1810+
intf = testClass.equals(MAP_TYPE) ? testClass : GenericsUtils.parameterizeType(testClass, MAP_TYPE);
1811+
// GRECLIPSE end
18021812
// 0 is the key, 1 is the value
18031813
GenericsType[] types = intf.getGenericsTypes();
18041814
if (types == null || types.length != 2) return OBJECT_TYPE;
@@ -1818,7 +1828,11 @@ private ClassNode getTypeForMapPropertyExpression(ClassNode testClass, ClassNode
18181828
addStaticTypeError("Spread operator on map only allows one of [key,value]", pexp);
18191829
}
18201830
} else {
1831+
/* GRECLIPSE edit -- GROOVY-9821
18211832
return types[1].getType();
1833+
*/
1834+
return getCombinedBoundType(types[1]);
1835+
// GRECLIPSE end
18221836
}
18231837
return null;
18241838
}

0 commit comments

Comments
 (0)