Skip to content

Commit 587103b

Browse files
committed
Fix for #421: immutable explicit defaults
1 parent f3e05e8 commit 587103b

File tree

7 files changed

+123
-5
lines changed

7 files changed

+123
-5
lines changed

Diff for: base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/CanonicalTests.java

+22
Original file line numberDiff line numberDiff line change
@@ -231,4 +231,26 @@ public void testCanonical9() {
231231

232232
runConformTest(sources, "Outer$Inner(foo:bar, baz:null)");
233233
}
234+
235+
@Test // GROOVY-10238
236+
public void testCanonical10() {
237+
//@formatter:off
238+
String[] sources = {
239+
"Main.groovy",
240+
"class Outer {\n" +
241+
" @groovy.transform.CompileStatic\n" +
242+
" @groovy.transform.Canonical\n" +
243+
" static class Inner {\n" +
244+
" Map<String,Object> map = [:].withDefault { new Object() }\n" + // NoSuchMethodError: java.util.Map.withDefault(Lgroovy/lang/Closure;)
245+
" }\n" +
246+
"}\n" +
247+
"def obj = new Outer.Inner()\n" +
248+
"assert obj.toString() == 'Outer$Inner([:])'\n" +
249+
"assert obj.map['foo'] != null\n" +
250+
"assert obj.toString() != 'Outer$Inner([:])'\n" ,
251+
};
252+
//@formatter:on
253+
254+
runConformTest(sources);
255+
}
234256
}

Diff for: base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/ImmutableTests.java

+45-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public void testImmutable2() {
7777
String[] sources = {
7878
"Main.java",
7979
"public class Main {\n" +
80-
" public static void main(String... args) {\n" +
80+
" public static void main(String[] args) {\n" +
8181
" System.out.print(new Foo(\"one\", \"two\"));\n" +
8282
" }\n" +
8383
"}\n",
@@ -92,4 +92,48 @@ public void testImmutable2() {
9292

9393
runConformTest(sources, "Foo(one, two)");
9494
}
95+
96+
@Test // https://github.com/groovy/groovy-eclipse/issues/421
97+
public void testImmutable3() {
98+
//@formatter:off
99+
String[] sources = {
100+
"Main.java",
101+
"public class Main {\n" +
102+
" public static void main(String[] args) {\n" +
103+
" System.out.print(new Foo(\"one\", \"two\"));\n" +
104+
" }\n" +
105+
"}\n",
106+
107+
"Foo.groovy",
108+
"@groovy.transform.Immutable(defaults=false)\n" +
109+
"class Foo {\n" +
110+
" String bar, baz\n" +
111+
"}\n",
112+
};
113+
//@formatter:on
114+
115+
runConformTest(sources, "Foo(one, two)");
116+
}
117+
118+
@Test // https://github.com/groovy/groovy-eclipse/issues/421
119+
public void testImmutable4() {
120+
//@formatter:off
121+
String[] sources = {
122+
"Main.java",
123+
"public class Main {\n" +
124+
" public static void main(String[] args) {\n" +
125+
" System.out.print(new Foo(\"one\"));\n" +
126+
" }\n" +
127+
"}\n",
128+
129+
"Foo.groovy",
130+
"@groovy.transform.Immutable(defaults=true,noArg=false)\n" + //TODO: GROOVY-10790
131+
"class Foo {\n" +
132+
" String bar, baz = \"two\"\n" +
133+
"}\n",
134+
};
135+
//@formatter:on
136+
137+
runConformTest(sources, "Foo(one, two)");
138+
}
95139
}

Diff for: base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TupleConstructorTests.java

+47
Original file line numberDiff line numberDiff line change
@@ -262,4 +262,51 @@ public void testTupleConstructor9() {
262262

263263
runConformTest(sources, "Foo(baz:two, bar:one)");
264264
}
265+
266+
@Test
267+
public void testTupleConstructor10() {
268+
//@formatter:off
269+
String[] sources = {
270+
"Main.groovy",
271+
"@groovy.transform.TupleConstructor(includeFields=true)\n" +
272+
"class Person {\n" +
273+
" String firstName = 'John'\n" +
274+
" private String lastName = 'Doe'\n" +
275+
" String getLastName() { lastName }\n" +
276+
"}\n" +
277+
"def p = new Person()\n" +
278+
"assert p.firstName == 'John'\n" +
279+
"assert p.lastName == 'Doe'\n" +
280+
"p = new Person('Jane')\n" +
281+
"assert p.firstName == 'Jane'\n" +
282+
"assert p.lastName == 'Doe'\n",
283+
};
284+
//@formatter:on
285+
286+
runConformTest(sources);
287+
}
288+
289+
@Test
290+
public void testTupleConstructor11() {
291+
//@formatter:off
292+
String[] sources = {
293+
"Main.groovy",
294+
"@groovy.transform.TupleConstructor(force=true)\n" +
295+
"class Person {\n" +
296+
" String firstName, lastName\n" +
297+
" Person(Person that) {\n" +
298+
" this.firstName = that.firstName\n" +
299+
" }\n" +
300+
"}\n" +
301+
"def p = new Person('John', 'Doe')\n" +
302+
"assert p.firstName == 'John'\n" +
303+
"assert p.lastName == 'Doe'\n" +
304+
"p = new Person(p)\n" +
305+
"assert p.firstName == 'John'\n" +
306+
"assert p.lastName == null\n",
307+
};
308+
//@formatter:on
309+
310+
runConformTest(sources);
311+
}
265312
}

