private JMethod createSyntheticConstructor(JMethod constructor,
boolean staticClass, JReferenceType enclosingType) {
JClassType type = (JClassType) constructor.getEnclosingType();
// Define the method
JMethod synthetic = program.createMethod(type.getSourceInfo().makeChild(
BuildDeclMapVisitor.class, "Synthetic constructor"),
"new".toCharArray(), type, type, false, true, true, false, false);
// new Foo() : Create the instance
JNewInstance newInstance = new JNewInstance(
type.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
"new instance"), type);
// (new Foo()).Foo() : Invoke the constructor method on the instance
JMethodCall call = new JMethodCall(type.getSourceInfo().makeChild(
BuildDeclMapVisitor.class, "constructor invocation"), newInstance,
constructor);
/*
* If the type isn't static, make the first parameter a reference to the
* instance of the enclosing class. It's the first instance to allow the
* JSNI qualifier to be moved without affecting evaluation order.
*/
JParameter enclosingInstance = null;
if (!staticClass) {
enclosingInstance = program.createParameter(
synthetic.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
"outer instance"), "this$outer".toCharArray(), enclosingType,
false, false, synthetic);
}
/*
* In one pass, add the parameters to the synthetic constructor and
* arguments to the method call.
*/
for (Iterator<JParameter> i = constructor.getParams().iterator(); i.hasNext();) {
JParameter param = i.next();
/*
* This supports x.new Inner() by passing the enclosing instance
* implicitly as the last argument to the constructor.
*/
if (enclosingInstance != null && !i.hasNext()) {
call.addArg(new JParameterRef(synthetic.getSourceInfo().makeChild(
BuildDeclMapVisitor.class, "enclosing instance"),
enclosingInstance));
} else {
JParameter syntheticParam = program.createParameter(
synthetic.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
"Argument " + param.getName()),
param.getName().toCharArray(), param.getType(), true, false,
synthetic);
call.addArg(new JParameterRef(
syntheticParam.getSourceInfo().makeChild(
BuildDeclMapVisitor.class, "reference"), syntheticParam));
}
}
// Lock the method.
synthetic.freezeParamTypes();
// return (new Foo()).Foo() : The only statement in the function
JReturnStatement ret = new JReturnStatement(
synthetic.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
"Return statement"), call);
// Add the return statement to the method body
JMethodBody body = (JMethodBody) synthetic.getBody();
body.getBlock().addStmt(ret);
// Done
return synthetic;
}