/*
* Copyright 2009-2017 the original author or authors.
*
* Licensed 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.eclipse.jdt.groovy.core.tests.basic;
import static org.eclipse.jdt.core.tests.util.GroovyUtils.isAtLeastGroovy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
import org.codehaus.jdt.groovy.internal.compiler.ast.GroovyCompilationUnitDeclaration;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.core.JavaCore;
import org.junit.Ignore;
import org.junit.Test;
import org.osgi.framework.Version;
public final class GenericsTests extends GroovyCompilerTestSuite {
public GenericsTests(long level) {
super(level);
}
private void runWarningFreeTest(String[] sources) {
runNegativeTest(sources, ""); // expect no compiler output (warnings or errors)
}
@Test
public void testGenericField() {
String[] sources = {
"A.groovy",
"class Foo {\n" +
" List<String> bar\n" +
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testGenericArrayField() {
String[] sources = {
"A.groovy",
"class Foo {\n" +
" List<String>[] bar\n" +
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testGenericParam() {
String[] sources = {
"A.groovy",
"class Foo {\n" +
" public void m(List<String> bar) {}\n" +
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testGenericArrayParam() {
String[] sources = {
"A.groovy",
"class Foo {\n" +
" public void m(List<String>[] bar) {}\n" +
"}"
};
if (!isAtLeastJava(JDK7)) {
runWarningFreeTest(sources);
} else {
runNegativeTest(sources,
"----------\n" +
"1. WARNING in A.groovy (at line 2)\n" +
"\tpublic void m(List<String>[] bar) {}\n" +
"\t ^^^^^^^^^^^^^^^^^^\n" +
"Type safety: Potential heap pollution via varargs parameter bar\n" +
"----------\n");
}
}
@Test
public void testGenericVaragsParam() {
String[] sources = {
"A.groovy",
"class Foo {\n" +
" public void m(List<String>... bar) {}\n" +
"}"
};
if (!isAtLeastJava(JDK7)) {
runWarningFreeTest(sources);
} else {
runNegativeTest(sources,
"----------\n" +
"1. WARNING in A.groovy (at line 2)\n" +
"\tpublic void m(List<String>... bar) {}\n" +
"\t ^^^^^^^^^^^^^^^^^^^\n" +
"Type safety: Potential heap pollution via varargs parameter bar\n" +
"----------\n");
}
}
@Test
public void testCallingGenericConstructors() {
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends A {\n" +
" public static void main(String[] argv) {\n" +
" new A(35);\n" +
" System.out.println('success');\n" +
" }\n" +
"}",
"p/A.java",
"package p;\n" +
"public class A {\n" +
" public <T> A(T t) {}\n" +
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testGenericsPositions_GRE267_1() {
String[] sources = {
"X.groovy",
"class X {\n" +
" Set<?> setone;\n" +
" Set<? extends Serializable> settwo;\n" +
" Set<? super Number> setthree;\n" +
" public static void main(String[]argv){ print 'y' }\n" +
"}",
// this Java class is for comparison - breakpoint on building type bindings and you can check the decls
"Y.java",
"import java.util.*;\n" +
"class Y {\n" +
" Set<?> a;\n" +
" Set<? extends java.io.Serializable> b;\n" +
" Set<? super Number> c;\n" +
"}"
};
runWarningFreeTest(sources);
GroovyCompilationUnitDeclaration decl = getCUDeclFor("X.groovy");
assertEquals("(12>14)Set<(16>16)?>", stringify(grabField(decl, "setone").type));
assertEquals("(29>31)Set<(33>54)? extends (43>54)Serializable>", stringify(grabField(decl, "settwo").type));
assertEquals("(67>69)Set<(71>84)? super (79>84)Number>", stringify(grabField(decl,"setthree").type));
}
@Test
public void testGenericsPositions_GRE267_2() {
String[] sources = {
"X.groovy",
"class X {\n" +
" Set<?> setone;\n" +
" Set<? extends java.io.Serializable> settwo;\n" +
" Set<? super java.lang.Thread> setthree;\n" +
" public static void main(String[]argv){ print 'y' }\n" +
"}"
};
runWarningFreeTest(sources);
GroovyCompilationUnitDeclaration decl = getCUDeclFor("X.groovy");
assertEquals("(12>14)Set<(16>16)?>", stringify(grabField(decl, "setone").type));
assertEquals("(29>31)Set<(33>62)? extends (43>62)(43>46)java.(48>49)io.(51>62)Serializable>", stringify(grabField(decl, "settwo").type));
assertEquals("(75>77)Set<(79>102)? super (87>102)(87>90)java.(92>95)lang.(97>102)Thread>", stringify(grabField(decl, "setthree").type));
}
@Test
public void testGenericsPositions_GRE267_3() {
String[] sources = {
"X.groovy",
"class X {\n" +
" Set<?> setone;\n" +
" Set<String[]> settwo;\n" +
" Set<String[][]> setthree;\n" +
" Set<java.lang.Thread[][][]> setfour;\n" +
" public static void main(String[]argv){ print 'y' }\n" +
"}",
"Y.java",
"import java.util.*;\n" +
"class Y {\n" +
" Set<String[]> a;\n" +
" Set<String[][]> b;\n" +
" Set<java.lang.Thread[][][]> c;\n" +
"}"
};
runWarningFreeTest(sources);
GroovyCompilationUnitDeclaration decl = getCUDeclFor("X.groovy");
assertEquals("(12>14)Set<(16>16)?>", stringify(grabField(decl, "setone").type));
assertEquals("(29>31)Set<(33>40 ose:38)String[]>", stringify(grabField(decl, "settwo").type));
assertEquals("(53>55)Set<(57>66 ose:62)String[][]>", stringify(grabField(decl, "setthree").type));
//assertEquals("(81>83)Set<(85>106)(85>88)java.(90>93)lang.(95>100)Thread[][][]>", stringify(grabField(decl, "setfour")));
}
@Test
public void testGenericsPositions_4_GRE267() {
String[] sources = {
"X.groovy",
"class X {\n" +
" java.util.Set<?> setone;\n" +
" java.util.Set<? extends Serializable> settwo;\n" +
" java.util.Set<? super Number> setthree;\n" +
" public static void main(String[]argv){ print 'y' }\n" +
"}"
};
runWarningFreeTest(sources);
GroovyCompilationUnitDeclaration decl = getCUDeclFor("X.groovy");
assertEquals("(12>24)(12>15)java.(17>20)util.(22>24)Set<(26>26)?>", stringify(grabField(decl, "setone").type));
assertEquals("(39>51)(39>42)java.(44>47)util.(49>51)Set<(53>74)? extends (63>74)Serializable>", stringify(grabField(decl, "settwo").type));
assertEquals("(87>99)(87>90)java.(92>95)util.(97>99)Set<(101>114)? super (109>114)Number>", stringify(grabField(decl, "setthree").type));
}
@Test
public void testGenericsPositions_5_GRE267() {
String[] sources = {
"X.groovy",
"class X {\n" +
" java.util.Set<?> setone;\n" +
" java.util.Set<? extends java.io.Serializable> settwo;\n" +
" java.util.Set<? super java.lang.Thread> setthree;\n" +
" public static void main(String[]argv){ print 'y' }\n" +
"}"
};
runWarningFreeTest(sources);
GroovyCompilationUnitDeclaration decl = getCUDeclFor("X.groovy");
assertEquals("(12>24)(12>15)java.(17>20)util.(22>24)Set<(26>26)?>", stringify(grabField(decl, "setone").type));
assertEquals("(39>51)(39>42)java.(44>47)util.(49>51)Set<(53>82)? extends (63>82)(63>66)java.(68>69)io.(71>82)Serializable>", stringify(grabField(decl, "settwo").type));
assertEquals("(95>107)(95>98)java.(100>103)util.(105>107)Set<(109>132)? super (117>132)(117>120)java.(122>125)lang.(127>132)Thread>", stringify(grabField(decl, "setthree").type));
}
@Test @Ignore
public void testGenericsPositions_6_GRE267() {
// FIXASC check tests after porting to recent 1.7 compiler
// Multiple generified components in a reference
String[] sources = {
"X.groovy",
"class X {\n" +
" One<String,Integer>.Two<Boolean> whoa;\n" +
" java.util.Set<? extends java.io.Serializable> settwo;\n" +
" java.util.Set<? super java.lang.Number> setthree;\n" +
" public static void main(String[]argv){ print 'y' }\n" +
"}",
"One.java",
"public class One<A,B> {\n" +
" class Two<C> {\n" +
" }\n" +
"}"
};
runWarningFreeTest(sources);
GroovyCompilationUnitDeclaration decl = getCUDeclFor("X.groovy");
assertEquals("(12>14)Set<(16>16)?>", stringify(grabField(decl, "one").type));
assertEquals("(29>31)Set<(33>33)? extends (43>61)(43>47)java.(48>50)io.(51>61)Serializable>", stringify(grabField(decl, "settwo").type));
assertEquals("(67>69)Set<(71>71)? super (79>84)Number>", stringify(grabField(decl, "setthree").type));
}
@Test
public void testGenericsPositions_7_GRE267() {
String[] sources = {
"X.groovy",
"class X {\n" +
" java.util.Set<?> setone;\n" +
" java.util.Set<String[]> settwo;\n" +
" java.util.Set<java.lang.Number[][][]> setthree;\n" +
" public static void main(String[]argv){ print 'y' }\n" +
"}"
};
runWarningFreeTest(sources);
GroovyCompilationUnitDeclaration decl = getCUDeclFor("X.groovy");
assertEquals("(12>24)(12>15)java.(17>20)util.(22>24)Set<(26>26)?>", stringify(grabField(decl, "setone").type));
assertEquals("(39>51)(39>42)java.(44>47)util.(49>51)Set<(53>60 ose:58)String[]>", stringify(grabField(decl, "settwo").type));
assertEquals("(73>85)(73>76)java.(78>81)util.(83>85)Set<(87>108)(87>90)java.(92>95)lang.(97>102)Number[][][]>", stringify(grabField(decl, "setthree").type));
}
@Test
public void testGenericsPositions_8_GRE267() {
String[] sources = {
"X.groovy",
"class X {\n" +
" Set<Map.Entry<String,List<String>>> foo;\n" +
" public static void main(String[]argv){ print 'y' }\n" +
"}"
};
runWarningFreeTest(sources);
GroovyCompilationUnitDeclaration decl = getCUDeclFor("X.groovy");
assertEquals("(12>14)Set<(16>24)(16>18)Map.(20>24)Entry<(26>31)String(33>36)List<(38>43)String>>>", stringify(grabField(decl, "foo").type));
}
@Test
public void testGenericsPositions_9_GRE267() {
String[] sources = {
"X.groovy",
"class X {\n" +
" Map.Entry<String,List<String>> foo;\n" +
" public static void main(String[]argv){ print 'y' }\n" +
"}"
};
runWarningFreeTest(sources);
GroovyCompilationUnitDeclaration decl = getCUDeclFor("X.groovy");
assertEquals("(12>20)(12>14)Map.(16>20)Entry<(22>27)String(29>32)List<(34>39)String>>", stringify(grabField(decl, "foo").type));
}
@Test
public void testGenericsAndGroovyJava_GRE278_1() {
String[] sources = {
"p/Field.java",
"package test;\n" +
"public interface Field<T> extends Comparable<T> {\n" +
" public String getFieldTypeName();\n" +
" public String getName();\n" +
" public T getValue();\n" +
" public void setValue(T o);\n" +
"}",
"p/Structure.java",
"package test;\n" +
"import java.util.Map;\n" +
"import java.nio.ByteBuffer;\n" +
"public interface Structure extends Map<String, Field<?>> {\n" +
" public void reset();\n" +
" public void setup(ByteBuffer clientBuff);\n" +
"}",
"p/StructureBase.groovy",
"package test;\n" +
"import java.nio.ByteBuffer;\n" +
"@SuppressWarnings('rawtypes')\n" +
"public class StructureBase implements Structure {\n" +
" protected final Structure str = null;\n" +
" StructureBase(Structure struct){\n" +
" this.str = struct;\n" +
" }\n" +
" public void clear() {\n" +
" str.clear()\n" +
" }\n" +
" public boolean containsKey(Object arg0) {\n" +
" return str.containsKey(arg0);\n" +
" }\n" +
" public boolean containsValue(Object arg0) {\n" +
" return str.containsValue(arg0);\n" +
" }\n" +
" public Set<java.util.Map.Entry<String, Field<?>>> entrySet() {\n" +
" return Collections.unmodifiableSet(str.entrySet());\n" +
" }\n" +
" public Field<?> get(Object arg0) {\n" +
" return str.get(arg0);\n" +
" }\n" +
" public boolean isEmpty() {\n" +
" return str.isEmpty();\n" +
" }\n" +
" public Set<String> keySet() {\n" +
" return Collections.unmodifiableSet(str.keySet());\n" +
" }\n" +
" public Field<?> put(String arg0, Field<?> arg1) {\n" +
" return str.put(arg0, arg1);\n" +
" }\n" +
" //public Object put(Object key, Object value) {\n" +
" // return str.put(key, value)\n" +
" //}\n" +
" public void putAll(Map<? extends String, ? extends Field<?>> arg0) {\n" +
" str.putAll(arg0);\n" +
" }\n" +
" public Field<?> remove(Object key) {\n" +
" return str.remove(key);\n" +
" }\n" +
" public int size() {\n" +
" return str.size();\n" +
" }\n" +
" public Collection<Field<?>> values() {\n" +
" return Collections.unmodifiableCollection(str.values());\n" +
" }\n" +
" //public void reset(){\n" +
" // str.reset();\n" +
" //}\n" +
" //public void setup(ByteBuffer buff) {\n" +
" // str.setup(buff);\n" +
" //}\n" +
"}",
"p/StructureBaseTest.groovy",
"package test;\n" +
"public class StructureBaseTest {\n" +
" public static void main(String[] args) {\n" +
" Structure str = new StructureBase(new TestStructure());\n" +
" str.put('test', new TestField());\n" +
" def content = str.get('test');\n" +
" if (!TestField.FIELD_NAME.equals(str.get('test').name)) {\n" +
" System.out.println('Failed');\n" +
" }\n" +
" }\n" +
"}",
"p/TestField.java",
"package test;\n" +
"public class TestField implements Field<String> {\n" +
" public static final String FIELD_NAME = \"Test\";\n" +
" private StringBuilder buffer = new StringBuilder();\n" +
" private String value = null;\n" +
" public String getFieldTypeName() {\n" +
" return String.class.getSimpleName();\n" +
" }\n" +
" public String getName() {\n" +
" return FIELD_NAME;\n" +
" }\n" +
" public String getValue() {\n" +
" if (null == value)\n" +
" value = buffer.toString();\n" +
" return value;\n" +
" }\n" +
" public void setValue(String o) {\n" +
" value = o;\n" +
" buffer.replace(0, buffer.length(), o);\n" +
" }\n" +
" public int compareTo(String arg0) {\n" +
" return getValue().compareTo(arg0);\n" +
" }\n" +
"}",
"p/TestStructure.java",
"package test;\n" +
"import java.nio.ByteBuffer;\n" +
"import java.util.HashMap;\n" +
"import java.util.Map;\n" +
"@SuppressWarnings(\"serial\")\n" +
"public class TestStructure extends HashMap<String, Field<?>> implements Structure {\n" +
" public void reset() {\n" +
" // TODO Auto-generated method stub\n" +
" }\n" +
" public void setup(ByteBuffer clientBuff) {\n" +
" // TODO Auto-generated method stub\n" +
" }\n" +
" public Field<?> put(String arg0, Field<?> arg1) {\n" +
" return super.put(arg0, arg1);\n" +
"}\n" +
" public void putAll(Map<? extends String, ? extends Field<?>> arg0) {\n" +
" super.putAll(arg0);\n" +
" }\n" +
"}"
};
runNegativeTest(sources,
"----------\n" +
"1. ERROR in p\\StructureBase.groovy (at line 4)\n" +
"\tpublic class StructureBase implements Structure {\n" +
"\t ^^^^^^^^^^^^^\n" +
"Groovy:Can\'t have an abstract method in a non-abstract class. The class \'test.StructureBase\' must be declared abstract or the method \'void setup(java.nio.ByteBuffer)\' must be implemented.\n" +
"----------\n" +
"2. ERROR in p\\StructureBase.groovy (at line 4)\n" +
"\tpublic class StructureBase implements Structure {\n" +
"\t ^^^^^^^^^^^^^\n" +
"Groovy:Can\'t have an abstract method in a non-abstract class. The class \'test.StructureBase\' must be declared abstract or the method \'void reset()\' must be implemented.\n" +
"----------\n");
}
@Test
public void testGenericsAndGroovyJava_GRE278_2() {
String[] sources = {
"Main.java",
"public class Main {\n" +
" public static void main(String[]argv) {\n" +
" test.StructureBaseTest.main(argv);\n" +
" }\n" +
"}",
"p/Field.java",
"package test;\n" +
"public interface Field<T> extends Comparable<T> {\n" +
" public String getFieldTypeName();\n" +
" public String getName();\n" +
" public T getValue();\n" +
" public void setValue(T o);\n" +
"}",
"p/Structure.java",
"package test;\n" +
"import java.util.Map;\n" +
"import java.nio.ByteBuffer;\n" +
"public interface Structure extends Map<String, Field<?>> {\n" +
" public void reset();\n" +
" public void setup(ByteBuffer clientBuff);\n" +
"}",
"p/StructureBase.groovy",
"package test;\n" +
"import java.nio.ByteBuffer;\n" +
"public class StructureBase implements Structure {\n" +
" protected final Structure str = null;\n" +
" StructureBase(Structure struct){\n" +
" this.str = struct;\n" +
" }\n" +
" public void clear() {\n" +
" str.clear()\n" +
" }\n" +
" public boolean containsKey(Object arg0) {\n" +
" return str.containsKey(arg0);\n" +
" }\n" +
" public boolean containsValue(Object arg0) {\n" +
" return str.containsValue(arg0);\n" +
" }\n" +
" public Set<java.util.Map.Entry<String, Field<?>>> entrySet() {\n" +
" return Collections.unmodifiableSet(str.entrySet());\n" +
" }\n" +
" public Field<?> get(Object arg0) {\n" +
" return str.get(arg0);\n" +
" }\n" +
" public boolean isEmpty() {\n" +
" return str.isEmpty();\n" +
" }\n" +
" public Set<String> keySet() {\n" +
" return Collections.unmodifiableSet(str.keySet());\n" +
" }\n" +
" public Field<?> put(String arg0, Field<?> arg1) {\n" +
" return str.put(arg0, arg1);\n" +
" }\n" +
" public void putAll(Map<? extends String, ? extends Field<?>> arg0) {\n" +
" str.putAll(arg0);\n" +
" }\n" +
" public Field<?> remove(Object key) {\n" +
" return str.remove(key);\n" +
" }\n" +
" public int size() {\n" +
" return str.size();\n" +
" }\n" +
" public Collection<Field<?>> values() {\n" +
" return Collections.unmodifiableCollection(str.values());\n" +
" }\n" +
" public void reset() {\n" +
" str.reset();\n" +
" }\n" +
" public void setup(ByteBuffer buff) {\n" +
" str.setup(buff);\n" +
" }\n" +
"}",
"p/StructureBaseTest.groovy",
"package test;\n" +
"public class StructureBaseTest {\n" +
" public static void main(String[] args) {\n" +
" Structure str = new StructureBase(new TestStructure());\n" +
" str.put('test', new TestField());\n" +
" def content = str.get('test');\n" +
" if (!TestField.FIELD_NAME.equals(str.get('test').name)) {\n" +
" println('Failed');\n" +
" }\n" +
" }\n" +
"}",
"p/TestField.java",
"package test;\n" +
"public class TestField implements Field<String> {\n" +
" public static final String FIELD_NAME = \"Test\";\n" +
" private StringBuilder buffer = new StringBuilder();\n" +
" private String value = null;\n" +
" public String getFieldTypeName() {\n" +
" return String.class.getSimpleName();\n" +
" }\n" +
" public String getName() {\n" +
" return FIELD_NAME;\n" +
" }\n" +
" public String getValue() {\n" +
" if (null == value)\n" +
" value = buffer.toString();\n" +
" return value;\n" +
" }\n" +
" public void setValue(String o) {\n" +
" value = o;\n" +
" buffer.replace(0, buffer.length(), o);\n" +
" }\n" +
" public int compareTo(String arg0) {\n" +
" return getValue().compareTo(arg0);\n" +
" }\n" +
"}",
"p/TestStructure.java",
"package test;\n" +
"import java.nio.ByteBuffer;\n" +
"import java.util.HashMap;\n" +
"import java.util.Map;\n" +
"@SuppressWarnings(\"serial\")\n" +
"public class TestStructure extends HashMap<String, Field<?>> implements Structure {\n" +
" public void reset() {\n" +
" // TODO Auto-generated method stub\n" +
" }\n" +
" public void setup(ByteBuffer clientBuff) {\n" +
" // TODO Auto-generated method stub\n" +
" }\n" +
" public Field<?> put(String arg0, Field<?> arg1) {\n" +
" return super.put(arg0, arg1);\n" +
"}\n" +
" public void putAll(Map<? extends String, ? extends Field<?>> arg0) {\n" +
" super.putAll(arg0);\n" +
" }\n" +
"}"
};
runWarningFreeTest(sources);
}
@Test @Ignore("when GROOVY-5861 is fixed we can enable this test")
public void testGenericsAndGroovyJava_GRE278_3() {
String[] sources = {
"p/Field.java",
"package test;\n" +
"public interface Field<T extends java.io.Serializable> extends Comparable<T> {\n" +
"}",
"p/StructureBase.groovy",
"package test;\n" +
"public class StructureBase {\n" +
" public Field<?> get(Object arg0) {\n" +
" return str.get(arg0);\n" +
" }\n" +
"}"
};
runWarningFreeTest(sources);
}
@Test @Ignore("when GROOVY-5861 is fixed we can enable this test")
public void testGenericsAndGroovyJava_GRE278_3a() {
String[] sources = {
"Main.java",
"public class Main {\n" +
" public static void main(String[]argv) {\n" +
" test.StructureBaseTest.main(argv);\n" +
" }\n" +
"}",
"p/Field.java",
"package test;\n" +
"public interface Field<T extends java.io.Serializable> extends Comparable<T> {\n" +
" public String getFieldTypeName();\n" +
" public String getName();\n" +
" public T getValue();\n" +
" public void setValue(T o);\n" +
"}",
"p/Structure.java",
"package test;\n" +
"import java.util.Map;\n" +
"import java.nio.ByteBuffer;\n" +
"public interface Structure extends Map<String, Field<?>> {\n" +
" public void reset();\n" +
" public void setup(ByteBuffer clientBuff);\n" +
"}",
"p/StructureBase.groovy",
"package test;\n" +
"import java.nio.ByteBuffer;\n" +
"@SuppressWarnings(\"unchecked\")\n" +
"public class StructureBase implements Structure {\n" +
" protected final Structure str = null;\n" +
" StructureBase(Structure struct) {\n" +
" this.str = struct;\n" +
" }\n" +
" public void clear() {\n" +
" str.clear()\n" +
" }\n" +
" public boolean containsKey(Object arg0) {\n" +
" return str.containsKey(arg0);\n"+
" }\n" +
" public boolean containsValue(Object arg0) {\n" +
" return str.containsValue(arg0);\n" +
" }\n" +
" public Set<java.util.Map.Entry<String, Field<?>>> entrySet() {\n" +
" return Collections.unmodifiableSet(str.entrySet());\n" +
" }\n" +
" public Field<?> get(Object arg0) {\n" +
" return str.get(arg0);\n" +
" }\n" +
" public boolean isEmpty() {\n" +
" return str.isEmpty();\n" +
" }\n" +
" public Set<String> keySet() {\n" +
" return Collections.unmodifiableSet(str.keySet());\n" +
" }\n" +
" public Field<?> put(String arg0, Field<?> arg1) {\n" +
" return str.put(arg0, arg1);\n" +
" }\n" +
" public Object put(Object key, Object value) {\n" +
" return str.put(key, value)\n" +
" }\n" +
" public void putAll(Map<? extends String, ? extends Field<?>> arg0) {\n" +
" str.putAll(arg0);\n" +
" }\n" +
" public Field<?> remove(Object key) {\n" +
" return str.remove(key);\n" +
" }\n" +
" public int size() {\n" +
" return str.size();\n" +
" }\n" +
" public Collection<Field<?>> values() {\n" +
" return Collections.unmodifiableCollection(str.values());\n" +
" }\n" +
" public void reset(){\n" +
" str.reset();\n" +
" }\n" +
" public void setup(ByteBuffer buff) {\n" +
" str.setup(buff);\n" +
" }\n" +
"}",
"p/StructureBaseTest.groovy",
"package test;\n" +
"public class StructureBaseTest {\n" +
" public static void main(String[] args) {\n" +
" Structure str = new StructureBase(new TestStructure());\n" +
" str.put('test', new TestField());\n" +
" def content = str.get('test');\n" +
" if (!TestField.FIELD_NAME.equals(str.get('test').name)) {\n" +
" System.out.println('Failed');\n" +
" } else {\n" +
" System.out.println('Success');\n" +
" }\n" +
" }\n" +
"}",
"p/TestField.java",
"package test;\n" +
"public class TestField implements Field<String> {\n" +
" public static final String FIELD_NAME = \"Test\";\n" +
" private StringBuilder buffer = new StringBuilder();\n" +
" private String value = null;\n" +
" public String getFieldTypeName() {\n" +
" return String.class.getSimpleName();\n" +
" }\n" +
" public String getName() {\n" +
" return FIELD_NAME;\n" +
" }\n" +
" public String getValue() {\n" +
" if (null == value)\n" +
" value = buffer.toString();\n" +
" return value;\n" +
" }\n" +
" public void setValue(String o) {\n" +
" value = o;\n" +
" buffer.replace(0, buffer.length(), o);\n" +
" }\n" +
" public int compareTo(String arg0) {\n" +
" return getValue().compareTo(arg0);\n" +
" }\n" +
"}",
"p/TestStructure.java",
"package test;\n" +
"import java.nio.ByteBuffer;\n" +
"import java.util.HashMap;\n" +
"import java.util.Map;\n" +
"@SuppressWarnings(\"serial\")\n" +
"public class TestStructure extends HashMap<String, Field<?>> implements Structure {\n" +
" public void reset() {\n" +
" }\n" +
" public void setup(ByteBuffer clientBuff) {\n" +
" }\n" +
" public Field<?> put(String arg0, Field<?> arg1) {\n" +
" return super.put(arg0, arg1);\n" +
" }\n" +
" public void putAll(Map<? extends String, ? extends Field<?>> arg0) {\n" +
" super.putAll(arg0);\n" +
" }\n" +
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testGenericsAndGroovyJava_GRE278_4() {
String[] sources = {
"Main.groovy",
"public class Main {\n"+
" public static void main(String[]argv) {\n"+
" def content = new StructureBase().get('test');\n"+
" print 'test';\n"+
" }\n"+
"}",
"MyMap.java",
"public interface MyMap<A,B> {" +
" B get(Object key);\n" +
"}",
"Structure.java",
"public interface Structure extends MyMap<String, Integer> {\n"+
"}",
"StructureBase.groovy",
"public class StructureBase implements Structure {\n"+
" public Integer get(Object key) {\n"+
" return null;\n"+
" }\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testGenericFields_JcallingG() {
String[] sources = {
"p/Code.java",
"package p;\n"+
"public class Code extends G<String> {\n"+
" public static void main(String[] argv) {\n"+
" Code c = new Code();\n"+
" c.setField(\"success\");\n"+
" System.out.print(c.getField());\n"+
" }\n"+
"}\n",
"p/G.groovy",
"package p;\n"+
"class G<T> { T field; }"
};
runWarningFreeTest(sources);
}
@Test
public void testGenericFields_GcallingJ() {
String[] sources = {
"p/Code.groovy",
"package p;\n"+
"public class Code extends G<String> {\n"+
" public static void main(String[] argv) {\n"+
" Code c = new Code();\n"+
" c.field=\"success\";\n"+
" System.out.print(c.field);\n"+
" }\n"+
"}\n",
"p/G.java",
"package p;\n"+
"class G<T> { public T field; }" // TODO why must this be public for the groovy code to see it? If non public should it be instead defined as a property on the JDTClassNode rather than a field?
};
runWarningFreeTest(sources);
}
@Test
public void testGroovyPropertyAccessorsGenerics() {
String[] sources = {
"p/C.java",
"package p;\n" +
"public class C {\n"+
" public static void main(String[] argv) {\n"+
" G o = new G();\n"+
" for (Integer s: o.getB()) {\n"+
" System.out.print(s);\n"+
" }\n"+
" }\n"+
"}\n",
"p/G.groovy",
"package p;\n"+
"public class G {\n" +
" List<Integer> b = [1,2,3]\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testGroovyGenerics() {
// GroovyBug: this surfaced the problem that the generics declarations are checked before resolution is complete -
// had to change CompilationUnit so that resolve and checkGenerics are different stages in the SEMANTIC_ANALYSIS phase
// otherwise it depends on whether the super type is resolved before the subtype has its generic decl checked
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends A<String> {\n" +
" public static void main(String[] argv) {\n"+
" new B();\n"+
" System.out.println( \"success\");\n"+
" }\n"+
"}\n",
"p/A.groovy",
"package p;\n" +
"public class A<T> {}\n"
};
runWarningFreeTest(sources);
}
@Test
public void testGreclipse1563() {
assumeTrue(isAtLeastGroovy(20));
String[] sources = {
"Inter.java",
"package ab;\n"+
"public interface Inter {\n"+
" public Number getItem(Object itemId);\n"+
"}\n",
"Clazz.java",
"package ab;\n"+
"public abstract class Clazz<ITEM extends Number> implements Inter {\n"+
" public ITEM getItem(Object itemId) {\n"+
" return null;\n"+
" }\n"+
"}\n",
"GClazz.groovy",
"package ab;\n"+
"class GClazz extends Clazz<Number> {}"
};
runWarningFreeTest(sources);
}
@Test
public void testGreclipse1563_2() {
assumeTrue(isAtLeastGroovy(20));
String[] sources = {
"Clazz.java",
"package ab;\n"+
"public abstract class Clazz<ITEM extends MyItem> implements Inter {\n"+
" public ITEM getItem(Object itemId) {\n"+
" return null;\n"+
" }\n"+
"}\n",
"Inter.java",
"package ab;\n"+
"public interface Inter {\n"+
" public MyItem getItem(Object itemId);\n"+
"}\n",
"MyItem.java",
"package ab;\n"+
"public class MyItem {}\n",
"GClazz.groovy",
"package ab;\n"+
"class GClazz extends Clazz<MyItem> {}"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_JavaExtendsGroovy() {
// WMTW: GroovyCompilationUnit builds a correct representation of the groovy type A
String[] sources = {
"p/B.java",
"package p;\n" +
"public class B extends A<String> {\n" +
" public static void main(String[] argv) {\n"+
" new B();\n"+
" System.out.println( \"success\");\n"+
" }\n"+
"}\n",
"p/A.groovy",
"package p;\n" +
"public class A<T> {}\n"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava() {
// WMTW: JDT ClassNode builds a correct groovy representation of the A type
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends A<String> {\n" +
" public static void main(String[] argv) {\n"+
" new B()\n"+
" println 'success'\n"+
" }\n"+
"}\n",
"p/A.java",
"package p;\n" +
"public class A<T> {public void set(T t) { }}\n"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava2() {
// test when the upper bound is not just 'Object'
// WMTW: notice I and Impl are classes and not interfaces, because right now only the superclass stuff is set up correctly for nodes.
// In order for no error to occur we have to override getUnresolvedSuperClass() in our JDTClassNode so that the code in
// GenericsVisitor.checkGenericsUsage() correctly determines Impl isDerivedFrom I
// the rule seems to be coming out that there is no redirection from JDTClassNode, they are absolute
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends A<Impl> {\n" +
" public static void main(String[] argv) {\n"+
" new B()\n"+
" println 'success'\n"+
" }\n"+
"}\n",
"p/I.java",
"package p; class I {}",
"p/Impl.java",
"package p; class Impl extends I {}",
"p/A.java",
"package p;\n" +
"public class A<T extends I> {}\n"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava2a() {
// TODO create more variations around mixing types up (including generics bounds)
// variation of above - the interface type is a java file and not a groovy file
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends A<Impl> {\n" +
" public static void main(String[] argv) {\n"+
" new B()\n"+
" println 'success'\n"+
" }\n"+
"}\n",
"p/I.java",
"package p; interface I {}", // class->interface
"p/Impl.java",
"package p; class Impl implements I {}",
"p/A.java",
"package p;\n" +
"public class A<T extends I> {}\n"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava2b() {
// WMTW: JDTClassNode correctly initializes interfaces based on binding interfaces
// It needs the interface set for Impl to be defined correctly so that groovy can determine Impl extends I
// test when the upper bound is not just 'Object'
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends A<Impl> {\n" +
" public static void main(String[] argv) {\n"+
" new B()\n"+
" println 'success'\n"+
" }\n"+
"}\n",
"p/I.groovy", // java->groovy
"package p; interface I {}", // class->interface
"p/Impl.groovy",
"package p; class Impl implements I {}",
"p/A.java",
"package p;\n" +
"public class A<T extends I> {}\n"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava3() {
// GRECLIPSE-430: the declaration of B violates the 'T extends I' specification of A
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends A<String> {\n" +
" public static void main(String[] argv) {\n"+
" println 'success'\n"+
" }\n"+
"}\n",
"p/I.java",
"package p; interface I {}",
"p/Impl.java",
"package p; class Impl implements I {}",
"p/A.java",
"package p;\n" +
"public class A<T extends I> {}\n"
};
runNegativeTest(sources,
"----------\n" +
"1. ERROR in p\\B.groovy (at line 2)\n" +
"\tpublic class B extends A<String> {\n" +
"\t ^\n" +
"Groovy:The type String is not a valid substitute for the bounded parameter <T extends p.I>\n" +
"----------\n");
}
@Test
public void testExtendingGenerics_GroovyExtendsJava4() {
assumeTrue(!isAtLeastJava(JDK8));
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends java.util.ArrayList<String> {\n" +
" public static void main(String[] argv) {\n"+
" B b = new B()\n"+
" b.add('abc')\n"+
" print b.get(0)\n"+
" println 'success'\n"+
" }\n"+
" void print(String msg) { print msg; }\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava5() {
assumeTrue(!isAtLeastJava(JDK8));
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends java.util.ArrayList<String> {\n" +
" public static void main(String[] argv) {\n"+
" new B()\n"+
" println 'success'\n"+
" }\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava5a() {
assumeTrue(!isAtLeastJava(JDK8));
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends ArrayList<String> {\n" +
" public static void main(String[] argv) {\n"+
" new B()\n"+
" println 'success'\n"+
" }\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava6() {
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends A<String> {\n" +
" public static void main(String[] argv) {\n"+
" new B()\n"+
" println 'success'\n"+
" }\n"+
"}\n",
"p/A.java",
"package p;\n" +
"public class A<T> {public void set(T t) { }}\n"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava7() {
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends q.A<String> {\n" +
" public static void main(String[] argv) {\n"+
" new B().set(\"abc\");\n"+
" System.out.println( \"success\");\n"+
" }\n"+
"}\n",
"q/A.java",
"package q;\n" +
"public class A<T> {public void set(T t) { }}\n"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava8() {
// arrays
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends A<int[]> {\n" +
" public static void main(String[] argv) {\n"+
" new B().foo([1,2,3]);\n"+
" System.out.println( \"success\");\n"+
" }\n"+
"}\n",
"p/A.java",
"package p;\n" +
"public class A<T extends Object> {\n"+
" public void foo(T t) {}\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava9() {
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends C {\n" +
" public static void main(String[] argv) {\n"+
" new B().foo([1,2,3]);\n"+
" System.out.println( \"success\");\n"+
" }\n"+
"}\n",
"p/C.java",
"package p;\n"+
"public class C extends A<int[]> {}\n",
"p/A.java",
"package p;\n" +
"public class A<T extends Object> {\n"+
" public void foo(T t) {}\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testExtendingGenerics_GroovyExtendsJava10() {
String[] sources = {
"p/B.groovy",
"package p;\n" +
"public class B extends C<String> {\n" +
" public static void main(String[] argv) {\n"+
" new B().foo([1,2,3],\"hello\");\n"+
" System.out.println( \"success\");\n"+
" }\n"+
"}",
"p/C.java",
"package p;\n"+
"public class C<Q> extends A<int[],Q> {\n" +
"}",
"p/A.java",
"package p;\n" +
"public class A<T extends Object,R> {\n"+
" public void foo(T t, R r) {}\n"+
"}"
};
runWarningFreeTest(sources);
}
/**
* https://issuetracker.springsource.com/browse/STS-3930
*
* @see org.codehaus.jdt.groovy.internal.compiler.ast.GroovyClassScope#buildFieldsAndMethods()
*/
@Test
public void testExtendingGenerics_GroovyExtendsJava11() {
if (JavaCore.getPlugin().getBundle().getVersion().compareTo(Version.parseVersion("3.10")) < 0) return;
String[] sources = {
"Groovy.groovy",
"class Groovy {\n" +
" static <T> List<T> method(Class<T> factory, ClassLoader loader = Groovy.class.classLoader) {\n" +
" null\n" +
" }\n" +
"}",
"Java.java",
"public class Java {\n" +
" public static void method() {\n" +
" Groovy.method(Java.class);\n" +
" }\n" +
"}"
};
runWarningFreeTest(sources);
}
/**
* https://github.com/groovy/groovy-eclipse/issues/144
*
* java.lang.NullPointerException
* at org.codehaus.jdt.groovy.internal.compiler.ast.GroovyClassScope.fixupTypeParameters(GroovyClassScope.java:559)
*/
@Test
public void testExtendingGenerics_GroovyExtendsJava12() {
assumeTrue(isAtLeastGroovy(20));
String[] sources = {
"Template.java",
"public interface Template<S> {\n" +
" interface Callback<T,S> {\n" +
" T apply(S context);\n" +
" }\n" +
" <T> T execute(Callback<T,S> callback);\n" +
"}",
"TemplateImpl.groovy",
"@groovy.transform.CompileStatic\n" +
"class TemplateImpl<S> implements Template<S> {\n" +
" @Override\n" +
" public <T> T execute(Callback<T,S> callback) {\n" +
" return callback.apply(null)\n" +
" }\n" +
"}"
};
runWarningFreeTest(sources);
}
/**
* https://github.com/groovy/groovy-eclipse/issues/148
*/
@Test
public void testExtendingGenerics_GroovyExtendsJava13() {
String[] sources = {
"A.java",
"public interface A<Q extends A<? super Q>> {\n" +
"}",
"B.groovy",
"class B {\n" +
" public void test(A<?> a) {\n" +
" }\n" +
"}"
};
runWarningFreeTest(sources);
}
/**
* https://github.com/groovy/groovy-eclipse/issues/174
*
* java.lang.NullPointerException
* at com.sun.beans.TypeResolver.resolve(TypeResolver.java:203)
* at com.sun.beans.TypeResolver.resolve(TypeResolver.java:162)
* at com.sun.beans.TypeResolver.resolveInClass(TypeResolver.java:81)
* at java.beans.FeatureDescriptor.getReturnType(FeatureDescriptor.java:370)
* at java.beans.Introspector.getTargetEventInfo(Introspector.java:1052)
* at java.beans.Introspector.getBeanInfo(Introspector.java:427)
* at java.beans.Introspector.getBeanInfo(Introspector.java:173)
* at groovy.lang.MetaClassImpl$15.run(MetaClassImpl.java:3290)
* at java.security.AccessController.doPrivileged(Native Method)
* at groovy.lang.MetaClassImpl.addProperties(MetaClassImpl.java:3288)
* at groovy.lang.MetaClassImpl.initialize(MetaClassImpl.java:3265)
* at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:254)
* at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:285)
* at MIData.$getStaticMetaClass(MIData.groovy)
* at MIData.<init>(MIData.groovy)
* at Main.main(Main.groovy:3)
*/
@Test @Ignore
public void testExtendingGenerics_GroovyExtendsJava14() {
assumeTrue(isAtLeastGroovy(20));
String[] sources = {
"Main.groovy",
"@groovy.transform.CompileStatic class Main {\n" +
" public static void main(String[] args) {\n" +
" def data = new MIData('V', 1, 'B')\n" +
" print 'no error'\n" +
" }\n" +
"}",
"MultiIndexed.java",
"public interface MultiIndexed<PK, SK> {\n" +
" PK getPrimaryKey();\n" +
" SK[] getSecondaryKeys();\n" +
"}",
"MIData.groovy",
"class MIData implements MultiIndexed<Integer, String> {\n" +
" final String value\n" +
" final Integer primaryKey\n" +
" final String[] secondaryKeys\n" +
"\n" +
" MIData(String val, Integer pk, String... sk) {\n" +
" this.value = val\n" +
" this.primaryKey = pk\n" +
" this.secondaryKeys = sk\n" +
" }\n" +
"}"
};
runWarningFreeTest(sources);
}
@Test // https://github.com/groovy/groovy-eclipse/issues/221
public void testExtendingGenerics_GroovyExtendsJava15() {
assumeTrue(isAtLeastGroovy(20));
String[] sources = {
"AttributeConverter.java",
"interface AttributeConverter<X,Y> {\n" +
" Y encode(X eks);\n" +
" X decode(Y why);\n" +
"}",
"Main.groovy",
"@groovy.transform.TypeChecked\n" +
"class Main implements AttributeConverter<String,Object> {\n" +
" @Override\n" +
" Object encode(String s) { return null; }\n" +
" @Override\n" +
" String decode(Object o) { return null; }\n" +
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testImplementingInterface_JavaExtendingGroovyGenericType() {
String[] sources = {
"p/C.java",
"package p;\n" +
"import java.util.List;\n"+
"public class C extends groovy.lang.GroovyObjectSupport implements I {\n"+
" public List<?> m() { return null;}\n"+
" public static void main(String[] argv) {\n"+
" System.out.println( \"success\");\n"+
" }\n"+
"}",
"p/I.groovy",
"package p;\n"+
"public interface I {\n" +
" List<?> m();\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testImplementingInterface_JavaGenericsIncorrectlyExtendingGroovyGenerics() {
String[] sources = {
"p/C.java",
"package p;\n" +
"import java.util.List;\n"+
"public class C extends groovy.lang.GroovyObjectSupport implements I<String> {\n"+
" public List<String> m() { return null;}\n"+
" public static void main(String[] argv) {\n"+
" System.out.println( \"success\");\n"+
" }\n"+
"}",
"p/I.groovy",
"package p;\n"+
"public interface I<T extends Number> {\n" +
" List<T> m();\n"+
"}"
};
runNegativeTest(sources,
"----------\n" +
"1. ERROR in p\\C.java (at line 3)\n" +
"\tpublic class C extends groovy.lang.GroovyObjectSupport implements I<String> {\n" +
"\t ^^^^^^\n" +
"Bound mismatch: The type String is not a valid substitute for the bounded parameter <T extends Number> of the type I<T>\n" +
"----------\n");
}
@Test
public void testImplementingInterface_GroovyGenericsIncorrectlyExtendingJavaGenerics() {
String[] sources = {
"p/C.groovy",
"package p;\n" +
"public class C implements Iii<String> {\n"+
" public List<String> m() { return null;}\n"+
" public static void main(String[] argv) {\n"+
" System.out.println( \"success\");\n"+
" }\n"+
"}\n",
"p/I.groovy",
"package p;\n"+
"import java.util.List;\n"+
"public interface Iii<T extends Number> {\n" +
" List<T> m();\n"+
"}"
};
runNegativeTest(sources,
"----------\n" +
"1. ERROR in p\\C.groovy (at line 2)\n" +
"\tpublic class C implements Iii<String> {\n" +
"\t ^^^^^^^^^^^^\n" +
"Groovy:The type String is not a valid substitute for the bounded parameter <T extends java.lang.Number>\n" +
"----------\n");
}
@Test
public void testReferencingFieldsGenerics_JreferingToG() {
String[] sources = {
"p/C.java",
"package p;\n" +
"public class C {\n"+
" public static void main(String[] argv) {\n"+
" OtherClass oClass = new OtherClass();\n"+
" for (String message: oClass.messages) {\n"+
" System.out.print(message);\n"+
" }\n"+
" }\n"+
"}",
"p/OtherClass.groovy",
"package p;\n"+
"public class OtherClass {\n" +
" public List<String> messages = new ArrayList<String>();\n"+ // auto imports of java.util
" public OtherClass() {\n"+
" messages.add(\"hello\");\n"+
" messages.add(\" \");\n"+
" messages.add(\"world\");\n"+
" messages.add(\"\\n\");\n"+
" }\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testReferencingFieldsGenerics_GreferingToJ() {
String[] sources = {
"p/C.groovy",
"package p;\n" +
"public class C {\n"+
" public static void main(String[] argv) {\n"+
" OtherClass oClass = new OtherClass();\n"+
" for (String message: oClass.messages) {\n"+
" System.out.print(message);\n"+
" }\n"+
" }\n"+
"}",
"p/OtherClass.java",
"package p;\n"+
"import java.util.*;\n"+
"public class OtherClass {\n" +
" public List<String> messages = new ArrayList<String>();\n"+ // auto imports of java.util
" public OtherClass() {\n"+
" messages.add(\"hello\");\n"+
" messages.add(\" \");\n"+
" messages.add(\"world\");\n"+
" messages.add(\"\\n\");\n"+
" }\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testHalfFinishedGenericsProgram() {
String[] sources = {
"Demo.groovy",
"public class Demo {\n"+
"\n"+
"List myList;\n"+
"\n"+
" def funkyMethod(Map map) {\n"+
" print \"Groovy!\"\n"+
" }\n"+
" }\n"+
"\n"+
"class MyMap<K,V> extends Map {\n"+
"\n"+
"}"
};
runNegativeTest(sources,
"----------\n" +
"1. WARNING in Demo.groovy (at line 3)\n" +
"\tList myList;\n" +
"\t^^^^\n" +
"List is a raw type. References to generic type List<E> should be parameterized\n" +
"----------\n" +
"2. WARNING in Demo.groovy (at line 5)\n" +
"\tdef funkyMethod(Map map) {\n" +
"\t ^^^\n" +
"Map is a raw type. References to generic type Map<K,V> should be parameterized\n" +
"----------\n" +
"3. ERROR in Demo.groovy (at line 10)\n" +
"\tclass MyMap<K,V> extends Map {\n" +
"\t ^^^^^\n" +
"Groovy:You are not allowed to extend the interface \'java.util.Map\', use implements instead.\n" +
"----------\n" +
"4. WARNING in Demo.groovy (at line 10)\n" +
"\tclass MyMap<K,V> extends Map {\n" +
"\t ^^^\n" +
"Map is a raw type. References to generic type Map<K,V> should be parameterized\n" +
"----------\n");
}
@Test
public void testHalfFinishedGenericsProgramWithCorrectSuppression() {
String[] sources = {
"Demo.groovy",
"public class Demo {\n"+
"\n"+
"@SuppressWarnings(\"rawtypes\")\n"+ // should cause no warnings
"List myList;\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testHalfFinishedGenericsProgramWithCorrectSuppressionAtTheTypeLevel() {
String[] sources = {
"Demo.groovy",
"@SuppressWarnings(\"rawtypes\")\n"+ // should cause no warnings
"public class Demo {\n"+
"\n"+
"List myList;\n"+
"}"
};
runWarningFreeTest(sources);
}
@Test
public void testHalfFinishedGenericsProgramWithUnnecessarySuppression() {
String[] sources = {
"Demo.groovy",
"public class Demo {\n"+
"\n"+
"@SuppressWarnings(\"unchecked\")\n"+ // unnecessary suppression
"List<String> myList;\n"+
"}"
};
runNegativeTest(sources,
"----------\n" +
"1. WARNING in Demo.groovy (at line 3)\n" +
"\t@SuppressWarnings(\"unchecked\")\n" +
"\t ^^^^^^^^^^^\n" +
"Unnecessary @SuppressWarnings(\"unchecked\")\n" +
"----------\n");
}
@Test
public void testHalfFinishedGenericsProgramWithSuppressionValueSpeltWrong() {
String[] sources = {
"Demo.groovy",
"public class Demo {\n"+
"\n"+
"@SuppressWarnings(\"unchecked2\")\n"+ // spelt wrong
"List<String> myList;\n"+
"}"
};
runNegativeTest(sources,
"----------\n" +
"1. WARNING in Demo.groovy (at line 3)\n" +
"\t@SuppressWarnings(\"unchecked2\")\n" +
"\t ^^^^^^^^^^^^\n" +
"Unsupported @SuppressWarnings(\"unchecked2\")\n" +
"----------\n");
}
@Test
public void testHalfFinishedGenericsProgramWithMultipleSuppressionValues() {
String[] sources = {
"Demo.groovy",
"class Demo {\n"+
" @SuppressWarnings(['rawtypes','cast'])\n"+
" List list\n"+
"}"
};
// Eclipse Oxygen (i.e. JDT Core 3.13) added warning for mixed mode
Version v = Platform.getBundle("org.eclipse.jdt.core").getVersion();
runNegativeTest(sources, (v.getMajor() == 3 && v.getMinor() < 13) ? "" : "----------\n" +
"1. WARNING in Demo.groovy (at line 2)\n" +
"\t@SuppressWarnings(['rawtypes','cast'])\n" +
"\t ^^^^^^\n" +
"At least one of the problems in category 'cast' is not analysed due to a compiler option being ignored\n" +
"----------\n");
}
@Test
public void testHalfFinishedGenericsProgramWithMultipleSuppressionValuesWithOneSpeltWrong() {
String[] sources = {
"Demo.groovy",
"public class Demo {\n"+
"\n"+
"@SuppressWarnings([\"rawtypes\",\"cast2\"])\n"+
"List myList;\n"+
"}"
};
runNegativeTest(sources,
"----------\n" +
"1. WARNING in Demo.groovy (at line 3)\n" +
"\t@SuppressWarnings([\"rawtypes\",\"cast2\"])\n" +
"\t ^^^^^^^\n" +
"Unsupported @SuppressWarnings(\"cast2\")\n" +
"----------\n");
}
@Test
public void testJava7() {
assumeTrue(isAtLeastJava(JDK7));
String[] sources = {
"A.java",
"import java.util.*;\n"+
"public class A {\n"+
"public static void main(String[]argv) {\n"+
" List<String> ls = new ArrayList<>();"+
" int i = 1_000_000;\n"+
" int b = 0b110101;\n"+
" try {\n"+
" foo();\n"+
" } catch (java.io.IOException | IllegalStateException re) {\n"+
" }\n"+
"}\n"+
" public static void foo() throws java.io.IOException {}\n"+
"}",
"B.groovy",
"print 'a'\n"
};
runWarningFreeTest(sources);
}
@Test
public void testJava7_2() {
assumeTrue(!isAtLeastJava(JDK7));
String[] sources = {
"A.java",
"import java.util.*;\n"+
"public class A {\n"+
"public static void main(String[]argv) {\n"+
" List<String> ls = new ArrayList<>();"+
" int i = 1_000_000;\n"+
" int b = 0b110101;\n"+
"}\n"+
" public static void foo() throws java.io.IOException {}\n"+
"}",
"B.groovy",
"print 'a'\n"
};
runNegativeTest(sources,
"----------\n" +
"1. ERROR in A.java (at line 4)\n" +
"\tList<String> ls = new ArrayList<>(); int i = 1_000_000;\n" +
"\t ^^^^^^^^^\n" +
"\'<>\' operator is not allowed for source level below 1.7\n" +
"----------\n" +
"2. ERROR in A.java (at line 4)\n" +
"\tList<String> ls = new ArrayList<>(); int i = 1_000_000;\n" +
"\t ^^^^^^^^^\n" +
"Underscores can only be used with source level 1.7 or greater\n" +
"----------\n");
}
@Test
public void testJava7_3() {
assumeTrue(!isAtLeastJava(JDK7));
String[] sources = {
"A.java",
"import java.util.*;\n"+
"public class A {\n"+
"public static void main(String[]argv) {\n"+
" try {\n"+
" foo();\n"+
" } catch (java.io.IOException | IllegalStateException re) {\n"+
" }\n"+
"}\n"+
" public static void foo() throws java.io.IOException {}\n"+
"}",
"B.groovy",
"print 'a'\n"
};
runNegativeTest(sources,
"----------\n" +
"1. ERROR in A.java (at line 6)\n" +
"\t} catch (java.io.IOException | IllegalStateException re) {\n" +
"\t ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Multi-catch parameters are not allowed for source level below 1.7\n" +
"----------\n");
}
@Test
public void testTurningOffGenericsWarnings() {
// Map<String, String> options = getCompilerOptions();
// options.put(CompilerOptions.OPTIONG_GroovyFlags, "0");
//
// runConformTest(new String[] {
// "Assertions.groovy",
// "import spock.lang.*\n"+
// "@Speck\n"+
// "class Assertions {\n"+
//// " public static void main(String[] argv) { new Assertions().comparingXandY();}\n"+
// " def comparingXandY() {\n"+
// " def x = 1\n"+
// " def y = 2\n"+
// " \n"+
//// " print 'a'\n"+
// " expect:\n"+
// " x < y // OK\n"+
// " x == y // BOOM!\n"+
// " }\n"+
// "}"},
// "----------\n" +
// "1. ERROR in Assertions.groovy (at line 4)\n" +
// " public static void main(String[] argv) {\n" +
// " ^^\n" +
// "Groovy:Feature methods must not be static @ line 4, column 2.\n" +
// "----------\n",
// null,
// true,
// null,
// options,
// null)
// this.runNegativeTest(new String[] {
// "p/X.groovy",
// "package p;\n" +
// "public class X {\n" +
// " List l = new ArrayList();\n" +
// " public static void main(String[] argv) {\n"+
// " print 'success'\n"+
// " }\n"+
// "}\n"},
// "----------\n" +
// "1. ERROR in Assertions.groovy (at line 4)\n" +
// " public static void main(String[] argv) {\n" +
// " ^^\n" +
// "Groovy:Feature methods must not be static @ line 4, column 2.\n" +
// "----------\n",
// null,
// true,
// null,
// options,
// null)
}
}