Skip to content

Commit

Permalink
Use CF constructor from use impl
Browse files Browse the repository at this point in the history
  • Loading branch information
Ao-senXiong committed Feb 27, 2024
1 parent 0b4b1db commit 767c165
Showing 1 changed file with 118 additions and 4 deletions.
122 changes: 118 additions & 4 deletions src/checkers/inference/InferenceAnnotatedTypeFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree;
import org.checkerframework.javacutil.TypesUtils;
import org.plumelib.util.CollectionsPlume;

/**
* InferenceAnnotatedTypeFactory is responsible for creating AnnotatedTypeMirrors that are annotated with
Expand Down Expand Up @@ -389,11 +391,126 @@ public ParameterizedExecutableType constructorFromUse(final NewClassTree newClas
"Current path:\n" + getVisitorTreePath();

final ExecutableElement constructorElem = TreeUtils.elementFromUse(newClassTree);

AnnotatedDeclaredType constructorReturnType =
(AnnotatedDeclaredType) toAnnotatedType(TreeUtils.typeOf(newClassTree), false);
addComputedTypeAnnotations(newClassTree, constructorReturnType);

final AnnotatedExecutableType constructorType = AnnotatedTypes.asMemberOf(types, this, constructorReturnType, constructorElem);
if (!TreeUtils.isDiamondTree(newClassTree)) {
if (newClassTree.getClassBody() == null) {
constructorReturnType.setTypeArguments(getExplicitNewClassClassTypeArgs(newClassTree));
}
} else {
constructorReturnType = getAnnotatedType(TypesUtils.getTypeElement(constructorReturnType.underlyingType));
// Add explicit annotations below.
constructorReturnType.clearAnnotations();
}

AnnotationMirrorSet explicitAnnos = getExplicitNewClassAnnos(newClassTree);
constructorReturnType.addAnnotations(explicitAnnos);

// Get the enclosing type of the constructor, if one exists.
// this.new InnerClass()
AnnotatedDeclaredType enclosingType = (AnnotatedDeclaredType) getReceiverType(newClassTree);
constructorReturnType.setEnclosingType(enclosingType);

// Add computed annotations to the type.
addComputedTypeAnnotations(newClassTree, constructorReturnType);

// final AnnotatedExecutableType constructorType = AnnotatedTypes.asMemberOf(types, this, constructorReturnType, constructorElem);
ExecutableElement ctor = TreeUtils.elementFromUse(newClassTree);
AnnotatedExecutableType constructorType = getAnnotatedType(ctor); // get unsubstituted type
constructorFromUsePreSubstitution(newClassTree, constructorType);

if (viewpointAdapter != null) {
viewpointAdapter.viewpointAdaptConstructor(constructorReturnType, constructorElem, constructorType);
}

if (newClassTree.getClassBody() != null) {
// Because the anonymous constructor can't have explicit annotations on its parameters,
// they are copied from the super constructor invoked in the anonymous constructor. To
// do this:
// 1. get unsubstituted type of the super constructor.
// 2. adapt it to this call site.
// 3. compute and store the vararg type.
// 4. copy the parameters to the anonymous constructor, `con`.
// 5. copy annotations on the return type to `con`.
AnnotatedExecutableType superCon =
getAnnotatedType(TreeUtils.getSuperConstructor(newClassTree));
constructorFromUsePreSubstitution(newClassTree, superCon);
// no viewpoint adaptation needed for super invocation
superCon =
AnnotatedTypes.asMemberOf(types, this, constructorReturnType, superCon.getElement(), superCon);
constructorType.computeVarargType(superCon);
if (superCon.getParameterTypes().size() == constructorType.getParameterTypes().size()) {
constructorType.setParameterTypes(superCon.getParameterTypes());
} else {
// If the super class of the anonymous class has an enclosing type, then it is the
// first parameter of the anonymous constructor. For example,
// class Outer { class Inner {} }
// new Inner(){};
// Then javac creates the following constructor:
// (.Outer x0) {
// x0.super();
// }
// So the code below deals with this.
List<AnnotatedTypeMirror> p =
new ArrayList<>(superCon.getParameterTypes().size() + 1);
if (TreeUtils.hasSyntheticArgument(newClassTree)) {
p.add(constructorType.getParameterTypes().get(0));
constructorType.setReceiverType(superCon.getReceiverType());
} else if (constructorType.getReceiverType() != null) {
// Because the anonymous constructor doesn't have annotated receiver type,
// we copy the receiver type from the super constructor invoked in the anonymous
// constructor and add it to the parameterTypes as the first element.
constructorType.setReceiverType(superCon.getReceiverType());
p.add(constructorType.getReceiverType());
} else {
p.add(constructorType.getParameterTypes().get(0));
}
p.addAll(1, superCon.getParameterTypes());
constructorType.setParameterTypes(Collections.unmodifiableList(p));
}
constructorType.getReturnType().replaceAnnotations(superCon.getReturnType().getAnnotations());
} else {
// Store varargType before calling setParameterTypes, otherwise we may lose the
// varargType as it is the last element of the original parameterTypes.
// AnnotatedTypes.asMemberOf handles vararg type properly, so we do not need to compute
// vararg type again.
constructorType.computeVarargType();
constructorType = AnnotatedTypes.asMemberOf(types, this, constructorReturnType, ctor, constructorType);
}

Map<TypeVariable, AnnotatedTypeMirror> typeParamToTypeArg =
AnnotatedTypes.findTypeArguments(processingEnv, this, newClassTree, ctor, constructorType);
List<AnnotatedTypeMirror> typeargs;
if (typeParamToTypeArg.isEmpty()) {
typeargs = Collections.emptyList();
} else {
typeargs =
CollectionsPlume.mapList(
(AnnotatedTypeMirror.AnnotatedTypeVariable tv) ->
typeParamToTypeArg.get(tv.getUnderlyingType()),
constructorType.getTypeVariables());
}
if (TreeUtils.isDiamondTree(newClassTree)) {
// TODO: This should be done at the same time as type argument inference.
List<AnnotatedTypeMirror> classTypeArgs = inferDiamondType(newClassTree);
int i = 0;
for (AnnotatedTypeMirror typeParam : constructorReturnType.getTypeArguments()) {
typeParamToTypeArg.put(
(TypeVariable) typeParam.getUnderlyingType(), classTypeArgs.get(i));
i++;
}
}
constructorType = (AnnotatedExecutableType) typeVarSubstitutor.substitute(typeParamToTypeArg, constructorType);

stubTypes.injectRecordComponentType(types, ctor, constructorType);
if (enclosingType != null) {
// Reset the enclosing type because it can be substituted incorrectly.
((AnnotatedDeclaredType) constructorType.getReturnType()).setEnclosingType(enclosingType);
}

// Take adapt parameter logic from AnnotatedTypeFactory#constructorFromUse to
// InferenceAnnotatedTypeFactory#constructorFromUse.
// Store varargType before calling setParameterTypes, otherwise we may lose the
Expand All @@ -407,9 +524,6 @@ public ParameterizedExecutableType constructorFromUse(final NewClassTree newClas
List<AnnotatedTypeMirror> parameters =
AnnotatedTypes.adaptParameters(this, constructorType, newClassTree.getArguments());
constructorType.setParameterTypes(parameters);
if (viewpointAdapter != null) {
viewpointAdapter.viewpointAdaptConstructor(constructorReturnType, constructorElem, constructorType);
}

ParameterizedExecutableType substitutedPair = substituteTypeArgs(newClassTree, constructorElem, constructorType);
inferencePoly.replacePolys(newClassTree, substitutedPair.executableType);
Expand Down

0 comments on commit 767c165

Please sign in to comment.