From f56621ffc55d2b442da74a70db1d48a2532f3ed2 Mon Sep 17 00:00:00 2001 From: Anthony Leonardo Gracio Date: Wed, 17 Jul 2024 12:34:51 +0000 Subject: [PATCH] Add defensive code when computing tooltip text In particular we should not even try to compute the variables' declarations if the root project could not be parsed. Add automatic test for this. For eng/ide/gnatstudio#345 --- source/gpr/lsp-gpr_documents.adb | 11 +- source/gpr/lsp-gpr_documents.ads | 3 +- source/gpr/lsp-gpr_handlers.adb | 5 +- .../prj1.gpr | 9 + .../prj3.gpr | 16 ++ .../test.json | 168 ++++++++++++++++++ .../test.yaml | 3 + 7 files changed, 205 insertions(+), 10 deletions(-) create mode 100644 testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/prj1.gpr create mode 100644 testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/prj3.gpr create mode 100644 testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/test.json create mode 100644 testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/test.yaml diff --git a/source/gpr/lsp-gpr_documents.adb b/source/gpr/lsp-gpr_documents.adb index 9106c8ea9..2e5ad097e 100644 --- a/source/gpr/lsp-gpr_documents.adb +++ b/source/gpr/lsp-gpr_documents.adb @@ -123,10 +123,11 @@ package body LSP.GPR_Documents is ---------------- function Has_Errors - (Self : Document) + (Self : Document) return Boolean is begin - return Self.Tree.Log_Messages.Has_Error; + return Self.Tree.Log_Messages.Has_Error + or else not Self.Tree.Root_Project.Is_Defined; end Has_Errors; ---------------- @@ -300,7 +301,7 @@ package body LSP.GPR_Documents is begin if LSP.GPR_Files.References.Is_Variable_Reference (Reference) - and then not Self.Tree.Log_Messages.Has_Error + and then not Self.Has_Errors then declare File : constant LSP.GPR_Files.File_Access := @@ -373,7 +374,7 @@ package body LSP.GPR_Documents is begin if LSP.GPR_Files.References.Is_Attribute_Reference (Reference) - and then not Self.Tree.Log_Messages.Has_Error + and then not Self.Has_Errors then declare File : constant LSP.GPR_Files.File_Access := @@ -446,7 +447,7 @@ package body LSP.GPR_Documents is begin if LSP.GPR_Files.References.Is_Type_Reference (Reference) - and then not Self.Tree.Log_Messages.Has_Error + and then not Self.Has_Errors then declare File : constant LSP.GPR_Files.File_Access := diff --git a/source/gpr/lsp-gpr_documents.ads b/source/gpr/lsp-gpr_documents.ads index efc249856..f95e276c0 100644 --- a/source/gpr/lsp-gpr_documents.ads +++ b/source/gpr/lsp-gpr_documents.ads @@ -103,7 +103,8 @@ package LSP.GPR_Documents is function Has_Errors (Self : Document) return Boolean; - -- Returns True when errors found during document parsing. + -- Returns True when errors found during document parsing or if + -- the tree could not be parsed properly (no defined root project). ----------------------- -- Document_Provider -- diff --git a/source/gpr/lsp-gpr_handlers.adb b/source/gpr/lsp-gpr_handlers.adb index 554420b1c..0e5244601 100644 --- a/source/gpr/lsp-gpr_handlers.adb +++ b/source/gpr/lsp-gpr_handlers.adb @@ -302,7 +302,6 @@ package body LSP.GPR_Handlers is Documentation_Text : VSS.Strings.Virtual_String; Location_Text : VSS.Strings.Virtual_String; begin - LSP.GPR_Documentation.Get_Tooltip_Text (Self => File, URI => Value.textDocument.uri, @@ -620,9 +619,7 @@ package body LSP.GPR_Handlers is declare Message : constant VSS.Strings.Virtual_String := VSS.Strings.Conversions.To_Virtual_String - ("Exception: " & - Ada.Exceptions.Exception_Name (E) & " (" & - Ada.Exceptions.Exception_Message (E) & ")"); + ("Exception: " & Ada.Exceptions.Exception_Information (E)); begin Self.Tracer.Trace_Exception (E, "On_Server_Request"); diff --git a/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/prj1.gpr b/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/prj1.gpr new file mode 100644 index 000000000..92f7e97d2 --- /dev/null +++ b/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/prj1.gpr @@ -0,0 +1,9 @@ +project Prj1 is +for Source_Dirs use ("src"); +package Compiler is +for Switches ("Ada") use (); +end Compiler; +package IDE is +for Artifacts_Dir use ""; +end IDE; +end Prj1; diff --git a/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/prj3.gpr b/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/prj3.gpr new file mode 100644 index 000000000..96c9db566 --- /dev/null +++ b/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/prj3.gpr @@ -0,0 +1,16 @@ +with "unknown"; +project Prj3 is + type T is ("project.Var value "); + Var : T := "project.Var value "; + package Builder is + Var := "project.Builder.Var value "; + for Global_Configuration_Pragmas use "project.Builder'Global_Configuration_Pragmas value "; + end Builder; + Var1 := Var & project.Var & project.Builder.Var & project'Name & Prj3'Name & Prj3.Builder'Global_Configuration_Pragmas; + package Compiler is + for Switches ("main.adb") use ("value1"); + for Switches ("main.adb" at 1) use ("value2"); + for Switches (others) use ("value3"); + Var := Compiler'Switches ("main.adb") & Compiler'Switches (others); + end Compiler; +end Prj3; diff --git a/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/test.json b/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/test.json new file mode 100644 index 000000000..78f11c623 --- /dev/null +++ b/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/test.json @@ -0,0 +1,168 @@ +[ + { + "comment": [ + "Check that we don't get any exception when computing variables'", + "tooltips on non-valid projects" + ] + }, + { + "start": { + "cmd": ["${ALS}", "--language-gpr"] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": "init", + "method": "initialize", + "params": { + "processId": 441587, + "rootUri": "$URI{.}", + "capabilities": { + "workspace": { + "applyEdit": true, + "workspaceEdit": {}, + "didChangeConfiguration": {}, + "didChangeWatchedFiles": {}, + "executeCommand": {} + }, + "textDocument": { + "synchronization": {}, + "completion": { + "dynamicRegistration": true, + "completionItem": { + "snippetSupport": true, + "documentationFormat": ["plaintext", "markdown"] + } + }, + "hover": {}, + "signatureHelp": {}, + "declaration": {}, + "definition": {}, + "typeDefinition": {}, + "implementation": {}, + "references": {}, + "documentHighlight": {}, + "documentSymbol": { + "hierarchicalDocumentSymbolSupport": true + }, + "codeLens": {}, + "colorProvider": {}, + "formatting": { + "dynamicRegistration": false + }, + "rangeFormatting": { + "dynamicRegistration": false + }, + "onTypeFormatting": { + "dynamicRegistration": false + }, + "foldingRange": { + "lineFoldingOnly": true + }, + "selectionRange": {}, + "linkedEditingRange": {}, + "callHierarchy": {}, + "moniker": {} + } + } + } + }, + "wait": [ + { + "jsonrpc": "2.0", + "id": "init", + "result": { + "capabilities": { + "textDocumentSync": { + "openClose": true, + "change": 1 + } + } + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "initialized" + }, + "wait": [] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "textDocument/didOpen", + "params": { + "textDocument": { + "uri": "$URI{prj3.gpr}", + "languageId": "Gpr", + "version": 1, + "text": "with \"unknown\";\nproject Prj3 is\n type T is (\"project.Var value \");\n Var : T := \"project.Var value \";\n package Builder is\n Var := \"project.Builder.Var value \";\n for Global_Configuration_Pragmas use \"project.Builder'Global_Configuration_Pragmas value \";\n end Builder;\n Var1 := Var & project.Var & project.Builder.Var & project'Name & Prj3'Name & Prj3.Builder'Global_Configuration_Pragmas;\n package Compiler is\n for Switches (\"main.adb\") use (\"value1\");\n for Switches (\"main.adb\" at 1) use (\"value2\");\n for Switches (others) use (\"value3\");\n Var := Compiler'Switches (\"main.adb\") & Compiler'Switches (others);\n end Compiler;\nend Prj3;\n" + } + } + }, + "wait": [] + } + }, + { + "send": { + "request": { + "params": { + "position": { + "line": 3, + "character": 3 + }, + "textDocument": { + "uri": "$URI{prj3.gpr}" + } + }, + "jsonrpc": "2.0", + "id": 9, + "method": "textDocument/hover" + }, + "wait": [ + { + "id": 9, + "result": null + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": "shutdown", + "method": "shutdown", + "params": null + }, + "wait": [ + { + "id": "shutdown", + "result": null + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "exit" + }, + "wait": [] + } + }, + { + "stop": { + "exit_code": 0 + } + } +] diff --git a/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/test.yaml b/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/test.yaml new file mode 100644 index 000000000..caff4e308 --- /dev/null +++ b/testsuite/gpr_lsp/hover.no_exception_when_failed_to_load/test.yaml @@ -0,0 +1,3 @@ +title: 'hover.no_exception_when_failed_to_load' +skip: + - ['SKIP', 'env.build.os.name not in ("linux","windows")']