Skip to content

Commit 052eb68

Browse files
authored
Override context when locating (#91)
* Add context override to locate * Create tests * Add more context and tests * Remove query_protocol.mli * Cleanup signature of Locate.from_string * Stop using array literals in test * Declare arrays * Rewrite test without using arrays * Fix if syntax * Change == to = * Format files
1 parent 71d4117 commit 052eb68

File tree

12 files changed

+445
-24
lines changed

12 files changed

+445
-24
lines changed

src/analysis/context.ml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ type t =
3535
(* We attach the constructor description here so in the case of
3636
disambiguated constructors we actually directly look for the type
3737
path (cf. #486, #794). *)
38+
| Unknown_constructor
3839
| Expr
3940
| Label of Types.label_description (* Similar to constructors. *)
41+
| Unknown_label
4042
| Module_path
4143
| Module_type
4244
| Patt
@@ -46,15 +48,28 @@ type t =
4648

4749
let to_string = function
4850
| Constructor (cd, _) -> Printf.sprintf "constructor %s" cd.cstr_name
51+
| Unknown_constructor -> Printf.sprintf "unknown constructor"
4952
| Expr -> "expression"
5053
| Label lbl -> Printf.sprintf "record field %s" lbl.lbl_name
54+
| Unknown_label -> Printf.sprintf "record field"
5155
| Module_path -> "module path"
5256
| Module_type -> "module type"
5357
| Patt -> "pattern"
5458
| Constant -> "constant"
5559
| Type -> "type"
5660
| Unknown -> "unknown"
5761

62+
let of_locate_context : Query_protocol.Locate_context.t -> t = function
63+
| Expr -> Expr
64+
| Module_path -> Module_path
65+
| Module_type -> Module_type
66+
| Patt -> Patt
67+
| Type -> Type
68+
| Constant -> Constant
69+
| Constructor -> Unknown_constructor
70+
| Label -> Unknown_label
71+
| Unknown -> Unknown
72+
5873
(* Distinguish between "Mo[d]ule.something" and "Module.some[t]hing" *)
5974
let cursor_on_longident_end ~cursor:cursor_pos
6075
~lid_loc:{ Asttypes.loc; txt = lid } name =

src/analysis/context.mli

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ type t =
3131
(* We attach the constructor description here so in the case of
3232
disambiguated constructors we actually directly look for the type
3333
path (cf. #486, #794). *)
34+
| Unknown_constructor
3435
| Expr
3536
| Label of Types.label_description (* Similar to constructors. *)
37+
| Unknown_label
3638
| Module_path
3739
| Module_type
3840
| Patt
@@ -42,6 +44,8 @@ type t =
4244

4345
val to_string : t -> string
4446

47+
val of_locate_context : Query_protocol.Locate_context.t -> t
48+
4549
(**
4650
[inspect_browse_tree lid ~cursor mbrowse] tries to provide contextual
4751
information given the selected identifier, the position of the cursor and the

src/analysis/env_lookup.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ module Namespace = struct
2121
| Type -> [ `Type; `Mod; `Modtype; `Constr; `Labels; `Vals ]
2222
| Module_type -> [ `Modtype; `Mod; `Type; `Constr; `Labels; `Vals ]
2323
| Expr | Constant -> [ `Vals; `Mod; `Modtype; `Constr; `Labels; `Type ]
24+
| Unknown_constructor -> [ `Constr; `Vals; `Mod; `Modtype; `Labels; `Type ]
25+
| Unknown_label -> [ `Labels; `Vals; `Mod; `Modtype; `Constr; `Type ]
2426
| Patt -> [ `Mod; `Modtype; `Type; `Constr; `Labels; `Vals ]
2527
| Unknown -> [ `Vals; `Type; `Constr; `Mod; `Modtype; `Labels ]
2628
| Label lbl -> [ `This_label lbl ]

src/analysis/locate.ml

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ type result =
4343
approximated : bool
4444
}
4545

46+
module Namespace_resolution = struct
47+
type t =
48+
| From_context of Query_protocol.Locate_context.t
49+
| Explicit of Env_lookup.Namespace.inferred_basic list
50+
| Inferred
51+
end
52+
4653
module File : sig
4754
type t = private
4855
| ML of string
@@ -897,16 +904,26 @@ let infer_namespace ?let_pun_behavior ?namespaces ~pos lid browse is_label =
897904
"dropping inferred context, it is not precise enough";
898905
`Ok [ `Labels ])
899906

900-
let from_string ~config ~env ~local_defs ~pos ?let_pun_behavior ?namespaces path
901-
=
907+
let from_string ~config ~env ~local_defs ~pos ?let_pun_behavior
908+
?(namespaces = Namespace_resolution.Inferred) path =
902909
File_switching.reset ();
903910
let browse = Mbrowse.of_typedtree local_defs in
904911
let lid = Type_utils.parse_longident path in
905912
let from_lid lid =
906913
let ident, is_label = Longident.keep_suffix lid in
907-
match
908-
infer_namespace ?let_pun_behavior ?namespaces ~pos lid browse is_label
909-
with
914+
let namespaces =
915+
match namespaces with
916+
| From_context ctxt ->
917+
let ctxt = Context.of_locate_context ctxt in
918+
log ~title:"from_string" "overrode context: %s" (Context.to_string ctxt);
919+
`Ok (Env_lookup.Namespace.from_context ctxt)
920+
| Explicit namespaces ->
921+
infer_namespace ?let_pun_behavior ~namespaces ~pos lid browse is_label
922+
| Inferred ->
923+
infer_namespace ?let_pun_behavior ?namespaces:None ~pos lid browse
924+
is_label
925+
in
926+
match namespaces with
910927
| `Error e -> e
911928
| `Ok nss ->
912929
log ~title:"from_string"

src/analysis/locate.mli

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ type result =
4747
approximated : bool
4848
}
4949

50+
module Namespace_resolution : sig
51+
type t =
52+
| From_context of Query_protocol.Locate_context.t
53+
(** Choose the namespaces based on a [Query_protocol.Locate_context.t] *)
54+
| Explicit of Env_lookup.Namespace.inferred_basic list
55+
(** Explicitly choose which namespaces to search in. The namespaces are prioritized
56+
based on the list order (with the first element being highest priority) *)
57+
| Inferred (** Infer which namespaces to search in *)
58+
end
59+
5060
val uid_of_result :
5161
traverse_aliases:bool -> Shape_reduce.result -> Shape.Uid.t option * bool
5262

@@ -74,7 +84,7 @@ val from_string :
7484
local_defs:Mtyper.typedtree ->
7585
pos:Lexing.position ->
7686
?let_pun_behavior:Mbrowse.Let_pun_behavior.t ->
77-
?namespaces:Env_lookup.Namespace.inferred_basic list ->
87+
?namespaces:Namespace_resolution.t ->
7888
string ->
7989
[> `File_not_found of string
8090
| `Found of result

src/commands/new_commands.ml

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -455,21 +455,34 @@ let all_commands =
455455
command "locate"
456456
~spec:
457457
[ optional "-prefix" "<string> Prefix to complete"
458-
(Marg.param "string" (fun txt (_, pos, kind) ->
459-
(Some txt, pos, kind)));
458+
(Marg.param "string" (fun txt (_, pos, kind, ctx) ->
459+
(Some txt, pos, kind, ctx)));
460460
arg "-position" "<position> Position to complete"
461-
(marg_position (fun pos (prefix, _pos, kind) -> (prefix, pos, kind)));
461+
(marg_position (fun pos (prefix, _pos, kind, ctx) ->
462+
(prefix, pos, kind, ctx)));
462463
optional "-look-for"
463464
"<interface|implementation> Prefer opening interface or \
464465
implementation"
465466
(Marg.param "<interface|implementation>"
466-
(fun kind (prefix, pos, _) ->
467+
(fun kind (prefix, pos, _, ctx) ->
467468
match kind with
468-
| "mli" | "interface" -> (prefix, pos, `MLI)
469-
| "ml" | "implementation" -> (prefix, pos, `ML)
469+
| "mli" | "interface" -> (prefix, pos, `MLI, ctx)
470+
| "ml" | "implementation" -> (prefix, pos, `ML, ctx)
470471
| str ->
471472
failwithf "expecting interface or implementation, got %S."
472-
str))
473+
str));
474+
(let contexts =
475+
let open Query_protocol.Locate_context in
476+
all |> List.map ~f:to_string |> String.concat ~sep:"|"
477+
in
478+
optional "-context"
479+
(Format.sprintf
480+
"<%s> Which context to search for the identifier in" contexts)
481+
(Marg.param (Format.sprintf "<%s>" contexts)
482+
(fun ctx (prefix, pos, kind, _) ->
483+
match Query_protocol.Locate_context.of_string ctx with
484+
| Some ctx -> (prefix, pos, kind, Some ctx)
485+
| None -> failwithf "invalid context %s." ctx)))
473486
]
474487
~doc:
475488
"Finds the declaration of entity at the specified position, Or \
@@ -479,13 +492,13 @@ let all_commands =
479492
- `{'pos': position}` if the location is in the current buffer,\n\
480493
- `{'file': string, 'pos': position}` if definition is located in a \
481494
different file."
482-
~default:(None, `None, `MLI)
495+
~default:(None, `None, `MLI, None)
483496
begin
484-
fun buffer (prefix, pos, lookfor) ->
497+
fun buffer (prefix, pos, lookfor, context) ->
485498
match pos with
486499
| `None -> failwith "-position <pos> is mandatory"
487500
| #Msource.position as pos ->
488-
run buffer (Query_protocol.Locate (prefix, lookfor, pos))
501+
run buffer (Query_protocol.Locate (prefix, lookfor, pos, context))
489502
end;
490503
command "locate-type"
491504
~spec:

src/commands/query_json.ml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ let dump (type a) : a t -> json =
105105
| Syntax_document pos ->
106106
mk "syntax-document" [ ("position", mk_position pos) ]
107107
| Expand_ppx pos -> mk "ppx-expand" [ ("position", mk_position pos) ]
108-
| Locate (prefix, look_for, pos) ->
108+
| Locate (prefix, look_for, pos, context) ->
109109
mk "locate"
110110
[ ( "prefix",
111111
match prefix with
@@ -115,7 +115,12 @@ let dump (type a) : a t -> json =
115115
match look_for with
116116
| `ML -> `String "implementation"
117117
| `MLI -> `String "interface" );
118-
("position", mk_position pos)
118+
("position", mk_position pos);
119+
( "context",
120+
match context with
121+
| Some context ->
122+
`String (Query_protocol.Locate_context.to_string context)
123+
| None -> `Null )
119124
]
120125
| Jump (target, pos) ->
121126
mk "jump" [ ("target", `String target); ("position", mk_position pos) ]

src/frontend/ocamlmerlin/old/old_IO.ml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,12 @@ let request_of_json context =
170170
| `String "document" :: `String path :: pos ->
171171
request (Query (Document (Some path, mandatory_position pos)))
172172
| `String "locate" :: (`String "" | `Null) :: `String choice :: pos ->
173-
request (Query (Locate (None, ml_or_mli choice, mandatory_position pos)))
173+
request
174+
(Query (Locate (None, ml_or_mli choice, mandatory_position pos, None)))
174175
| `String "locate" :: `String path :: `String choice :: pos ->
175176
request
176-
(Query (Locate (Some path, ml_or_mli choice, mandatory_position pos)))
177+
(Query
178+
(Locate (Some path, ml_or_mli choice, mandatory_position pos, None)))
177179
| `String "jump" :: `String target :: pos ->
178180
request (Query (Jump (target, mandatory_position pos)))
179181
| [ `String "outline" ] -> request (Query Outline)

src/frontend/query_commands.ml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ let dispatch pipeline (type a) : a Query_protocol.t -> a = function
614614
(Ppx_expand.get_ppxed_source ~ppxed_parsetree ~pos
615615
(Option.get ppx_kind_with_attr))
616616
| None -> `No_ppx)
617-
| Locate (patho, ml_or_mli, pos) ->
617+
| Locate (patho, ml_or_mli, pos, context) ->
618618
let typer = Mpipeline.typer_result pipeline in
619619
let local_defs = Mtyper.get_typedtree typer in
620620
let pos = Mpipeline.get_lexing_pos pipeline pos in
@@ -641,9 +641,13 @@ let dispatch pipeline (type a) : a Query_protocol.t -> a = function
641641
}
642642
in
643643
begin
644+
let namespaces =
645+
Option.map context ~f:(fun ctx ->
646+
Locate.Namespace_resolution.From_context ctx)
647+
in
644648
match
645-
Locate.from_string ~config ~env ~local_defs ~pos ~let_pun_behavior
646-
path
649+
Locate.from_string ~config ~env ~local_defs ~pos ?namespaces
650+
~let_pun_behavior path
647651
with
648652
| `Found { file; location; _ } ->
649653
Locate.log ~title:"result" "found: %s" file;

src/frontend/query_protocol.ml

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,54 @@ type _ _bool = bool
129129
type occurrences_status =
130130
[ `Not_requested | `Out_of_sync of string list | `No_def | `Included ]
131131

132+
module Locate_context = struct
133+
type t =
134+
| Expr
135+
| Module_path
136+
| Module_type
137+
| Patt
138+
| Type
139+
| Constant
140+
| Constructor
141+
| Label
142+
| Unknown
143+
144+
let to_string = function
145+
| Expr -> "expr"
146+
| Module_path -> "module_path"
147+
| Module_type -> "module_type"
148+
| Patt -> "pattern"
149+
| Type -> "type"
150+
| Constant -> "constant"
151+
| Constructor -> "constructor"
152+
| Label -> "label"
153+
| Unknown -> "unknown"
154+
155+
let of_string = function
156+
| "expr" -> Some Expr
157+
| "module_path" -> Some Module_path
158+
| "module_type" -> Some Module_type
159+
| "pattern" -> Some Patt
160+
| "type" -> Some Type
161+
| "constant" -> Some Constant
162+
| "constructor" -> Some Constructor
163+
| "label" -> Some Label
164+
| "unknown" -> Some Unknown
165+
| _ -> None
166+
167+
let all =
168+
[ Expr;
169+
Module_path;
170+
Module_type;
171+
Patt;
172+
Type;
173+
Constant;
174+
Constructor;
175+
Label;
176+
Unknown
177+
]
178+
end
179+
132180
type _ t =
133181
| Type_expr (* *) : string * Msource.position -> string t
134182
| Stack_or_heap_enclosing (* *) :
@@ -182,7 +230,10 @@ type _ t =
182230
| `At_origin ]
183231
t
184232
| Locate (* *) :
185-
string option * [ `ML | `MLI ] * Msource.position
233+
string option
234+
* [ `ML | `MLI ]
235+
* Msource.position
236+
* Locate_context.t option
186237
-> [ `Found of string option * Lexing.position
187238
| `Invalid_context
188239
| `Builtin of string

0 commit comments

Comments
 (0)