Skip to content

Commit a273f2e

Browse files
committed
Improve recovery of incomplete jsx tags.
Port frontend completion.
1 parent 203ff25 commit a273f2e

File tree

7 files changed

+70
-76
lines changed

7 files changed

+70
-76
lines changed

analysis/src/CompletionFrontEnd.ml

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,10 +1325,27 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
13251325
inJsx = !inJsxContext;
13261326
}))
13271327
| None -> ())
1328-
| Pexp_apply {funct = {pexp_desc = Pexp_ident compName}; args}
1329-
when Res_parsetree_viewer.is_jsx_expression expr ->
1328+
| Pexp_jsx_unary_element
1329+
{
1330+
jsx_unary_element_tag_name = compName;
1331+
jsx_unary_element_props = props;
1332+
}
1333+
| Pexp_jsx_container_element
1334+
{
1335+
jsx_container_element_tag_name_start = compName;
1336+
jsx_container_element_props = props;
1337+
} ->
13301338
inJsxContext := true;
1331-
let jsxProps = CompletionJsx.extractJsxProps ~compName ~args in
1339+
let children =
1340+
match expr.pexp_desc with
1341+
| Pexp_jsx_container_element
1342+
{jsx_container_element_children = children} ->
1343+
children
1344+
| _ -> JSXChildrenItems []
1345+
in
1346+
let jsxProps =
1347+
CompletionJsx.extractJsxProps ~compName ~props ~children
1348+
in
13321349
let compNamePath = flattenLidCheckDot ~jsx:true compName in
13331350
if debug then
13341351
Printf.printf "JSX <%s:%s %s> _children:%s\n"

analysis/src/CompletionJsx.ml

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -455,40 +455,39 @@ let findJsxPropsCompletable ~jsxProps ~endPos ~posBeforeCursor
455455
in
456456
loop jsxProps.props
457457

458-
let extractJsxProps ~(compName : Longident.t Location.loc) ~args =
459-
let thisCaseShouldNotHappen =
460-
{
461-
compName = Location.mknoloc (Longident.Lident "");
462-
props = [];
463-
childrenStart = None;
464-
}
458+
let extractJsxProps ~(compName : Longident.t Location.loc) ~props ~children =
459+
let open Parsetree in
460+
let childrenStart =
461+
match children with
462+
| JSXChildrenItems [] -> None
463+
| JSXChildrenSpreading child | JSXChildrenItems (child :: _) ->
464+
if child.pexp_loc.loc_ghost then None else Some (Loc.start child.pexp_loc)
465465
in
466-
let rec processProps ~acc args =
467-
match args with
468-
| (Asttypes.Labelled {txt = "children"}, {Parsetree.pexp_loc}) :: _ ->
469-
{
470-
compName;
471-
props = List.rev acc;
472-
childrenStart =
473-
(if pexp_loc.loc_ghost then None else Some (Loc.start pexp_loc));
474-
}
475-
| ( (Labelled {txt = s; loc} | Optional {txt = s; loc}),
476-
(eProp : Parsetree.expression) )
477-
:: rest -> (
478-
let namedArgLoc = if loc = Location.none then None else Some loc in
479-
match namedArgLoc with
480-
| Some loc ->
481-
processProps
482-
~acc:
483-
({
484-
name = s;
485-
posStart = Loc.start loc;
486-
posEnd = Loc.end_ loc;
487-
exp = eProp;
488-
}
489-
:: acc)
490-
rest
491-
| None -> processProps ~acc rest)
492-
| _ -> thisCaseShouldNotHappen
466+
let props =
467+
props
468+
|> List.map (function
469+
| JSXPropPunning (_, name) ->
470+
{
471+
name = name.txt;
472+
posStart = Loc.start name.loc;
473+
posEnd = Loc.end_ name.loc;
474+
exp =
475+
Ast_helper.Exp.ident
476+
{txt = Longident.Lident name.txt; loc = name.loc};
477+
}
478+
| JSXPropValue (name, _, value) ->
479+
{
480+
name = name.txt;
481+
posStart = Loc.start name.loc;
482+
posEnd = Loc.end_ name.loc;
483+
exp = value;
484+
}
485+
| JSXPropSpreading (loc, expr) ->
486+
{
487+
name = "_spreadProps";
488+
posStart = Loc.start loc;
489+
posEnd = Loc.end_ loc;
490+
exp = expr;
491+
})
493492
in
494-
args |> processProps ~acc:[]
493+
{compName; props; childrenStart}

analysis/src/Utils.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ let identifyPexp pexp =
112112
| Pexp_extension _ -> "Pexp_extension"
113113
| Pexp_open _ -> "Pexp_open"
114114
| Pexp_jsx_fragment _ -> "Pexp_jsx_fragment"
115+
| Pexp_jsx_unary_element _ -> "Pexp_jsx_unary_element"
116+
| Pexp_jsx_container_element _ -> "Pexp_jsx_container_element"
115117

116118
let identifyPpat pat =
117119
match pat with

compiler/syntax/src/res_core.ml

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ module InExternal = struct
145145
let status = ref false
146146
end
147147

