Skip to content

Commit 84d968c

Browse files
SA11-051 Introduce Parameter tool initial implementation
1 parent 026b81c commit 84d968c

File tree

15 files changed

+752
-22
lines changed

15 files changed

+752
-22
lines changed

doc/refactoring_tools.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* [Extract Subprogram](#extract-subprogram)
1515
* [Pull Up Declaration](#pull-up-declaration)
1616
* [Suppress Separate](#suppress-separate)
17+
* [Introduce Parameter](#introduce-parameter)
1718

1819
## Named Parameters
1920

@@ -135,3 +136,15 @@
135136

136137
![suppress_separate](https://user-images.githubusercontent.com/22893717/166927780-441fdb3f-271f-4f69-99ff-367e8eef301e.gif)
137138

139+
## Introduce Parameter
140+
141+
* Introduces a formal parameter based on an object declaration or expression inside a subprogram.
142+
* All references of the object declaration or expression are replaced by the introduced parameter.
143+
* The user must mannually fix the calls to the subprogram that was refactored by addings the corresponding actual parameter.
144+
145+
[Source](https://github.com/AdaCore/libadalang-tools/blob/master/src/laltools-refactor-introduce_parameter.ads)
146+
147+
[Demo Source](../integration/vscode/Code%20Samples/refactoring_demos/introduce_parameter)
148+
149+
![introduce parameter](https://user-images.githubusercontent.com/22893717/181477996-564a1365-33df-4227-bb82-e9ed802b4ed0.gif)
150+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
project Default is
2+
for Source_Dirs use ("src");
3+
for Object_Dir use "obj";
4+
for Main use ("main.adb");
5+
end Default;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
with Ada.Text_IO;
2+
with My_Package;
3+
procedure Main is
4+
begin
5+
Ada.Text_IO.Put_Line (My_Package.C1.Q.B.F.I'Image);
6+
Ada.Text_IO.Put_Line (My_Package.C1.Q.B.F.I'Image);
7+
Ada.Text_IO.Put_Line (My_Package.C2.Q.B.F.I'Image);
8+
end Main;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package My_Package is
2+
type Foo is record I : Integer; end record;
3+
type Bar is record F : Foo; end record;
4+
type Qux is record B : Bar; end record;
5+
type Corge is record Q : Qux; end record;
6+
C1 : constant Corge := (Q => (B => (F => (I => 1))));
7+
C2 : constant Corge := (Q => (B => (F => (I => 2))));
8+
end My_Package;

source/ada/lsp-ada_driver.adb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ with LSP.Ada_Handlers.Refactor_Change_Parameters_Type;
4949
with LSP.Ada_Handlers.Refactor_Change_Parameters_Default_Value;
5050
with LSP.Ada_Handlers.Refactor_Suppress_Seperate;
5151
with LSP.Ada_Handlers.Refactor_Extract_Subprogram;
52+
with LSP.Ada_Handlers.Refactor_Introduce_Parameter;
5253
with LSP.Ada_Handlers.Refactor_Pull_Up_Declaration;
5354
with LSP.Commands;
5455
with LSP.Error_Decorators;
@@ -139,6 +140,8 @@ procedure LSP.Ada_Driver is
139140
(LSP.Ada_Handlers.Refactor_Suppress_Seperate.Command'Tag);
140141
LSP.Commands.Register
141142
(LSP.Ada_Handlers.Refactor_Extract_Subprogram.Command'Tag);
143+
LSP.Commands.Register
144+
(LSP.Ada_Handlers.Refactor_Introduce_Parameter.Command'Tag);
142145
LSP.Commands.Register
143146
(LSP.Ada_Handlers.Refactor_Pull_Up_Declaration.Command'Tag);
144147

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
------------------------------------------------------------------------------
2+
-- Language Server Protocol --
3+
-- --
4+
-- Copyright (C) 2022, AdaCore --
5+
-- --
6+
-- This is free software; you can redistribute it and/or modify it under --
7+
-- terms of the GNU General Public License as published by the Free Soft- --
8+
-- ware Foundation; either version 3, or (at your option) any later ver- --
9+
-- sion. This software is distributed in the hope that it will be useful, --
10+
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
11+
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public --
12+
-- License for more details. You should have received a copy of the GNU --
13+
-- General Public License distributed with this software; see file --
14+
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy --
15+
-- of the license. --
16+
------------------------------------------------------------------------------
17+
18+
with Ada.Exceptions;
19+
with Ada.Strings.UTF_Encoding;
20+
21+
with Libadalang.Analysis; use Libadalang.Analysis;
22+
23+
with Langkit_Support.Slocs;
24+
25+
with Laltools.Refactor.Introduce_Parameter;
26+
use Laltools.Refactor.Introduce_Parameter;
27+
28+
with LSP.Messages.Client_Requests;
29+
with LSP.Lal_Utils;
30+
31+
with VSS.Strings.Conversions;
32+
33+
package body LSP.Ada_Handlers.Refactor_Introduce_Parameter is
34+
35+
------------------------
36+
-- Append_Code_Action --
37+
------------------------
38+
39+
procedure Append_Code_Action
40+
(Self : in out Command;
41+
Context : Context_Access;
42+
Commands_Vector : in out LSP.Messages.CodeAction_Vector;
43+
Where : LSP.Messages.Location)
44+
is
45+
use LSP.Commands;
46+
use LSP.Messages;
47+
48+
Pointer : Command_Pointer;
49+
Code_Action : CodeAction;
50+
51+
begin
52+
Self.Initialize (Context => Context.all, Where => Where);
53+
54+
Pointer.Set (Data => Self);
55+
56+
Code_Action :=
57+
(title => "Introduce Parameter",
58+
kind => (Is_Set => True, Value => RefactorRewrite),
59+
diagnostics => (Is_Set => False),
60+
edit => (Is_Set => False),
61+
isPreferred => (Is_Set => False),
62+
disabled => (Is_Set => False),
63+
command =>
64+
(Is_Set => True,
65+
Value => (Is_Unknown => False, title => <>, Custom => Pointer)));
66+
67+
Commands_Vector.Append (New_Item => Code_Action);
68+
end Append_Code_Action;
69+
70+
------------
71+
-- Create --
72+
------------
73+
74+
overriding function Create
75+
(JS : not null access LSP.JSON_Streams.JSON_Stream'Class)
76+
return Command
77+
is
78+
use Ada.Strings.UTF_Encoding;
79+
use VSS.Strings.Conversions;
80+
use LSP.Messages;
81+
use LSP.Types;
82+
83+
begin
84+
return V : Command do
85+
pragma Assert (JS.R.Is_Start_Object);
86+
87+
JS.R.Read_Next;
88+
89+
while not JS.R.Is_End_Object loop
90+
pragma Assert (JS.R.Is_Key_Name);
91+
92+
declare
93+
Key : constant UTF_8_String := To_UTF_8_String (JS.R.Key_Name);
94+
95+
begin
96+
JS.R.Read_Next;
97+
98+
if Key = "context_id" then
99+
Read_String (JS, V.Context_Id);
100+
101+
elsif Key = "where" then
102+
Location'Read (JS, V.Where);
103+
104+
else
105+
JS.Skip_Value;
106+
end if;
107+
end;
108+
end loop;
109+
110+
JS.R.Read_Next;
111+
end return;
112+
end Create;
113+
114+
-------------
115+
-- Execute --
116+
-------------
117+
118+
overriding procedure Execute
119+
(Self : Command;
120+
Handler : not null access LSP.Server_Notification_Receivers.
121+
Server_Notification_Receiver'Class;
122+
Client : not null access LSP.Client_Message_Receivers.
123+
Client_Message_Receiver'Class;
124+
Error : in out LSP.Errors.Optional_ResponseError)
125+
is
126+
use Ada.Exceptions;
127+
use Langkit_Support.Slocs;
128+
use Laltools.Refactor;
129+
use LSP.Errors;
130+
use LSP.Lal_Utils;
131+
use LSP.Messages;
132+
use VSS.Strings.Conversions;
133+
134+
Message_Handler : LSP.Ada_Handlers.Message_Handler renames
135+
LSP.Ada_Handlers.Message_Handler (Handler.all);
136+
Context : LSP.Ada_Contexts.Context renames
137+
Message_Handler.Contexts.Get (Self.Context_Id).all;
138+
139+
Apply : Client_Requests.Workspace_Apply_Edit_Request;
140+
141+
Workspace_Edits : WorkspaceEdit renames Apply.params.edit;
142+
143+
Introducer : constant Parameter_Introducer :=
144+
Create_Parameter_Introducer
145+
(Unit =>
146+
Context.Get_AU (Context.URI_To_File (Self.Where.uri)),
147+
SLOC_Range =>
148+
(Line_Number (Self.Where.span.first.line) + 1,
149+
Line_Number (Self.Where.span.last.line) + 1,
150+
Column_Number (Self.Where.span.first.character) + 1,
151+
Column_Number (Self.Where.span.last.character) + 1));
152+
153+
Edits : Refactoring_Edits;
154+
155+
function Analysis_Units return Analysis_Unit_Array is
156+
(Context.Analysis_Units);
157+
-- Provides the Context Analysis_Unit_Array to the Parameter_Introducer
158+
159+
begin
160+
Edits := Introducer.Refactor (Analysis_Units'Access);
161+
162+
Workspace_Edits :=
163+
To_Workspace_Edit
164+
(EM => Edits.Text_Edits,
165+
Versioned_Documents => Message_Handler.Versioned_Documents,
166+
Document_Provider => Message_Handler'Access);
167+
168+
Client.On_Workspace_Apply_Edit_Request (Message => Apply);
169+
170+
exception
171+
when E : others =>
172+
Error :=
173+
(Is_Set => True,
174+
Value =>
175+
(code => UnknownErrorCode,
176+
message => To_Virtual_String (Exception_Information (E)),
177+
data => <>));
178+
end Execute;
179+
180+
----------------
181+
-- Initialize --
182+
----------------
183+
184+
procedure Initialize
185+
(Self : in out Command'Class;
186+
Context : LSP.Ada_Contexts.Context;
187+
Where : LSP.Messages.Location) is
188+
begin
189+
Self.Context_Id := Context.Id;
190+
Self.Where := Where;
191+
end Initialize;
192+
193+
-------------------
194+
-- Write_Command --
195+
-------------------
196+
197+
procedure Write_Command
198+
(S : access Ada.Streams.Root_Stream_Type'Class;
199+
C : Command)
200+
is
201+
use LSP.JSON_Streams;
202+
203+
JS : JSON_Stream'Class renames JSON_Stream'Class (S.all);
204+
205+
begin
206+
JS.Start_Object;
207+
JS.Key ("context_id");
208+
LSP.Types.Write_String (S, C.Context_Id);
209+
JS.Key ("where");
210+
LSP.Messages.Location'Write (S, C.Where);
211+
JS.End_Object;
212+
end Write_Command;
213+
214+
end LSP.Ada_Handlers.Refactor_Introduce_Parameter;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
------------------------------------------------------------------------------
2+
-- Language Server Protocol --
3+
-- --
4+
-- Copyright (C) 2022, AdaCore --
5+
-- --
6+
-- This is free software; you can redistribute it and/or modify it under --
7+
-- terms of the GNU General Public License as published by the Free Soft- --
8+
-- ware Foundation; either version 3, or (at your option) any later ver- --
9+
-- sion. This software is distributed in the hope that it will be useful, --
10+
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
11+
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public --
12+
-- License for more details. You should have received a copy of the GNU --
13+
-- General Public License distributed with this software; see file --
14+
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy --
15+
-- of the license. --
16+
------------------------------------------------------------------------------
17+
--
18+
-- Implementation of the refactoring tool to introduce a parameter
19+
20+
with Ada.Streams;
21+
22+
with LSP.Client_Message_Receivers;
23+
with LSP.Commands;
24+
with LSP.Messages;
25+
with LSP.Errors;
26+
with LSP.JSON_Streams;
27+
28+
with VSS.Strings;
29+
30+
package LSP.Ada_Handlers.Refactor_Introduce_Parameter is
31+
32+
type Command is new LSP.Commands.Command with private;
33+
34+
procedure Append_Code_Action
35+
(Self : in out Command;
36+
Context : Context_Access;
37+
Commands_Vector : in out LSP.Messages.CodeAction_Vector;
38+
Where : LSP.Messages.Location);
39+
-- Initializes Self and appends it to Commands_Vector
40+
41+
private
42+
43+
type Command is new LSP.Commands.Command with record
44+
Context_Id : VSS.Strings.Virtual_String;
45+
Where : LSP.Messages.Location;
46+
end record;
47+
48+
overriding
49+
function Create
50+
(JS : not null access LSP.JSON_Streams.JSON_Stream'Class)
51+
return Command;
52+
-- Reads JS and creates a new Command
53+
54+
overriding
55+
procedure Execute
56+
(Self : Command;
57+
Handler : not null access
58+
LSP.Server_Notification_Receivers.Server_Notification_Receiver'Class;
59+
Client : not null access
60+
LSP.Client_Message_Receivers.Client_Message_Receiver'Class;
61+
Error : in out LSP.Errors.Optional_ResponseError);
62+
-- Executes Self by computing the necessary refactorings
63+
64+
procedure Initialize
65+
(Self : in out Command'Class;
66+
Context : LSP.Ada_Contexts.Context;
67+
Where : LSP.Messages.Location);
68+
-- Initializes Self
69+
70+
procedure Write_Command
71+
(S : access Ada.Streams.Root_Stream_Type'Class;
72+
C : Command);
73+
-- Writes C to S
74+
75+
for Command'Write use Write_Command;
76+
for Command'External_Tag use "als-refactor-introduce-parameter";
77+
78+
end LSP.Ada_Handlers.Refactor_Introduce_Parameter;

0 commit comments

Comments
 (0)