Skip to content

Commit 446c060

Browse files
committed
wip migrate command
1 parent 812d07e commit 446c060

File tree

12 files changed

+283
-3
lines changed

12 files changed

+283
-3
lines changed

analysis/src/Cmt.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,17 @@ let fullsFromModule ~package ~moduleName =
5151
let loadFullCmtFromPath ~path =
5252
let uri = Uri.fromPath path in
5353
fullFromUri ~uri
54+
55+
let loadCmtInfosFromPath ~path =
56+
let uri = Uri.fromPath path in
57+
match Packages.getPackage ~uri with
58+
| None -> None
59+
| Some package -> (
60+
let moduleName =
61+
BuildSystem.namespacedName package.namespace (FindFiles.getName path)
62+
in
63+
match Hashtbl.find_opt package.pathsForModule moduleName with
64+
| Some paths ->
65+
let cmt = getCmtPath ~uri paths in
66+
Shared.tryReadCmt cmt
67+
| None -> None)

compiler/ml/builtin_attributes.ml

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,46 @@ let rec deprecated_of_attrs = function
7979
Some (string_of_opt_payload p)
8080
| _ :: tl -> deprecated_of_attrs tl
8181

82+
let rec deprecated_of_attrs_with_migrate = function
83+
| [] -> None
84+
| ( {txt = "deprecated"; _},
85+
PStr [{pstr_desc = Pstr_eval ({pexp_desc = Pexp_record (fields, _)}, _)}]
86+
)
87+
:: _ -> (
88+
let reason =
89+
fields
90+
|> List.find_map (fun field ->
91+
match field with
92+
| {
93+
lid = {txt = Lident "reason"};
94+
x = {pexp_desc = Pexp_constant (Pconst_string (reason, _))};
95+
} ->
96+
Some reason
97+
| _ -> None)
98+
in
99+
let migration_template =
100+
fields
101+
|> List.find_map (fun field ->
102+
match field with
103+
| {lid = {txt = Lident "migrate"}; x = migration_template} ->
104+
Some migration_template
105+
| _ -> None)
106+
in
107+
108+
(* TODO: Validate and error if expected shape mismatches *)
109+
match reason with
110+
| Some reason -> Some (reason, migration_template)
111+
| None -> None)
112+
| ({txt = "ocaml.deprecated" | "deprecated"; _}, p) :: _ ->
113+
Some (string_of_opt_payload p, None)
114+
| _ :: tl -> deprecated_of_attrs_with_migrate tl
115+
82116
let check_deprecated loc attrs s =
83-
match deprecated_of_attrs attrs with
117+
match deprecated_of_attrs_with_migrate attrs with
84118
| None -> ()
85-
| Some txt -> Location.deprecated loc (cat s txt)
119+
| Some (txt, migration_template) ->
120+
!Cmt_utils.record_deprecated_used loc txt migration_template;
121+
Location.deprecated loc (cat s txt)
86122

87123
let check_deprecated_inclusion ~def ~use loc attrs1 attrs2 s =
88124
match (deprecated_of_attrs attrs1, deprecated_of_attrs attrs2) with

compiler/ml/cmt_format.ml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type cmt_infos = {
6363
cmt_imports : (string * Digest.t option) list;
6464
cmt_interface_digest : Digest.t option;
6565
cmt_use_summaries : bool;
66+
cmt_extra_info: Cmt_utils.cmt_extra_info;
6667
}
6768

6869
type error =
@@ -154,15 +155,22 @@ let read_cmi filename =
154155

155156
let saved_types = ref []
156157
let value_deps = ref []
158+
let deprecated_used = ref []
157159

158160
let clear () =
159161
saved_types := [];
160-
value_deps := []
162+
value_deps := [];
163+
deprecated_used := []
161164

162165
let add_saved_type b = saved_types := b :: !saved_types
163166
let get_saved_types () = !saved_types
164167
let set_saved_types l = saved_types := l
165168

