8000 Fix issue when resolving a static method-call with only a generic variadic parameter by maartenc · Pull Request #3194 · javaparser/javaparser · GitHub
[go: up one dir, main page]

Skip to content

Fix issue when resolving a static method-call with only a generic variadic parameter #3194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Fix issue when resolving a static method-call with only a generic var…
…iadic parameter
  • Loading branch information
maartenc committed Mar 24, 2021
commit 67440d6005f3a132a601bbe87475a41df30402c6
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.resolution.Value;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.reflectionmodel.MyObjectProvider;
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic;
import com.github.javaparser.utils.Pair;
Expand Down Expand Up @@ -218,23 +217,7 @@ private Optional<MethodUsage> solveMethodAsUsage(ResolvedReferenceType refType,
// In our example Stream.T equal to String, so the R (and the result of the call to collect) is
// List<? super String>

Map<ResolvedTypeParameterDeclaration, ResolvedType> derivedValues = new HashMap<>();
for (int i = 0; i < methodUsage.getParamTypes().size(); i++) {
ResolvedParameterDeclaration parameter = methodUsage.getDeclaration().getParam(i);
ResolvedType parameterType = parameter.getType();
// Don't continue if a vararg parameter is reached and there are no arguments left
if (parameter.isVariadic() && argumentsTypes.size() < methodUsage.getNoParams()) {
break;
}
if (!argumentsTypes.get(i).isArray() && parameter.isVariadic()) {
parameterType = parameterType.asArrayType().getComponentType();
}
inferTypes(argumentsTypes.get(i), parameterType, derivedValues);
}

for (Map.Entry<ResolvedTypeParameterDeclaration, ResolvedType> entry : derivedValues.entrySet()){
methodUsage = methodUsage.replaceTypeParameter(entry.getKey(), entry.getValue());
}
methodUsage = resolveMethodTypeParameters(methodUsage, argumentsTypes);

ResolvedType returnType = refType.useThisTypeParametersOnTheGivenType(methodUsage.returnType());
// we don't want to replace the return type in case of UNBOUNDED type (<?>)
Expand Down Expand Up @@ -339,97 +322,25 @@ private void inferTypes(ResolvedType source, ResolvedType target, Map<ResolvedTy
}

private MethodUsage resolveMethodTypeParameters(MethodUsage methodUsage, List<ResolvedType> actualParamTypes) {
Map<ResolvedTypeParameterDeclaration, ResolvedType> matchedTypeParameters = new HashMap<>();

if (methodUsage.getDeclaration().hasVariadicParameter()) {
if (actualParamTypes.size() == methodUsage.getDeclaration().getNumberOfParams()) {
// the varargs parameter is an Array, so extract the inner type
ResolvedType expectedType =
methodUsage.getDeclaration().getLastParam().getType().asArrayType().getComponentType();
// the varargs corresponding type can be either T or Array<T>
ResolvedType actualType =
actualParamTypes.get(actualParamTypes.size() - 1).isArray() ?
actualParamTypes.get(actualParamTypes.size() - 1).asArrayType().getComponentType() :
actualParamTypes.get(actualParamTypes.size() - 1);
if (!expectedType.isAssignableBy(actualType)) {
for (ResolvedTypeParameterDeclaration tp : methodUsage.getDeclaration().getTypeParameters()) {
expectedType = MethodResolutionLogic.replaceTypeParam(expectedType, tp, typeSolver);
}
}
if (!expectedType.isAssignableBy(actualType)) {
// ok, then it needs to be wrapped
throw new UnsupportedOperationException(
String.format("Unable to resolve the type typeParametersValues in a MethodUsage. Expected type: %s, Actual type: %s. Method Declaration: %s. MethodUsage: %s",
expectedType,
actualType,
methodUsage.getDeclaration(),
methodUsage));
}
// match only the varargs type
matchTypeParameters(expectedType, actualType, matchedTypeParameters);
} else {
return methodUsage;
Map<ResolvedTypeParameterDeclaration, ResolvedType> derivedValues = new HashMap<>();
for (int i = 0; i < methodUsage.getParamTypes().size(); i++) {
ResolvedParameterDeclaration parameter = methodUsage.getDeclaration().getParam(i);
ResolvedType parameterType = parameter.getType();
// Don't continue if a vararg parameter is reached and there are no arguments left
if (parameter.isVariadic() && actualParamTypes.size() < methodUsage.getNoParams()) {
break;
}
if (!actualParamTypes.get(i).isArray() && parameter.isVariadic()) {
parameterType = parameterType.asArrayType().getComponentType();
}
inferTypes(actualParamTypes.get(i), parameterType, derivedValues);
}

int until = methodUsage.getDeclaration().hasVariadicParameter() ?
actualParamTypes.size() - 1 :
actualParamTypes.size();

for (int i = 0; i < until; i++) {
ResolvedType expectedType = methodUsage.getParamType(i);
ResolvedType actualType = actualParamTypes.get(i);
matchTypeParameters(expectedType, actualType, matchedTypeParameters);
for (Map.Entry<ResolvedTypeParameterDeclaration, ResolvedType> entry : derivedValues.entrySet()){
methodUsage = methodUsage.replaceTypeParameter(entry.getKey(), entry.getValue());
}
for (ResolvedTypeParameterDeclaration tp : matchedTypeParameters.keySet()) {
methodUsage = methodUsage.replaceTypeParameter(tp, matchedTypeParameters.get(tp));
}
return methodUsage;
}

private void matchTypeParameters(ResolvedType expectedType, ResolvedType actualType, Map<ResolvedTypeParameterDeclaration, ResolvedType> matchedTypeParameters) {
if (expectedType.isTypeVariable()) {
ResolvedType type = actualType;
// in case of primitive type, the expected type must be compared with the boxed type of the actual type
if (type.isPrimitive()) {
type = MyObjectProvider.INSTANCE.byName(type.asPrimitive().getBoxTypeQName());
}
/*
* "a value of the null type (the null reference is the only such value) may be assigned to any reference type, resulting in a null reference of that type"
* https://docs.oracle.com/javase/specs/jls/se15/html/jls-5.html#jls-5.2
*/
if (type.isNull()) {
type = MyObjectProvider.INSTANCE.object();
}
if (!type.isTypeVariable() && !type.isReferenceType()) {
throw new UnsupportedOperationException(type.getClass().getCanonicalName());
}
matchedTypeParameters.put(expectedType.asTypeParameter(), type);
} else if (expectedType.isArray()) {
// Issue 2258 : NullType must not fail this search
if (!(actualType.isArray() || actualType.isNull())) {
throw new UnsupportedOperationException(actualType.getClass().getCanonicalName());
}
matchTypeParameters(
expectedType.asArrayType().getComponentType(),
actualType.isNull() ? actualType : actualType.asArrayType().getComponentType(),
matchedTypeParameters);
} else if (expectedType.isReferenceType()) {
// avoid cases where the actual type has no type parameters but the expected one has. Such as: "classX extends classY<Integer>"
if (actualType.isReferenceType() && actualType.asReferenceType().typeParametersValues().size() > 0) {
int i = 0;
for (ResolvedType tp : expectedType.asReferenceType().typeParametersValues()) {
matchTypeParameters(tp, actualType.asReferenceType().typeParametersValues().get(i), matchedTypeParameters);
i++;
}
}
} else if (expectedType.isPrimitive()) {
// nothing to do
} else if (expectedType.isWildcard()) {
// nothing to do
} else {
throw new UnsupportedOperationException(expectedType.getClass().getCanonicalName());
}
return methodUsage;
}

private Optional<MethodUsage> solveMethodAsUsage(ResolvedTypeVariable tp, String name, List<ResolvedType> argumentsTypes, Context invokationContext) {
Expand Down
0