This repository has been archived by the owner on Jun 4, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 205
/
graph_code_checker.ml
119 lines (107 loc) · 3.77 KB
/
graph_code_checker.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
(* Yoann Padioleau
*
* Copyright (C) 2014 Facebook
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation, with the
* special exception on linking described in file license.txt.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
* license.txt for more details.
*)
open Common
module E = Entity_code
module G = Graph_code
module PI = Parse_info
module Error = Errors_code
(*****************************************************************************)
(* Prelude *)
(*****************************************************************************)
(*
* current checks:
* - Deadcode
* - UndefinedDefOfDecl
* - UnusedExport
*)
(*****************************************************************************)
(* Helpers *)
(*****************************************************************************)
(* todo: generalize and mv in file_type.ml? *)
let is_header_file file =
let (_d,_b,e) = Common2.dbe_of_filename file in
e = "h"
(*****************************************************************************)
(* Checker *)
(*****************************************************************************)
let check_imperative g =
let pred = G.mk_eff_use_pred g in
g +> G.iter_nodes (fun n ->
G.nodeinfo_opt n g +> Common.do_option (fun info ->
let ps = pred n in
(* todo: filter nodes that are in boilerplate code *)
if ps = []
then
(match n with
| s, E.Function when s =$= "main" || s =~ "^main__.*" -> ()
| _ ->
Error.warning info.G.pos (Error.Deadcode n);
);
(* todo: factorize with graph_code_clang, put in database_code? *)
let n_def_opt =
match n with
| s, E.Prototype -> Some (s, E.Function)
| s, E.GlobalExtern -> Some (s, E.Global)
| _ -> None
in
n_def_opt +> Common.do_option (fun n_def ->
let n_decl = n in
if not (G.has_node n_def g)
then
(* actually in C we can have things that looks like GlobalExtern
* e.g. Syscall sysnop; but are actually Prototype, so we must look
* for E.Function in that case
*)
if (G.has_node (fst n_def, E.Function) g)
then ()
else
Error.warning info.G.pos (Error.UndefinedDefOfDecl n_decl)
);
let n_decl_opt =
match n with
| s, E.Function -> Some (s, E.Prototype)
| s, E.Global -> Some (s, E.GlobalExtern)
| _ -> None
in
n_decl_opt +> Common.do_option (fun n_decl ->
let n_def = n in
if (G.has_node n_decl g)
then begin
let file_def = G.file_of_node n_def g in
let file_decl = G.file_of_node n_decl g in
let info_decl = G.nodeinfo n_decl g in
let users_outside = ps +> List.filter (fun n ->
try
let file_user = G.file_of_node n g in
file_user <> file_def
with Not_found -> true
)
in
if users_outside = [] && ps <> [] && is_header_file file_decl
then Error.warning info_decl.G.pos
(Error.UnusedExport (n_decl, file_def));
(* for clang I usually add a Use edge between the def and the decl
* so the decl would not have been marked as dead without this:
*)
if ps = []
then Error.warning info_decl.G.pos (Error.Deadcode n_decl);
end
);
))
let check g =
Common.save_excursion Error.g_errors [] (fun () ->
check_imperative g;
!Error.g_errors +> List.rev
)