169+
let record_deprecated_used source_loc deprecated_text migration_template =
170+
deprecated_used := {Cmt_utils.source_loc; deprecated_text; migration_template} :: !deprecated_used
171+
172+
let _ = Cmt_utils.record_deprecated_used := record_deprecated_used
173+
166174
let record_value_dependency vd1 vd2 =
167175
if vd1.Types.val_loc <> vd2.Types.val_loc then
168176
value_deps := (vd1, vd2) :: !value_deps
@@ -197,6 +205,7 @@ let save_cmt filename modname binary_annots sourcefile initial_env cmi =
197205
cmt_imports = List.sort compare (Env.imports ());
198206
cmt_interface_digest = this_crc;
199207
cmt_use_summaries = need_to_clear_env;
208+
cmt_extra_info = {deprecated_used = !deprecated_used};
200209
} in
201210
output_cmt oc cmt)
202211
end;

compiler/ml/cmt_format.mli

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type cmt_infos = {
6363
cmt_imports: (string * Digest.t option) list;
6464
cmt_interface_digest: Digest.t option;
6565
cmt_use_summaries: bool;
66+
cmt_extra_info: Cmt_utils.cmt_extra_info;
6667
}
6768

6869
type error = Not_a_typedtree of string
@@ -111,6 +112,9 @@ val set_saved_types : binary_part list -> unit
111112
val record_value_dependency :
112113
Types.value_description -> Types.value_description -> unit
113114

115+
val record_deprecated_used :
116+
Location.t -> string -> Parsetree.expression option -> unit
117+
114118
(*
115119
116120
val is_magic_number : string -> bool

compiler/ml/cmt_utils.ml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
type deprecated_used = {
2+
source_loc: Location.t;
3+
deprecated_text: string;
4+
migration_template: Parsetree.expression option;
5+
}
6+
7+
type cmt_extra_info = {deprecated_used: deprecated_used list}
8+
9+
let record_deprecated_used :
10+
(Location.t -> string -> Parsetree.expression option -> unit) ref =
11+
ref (fun _ _ _ -> ())
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DeprecatedStuff.res: File did not need migration
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
let someNiceString = String.slice("abcdefg", ~start=2, ~end=5)
2+
3+
let someNiceString2 = String.slice(String.slice("abcdefg", ~start=0, ~end=1), ~start=2, ~end=5)
4+
5+
let someNiceString3 = "abcdefg"->String.slice(~start=2, ~end=5)
6+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@deprecated({
2+
reason: "Use `String.slice` instead",
3+
migrate: String.slice(
4+
~start=%insert.labelledArgument("from"),
5+
~end=%insert.labelledArgument("to_"),
6+
),
7+
})
8+
@send
9+
external slice: (string, ~from: int, ~to_: int) => string = "slice"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
let someNiceString = DeprecatedStuff.slice("abcdefg", ~from=2, ~to_=5)
2+
3+
let someNiceString2 = DeprecatedStuff.slice(
4+
DeprecatedStuff.slice("abcdefg", ~from=0, ~to_=1),
5+
~from=2,
6+
~to_=5,
7+
)
8+
9+
let someNiceString3 = "abcdefg"->DeprecatedStuff.slice(~from=2, ~to_=5)

tests/tools_tests/test.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ for file in src/docstrings-format/*.{res,resi,md}; do
3333
fi
3434
done
3535

36+
# Test migrate command
37+
for file in src/migrate/*.{res,resi}; do
38+
output="src/expected/$(basename $file).expected"
39+
../../_build/install/default/bin/rescript-tools migrate "$file" --stdout > $output
40+
# # CI. We use LF, and the CI OCaml fork prints CRLF. Convert.
41+
if [ "$RUNNER_OS" == "Windows" ]; then
42+
perl -pi -e 's/\r\n/\n/g' -- $output
43+
fi
44+
done
45+
3646
warningYellow='\033[0;33m'
3747
successGreen='\033[0;32m'
3848
reset='\033[0m'

0 commit comments

Comments
 (0)