148-
(* let jsx_attr = (Location.mknoloc "JSX", Parsetree.PStr []) *)
149148
let ternary_attr = (Location.mknoloc "res.ternary", Parsetree.PStr [])
150149
let if_let_attr = (Location.mknoloc "res.iflet", Parsetree.PStr [])
151150
let make_await_attr loc = (Location.mkloc "res.await" loc, Parsetree.PStr [])
@@ -2598,11 +2597,7 @@ and parse_jsx_opening_or_self_closing_element ~start_pos p :
25982597
Parser.expect GreaterThan p;
25992598
let loc = mk_loc jsx_start_pos p.Parser.start_pos in
26002599
(* Ast_helper.Exp.make_list_expression loc [] None no children *)
2601-
let desc =
2602-
Parsetree.Pexp_jsx_unary_element
2603-
{jsx_unary_element_tag_name = name; jsx_unary_element_props = jsx_props}
2604-
in
2605-
{pexp_desc = desc; pexp_loc = loc; pexp_attributes = []}
2600+
Ast_helper.Exp.jsx_unary_element ~loc name jsx_props
26062601
| GreaterThan -> (
26072602
(* <foo a=b> bar </foo> *)
26082603
(* let children_start_pos = p.Parser.start_pos in *)
@@ -2623,15 +2618,7 @@ and parse_jsx_opening_or_self_closing_element ~start_pos p :
26232618
Scanner.pop_mode p.scanner Jsx;
26242619
Parser.expect GreaterThan p;
26252620
let loc = mk_loc jsx_start_pos p.Parser.start_pos in
2626-
let desc =
2627-
Parsetree.Pexp_jsx_container_element
2628-
{
2629-
jsx_container_element_tag_name_start = name;
2630-
jsx_container_element_props = jsx_props;
2631-
jsx_container_element_children = children;
2632-
}
2633-
in
2634-
{pexp_desc = desc; pexp_loc = loc; pexp_attributes = []}
2621+
Ast_helper.Exp.jsx_container_element ~loc name jsx_props children
26352622
(* let loc = mk_loc children_start_pos children_end_pos in
26362623
match (spread, children) with
26372624
| true, child :: _ -> child
@@ -2653,12 +2640,17 @@ and parse_jsx_opening_or_self_closing_element ~start_pos p :
26532640
(Diagnostics.message msg);
26542641
Parser.expect GreaterThan p
26552642
in
2656-
Ast_helper.Exp.make_list_expression (mk_loc p.start_pos p.end_pos) [] None
2643+
Ast_helper.Exp.jsx_container_element
2644+
~loc:(mk_loc jsx_start_pos p.end_pos)
2645+
name jsx_props children
2646+
(* Ast_helper.Exp.make_list_expression (mk_loc p.start_pos p.end_pos) [] None *)
26572647
)
26582648
| token ->
26592649
Scanner.pop_mode p.scanner Jsx;
26602650
Parser.err p (Diagnostics.unexpected token p.breadcrumbs);
2661-
Ast_helper.Exp.make_list_expression Location.none [] None
2651+
Ast_helper.Exp.jsx_unary_element
2652+
~loc:(mk_loc jsx_start_pos p.end_pos)
2653+
name jsx_props
26622654

26632655
(* and parse_jsx_opening_or_self_closing_element_old ~start_pos p =
26642656
let jsx_start_pos = p.Parser.start_pos in

compiler/syntax/src/res_parsetree_viewer.ml

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -485,26 +485,12 @@ let filter_fragile_match_attributes attrs =
485485
attrs
486486

487487
let is_jsx_expression expr =
488-
let rec loop attrs =
489-
match attrs with
490-
| [] -> false
491-
| ({Location.txt = "JSX"}, _) :: _ -> true
492-
| _ :: attrs -> loop attrs
493-
in
494488
match expr.pexp_desc with
495-
| Pexp_jsx_fragment _ -> true
496-
| Pexp_apply _ -> loop expr.Parsetree.pexp_attributes
489+
| Pexp_jsx_fragment _ | Pexp_jsx_unary_element _
490+
| Pexp_jsx_container_element _ ->
491+
true
497492
| _ -> false
498493

499-
let has_jsx_attribute attributes =
500-
let rec loop attrs =
501-
match attrs with
502-
| [] -> false
503-
| ({Location.txt = "JSX"}, _) :: _ -> true
504-
| _ :: attrs -> loop attrs
505-
in
506-
loop attributes
507-
508494
let should_indent_binary_expr expr =
509495
let same_precedence_sub_expression operator sub_expression =
510496
match sub_expression with

compiler/syntax/src/res_parsetree_viewer.mli

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ val filter_fragile_match_attributes :
8888
Parsetree.attributes -> Parsetree.attributes
8989

9090
val is_jsx_expression : Parsetree.expression -> bool
91-
val has_jsx_attribute : Parsetree.attributes -> bool
9291

9392
val should_indent_binary_expr : Parsetree.expression -> bool
9493
val should_inline_rhs_binary_expr : Parsetree.expression -> bool

compiler/syntax/src/res_printer.ml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3420,9 +3420,8 @@ and print_expression ~state (e : Parsetree.expression) cmt_tbl =
34203420
| Pexp_ifthenelse _ ->
34213421
true
34223422
| Pexp_match _ when ParsetreeViewer.is_if_let_expr e -> true
3423-
| Pexp_jsx_fragment _ -> true
3424-
| Pexp_construct _ when ParsetreeViewer.has_jsx_attribute e.pexp_attributes
3425-
->
3423+
| Pexp_jsx_fragment _ | Pexp_jsx_unary_element _
3424+
| Pexp_jsx_container_element _ ->
34263425
true
34273426
| _ -> false
34283427
in

0 commit comments

Comments
 (0)