import org.eclipse.jdt.internal.compiler.flow.*;
import org.eclipse.jdt.internal.compiler.lookup.*;
-public class ExplicitConstructorCall
- extends Statement
- implements InvocationSite {
+public class ExplicitConstructorCall extends Statement implements InvocationSite {
public Expression[] arguments;
public Expression qualification;
- public MethodBinding binding;
-
+ public MethodBinding binding; // exact binding resulting from lookup
+ protected MethodBinding codegenBinding; // actual binding used for code generation (if no synthetic accessor)
+ MethodBinding syntheticAccessor; // synthetic accessor for inner-emulation
public int accessMode;
-
+ public TypeReference[] typeArguments;
+ public TypeBinding[] genericTypeArguments;
+
public final static int ImplicitSuper = 1;
public final static int Super = 2;
public final static int This = 3;
public VariableBinding[][] implicitArguments;
boolean discardEnclosingInstance;
-
- MethodBinding syntheticAccessor;
+
+ // TODO Remove once DOMParser is activated
+ public int typeArgumentsSourceStart;
public ExplicitConstructorCall(int accessMode) {
this.accessMode = accessMode;
int pc = codeStream.position;
codeStream.aload_0();
+ ReferenceBinding targetType = this.codegenBinding.declaringClass;
+
+ // special name&ordinal argument generation for enum constructors
+ if (targetType.erasure().id == T_JavaLangEnum || targetType.isEnum()) {
+ codeStream.aload_1(); // pass along name param as name arg
+ codeStream.iload_2(); // pass along ordinal param as ordinal arg
+ }
// handling innerclass constructor invocation
- ReferenceBinding targetType = binding.declaringClass;
// handling innerclass instance allocation - enclosing instance arguments
if (targetType.isNestedType()) {
codeStream.generateSyntheticEnclosingInstanceValues(
discardEnclosingInstance ? null : qualification,
this);
}
- // regular code gen
- if (arguments != null) {
- for (int i = 0, max = arguments.length; i < max; i++) {
- arguments[i].generateCode(currentScope, codeStream, true);
- }
- }
+ // generate arguments
+ generateArguments(binding, arguments, currentScope, codeStream);
+
// handling innerclass instance allocation - outer local arguments
if (targetType.isNestedType()) {
codeStream.generateSyntheticOuterArgumentValues(
if (syntheticAccessor != null) {
// synthetic accessor got some extra arguments appended to its signature, which need values
for (int i = 0,
- max = syntheticAccessor.parameters.length - binding.parameters.length;
+ max = syntheticAccessor.parameters.length - this.codegenBinding.parameters.length;
i < max;
i++) {
codeStream.aconst_null();
}
codeStream.invokespecial(syntheticAccessor);
} else {
- codeStream.invokespecial(binding);
+ codeStream.invokespecial(this.codegenBinding);
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
} finally {
((MethodScope) currentScope).isConstructorCall = false;
}
}
-
+ /**
+ * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
+ */
+ public TypeBinding[] genericTypeArguments() {
+ return this.genericTypeArguments;
+ }
public boolean isImplicitSuper() {
//return true if I'm of these compiler added statement super();
* exact need.
*/
void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
- ReferenceBinding superType;
+ ReferenceBinding superTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
if (!flowInfo.isReachable()) return;
// perform some emulation work in case there is some and we are inside a local type only
- if ((superType = binding.declaringClass).isNestedType()
+ if (superTypeErasure.isNestedType()
&& currentScope.enclosingSourceType().isLocalType()) {
- if (superType.isLocalType()) {
- ((LocalTypeBinding) superType).addInnerEmulationDependent(currentScope, qualification != null);
+ if (superTypeErasure.isLocalType()) {
+ ((LocalTypeBinding) superTypeErasure).addInnerEmulationDependent(currentScope, qualification != null);
} else {
// locally propagate, since we already now the desired shape for sure
- currentScope.propagateInnerEmulation(superType, qualification != null);
+ currentScope.propagateInnerEmulation(superTypeErasure, qualification != null);
}
}
}
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
if (!flowInfo.isReachable()) return;
+ // if constructor from parameterized type got found, use the original constructor at codegen time
+ this.codegenBinding = this.binding.original();
+
// perform some emulation work in case there is some and we are inside a local type only
- if (binding.isPrivate() && (accessMode != This)) {
+ if (binding.isPrivate() && accessMode != This) {
- if (currentScope
- .environment()
- .options
- .isPrivateConstructorAccessChangingVisibility) {
- binding.tagForClearingPrivateModifier();
+ if (currentScope.environment().options.isPrivateConstructorAccessChangingVisibility) {
+ this.codegenBinding.tagForClearingPrivateModifier();
// constructor will not be dumped as private, no emulation required thus
} else {
syntheticAccessor =
- ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, isSuperAccess());
- currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
+ ((SourceTypeBinding) this.codegenBinding.declaringClass).addSyntheticMethod(this.codegenBinding, isSuperAccess());
+ currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this);
}
}
}
printIndent(indent, output);
if (qualification != null) qualification.printExpression(0, output).append('.');
+ if (typeArguments != null) {
+ output.append('<');//$NON-NLS-1$
+ int max = typeArguments.length - 1;
+ for (int j = 0; j < max; j++) {
+ typeArguments[j].print(0, output);
+ output.append(", ");//$NON-NLS-1$
+ }
+ typeArguments[max].print(0, output);
+ output.append('>');
+ }
if (accessMode == This) {
output.append("this("); //$NON-NLS-1$
} else {
if (receiverType == null) {
return;
}
-
+ // prevent (explicit) super constructor invocation from within enum
+ if (this.accessMode == Super && receiverType.erasure().id == T_JavaLangEnum) {
+ scope.problemReporter().cannotInvokeSuperConstructorInEnum(this, methodScope.referenceMethod().binding);
+ }
// qualification should be from the type of the enclosingType
if (qualification != null) {
if (accessMode != Super) {
discardEnclosingInstance = true;
} else {
TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType);
- qualification.implicitWidening(qTb, qTb);
+ qualification.computeConversion(scope, qTb, qTb);
}
}
-
+ // resolve type arguments (for generic constructor call)
+ if (this.typeArguments != null) {
+ int length = this.typeArguments.length;
+ boolean argHasError = false; // typeChecks all arguments
+ this.genericTypeArguments = new TypeBinding[length];
+ for (int i = 0; i < length; i++) {
+ if ((this.genericTypeArguments[i] = this.typeArguments[i].resolveType(scope, true /* check bounds*/)) == null) {
+ argHasError = true;
+ }
+ }
+ if (argHasError) {
+ return;
+ }
+ }
+
// arguments buffering for the method lookup
TypeBinding[] argumentTypes = NoParameters;
boolean argsContainCast = false;
if (argHasError) {
return;
}
+ } else if (receiverType.erasure().id == T_JavaLangEnum) {
+ // TODO (philippe) get rid of once well-known binding is available
+ argumentTypes = new TypeBinding[] { scope.getJavaLangString(), BaseTypes.IntBinding };
}
if ((binding = scope.getConstructor(receiverType, argumentTypes, this)).isValidBinding()) {
if (isMethodUseDeprecated(binding, scope))
scope.problemReporter().deprecatedMethod(binding, this);
-
- // see for user-implicit widening conversion
- if (arguments != null) {
- int length = arguments.length;
- TypeBinding[] paramTypes = binding.parameters;
- for (int i = 0; i < length; i++) {
- arguments[i].implicitWidening(paramTypes[i], argumentTypes[i]);
- }
- if (argsContainCast) {
- CastExpression.checkNeedForArgumentCasts(scope, null, receiverType, binding, this.arguments, argumentTypes, this);
- }
- }
+ if (this.arguments != null)
+ checkInvocationArguments(scope, null, receiverType, binding, this.arguments, argumentTypes, argsContainCast, this);
if (binding.isPrivate()) {
- binding.modifiers |= AccPrivateUsed;
+ binding.original().modifiers |= AccPrivateUsed;
}
} else {
if (binding.declaringClass == null)
if (this.qualification != null) {
this.qualification.traverse(visitor, scope);
}
+ if (this.typeArguments != null) {
+ for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) {
+ this.typeArguments[i].traverse(visitor, scope);
+ }
+ }
if (this.arguments != null) {
for (int i = 0, argumentLength = this.arguments.length; i < argumentLength; i++)
this.arguments[i].traverse(visitor, scope);