From 29968adf2604d6af996beece1e9913eb194f5dbd Mon Sep 17 00:00:00 2001 From: Amirali Esmaeili Date: Thu, 10 Jun 2021 23:12:57 +0430 Subject: [PATCH 1/2] Add type def tests --- analysis/tests/src/Cross.res | 4 ++++ analysis/tests/src/TypeDefinition.res | 24 +++++++++++++++++++ analysis/tests/src/expected/Cross.res.txt | 3 +++ .../tests/src/expected/TypeDefinition.res.txt | 15 ++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 analysis/tests/src/TypeDefinition.res create mode 100644 analysis/tests/src/expected/TypeDefinition.res.txt diff --git a/analysis/tests/src/Cross.res b/analysis/tests/src/Cross.res index c4fc51baf..9f13df4ee 100644 --- a/analysis/tests/src/Cross.res +++ b/analysis/tests/src/Cross.res @@ -24,3 +24,7 @@ let _ = RenameWithInterface.x let _ = RenameWithInterface.x // ^ren xPrime + + +let typeDef = {TypeDefinition.item: "foobar"} +// ^typ diff --git a/analysis/tests/src/TypeDefinition.res b/analysis/tests/src/TypeDefinition.res new file mode 100644 index 000000000..60c740aa9 --- /dev/null +++ b/analysis/tests/src/TypeDefinition.res @@ -0,0 +1,24 @@ +type variant = Foo | Bar + +type record = {item: string} + +let x = Foo +// ^typ + +let y = {item: "foo"} +// ^typ + +type obj = {"foo": string} + +let obj: obj = {"foo": "bar"} +// ^type + +let f = r => r.item +// ^typ + +let g = v => + switch v { + // ^typ + | Foo => "Foo" + | Bar => "Bar" + } diff --git a/analysis/tests/src/expected/Cross.res.txt b/analysis/tests/src/expected/Cross.res.txt index 6f3461a8b..67a50b2b8 100644 --- a/analysis/tests/src/expected/Cross.res.txt +++ b/analysis/tests/src/expected/Cross.res.txt @@ -81,3 +81,6 @@ Rename tests/src/Cross.res 24:28 xPrime } ] +TypeDefinition tests/src/Cross.res 28:5 +{"uri": "TypeDefinition.res", "range": {"start": {"line": 2, "character": 0}, "end": {"line": 2, "character": 28}}} + diff --git a/analysis/tests/src/expected/TypeDefinition.res.txt b/analysis/tests/src/expected/TypeDefinition.res.txt new file mode 100644 index 000000000..153209db5 --- /dev/null +++ b/analysis/tests/src/expected/TypeDefinition.res.txt @@ -0,0 +1,15 @@ +TypeDefinition tests/src/TypeDefinition.res 4:4 +{"uri": "TypeDefinition.res", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 24}}} + +TypeDefinition tests/src/TypeDefinition.res 7:4 +{"uri": "TypeDefinition.res", "range": {"start": {"line": 2, "character": 0}, "end": {"line": 2, "character": 28}}} + +TypeDefinition tests/src/TypeDefinition.res 12:4 +{"uri": "TypeDefinition.res", "range": {"start": {"line": 10, "character": 0}, "end": {"line": 10, "character": 26}}} + +TypeDefinition tests/src/TypeDefinition.res 15:13 +{"uri": "TypeDefinition.res", "range": {"start": {"line": 2, "character": 0}, "end": {"line": 2, "character": 28}}} + +TypeDefinition tests/src/TypeDefinition.res 19:9 +{"uri": "TypeDefinition.res", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 24}}} + From 6a87078ff5a2c8e8c7ccc31b358736a081386ff8 Mon Sep 17 00:00:00 2001 From: Amirali Esmaeili Date: Thu, 10 Jun 2021 23:14:57 +0430 Subject: [PATCH 2/2] Add type definition provider --- analysis/.depend | 125 ++++++++++++++++++++++++++++--------- analysis/src/Cli.ml | 8 +++ analysis/src/Commands.ml | 25 ++++++++ analysis/src/References.ml | 23 +++++++ server/src/server.ts | 15 +++++ 5 files changed, 167 insertions(+), 29 deletions(-) diff --git a/analysis/.depend b/analysis/.depend index b1e57ed8a..23cbab5d7 100644 --- a/analysis/.depend +++ b/analysis/.depend @@ -1,39 +1,106 @@ -src/BuildSystem.cmx : src/ModuleResolution.cmx src/Log.cmx src/Files.cmx -src/Cli.cmx : src/Commands.cmx -src/Cmt.cmx : src/Utils.cmx src/Uri2.cmx src/SharedTypes.cmx \ - src/ProcessCmt.cmx src/Packages.cmx src/FindFiles.cmx src/BuildSystem.cmx -src/Commands.cmx : src/Utils.cmx src/Uri2.cmx src/SharedTypes.cmx \ - src/Shared.cmx src/References.cmx src/Protocol.cmx src/NewCompletions.cmx \ - src/Hover.cmx src/Files.cmx src/Cmt.cmx +src/BuildSystem.cmx : \ + src/ModuleResolution.cmx \ + src/Log.cmx \ + src/Files.cmx +src/Cli.cmx : \ + src/Commands.cmx +src/Cmt.cmx : \ + src/Utils.cmx \ + src/Uri2.cmx \ + src/SharedTypes.cmx \ + src/ProcessCmt.cmx \ + src/Packages.cmx \ + src/FindFiles.cmx \ + src/BuildSystem.cmx +src/Commands.cmx : \ + src/Utils.cmx \ + src/Uri2.cmx \ + src/SharedTypes.cmx \ + src/Shared.cmx \ + src/References.cmx \ + src/Protocol.cmx \ + src/NewCompletions.cmx \ + src/Hover.cmx \ + src/Files.cmx \ + src/Cmt.cmx src/Files.cmx : -src/FindFiles.cmx : src/Utils.cmx src/SharedTypes.cmx \ - src/ModuleResolution.cmx src/Log.cmx src/vendor/Json.cmx src/Infix.cmx \ - src/Files.cmx src/BuildSystem.cmx -src/Hover.cmx : src/Utils.cmx src/SharedTypes.cmx src/Shared.cmx \ - src/References.cmx src/ProcessCmt.cmx +src/FindFiles.cmx : \ + src/Utils.cmx \ + src/SharedTypes.cmx \ + src/ModuleResolution.cmx \ + src/Log.cmx \ + src/vendor/Json.cmx \ + src/Infix.cmx \ + src/Files.cmx \ + src/BuildSystem.cmx +src/Hover.cmx : \ + src/Utils.cmx \ + src/SharedTypes.cmx \ + src/Shared.cmx \ + src/References.cmx \ + src/ProcessCmt.cmx src/Infix.cmx : src/Log.cmx : -src/ModuleResolution.cmx : src/Files.cmx -src/NewCompletions.cmx : src/Utils.cmx src/Uri2.cmx src/SharedTypes.cmx \ - src/Shared.cmx src/Protocol.cmx src/ProcessCmt.cmx src/PartialParser.cmx \ - src/Log.cmx src/Hover.cmx -src/Packages.cmx : src/Uri2.cmx src/SharedTypes.cmx src/Log.cmx \ - src/vendor/Json.cmx src/Infix.cmx src/FindFiles.cmx src/Files.cmx \ +src/ModuleResolution.cmx : \ + src/Files.cmx +src/NewCompletions.cmx : \ + src/Utils.cmx \ + src/Uri2.cmx \ + src/SharedTypes.cmx \ + src/Shared.cmx \ + src/Protocol.cmx \ + src/ProcessCmt.cmx \ + src/PartialParser.cmx \ + src/Log.cmx \ + src/Hover.cmx +src/Packages.cmx : \ + src/Uri2.cmx \ + src/SharedTypes.cmx \ + src/Log.cmx \ + src/vendor/Json.cmx \ + src/Infix.cmx \ + src/FindFiles.cmx \ + src/Files.cmx \ src/BuildSystem.cmx -src/PartialParser.cmx : src/SharedTypes.cmx +src/PartialParser.cmx : \ + src/SharedTypes.cmx src/PrepareUtils.cmx : -src/PrintType.cmx : src/vendor/res_outcome_printer/res_outcome_printer.cmx \ +src/PrintType.cmx : \ + src/vendor/res_outcome_printer/res_outcome_printer.cmx \ src/vendor/res_outcome_printer/res_doc.cmx -src/ProcessAttributes.cmx : src/SharedTypes.cmx src/PrepareUtils.cmx -src/ProcessCmt.cmx : src/Utils.cmx src/Uri2.cmx src/SharedTypes.cmx \ - src/Shared.cmx src/ProcessAttributes.cmx src/Log.cmx src/Files.cmx -src/Protocol.cmx : src/vendor/Json.cmx -src/References.cmx : src/Utils.cmx src/Uri2.cmx src/SharedTypes.cmx \ - src/ProcessCmt.cmx src/Log.cmx src/Infix.cmx src/Cmt.cmx -src/Shared.cmx : src/PrintType.cmx src/Log.cmx src/Files.cmx -src/SharedTypes.cmx : src/Utils.cmx src/Uri2.cmx src/Shared.cmx +src/ProcessAttributes.cmx : \ + src/SharedTypes.cmx \ + src/PrepareUtils.cmx +src/ProcessCmt.cmx : \ + src/Utils.cmx \ + src/Uri2.cmx \ + src/SharedTypes.cmx \ + src/Shared.cmx \ + src/ProcessAttributes.cmx \ + src/Log.cmx \ + src/Files.cmx +src/Protocol.cmx : \ + src/vendor/Json.cmx +src/References.cmx : \ + src/Utils.cmx \ + src/Uri2.cmx \ + src/SharedTypes.cmx \ + src/Shared.cmx \ + src/ProcessCmt.cmx \ + src/Log.cmx \ + src/Infix.cmx \ + src/Cmt.cmx +src/Shared.cmx : \ + src/PrintType.cmx \ + src/Log.cmx \ + src/Files.cmx +src/SharedTypes.cmx : \ + src/Utils.cmx \ + src/Uri2.cmx \ + src/Shared.cmx src/Uri2.cmx : -src/Utils.cmx : src/Protocol.cmx +src/Utils.cmx : \ + src/Protocol.cmx src/vendor/Json.cmx : src/vendor/res_outcome_printer/res_comment.cmx : \ src/vendor/res_outcome_printer/res_comment.cmi diff --git a/analysis/src/Cli.ml b/analysis/src/Cli.ml index ce982dafc..357182596 100644 --- a/analysis/src/Cli.ml +++ b/analysis/src/Cli.ml @@ -5,6 +5,7 @@ let help = API examples: ./rescript-editor-analysis.exe completion src/MyFile.res 0 4 currentContent.res ./rescript-editor-analysis.exe definition src/MyFile.res 9 3 + ./rescript-editor-analysis.exe typeDefinition src/MyFile.res 9 3 ./rescript-editor-analysis.exe documentSymbol src/Foo.res ./rescript-editor-analysis.exe hover src/MyFile.res 10 2 ./rescript-editor-analysis.exe references src/MyFile.res 10 2 @@ -27,6 +28,10 @@ Options: ./rescript-editor-analysis.exe definition src/MyFile.res 10 2 + typeDefinition: get type definition for item in MyFile.res at line 10 column 2: + + ./rescript-editor-analysis.exe typeDefinition src/MyFile.res 10 2 + documentSymbol: get all symbols declared in MyFile.res ./rescript-editor-analysis.exe documentSymbol src/MyFile.res @@ -60,6 +65,9 @@ let main () = | [_; "definition"; path; line; col] -> Commands.definition ~path ~line:(int_of_string line) ~col:(int_of_string col) + | [_; "typeDefinition"; path; line; col] -> + Commands.typeDefinition ~path ~line:(int_of_string line) + ~col:(int_of_string col) | _ :: "dump" :: files -> Commands.dump files | [_; "documentSymbol"; path] -> Commands.documentSymbol ~path | [_; "hover"; path; line; col] -> diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index e2ab4225b..a1e87b22c 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -122,6 +122,26 @@ let definition ~path ~line ~col = | None -> Protocol.null | Some location -> location |> Protocol.stringifyLocation) +let typeDefinition ~path ~line ~col = + let maybeLocation = + match Cmt.fromPath ~path with + | None -> None + | Some full -> ( + match References.getLocItem ~full ~line ~col with + | None -> None + | Some locItem -> ( + match References.typeDefinitionForLocItem ~full locItem with + | None -> None + | Some (uri, loc) -> + Some + {Protocol.uri = Uri2.toString uri; range = Utils.cmtLocToRange loc}) + ) + in + print_endline + (match maybeLocation with + | None -> Protocol.null + | Some location -> location |> Protocol.stringifyLocation) + let references ~path ~line ~col = let allLocs = match Cmt.fromPath ~path with @@ -281,6 +301,11 @@ let test ~path = ("Definition " ^ path ^ " " ^ string_of_int line ^ ":" ^ string_of_int col); definition ~path ~line ~col + | "typ" -> + print_endline + ("TypeDefinition " ^ path ^ " " ^ string_of_int line ^ ":" + ^ string_of_int col); + typeDefinition ~path ~line ~col | "hov" -> print_endline ("Hover " ^ path ^ " " ^ string_of_int line ^ ":" diff --git a/analysis/src/References.ml b/analysis/src/References.ml index 6a58980fc..005b38e88 100644 --- a/analysis/src/References.ml +++ b/analysis/src/References.ml @@ -359,6 +359,29 @@ let definitionForLocItem ~full:{file; package} locItem = maybeLog ("Got stamp " ^ string_of_int stamp); definition ~file:env.file ~package stamp tip))) +let typeDefinitionForLocItem ~full:{file; package} locItem = + match locItem.locType with + | Constant _ | TopLevelModule _ | LModule _ | TypeDefinition _ -> None + | Typed (_, typ, _) -> ( + let env = SharedTypes.QueryEnv.fromFile file in + match Shared.digConstructor typ with + | None -> None + | Some path -> ( + match ProcessCmt.resolveFromCompilerPath ~env ~package path with + | `Not_found -> None + | `Stamp stamp -> ( + match Hashtbl.find_opt env.file.stamps.types stamp with + | None -> None + | Some declared -> Some (env.file.uri, declared.item.decl.type_loc)) + | `Exported (env, name) -> ( + match Hashtbl.find_opt env.exported.types name with + | None -> None + | Some stamp -> ( + match Hashtbl.find_opt env.file.stamps.types stamp with + | None -> None + | Some declared -> Some (env.file.uri, declared.item.decl.type_loc)))) + ) + let isVisible (declared : _ SharedTypes.declared) = declared.isExported && diff --git a/server/src/server.ts b/server/src/server.ts index cee0683bb..43e1074f3 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -265,6 +265,18 @@ function definition(msg: p.RequestMessage) { return response; } +function typeDefinition(msg: p.RequestMessage) { + // https://microsoft.github.io/language-server-protocol/specification/specification-current/#textDocument_typeDefinition + let params = msg.params as p.TypeDefinitionParams; + let filePath = fileURLToPath(params.textDocument.uri); + let response = utils.runAnalysisCommand( + filePath, + ["typeDefinition", filePath, params.position.line, params.position.character], + msg + ); + return response; +} + function references(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references let params = msg.params as p.ReferenceParams; @@ -620,6 +632,7 @@ function onMessage(msg: m.Message) { documentFormattingProvider: true, hoverProvider: true, definitionProvider: true, + typeDefinitionProvider: true, referencesProvider: true, renameProvider: { prepareProvider: true }, documentSymbolProvider: false, @@ -670,6 +683,8 @@ function onMessage(msg: m.Message) { send(hover(msg)); } else if (msg.method === p.DefinitionRequest.method) { send(definition(msg)); + } else if (msg.method === p.TypeDefinitionRequest.method) { + send(typeDefinition(msg)); } else if (msg.method === p.ReferencesRequest.method) { send(references(msg)); } else if (msg.method === p.PrepareRenameRequest.method) {