[infer][java] avoid conflicts between Eradicate warnings and Biabdduction warnings

Summary:
This is to fix the conflicts between Eradicate and the Biabduction when reporting the same kind of errors: when Eradicate is on, the Eradicate warnings will have priority over the null deference reported by the biabduction.

If this approach proved to be successful in prod, I will refactor the reporting mechanism in the analysis itself to simply not report the null dereference in this case at all. For the codebases that aren't yet fully consistently using `Nullable`, this combined approach looks like a good way to deploy Infer toward full null safety.

Reviewed By: mbouaziz

Differential Revision: D7102119

fbshipit-source-id: 35d3add
master
Jeremy Dubreil 7 years ago committed by Facebook Github Bot
parent c1d0709fe9
commit 79276d26bf

@ -151,6 +151,21 @@ def get_key(e):
e[issues.JSON_INDEX_LINE], e[issues.JSON_INDEX_QUALIFIER]) e[issues.JSON_INDEX_LINE], e[issues.JSON_INDEX_QUALIFIER])
def remove_eradicate_conflicts(report):
eradicate_warnings = {
(e[issues.JSON_INDEX_FILENAME], e[issues.JSON_INDEX_LINE])
for e in report
if e[issues.JSON_INDEX_TYPE] == 'ERADICATE_NULL_METHOD_CALL' or
e[issues.JSON_INDEX_TYPE] == 'ERADICATE_NULL_FIELD_ACCESS'}
if eradicate_warnings == set():
return report
else:
return [e for e in report
if e[issues.JSON_INDEX_TYPE] != 'NULL_DEREFERENCE' or
(e[issues.JSON_INDEX_FILENAME], e[issues.JSON_INDEX_LINE])
not in eradicate_warnings]
def merge_reports(report, collected): def merge_reports(report, collected):
for e in report: for e in report:
key = get_key(e) key = get_key(e)
@ -168,6 +183,8 @@ def collect_results(buck_args, infer_args, start_time, targets):
try: try:
with zipfile.ZipFile(path) as jar: with zipfile.ZipFile(path) as jar:
report = load_json_report(jar) report = load_json_report(jar)
if not infer_args.no_filtering:
report = remove_eradicate_conflicts(report)
merge_reports(report, collected_reports) merge_reports(report, collected_reports)
except NotFoundInJar: except NotFoundInJar:
pass pass

