int methodTypeVariablesArity = methodTypeVariables.length;
MethodBinding staticFactory = new MethodBinding(method.modifiers | ClassFileConstants.AccStatic, TypeConstants.SYNTHETIC_STATIC_FACTORY,
null, null, null, method.declaringClass);
staticFactory.typeVariables = new TypeVariableBinding[classTypeVariablesArity + methodTypeVariablesArity];
final SimpleLookupTable map = new SimpleLookupTable(classTypeVariablesArity + methodTypeVariablesArity);
// Rename each type variable T of the type to T'
final LookupEnvironment environment = environment();
for (int j = 0; j < classTypeVariablesArity; j++) {
map.put(classTypeVariables[j], staticFactory.typeVariables[j] = new TypeVariableBinding(CharOperation.concat(classTypeVariables[j].sourceName, "'".toCharArray()), //$NON-NLS-1$
staticFactory, j, environment));
}
// Rename each type variable U of method U to U''.
for (int j = classTypeVariablesArity, max = classTypeVariablesArity + methodTypeVariablesArity; j < max; j++) {
map.put(methodTypeVariables[j - classTypeVariablesArity],
(staticFactory.typeVariables[j] = new TypeVariableBinding(CharOperation.concat(methodTypeVariables[j - classTypeVariablesArity].sourceName, "''".toCharArray()), //$NON-NLS-1$
staticFactory, j, environment)));
}
ReferenceBinding enclosingType = originalEnclosingType;
while (enclosingType != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=345968
if (enclosingType.kind() == Binding.PARAMETERIZED_TYPE) {
final ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) enclosingType;
final ReferenceBinding genericType = parameterizedType.genericType();
TypeVariableBinding[] enclosingClassTypeVariables = genericType.typeVariables();
int enclosingClassTypeVariablesArity = enclosingClassTypeVariables.length;
for (int j = 0; j < enclosingClassTypeVariablesArity; j++) {
map.put(enclosingClassTypeVariables[j], parameterizedType.arguments[j]);
}
}
enclosingType = enclosingType.enclosingType();
}
final Scope scope = this;
Substitution substitution = new Substitution() {
public LookupEnvironment environment() {
return scope.environment();
}
public boolean isRawSubstitution() {
return false;
}
public TypeBinding substitute(TypeVariableBinding typeVariable) {
TypeBinding retVal = (TypeBinding) map.get(typeVariable);
return retVal != null ? retVal : typeVariable;
}
};
// initialize new variable bounds
for (int j = 0, max = classTypeVariablesArity + methodTypeVariablesArity; j < max; j++) {
TypeVariableBinding originalVariable = j < classTypeVariablesArity ? classTypeVariables[j] : methodTypeVariables[j - classTypeVariablesArity];
TypeBinding substitutedType = (TypeBinding) map.get(originalVariable);
if (substitutedType instanceof TypeVariableBinding) {
TypeVariableBinding substitutedVariable = (TypeVariableBinding) substitutedType;
TypeBinding substitutedSuperclass = Scope.substitute(substitution, originalVariable.superclass);
ReferenceBinding[] substitutedInterfaces = Scope.substitute(substitution, originalVariable.superInterfaces);
if (originalVariable.firstBound != null) {
substitutedVariable.firstBound = originalVariable.firstBound == originalVariable.superclass
? substitutedSuperclass // could be array type or interface
: substitutedInterfaces[0];
}
switch (substitutedSuperclass.kind()) {
case Binding.ARRAY_TYPE :
substitutedVariable.superclass = environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null);
substitutedVariable.superInterfaces = substitutedInterfaces;
break;
default:
if (substitutedSuperclass.isInterface()) {
substitutedVariable.superclass = environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null);
int interfaceCount = substitutedInterfaces.length;
System.arraycopy(substitutedInterfaces, 0, substitutedInterfaces = new ReferenceBinding[interfaceCount+1], 1, interfaceCount);
substitutedInterfaces[0] = (ReferenceBinding) substitutedSuperclass;
substitutedVariable.superInterfaces = substitutedInterfaces;
} else {
substitutedVariable.superclass = (ReferenceBinding) substitutedSuperclass; // typeVar was extending other typeVar which got substituted with interface
substitutedVariable.superInterfaces = substitutedInterfaces;
}
}
}
}
TypeVariableBinding[] returnTypeParameters = new TypeVariableBinding[classTypeVariablesArity];
for (int j = 0; j < classTypeVariablesArity; j++) {
returnTypeParameters[j] = (TypeVariableBinding) map.get(classTypeVariables[j]);
}
staticFactory.returnType = environment.createParameterizedType(allocationType, returnTypeParameters, allocationType.enclosingType());
staticFactory.parameters = Scope.substitute(substitution, method.parameters);
staticFactory.thrownExceptions = Scope.substitute(substitution, method.thrownExceptions);
if (staticFactory.thrownExceptions == null) {