[java] Support Ultralight synthetic names

Summary:
Previously, only names containing '$' were considered synthetic. We need
to extend the logic and look for "_UL_" in the name as well.

Also I deduped 4 different impls of "is_synthetic/generated/autogen".

Reviewed By: ngorogiannis

Differential Revision: D25899232

fbshipit-source-id: 9463eca6b
master
Artem Pianykh 4 years ago committed by Facebook GitHub Bot
parent 01c8024a50
commit 3aaf1de4f7

@ -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]

@ -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[]. *)

@ -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

@ -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_"

@ -54,3 +54,5 @@ val field_cst : string
val field_st : Mangled.t
val infer_builtins_cl : string
val is_synthetic_name : string -> bool

@ -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)

@ -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

@ -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. *)

@ -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() {

@ -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"

Loading…
Cancel
Save