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

External Library Models Integration #922

Merged
merged 61 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
1d48e6e
fixes
akulk022 Jan 31, 2024
b0631cb
stubx file writer logic
akulk022 Feb 7, 2024
e5353d1
changing method returns to nullable
akulk022 Feb 9, 2024
ea7d117
Adding safe cast for EnumDeclaration as parent for method
akulk022 Feb 14, 2024
e9a06dc
updating logic for method declaration
akulk022 Feb 18, 2024
19b020b
moving lib model to separate module
akulk022 Feb 21, 2024
31f569c
moving code
akulk022 Feb 21, 2024
a26f856
infrastructure code for lib model
akulk022 Feb 24, 2024
a863363
Merge branch 'uber:master' into library_model_stub_abhijitk
akulk022 Feb 24, 2024
ee56362
adding sample_jdk source files in resources
akulk022 Feb 26, 2024
3806c80
Merge remote-tracking branch 'origin/library_model_stub_abhijitk' int…
akulk022 Feb 26, 2024
32f0990
adding logic to create directories if they don't exist to avoid NoSuc…
akulk022 Feb 26, 2024
3dedc77
changing logic for ArrayTypes and adding Scanner findInLine test case…
akulk022 Feb 27, 2024
07586ae
replacing with synthetic test case files
akulk022 Feb 27, 2024
4b7891e
unnecessary formatting change
akulk022 Feb 27, 2024
10c36e3
minor cleanup
msridhar Feb 29, 2024
36b5a21
Update lib-model/lib-model-consume/src/main/java/com/uber/nullaway/li…
akulk022 Feb 29, 2024
a6c8204
fixes
akulk022 Feb 29, 2024
0c2cd44
Generating MethodAnnotationsRecord using AutoValue
akulk022 Feb 29, 2024
ac14c99
Removing Redundant files for StubxWriter and MethodAnnotationsRecord
akulk022 Mar 1, 2024
2dbc283
Merge branch 'master' into library_model_stub_abhijitk
msridhar Mar 5, 2024
32e80d5
making methodRecords local variable and passing as a param to make it…
akulk022 Mar 5, 2024
2b637f1
Merge remote-tracking branch 'origin/library_model_stub_abhijitk' int…
akulk022 Mar 5, 2024
888c1b2
separating lib model cli module
akulk022 Mar 5, 2024
fb81869
removing unnecessary dependencies
akulk022 Mar 6, 2024
e889dc3
refactoring module names and build files
akulk022 Mar 7, 2024
26efa96
using shadowJar plugin
akulk022 Mar 7, 2024
cbe7bf5
formatting
akulk022 Mar 7, 2024
600164c
refactoring, adding javadocs and clean-up
akulk022 Mar 7, 2024
d1fed93
create directory fix
akulk022 Mar 7, 2024
db993b8
Handling ArrayType @Nullable return Scenario and some refactoring
akulk022 Mar 7, 2024
09c0f4c
javadoc changes
akulk022 Mar 7, 2024
161c6ac
Logic to only consider jspecify Nullable annotation
akulk022 Mar 8, 2024
27ebcc9
tweak comment
msridhar Mar 8, 2024
5ee2428
Refactoring and documentation
akulk022 Mar 8, 2024
8c442f7
removing comment
akulk022 Mar 9, 2024
609f2e5
cleanup
akulk022 Mar 9, 2024
fb83aff
Adding NullMarked flag and some clean up
akulk022 Mar 10, 2024
629ec5b
adding doc
akulk022 Mar 10, 2024
5190597
refactoring
akulk022 Mar 13, 2024
fd7d546
Removing unused test case
akulk022 Mar 13, 2024
f213d82
Refactoring test setup for library-model-generator
akulk022 Mar 13, 2024
1137aa9
Refactoring test setup
akulk022 Mar 13, 2024
6e0ef33
Merge branch 'master' into library_model_stub_abhijitk
akulk022 Mar 13, 2024
41bc90f
adding comment for NullMarked functionality
akulk022 Mar 14, 2024
26c4907
adding simple usage message
akulk022 Mar 22, 2024
dc0618a
review suggestion
msridhar Mar 23, 2024
5fa73da
adding condition to consider jspecify annotation in InferredJARModels…
akulk022 Mar 23, 2024
14e39b6
Merge branch 'master' into library_model_stub_abhijitk
akulk022 Mar 24, 2024
f390cd1
try to incorporate more code coverage info
msridhar Mar 24, 2024
ad44788
Adding a test to check if the functionality is off without the JarInf…
akulk022 Mar 24, 2024
2a1c2da
Merge remote-tracking branch 'origin/library_model_stub_abhijitk' int…
akulk022 Mar 24, 2024
8f86b36
Handling the scenario for inner class: https://github.com/uber/NullAw…
akulk022 Mar 24, 2024
35b988c
minor comment modifications.
akulk022 Mar 24, 2024
c1fe36b
Removing redundant main class specification in javaexec; it's already…
akulk022 Mar 24, 2024
d301e28
Merge branch 'master' into library_model_stub_abhijitk
akulk022 Mar 24, 2024
439ca14
changing parentName from StringBuilder to String
akulk022 Mar 28, 2024
e2a9c60
Merge branch 'master' into library_model_stub_abhijitk
akulk022 Mar 28, 2024
a072bbd
updating year in copyright header for newly created files
akulk022 Mar 29, 2024
75785fa
Merge remote-tracking branch 'origin/library_model_stub_abhijitk' int…
akulk022 Mar 29, 2024
80be0d4
Merge branch 'master' into library_model_stub_abhijitk
akulk022 Mar 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ subprojects { project ->
google()
}

