-
Notifications
You must be signed in to change notification settings - Fork 63
Expand file tree
/
Copy pathWriteDeadAnnotations.ml
More file actions
154 lines (139 loc) · 4.86 KB
/
WriteDeadAnnotations.ml
File metadata and controls
154 lines (139 loc) · 4.86 KB
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
open Common
type language = Ml | Res
let posLanguage (pos : Lexing.position) =
if
Filename.check_suffix pos.pos_fname ".res"
|| Filename.check_suffix pos.pos_fname ".resi"
then Res
else Ml
let deadAnnotation = "dead"
let annotateAtEnd ~pos =
match posLanguage pos with
| Res -> false
| Ml -> true
let getPosAnnotation decl =
match annotateAtEnd ~pos:decl.pos with
| true -> decl.posEnd
| false -> decl.posStart
let rec lineToString_ {original; declarations} =
match declarations with
| [] -> original
| ({declKind; path; pos} as decl) :: nextDeclarations ->
let language = posLanguage pos in
let annotationStr =
match language with
| Res ->
"@" ^ deadAnnotation ^ "(\"" ^ (path |> Path.withoutHead) ^ "\") "
| Ml ->
" " ^ "["
^ (match declKind |> DeclKind.isType with
| true -> "@"
| false -> "@@")
^ deadAnnotation ^ " \"" ^ (path |> Path.withoutHead) ^ "\"] "
in
let posAnnotation = decl |> getPosAnnotation in
let col = posAnnotation.pos_cnum - posAnnotation.pos_bol in
let originalLen = String.length original in
{
original =
(if String.length original >= col && col > 0 then
let original1, original2 =
try
( String.sub original 0 col,
String.sub original col (originalLen - col) )
with Invalid_argument _ -> (original, "")
in
if language = Res && declKind = VariantCase then
if
String.length original2 >= 2
&& (String.sub [@doesNotRaise]) original2 0 2 = "| "
then
original1 ^ "| " ^ annotationStr
^ (String.sub [@doesNotRaise]) original2 2
(String.length original2 - 2)
else if
String.length original2 >= 1
&& (String.sub [@doesNotRaise]) original2 0 1 = "|"
then
original1 ^ "|" ^ annotationStr
^ (String.sub [@doesNotRaise]) original2 1
(String.length original2 - 1)
else original1 ^ "| " ^ annotationStr ^ original2
else original1 ^ annotationStr ^ original2
else
match language = Ml with
| true -> original ^ annotationStr
| false -> annotationStr ^ original);
declarations = nextDeclarations;
}
|> lineToString_
let lineToString {original; declarations} =
let declarations =
declarations
|> List.sort (fun decl1 decl2 ->
(getPosAnnotation decl2).pos_cnum - (getPosAnnotation decl1).pos_cnum)
in
lineToString_ {original; declarations}
let currentFile = ref ""
let currentFileLines = (ref [||] : line array ref)
let readFile fileName =
let channel = open_in fileName in
let lines = ref [] in
let rec loop () =
let line = {original = input_line channel; declarations = []} in
lines := line :: !lines;
loop ()
[@@raises End_of_file]
in
try loop ()
with End_of_file ->
close_in_noerr channel;
!lines |> List.rev |> Array.of_list
let writeFile fileName lines =
if fileName <> "" && !Cli.write then (
let channel = open_out fileName in
let lastLine = Array.length lines in
lines
|> Array.iteri (fun n line ->
output_string channel (line |> lineToString);
if n < lastLine - 1 then output_char channel '\n');
close_out_noerr channel)
let offsetOfPosAdjustment = function
| FirstVariant | Nothing -> 0
| OtherVariant -> 2
let getLineAnnotation ~decl ~line =
if !Cli.json then
let posAnnotation = decl |> getPosAnnotation in
let offset = decl.posAdjustment |> offsetOfPosAdjustment in
EmitJson.emitAnnotate
~pos:
( posAnnotation.pos_lnum - 1,
posAnnotation.pos_cnum - posAnnotation.pos_bol + offset )
~text:
(if decl.posAdjustment = FirstVariant then
(* avoid syntax error *)
"| @dead "
else "@dead ")
~action:"Suppress dead code warning"
else
Format.asprintf "@. <-- line %d@. %s" decl.pos.pos_lnum
(line |> lineToString)
let cantFindLine () = if !Cli.json then "" else "\n <-- Can't find line"
let lineAnnotationToString = function
| None -> cantFindLine ()
| Some (decl, line) -> getLineAnnotation ~decl ~line
let addLineAnnotation ~decl : lineAnnotation =
let fileName = decl.pos.pos_fname in
if Sys.file_exists fileName then (
if fileName <> !currentFile then (
writeFile !currentFile !currentFileLines;
currentFile := fileName;
currentFileLines := readFile fileName);
let indexInLines = (decl |> getPosAnnotation).pos_lnum - 1 in
match !currentFileLines.(indexInLines) with
| line ->
line.declarations <- decl :: line.declarations;
Some (decl, line)
| exception Invalid_argument _ -> None)
else None
let write () = writeFile !currentFile !currentFileLines