Skip to content
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

Adding support for nullable type upper bounds considering Library mod… #893

Closed
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
f71df65
Adding support for nullable type upper bounds considering Library mod…
akulk022 Jan 10, 2024
e27b474
Adding implementation for nullableVariableTypeUpperBounds method
akulk022 Jan 10, 2024
529a26b
Adding method onOverrideTypeParameterUpperBound to Handler Interface …
akulk022 Jan 11, 2024
f10c491
Updating java docs
akulk022 Jan 12, 2024
b122a66
updating variable name and removing redundant variable
akulk022 Jan 12, 2024
50578d7
Update nullaway/src/main/java/com/uber/nullaway/handlers/Handler.java
akulk022 Jan 15, 2024
273a959
updating var name and documentation
akulk022 Jan 15, 2024
88a4799
Merge remote-tracking branch 'origin/library_models_Function_abhijitk…
akulk022 Jan 15, 2024
7849690
Merge branch 'master' into library_models_Function_abhijitk7
akulk022 Jan 15, 2024
ce9609c
using putAll instead of loop
akulk022 Jan 15, 2024
b56733a
adding positive test case
akulk022 Jan 15, 2024
81f8b7d
Adding EmptyLibraryModels abstract class for LibraryModels interface
akulk022 Jan 16, 2024
488f005
Revert "Adding EmptyLibraryModels abstract class for LibraryModels in…
akulk022 Jan 16, 2024
2634b16
Adding documentation for onOverrideTypeParameterUpperBound in Composi…
akulk022 Jan 16, 2024
2730d2a
Adding default implementations for typeVariablesWithNullableUpperBoun…
akulk022 Jan 16, 2024
ec115af
Update nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModel…
akulk022 Jan 16, 2024
f72959f
Removing redundant default implementations from ExampleLibraryModels …
akulk022 Jan 16, 2024
3e0fb0b
Removing positive test case and incorrect java.util.Map library model
akulk022 Jan 17, 2024
ee15c59
documentation improvements
msridhar Jan 17, 2024
f7462aa
Adding support for nullable type upper bounds considering Library mod…
akulk022 Jan 10, 2024
2ee3522
Adding implementation for nullableVariableTypeUpperBounds method
akulk022 Jan 10, 2024
8699e85
Adding method onOverrideTypeParameterUpperBound to Handler Interface …
akulk022 Jan 11, 2024
ae62aaa
Updating java docs
akulk022 Jan 12, 2024
c3eb477
updating variable name and removing redundant variable
akulk022 Jan 12, 2024
c3e17cf
updating var name and documentation
akulk022 Jan 15, 2024
107d40c
Update nullaway/src/main/java/com/uber/nullaway/handlers/Handler.java
akulk022 Jan 15, 2024
e80e35f
using putAll instead of loop
akulk022 Jan 15, 2024
0cfd0e2
adding positive test case
akulk022 Jan 15, 2024
dc1af63
Adding EmptyLibraryModels abstract class for LibraryModels interface
akulk022 Jan 16, 2024
e4d5813
Revert "Adding EmptyLibraryModels abstract class for LibraryModels in…
akulk022 Jan 16, 2024
3bf421d
Adding documentation for onOverrideTypeParameterUpperBound in Composi…
akulk022 Jan 16, 2024
334af66
Adding default implementations for typeVariablesWithNullableUpperBoun…
akulk022 Jan 16, 2024
20f3fe1
Update nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModel…
akulk022 Jan 16, 2024
2453b08
Removing redundant default implementations from ExampleLibraryModels …
akulk022 Jan 16, 2024
c70ec1d
Removing positive test case and incorrect java.util.Map library model
akulk022 Jan 17, 2024
84247a2
library models for nullmarked classes
akulk022 Jan 22, 2024
ac94e7a
Merge remote-tracking branch 'origin/library_models_Function_abhijitk…
akulk022 Jan 22, 2024
6b92af4
updating isAnnotatedTopLevelClass
akulk022 Jan 22, 2024
27918ff
bug fix, still more to do
msridhar Jan 23, 2024
026970c
more fixes, still needs cleanup
msridhar Jan 23, 2024
4e829d7
Updating javadoc for nullMarkedClasses
akulk022 Jan 25, 2024
b94597a
Fix bug with implicit equals() methods in interfaces (#898)
msridhar Jan 25, 2024
091ac38
Fix crash with raw types in overrides in JSpecify mode (#899)
msridhar Jan 25, 2024
115d683
Update instructions for Android and our sample app (#900)
msridhar Jan 25, 2024
373917e
docs
msridhar Jan 29, 2024
986d060
Prepare for release 0.10.22.
yuxincs Jan 29, 2024
00a317a
Prepare next development version.
yuxincs Jan 29, 2024
35eac21
Adding support for nullable type upper bounds considering Library mod…
akulk022 Jan 10, 2024
71cecb4
Adding implementation for nullableVariableTypeUpperBounds method
akulk022 Jan 10, 2024
18a0c6d
Adding method onOverrideTypeParameterUpperBound to Handler Interface …
akulk022 Jan 11, 2024
1f28ff5
Updating java docs
akulk022 Jan 12, 2024
c911842
updating variable name and removing redundant variable
akulk022 Jan 12, 2024
9aea517
updating var name and documentation
akulk022 Jan 15, 2024
ba88839
Update nullaway/src/main/java/com/uber/nullaway/handlers/Handler.java
akulk022 Jan 15, 2024
75436eb
using putAll instead of loop
akulk022 Jan 15, 2024
865873e
adding positive test case
akulk022 Jan 15, 2024
91a12f4
Adding EmptyLibraryModels abstract class for LibraryModels interface
akulk022 Jan 16, 2024
db16c7a
Revert "Adding EmptyLibraryModels abstract class for LibraryModels in…
akulk022 Jan 16, 2024
836ff44
Adding documentation for onOverrideTypeParameterUpperBound in Composi…
akulk022 Jan 16, 2024
6a9d7c1
Adding default implementations for typeVariablesWithNullableUpperBoun…
akulk022 Jan 16, 2024
cea3614
Update nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModel…
akulk022 Jan 16, 2024
7bf7497
Removing redundant default implementations from ExampleLibraryModels …
akulk022 Jan 16, 2024
37c7cb0
Removing positive test case and incorrect java.util.Map library model
akulk022 Jan 17, 2024
26c82dd
library models for nullmarked classes
akulk022 Jan 22, 2024
cd0e659
Adding support for nullable type upper bounds considering Library mod…
akulk022 Jan 10, 2024
1bf78df
Adding implementation for nullableVariableTypeUpperBounds method
akulk022 Jan 10, 2024
268022a
Adding method onOverrideTypeParameterUpperBound to Handler Interface …
akulk022 Jan 11, 2024
5e5df6a
Updating java docs
akulk022 Jan 12, 2024
6c24cbd
updating variable name and removing redundant variable
akulk022 Jan 12, 2024
32f84ac
updating var name and documentation
akulk022 Jan 15, 2024
5f6d9a8
using putAll instead of loop
akulk022 Jan 15, 2024
dcc1507
adding positive test case
akulk022 Jan 15, 2024
4bba915
Adding EmptyLibraryModels abstract class for LibraryModels interface
akulk022 Jan 16, 2024
d24e9c5
Revert "Adding EmptyLibraryModels abstract class for LibraryModels in…
akulk022 Jan 16, 2024
2ba7932
Adding default implementations for typeVariablesWithNullableUpperBoun…
akulk022 Jan 16, 2024
2ea0b77
Removing redundant default implementations from ExampleLibraryModels …
akulk022 Jan 16, 2024
1c1316d
Removing positive test case and incorrect java.util.Map library model
akulk022 Jan 17, 2024
924396c
documentation improvements
msridhar Jan 17, 2024
24d5ed0
updating isAnnotatedTopLevelClass
akulk022 Jan 22, 2024
0de4d12
bug fix, still more to do
msridhar Jan 23, 2024
32aef72
more fixes, still needs cleanup
msridhar Jan 23, 2024
2acffb3
docs
msridhar Jan 29, 2024
e1e23d1
handler updates
akulk022 Jan 29, 2024
fb23172
handler updates
akulk022 Jan 29, 2024
bc0edd1
Merge remote-tracking branch 'origin/library_models_Function_abhijitk…
akulk022 Jan 30, 2024
2dd0ca6
fixes
akulk022 Jan 30, 2024
badfd16
updating docs
akulk022 Jan 30, 2024
6fc4337
fixes
akulk022 Jan 30, 2024
c97e8dc
Merge remote-tracking branch 'origin/library_models_Function_abhijitk…
akulk022 Jan 30, 2024
05fe856
Revert "Prepare next development version."
akulk022 Jan 30, 2024
37a2008
Revert "Prepare for release 0.10.22."
akulk022 Jan 30, 2024
57a2116
Revert "Update instructions for Android and our sample app (#900)"
akulk022 Jan 30, 2024
e2beddc
Revert "Fix crash with raw types in overrides in JSpecify mode (#899)"
akulk022 Jan 30, 2024
f6996d1
Fix crash with raw types in overrides in JSpecify mode (#899)
msridhar Jan 25, 2024
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
9 changes: 9 additions & 0 deletions nullaway/src/main/java/com/uber/nullaway/LibraryModels.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ public interface LibraryModels {
*/
ImmutableSet<MethodRef> nonNullReturns();

/**
* Get the (className, generic type argument) pairs for library Classes where the generic type
* argument has a Nullable upper bound.
*
* @return map from the className to the position of the generic type argument that has a Nullable
* upper bound.
*/
ImmutableSetMultimap<String, Integer> typeVariablesWithNullableUpperBounds();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, thinking more about this change, one thing is that thus far, JSpecify mode changes have all been hidden under a flag and current NullAway users have not been impacted at all. This change would be different, since anyone who built their own LibraryModels implementation will need to implement this method. But, the LibraryModels interface is where this method belongs. I am leaning towards allowing this method here, but maybe we should also provide an abstract class like EmptyLibraryModels that users can subclass, where it would just return empty for everything. What do you think?

Also, maybe we should be more careful about version numbering, and make the next release 0.11.0 to indicate there is a "breaking" change for users who implemented the LibraryModels interface before. @yuxincs do you agree?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should we also extend the new Empty library models abstract class for the classes currently implementing LibraryModels interface. for e.g the Example Library Models? So that the default implementations are kept in the EmptyLibraryModels.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's what I'm thinking. Our current implementations should extend the new empty library models class.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Makes sense, I'll do that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, really sorry here, but I realized we are going about this the wrong way, and we really should be using the language feature introduced for just this case, default methods in interfaces. There is no need for introducing the EmptyLibraryModels class; we should just make typeVariablesWithNullableUpperBounds() a default method that returns the empty set and then all existing implementations will just work without any changes.

@akulk022 could you do the following:

  1. Make typeVariablesWithNullableUpperBounds() a default method.
  2. Also make LibraryModels.nullableFields() a default method that returns an empty set. We should have done this when introducing this method before but I forgot.
  3. Get rid of EmptyLibraryModels, and undo the changes to ExampleLibraryModels and TestLibraryModels.

Sorry again for not remembering about default methods but they are definitely the best way to go here.

Copy link
Collaborator Author

@akulk022 akulk022 Jan 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, It's a nice language feature to deal with such a problem and I should have known it exists, I will certainly remember it now. I'll do the needful right away.


/**
* Get (method, parameter) pairs that act as castToNonNull(...) methods.
*
Expand Down
3 changes: 2 additions & 1 deletion nullaway/src/main/java/com/uber/nullaway/NullAway.java
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,8 @@ public Description matchParameterizedType(ParameterizedTypeTree tree, VisitorSta
return Description.NO_MATCH;
}
if (config.isJSpecifyMode()) {
GenericsChecks.checkInstantiationForParameterizedTypedTree(tree, state, this, config);
GenericsChecks.checkInstantiationForParameterizedTypedTree(
tree, state, this, config, handler);
}
return Description.NO_MATCH;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.uber.nullaway.ErrorMessage;
import com.uber.nullaway.NullAway;
import com.uber.nullaway.Nullness;
import com.uber.nullaway.handlers.Handler;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -57,9 +58,14 @@ private GenericsChecks() {}
* @param state visitor state
* @param analysis the analysis object
* @param config the analysis config
* @param handler the handler instance
*/
public static void checkInstantiationForParameterizedTypedTree(
ParameterizedTypeTree tree, VisitorState state, NullAway analysis, Config config) {
ParameterizedTypeTree tree,
VisitorState state,
NullAway analysis,
Config config,
Handler handler) {
if (!config.isJSpecifyMode()) {
return;
}
Expand Down Expand Up @@ -96,7 +102,9 @@ public static void checkInstantiationForParameterizedTypedTree(
com.sun.tools.javac.util.List<Attribute.TypeCompound> annotationMirrors =
upperBound.getAnnotationMirrors();
boolean hasNullableAnnotation =
Nullness.hasNullableAnnotation(annotationMirrors.stream(), config);
Nullness.hasNullableAnnotation(annotationMirrors.stream(), config)
|| handler.onOverrideTypeParameterUpperBound(baseType.tsym.toString(), i);
;
// if base type argument does not have @Nullable annotation then the instantiation is
// invalid
if (!hasNullableAnnotation) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ public void onNonNullFieldAssignment(
// NoOp
}

@Override
public boolean onOverrideTypeParameterUpperBound(String className, int arg) {
return false;
}

@Override
public MethodInvocationNode onCFGBuildPhase1AfterVisitMethodInvocation(
NullAwayCFGBuilder.NullAwayCFGTranslationPhaseOne phase,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,4 +305,16 @@ public Integer castToNonNullArgumentPositionsForMethod(
}
return previousArgumentPosition;
}

@Override
public boolean onOverrideTypeParameterUpperBound(String className, int arg) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document in Javadoc that this returns true if any handler returns true

boolean result = false;
for (Handler h : handlers) {
result = h.onOverrideTypeParameterUpperBound(className, arg);
if (result) {
break;
}
}
return result;
}
}
12 changes: 12 additions & 0 deletions nullaway/src/main/java/com/uber/nullaway/handlers/Handler.java
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,18 @@ Integer castToNonNullArgumentPositionsForMethod(
List<? extends ExpressionTree> actualParams,
@Nullable Integer previousArgumentPosition);

/**
* Called to get the library models which have Nullable upper bound for their Generic Type
* Arguments.
*
* @param className A String containing the name of the class for which we want to check Nullable
* upper bound.
* @param arg Indicates the generic type argument for which we want to check Nullable upper bound.
* @return boolean value of regardless of whether the upper bound for that argument has a Nullable
* upper bound.
*/
akulk022 marked this conversation as resolved.
Show resolved Hide resolved
boolean onOverrideTypeParameterUpperBound(String className, int arg);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
boolean onOverrideTypeParameterUpperBound(String className, int arg);
boolean onOverrideTypeParameterUpperBound(String className, int index);


/**
* A three value enum for handlers implementing onDataflowVisitMethodInvocation to communicate
* their knowledge of the method return nullability to the rest of NullAway.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,12 @@ private void setUnconditionalArgumentNullness(
}
}

@Override
public boolean onOverrideTypeParameterUpperBound(String className, int arg) {
ImmutableSet<Integer> res = libraryModels.typeVariablesWithNullableUpperBounds().get(className);
return res.contains(arg);
}

/**
* Get all the stream specifications loaded from any of our library models.
*
Expand Down Expand Up @@ -826,7 +832,11 @@ private static class DefaultLibraryModels implements LibraryModels {
"getDrawable(android.content.Context,int)"))
.add(methodRef("android.support.design.widget.TextInputLayout", "getEditText()"))
.build();

private static final ImmutableSetMultimap<String, Integer> NULLABLE_VARIABLE_TYPE_UPPER_BOUNDS =
new ImmutableSetMultimap.Builder<String, Integer>()
.put("java.util.function.Function", 0)
.put("java.util.function.Function", 1)
.build();
private static final ImmutableSetMultimap<MethodRef, Integer> CAST_TO_NONNULL_METHODS =
new ImmutableSetMultimap.Builder<MethodRef, Integer>().build();

Expand Down Expand Up @@ -870,6 +880,11 @@ public ImmutableSet<MethodRef> nonNullReturns() {
return NONNULL_RETURNS;
}

@Override
public ImmutableSetMultimap<String, Integer> typeVariablesWithNullableUpperBounds() {
return NULLABLE_VARIABLE_TYPE_UPPER_BOUNDS;
}

@Override
public ImmutableSetMultimap<MethodRef, Integer> castToNonNullMethods() {
return CAST_TO_NONNULL_METHODS;
Expand Down Expand Up @@ -902,6 +917,8 @@ private static class CombinedLibraryModels implements LibraryModels {

private final ImmutableSet<MethodRef> nonNullReturns;

private final ImmutableSetMultimap<String, Integer> nullableVariableTypeUpperBounds;

private final ImmutableSet<FieldRef> nullableFields;

private final ImmutableSetMultimap<MethodRef, Integer> castToNonNullMethods;
Expand All @@ -916,6 +933,8 @@ public CombinedLibraryModels(Iterable<LibraryModels> models, Config config) {
new ImmutableSetMultimap.Builder<>();
ImmutableSetMultimap.Builder<MethodRef, Integer> nonNullParametersBuilder =
new ImmutableSetMultimap.Builder<>();
ImmutableSetMultimap.Builder<String, Integer> nullableVariableTypeUpperBoundsBuilder =
new ImmutableSetMultimap.Builder<>();
ImmutableSetMultimap.Builder<MethodRef, Integer> nullImpliesTrueParametersBuilder =
new ImmutableSetMultimap.Builder<>();
ImmutableSetMultimap.Builder<MethodRef, Integer> nullImpliesFalseParametersBuilder =
Expand Down Expand Up @@ -988,6 +1007,10 @@ public CombinedLibraryModels(Iterable<LibraryModels> models, Config config) {
}
castToNonNullMethodsBuilder.put(entry);
}
for (Map.Entry<String, Integer> entry :
libraryModels.typeVariablesWithNullableUpperBounds().entries()) {
nullableVariableTypeUpperBoundsBuilder.put(entry);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use putAll instead of writing a loop

for (StreamTypeRecord streamTypeRecord : libraryModels.customStreamNullabilitySpecs()) {
customStreamNullabilitySpecsBuilder.add(streamTypeRecord);
}
Expand All @@ -1006,6 +1029,7 @@ public CombinedLibraryModels(Iterable<LibraryModels> models, Config config) {
castToNonNullMethods = castToNonNullMethodsBuilder.build();
customStreamNullabilitySpecs = customStreamNullabilitySpecsBuilder.build();
nullableFields = nullableFieldsBuilder.build();
nullableVariableTypeUpperBounds = nullableVariableTypeUpperBoundsBuilder.build();
}

private boolean shouldSkipModel(MethodRef key) {
Expand Down Expand Up @@ -1052,6 +1076,11 @@ public ImmutableSet<MethodRef> nonNullReturns() {
return nonNullReturns;
}

@Override
public ImmutableSetMultimap<String, Integer> typeVariablesWithNullableUpperBounds() {
return nullableVariableTypeUpperBounds;
}

@Override
public ImmutableSet<FieldRef> nullableFields() {
return nullableFields;
Expand All @@ -1068,16 +1097,13 @@ public ImmutableList<StreamTypeRecord> customStreamNullabilitySpecs() {
}
}

/**
* A view of library models optimized to make lookup of {@link
* com.sun.tools.javac.code.Symbol.MethodSymbol}s fast
*/
/** A view of library models optimized to make lookup of {@link Symbol.MethodSymbol}s fast */
private static class OptimizedLibraryModels {

/**
* Mapping from {@link MethodRef} to some state, where lookups first check for a matching method
* name as an optimization. The {@link Name} data structure is used to avoid unnecessary String
* conversions when looking up {@link com.sun.tools.javac.code.Symbol.MethodSymbol}s.
* conversions when looking up {@link Symbol.MethodSymbol}s.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure why this went in there, It was probably the IDE that did something, I'll revert it.

*
* @param <T> the type of the associated state.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1615,6 +1615,22 @@ public void testForNullTypeRhsTypeForArrayType() {
.doTest();
}

@Test
public void testForUtilFunctionLibModel() {
makeHelper()
.addSourceLines(
"Test.java",
"package com.uber;",
"import org.jspecify.annotations.Nullable;",
"import java.util.function.Function;",
"class Test {",
" static void testNegative() {",
" Function<String,@Nullable String> removeA = a -> a.replace(\"a\",\"\");",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's write more tests to show the type argument is being handled correctly. E.g., check that passing in @Nullable when the first type argument is not @Nullable yields an error, etc.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is still not addressed

" }",
"}")
.doTest();
}

private CompilationTestHelper makeHelper() {
return makeTestHelperWithArgs(
Arrays.asList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ public ImmutableSet<MethodRef> nonNullReturns() {
return ImmutableSet.of();
}

@Override
public ImmutableSetMultimap<String, Integer> typeVariablesWithNullableUpperBounds() {
return ImmutableSetMultimap.of();
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code like in this class could be the EmptyLibraryModels implementation maybe

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akulk022 we can now delete this method right?

@Override
public ImmutableSetMultimap<MethodRef, Integer> castToNonNullMethods() {
return ImmutableSetMultimap.of();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ public ImmutableSet<MethodRef> nonNullReturns() {
return ImmutableSet.of();
}

@Override
public ImmutableSetMultimap<String, Integer> typeVariablesWithNullableUpperBounds() {
return ImmutableSetMultimap.of();
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the default method I think we can delete this

@Override
public ImmutableSetMultimap<MethodRef, Integer> castToNonNullMethods() {
return ImmutableSetMultimap.<MethodRef, Integer>builder()
Expand Down