diff --git a/infer/src/IR/Fieldname.ml b/infer/src/IR/Fieldname.ml index ae3798253..cbb77aa68 100644 --- a/infer/src/IR/Fieldname.ml +++ b/infer/src/IR/Fieldname.ml @@ -18,7 +18,7 @@ let get_field_name {field_name} = field_name let is_java {class_name} = Typ.Name.Java.is_class class_name -let is_java_synthetic t = is_java t && String.contains (get_field_name t) '$' +let is_java_synthetic t = is_java t && JConfig.is_synthetic_name (get_field_name t) module T = struct type nonrec t = t [@@deriving compare] diff --git a/infer/src/IR/Procname.ml b/infer/src/IR/Procname.ml index c09cfa413..b38976fbd 100644 --- a/infer/src/IR/Procname.ml +++ b/infer/src/IR/Procname.ml @@ -154,9 +154,7 @@ module Java = struct false - let is_autogen_method_name method_name = String.contains method_name '$' - - let is_autogen_method {method_name} = is_autogen_method_name method_name + let is_autogen_method {method_name} = JConfig.is_synthetic_name method_name (** Check if the proc name has the type of a java vararg. Note: currently only checks that the last argument has type Object[]. *) diff --git a/infer/src/IR/Procname.mli b/infer/src/IR/Procname.mli index 64e09baf2..2e905f9b0 100644 --- a/infer/src/IR/Procname.mli +++ b/infer/src/IR/Procname.mli @@ -63,10 +63,7 @@ module Java : sig from a nested class. *) val is_autogen_method : t -> bool - (** Check if the procedure name is of an auto-generated method containing '$'. *) - - val is_autogen_method_name : string -> bool - (** Check if the string of procedure name is of an auto-generated method containing '$'. *) + (** Check if the procedure name is of an auto-generated/synthetic method. *) val is_anonymous_inner_class_constructor_exn : t -> bool (** Check if the procedure name is an anonymous inner class constructor. Throws if it is not a diff --git a/infer/src/IR/jConfig.ml b/infer/src/IR/jConfig.ml index 6d341b1ff..752e095bf 100644 --- a/infer/src/IR/jConfig.ml +++ b/infer/src/IR/jConfig.ml @@ -65,3 +65,9 @@ let long_code = "J" let short_code = "S" let class_code cl = "L" ^ cl + +let is_synthetic_name name = + (* regular synthetic name *) + String.contains name '$' + (* Ultralight DI *) + || String.is_prefix name ~prefix:"_UL_" diff --git a/infer/src/IR/jConfig.mli b/infer/src/IR/jConfig.mli index 98c9a200b..2c1a87632 100644 --- a/infer/src/IR/jConfig.mli +++ b/infer/src/IR/jConfig.mli @@ -54,3 +54,5 @@ val field_cst : string val field_st : Mangled.t val infer_builtins_cl : string + +val is_synthetic_name : string -> bool diff --git a/infer/src/java/jTrans.ml b/infer/src/java/jTrans.ml index 64eb1e346..a5c1460ea 100644 --- a/infer/src/java/jTrans.ml +++ b/infer/src/java/jTrans.ml @@ -55,7 +55,7 @@ let get_start_location_heuristics = fun ~default pname -> let name = Procname.get_method pname in if - (not (Procname.Java.is_autogen_method_name name)) + (not (Procname.is_java_autogen_method pname)) && (not (String.equal name Procname.Java.constructor_method_name)) && not (String.equal name Procname.Java.class_initializer_method_name) then Option.value ~default (find_proc_loc_backward name ~lines_to_find default) diff --git a/infer/src/nullsafe/AnnotatedField.ml b/infer/src/nullsafe/AnnotatedField.ml index a4cb90a73..96e0cbae9 100644 --- a/infer/src/nullsafe/AnnotatedField.ml +++ b/infer/src/nullsafe/AnnotatedField.ml @@ -36,8 +36,6 @@ let is_enum_value tenv ~class_typ (field_info : Struct.field_info) = false -let is_synthetic field_name = String.contains field_name '$' - (* For the special mode, return the provisionally nullable annotation, otherwise return the unchaged nullability *) let maybe_provisionally_nullable field_name ~field_class ~class_under_analysis nullability = if @@ -87,7 +85,7 @@ let get tenv field_name ~class_typ ~class_under_analysis = not an enum value, but just a static field annotated as nullable. *) then AnnotatedNullability.StrictNonnull EnumValue - else if is_synthetic (Fieldname.get_field_name field_name) then + else if Fieldname.is_java_synthetic field_name then (* This field is artifact of codegen and is not visible to the user. Surfacing it as non-strict is non-actionable for the user *) AnnotatedNullability.StrictNonnull SyntheticField diff --git a/infer/src/nullsafe/eradicateChecks.ml b/infer/src/nullsafe/eradicateChecks.ml index 46d1291a0..8620b606a 100644 --- a/infer/src/nullsafe/eradicateChecks.ml +++ b/infer/src/nullsafe/eradicateChecks.ml @@ -210,13 +210,6 @@ let get_nullability_upper_bound field_name typestate_list = (get_nullability_upper_bound_for_typestate proc_name field_name typestate) ) -let is_generated_field field_name = - (* Annotation transformers might generate hidden fields in the class. - We distinguish such fields by their prefix. - *) - String.is_prefix ~prefix:"$" (Fieldname.get_field_name field_name) - - (** Check field initialization for a given constructor *) let check_constructor_initialization ({IntraproceduralAnalysis.tenv; proc_desc= curr_constructor_pdesc; _} as analysis_data) @@ -281,7 +274,7 @@ let check_constructor_initialization && in_current_class && (not (Fieldname.is_java_outer_instance field_name)) (* not user code, unactionable errors *) - && not (is_generated_field field_name) + && not (Fieldname.is_java_synthetic field_name) in if should_check_field_initialization then ( (* Check if non-null field is not initialized. *) diff --git a/infer/tests/codetoanalyze/java/nullsafe/SyntheticErrorSuppressions.java b/infer/tests/codetoanalyze/java/nullsafe/SyntheticErrorSuppressions.java index 3493eab1e..43eba377f 100644 --- a/infer/tests/codetoanalyze/java/nullsafe/SyntheticErrorSuppressions.java +++ b/infer/tests/codetoanalyze/java/nullsafe/SyntheticErrorSuppressions.java @@ -24,12 +24,17 @@ public class SyntheticErrorSuppressions { static class ClassWithSyntheticCode { @Nullable private Object $ul_fieldNullable; private Object $ul_fieldNotNull; + private Object _UL__ULSEP__fieldNotNull; // This method contains $ which is *extremely* rarely used in user code, but // used extensively in autogenerated code, therefore is good marker. private static void $ul_iAmAutogen( final ClassWithSyntheticCode instance, final Object context) {} + // Anothe example of autogen'd code + private static void _UL_iAmAutogen( + final ClassWithSyntheticCode instance, final Object context) {} + @Nullable private Object $ul_iAmNullableAutogen() { return $ul_fieldNullable; @@ -37,10 +42,12 @@ public class SyntheticErrorSuppressions { public void passingIncorrectParamToSyntheticMethod_OK() { $ul_iAmAutogen(this, Fragment.getContext()); + _UL_iAmAutogen(this, Fragment.getContext()); } public void assigningAnythingToSyntheticField_OK() { $ul_fieldNotNull = null; + _UL__ULSEP__fieldNotNull = null; } // Following cases are hard to support since synthetic code can be a part of @@ -50,6 +57,7 @@ public class SyntheticErrorSuppressions { public void passingSyntheticParamToAnyMethod_OK_FP() { Fragment.setContext($ul_fieldNullable); + Fragment.setContext(_UL__ULSEP__fieldNotNull); } public String dereferencingSyntheticNullableField_OK_FP() { diff --git a/infer/tests/codetoanalyze/java/nullsafe/issues.exp b/infer/tests/codetoanalyze/java/nullsafe/issues.exp index 5d470ae88..55290865c 100644 --- a/infer/tests/codetoanalyze/java/nullsafe/issues.exp +++ b/infer/tests/codetoanalyze/java/nullsafe/issues.exp @@ -371,7 +371,7 @@ codetoanalyze/java/nullsafe/SwitchCase.java, codetoanalyze.java.nullsafe.SwitchC codetoanalyze/java/nullsafe/SwitchCase.java, codetoanalyze.java.nullsafe.SwitchCase.switchOnNullIsBad():java.lang.String, 2, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [NullPointerException will be thrown at this line! `color` is `null` and is dereferenced via calling `ordinal()`: null constant at line 14.], SwitchCase, codetoanalyze.java.nullsafe codetoanalyze/java/nullsafe/SwitchCase.java, codetoanalyze.java.nullsafe.SwitchCase.switchOnNullableIsBad():java.lang.String, 2, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`color` is nullable and is not locally checked for null when calling `ordinal()`: call to getNullableColor() at line 28.], SwitchCase, codetoanalyze.java.nullsafe, nullable_methods:codetoanalyze.java.nullsafe.SwitchCase.getNullableColor at 28 codetoanalyze/java/nullsafe/SyntheticErrorSuppressions.java, Linters_dummy_method, 13, ERADICATE_META_CLASS_NEEDS_IMPROVEMENT, no_bucket, INFO, [], SyntheticErrorSuppressions, codetoanalyze.java.nullsafe, issues: 3, curr_mode: "Default" -codetoanalyze/java/nullsafe/SyntheticErrorSuppressions.java, codetoanalyze.java.nullsafe.SyntheticErrorSuppressions$ClassWithSyntheticCode.dereferencingNullableSyntheticMethodCall_OK_FP():java.lang.String, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`$ul_iAmNullableAutogen(...)` is nullable and is not locally checked for null when calling `toString()`: call to $ul_iAmNullableAutogen() at line 60.], SyntheticErrorSuppressions$ClassWithSyntheticCode, codetoanalyze.java.nullsafe, nullable_methods:codetoanalyze.java.nullsafe.SyntheticErrorSuppressions$ClassWithSyntheticCode.$ul_iAmNullableAutogen at 60 +codetoanalyze/java/nullsafe/SyntheticErrorSuppressions.java, codetoanalyze.java.nullsafe.SyntheticErrorSuppressions$ClassWithSyntheticCode.dereferencingNullableSyntheticMethodCall_OK_FP():java.lang.String, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`$ul_iAmNullableAutogen(...)` is nullable and is not locally checked for null when calling `toString()`: call to $ul_iAmNullableAutogen() at line 68.], SyntheticErrorSuppressions$ClassWithSyntheticCode, codetoanalyze.java.nullsafe, nullable_methods:codetoanalyze.java.nullsafe.SyntheticErrorSuppressions$ClassWithSyntheticCode.$ul_iAmNullableAutogen at 68 codetoanalyze/java/nullsafe/SyntheticErrorSuppressions.java, codetoanalyze.java.nullsafe.SyntheticErrorSuppressions$ClassWithSyntheticCode.dereferencingSyntheticNullableField_OK_FP():java.lang.String, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`SyntheticErrorSuppressions$ClassWithSyntheticCode.$ul_fieldNullable` is nullable and is not locally checked for null when calling `toString()`.], SyntheticErrorSuppressions$ClassWithSyntheticCode, codetoanalyze.java.nullsafe codetoanalyze/java/nullsafe/SyntheticErrorSuppressions.java, codetoanalyze.java.nullsafe.SyntheticErrorSuppressions$ClassWithSyntheticCode.passingSyntheticParamToAnyMethod_OK_FP():void, 1, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [`SyntheticErrorSuppressions$Fragment.setContext(...)`: parameter #1(`context`) is declared non-nullable but the argument `SyntheticErrorSuppressions$ClassWithSyntheticCode.$ul_fieldNullable` is nullable.], SyntheticErrorSuppressions$ClassWithSyntheticCode, codetoanalyze.java.nullsafe codetoanalyze/java/nullsafe/TrueFalseOnNull.java, Linters_dummy_method, 17, ERADICATE_META_CLASS_NEEDS_IMPROVEMENT, no_bucket, INFO, [], TrueFalseOnNull, codetoanalyze.java.nullsafe, issues: 17, curr_mode: "Default"