Summary: This is a complex enough feature so iterating on it in a safe manner will be useful. Reviewed By: artempyanykh Differential Revision: D24725406 fbshipit-source-id: 81b247143master
parent
bd2d2d129e
commit
dc667bec0f
@ -0,0 +1,55 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
|
||||
let pp_annotation_point fmt
|
||||
Jsonbug_t.{id; kind; method_info; field_name; param_num; num_violations; dependent_point_ids} =
|
||||
let pp_id fmt = Format.fprintf fmt "id: %s@\n" id in
|
||||
let pp_kind fmt =
|
||||
let kind_str = match kind with `Field -> "Field" | `Method -> "Method" | `Param -> "Param" in
|
||||
Format.fprintf fmt "kind: %s@\n" kind_str
|
||||
in
|
||||
let pp_method_info fmt =
|
||||
Option.iter method_info ~f:(fun Jsonbug_t.{method_name; params; access_level} ->
|
||||
let access_level_str =
|
||||
match access_level with
|
||||
| `Public ->
|
||||
"Public"
|
||||
| `Private ->
|
||||
"Private"
|
||||
| `Protected ->
|
||||
"Protected"
|
||||
| `Default ->
|
||||
"Default"
|
||||
in
|
||||
Format.fprintf fmt "method_info:@\n @[method_name: %s@\nparams: %s@\naccess_level: %s@]@\n"
|
||||
method_name (String.concat ~sep:", " params) access_level_str )
|
||||
in
|
||||
let pp_field_name fmt =
|
||||
Option.iter field_name ~f:(fun field_name -> Format.fprintf fmt "field_name: %s@\n" field_name)
|
||||
in
|
||||
let pp_param_num fmt =
|
||||
Option.iter param_num ~f:(fun param_num -> Format.fprintf fmt "param_num: %d@\n" param_num)
|
||||
in
|
||||
let pp_num_violations fmt = Format.fprintf fmt "num_violations: %d@\n" num_violations in
|
||||
let pp_dependent_point_ids fmt =
|
||||
Format.fprintf fmt "dependent_point_ids: [%s]@\n" (String.concat ~sep:", " dependent_point_ids)
|
||||
in
|
||||
let pp_point fmt =
|
||||
pp_id fmt ;
|
||||
pp_kind fmt ;
|
||||
pp_method_info fmt ;
|
||||
pp_field_name fmt ;
|
||||
pp_param_num fmt ;
|
||||
pp_num_violations fmt ;
|
||||
pp_dependent_point_ids fmt
|
||||
in
|
||||
Format.fprintf fmt "Annotation point:@\n @[%t@]@\n" pp_point
|
||||
|
||||
|
||||
let pp_annotation_graph = Pp.seq ~sep:"" pp_annotation_point
|
@ -0,0 +1,12 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
|
||||
(** A helper module to deal with Nullsafe annotation graph's JSON representation *)
|
||||
|
||||
val pp_annotation_graph : Format.formatter -> Jsonbug_t.annotation_point list -> unit
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"nullsafe-annotation-graph": true
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package codetoanalyze.java.nullsafe_annotation_graph;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class AnnotationGraph {
|
||||
public String fieldA;
|
||||
public String fieldB;
|
||||
public @Nullable String fieldC;
|
||||
public String fieldD;
|
||||
|
||||
// methodA() depends on `p` and on `fieldD`
|
||||
private String methodA(String p, boolean flag) {
|
||||
// fieldA depends on p
|
||||
fieldA = p;
|
||||
if (flag) {
|
||||
return p;
|
||||
} else {
|
||||
return fieldD;
|
||||
}
|
||||
}
|
||||
|
||||
// methodB() depends on methodA()'s return
|
||||
private String methodB() {
|
||||
return methodA("", true);
|
||||
}
|
||||
|
||||
public String methodC() {
|
||||
String a = methodB();
|
||||
// fieldC depends on methodB()
|
||||
fieldC = a;
|
||||
|
||||
// return does NOT depend on methodB(): already checked for null
|
||||
if (a != null) {
|
||||
return a;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private void methodD() {
|
||||
// fieldB depends on fieldA
|
||||
fieldB = fieldA;
|
||||
}
|
||||
|
||||
private void methodE() {
|
||||
// violation for fieldD
|
||||
SomeExternalClass.acceptsNull(fieldD);
|
||||
// violation for fieldD
|
||||
fieldD.toString();
|
||||
if (fieldD != null) {
|
||||
// no violation for fieldD
|
||||
SomeExternalClass.acceptsNull(fieldD);
|
||||
}
|
||||
// no violation for fieldB
|
||||
SomeExternalClass.doesNotAcceptNull(fieldB);
|
||||
|
||||
if (methodC() != null) {
|
||||
methodC().toString(); // no violation for methodC
|
||||
}
|
||||
}
|
||||
|
||||
private void methodF() {
|
||||
// violation for fieldA
|
||||
fieldA.toString();
|
||||
|
||||
methodC().toString(); // violation for methodC
|
||||
}
|
||||
}
|
||||
|
||||
class SomeExternalClass {
|
||||
public static void acceptsNull(@Nullable String a) {}
|
||||
|
||||
public static void doesNotAcceptNull(String a) {}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
TESTS_DIR = ../../..
|
||||
|
||||
INFER_OPTIONS = \
|
||||
--eradicate-only \
|
||||
--debug-exceptions
|
||||
INFERPRINT_OPTIONS = --issues-tests
|
||||
SOURCES = $(wildcard *.java)
|
||||
|
||||
include $(TESTS_DIR)/javac.make
|
@ -0,0 +1,172 @@
|
||||
codetoanalyze/java/nullsafe-annotation-graph/AnnotationGraph.java, Linters_dummy_method, 12, ERADICATE_ANNOTATION_GRAPH, no_bucket, INFO, [], AnnotationGraph, codetoanalyze.java.nullsafe_annotation_graph
|
||||
AnnotationGraph:
|
||||
Annotation point:
|
||||
id: f0
|
||||
kind: Field
|
||||
field_name: fieldA
|
||||
num_violations: 1
|
||||
dependent_point_ids: [f1]
|
||||
|
||||
Annotation point:
|
||||
id: f1
|
||||
kind: Field
|
||||
field_name: fieldB
|
||||
num_violations: 1
|
||||
dependent_point_ids: []
|
||||
|
||||
Annotation point:
|
||||
id: f2
|
||||
kind: Field
|
||||
field_name: fieldD
|
||||
num_violations: 1
|
||||
dependent_point_ids: [m4]
|
||||
|
||||
Annotation point:
|
||||
id: m4
|
||||
kind: Method
|
||||
method_info:
|
||||
method_name: methodA
|
||||
params: java.lang.String, boolean
|
||||
access_level: Private
|
||||
num_violations: 0
|
||||
dependent_point_ids: [m7]
|
||||
|
||||
Annotation point:
|
||||
id: m7
|
||||
kind: Method
|
||||
method_info:
|
||||
method_name: methodB
|
||||
params:
|
||||
access_level: Private
|
||||
num_violations: 0
|
||||
dependent_point_ids: []
|
||||
|
||||
Annotation point:
|
||||
id: m9
|
||||
kind: Method
|
||||
method_info:
|
||||
method_name: methodC
|
||||
params:
|
||||
access_level: Public
|
||||
num_violations: 1
|
||||
dependent_point_ids: []
|
||||
|
||||
Annotation point:
|
||||
id: p10
|
||||
kind: Param
|
||||
method_info:
|
||||
method_name: methodC
|
||||
params:
|
||||
access_level: Public
|
||||
param_num: 0
|
||||
num_violations: 0
|
||||
dependent_point_ids: []
|
||||
|
||||
Annotation point:
|
||||
id: p11
|
||||
kind: Param
|
||||
method_info:
|
||||
method_name: methodD
|
||||
params:
|
||||
access_level: Private
|
||||
param_num: 0
|
||||
num_violations: 0
|
||||
dependent_point_ids: []
|
||||
|
||||
Annotation point:
|
||||
id: p12
|
||||
kind: Param
|
||||
method_info:
|
||||
method_name: methodE
|
||||
params:
|
||||
access_level: Private
|
||||
param_num: 0
|
||||
num_violations: 0
|
||||
dependent_point_ids: []
|
||||
|
||||
Annotation point:
|
||||
id: p13
|
||||
kind: Param
|
||||
method_info:
|
||||
method_name: methodF
|
||||
params:
|
||||
access_level: Private
|
||||
param_num: 0
|
||||
num_violations: 0
|
||||
dependent_point_ids: []
|
||||
|
||||
Annotation point:
|
||||
id: p3
|
||||
kind: Param
|
||||
method_info:
|
||||
method_name: <init>
|
||||
params:
|
||||
access_level: Public
|
||||
param_num: 0
|
||||
num_violations: 0
|
||||
dependent_point_ids: []
|
||||
|
||||
Annotation point:
|
||||
id: p5
|
||||
kind: Param
|
||||
method_info:
|
||||
method_name: methodA
|
||||
params: java.lang.String, boolean
|
||||
access_level: Private
|
||||
param_num: 0
|
||||
num_violations: 0
|
||||
dependent_point_ids: []
|
||||
|
||||
Annotation point:
|
||||
id: p6
|
||||
kind: Param
|
||||
method_info:
|
||||
method_name: methodA
|
||||
params: java.lang.String, boolean
|
||||
access_level: Private
|
||||
param_num: 1
|
||||
num_violations: 0
|
||||
dependent_point_ids: [f0, m4]
|
||||
|
||||
Annotation point:
|
||||
id: p8
|
||||
kind: Param
|
||||
method_info:
|
||||
method_name: methodB
|
||||
params:
|
||||
access_level: Private
|
||||
param_num: 0
|
||||
num_violations: 0
|
||||
dependent_point_ids: []
|
||||
|
||||
|
||||
codetoanalyze/java/nullsafe-annotation-graph/AnnotationGraph.java, Linters_dummy_method, 12, ERADICATE_META_CLASS_NEEDS_IMPROVEMENT, no_bucket, INFO, [], AnnotationGraph, codetoanalyze.java.nullsafe_annotation_graph, issues: 3, curr_mode: "Default"
|
||||
codetoanalyze/java/nullsafe-annotation-graph/AnnotationGraph.java, Linters_dummy_method, 77, ERADICATE_ANNOTATION_GRAPH, no_bucket, INFO, [], SomeExternalClass, codetoanalyze.java.nullsafe_annotation_graph
|
||||
AnnotationGraph:
|
||||
Annotation point:
|
||||
id: p0
|
||||
kind: Param
|
||||
method_info:
|
||||
method_name: <init>
|
||||
params:
|
||||
access_level: Default
|
||||
param_num: 0
|
||||
num_violations: 0
|
||||
dependent_point_ids: []
|
||||
|
||||
Annotation point:
|
||||
id: p1
|
||||
kind: Param
|
||||
method_info:
|
||||
method_name: doesNotAcceptNull
|
||||
params: java.lang.String
|
||||
access_level: Public
|
||||
param_num: 0
|
||||
num_violations: 0
|
||||
dependent_point_ids: []
|
||||
|
||||
|
||||
codetoanalyze/java/nullsafe-annotation-graph/AnnotationGraph.java, Linters_dummy_method, 77, ERADICATE_META_CLASS_CAN_BE_NULLSAFE, no_bucket, ADVICE, [Congrats! `SomeExternalClass` is free of nullability issues. Mark it `@Nullsafe(Nullsafe.Mode.LOCAL)` to prevent regressions.], SomeExternalClass, codetoanalyze.java.nullsafe_annotation_graph, issues: 0, curr_mode: "Default", promote_mode: "Strict"
|
||||
codetoanalyze/java/nullsafe-annotation-graph/AnnotationGraph.java, codetoanalyze.java.nullsafe_annotation_graph.AnnotationGraph.<init>(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `fieldD` is declared non-nullable, so it should be initialized in the constructor or in an `@Initializer` method], AnnotationGraph, codetoanalyze.java.nullsafe_annotation_graph
|
||||
codetoanalyze/java/nullsafe-annotation-graph/AnnotationGraph.java, codetoanalyze.java.nullsafe_annotation_graph.AnnotationGraph.<init>(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `fieldB` is declared non-nullable, so it should be initialized in the constructor or in an `@Initializer` method], AnnotationGraph, codetoanalyze.java.nullsafe_annotation_graph
|
||||
codetoanalyze/java/nullsafe-annotation-graph/AnnotationGraph.java, codetoanalyze.java.nullsafe_annotation_graph.AnnotationGraph.<init>(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `fieldA` is declared non-nullable, so it should be initialized in the constructor or in an `@Initializer` method], AnnotationGraph, codetoanalyze.java.nullsafe_annotation_graph
|
Loading…
Reference in new issue