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: Adding support for @Nullable Method parameters #1006

Merged
merged 47 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
fb19551
default and nullable params initial changes
akulk022 Jul 12, 2024
d76a3b2
Adding javaparser type solver to use fully qualified names for method…
akulk022 Jul 22, 2024
6ef1afe
Merge branch 'master' into library_model_nullable_params
akulk022 Jul 22, 2024
9b7d5c1
clean up
akulk022 Jul 22, 2024
0182cf9
Merge remote-tracking branch 'origin/library_model_nullable_params' i…
akulk022 Jul 22, 2024
96be113
specify javaparser version in one place
msridhar Jul 22, 2024
9be47fe
Merge branch 'master' into library_model_nullable_params
msridhar Aug 21, 2024
528ff22
Merge branch 'master' into library_model_nullable_params
msridhar Sep 4, 2024
972c977
WIP
msridhar Sep 4, 2024
38f639f
fix more tests
msridhar Sep 5, 2024
4d375d1
more
msridhar Sep 5, 2024
3f25628
resolving conflicts for merge
akulk022 Sep 7, 2024
8abe95e
Merge branch 'master' into library_model_nullable_params
akulk022 Sep 7, 2024
515bb29
updating test with fully qualified name
akulk022 Sep 7, 2024
e1daf7b
fix another
msridhar Sep 7, 2024
0681d1f
latest javaparser
msridhar Sep 7, 2024
5b29341
Merge branch 'master' into library_model_nullable_params
msridhar Sep 7, 2024
81ec20c
adding logic and test for checking null marked classes
akulk022 Sep 9, 2024
f61478d
updating test cases
akulk022 Sep 10, 2024
aaaa00a
adding test case for nullable parameters
akulk022 Sep 10, 2024
b372f53
Merge branch 'master' into library_model_nullable_params
akulk022 Sep 10, 2024
e5dc95f
removing unnecessary suppress warning
akulk022 Sep 10, 2024
e204963
Merge remote-tracking branch 'origin/library_model_nullable_params' i…
akulk022 Sep 10, 2024
3a5946b
clean up
akulk022 Sep 10, 2024
d83e024
adding check for Nullable annotation
akulk022 Sep 11, 2024
8083b57
Merge branch 'master' into library_model_nullable_params
akulk022 Sep 11, 2024
32f6abb
adding test case for explicitly @NonNull parameter
akulk022 Sep 12, 2024
ef50479
Merge remote-tracking branch 'origin/library_model_nullable_params' i…
akulk022 Sep 12, 2024
13083c1
Merge branch 'master' into library_model_nullable_params
akulk022 Sep 16, 2024
b0a25f4
updating logic for using Array type qualified names
akulk022 Sep 17, 2024
254ada4
updating logic for correctly taking the annotation for @Nullable arra…
akulk022 Sep 17, 2024
10ddcd3
updating test case logic
akulk022 Sep 17, 2024
2edafa6
Merge branch 'master' into library_model_nullable_params
akulk022 Sep 18, 2024
c3f669c
handling primitive return type scenario
akulk022 Sep 18, 2024
8600bf9
adding test cases for JarInfer
akulk022 Sep 19, 2024
eb832dc
test case
msridhar Sep 20, 2024
0b898b9
tweak test
msridhar Sep 20, 2024
6c1cea8
another test
msridhar Sep 20, 2024
55dc4e2
fix test?
msridhar Sep 20, 2024
6bd3185
more tests and tweaks
msridhar Sep 21, 2024
1e8ac44
fix tests
msridhar Sep 21, 2024
16ac993
bump astubx version number
msridhar Sep 21, 2024
f8fd564
suppress
msridhar Sep 21, 2024
d24267c
add integration test for nullable array parameter
msridhar Sep 21, 2024
29a902b
adding test case for void return type and updating the NullUnmarked test
akulk022 Sep 22, 2024
5a4e7cd
remove unnecessary locals
msridhar Sep 22, 2024
e1cbcf9
Merge branch 'master' into library_model_nullable_params
akulk022 Sep 22, 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
4 changes: 3 additions & 1 deletion gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def versions = [
commonscli : "1.4",
autoValue : "1.10.2",
autoService : "1.1.1",
javaparser : "3.26.2",
]

