Find and remove dead code and unused APIs in OCaml projects
1(** Core types and utilities for prune *)
2
3(** {2 Location information} *)
4
5type location = private {
6 file : string;
7 start_line : int;
8 start_col : int;
9 end_line : int;
10 end_col : int;
11}
12
13val extend :
14 ?start_line:int -> end_line:int -> ?end_col:int -> location -> location
15(** [extend ?start_line ~end_line ?end_col location] extends a location's
16 boundaries. *)
17
18val merge : location -> location -> location
19(** [merge loc1 loc2] merges two locations into one encompassing both. *)
20
21val location :
22 line:int ->
23 ?end_line:int ->
24 start_col:int ->
25 end_col:int ->
26 string ->
27 location
28(** [location ~line ?end_line ~start_col ~end_col file] creates a location for a
29 single line. *)
30
31val pp_location : Format.formatter -> location -> unit
32(** [pp_location fmt location] pretty-prints a location. *)
33
34(** {2 Symbol information} *)
35
36type symbol_kind =
37 | Value (** Functions, variables, etc. *)
38 | Type (** Type declarations *)
39 | Module (** Module declarations *)
40 | Constructor (** Variant constructors *)
41 | Field (** Record fields *)
42
43val string_of_symbol_kind : symbol_kind -> string
44(** [string_of_symbol_kind kind] converts symbol kind to lowercase string for
45 user-facing display. *)
46
47type symbol_info = { name : string; kind : symbol_kind; location : location }
48
49(** {2 Occurrence information} *)
50
51type usage_classification =
52 | Unused
53 | Used_only_in_excluded (** Used only in excluded directories *)
54 | Used (** Used in at least one non-excluded location *)
55 | Unknown
56 (** Cannot determine usage via occurrences (e.g., modules, exceptions) *)
57
58val pp_usage_classification : Format.formatter -> usage_classification -> unit
59(** [pp_usage_classification fmt classification] pretty-prints a usage
60 classification. *)
61
62type occurrence_info = {
63 symbol : symbol_info;
64 occurrences : int;
65 locations : location list;
66 usage_class : usage_classification;
67}
68
69(** {2 Statistics} *)
70
71type stats = {
72 mli_exports_removed : int;
73 ml_implementations_removed : int;
74 iterations : int;
75 lines_removed : int;
76}
77(** Statistics about a prune run *)
78
79val empty_stats : stats
80(** [empty_stats] is an empty statistics record. *)
81
82val pp_stats : Format.formatter -> stats -> unit
83(** [pp_stats fmt stats] pretty-prints statistics. *)
84
85(** {2 Warning information} *)
86
87type warning_type =
88 | Unused_value (** Warning 32: unused value declaration *)
89 | Unused_type (** Warning 34: unused type declaration *)
90 | Unused_open (** Warning 33: unused open statement *)
91 | Unused_constructor (** Warning 37: unused constructor *)
92 | Unused_exception (** Warning 38: unused exception declaration *)
93 | Unused_field (** Warning 69: unused record field definition *)
94 | Unnecessary_mutable
95 (** Warning 69: mutable record field that is never mutated *)
96 | Signature_mismatch (** Compiler error: value required but not provided *)
97 | Unbound_field (** Compiler error: unbound record field *)
98
99val pp_warning_type : Format.formatter -> warning_type -> unit
100(** [pp_warning_type fmt warning_type] pretty-prints a warning type. *)
101
102(** Precision of location information from compiler warnings/errors *)
103type location_precision =
104 | Exact_definition
105 (** Location covers the full definition that should be removed. Doc
106 comments should be removed as they document the definition. *)
107 | Exact_statement
108 (** Location covers a full statement (like open) that should be removed.
109 No doc comments to remove as statements don't have doc comments. *)
110 | Needs_enclosing_definition
111 (** Location is just an identifier, needs merlin enclosing to find full
112 definition. Doc comments should be removed after finding enclosing. *)
113 | Needs_field_usage_parsing
114 (** Location is field name in record construction, needs special parsing.
115 No doc comments removal as we're removing usage, not definition. *)
116
117val precision_of_warning_type : warning_type -> location_precision
118(** [precision_of_warning_type warning_type] gets the location precision for a
119 given warning type. *)
120
121val symbol_kind_of_warning : warning_type -> symbol_kind
122(** [symbol_kind_of_warning warning_type] converts warning type to symbol kind.
123*)
124
125type warning_info = {
126 location : location;
127 name : string;
128 warning_type : warning_type;
129 location_precision : location_precision;
130}
131
132val pp_warning_info : Format.formatter -> warning_info -> unit
133(** [pp_warning_info fmt warning_info] pretty-prints a warning info. *)
134
135(** {2 Build tracking} *)
136
137type build_result = {
138 success : bool;
139 output : string;
140 exit_code : int;
141 warnings : warning_info list; (* Parsed warnings from build output *)
142}
143(** Result of a build operation *)
144
145type context
146(** Context for tracking build state across operations *)
147
148val empty_context : context
149(** [empty_context] is an empty context with no build result. *)
150
151(** {2 Error handling} *)
152
153type error = [ `Msg of string | `Build_error of context ]
154
155val pp_error : Format.formatter -> error -> unit
156(** [pp_error fmt error] pretty-prints an error. *)
157
158val update_build_result : context -> build_result -> context
159(** [update_build_result ctx result] updates context with a new build result. *)
160
161val last_build_result : context -> build_result option
162(** [last_build_result ctx] gets the last build result from context. *)
163
164(** Build error classification *)
165type build_error_type =
166 | No_error (** Build succeeded *)
167 | Fixable_errors of warning_info list
168 (** Errors that prune might be able to fix *)
169 | Other_errors of string (** Any other build errors - show full output *)
170
171(** {2 Merlin response types} *)
172
173type outline_item = {
174 kind : symbol_kind;
175 name : string;
176 location : location;
177 children : outline_item list option;
178}
179(** Outline item from merlin *)
180
181type outline_response = outline_item list
182(** Merlin response types *)
183
184type occurrences_response = location list
185
186val outline_response_of_json :
187 file:string -> Jsont.json -> (outline_response, error) result
188(** [outline_response_of_json ~file json] parses JSON response into outline. *)
189
190val occurrences_response_of_json :
191 root_dir:string -> Jsont.json -> (occurrences_response, error) result
192(** [occurrences_response_of_json ~root_dir json] parses JSON response into
193 occurrences. *)