Skip to content

Commit ee91f1b

Browse files
T723-027: Implement SignatureHelp
Use P_All_Env_Elements and filter the returned node to find all the function declaration with the same name. Fix param type in the generated spec. Add tests.
1 parent 1396835 commit ee91f1b

File tree

21 files changed

+3630
-11
lines changed

21 files changed

+3630
-11
lines changed

scripts/generate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@
283283
('textDocument/references', 'References', 'ReferenceParams',
284284
'Location_Response'),
285285
('textDocument/signatureHelp', 'Signature_Help',
286-
'TextDocumentPositionParams', 'SignatureHelp_Response'),
286+
'SignatureHelpParams', 'SignatureHelp_Response'),
287287
('textDocument/documentSymbol', 'Document_Symbols',
288288
'DocumentSymbolParams', 'Symbol_Response'),
289289
('textDocument/rename', 'Rename', 'RenameParams', 'Rename_Response'),

source/ada/lsp-ada_contexts.adb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,30 @@ package body LSP.Ada_Contexts is
471471
Log (Self.Trace, E, "in Is_Called_By");
472472
end Find_All_Calls;
473473

474+
---------------------------
475+
-- Find_All_Env_Elements --
476+
---------------------------
477+
478+
function Find_All_Env_Elements
479+
(Self : Context;
480+
Name : Libadalang.Analysis.Name;
481+
Seq : Boolean := True;
482+
Seq_From : Libadalang.Analysis.Ada_Node'Class :=
483+
Libadalang.Analysis.No_Ada_Node)
484+
return Libadalang.Analysis.Ada_Node_Array is
485+
begin
486+
return Libadalang.Analysis.P_All_Env_Elements (Name, Seq, Seq_From);
487+
exception
488+
when E : Libadalang.Common.Property_Error =>
489+
Log (Self.Trace, E, "in Find_All_Env_Elements");
490+
declare
491+
Empty_Node_Array : constant
492+
Libadalang.Analysis.Ada_Node_Array (1 .. 0) := (others => <>);
493+
begin
494+
return Empty_Node_Array;
495+
end;
496+
end Find_All_Env_Elements;
497+
474498
-------------------------------
475499
-- Get_Any_Symbol_Completion --
476500
-------------------------------

source/ada/lsp-ada_contexts.ads

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,17 @@ package LSP.Ada_Contexts is
142142
-- Return all the enclosing entities that call Definition in all sources
143143
-- known to this project.
144144

