Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: 1.5.6, 1.6-beta-1
-
Fix Version/s: 1.6-rc-1, 1.5.8, 1.7-beta-1
-
Component/s: command line processing
-
Labels:None
-
Number of attachments :
Description
class Foo {
Foo(String s) {}
Foo(Date d) {
println "call to this() must be the first statement of a ctor"
this(d.toString())
}
}
new Foo(new Date())
In the snippet above, I'm calling this() after a println call.
But in Java, it is mandatory that calls to this() or super() inside a constructor are the first statements of the block.
Here I get the following stacktrace:
groovy.lang.MissingMethodException: No signature of method: Foo.call() is applicable for argument types: (java.lang.String) values: {Fri May 16 23:48:20 CEST 2008} at Foo.invokeMethod(Script35) at Foo.<init>(Script35:6) at Script35.run(Script35:10)
The compiler should check that calls to this() or super() are done as the first statement, and not afterwards.
(This bug was work in progress and also I haven't yet gone through the new guidelines, so just attaching the patches one more time.)
Attaching the patches for versions 1.5.8, 1.6-RC-1, 1.7-beta-1. One existing testcase also needed to be patched as it was in conflict with the requirement of this JIRA.
The fix done is "throwing a compilation error when this(..) / super(..) when not on 1st statement"
"groovy.g" makes sure that constructor calls on first statement (this(..) / super(..)) are captured explicitly by marking their AST node types as CTOR_CALL / SUPER_CTOR_CALL. Later, AntlrParserPlugin converts such captured calls into ConstructorCallExpression.
But if this(..)/super(..) comes after the first statement, it is turned into a MethodCallExpression representing this.call(..)/super.call(..), which causes failures as noted in the current bug ("No signature of method: Foo.call() is applicable....").
The change is made to AntlrParserPlugin.methodCallExpression(), which now rejects the this()/super() kind of calls with a compilation error saying "Constructor call must be the first statement in a constructor."
Here is one testcase to show the new behavior:
void testThisConstructorCallNotOnFirstStmt() { def scriptStr = """ class ThisConstructorCall { public ThisConstructorCall() { println 'dummy first statement' this(19) } public ThisConstructorCall(int b) { println "another dummy statement" } } 1 """ try { assertScript scriptStr fail("The script compilation should have failed as it calls constructor on 2nd statement") } catch(MultipleCompilationErrorsException mcee) { def text = mcee.toString(); assert text.contains("Constructor call must be the first statement in a constructor.") } }