forked from typetools/checker-framework
-
Notifications
You must be signed in to change notification settings - Fork 29
Extract ATF#get(Constructor/Method)ReceiverType helpers
#1872
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
Open
wmdietl
wants to merge
6
commits into
master
Choose a base branch
from
atf-helpers
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
1322f70
Use adapted bounds for method type arguments
aosen-xiong 8060201
Merge branch 'master' into method-typevariables-from-use
aosen-xiong f7cbccc
Reuse method receiver handling for type-variable bounds
aosen-xiong f49d910
Merge branch 'master' into method-typevariables-from-use
wmdietl c2323bc
Viewpoint adapt constructor type variable bounds and extract receiver…
wmdietl 17ecf33
Merge branch 'master' into atf-helpers
wmdietl File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1280,7 +1280,7 @@ | |
| /** | ||
| * TypeVariableSubstitutor provides a method to replace type parameters with their arguments. | ||
| */ | ||
| protected TypeVariableSubstitutor createTypeVariableSubstitutor() { | ||
|
Check warning on line 1283 in framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java
|
||
| return new TypeVariableSubstitutor(); | ||
| } | ||
|
|
||
|
|
@@ -1342,7 +1342,7 @@ | |
| * annotation classes. Subclasses can override this method and return a custom | ||
| * AnnotationClassLoader subclass to customize loading logic. | ||
| */ | ||
| protected AnnotationClassLoader createAnnotationClassLoader() { | ||
|
Check warning on line 1345 in framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java
|
||
| return new AnnotationClassLoader(checker); | ||
| } | ||
|
|
||
|
|
@@ -2446,6 +2446,116 @@ | |
| return res; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the method type-variable bounds adapted to the viewpoint of a method invocation. | ||
| * | ||
| * @param tree a method invocation | ||
| * @param invokedMethod the type of the invoked method | ||
| * @return the adapted method type parameter bounds | ||
| */ | ||
| public List<AnnotatedTypeParameterBounds> methodTypeVariableBoundsFromUse( | ||
| MethodInvocationTree tree, AnnotatedExecutableType invokedMethod) { | ||
| List<AnnotatedTypeParameterBounds> bounds = | ||
| CollectionsPlume.mapList( | ||
| AnnotatedTypeVariable::getBounds, invokedMethod.getTypeVariables()); | ||
|
|
||
| AnnotatedTypeMirror receiverType = getMethodReceiverType(tree); | ||
| if (viewpointAdapter != null && receiverType != null) { | ||
| viewpointAdapter.viewpointAdaptTypeParameterBounds(receiverType, bounds); | ||
| } | ||
| return bounds; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the constructor type-variable bounds adapted to the viewpoint of a constructor | ||
| * invocation. | ||
| * | ||
| * @param tree a constructor invocation | ||
| * @param invokedConstructor the type of the invoked constructor | ||
| * @return the adapted constructor type parameter bounds | ||
| */ | ||
| public List<AnnotatedTypeParameterBounds> constructorTypeVariableBoundsFromUse( | ||
| NewClassTree tree, AnnotatedExecutableType invokedConstructor) { | ||
| List<AnnotatedTypeParameterBounds> bounds = | ||
| CollectionsPlume.mapList( | ||
| AnnotatedTypeVariable::getBounds, invokedConstructor.getTypeVariables()); | ||
|
|
||
| if (viewpointAdapter != null) { | ||
| AnnotatedTypeMirror receiverType = getConstructorReceiverType(tree); | ||
| viewpointAdapter.viewpointAdaptTypeParameterBounds(receiverType, bounds); | ||
| } | ||
| return bounds; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the receiver type used to viewpoint-adapt a constructor invocation. | ||
| * | ||
| * @param tree a constructor invocation tree | ||
| * @return the receiver type | ||
| * @see #getReceiverType(ExpressionTree) | ||
| * @see #getMethodReceiverType(MethodInvocationTree) | ||
| */ | ||
| public AnnotatedDeclaredType getConstructorReceiverType(NewClassTree tree) { | ||
| // Get the annotations written on the new class tree. | ||
| AnnotatedDeclaredType type = | ||
| (AnnotatedDeclaredType) toAnnotatedType(TreeUtils.typeOf(tree), false); | ||
| if (!TreeUtils.isDiamondTree(tree)) { | ||
| if (tree.getClassBody() == null) { | ||
| type.setTypeArguments(getExplicitNewClassClassTypeArgs(tree)); | ||
| } | ||
| } else { | ||
| type = getAnnotatedType(TypesUtils.getTypeElement(type.underlyingType)); | ||
| // Add explicit annotations below. | ||
| type.clearAnnotations(); | ||
| } | ||
|
|
||
| AnnotationMirrorSet explicitAnnos = getExplicitNewClassAnnos(tree); | ||
| type.addAnnotations(explicitAnnos); | ||
|
|
||
| // Get the enclosing type of the constructor, if one exists. | ||
| // this.new InnerClass() | ||
| AnnotatedDeclaredType enclosingType = (AnnotatedDeclaredType) getReceiverType(tree); | ||
| if (enclosingType != null && enclosingType.isFrozen()) { | ||
| // getReceiverType may return a shared frozen cache value; it is embedded in `type` and | ||
| // mutated by addComputedTypeAnnotations below, so copy it first. | ||
| enclosingType = enclosingType.deepCopy(); | ||
| } | ||
| type.setEnclosingType(enclosingType); | ||
|
|
||
| // Add computed annotations to the type. | ||
| addComputedTypeAnnotations(tree, type); | ||
|
|
||
| return type; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the receiver type used to viewpoint-adapt a method invocation. | ||
| * | ||
| * @param tree a method invocation tree | ||
| * @return the receiver type, or null if the invocation has no receiver | ||
| * @see #getReceiverType(ExpressionTree) | ||
| * @see #getConstructorReceiverType(NewClassTree) | ||
| */ | ||
| public @Nullable AnnotatedTypeMirror getMethodReceiverType(MethodInvocationTree tree) { | ||
| ExecutableElement methodElt = TreeUtils.elementFromUse(tree); | ||
| if (ElementUtils.isStatic(methodElt)) { | ||
| return null; | ||
| } | ||
|
|
||
| AnnotatedTypeMirror receiverType = getReceiverType(tree); | ||
| if (receiverType == null | ||
| && (TreeUtils.isSuperConstructorCall(tree) | ||
| || TreeUtils.isThisConstructorCall(tree))) { | ||
| // super() and this() calls don't have a receiver, but they should be view-point adapted | ||
| // as if "this" is the receiver. | ||
| receiverType = getSelfType(tree); | ||
| } | ||
| if (receiverType != null && receiverType.getKind() == TypeKind.DECLARED) { | ||
| receiverType = applyCaptureConversion(receiverType); | ||
| } | ||
| return receiverType; | ||
| } | ||
|
|
||
| /** | ||
| * Creates and returns an AnnotatedNullType qualified with {@code annotations}. | ||
| * | ||
|
|
@@ -2660,6 +2770,8 @@ | |
| * | ||
| * @param expression the expression for which to determine the receiver type | ||
| * @return the type of the receiver of expression | ||
| * @see #getMethodReceiverType(MethodInvocationTree) | ||
| * @see #getConstructorReceiverType(NewClassTree) | ||
| */ | ||
| public final @Nullable AnnotatedTypeMirror getReceiverType(ExpressionTree expression) { | ||
| AnnotatedTypeMirror receiverType; | ||
|
|
@@ -2781,17 +2893,7 @@ | |
| protected ParameterizedExecutableType methodFromUse( | ||
| MethodInvocationTree tree, boolean inferTypeArgs) { | ||
| ExecutableElement methodElt = TreeUtils.elementFromUse(tree); | ||
| AnnotatedTypeMirror receiverType = getReceiverType(tree); | ||
| if (receiverType == null | ||
| && (TreeUtils.isSuperConstructorCall(tree) | ||
| || TreeUtils.isThisConstructorCall(tree))) { | ||
| // super() and this() calls don't have a receiver, but they should be view-point adapted | ||
| // as if "this" is the receiver. | ||
| receiverType = getSelfType(tree); | ||
| } | ||
| if (receiverType != null && receiverType.getKind() == TypeKind.DECLARED) { | ||
| receiverType = applyCaptureConversion(receiverType); | ||
| } | ||
| AnnotatedTypeMirror receiverType = getMethodReceiverType(tree); | ||
|
|
||
| ParameterizedExecutableType result = | ||
| methodFromUse(tree, methodElt, receiverType, inferTypeArgs); | ||
|
|
@@ -3519,34 +3621,7 @@ | |
| */ | ||
| protected ParameterizedExecutableType constructorFromUse( | ||
| NewClassTree tree, boolean inferTypeArgs) { | ||
| // Get the annotations written on the new class tree. | ||
| AnnotatedDeclaredType type = | ||
| (AnnotatedDeclaredType) toAnnotatedType(TreeUtils.typeOf(tree), false); | ||
| if (!TreeUtils.isDiamondTree(tree)) { | ||
| if (tree.getClassBody() == null) { | ||
| type.setTypeArguments(getExplicitNewClassClassTypeArgs(tree)); | ||
| } | ||
| } else { | ||
| type = getAnnotatedType(TypesUtils.getTypeElement(type.underlyingType)); | ||
| // Add explicit annotations below. | ||
| type.clearAnnotations(); | ||
| } | ||
|
|
||
| AnnotationMirrorSet explicitAnnos = getExplicitNewClassAnnos(tree); | ||
| type.addAnnotations(explicitAnnos); | ||
|
|
||
| // Get the enclosing type of the constructor, if one exists. | ||
| // this.new InnerClass() | ||
| AnnotatedDeclaredType enclosingType = (AnnotatedDeclaredType) getReceiverType(tree); | ||
| if (enclosingType != null && enclosingType.isFrozen()) { | ||
| // getReceiverType may return a shared frozen cache value; it is embedded in `type` and | ||
| // mutated by addComputedTypeAnnotations below, so copy it first. | ||
| enclosingType = enclosingType.deepCopy(); | ||
| } | ||
| type.setEnclosingType(enclosingType); | ||
|
|
||
| // Add computed annotations to the type. | ||
| addComputedTypeAnnotations(tree, type); | ||
| AnnotatedDeclaredType type = getConstructorReceiverType(tree); | ||
|
|
||
| ExecutableElement ctor = TreeUtils.elementFromUse(tree); | ||
| AnnotatedExecutableType con = getAnnotatedType(ctor); // get unsubstituted type | ||
|
|
@@ -3645,9 +3720,9 @@ | |
| addDefaultAnnotations(returnType); | ||
| con.setReturnType(returnType); | ||
| } | ||
| if (enclosingType != null) { | ||
| if (type.getEnclosingType() != null) { | ||
| // Reset the enclosing type because it can be substituted incorrectly. | ||
| ((AnnotatedDeclaredType) con.getReturnType()).setEnclosingType(enclosingType); | ||
| ((AnnotatedDeclaredType) con.getReturnType()).setEnclosingType(type.getEnclosingType()); | ||
| } | ||
| if (type.isUnderlyingTypeRaw() || TypesUtils.isRaw(TreeUtils.typeOf(tree))) { | ||
| ((AnnotatedDeclaredType) con.getReturnType()).setIsUnderlyingTypeRaw(); | ||
|
|
||
19 changes: 19 additions & 0 deletions
19
framework/tests/viewpointtest/ConstructorTypeVariableBounds.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import viewpointtest.quals.*; | ||
|
|
||
| public class ConstructorTypeVariableBounds { | ||
| static class MyClass { | ||
| <T extends @ReceiverDependentQual Object> MyClass(T t) {} | ||
| } | ||
|
|
||
| void test(@Top Object top, @A Object a, @B Object b, @Bottom Object bottom) { | ||
|
|
||
| // :: error: (type.argument.type.incompatible) :: error: (new.class.type.invalid) | ||
| new <@Top Object>@Top MyClass(top); | ||
|
|
||
| // :: warning: (cast.unsafe.constructor.invocation) | ||
| new <@A Object>@A MyClass(a); | ||
|
|
||
| // :: warning: (cast.unsafe.constructor.invocation) | ||
| new <@B Object>@B MyClass(b); | ||
| } | ||
| } |
72 changes: 72 additions & 0 deletions
72
framework/tests/viewpointtest/MethodTypeVariableBounds.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| import viewpointtest.quals.*; | ||
|
|
||
| public class MethodTypeVariableBounds { | ||
| static class Methods { | ||
| <T extends @ReceiverDependentQual Object> void noArg() {} | ||
|
|
||
| <T extends @ReceiverDependentQual Object> void withArg(T t) {} | ||
| } | ||
|
|
||
| void topReceiver( | ||
| @Top Methods methods, | ||
| @Top Object top, | ||
| @A Object a, | ||
| @B Object b, | ||
| @Bottom Object bottom) { | ||
| // @Top viewpoint-adapts @ReceiverDependentQual to @Lost, so only @Bottom is within the | ||
| // adapted method type parameter bound. | ||
| // :: error: (type.argument.type.incompatible) | ||
| methods.noArg(); | ||
|
|
||
| // :: error: (type.argument.type.incompatible) | ||
| methods.<@Top Object>withArg(top); | ||
|
|
||
| // :: error: (type.argument.type.incompatible) | ||
| methods.<@A Object>withArg(a); | ||
|
|
||
| // :: error: (type.argument.type.incompatible) | ||
| methods.<@B Object>withArg(b); | ||
|
|
||
| methods.<@Bottom Object>withArg(bottom); | ||
|
|
||
| // :: error: (type.arguments.not.inferred) | ||
| methods.withArg(top); | ||
|
|
||
| // :: error: (type.arguments.not.inferred) | ||
| methods.withArg(a); | ||
|
|
||
| // :: error: (type.arguments.not.inferred) | ||
| methods.withArg(b); | ||
|
|
||
| methods.withArg(bottom); | ||
| } | ||
|
|
||
| void aReceiver( | ||
| @A Methods methods, @Top Object top, @A Object a, @B Object b, @Bottom Object bottom) { | ||
| // @A viewpoint-adapts @ReceiverDependentQual to @A, so @A and @Bottom are within the | ||
| // adapted method type parameter bound. | ||
| // :: error: (type.argument.type.incompatible) | ||
| methods.noArg(); | ||
|
|
||
| // :: error: (type.argument.type.incompatible) | ||
| methods.<@Top Object>withArg(top); | ||
|
|
||
| methods.<@A Object>withArg(a); | ||
|
|
||
| // :: error: (type.argument.type.incompatible) | ||
| methods.<@B Object>withArg(b); | ||
|
|
||
| methods.<@Bottom Object>withArg(bottom); | ||
|
|
||
| // :: error: (type.arguments.not.inferred) | ||
| methods.withArg(top); | ||
|
|
||
| // :: error: (type.arguments.not.inferred) | ||
| methods.withArg(a); | ||
|
|
||
| // :: error: (type.arguments.not.inferred) | ||
| methods.withArg(b); | ||
|
|
||
| methods.withArg(bottom); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this line should not issue an error.
Let me think about how to combine this with #1850.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test cases are from #1850 and I didn't touch them. The point of this branch is extracting the logic... which isn't re-used anymore (as it was in that earlier version of #1850), but it might still be nice to extract.