145+
function Find_All_Env_Elements
146+
(Self : Context;
147+
Name : Libadalang.Analysis.Name;
148+
Seq : Boolean := True;
149+
Seq_From : Libadalang.Analysis.Ada_Node'Class :=
150+
Libadalang.Analysis.No_Ada_Node)
151+
return Libadalang.Analysis.Ada_Node_Array;
152+
-- Return all elements lexically named like Name.
153+
-- If Seq is True and Seq_From is not empty, reduce the scope to the
154+
-- node above Seq_From.
155+
145156
procedure Get_References_For_Renaming
146157
(Self : Context;
147158
Definition : Libadalang.Analysis.Defining_Name;

source/ada/lsp-ada_handlers.adb

Lines changed: 88 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,11 @@ package body LSP.Ada_Handlers is
690690
LSP.Messages.Incremental
691691
else
692692
LSP.Messages.Full));
693+
Response.result.capabilities.signatureHelpProvider :=
694+
(True,
695+
(triggerCharacters => (True, Empty_Vector & (+",") & (+"(")),
696+
retriggerCharacters => (True, Empty_Vector & (+" ")),
697+
workDoneProgress => LSP.Types.None));
693698
Response.result.capabilities.completionProvider :=
694699
(True,
695700
(resolveProvider => LSP.Types.False,
@@ -2788,15 +2793,91 @@ package body LSP.Ada_Handlers is
27882793
Request : LSP.Messages.Server_Requests.Signature_Help_Request)
27892794
return LSP.Messages.Server_Responses.SignatureHelp_Response
27902795
is
2791-
pragma Unreferenced (Self, Request);
2796+
use Libadalang.Analysis;
2797+
use LSP.Messages;
2798+
2799+
Value : LSP.Messages.SignatureHelpParams renames
2800+
Request.params;
27922801
Response : LSP.Messages.Server_Responses.SignatureHelp_Response
2793-
(Is_Error => True);
2802+
(Is_Error => False);
2803+
2804+
C : constant Context_Access :=
2805+
Self.Contexts.Get_Best_Context (Value.textDocument.uri);
2806+
2807+
Node : constant Libadalang.Analysis.Ada_Node :=
2808+
C.Get_Node_At
2809+
(Get_Open_Document (Self, Value.textDocument.uri),
2810+
Value);
2811+
Name_Node : Libadalang.Analysis.Name;
2812+
Designator : Libadalang.Analysis.Ada_Node;
2813+
Active_Position : LSP.Types.LSP_Number;
2814+
2815+
procedure Add_Signature (Decl_Node : Libadalang.Analysis.Basic_Decl);
2816+
2817+
-------------------
2818+
-- Add_Signature --
2819+
-------------------
2820+
2821+
procedure Add_Signature (Decl_Node : Libadalang.Analysis.Basic_Decl)
2822+
is
2823+
Param_Index : constant LSP.Types.LSP_Number :=
2824+
Get_Active_Parameter (Decl_Node, Designator, Active_Position);
2825+
begin
2826+
if Param_Index = -1 then
2827+
return;
2828+
end if;
2829+
2830+
declare
2831+
Signature : LSP.Messages.SignatureInformation :=
2832+
(label => Get_Hover_Text (Decl_Node),
2833+
documentation =>
2834+
(Is_Set => True,
2835+
Value =>
2836+
(Is_String => True,
2837+
String =>
2838+
To_LSP_String
2839+
(Ada.Strings.UTF_Encoding.Wide_Wide_Strings.Encode
2840+
(Libadalang.Doc_Utils.Get_Documentation
2841+
(Decl_Node).Doc.To_String)
2842+
)
2843+
)
2844+
),
2845+
activeParameter =>
2846+
(Is_Set => True,
2847+
Value => Param_Index
2848+
),
2849+
others => <>
2850+
);
2851+
begin
2852+
Get_Parameters (Decl_Node, Signature.parameters);
2853+
Response.result.signatures.Append (Signature);
2854+
end;
2855+
end Add_Signature;
2856+
27942857
begin
2795-
Response.error :=
2796-
(True,
2797-
(code => LSP.Errors.InternalError,
2798-
message => +"Not implemented",
2799-
data => <>));
2858+
Response.result := (others => <>);
2859+
2860+
-- Check if we are inside a function call and get the caller name
2861+
Get_Call_Expr_Name (Node, Active_Position, Designator, Name_Node);
2862+
2863+
if Name_Node = Libadalang.Analysis.No_Name then
2864+
return Response;
2865+
end if;
2866+
2867+
for N of C.Find_All_Env_Elements (Name_Node) loop
2868+
if N.Kind in Ada_Subp_Decl_Range then
2869+
Add_Signature (N.As_Basic_Decl);
2870+
end if;
2871+
end loop;
2872+
2873+
-- Set the active values to default
2874+
Response.result.activeSignature := (Is_Set => True,
2875+
Value => 0);
2876+
-- activeParameter will be ignored because it is properly set in
2877+
-- the signatures.
2878+
Response.result.activeParameter := (Is_Set => True,
2879+
Value => 0);
2880+
28002881
return Response;
28012882
end On_Signature_Help_Request;
28022883

source/ada/lsp-lal_utils.adb

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,140 @@ package body LSP.Lal_Utils is
350350
return LSP.Messages.A_Null;
351351
end Get_Decl_Kind;
352352

353+
------------------------
354+
-- Get_Call_Expr_Name --
355+
------------------------
356+
357+
procedure Get_Call_Expr_Name
358+
(Node : Libadalang.Analysis.Ada_Node'Class;
359+
Active_Position : out LSP.Types.LSP_Number;
360+
Designator : out Libadalang.Analysis.Ada_Node;
361+
Name_Node : out Libadalang.Analysis.Name)
362+
is
363+
Cur_Node : Ada_Node := Node.As_Ada_Node;
364+
begin
365+
Active_Position := 0;
366+
Name_Node := Libadalang.Analysis.No_Name;
367+
368+
-- Find the first Call_Expr node in the parents
369+
while not Cur_Node.Is_Null loop
370+
exit when Cur_Node.Kind in Ada_Call_Expr_Range;
371+
372+
Cur_Node := Cur_Node.Parent;
373+
end loop;
374+
375+
if Cur_Node.Is_Null then
376+
return;
377+
end if;
378+
379+
declare
380+
Call_Expr_Node : constant Libadalang.Analysis.Call_Expr :=
381+
Cur_Node.As_Call_Expr;
382+
Suffix_Node : constant Libadalang.Analysis.Ada_Node'Class :=
383+
Call_Expr_Node.F_Suffix;
384+
Node_Parents : constant Libadalang.Analysis.Ada_Node_Array :=
385+
Node.Parents;
386+
begin
387+
Name_Node := Call_Expr_Node.F_Name;
388+
389+
if Suffix_Node = Libadalang.Analysis.No_Ada_Node then
390+
return;
391+
end if;
392+
393+
-- Find the position in the Assoc_List
394+
if Suffix_Node.Kind in Ada_Assoc_List_Range then
395+
for Assoc of Suffix_Node.As_Assoc_List loop
396+
Designator := Assoc.As_Param_Assoc.F_Designator;
397+
for Parent of Node_Parents loop
398+
exit when Assoc = Parent;
399+
end loop;
400+
Active_Position := Active_Position + 1;
401+
end loop;
402+
end if;
403+
-- The active position index starts at 0
404+
Active_Position := Active_Position - 1;
405+
end;
406+
end Get_Call_Expr_Name;
407+
408+
--------------------
409+
-- Get_Parameters --
410+
--------------------
411+
412+
procedure Get_Parameters
413+
(Node : Libadalang.Analysis.Basic_Decl;
414+
Parameters : in out LSP.Messages.ParameterInformation_Vector)
415+
is
416+
Spec : constant Libadalang.Analysis.Base_Subp_Spec :=
417+
Node.P_Subp_Spec_Or_Null;
418+
begin
419+
if Spec = Libadalang.Analysis.No_Base_Subp_Spec then
420+
return;
421+
end if;
422+
423+
for Param of Spec.P_Params loop
424+
for Id of Param.F_Ids loop
425+
declare
426+
P : constant LSP.Messages.ParameterInformation :=
427+
(label =>
428+
(Is_String => True,
429+
String => To_LSP_String (Id.Text)),
430+
documentation =>
431+
(Is_Set => False)
432+
);
433+
begin
434+
Parameters.Append (P);
435+
end;
436+
end loop;
437+
end loop;
438+
end Get_Parameters;
439+
440+
--------------------------
441+
-- Get_Active_Parameter --
442+
--------------------------
443+
444+
function Get_Active_Parameter
445+
(Node : Libadalang.Analysis.Basic_Decl;
446+
Designator : Libadalang.Analysis.Ada_Node;
447+
Position : LSP.Types.LSP_Number)
448+
return LSP.Types.LSP_Number
449+
is
450+
Spec : constant Libadalang.Analysis.Base_Subp_Spec :=
451+
Node.P_Subp_Spec_Or_Null;
452+
Index : LSP.Types.LSP_Number := 0;
453+
begin
454+
if Spec = Libadalang.Analysis.No_Base_Subp_Spec then
455+
return -1;
456+
457+
elsif Designator = Libadalang.Analysis.No_Ada_Node then
458+
-- Check if the given position is a valid index for Node
459+
for Param of Spec.P_Params loop
460+
for Id of Param.F_Ids loop
461+
Index := Index + 1;
462+
end loop;
463+
end loop;
464+
if Position > Index - 1 then
465+
return -1;
466+
else
467+
return Position;
468+
end if;
469+
470+
else
471+
-- If we have a designator then try to find the position of a
472+
-- parameter with the same name
473+
for Param of Spec.P_Params loop
474+
for Id of Param.F_Ids loop
475+
if Id.Text = Designator.Text then
476+
return Index;
477+
end if;
478+
Index := Index + 1;
479+
end loop;
480+
end loop;
481+
482+
-- No matching designator
483+
return -1;
484+
end if;
485+
end Get_Active_Parameter;
486+
353487
-----------------------
354488
-- Get_Node_Location --
355489
-----------------------

source/ada/lsp-lal_utils.ads

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,29 @@ package LSP.Lal_Utils is
133133
-- When Ignore_Local it will return Is_Null for all local objects like
134134
-- variables.
135135

136+
procedure Get_Call_Expr_Name
137+
(Node : Libadalang.Analysis.Ada_Node'Class;
138+
Active_Position : out LSP.Types.LSP_Number;
139+
Designator : out Libadalang.Analysis.Ada_Node;
140+
Name_Node : out Libadalang.Analysis.Name);
141+
-- If Node is inside a Call_Expr returns the following:
142+
-- Active_Position: the index of the parameter in the Call_Expr
143+
-- Designator: the designator of the Active_Position
144+
-- Name_Node: the name of the Call_Expr
145+
146+
procedure Get_Parameters
147+
(Node : Libadalang.Analysis.Basic_Decl;
148+
Parameters : in out LSP.Messages.ParameterInformation_Vector);
149+
-- Append all the parameters of Node inside Parameters
150+
151+
function Get_Active_Parameter
152+
(Node : Libadalang.Analysis.Basic_Decl;
153+
Designator : Libadalang.Analysis.Ada_Node;
154+
Position : LSP.Types.LSP_Number)
155+
return LSP.Types.LSP_Number;
156+
-- Return the position of Designator in the parameters of Node else -1
157+
-- If Designator is null try check if Position is a valid parameter index
158+
136159
function To_Call_Hierarchy_Item
137160
(Name : Libadalang.Analysis.Defining_Name)
138161
return LSP.Messages.CallHierarchyItem;

source/client/lsp-clients.adb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1167,7 +1167,7 @@ package body LSP.Clients is
11671167
procedure Text_Document_Signature_Help_Request
11681168
(Self : in out Client'Class;
11691169
Request : out LSP.Types.LSP_Number_Or_String;
1170-
Value : LSP.Messages.TextDocumentPositionParams)
1170+
Value : LSP.Messages.SignatureHelpParams)
11711171
is
11721172
Message : Signature_Help_Request := (params => Value, others => <>);
11731173
begin