Diff for: base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/asm/InvocationWriter.java

+1
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,7 @@ private void makeMOPBasedConstructorCall(List<ConstructorNode> constructors, Con
10511051
if (sameHashNode!=null) {
10521052
controller.getSourceUnit().addError(
10531053
new SyntaxException("Unable to compile class "+controller.getClassNode().getName() + " due to hash collision in constructors", call.getLineNumber(), call.getColumnNumber()));
1054+
return; // GRECLIPSE add
10541055
}
10551056
}
10561057
Label[] targets = new Label[constructors.size()];

Diff for: base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/asm/InvocationWriter.java

+1
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,7 @@ private void makeMOPBasedConstructorCall(final List<ConstructorNode> constructor
10261026
if (sameHashNode != null) {
10271027
controller.getSourceUnit().addError(new SyntaxException(
10281028
"Unable to compile class "+controller.getClassNode().getName() + " due to hash collision in constructors", call.getLineNumber(), call.getColumnNumber()));
1029+
return; // GRECLIPSE add
10291030
}
10301031
}
10311032
Label[] targets = new Label[constructors.size()];

Diff for: base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java

-1
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,6 @@ private static Parameter createParam(FieldNode fNode, String name, DefaultsMode
340340
private static Expression providedOrDefaultInitialValue(final FieldNode fNode) {
341341
ClassNode fType = fNode.getType();
342342
Expression init = fNode.getInitialExpression();
343-
fNode.setInitialValueExpression(null); // GROOVY-10238
344343
if (init == null || (ClassHelper.isPrimitiveType(fType) && ExpressionUtils.isNullConstant(init))) {
345344
init = defaultValueX(fType);
346345
}

Diff for: base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/internal/compiler/ast/GroovyCompilationUnitDeclaration.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.stream.Stream;
3434

3535
import groovy.lang.GroovyRuntimeException;
36+
import groovy.transform.CompilationUnitAware;
3637
import groovy.transform.PackageScopeTarget;
3738

3839
import org.codehaus.groovy.GroovyBugError;
@@ -2957,7 +2958,7 @@ private List<ConstructorNode> getDeclaredAndGeneratedConstructors(ClassNode clas
29572958
AnnotationNode anno = new AnnotationNode(ClassHelper.make(groovy.transform.TupleConstructor.class));
29582959
if (isType("groovy.transform.Immutable", annotationType))
29592960
anno.addMember("defaults", ConstantExpression.FALSE);
2960-
attributes.forEach((name, value) -> anno.addMember(name, value));
2961+
attributes.forEach((name, value) -> anno.setMember(name, value));
29612962

29622963
// create type that intercepts generated constructors
29632964
ClassNode type = new ClassNode(classNode.getName(), 0, null) {
@@ -2981,9 +2982,12 @@ public void addConstructor(ConstructorNode ctor) {
29812982
}
29822983
};
29832984

2984-
ASTTransformation astt = new org.codehaus.groovy.transform.TupleConstructorASTTransformation();
2985+
ASTTransformation astt = new org.codehaus.groovy.transform.TupleConstructorASTTransformation() {
2986+
@Override public void addError(String msg, org.codehaus.groovy.ast.ASTNode node) {}
2987+
};
2988+
((CompilationUnitAware) astt).setCompilationUnit(unitDeclaration.compilationUnit);
29852989
// apply TupleConstructorASTTransformation early to generate constructor(s)
2986-
astt.visit(new org.codehaus.groovy.ast.ASTNode[] {anno, type}, sourceUnit);
2990+
astt.visit(new org.codehaus.groovy.ast.ASTNode[] {anno, type}, null);
29872991

29882992
if (!generated.isEmpty()) {
29892993
constructorNodes = new ArrayList<>(constructorNodes);

0 commit comments

Comments
 (0)