forked from LexiFi/dead_code_analyzer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
deadFlag.ml
209 lines (184 loc) · 6.58 KB
/
deadFlag.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
(***************************************************************************)
(* *)
(* Copyright (c) 2014-2016 LexiFi SAS. All rights reserved. *)
(* *)
(* This source code is licensed under the MIT License *)
(* found in the LICENSE file at the root of this source tree *)
(* *)
(***************************************************************************)
type threshold = {exceptions: int; percentage: float; optional: [`Percent | `Both]}
type opt = {print: bool; call_sites: bool; threshold: threshold}
let opta = ref
{
print = false;
call_sites = false;
threshold =
{
exceptions = 0;
percentage = 1.;
optional = `Percent
};
}
let optn = ref
{
print = false;
call_sites = false;
threshold =
{
exceptions = 0;
percentage = 1.;
optional = `Percent
};
}
let update_opt opt s =
let threshold s =
let len = String.length s in
if len > 5 && String.sub s 0 5 = "both:" then begin
let limits = String.sub s 5 (String.length s - 5) in
let thr =
let rec loop s pos len =
if len = String.length s then s
else if s.[pos] = ',' then String.sub s (pos - len) len
else loop s (pos + 1) (len + 1)
in loop limits 0 0
in
let pos = String.length thr + 1 in
let pct = String.sub limits pos (String.length limits - pos) in
opt := {!opt with threshold={!opt.threshold with optional = `Both}};
let thr = String.trim thr in
let pct = String.trim pct in
try
opt := {!opt with threshold = {!opt.threshold with exceptions = int_of_string thr}};
opt := {!opt with threshold = {!opt.threshold with percentage = float_of_string pct}}
with Failure _ -> raise (Arg.Bad ("-Ox: wrong arguments: " ^ limits))
end
else if len > 8 && String.sub s 0 8 = "percent:" then
let pct = String.sub s 8 (String.length s - 8) |> String.trim in
try opt := {!opt with threshold={!opt.threshold with percentage = float_of_string pct}}
with Failure _ -> raise (Arg.Bad ("-Ox: wrong argument: " ^ pct))
else raise (Arg.Bad ("-Ox: unknown option " ^ s))
in
match s with
| "all" -> opt := {!opt with print = true}
| "nothing" -> opt := {!opt with print = false}
| s ->
opt := {!opt with print = true};
let s =
if String.length s > 6 && String.sub s 0 6 = "calls:" then begin
opt := {!opt with call_sites = true};
String.sub s 6 (String.length s - 6)
end
else s
in
threshold s;
if !opt.threshold.exceptions < 0 then
raise (Arg.Bad ("-Ox: number of exceptions must be >= 0"))
else if !opt.threshold.percentage > 1. || !opt.threshold.percentage < 0. then
raise (Arg.Bad ("-Ox: percentage must be >= 0.0 and <= 1.0"))
type style = {opt_arg: bool; unit_pat: bool; seq: bool; binding: bool}
let style = ref
{
opt_arg = false;
unit_pat = false;
seq = false;
binding = false;
}
let update_style s =
let rec aux = function
| (b, "opt")::l -> style := {!style with opt_arg = b};
aux l
| (b, "unit")::l -> style := {!style with unit_pat = b};
aux l
| (b, "seq")::l -> style := {!style with seq = b};
aux l
| (b, "bind")::l -> style := {!style with binding = b};
aux l
| (b, "all")::l -> style := {unit_pat = b; opt_arg = b; seq = b; binding = b};
aux l
| (_, "")::l -> aux l
| (_, s)::_ -> raise (Arg.Bad ("-S: unknown option: " ^ s))
| [] -> ()
in
let list_of_opt str =
try
let rec split acc pos len =
if str.[pos] <> '+' && str.[pos] <> '-' then
split acc (pos - 1) (len + 1)
else let acc = (str.[pos] = '+', String.trim (String.sub str (pos + 1) len)) :: acc in
if pos > 0 then split acc (pos - 1) 0
else acc
in split [] (String.length str - 1) 0
with _ -> raise (Arg.Bad ("options' arguments must start with a delimiter (`+' or `-')"))
in
aux (list_of_opt s)
type basic = {print: bool; call_sites: bool; threshold: int}
let exported : basic ref = ref
({
print = true;
call_sites = false;
threshold = 0
} : basic)
let obj = ref
({
print = true;
call_sites = false;
threshold = 0;
} : basic)
let typ : basic ref = ref
({
print = true;
call_sites = false;
threshold = 0
} : basic)
let update_basic opt (flag : basic ref) = function
| "all" -> flag := {!flag with print = true}
| "nothing" -> flag := {!flag with print = false}
| s ->
flag := {!flag with print = true};
let threshold =
let len = String.length s in
if len > 6 && String.sub s 0 6 = "calls:" then begin
flag := {!flag with call_sites = true};
String.sub s 6 (String.length s - 6)
end
else if len > 10 && String.sub s 0 10 = "threshold:" then
String.sub s 10 (String.length s - 10)
else raise (Arg.Bad (opt ^ ": unknown option: " ^ s))
in
let threshold = String.trim threshold |> int_of_string in
if threshold < 0 then
raise (Arg.Bad (opt ^ ": integer should be >= 0; Got " ^ string_of_int threshold))
else flag := {!flag with threshold}
let verbose = ref false
let set_verbose () = verbose := true
(* Print name starting with '_' *)
let underscore = ref true
let set_underscore () = underscore := false
let internal = ref false
let set_internal () = internal := true
let normalize_path s =
let rec split_path s =
let open Filename in
if s = current_dir_name || s = dirname s then [s]
else (basename s) :: (split_path (dirname s))
in
let rec norm_path = function
| [] -> []
| x :: ((y :: _) as yss) when x = y && x = Filename.current_dir_name -> norm_path yss
| x :: xss ->
if x = Filename.current_dir_name then norm_path xss (* strip leading ./ *)
else
let yss = List.filter (fun x -> x <> Filename.current_dir_name) xss in
x :: yss
in
let rec concat_path = function
| [] -> ""
| x :: xs -> Filename.concat x (concat_path xs)
in
concat_path (norm_path (List.rev (split_path s)))
let exclude, is_excluded =
let tbl = Hashtbl.create 10 in
let exclude s = Hashtbl.replace tbl (normalize_path s) () in
let is_excluded s = Hashtbl.mem tbl (normalize_path s) in
exclude, is_excluded
let directories : string list ref = ref []