public static GenericsType[] alignGenericTypes(final GenericsType[] redirectGenericTypes, final GenericsType[] parameterizedTypes, final GenericsType[] alignmentTarget) {
if (alignmentTarget==null) return EMPTY_GENERICS_ARRAY;
if (parameterizedTypes==null || parameterizedTypes.length==0) return alignmentTarget;
GenericsType[] generics = new GenericsType[alignmentTarget.length];
for (int i = 0, scgtLength = alignmentTarget.length; i < scgtLength; i++) {
final GenericsType currentTarget = alignmentTarget[i];
GenericsType match = null;
if (redirectGenericTypes!=null) {
for (int j = 0; j < redirectGenericTypes.length && match == null; j++) {
GenericsType redirectGenericType = redirectGenericTypes[j];
if (redirectGenericType.isCompatibleWith(currentTarget.getType())) {
if (currentTarget.isPlaceholder() && redirectGenericType.isPlaceholder() && !currentTarget.getName().equals(redirectGenericType.getName())) {
// check if there's a potential better match
boolean skip = false;
for (int k=j+1; k<redirectGenericTypes.length && !skip; k++) {
GenericsType ogt = redirectGenericTypes[k];
if (ogt.isPlaceholder() && ogt.isCompatibleWith(currentTarget.getType()) && ogt.getName().equals(currentTarget.getName())) {
skip = true;
}
}
if (skip) continue;
}
match = parameterizedTypes[j];
if (currentTarget.isWildcard()) {
// if alignment target is a wildcard type
// then we must make best effort to return a parameterized
// wildcard
ClassNode lower = currentTarget.getLowerBound()!=null?match.getType():null;
ClassNode[] currentUpper = currentTarget.getUpperBounds();
ClassNode[] upper = currentUpper !=null?new ClassNode[currentUpper.length]:null;
if (upper!=null) {
for (int k = 0; k < upper.length; k++) {
upper[k] = currentUpper[k].isGenericsPlaceHolder()?match.getType():currentUpper[k];
}
}
match = new GenericsType(ClassHelper.makeWithoutCaching("?"), upper, lower);
match.setWildcard(true);
}
}
}
}