Clang Diff Determinator

Reviewed By: jvillard

Differential Revision: D14722626

fbshipit-source-id: 074ef2413
master
Martin Trojer 6 years ago committed by Facebook Github Bot
parent 67cd0e1cd7
commit 52fd4c50de

17
.gitignore vendored

@ -24,22 +24,23 @@ duplicates.txt
*.ast.sh
*.ast.bdump
*.ast.biniou
/infer/tests/build_systems/buck_flavors_deterministic/capture_hash-*.sha
/infer/tests/build_systems/buck_flavors_diff/src/hello.c
/infer/tests/build_systems/codetoanalyze/ndk-build/hello_app/libs/
/infer/tests/build_systems/codetoanalyze/ndk-build/hello_app/obj/
/infer/tests/build_systems/codetoanalyze/utf8_*n_pwd
/infer/tests/build_systems/codetoanalyze/mvn/**/target/
/infer/tests/build_systems/codetoanalyze/path with spaces/
/infer/tests/build_systems/clang_compilation_db_escaped/compile_commands.json
/infer/tests/build_systems/clang_compilation_db_relpath/compile_commands.json
/infer/tests/build_systems/clang_test_determinator/*.test
/infer/tests/build_systems/clang_with_MD_flag/hello.d
/infer/tests/build_systems/codetoanalyze/mvn/**/target/
/infer/tests/build_systems/codetoanalyze/ndk-build/hello_app/libs/
/infer/tests/build_systems/codetoanalyze/ndk-build/hello_app/obj/
/infer/tests/build_systems/codetoanalyze/path with spaces/
/infer/tests/build_systems/codetoanalyze/utf8_*n_pwd
/infer/tests/build_systems/codetoanalyze/xcodebuild/simple_app/app_built
/infer/tests/build_systems/codetoanalyze/xcodebuild/simple_app/build/
/infer/tests/build_systems/differential_*/**/*.class
/infer/tests/build_systems/differential_*/**/Diff*.java
/infer/tests/build_systems/diff/src
/infer/tests/build_systems/diff_*/src
/infer/tests/build_systems/buck_flavors_deterministic/capture_hash-*.sha
/infer/tests/build_systems/differential_*/**/*.class
/infer/tests/build_systems/differential_*/**/Diff*.java
/infer/tests/build_systems/genrule/report.json
/infer/tests/build_systems/java_test_determinator/*.test
/infer/tests/codetoanalyze/java/classloads/*.loads

@ -45,6 +45,7 @@ BUILD_SYSTEMS_TESTS += \
run_hidden_linters \
tracebugs \
utf8_in_procname \
clang_test_determinator \
DIRECT_TESTS += \
c_biabduction \

@ -1514,6 +1514,11 @@ INTERNAL OPTIONS
which speficy the relevant arguments. (Conversely:
--no-test-determinator)
--test-determinator-clang
Activates: Run infer in Test Determinator mode for clang. It is
used together with the --modified-lines. (Conversely:
--no-test-determinator-clang)
--test-filtering
Activates: List all the files Infer can report on (should be
called from the root of the project) (Conversely:

@ -1068,6 +1068,9 @@ let register_perf_stats_report () =
let main ~report_json =
if Config.test_determinator_clang then (
TestDeterminator.emit_tests_to_run () ;
TestDeterminator.emit_relevant_methods () ) ;
let issue_formats = init_issues_format_list report_json in
let formats_by_report_kind =
let costs_report_format_kind =

@ -2163,6 +2163,12 @@ and test_determinator =
$(b,--test-profiler) flags, which speficy the relevant arguments."
and test_determinator_clang =
CLOpt.mk_bool ~long:"test-determinator-clang" ~default:false
"Run infer in Test Determinator mode for clang. It is used together with the \
$(b,--modified-lines)."
and test_filtering =
CLOpt.mk_bool ~deprecated:["test_filtering"] ~long:"test-filtering"
"List all the files Infer can report on (should be called from the root of the project)"
@ -3024,6 +3030,8 @@ and keep_going = !keep_going
and test_determinator = !test_determinator
and test_determinator_clang = !test_determinator_clang
and test_filtering = !test_filtering
and profiler_samples = !profiler_samples

@ -652,6 +652,8 @@ val symops_per_iteration : int option
val test_determinator : bool
val test_determinator_clang : bool
val test_filtering : bool
val testing_mode : bool

@ -52,6 +52,8 @@ let do_source_file (translation_unit_context : CFrontend_config.translation_unit
let cfg = compute_icfg translation_unit_context tenv ast in
L.(debug Capture Verbose)
"@\n End building call/cfg graph for '%a'.@\n" SourceFile.pp source_file ;
if Config.test_determinator_clang then
TestDeterminator.test_to_run_clang source_file cfg Config.modified_lines None ;
(* This part below is a boilerplate in every frontends. *)
(* This could be moved in the cfg_infer module *)
NullabilityPreanalysis.analysis cfg tenv ;

@ -100,8 +100,8 @@ module MethodRangeMap = struct
end
module DiffLines = struct
(* This is a map
file name |--> {set of changed line }
(* This is a map
file name |--> {set of changed line }
*)
let map : int list String.Map.t ref = ref String.Map.empty
@ -136,8 +136,8 @@ module DiffLines = struct
end
let pp_profiler_sample_set fmt s =
F.fprintf fmt " (size = %i) " (JPS.ProfilerSample.cardinal s) ;
JPS.ProfilerSample.iter (fun m -> F.fprintf fmt "@\n > %a " Typ.Procname.pp m) s
F.fprintf fmt " (set size = %i) " (JPS.ProfilerSample.cardinal s) ;
JPS.ProfilerSample.iter (fun m -> F.fprintf fmt "@\n <Method:> %a " Typ.Procname.pp m) s
module TestSample = struct
@ -201,7 +201,7 @@ let compute_affected_methods_clang source_file changed_lines_map method_range_ma
L.(debug TestDeterminator Medium) "found!@\n" ;
let affected_methods = affected_methods method_range_map fname changed_lines in
L.(debug TestDeterminator Medium)
"== Resulting Affected Methods ==@\n%a@\n== End Affected Methods ==@\n"
"@\n@\n== Resulting Affected Methods ==%a@\n== End Affected Methods ==@\n\n"
pp_profiler_sample_set affected_methods ;
affected_methods
| None ->
@ -212,6 +212,9 @@ let compute_affected_methods_clang source_file changed_lines_map method_range_ma
let relevant_tests = ref []
(* Methods modified in a diff *)
let relevant_methods = ref []
let _get_relevant_test_to_run () = !relevant_tests
let emit_tests_to_run () =
@ -221,14 +224,28 @@ let emit_tests_to_run () =
L.progress "Tests to run: [%a]@\n" (Pp.seq ~sep:", " F.pp_print_string) !relevant_tests
let emit_relevant_methods () =
let methods = List.dedup_and_sort ~compare:String.compare !relevant_methods in
let json = `List (List.map ~f:(fun t -> `String t) methods) in
let outpath = Config.results_dir ^/ "diff_determinator.json" in
Yojson.Basic.to_file outpath json ;
L.progress "Methods modified in this Diff: [%a]@\n"
(Pp.seq ~sep:", " F.pp_print_string)
!relevant_methods
let init_clang cfg changed_lines_file test_samples_file =
DiffLines.init_changed_lines_map changed_lines_file ;
DiffLines.print_changed_lines () ;
MethodRangeMap.create_clang_method_range_map cfg ;
L.(debug TestDeterminator Medium) "%a@\n" MethodRangeMap.pp_map () ;
TestSample.init_test_sample test_samples_file ;
L.(debug TestDeterminator Medium) "%a@\n" TestSample.pp_map () ;
initialized_test_determinator := true
match test_samples_file with
| Some _ ->
TestSample.init_test_sample test_samples_file
| _ ->
() ;
L.(debug TestDeterminator Medium) "%a@\n" TestSample.pp_map () ;
initialized_test_determinator := true
let init_java changed_lines_file test_samples_file code_graph_file =
@ -242,7 +259,7 @@ let init_java changed_lines_file test_samples_file code_graph_file =
(* test_to_run = { n | Affected_Method /\ ts_n != 0 } *)
let _test_to_run_clang source_file cfg changed_lines_file test_samples_file =
let test_to_run_clang source_file cfg changed_lines_file test_samples_file =
L.(debug TestDeterminator Quiet)
"****** Start Test Determinator for %s *****@\n"
(SourceFile.to_string source_file) ;
@ -251,6 +268,10 @@ let _test_to_run_clang source_file cfg changed_lines_file test_samples_file =
compute_affected_methods_clang source_file (DiffLines.changed_lines_map ())
(MethodRangeMap.method_range_map ())
in
let affected_methods_list =
JPS.ProfilerSample.fold (fun m acc -> Typ.Procname.to_string m :: acc) affected_methods []
in
relevant_methods := List.append affected_methods_list !relevant_methods ;
let test_to_run =
if JPS.ProfilerSample.is_empty affected_methods then []
else

@ -9,9 +9,11 @@ open! IStd
val test_to_run_java : string option -> string option -> string option -> unit
val _test_to_run_clang :
val test_to_run_clang :
SourceFile.t -> Procdesc.t Typ.Procname.Hash.t -> string option -> string option -> unit
val emit_tests_to_run : unit -> unit
val emit_relevant_methods : unit -> unit
val _get_relevant_test_to_run : unit -> string list

@ -0,0 +1,46 @@
# Copyright (c) 2017-present, Facebook, Inc.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
# E2E test involving the test_determinator feature
TESTS_DIR = ../..
include $(TESTS_DIR)/base.make
A_CPP = A.cpp
TEST_DETERMINATOR_RESULT = infer-out-mod2/diff_determinator.json
DIFF_OUTPUT = diff.mod2.test
default: $(TEST_DETERMINATOR_RESULT)
$(DIFF_OUTPUT):
$(QUIET)echo -n '$(A_CPP):' > diff.mod1.test
$(QUIET)(diff -N --unchanged-line-format="U" --old-line-format="O" --new-line-format="N" \
orig-$(A_CPP) mod1-$(A_CPP) || [ $$? = 1 ]) >> diff.mod1.test
$(QUIET)echo -n '$(A_CPP):' > diff.mod2.test
$(QUIET)(diff -N --unchanged-line-format="U" --old-line-format="O" --new-line-format="N" \
orig-$(A_CPP) mod2-$(A_CPP) || [ $$? = 1 ]) >> diff.mod2.test
$(TEST_DETERMINATOR_RESULT): $(DIFF_OUTPUT)
$(QUIET)$(call silent_on_success,Testing test-determinator with set of changes in mod1,\
cp mod1-$(A_CPP) $(A_CPP);\
$(INFER_BIN) -o infer-out-mod1 --test-determinator-clang --modified-lines diff.mod1.test -- clang -c $(A_CPP))
$(QUIET)$(call silent_on_success,Testing test-determinator-clang with set of changes in mod2,\
cp mod2-$(A_CPP) $(A_CPP);\
$(INFER_BIN) -o infer-out-mod2 --test-determinator-clang --modified-lines diff.mod2.test -- clang -c $(A_CPP))
$(QUIET) rm $(A_CPP)
.PHONY: test
test: $(TEST_DETERMINATOR_RESULT)
$(QUIET)$(call check_no_diff,diff_determinator.json.mod1.exp,infer-out-mod1/diff_determinator.json)
$(QUIET)$(call check_no_diff,diff_determinator.json.mod2.exp,infer-out-mod2/diff_determinator.json)
.PHONY: replace
replace: $(TEST_DETERMINATOR_RESULT)
$(COPY) infer-out-mod1/diff_determinator.json diff_determinator.json.mod1.exp
$(COPY) infer-out-mod2/diff_determinator.json diff_determinator.json.mod2.exp
.PHONY: clean
clean:
$(REMOVE_DIR) *.test infer-out-mod* *.o

@ -0,0 +1 @@
["Shapes::Cube::area","Shapes::Cube::sort","Shapes::Cube::sort::lambda_A.cpp:24:25::","Shapes::Cube::sort::lambda_A.cpp:24:25::operator()"]

@ -0,0 +1,26 @@
/*
* Copyright (c) 2019-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <algorithm>
namespace Shapes {
class Cube {
int size;
public:
void set_size(int);
int area() { return size * size * size; };
void sort(Cube*, unsigned);
};
void Cube::set_size(int s) { size = s; }
void Cube::sort(Cube* xs, unsigned n) {
std::sort(xs, xs + n, [](Cube a, Cube b) { return (a.area() > b.area()); });
}
} // namespace Shapes

@ -0,0 +1,27 @@
/*
* Copyright (c) 2019-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <algorithm>
namespace Shapes {
class Cube {
int size;
public:
void set_size(int);
int area() { return size * size; };
void sort(Cube*, unsigned);
};
void Cube::set_size(int s) { size = s; }
void Cube::sort(Cube* xs, unsigned n) {
// this is a lambda folks
std::sort(xs, xs + n, [](Cube a, Cube b) { return (a.area() < b.area()); });
}
} // namespace Shapes

@ -0,0 +1,26 @@
/*
* Copyright (c) 2019-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <algorithm>
namespace Shapes {
class Cube {
int size;
public:
void set_size(int);
int area() { return size * size; };
void sort(Cube*, unsigned);
};
void Cube::set_size(int s) { size = s; }
void Cube::sort(Cube* xs, unsigned n) {
std::sort(xs, xs + n, [](Cube a, Cube b) { return (a.area() < b.area()); });
}
} // namespace Shapes
Loading…
Cancel
Save