@ -12,6 +12,7 @@ ANALYZER = checkers
BUCK_TARGET = //infer/tests/build_systems/genrule/module2:module2 BUCK_TARGET = //infer/tests/build_systems/genrule/module2:module2
SOURCES = $(wildcard $(TESTS_DIR)/codetoanalyze/java/infer/*.java) SOURCES = $(wildcard $(TESTS_DIR)/codetoanalyze/java/infer/*.java)
OBJECTS = $(ROOT_DIR)/buck-out/gen/infer/tests/build_systems/genrule/module2/lib__module2__output/module2.jar OBJECTS = $(ROOT_DIR)/buck-out/gen/infer/tests/build_systems/genrule/module2/lib__module2__output/module2.jar
INFER_OPTIONS = --eradicate
INFERPRINT_OPTIONS = --project-root $(ROOT_DIR) --issues-tests INFERPRINT_OPTIONS = --project-root $(ROOT_DIR) --issues-tests
CLEAN_EXTRA = $(ROOT_DIR)/buck-out CLEAN_EXTRA = $(ROOT_DIR)/buck-out
@ -29,5 +30,5 @@ infer-out/report.json: $(JAVA_DEPS) $(JAVA_SOURCE_FILES)
$(REMOVE_DIR) buck-out && \ $(REMOVE_DIR) buck-out && \
$(call silent_on_success,Testing Buck Java integration,\ $(call silent_on_success,Testing Buck Java integration,\
INFER_BIN=$(INFER_BIN) NO_BUCKD=1 \ INFER_BIN=$(INFER_BIN) NO_BUCKD=1 \
$(INFER_BIN) -a $(ANALYZER) --results-dir $(CURDIR)/infer-out -- \ $(INFER_BIN) $(INFER_OPTIONS) -a $(ANALYZER) --results-dir $(CURDIR)/infer-out -- \
$(BUCK) build --deep --no-cache $(BUCK_TARGET)) $(BUCK) build --deep --no-cache $(BUCK_TARGET))

@ -1,8 +1,11 @@
infer/tests/build_systems/genrule/module1/Class1.java, void Class1.localNPE1(), 2, NULL_DEREFERENCE, [start of procedure localNPE1()] infer/tests/build_systems/genrule/module1/Class1.java, Object Class1.unannotatedReturnNull(), 0, ERADICATE_RETURN_NOT_NULLABLE, [origin,Method `unannotatedReturnNull()` may return null but it is not annotated with `@Nullable`. (Origin: null constant at line 35)]
infer/tests/build_systems/genrule/module2/Class2.java, void Class2.dereferenceInterTargetFieldBad(Class1), 1, NULL_DEREFERENCE, [start of procedure dereferenceInterTargetFieldBad(...)] infer/tests/build_systems/genrule/module1/Class1.java, void Class1.localNPE1(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj` in the call to `toString()` could be null. (Origin: null constant at line 26)]
infer/tests/build_systems/genrule/module2/Class2.java, void Class2.dereferenceLocalNullableFieldBad(), 1, NULL_DEREFERENCE, [start of procedure dereferenceLocalNullableFieldBad()] infer/tests/build_systems/genrule/module2/Class2.java, int Class2.dereferenceInterTargetField2Bad(Class1), 1, ERADICATE_NULL_FIELD_ACCESS, [origin,Object `class1.field2` could be null when accessing field `Class1.x`. (Origin: field Class1.field2 at line 59)]
infer/tests/build_systems/genrule/module2/Class2.java, void Class2.followMethodDeclarationOnlyBad(SkipImplementationClass1), 2, NULL_DEREFERENCE, [start of procedure followMethodDeclarationOnlyBad(...),Skipping annotatedNullable(): method has no implementation,Definition of annotatedNullable()] infer/tests/build_systems/genrule/module2/Class2.java, void Class2.dereferenceInterTargetField1Bad(Class1), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `class1.field1` in the call to `toString()` could be null. (Origin: field Class1.field1 at line 55)]
infer/tests/build_systems/genrule/module2/Class2.java, void Class2.interTargetAbstractNPEBad(Class1), 2, NULL_DEREFERENCE, [start of procedure interTargetAbstractNPEBad(...),Skipping abstractMayReturnNull(): abstract method,Definition of abstractMayReturnNull()] infer/tests/build_systems/genrule/module2/Class2.java, void Class2.dereferenceLocalNullableFieldBad(), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `Class2.field` in the call to `toString()` could be null. (Origin: field Class2.field at line 51)]
infer/tests/build_systems/genrule/module2/Class2.java, void Class2.interTargetNPEBad(), 2, NULL_DEREFERENCE, [start of procedure interTargetNPEBad(),start of procedure returnsNull(),return from a call to String Class1.returnsNull()] infer/tests/build_systems/genrule/module2/Class2.java, void Class2.dereferenceUnannotatedMethodReturningNullBad(Class1), 1, NULL_DEREFERENCE, [start of procedure dereferenceUnannotatedMethodReturningNullBad(...),start of procedure unannotatedReturnNull(),return from a call to Object Class1.unannotatedReturnNull()]
infer/tests/build_systems/genrule/module2/Class2.java, void Class2.interTargetNativeNPEBad(Class1), 2, NULL_DEREFERENCE, [start of procedure interTargetNativeNPEBad(...),Skipping nativeMayReturnNull(): method has no implementation,Definition of nativeMayReturnNull()] infer/tests/build_systems/genrule/module2/Class2.java, void Class2.followMethodDeclarationOnlyBad(SkipImplementationClass1), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj2` in the call to `toString()` could be null. (Origin: call to annotatedNullable() at line 41)]
infer/tests/build_systems/genrule/module2/Class2.java, void Class2.localNPE2Bad(), 2, NULL_DEREFERENCE, [start of procedure localNPE2Bad()] infer/tests/build_systems/genrule/module2/Class2.java, void Class2.interTargetAbstractNPEBad(Class1), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj` in the call to `toString()` could be null. (Origin: call to abstractMayReturnNull() at line 31)]
infer/tests/build_systems/genrule/module2/Class2.java, void Class2.interTargetNPEBad(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj` in the call to `toString()` could be null. (Origin: call to returnsNull() at line 26)]
infer/tests/build_systems/genrule/module2/Class2.java, void Class2.interTargetNativeNPEBad(Class1), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj` in the call to `toString()` could be null. (Origin: call to nativeMayReturnNull() at line 36)]
infer/tests/build_systems/genrule/module2/Class2.java, void Class2.localNPE2Bad(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj` in the call to `toString()` could be null. (Origin: null constant at line 21)]

@ -1,5 +1,6 @@
build_systems/genrule/module2/Class2.java, void Class2.dereferenceInterTargetFieldBad(Class1), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `class1.field1` in the call to `toString()` could be null. (Origin: field Class1.field1 at line 55)] build_systems/genrule/module2/Class2.java, int Class2.dereferenceInterTargetField2Bad(Class1), 1, ERADICATE_NULL_FIELD_ACCESS, [origin,Object `class1.field2` could be null when accessing field `Class1.x`. (Origin: field Class1.field2 at line 59)]
build_systems/genrule/module2/Class2.java, void Class2.dereferenceLocalNullableFieldBad(), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `Class2.field2` in the call to `toString()` could be null. (Origin: field Class2.field2 at line 51)] build_systems/genrule/module2/Class2.java, void Class2.dereferenceInterTargetField1Bad(Class1), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `class1.field1` in the call to `toString()` could be null. (Origin: field Class1.field1 at line 55)]
build_systems/genrule/module2/Class2.java, void Class2.dereferenceLocalNullableFieldBad(), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `Class2.field` in the call to `toString()` could be null. (Origin: field Class2.field at line 51)]
build_systems/genrule/module2/Class2.java, void Class2.followMethodDeclarationOnlyBad(SkipImplementationClass1), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj2` in the call to `toString()` could be null. (Origin: call to annotatedNullable() at line 41)] build_systems/genrule/module2/Class2.java, void Class2.followMethodDeclarationOnlyBad(SkipImplementationClass1), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj2` in the call to `toString()` could be null. (Origin: call to annotatedNullable() at line 41)]
build_systems/genrule/module2/Class2.java, void Class2.interTargetAbstractNPEBad(Class1), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj` in the call to `toString()` could be null. (Origin: call to abstractMayReturnNull() at line 31)] build_systems/genrule/module2/Class2.java, void Class2.interTargetAbstractNPEBad(Class1), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj` in the call to `toString()` could be null. (Origin: call to abstractMayReturnNull() at line 31)]
build_systems/genrule/module2/Class2.java, void Class2.interTargetNPEBad(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj` in the call to `toString()` could be null. (Origin: call to returnsNull() at line 26)] build_systems/genrule/module2/Class2.java, void Class2.interTargetNPEBad(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `obj` in the call to `toString()` could be null. (Origin: call to returnsNull() at line 26)]

@ -15,6 +15,9 @@ public abstract class Class1 {
public @Nullable Object field1; public @Nullable Object field1;
public int x;
public @Nullable Class1 field2;
public static @Nullable String returnsNull() { public static @Nullable String returnsNull() {
return null; return null;
} }
@ -28,4 +31,7 @@ public abstract class Class1 {
public native @Nullable Object nativeMayReturnNull(); public native @Nullable Object nativeMayReturnNull();
public Object unannotatedReturnNull() {
return null;
}
} }

@ -15,7 +15,7 @@ import genrule.module1.SkipImplementationClass1;
public class Class2 { public class Class2 {
@Nullable Object field2; @Nullable Object field;
void localNPE2Bad() { void localNPE2Bad() {
Object obj = null; Object obj = null;
@ -48,11 +48,18 @@ public class Class2 {
} }
void dereferenceLocalNullableFieldBad() { void dereferenceLocalNullableFieldBad() {
field2.toString(); field.toString();
} }
void dereferenceInterTargetFieldBad(Class1 class1) { void dereferenceInterTargetField1Bad(Class1 class1) {
class1.field1.toString(); class1.field1.toString();
} }
int dereferenceInterTargetField2Bad(Class1 class1) {
return class1.field2.x;
}
void dereferenceUnannotatedMethodReturningNullBad(Class1 class1) {
class1.unannotatedReturnNull().toString();
}
} }

Loading…
Cancel
Save