From 231ceb2784cc9bddd648ea46237ef005a08fc19a Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Sun, 22 Jan 2023 09:53:44 +0100 Subject: [PATCH 1/2] Test cases for exotic identifiers --- analysis/tests/src/ExoticIdentifiers.res | 40 +++++++++++ .../src/expected/ExoticIdentifiers.res.txt | 71 +++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 analysis/tests/src/ExoticIdentifiers.res create mode 100644 analysis/tests/src/expected/ExoticIdentifiers.res.txt diff --git a/analysis/tests/src/ExoticIdentifiers.res b/analysis/tests/src/ExoticIdentifiers.res new file mode 100644 index 000000000..2cf1a55a5 --- /dev/null +++ b/analysis/tests/src/ExoticIdentifiers.res @@ -0,0 +1,40 @@ +module X = { + // ^hov + let \"Foo" = "foo" +} + +// let foo = X. +// ^com + +module type Y = { + // ^hov + let \"Foo": string +} + +type x = {\"Foo": string} +// ^hov + +let f = (x: x) => { + // let {} = x + // ^com + ignore(x) +} + +let g = (~\"Foo") => \"Foo" +// ^hov + +// g(~) +// ^com + +module C = { + // ^hov + @react.component + let make = (~\"Foo": option=?) => + switch \"Foo" { + | Some(foo) => React.string(foo) + | None => React.null + } +} + +let _ = +// ^com diff --git a/analysis/tests/src/expected/ExoticIdentifiers.res.txt b/analysis/tests/src/expected/ExoticIdentifiers.res.txt new file mode 100644 index 000000000..4f97fa009 --- /dev/null +++ b/analysis/tests/src/expected/ExoticIdentifiers.res.txt @@ -0,0 +1,71 @@ +Hover src/ExoticIdentifiers.res 0:7 +{"contents": {"kind": "markdown", "value": "```rescript\nmodule X: {\n let Foo: string\n}\n```"}} + +Complete src/ExoticIdentifiers.res 5:15 +posCursor:[5:15] posNoWhite:[5:14] Found expr:[5:13->5:15] +Pexp_ident X.:[5:13->5:15] +Completable: Cpath Value[X, ""] +[{ + "label": "Foo", + "kind": 12, + "tags": [], + "detail": "string", + "documentation": null + }] + +Hover src/ExoticIdentifiers.res 8:12 +{"contents": {"kind": "markdown", "value": "```rescript\nmodule type Y = {\n let Foo: string\n}\n```"}} + +Hover src/ExoticIdentifiers.res 13:5 +{"contents": {"kind": "markdown", "value": "```rescript\ntype x = {\\\"Foo\": string}\n```"}} + +Complete src/ExoticIdentifiers.res 17:10 +posCursor:[17:10] posNoWhite:[17:9] Found expr:[16:8->20:1] +posCursor:[17:10] posNoWhite:[17:9] Found expr:[17:5->19:11] +posCursor:[17:10] posNoWhite:[17:9] Found pattern:[17:9->17:11] +Completable: Cpattern Value[x]->recordBody +[{ + "label": "Foo", + "kind": 5, + "tags": [], + "detail": "Foo: string\n\nx", + "documentation": null + }] + +Hover src/ExoticIdentifiers.res 22:4 +{"contents": {"kind": "markdown", "value": "```rescript\n(~Foo: 'a) => 'a\n```"}} + +Complete src/ExoticIdentifiers.res 25:6 +posCursor:[25:6] posNoWhite:[25:5] Found expr:[25:3->25:7] +Pexp_apply ...[25:3->25:4] () +Completable: CnamedArg(Value[g], "", []) +Found type for function (~Foo: 'a) => 'a +[{ + "label": "Foo", + "kind": 4, + "tags": [], + "detail": "'a", + "documentation": null + }] + +Hover src/ExoticIdentifiers.res 28:7 +{"contents": {"kind": "markdown", "value": "```rescript\nmodule C: {\n let makeProps: (\n ~Foo: string=?,\n ~key: string=?,\n unit,\n) => {\"Foo\": option}\n let make: {\"Foo\": option} => React.element\n}\n```"}} + +Complete src/ExoticIdentifiers.res 38:11 +posCursor:[38:11] posNoWhite:[38:9] Found expr:[38:9->38:13] +JSX 38:10] > _children:38:11 +Completable: Cjsx([C], "", []) +[{ + "label": "Foo", + "kind": 4, + "tags": [], + "detail": "option", + "documentation": null + }, { + "label": "key", + "kind": 4, + "tags": [], + "detail": "string", + "documentation": null + }] + From c1d16dba0a07fd6f5db8e8e39ab0baf14f2abe31 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Sun, 22 Jan 2023 09:54:49 +0100 Subject: [PATCH 2/2] Some fixes --- analysis/src/CompletionBackEnd.ml | 8 +++++++- analysis/src/Hover.ml | 5 ++++- analysis/src/PrintType.ml | 4 ++++ analysis/src/SharedTypes.ml | 8 ++++++-- .../tests/src/expected/ExoticIdentifiers.res.txt | 12 ++++++------ .../res_outcome_printer/res_outcome_printer.mli | 2 ++ 6 files changed, 29 insertions(+), 10 deletions(-) diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index f503721cb..72916a48d 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -1090,7 +1090,10 @@ let rec completeTypedValue (t : SharedTypes.completionType) ~env ~full ~prefix |> List.filter (fun (field : field) -> List.mem field.fname.txt seenFields = false) |> List.map (fun (field : field) -> - Completion.create field.fname.txt + let fname = + PrintType.printIdentLike ~allowUident:false field.fname.txt + in + Completion.create fname ~kind:(Field (field, typeExpr |> Shared.typeToString)) ~env) |> filterItems ~prefix @@ -1214,6 +1217,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover | Cjsx ([id], prefix, identsSeen) when String.uncapitalize_ascii id = id -> (* Lowercase JSX tag means builtin *) let mkLabel (name, typString) = + let name = PrintType.printIdentLike ~allowUident:false name in Completion.create name ~kind:(Label typString) ~env in let keyLabels = @@ -1230,6 +1234,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover CompletionJsx.getJsxLabels ~componentPath ~findTypeOfValue ~package in let mkLabel_ name typString = + let name = PrintType.printIdentLike ~allowUident:false name in Completion.create name ~kind:(Label typString) ~env in let mkLabel (name, typ, _env) = @@ -1286,6 +1291,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover | None -> [] in let mkLabel (name, typ) = + let name = PrintType.printIdentLike ~allowUident:false name in Completion.create name ~kind:(Label (typ |> Shared.typeToString)) ~env in labels diff --git a/analysis/src/Hover.ml b/analysis/src/Hover.ml index 307f6155a..d0f4d7c34 100644 --- a/analysis/src/Hover.ml +++ b/analysis/src/Hover.ml @@ -10,7 +10,10 @@ let showModuleTopLevel ~docstring ~isType ~name (topLevel : Module.item list) = " " ^ (decl |> Shared.declToString ~recStatus item.name) | Module _ -> " module " ^ item.name | Value typ -> - " let " ^ item.name ^ ": " ^ (typ |> Shared.typeToString)) + " let " + ^ PrintType.printIdentLike ~allowUident:false item.name + ^ ": " + ^ (typ |> Shared.typeToString)) (* TODO indent *) |> String.concat "\n" in diff --git a/analysis/src/PrintType.ml b/analysis/src/PrintType.ml index f06239f60..2e1877f33 100644 --- a/analysis/src/PrintType.ml +++ b/analysis/src/PrintType.ml @@ -8,3 +8,7 @@ let printDecl ?printNameAsIs ~recStatus name decl = Res_doc.toString ~width:60 (Res_outcome_printer.printOutSigItemDoc ?printNameAsIs (Printtyp.tree_of_type_declaration (Ident.create name) decl recStatus)) + +let printIdentLike ~allowUident name = + Res_doc.toString ~width:60 + (Res_outcome_printer.printIdentLike ~allowUident name) diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index 638246fb4..bd3316d03 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -692,8 +692,12 @@ module Completable = struct ^ (match argumentLabel with | Unlabelled {argumentPosition} -> "$" ^ string_of_int argumentPosition - | Labelled name -> "~" ^ name - | Optional name -> "~" ^ name ^ "=?") + | Labelled name -> + let name = PrintType.printIdentLike ~allowUident:false name in + "~" ^ name + | Optional name -> + let name = PrintType.printIdentLike ~allowUident:false name in + "~" ^ name ^ "= ?") ^ ")" | CJsxPropValue {pathToComponent; propName} -> "CJsxPropValue " ^ (pathToComponent |> list) ^ " " ^ propName diff --git a/analysis/tests/src/expected/ExoticIdentifiers.res.txt b/analysis/tests/src/expected/ExoticIdentifiers.res.txt index 4f97fa009..885fdd202 100644 --- a/analysis/tests/src/expected/ExoticIdentifiers.res.txt +++ b/analysis/tests/src/expected/ExoticIdentifiers.res.txt @@ -1,5 +1,5 @@ Hover src/ExoticIdentifiers.res 0:7 -{"contents": {"kind": "markdown", "value": "```rescript\nmodule X: {\n let Foo: string\n}\n```"}} +{"contents": {"kind": "markdown", "value": "```rescript\nmodule X: {\n let \\\"Foo\": string\n}\n```"}} Complete src/ExoticIdentifiers.res 5:15 posCursor:[5:15] posNoWhite:[5:14] Found expr:[5:13->5:15] @@ -14,7 +14,7 @@ Completable: Cpath Value[X, ""] }] Hover src/ExoticIdentifiers.res 8:12 -{"contents": {"kind": "markdown", "value": "```rescript\nmodule type Y = {\n let Foo: string\n}\n```"}} +{"contents": {"kind": "markdown", "value": "```rescript\nmodule type Y = {\n let \\\"Foo\": string\n}\n```"}} Hover src/ExoticIdentifiers.res 13:5 {"contents": {"kind": "markdown", "value": "```rescript\ntype x = {\\\"Foo\": string}\n```"}} @@ -25,10 +25,10 @@ posCursor:[17:10] posNoWhite:[17:9] Found expr:[17:5->19:11] posCursor:[17:10] posNoWhite:[17:9] Found pattern:[17:9->17:11] Completable: Cpattern Value[x]->recordBody [{ - "label": "Foo", + "label": "\\\"Foo\"", "kind": 5, "tags": [], - "detail": "Foo: string\n\nx", + "detail": "\\\"Foo\": string\n\nx", "documentation": null }] @@ -41,7 +41,7 @@ Pexp_apply ...[25:3->25:4] () Completable: CnamedArg(Value[g], "", []) Found type for function (~Foo: 'a) => 'a [{ - "label": "Foo", + "label": "\\\"Foo\"", "kind": 4, "tags": [], "detail": "'a", @@ -56,7 +56,7 @@ posCursor:[38:11] posNoWhite:[38:9] Found expr:[38:9->38:13] JSX 38:10] > _children:38:11 Completable: Cjsx([C], "", []) [{ - "label": "Foo", + "label": "\\\"Foo\"", "kind": 4, "tags": [], "detail": "option", diff --git a/analysis/vendor/res_outcome_printer/res_outcome_printer.mli b/analysis/vendor/res_outcome_printer/res_outcome_printer.mli index d3ee60aa4..7292054f2 100644 --- a/analysis/vendor/res_outcome_printer/res_outcome_printer.mli +++ b/analysis/vendor/res_outcome_printer/res_outcome_printer.mli @@ -12,6 +12,8 @@ val parenthesized_ident : string -> bool [@@live] val setup : unit lazy_t [@@live] (* Needed for e.g. the playground to print typedtree data *) +val printIdentLike : allowUident:bool -> string -> Res_doc.t + val printOutTypeDoc : Outcometree.out_type -> Res_doc.t [@@live] val printOutSigItemDoc : ?printNameAsIs:bool -> Outcometree.out_sig_item -> Res_doc.t