def apt = [
Expand All @@ -75,7 +76,8 @@ def build = [
errorProneTestHelpersOld: "com.google.errorprone:error_prone_test_helpers:${oldestErrorProneVersion}",
checkerDataflow : "org.checkerframework:dataflow-nullaway:${versions.checkerFramework}",
guava : "com.google.guava:guava:30.1-jre",
javaparser : "com.github.javaparser:javaparser-core:3.26.0",
javaparser : "com.github.javaparser:javaparser-core:${versions.javaparser}",
javaparserSymbolSolver : "com.github.javaparser:javaparser-symbol-solver-core:${versions.javaparser}",
javaxValidation : "javax.validation:validation-api:2.0.1.Final",
jspecify : "org.jspecify:jspecify:1.0.0",
commonsIO : "commons-io:commons-io:2.11.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.ibm.wala.classLoader.PhantomClass;
import com.ibm.wala.classLoader.ShrikeCTMethod;
import com.ibm.wala.core.util.config.AnalysisScopeReader;
import com.ibm.wala.core.util.strings.StringStuff;
import com.ibm.wala.core.util.warnings.Warnings;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisCacheImpl;
Expand Down Expand Up @@ -456,6 +457,7 @@ private void writeModel(DataOutputStream out) throws IOException {
packageAnnotations,
typeAnnotations,
methodRecords,
Collections.emptySet(),
Collections.emptyMap());
}

Expand Down Expand Up @@ -527,28 +529,6 @@ private static String getAstubxSignature(IMethod mtd) {
* @return String Unqualified type name.
*/
private static String getSimpleTypeName(TypeReference typ) {
ImmutableMap<String, String> mapFullTypeName =
ImmutableMap.<String, String>builder()
.put("B", "byte")
.put("C", "char")
.put("D", "double")
.put("F", "float")
.put("I", "int")
.put("J", "long")
.put("S", "short")
.put("Z", "boolean")
.build();
if (typ.isArrayType()) {
return "Array";
}
String typName = typ.getName().toString();
if (typName.startsWith("L")) {
typName = typName.split("<")[0].substring(1); // handle generics
typName = typName.substring(typName.lastIndexOf('/') + 1); // get unqualified name
typName = typName.substring(typName.lastIndexOf('$') + 1); // handle inner classes
} else {
typName = mapFullTypeName.get(typName);
}
return typName;
return StringStuff.jvmToBinaryName(typ.getName().toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@

/** Unit tests for {@link com.uber.nullaway.jarinfer}. */
@RunWith(JUnit4.class)
@SuppressWarnings("CheckTestExtendsBaseClass")
public class JarInferTest {
msridhar marked this conversation as resolved.
Show resolved Hide resolved

@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
Expand Down Expand Up @@ -206,8 +205,8 @@ public void toyStatic() throws Exception {
"toys",
"Test",
ImmutableMap.of(
"toys.Test:void test(String, Foo, Bar)", Sets.newHashSet(0, 2),
"toys.Foo:boolean run(String)", Sets.newHashSet(1)),
"toys.Test:void test(java.lang.String, toys.Foo, toys.Bar)", Sets.newHashSet(0, 2),
"toys.Foo:boolean run(java.lang.String)", Sets.newHashSet(1)),
"class Foo {",
" private String foo;",
" public Foo(String str) {",
Expand Down Expand Up @@ -267,7 +266,8 @@ public void toyNonStatic() throws Exception {
"toyNonStatic",
"toys",
"Foo",
ImmutableMap.of("toys.Foo:void test(String, String)", Sets.newHashSet(1)),
ImmutableMap.of(
"toys.Foo:void test(java.lang.String, java.lang.String)", Sets.newHashSet(1)),
"class Foo {",
" private String foo;",
" public Foo(String str) {",
Expand Down Expand Up @@ -303,7 +303,9 @@ public void toyNullTestAPI() throws Exception {
"toyNullTestAPI",
"toys",
"Foo",
ImmutableMap.of("toys.Foo:void test(String, String, String)", Sets.newHashSet(1, 3)),
ImmutableMap.of(
"toys.Foo:void test(java.lang.String, java.lang.String, java.lang.String)",
Sets.newHashSet(1, 3)),
"import com.google.common.base.Preconditions;",
"import java.util.Objects;",
"import org.junit.Assert;",
Expand Down Expand Up @@ -332,7 +334,9 @@ public void toyConditionalFlow() throws Exception {
"toyNullTestAPI",
"toys",
"Foo",
ImmutableMap.of("toys.Foo:void test(String, String, String)", Sets.newHashSet(1, 2)),
ImmutableMap.of(
"toys.Foo:void test(java.lang.String, java.lang.String, java.lang.String)",
Sets.newHashSet(1, 2)),
"import com.google.common.base.Preconditions;",
"import java.util.Objects;",
"import org.junit.Assert;",
Expand Down Expand Up @@ -362,7 +366,8 @@ public void toyConditionalFlow2() throws Exception {
"toys",
"Foo",
ImmutableMap.of(
"toys.Foo:void test(Object, Object, Object, Object)", Sets.newHashSet(1, 4)),
"toys.Foo:void test(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object)",
Sets.newHashSet(1, 4)),
"import com.google.common.base.Preconditions;",
"import java.util.Objects;",
"import org.junit.Assert;",
Expand Down Expand Up @@ -401,7 +406,8 @@ public void toyReassigningTest() throws Exception {
"toyNullTestAPI",
"toys",
"Foo",
ImmutableMap.of("toys.Foo:void test(String, String)", Sets.newHashSet(1)),
ImmutableMap.of(
"toys.Foo:void test(java.lang.String, java.lang.String)", Sets.newHashSet(1)),
"import com.google.common.base.Preconditions;",
"import java.util.Objects;",
"import org.junit.Assert;",
Expand All @@ -421,6 +427,40 @@ public void toyReassigningTest() throws Exception {
"}");
}

@Test
public void testObjectArray() throws Exception {
testTemplate(
"testObjectArray",
"arrays",
"TestArray",
ImmutableMap.of(
"arrays.TestArray:java.lang.String foo(java.lang.Object[])", Sets.newHashSet(0)),
"class TestArray {",
" public static String foo(Object[] o) {",
" return o.toString();",
" }",
"}");
}

@Test
public void testGenericMethod() throws Exception {
testTemplate(
"testGenericMethod",
"generic",
"TestGeneric",
ImmutableMap.of(
"generic.TestGeneric:java.lang.String foo(java.lang.Object)", Sets.newHashSet(1)),
"public class TestGeneric<T> {",
" public String foo(T t) {",
" return t.toString();",
" }",
" public static void main(String arg[]) {",
" TestGeneric<String> tg = new TestGeneric<String>();",
" System.out.println(tg.foo(\"generic test\"));",
" }",
"}");
}

@Test
public void toyJARAnnotatingClasses() throws Exception {
testAnnotationInJarTemplate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,55 @@ public void jarinferLoadStubsTest() {
.doTest();
}

@Test
public void arrayTest() {
compilationHelper
.setArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
"-XepOpt:NullAway:JarInferEnabled=true",
"-XepOpt:NullAway:UnannotatedSubPackages=com.uber.nullaway.[a-zA-Z0-9.]+.unannotated"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import org.jspecify.annotations.Nullable;",
"import com.uber.nullaway.jarinfer.toys.unannotated.Toys;",
"class Test {",
" void test1(Object @Nullable [] o) {",
" // BUG: Diagnostic contains: passing @Nullable parameter 'o'",
" Toys.testArray(o);",
" }",
"}")
.doTest();
}

@Test
public void genericsTest() {
compilationHelper
.setArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
"-XepOpt:NullAway:JarInferEnabled=true",
"-XepOpt:NullAway:UnannotatedSubPackages=com.uber.nullaway.[a-zA-Z0-9.]+.unannotated"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import org.jspecify.annotations.Nullable;",
"import com.uber.nullaway.jarinfer.toys.unannotated.Toys;",
"class Test {",
" void test1() {",
" Toys.Generic<String> g = new Toys.Generic<>();",
" // BUG: Diagnostic contains: passing @Nullable parameter 'null'",
" g.getString(null);",
" }",
"}")
.doTest();
}

@Test
public void jarinferNullableReturnsTest() {
compilationHelper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ public static void test1(@ExpectNonnull String s, String t, String u) {
}
}

@SuppressWarnings("ArrayHashCode")
public static int testArray(Object[] o) {
return o.hashCode();
}

public static class Generic<T> {
public String getString(T t) {
return t.toString();
}
}

public static void main(String arg[]) throws java.io.IOException {
String s = "test string...";
Foo f = new Foo("let's");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,112 @@ public void libraryModelNullableUpperBoundsWithoutJarInferTest() {
"}")
.doTest();
}

@Test
public void libraryModelDefaultParameterNullabilityTest() {
compilationHelper
.setArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
"-XepOpt:NullAway:JSpecifyMode=true",
"-XepOpt:NullAway:JarInferEnabled=true",
"-XepOpt:NullAway:JarInferUseReturnAnnotations=true"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import com.test.ParameterAnnotationExample;",
"class Test {",
" static ParameterAnnotationExample annotationExample = new ParameterAnnotationExample();",
" static void testPositive() {",
" // BUG: Diagnostic contains: passing @Nullable parameter 'null' where @NonNull is required",
" annotationExample.add(5,null);",
" }",
"}")
.doTest();
}

@Test
public void libraryModelParameterNullabilityTest() {
compilationHelper
.setArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
"-XepOpt:NullAway:JSpecifyMode=true",
"-XepOpt:NullAway:JarInferEnabled=true",
"-XepOpt:NullAway:JarInferUseReturnAnnotations=true"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import com.test.ParameterAnnotationExample;",
"class Test {",
" static ParameterAnnotationExample annotationExample = new ParameterAnnotationExample();",
" static void testPositive() {",
" // BUG: Diagnostic contains: passing @Nullable parameter 'null' where @NonNull is required",
" annotationExample.printObjectString(null);",
" }",
" static void testNegative() {",
" annotationExample.getNewObjectIfNull(null);",
" }",
"}")
.doTest();
}

@Test
public void nullableArrayTest() {
compilationHelper
.setArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
"-XepOpt:NullAway:JSpecifyMode=true",
"-XepOpt:NullAway:JarInferEnabled=true",
"-XepOpt:NullAway:JarInferUseReturnAnnotations=true"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import com.test.ParameterAnnotationExample;",
"class Test {",
" static void testPositive() {",
" // BUG: Diagnostic contains: passing @Nullable parameter 'null' where @NonNull is required",
" ParameterAnnotationExample.takesNonNullArray(null);",
" }",
" static void testNegative() {",
" ParameterAnnotationExample.takesNullArray(null);",
" }",
"}")
.doTest();
}

@Test
public void genericParameterTest() {
compilationHelper
.setArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
"-XepOpt:NullAway:JSpecifyMode=true",
"-XepOpt:NullAway:JarInferEnabled=true",
"-XepOpt:NullAway:JarInferUseReturnAnnotations=true"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import com.test.ParameterAnnotationExample;",
"class Test {",
" static ParameterAnnotationExample.Generic<String> ex = new ParameterAnnotationExample.Generic<>();",
" static void testPositive() {",
" // BUG: Diagnostic contains: passing @Nullable parameter 'null' where @NonNull is required",
" ex.printObjectString(null);",
" }",
" static void testNegative() {",
" ex.getString(null);",
" }",
"}")
.doTest();
}
}
1 change: 1 addition & 0 deletions library-model/library-model-generator/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ plugins {
dependencies {
implementation deps.build.guava
implementation deps.build.javaparser
implementation deps.build.javaparserSymbolSolver
compileOnly deps.apt.autoValueAnnot
annotationProcessor deps.apt.autoValue

Expand Down
Loading