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
External Library Models: Adding support for Nullable upper bounds of Generic Type parameters #949
base: master
Are you sure you want to change the base?
Conversation
…ernal library models
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #949 +/- ##
============================================
- Coverage 86.08% 85.98% -0.11%
- Complexity 2018 2023 +5
============================================
Files 79 80 +1
Lines 6612 6663 +51
Branches 1280 1288 +8
============================================
+ Hits 5692 5729 +37
- Misses 510 524 +14
Partials 410 410 ☔ View full report in Codecov by Sentry. |
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 have a few initial comments. I got lost reviewing the changes under nullaway/src/main/java/com/uber/nullaway/handlers
. Can you describe the purpose of the new StubxCacheUtil
class and how the refactored code works, for both old JarInfer stubs and newly generated ones?
@@ -45,4 +45,11 @@ public String returnNull() { | |||
return null; | |||
} | |||
} | |||
|
|||
public static class GenericExample<T extends @Nullable Object> { |
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.
Let's call this UpperBoundExample
"package com.uber;", | ||
"import org.jspecify.annotations.Nullable;", | ||
"import com.uber.nullaway.libmodel.AnnotationExample;", | ||
"class Test {", |
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 would suggest we also update the libraryModelWithoutJarInferEnabledTest
test. But I think we will get errors there even without the modeling due to #872
methodRecords.put( | ||
parentName + ":" + GENERIC_TYPE_IDENTIFIER, | ||
MethodAnnotationsRecord.create(ImmutableSet.of(), genericParamAnnotationsMap)); |
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.
At first glance this seems rather hacky. Why are we reusing the methodRecords
map and the MethodAnnotationsRecord
class when the upper bound is on a type variable? At least for this case, the type variable is declared on a class, not a method. I'd prefer we just create a separate data structure for class or type variable records
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 agree, it is very hacky. I will use a separate data structure and work on a way to integrate it within the cache.
We insert a specialized MethodAnnotationsRecord object to store the generic type parameter nullability | ||
information for the class by using an identifier that can never be an actual method name. | ||
*/ | ||
if (this.isNullMarked && !genericParamAnnotationsMap.isEmpty()) { |
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.
Should we be checking if the class is null marked before getting the upper bounds at line 204, for efficiency?
* @param cid ClassOrInterfaceDeclaration instance. | ||
* @return Map of annotations for generic type parameters with Nullable upper bounds. | ||
*/ | ||
private ImmutableMap<Integer, ImmutableSet<String>> getGenericTypeParameterNullableUpperBounds( |
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.
Returning a map seems overly complex. If we are only looking for @Nullable
upper bounds why not just return an ImmutableSet<Integer>
containing those type variable indices with such a bound?
import java.util.ServiceLoader; | ||
import java.util.Set; | ||
|
||
public class StubxCacheUtil { |
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.
What is the purpose of this class? Please add Javadoc
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 created it to reuse the logic for caching the annotation information from the stubx file from InferredJARModelsHandler
private static final int RETURN = -1; | ||
private final Map<String, Map<String, Map<Integer, Set<String>>>> argAnnotCache; | ||
|
||
public StubxCacheUtil(String logCaller) { |
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.
Add Javadoc, including the purpose of the parameter
With these changes we are able to read and create library models for Nullable upper bounds of generic type parameters from externally annotated source code as shown in the below example.
Externally annotated source code example: