use of javax.lang.model.type.TypeVariable in project checker-framework by typetools.
the class AnnotatedTypeFactory method methodFromUse.
/**
* Determines the type of the invoked method based on the passed expression tree, executable
* element, and receiver type.
*
* @param tree either a MethodInvocationTree or a MemberReferenceTree
* @param methodElt the element of the referenced method
* @param receiverType the type of the receiver
* @return the method type being invoked with tree and the (inferred) type arguments
* @see #methodFromUse(MethodInvocationTree)
*/
public ParameterizedExecutableType methodFromUse(ExpressionTree tree, ExecutableElement methodElt, AnnotatedTypeMirror receiverType) {
AnnotatedExecutableType memberTypeWithoutOverrides = // get unsubstituted type
getAnnotatedType(methodElt);
AnnotatedExecutableType memberTypeWithOverrides = applyFakeOverrides(receiverType, methodElt, memberTypeWithoutOverrides);
memberTypeWithOverrides = applyRecordTypesToAccessors(methodElt, memberTypeWithOverrides);
methodFromUsePreSubstitution(tree, memberTypeWithOverrides);
AnnotatedExecutableType methodType = AnnotatedTypes.asMemberOf(types, this, receiverType, methodElt, memberTypeWithOverrides);
List<AnnotatedTypeMirror> typeargs = new ArrayList<>(methodType.getTypeVariables().size());
Map<TypeVariable, AnnotatedTypeMirror> typeParamToTypeArg = AnnotatedTypes.findTypeArguments(processingEnv, this, tree, methodElt, methodType);
if (!typeParamToTypeArg.isEmpty()) {
typeParamToTypeArg = captureMethodTypeArgs(typeParamToTypeArg, memberTypeWithOverrides.getTypeVariables());
for (AnnotatedTypeVariable tv : methodType.getTypeVariables()) {
if (typeParamToTypeArg.get(tv.getUnderlyingType()) == null) {
throw new BugInCF("AnnotatedTypeFactory.methodFromUse:mismatch between declared method type variables" + " and the inferred method type arguments. Method type variables: " + methodType.getTypeVariables() + "; " + "Inferred method type arguments: " + typeParamToTypeArg);
}
typeargs.add(typeParamToTypeArg.get(tv.getUnderlyingType()));
}
methodType = (AnnotatedExecutableType) typeVarSubstitutor.substitute(typeParamToTypeArg, methodType);
}
if (tree.getKind() == Tree.Kind.METHOD_INVOCATION && TreeUtils.isMethodInvocation(tree, objectGetClass, processingEnv)) {
adaptGetClassReturnTypeToReceiver(methodType, receiverType, tree);
}
return new ParameterizedExecutableType(methodType, typeargs);
}
use of javax.lang.model.type.TypeVariable in project checker-framework by typetools.
the class AnnotatedTypeFactory method constructorFromUse.
/**
* Determines the type of the invoked constructor based on the passed new class tree.
*
* <p>The returned method type has all type variables resolved, whether based on receiver type,
* passed type parameters if any, and constructor invocation parameter.
*
* <p>Subclasses may override this method to customize inference of types or qualifiers based on
* constructor invocation parameters.
*
* <p>As an implementation detail, this method depends on {@link AnnotatedTypes#asMemberOf(Types,
* AnnotatedTypeFactory, AnnotatedTypeMirror, Element)}, and customization based on receiver type
* should be in accordance with its specification.
*
* <p>The return type is a pair of the type of the invoked constructor and the (inferred) type
* arguments. Note that neither the explicitly passed nor the inferred type arguments are
* guaranteed to be subtypes of the corresponding upper bounds. See method {@link
* org.checkerframework.common.basetype.BaseTypeVisitor#checkTypeArguments} for the checks of type
* argument well-formedness.
*
* <p>Note that "this" and "super" constructor invocations are handled by method {@link
* #methodFromUse}. This method only handles constructor invocations in a "new" expression.
*
* @param tree the constructor invocation tree
* @return the annotated type of the invoked constructor (as an executable type) and the
* (inferred) type arguments
*/
public ParameterizedExecutableType constructorFromUse(NewClassTree tree) {
AnnotatedTypeMirror type = fromNewClass(tree);
addComputedTypeAnnotations(tree, type);
ExecutableElement ctor = TreeUtils.constructor(tree);
// get unsubstituted type
AnnotatedExecutableType con = getAnnotatedType(ctor);
if (TreeUtils.hasSyntheticArgument(tree)) {
AnnotatedExecutableType t = (AnnotatedExecutableType) getAnnotatedType(((JCNewClass) tree).constructor);
List<AnnotatedTypeMirror> p = new ArrayList<>(con.getParameterTypes().size() + 1);
p.add(t.getParameterTypes().get(0));
p.addAll(1, con.getParameterTypes());
t.setParameterTypes(p);
con = t;
}
constructorFromUsePreSubstitution(tree, con);
con = AnnotatedTypes.asMemberOf(types, this, type, ctor, con);
Map<TypeVariable, AnnotatedTypeMirror> typeParamToTypeArg = AnnotatedTypes.findTypeArguments(processingEnv, this, tree, ctor, con);
List<AnnotatedTypeMirror> typeargs;
if (typeParamToTypeArg.isEmpty()) {
typeargs = Collections.emptyList();
} else {
typeargs = CollectionsPlume.mapList((AnnotatedTypeVariable tv) -> typeParamToTypeArg.get(tv.getUnderlyingType()), con.getTypeVariables());
con = (AnnotatedExecutableType) typeVarSubstitutor.substitute(typeParamToTypeArg, con);
}
stubTypes.injectRecordComponentType(types, ctor, con);
return new ParameterizedExecutableType(con, typeargs);
}
use of javax.lang.model.type.TypeVariable in project checker-framework by typetools.
the class BoundsInitializer method initializeTypeArgs.
// ============================================================================================
// Static helper methods called from AnnotatedTypeMirror to initialize bounds of wildcards or
// type variables
// ============================================================================================
/**
* Initializes the type arguments of {@code declaredType}. The upper bound of unbound wildcards is
* set to the upper bound of the type parameter for which it is an argument. If {@code
* declaredType} is raw, then the type arguments are uninferred wildcards.
*
* @param declaredType type whose arguments are initialized
*/
public static void initializeTypeArgs(AnnotatedDeclaredType declaredType) {
final DeclaredType underlyingType = (DeclaredType) declaredType.underlyingType;
if (underlyingType.getTypeArguments().isEmpty() && !declaredType.isUnderlyingTypeRaw()) {
// No type arguments to initialize.
return;
}
final TypeElement typeElement = (TypeElement) declaredType.atypeFactory.types.asElement(underlyingType);
int numTypeParameters = typeElement.getTypeParameters().size();
final List<AnnotatedTypeMirror> typeArgs = new ArrayList<>(numTypeParameters);
// Create AnnotatedTypeMirror for each type argument and store them in the typeArgsMap.
// Take un-annotated type variables as the key for this map.
Map<TypeVariable, AnnotatedTypeMirror> typeArgMap = new HashMap<>(numTypeParameters);
for (int i = 0; i < numTypeParameters; i++) {
TypeMirror javaTypeArg;
if (declaredType.isUnderlyingTypeRaw()) {
TypeVariable typeVariable = (TypeVariable) typeElement.getTypeParameters().get(i).asType();
javaTypeArg = getUpperBoundAsWildcard(typeVariable, declaredType.atypeFactory);
} else {
javaTypeArg = declaredType.getUnderlyingType().getTypeArguments().get(i);
}
final AnnotatedTypeMirror typeArg = AnnotatedTypeMirror.createType(javaTypeArg, declaredType.atypeFactory, declaredType.isDeclaration());
if (typeArg.getKind() == TypeKind.WILDCARD) {
AnnotatedWildcardType wildcardType = (AnnotatedWildcardType) typeArg;
wildcardType.setTypeVariable(typeElement.getTypeParameters().get(i));
if (declaredType.isUnderlyingTypeRaw()) {
wildcardType.setUninferredTypeArgument();
}
}
typeArgs.add(typeArg);
// Add mapping from type parameter to the annotated type argument.
TypeVariable key = (TypeVariable) TypeAnnotationUtils.unannotatedType(typeElement.getTypeParameters().get(i).asType());
typeArgMap.put(key, typeArg);
if (javaTypeArg.getKind() == TypeKind.TYPEVAR) {
// Add mapping from Java type argument to the annotated type argument.
key = (TypeVariable) TypeAnnotationUtils.unannotatedType(javaTypeArg);
typeArgMap.put(key, typeArg);
}
}
// Initialize type argument bounds using the typeArgsMap.
for (AnnotatedTypeMirror typeArg : typeArgs) {
switch(typeArg.getKind()) {
case WILDCARD:
AnnotatedWildcardType wildcardType = (AnnotatedWildcardType) typeArg;
initializeExtendsBound(wildcardType, typeArgMap);
initializeSuperBound(wildcardType, typeArgMap);
break;
case TYPEVAR:
initializeBounds((AnnotatedTypeVariable) typeArg, typeArgMap);
break;
default:
}
}
declaredType.typeArgs = Collections.unmodifiableList(typeArgs);
}
use of javax.lang.model.type.TypeVariable in project checker-framework by typetools.
the class AnnotatedTypeFactory method makeGroundTargetType.
/**
* Create the ground target type of the functional interface.
*
* <p>Basically, it replaces the wildcards with their bounds doing a capture conversion like glb
* for extends bounds.
*
* @see "JLS 9.9"
* @param functionalType the functional interface type
* @param groundTargetJavaType the Java type as found by javac
* @return the grounded functional type
*/
private AnnotatedDeclaredType makeGroundTargetType(AnnotatedDeclaredType functionalType, DeclaredType groundTargetJavaType) {
if (functionalType.getTypeArguments().isEmpty()) {
return functionalType;
}
List<AnnotatedTypeParameterBounds> bounds = this.typeVariablesFromUse(functionalType, (TypeElement) functionalType.getUnderlyingType().asElement());
boolean sizesDiffer = functionalType.getTypeArguments().size() != groundTargetJavaType.getTypeArguments().size();
// This is the declared type of the functional type meaning that the type arguments are the
// type parameters.
DeclaredType declaredType = (DeclaredType) functionalType.getUnderlyingType().asElement().asType();
Map<TypeVariable, AnnotatedTypeMirror> typeVarToTypeArg = new HashMap<>(functionalType.getTypeArguments().size());
for (int i = 0; i < functionalType.getTypeArguments().size(); i++) {
TypeVariable typeVariable = (TypeVariable) declaredType.getTypeArguments().get(i);
AnnotatedTypeMirror argType = functionalType.getTypeArguments().get(i);
if (argType.getKind() == TypeKind.WILDCARD) {
AnnotatedWildcardType wildcardType = (AnnotatedWildcardType) argType;
TypeMirror wildcardUbType = wildcardType.getExtendsBound().getUnderlyingType();
if (wildcardType.isUninferredTypeArgument()) {
// Keep the uninferred type so that it is ignored by later subtyping and containment
// checks.
typeVarToTypeArg.put(typeVariable, wildcardType);
} else if (isExtendsWildcard(wildcardType)) {
TypeMirror correctArgType;
if (sizesDiffer) {
// The Java type is raw.
TypeMirror typeParamUbType = bounds.get(i).getUpperBound().getUnderlyingType();
correctArgType = TypesUtils.greatestLowerBound(typeParamUbType, wildcardUbType, this.checker.getProcessingEnvironment());
} else {
correctArgType = groundTargetJavaType.getTypeArguments().get(i);
}
final AnnotatedTypeMirror newArg;
if (types.isSameType(wildcardUbType, correctArgType)) {
newArg = wildcardType.getExtendsBound().deepCopy();
} else if (correctArgType.getKind() == TypeKind.TYPEVAR) {
newArg = this.toAnnotatedType(correctArgType, false);
AnnotatedTypeVariable newArgAsTypeVar = (AnnotatedTypeVariable) newArg;
newArgAsTypeVar.getUpperBound().replaceAnnotations(wildcardType.getExtendsBound().getAnnotations());
newArgAsTypeVar.getLowerBound().replaceAnnotations(wildcardType.getSuperBound().getAnnotations());
} else {
newArg = this.toAnnotatedType(correctArgType, false);
newArg.replaceAnnotations(wildcardType.getExtendsBound().getAnnotations());
}
typeVarToTypeArg.put(typeVariable, newArg);
} else {
typeVarToTypeArg.put(typeVariable, wildcardType.getSuperBound());
}
} else {
typeVarToTypeArg.put(typeVariable, argType);
}
}
// The ground functional type must be created using type variable substitution or else the
// underlying type will not match the annotated type.
AnnotatedDeclaredType groundFunctionalType = (AnnotatedDeclaredType) AnnotatedTypeMirror.createType(declaredType, this, functionalType.isDeclaration());
initializeAtm(groundFunctionalType);
groundFunctionalType = (AnnotatedDeclaredType) getTypeVarSubstitutor().substitute(typeVarToTypeArg, groundFunctionalType);
groundFunctionalType.addAnnotations(functionalType.getAnnotations());
// When the groundTargetJavaType is different from the underlying type of functionalType, only
// the main annotations are copied. Add default annotations in places without annotations.
addDefaultAnnotations(groundFunctionalType);
return groundFunctionalType;
}
use of javax.lang.model.type.TypeVariable in project checker-framework by typetools.
the class AnnotatedTypeFactory method applyCaptureConversion.
/**
* Apply capture conversion to {@code type}.
*
* <p>Capture conversion is the process of converting wildcards in a parameterized type to fresh
* type variables. See <a
* href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-5.html#jls-5.1.10">JLS 5.1.10</a>
* for details.
*
* <p>If {@code type} is not a declared type or if it does not have any wildcard type arguments,
* this method returns {@code type}.
*
* @param type type to capture
* @param typeMirror the result of applying capture conversion to the underlying type of {@code
* type}; it is used as the underlying type of the returned type
* @return the result of applying capture conversion to {@code type}
*/
public AnnotatedTypeMirror applyCaptureConversion(AnnotatedTypeMirror type, TypeMirror typeMirror) {
// shuuld have been captured as "uninferred" before it is returned.
if (type.containsUninferredTypeArguments() && typeMirror.getKind() == TypeKind.DECLARED && type.getKind() == TypeKind.DECLARED) {
AnnotatedDeclaredType uncapturedType = (AnnotatedDeclaredType) type;
DeclaredType capturedTypeMirror = (DeclaredType) typeMirror;
for (int i = 0; i < capturedTypeMirror.getTypeArguments().size(); i++) {
AnnotatedTypeMirror uncapturedTypeArg = uncapturedType.getTypeArguments().get(i);
TypeMirror capturedTypeArgTM = capturedTypeMirror.getTypeArguments().get(i);
if (uncapturedTypeArg.getKind() == TypeKind.WILDCARD && (TypesUtils.isCapturedTypeVariable(capturedTypeArgTM) || capturedTypeArgTM.getKind() != TypeKind.WILDCARD)) {
((AnnotatedWildcardType) uncapturedTypeArg).setUninferredTypeArgument();
}
}
return type;
}
if (!shouldCapture(type, typeMirror)) {
return type;
}
AnnotatedDeclaredType uncapturedType = (AnnotatedDeclaredType) type;
DeclaredType capturedTypeMirror = (DeclaredType) typeMirror;
// `capturedType` is the return value of this method.
AnnotatedDeclaredType capturedType = (AnnotatedDeclaredType) AnnotatedTypeMirror.createType(capturedTypeMirror, this, false);
nonWildcardTypeArgCopier.copy(uncapturedType, capturedType);
AnnotatedDeclaredType typeDeclaration = (AnnotatedDeclaredType) getAnnotatedType(uncapturedType.getUnderlyingType().asElement());
// A mapping from type variable to its type argument in the captured type.
Map<TypeVariable, AnnotatedTypeMirror> typeVarToAnnotatedTypeArg = new HashMap<>();
// A mapping from a captured type variable to the annotated captured type variable.
Map<TypeVariable, AnnotatedTypeVariable> capturedTypeVarToAnnotatedTypeVar = new HashMap<>();
// `newTypeArgs` will be the type arguments of the result of this method.
List<AnnotatedTypeMirror> newTypeArgs = new ArrayList<>();
for (int i = 0; i < typeDeclaration.getTypeArguments().size(); i++) {
TypeVariable typeVarTypeMirror = (TypeVariable) typeDeclaration.getTypeArguments().get(i).getUnderlyingType();
AnnotatedTypeMirror uncapturedTypeArg = uncapturedType.getTypeArguments().get(i);
AnnotatedTypeMirror capturedTypeArg = capturedType.getTypeArguments().get(i);
if (uncapturedTypeArg.getKind() == TypeKind.WILDCARD) {
// The type argument is a captured type variable. Use the type argument from the newly
// created and yet-to-be annotated capturedType. (The annotations are added by
// #annotateCapturedTypeVar, which is called at the end of this method.)
typeVarToAnnotatedTypeArg.put(typeVarTypeMirror, capturedTypeArg);
newTypeArgs.add(capturedTypeArg);
if (TypesUtils.isCapturedTypeVariable(capturedTypeArg.getUnderlyingType())) {
// Also, add a mapping from the captured type variable to the annotated captured
// type variable, so that if one captured type variable refers to another, the same
// AnnotatedTypeVariable object is used.
capturedTypeVarToAnnotatedTypeVar.put(((AnnotatedTypeVariable) capturedTypeArg).getUnderlyingType(), (AnnotatedTypeVariable) capturedTypeArg);
} else {
// Javac used a declared type instead of a captured type variable. This seems to happen
// when the bounds of the captured type variable would have been identical. This seems to
// be a violation of the JLS, but javac does this, so the Checker Framework must handle
// that case. (See https://bugs.openjdk.java.net/browse/JDK-8054309.)
replaceAnnotations(((AnnotatedWildcardType) uncapturedTypeArg).getSuperBound(), capturedTypeArg);
}
} else {
// The type argument is not a wildcard.
// typeVarTypeMirror is the type parameter for which uncapturedTypeArg is a type argument.
typeVarToAnnotatedTypeArg.put(typeVarTypeMirror, uncapturedTypeArg);
if (uncapturedTypeArg.getKind() == TypeKind.TYPEVAR) {
// If the type arg is a type variable also add it to the typeVarToAnnotatedTypeArg map, so
// that references to the type variable are substituted.
AnnotatedTypeVariable typeVar = (AnnotatedTypeVariable) uncapturedTypeArg;
typeVarToAnnotatedTypeArg.put(typeVar.getUnderlyingType(), typeVar);
}
newTypeArgs.add(uncapturedTypeArg);
}
}
// Set the annotations of each captured type variable.
List<AnnotatedTypeVariable> orderToCapture = order(capturedTypeVarToAnnotatedTypeVar.values());
for (AnnotatedTypeVariable capturedTypeArg : orderToCapture) {
int i = capturedTypeMirror.getTypeArguments().indexOf(capturedTypeArg.getUnderlyingType());
AnnotatedTypeMirror uncapturedTypeArg = uncapturedType.getTypeArguments().get(i);
AnnotatedTypeVariable typeVariable = (AnnotatedTypeVariable) typeDeclaration.getTypeArguments().get(i);
annotateCapturedTypeVar(typeVarToAnnotatedTypeArg, capturedTypeVarToAnnotatedTypeVar, (AnnotatedWildcardType) uncapturedTypeArg, typeVariable, capturedTypeArg);
newTypeArgs.set(i, capturedTypeArg);
}
capturedType.setTypeArguments(newTypeArgs);
capturedType.addAnnotations(uncapturedType.getAnnotations());
return capturedType;
}
Aggregations