From 56872d8126dbaa60e463612655b2bc8965b1288a Mon Sep 17 00:00:00 2001 From: Tony Hu Date: Fri, 2 Mar 2018 09:44:30 -0800 Subject: [PATCH] [java] Add command-line option to specify external Java packages Summary: Add a new command-line option `--external-java-packages` which allows the user to specify a list of Java package prefixes for external packages. Then the analysis will not report non-actionable warnings on those packages (e.g., inconsistent `Nullable` annotations in external packages). Reviewed By: jeremydubreil Differential Revision: D7126960 fbshipit-source-id: c4f3c7c --- .inferconfig | 1 - infer/src/base/Config.ml | 19 +++++++++++++++ infer/src/base/Config.mli | 3 +++ infer/src/checkers/NullabilitySuggest.ml | 23 +++++++------------ .../codetoanalyze/java/checkers/.inferconfig | 3 +++ .../codetoanalyze/java/checkers/Makefile | 2 +- .../java/checkers/NullableSuggest.java | 11 +++++++++ infer/tests/external/library/SomeClass.java | 15 ++++++++++++ 8 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 infer/tests/external/library/SomeClass.java diff --git a/.inferconfig b/.inferconfig index f6e6fcb94..d8e2d0048 100644 --- a/.inferconfig +++ b/.inferconfig @@ -14,5 +14,4 @@ "source_contains": "_SHOULD_SKIP_IMPLEMENTATION_" } ] - } diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 7cb22fe7e..829ce95a2 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -1245,6 +1245,14 @@ and eradicate_verbose = CLOpt.mk_bool ~long:"eradicate-verbose" "Print initial and final typestates" +and external_java_packages = + CLOpt.mk_string_list ~long:"external-java-packages" + ~in_help:InferCommand.([(Analyze, manual_java)]) + ~meta:"prefix" + "Specify a list of Java package prefixes for external Java packages. If set, the analysis \ + will not report non-actionable warnings on those packages." + + and fail_on_bug = CLOpt.mk_bool ~deprecated:["-fail-on-bug"] ~long:"fail-on-issue" ~default:false ~in_help:InferCommand.([(Run, manual_generic)]) @@ -2417,6 +2425,8 @@ and eradicate_debug = !eradicate_debug and eradicate_verbose = !eradicate_verbose +and external_java_packages = !external_java_packages + and fail_on_bug = !fail_on_bug and fcp_apple_clang = !fcp_apple_clang @@ -2818,3 +2828,12 @@ let pp_simple = ref true let reset_abs_val () = abs_val := abs_val_orig let run_with_abs_val_equal_zero f x = set_reference_and_call_function abs_val 0 f x + +(** Check if a Java package is external to the repository *) +let java_package_is_external package = + match external_java_packages with + | [] -> + false + | _ -> + List.exists external_java_packages ~f:(fun (prefix: string) -> + String.is_prefix package ~prefix ) diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index c811faf8e..73359bad7 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -679,3 +679,6 @@ val print_usage_exit : unit -> 'a (** Miscellanous *) val register_late_epilogue : (unit -> unit) -> unit + +val java_package_is_external : string -> bool +(** Check if a Java package is external to the repository *) diff --git a/infer/src/checkers/NullabilitySuggest.ml b/infer/src/checkers/NullabilitySuggest.ml index f9201bac2..665a04f31 100644 --- a/infer/src/checkers/NullabilitySuggest.ml +++ b/infer/src/checkers/NullabilitySuggest.ml @@ -151,31 +151,24 @@ let pretty_field_name proc_data field_name = Typ.Fieldname.to_string field_name -(* Checks if a field name stems from a class outside domain of what is analyzed by - * Infer, by seeing if we can get an on-demand summary for it. *) -let is_outside_codebase proc_desc tenv field_name = - match Procdesc.get_proc_name proc_desc with +(* Checks if a field name stems from a class outside the domain of what is analyzed by Infer *) +let is_outside_codebase proc_name field_name = + match proc_name with | Typ.Procname.Java _ -> let class_name = Typ.Fieldname.Java.get_class field_name in - let class_type = Typ.Name.Java.from_string class_name in - let class_struct = Tenv.lookup tenv class_type in - let first_method = - Option.bind ~f:(fun (cls: Typ.Struct.t) -> List.hd cls.methods) class_struct - in - let summary = - Option.bind ~f:(Ondemand.analyze_proc_name ~caller_pdesc:proc_desc) first_method - in - Option.is_none summary + let package, _ = Typ.Name.Java.split_classname class_name in + Option.exists ~f:Config.java_package_is_external package | _ -> false let checker {Callbacks.summary; proc_desc; tenv} = - let annotation = Localise.nullable_annotation_name (Procdesc.get_proc_name proc_desc) in + let proc_name = Procdesc.get_proc_name proc_desc in + let annotation = Localise.nullable_annotation_name proc_name in let report astate (proc_data: extras ProcData.t) = let report_access_path ap udchain = match AccessPath.get_field_and_annotation ap proc_data.tenv with - | Some (field_name, _) when is_outside_codebase proc_desc tenv field_name -> + | Some (field_name, _) when is_outside_codebase proc_name field_name -> (* Skip reporting when the field is outside the analyzed codebase *) () | Some (field_name, _) when Typ.Fieldname.Java.is_captured_parameter field_name -> diff --git a/infer/tests/codetoanalyze/java/checkers/.inferconfig b/infer/tests/codetoanalyze/java/checkers/.inferconfig index 5d7cc8d97..c3d06f43e 100644 --- a/infer/tests/codetoanalyze/java/checkers/.inferconfig +++ b/infer/tests/codetoanalyze/java/checkers/.inferconfig @@ -17,5 +17,8 @@ "sources": ["UserDefinedSource1", "UserDefinedSource2"], "sink": "UserDefinedSink" } + ], + "external-java-packages": [ + "external." ] } diff --git a/infer/tests/codetoanalyze/java/checkers/Makefile b/infer/tests/codetoanalyze/java/checkers/Makefile index 80737490e..8248ff42b 100644 --- a/infer/tests/codetoanalyze/java/checkers/Makefile +++ b/infer/tests/codetoanalyze/java/checkers/Makefile @@ -14,6 +14,6 @@ INFER_OPTIONS = \ --suggest-nullable --check-nullable --racerd \ INFERPRINT_OPTIONS = --issues-tests -SOURCES = $(wildcard *.java) +SOURCES = $(wildcard *.java) $(wildcard $(TESTS_DIR)/external/library/*.java) include $(TESTS_DIR)/javac.make diff --git a/infer/tests/codetoanalyze/java/checkers/NullableSuggest.java b/infer/tests/codetoanalyze/java/checkers/NullableSuggest.java index 74bc7b21d..1f5cebc26 100644 --- a/infer/tests/codetoanalyze/java/checkers/NullableSuggest.java +++ b/infer/tests/codetoanalyze/java/checkers/NullableSuggest.java @@ -8,6 +8,8 @@ */ package codetoanalyze.java.checkers; + +import external.library.SomeClass; import javax.annotation.Nullable; public class NullableSuggest { @@ -126,4 +128,13 @@ public class NullableSuggest { }; } + boolean checkExternalFieldForNullOk(SomeClass parameter) { + if (parameter.field == null) { + // Does not report here. The field belongs to an external library so the + // warning would not be actionable. + return true; + } + return false; + } + } diff --git a/infer/tests/external/library/SomeClass.java b/infer/tests/external/library/SomeClass.java new file mode 100644 index 000000000..c5bd33e62 --- /dev/null +++ b/infer/tests/external/library/SomeClass.java @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2018 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package external.library; + + +public class SomeClass { + public Object field; +}