From 745e0eeacfc772c35905f034dde5b3351fbc987a Mon Sep 17 00:00:00 2001 From: Boulanger Date: Thu, 17 Oct 2024 16:29:47 +0200 Subject: [PATCH] Fix Goto Definition for entry in Protected Types Add a test. Closes eng/ide/ada_language_server#1437 --- source/ada/lsp-ada_definition.adb | 42 ++- .../show_protected_objects_entries.adb | 67 +++++ .../ada_lsp/definition_protected/test.gpr | 2 + .../ada_lsp/definition_protected/test.json | 263 ++++++++++++++++++ .../ada_lsp/definition_protected/test.yaml | 1 + 5 files changed, 364 insertions(+), 11 deletions(-) create mode 100644 testsuite/ada_lsp/definition_protected/show_protected_objects_entries.adb create mode 100644 testsuite/ada_lsp/definition_protected/test.gpr create mode 100644 testsuite/ada_lsp/definition_protected/test.json create mode 100644 testsuite/ada_lsp/definition_protected/test.yaml diff --git a/source/ada/lsp-ada_definition.adb b/source/ada/lsp-ada_definition.adb index 6a2eb94a..46f40105 100644 --- a/source/ada/lsp-ada_definition.adb +++ b/source/ada/lsp-ada_definition.adb @@ -122,7 +122,6 @@ package body LSP.Ada_Definition is Manual_Fallback : Libadalang.Analysis.Defining_Name; Definition_Node : Libadalang.Analysis.Basic_Decl; Decl_For_Find_Overrides : Libadalang.Analysis.Basic_Decl; - Entry_Decl_Node : Libadalang.Analysis.Entry_Decl; Ignore : Boolean; begin @@ -186,7 +185,37 @@ package body LSP.Ada_Definition is -- Search for accept statements only if we are on an entry if Definition_Node.Kind in Libadalang.Common.Ada_Entry_Decl_Range then - Entry_Decl_Node := Definition_Node.As_Entry_Decl; + declare + Entry_Decl_Node : constant Libadalang.Analysis.Entry_Decl := + Definition_Node.As_Entry_Decl; + Entry_Parent_Node : constant Libadalang.Analysis.Basic_Decl := + Entry_Decl_Node.P_Parent_Basic_Decl; + begin + -- P_Accept_Stmts is only valid for entries declared in tasks + if Entry_Parent_Node.Kind in + Libadalang.Common.Ada_Task_Type_Decl_Range + then + for Accept_Node of Entry_Decl_Node.P_Accept_Stmts loop + Self.Parent.Context.Append_Location + (Self.Response, + Self.Filter, + Accept_Node.F_Body_Decl.F_Name); + end loop; + + -- Others entries are are handled as simple subprograms + else + declare + Other_Part_For_Decl : constant + Libadalang.Analysis.Basic_Decl := + Laltools.Common.Find_Next_Part_For_Decl + (Definition_Node, Trace); + begin + if not Other_Part_For_Decl.Is_Null then + Other_Part := Other_Part_For_Decl.P_Defining_Name; + end if; + end; + end if; + end; elsif Definition_Node.Kind in Libadalang.Common.Ada_Single_Task_Type_Decl_Range | @@ -265,15 +294,6 @@ package body LSP.Ada_Definition is end loop; end; end if; - - if not Entry_Decl_Node.Is_Null then - for Accept_Node of Entry_Decl_Node.P_Accept_Stmts loop - Self.Parent.Context.Append_Location - (Self.Response, - Self.Filter, - Accept_Node.F_Body_Decl.F_Name); - end loop; - end if; end Execute_Ada_Request; end LSP.Ada_Definition; diff --git a/testsuite/ada_lsp/definition_protected/show_protected_objects_entries.adb b/testsuite/ada_lsp/definition_protected/show_protected_objects_entries.adb new file mode 100644 index 00000000..9bb2c6c8 --- /dev/null +++ b/testsuite/ada_lsp/definition_protected/show_protected_objects_entries.adb @@ -0,0 +1,67 @@ +with Ada.Text_IO; use Ada.Text_IO; + +procedure Show_Protected_Objects_Entries is + + protected Obj is + procedure Set (V : Integer); + entry Get (V : out Integer); + private + Local : Integer; + Is_Set : Boolean := False; + end Obj; + + protected body Obj is + procedure Set (V : Integer) is + begin + Local := V; + Is_Set := True; + end Set; + + entry Get (V : out Integer) + when Is_Set is + -- Entry is blocked until the + -- condition is true. The barrier + -- is evaluated at call of entries + -- and at exits of procedures and + -- entries. The calling task sleeps + -- until the barrier is released. + begin + V := Local; + Is_Set := False; + end Get; + end Obj; + + N : Integer := 0; + + task T is + entry Seize; + end T; + + task body T is + begin + + accept Seize; + Put_Line + ("Task T will delay for 4 seconds..."); + delay 4.0; + + accept Seize; + Put_Line + ("Task T will set Obj..."); + Obj.Set (5); + + accept Seize; + Put_Line + ("Task T has just set Obj..."); + end T; +begin + Put_Line + ("Main application will get Obj..."); + Obj.Get (N); + + Put_Line + ("Main application has retrieved Obj..."); + Put_Line + ("Number is: " & Integer'Image (N)); + +end Show_Protected_Objects_Entries; diff --git a/testsuite/ada_lsp/definition_protected/test.gpr b/testsuite/ada_lsp/definition_protected/test.gpr new file mode 100644 index 00000000..99d5dd58 --- /dev/null +++ b/testsuite/ada_lsp/definition_protected/test.gpr @@ -0,0 +1,2 @@ +project Test is +end Test; diff --git a/testsuite/ada_lsp/definition_protected/test.json b/testsuite/ada_lsp/definition_protected/test.json new file mode 100644 index 00000000..c84cf64b --- /dev/null +++ b/testsuite/ada_lsp/definition_protected/test.json @@ -0,0 +1,263 @@ +[ + { + "comment": [ + "Test goto defintion on an entry in a protected type." + ] + }, + { + "start": { + "cmd": ["${ALS}"] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 1, + "method": "initialize", + "params": { + "rootUri": "$URI{.}", + "capabilities": {} + } + }, + "wait": [] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "initialized", + "params": {} + }, + "wait": [] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "textDocument/didOpen", + "params": { + "textDocument": { + "uri": "$URI{show_protected_objects_entries.adb}", + "languageId": "Ada", + "version": 0, + "text": "with Ada.Text_IO; use Ada.Text_IO;\n\nprocedure Show_Protected_Objects_Entries is\n\n protected Obj is\n procedure Set (V : Integer);\n entry Get (V : out Integer);\n private\n Local : Integer;\n Is_Set : Boolean := False;\n end Obj;\n\n protected body Obj is\n procedure Set (V : Integer) is\n begin\n Local := V;\n Is_Set := True;\n end Set;\n\n entry Get (V : out Integer)\n when Is_Set is\n -- Entry is blocked until the\n -- condition is true. The barrier\n -- is evaluated at call of entries\n -- and at exits of procedures and\n -- entries. The calling task sleeps\n -- until the barrier is released.\n begin\n V := Local;\n Is_Set := False;\n end Get;\n end Obj;\n\n N : Integer := 0;\n\n task T is\n entry Seize;\n end T;\n\n task body T is\n begin\n\n accept Seize;\n Put_Line\n (\"Task T will delay for 4 seconds...\");\n delay 4.0;\n\n accept Seize;\n Put_Line\n (\"Task T will set Obj...\");\n Obj.Set (5);\n\n accept Seize;\n Put_Line\n (\"Task T has just set Obj...\");\n end T;\nbegin\n Put_Line\n (\"Main application will get Obj...\");\n Obj.Get (N);\n\n Put_Line\n (\"Main application has retrieved Obj...\");\n Put_Line\n (\"Number is: \" & Integer'Image (N));\n\nend Show_Protected_Objects_Entries;\n" + } + } + }, + "wait": [] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 6, + "method": "textDocument/definition", + "params": { + "textDocument": { + "uri": "$URI{show_protected_objects_entries.adb}" + }, + "position": { + "line": 6, + "character": 12 + }, + "alsDisplayMethodAncestryOnNavigation": "Usage_And_Abstract_Only" + } + }, + "wait": [ + { + "id": 6, + "result": { + "uri": "$URI{show_protected_objects_entries.adb}", + "range": { + "start": { + "line": 19, + "character": 12 + }, + "end": { + "line": 19, + "character": 15 + } + } + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 9, + "method": "textDocument/definition", + "params": { + "textDocument": { + "uri": "$URI{show_protected_objects_entries.adb}" + }, + "position": { + "line": 19, + "character": 12 + }, + "alsDisplayMethodAncestryOnNavigation": "Usage_And_Abstract_Only" + } + }, + "wait": [ + { + "id": 9, + "result": { + "uri": "$URI{show_protected_objects_entries.adb}", + "range": { + "start": { + "line": 6, + "character": 12 + }, + "end": { + "line": 6, + "character": 15 + } + } + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 12, + "method": "textDocument/definition", + "params": { + "textDocument": { + "uri": "$URI{show_protected_objects_entries.adb}" + }, + "position": { + "line": 36, + "character": 12 + }, + "alsDisplayMethodAncestryOnNavigation": "Usage_And_Abstract_Only" + } + }, + "wait": [ + { + "id": 12, + "result": [ + { + "uri": "$URI{show_protected_objects_entries.adb}", + "range": { + "start": { + "line": 42, + "character": 13 + }, + "end": { + "line": 42, + "character": 18 + } + } + }, + { + "uri": "$URI{show_protected_objects_entries.adb}", + "range": { + "start": { + "line": 47, + "character": 13 + }, + "end": { + "line": 47, + "character": 18 + } + } + }, + { + "uri": "$URI{show_protected_objects_entries.adb}", + "range": { + "start": { + "line": 52, + "character": 13 + }, + "end": { + "line": 52, + "character": 18 + } + } + } + ] + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 18, + "method": "textDocument/definition", + "params": { + "textDocument": { + "uri": "$URI{show_protected_objects_entries.adb}" + }, + "position": { + "line": 47, + "character": 13 + }, + "alsDisplayMethodAncestryOnNavigation": "Usage_And_Abstract_Only" + } + }, + "wait": [ + { + "id": 18, + "result": { + "uri": "$URI{show_protected_objects_entries.adb}", + "range": { + "start": { + "line": 36, + "character": 12 + }, + "end": { + "line": 36, + "character": 17 + } + } + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "textDocument/didClose", + "params": { + "textDocument": { + "uri": "$URI{show_protected_objects_entries.adb}" + } + } + }, + "wait": [] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 21, + "method": "shutdown" + }, + "wait": [ + { + "id": 21, + "result": null + } + ] + } + }, + { + "stop": { + "exit_code": 0 + } + } +] diff --git a/testsuite/ada_lsp/definition_protected/test.yaml b/testsuite/ada_lsp/definition_protected/test.yaml new file mode 100644 index 00000000..4638ced4 --- /dev/null +++ b/testsuite/ada_lsp/definition_protected/test.yaml @@ -0,0 +1 @@ +title: 'definition_protected'