// For some reason, spotless complains when applied to the folders containing projects
// Spotless complains when applied to the folders containing projects
// when they do not have a build.gradle file
if (project.name != "jar-infer" && project.name != "library-model") {
project.apply plugin: "com.diffplug.spotless"
Expand Down
2 changes: 2 additions & 0 deletions code-coverage-report/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,6 @@ dependencies {
implementation project(':jar-infer:nullaway-integration-test')
implementation project(':guava-recent-unit-tests')
implementation project(':jdk-recent-unit-tests')
implementation project(':library-model:library-model-generator')
implementation project(':library-model:library-model-generator-integration-test')
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public class LibraryModelGeneratorCLI {
* directory.
*/
public static void main(String[] args) {
if (args.length != 2) {
System.out.println(
"Incorrect number of command line arguments. Required arguments: <inputSourceDirectory> <outputDirectory>");
return;
}
LibraryModelGenerator libraryModelGenerator = new LibraryModelGenerator();
libraryModelGenerator.generateAstubxForLibraryModels(args[0], args[1]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Check the number of args and print a basic usage message? (Not sure if we do that for JarInfer, and I don't think we need a full argument parser here yet, a check on the length of args would suffice for now)

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,54 @@ public void libraryModelNullableReturnsArrayTest() {
"}")
.doTest();
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add a test case without the -XepOpt:NullAway:JarInferEnabled flag or whatever we end up calling it, to check that this functionality is off without it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, may I suggest a case with a model adding @NonNull to a method argument, just for completeness here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@lazaroclapp We have not added the functionality for processing the annotations on method parameters in this PR so a test case with @NonNull on a method parameter will not be supported on these changes.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also @lazaroclapp I don't think supporting @NonNull on parameters will be a priority. Instead we are focusing on supporting treatment of a modeled class as @NullMarked, so everything is @NonNull by default, and then pulling in any explicit @Nullable annotations on parameters into the model

Copy link
Collaborator

Choose a reason for hiding this comment

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

There isn't a chance that specific classes will be @NullUnmarked with a few @NonNull locations? Either way, understood, not needed as part of this PR. I do feel in the medium term we might get surprised by the lack of symmetry here when using this for other kinds of library models.


@Test
public void libraryModelWithoutJarInferEnabledTest() {
compilationHelper
.setArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import com.uber.nullaway.libmodel.AnnotationExample;",
"class Test {",
" static AnnotationExample annotationExample = new AnnotationExample();",
" static void test(String value){",
" }",
" static void testNegative() {",
" // Since the JarInferEnabled and JarInferUseReturnAnnotations flags are not set, we don't get an error here",
" test(annotationExample.makeUpperCase(\"nullaway\"));",
" }",
"}")
.doTest();
}

@Test
public void libraryModelInnerClassNullableReturnsTest() {
compilationHelper
.setArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
"-XepOpt:NullAway:JarInferEnabled=true",
"-XepOpt:NullAway:JarInferUseReturnAnnotations=true"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import com.uber.nullaway.libmodel.AnnotationExample;",
"class Test {",
" static AnnotationExample.InnerExample innerExample = new AnnotationExample.InnerExample();",
" static void test(String value){",
" }",
" static void testPositive() {",
" // BUG: Diagnostic contains: passing @Nullable parameter 'innerExample.returnNull()'",
" test(innerExample.returnNull());",
" }",
"}")
.doTest();
}
}
3 changes: 2 additions & 1 deletion library-model/library-model-generator/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
* limitations under the License.
*/
plugins {
id "java-library"
id 'java-library'
id 'nullaway.java-test-conventions'
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@
import com.github.javaparser.ParserConfiguration.LanguageLevel;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.type.ArrayType;
Expand Down Expand Up @@ -59,12 +57,12 @@
* directory. It processes the annotated Java source code to generate an astubx file that contains
* the required annotation information to be able to generate library models.
*/
public class LibraryModelGenerator {

Check warning on line 60 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L60

Added line #L60 was not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

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

Going to assume these codecov warnings are because it doesn't properly count the coverage from running this as part of the build for the integration tests? (cc: @msridhar )

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is true. At the same time, we don't have any unit tests like those in com.uber.nullaway.jarinfer.JarInferTest right now. We'd have to write unit tests that generate a source file or files into a temporary directory, runs the generator on that source file, generates an astubx, and then directly parses the astubx to see if it has the right output. I'm thinking this might be overkill at this point, given the integration tests. What do you think @lazaroclapp?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Brief update is that the stubx writing code gets covered as part of the JarInfer tests, so the only code that doesn't show as covered now is the code for parsing .java files and reading in the annotations (it is covered by integration tests but not unit tests)


public void generateAstubxForLibraryModels(String inputSourceDirectory, String outputDirectory) {
Map<String, MethodAnnotationsRecord> methodRecords = processDirectory(inputSourceDirectory);
writeToAstubx(outputDirectory, methodRecords);
}

Check warning on line 65 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L63-L65

Added lines #L63 - L65 were not covered by tests

/**
* Parses all the source files within the directory using javaparser.
Expand All @@ -73,26 +71,26 @@
* @return a Map containing the Nullability annotation information from the source files.
*/
private Map<String, MethodAnnotationsRecord> processDirectory(String sourceDirectoryRoot) {
Map<String, MethodAnnotationsRecord> methodRecords = new LinkedHashMap<>();
Path root = dirnameToPath(sourceDirectoryRoot);
AnnotationCollectorCallback ac = new AnnotationCollectorCallback(methodRecords);
CollectionStrategy strategy = new ParserCollectionStrategy();

Check warning on line 77 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L74-L77

Added lines #L74 - L77 were not covered by tests
// Required to include directories that contain a module-info.java, which don't parse by
// default.
strategy.getParserConfiguration().setLanguageLevel(LanguageLevel.JAVA_17);
ProjectRoot projectRoot = strategy.collect(root);

Check warning on line 81 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L80-L81

Added lines #L80 - L81 were not covered by tests

projectRoot
.getSourceRoots()
.forEach(

Check warning on line 85 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L83-L85

Added lines #L83 - L85 were not covered by tests
sourceRoot -> {
try {
sourceRoot.parse("", ac);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
return methodRecords;

Check warning on line 93 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L88-L93

Added lines #L88 - L93 were not covered by tests
}

/**
Expand All @@ -104,124 +102,115 @@
private void writeToAstubx(
String outputPath, Map<String, MethodAnnotationsRecord> methodRecords) {
if (methodRecords.isEmpty()) {
return;

Check warning on line 105 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L105

Added line #L105 was not covered by tests
}
Map<String, String> importedAnnotations =
ImmutableMap.of(

Check warning on line 108 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L107-L108

Added lines #L107 - L108 were not covered by tests
"Nonnull", "javax.annotation.Nonnull",
"Nullable", "javax.annotation.Nullable");
"NonNull", "org.jspecify.annotations.NonNull",
"Nullable", "org.jspecify.annotations.Nullable");
Path outputPathInstance = Paths.get(outputPath);

Check warning on line 111 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L111

Added line #L111 was not covered by tests
try {
Files.createDirectories(outputPathInstance.getParent());
try (DataOutputStream dos = new DataOutputStream(Files.newOutputStream(outputPathInstance))) {
StubxWriter.write(

Check warning on line 115 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L113-L115

Added lines #L113 - L115 were not covered by tests
dos,
importedAnnotations,
Collections.emptyMap(),
Collections.emptyMap(),

Check warning on line 119 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L118-L119

Added lines #L118 - L119 were not covered by tests
methodRecords);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}

Check warning on line 125 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L122-L125

Added lines #L122 - L125 were not covered by tests

public Path dirnameToPath(String dir) {
File f = new File(dir);
String absoluteDir = f.getAbsolutePath();

Check warning on line 129 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L128-L129

Added lines #L128 - L129 were not covered by tests
if (absoluteDir.endsWith("/.")) {
absoluteDir = absoluteDir.substring(0, absoluteDir.length() - 2);

Check warning on line 131 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L131

Added line #L131 was not covered by tests
}
return Paths.get(absoluteDir);

Check warning on line 133 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L133

Added line #L133 was not covered by tests
}

private static class AnnotationCollectorCallback implements SourceRoot.Callback {

private final AnnotationCollectionVisitor annotationCollectionVisitor;

public AnnotationCollectorCallback(Map<String, MethodAnnotationsRecord> methodRecords) {
this.annotationCollectionVisitor = new AnnotationCollectionVisitor(methodRecords);
}

Check warning on line 142 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L140-L142

Added lines #L140 - L142 were not covered by tests

@Override
public Result process(Path localPath, Path absolutePath, ParseResult<CompilationUnit> result) {
Result res = Result.SAVE;
Optional<CompilationUnit> opt = result.getResult();

Check warning on line 147 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L146-L147

Added lines #L146 - L147 were not covered by tests
if (opt.isPresent()) {
CompilationUnit cu = opt.get();
cu.accept(annotationCollectionVisitor, null);

Check warning on line 150 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L149-L150

Added lines #L149 - L150 were not covered by tests
}
return res;

Check warning on line 152 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L152

Added line #L152 was not covered by tests
}
}

private static class AnnotationCollectionVisitor extends VoidVisitorAdapter<Void> {

private String packageName = "";
private StringBuilder parentName;
Copy link
Collaborator

@msridhar msridhar Mar 27, 2024

Choose a reason for hiding this comment

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

Probably better to just make this a String? I think making it a StringBuilder is an unnecessary optimization and makes the code more brittle. You can just overwrite it with new String values and I think it'll be fine

private boolean isJspecifyNullableImportPresent = false;
private boolean isNullMarked = false;

Check warning on line 160 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L159-L160

Added lines #L159 - L160 were not covered by tests
private Map<String, MethodAnnotationsRecord> methodRecords;
private static final String ARRAY_RETURN_TYPE_STRING = "Array";
private static final String NULL_MARKED = "NullMarked";
private static final String NULLABLE = "Nullable";
private static final String JSPECIFY_NULLABLE_IMPORT = "org.jspecify.annotations.Nullable";

public AnnotationCollectionVisitor(Map<String, MethodAnnotationsRecord> methodRecords) {
this.methodRecords = methodRecords;
}

Check warning on line 169 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L167-L169

Added lines #L167 - L169 were not covered by tests

@Override
public void visit(PackageDeclaration pd, Void arg) {
this.packageName = pd.getNameAsString();
this.parentName = new StringBuilder(pd.getNameAsString());
super.visit(pd, null);
}

Check warning on line 175 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L173-L175

Added lines #L173 - L175 were not covered by tests

@Override
public void visit(ImportDeclaration id, Void arg) {
if (id.getName().toString().contains(JSPECIFY_NULLABLE_IMPORT)) {
this.isJspecifyNullableImportPresent = true;

Check warning on line 180 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L180

Added line #L180 was not covered by tests
}
super.visit(id, null);
}

Check warning on line 183 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L182-L183

Added lines #L182 - L183 were not covered by tests

@Override
public void visit(ClassOrInterfaceDeclaration cid, Void arg) {
/*Currently, this logic only supports @NullMarked annotations on top-level classes and
does not handle cases where @NullMarked appears on some nested classes but not others*/
/*This logic assumes an explicit @NullMarked annotation on the top-level class within a
source file, and it's expected that each source file contains only one top-level class. The
logic does not currently handle cases where @NullMarked annotations appear on some nested
classes but not others. It also does not consider annotations within package-info.java or
module-info.java files.*/
parentName.append(".").append(cid.getNameAsString());
cid.getAnnotations()
.forEach(

Check warning on line 194 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L192-L194

Added lines #L192 - L194 were not covered by tests
a -> {
if (a.getNameAsString().equalsIgnoreCase(NULL_MARKED)) {
this.isNullMarked = true;

Check warning on line 197 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L197

Added line #L197 was not covered by tests
}
});
super.visit(cid, null);

Check warning on line 200 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L199-L200

Added lines #L199 - L200 were not covered by tests
// We reset the variable that constructs the parent name after visiting all the children.
parentName.delete(parentName.lastIndexOf("." + cid.getNameAsString()), parentName.length());
}

Check warning on line 203 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L202-L203

Added lines #L202 - L203 were not covered by tests

@Override
public void visit(MethodDeclaration md, Void arg) {
Optional<Node> parentClassNode = md.getParentNode();
String parentClassName = "";
if (parentClassNode.isPresent()) {
if (parentClassNode.get() instanceof ClassOrInterfaceDeclaration) {
parentClassName = ((ClassOrInterfaceDeclaration) parentClassNode.get()).getNameAsString();
} else if (parentClassNode.get() instanceof EnumDeclaration) {
parentClassName = ((EnumDeclaration) parentClassNode.get()).getNameAsString();
}
}
if (this.isNullMarked && hasNullableReturn(md)) {
methodRecords.put(
packageName
+ "."
+ parentClassName
+ ":"
+ getMethodReturnTypeString(md)
+ " "
+ md.getSignature().toString(),
parentName + ":" + getMethodReturnTypeString(md) + " " + md.getSignature().toString(),
MethodAnnotationsRecord.create(ImmutableSet.of("Nullable"), ImmutableMap.of()));

Check warning on line 210 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L208-L210

Added lines #L208 - L210 were not covered by tests
}
super.visit(md, null);
}

Check warning on line 213 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L212-L213

Added lines #L212 - L213 were not covered by tests

/**
* Determines if a MethodDeclaration can return null.
Expand All @@ -236,17 +225,17 @@
Nullable(@Nullable Object []) */
for (AnnotationExpr annotation : md.getType().getAnnotations()) {
if (isAnnotationNullable(annotation)) {
return true;

Check warning on line 228 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L228

Added line #L228 was not covered by tests
}
}

Check warning on line 230 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L230

Added line #L230 was not covered by tests
} else {
for (AnnotationExpr annotation : md.getAnnotations()) {
if (isAnnotationNullable(annotation)) {
return true;

Check warning on line 234 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L234

Added line #L234 was not covered by tests
}
}

Check warning on line 236 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L236

Added line #L236 was not covered by tests
}
return false;

Check warning on line 238 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L238

Added line #L238 was not covered by tests
}

/**
Expand All @@ -258,16 +247,16 @@
*/
private String getMethodReturnTypeString(MethodDeclaration md) {
if (md.getType() instanceof ClassOrInterfaceType) {
return md.getType().getChildNodes().get(0).toString();

Check warning on line 250 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L250

Added line #L250 was not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

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

Note that using simple names is something we inherited from the CF stub format + us not explicitly handling imports, I think. So we might want to change these to FQNs at some point (but probably not in this PR)

} else if (md.getType() instanceof ArrayType) {
return ARRAY_RETURN_TYPE_STRING;

Check warning on line 252 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L252

Added line #L252 was not covered by tests
} else {
return md.getType().toString();

Check warning on line 254 in library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java

View check run for this annotation

Codecov / codecov/patch

library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/LibraryModelGenerator.java#L254

Added line #L254 was not covered by tests
}
}

private boolean isAnnotationNullable(AnnotationExpr annotation) {
// Since we only want to consider jspecify Nullable annotations.
// We only consider jspecify Nullable annotations(star imports are not supported).
return (annotation.getNameAsString().equalsIgnoreCase(NULLABLE)
&& this.isJspecifyNullableImportPresent)
|| annotation.getNameAsString().equalsIgnoreCase(JSPECIFY_NULLABLE_IMPORT);
Expand Down
1 change: 0 additions & 1 deletion library-model/test-library-model-generator/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ jar {
jar.doLast {
javaexec {
classpath = files("${rootProject.projectDir}/library-model/library-model-generator-cli/build/libs/library-model-generator-cli.jar")
main = "com.uber.nullaway.libmodel.LibraryModelGeneratorCLI"
args = [
testInputsPath,
"${jar.destinationDirectory.get()}/${astubxPath}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,11 @@ public Integer[] generateIntArray(int size) {
public String nullReturn() {
return null;
}

public static class InnerExample {

public String returnNull() {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,19 @@ public String makeUpperCase(String inputString) {
/**
* This method exists to test that
* we do not process this annotation.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Interesting. Why not? I assume we currently only acknowledge org.jspecify.annotations.* for this tool? If so, let's make that explicit in the comment.

Copy link
Collaborator

Choose a reason for hiding this comment

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

As to reasoning, I wanted to narrow the focus because when declaration annotations get mixed in, things start getting very confusing (e.g., how to interpret them on array types). Since only JSpecify annotations are used in jspecify/jdk I thought we'd just focus on that for now

* Since for the purposes of this tool,
* we are only considering the jspecify annotation.
*/
@javax.annotation.Nullable
public String nullReturn() {
return null;
}

public static class InnerExample {

@Nullable
public String returnNull() {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ private boolean isReturnAnnotatedNullable(Symbol.MethodSymbol methodSymbol) {
if (methodArgAnnotations != null) {
Set<String> methodAnnotations = methodArgAnnotations.get(RETURN);
if (methodAnnotations != null) {
if (methodAnnotations.contains("javax.annotation.Nullable")) {
if (methodAnnotations.contains("javax.annotation.Nullable")
|| methodAnnotations.contains("org.jspecify.annotations.Nullable")) {
LOG(DEBUG, "DEBUG", "Nullable return for method: " + methodSign);
return true;
}
Expand Down