source/client/lsp-clients.ads

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ package LSP.Clients is
149149
procedure Text_Document_Signature_Help_Request
150150
(Self : in out Client'Class;
151151
Request : out LSP.Types.LSP_Number_Or_String;
152-
Value : LSP.Messages.TextDocumentPositionParams);
152+
Value : LSP.Messages.SignatureHelpParams);
153153

154154
procedure Text_Document_Symbol_Request
155155
(Self : in out Client'Class;

source/protocol/generated/lsp-messages-server_requests.ads

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ package LSP.Messages.Server_Requests is
179179
package Signature_Help_Requests is
180180
new LSP.Generic_Requests
181181
(Server_Request,
182-
TextDocumentPositionParams,
182+
SignatureHelpParams,
183183
Server_Request_Receiver'Class);
184184

185185
type Signature_Help_Request is
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
project Default is
2+
3+
end Default;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
procedure Foo
2+
is
3+
procedure Bar (A : Integer; B, C : Integer);
4+
function FooBar (A : Integer) return Integer;
5+
6+
---------
7+
-- Bar --
8+
---------
9+
10+
procedure Bar (A : Integer; B, C : Integer) is
11+
begin
12+
null;
13+
end Bar;
14+
15+
------------
16+
-- FooBar --
17+
------------
18+
19+
function FooBar (A : Integer) return Integer is
20+
begin
21+
return A;
22+
end FooBar;
23+
begin
24+
Bar (1, FooBar (2), 3);
25+
end Foo;

0 commit comments

Comments
 (0)