Skip to content

Commit cfb1ec8

Browse files
Merge branch 'topic/completion_first_token' into 'master'
Add defensive code in LSP completion See merge request eng/ide/ada_language_server!1413
2 parents dc4577b + f702155 commit cfb1ec8

File tree

9 files changed

+259
-20
lines changed

9 files changed

+259
-20
lines changed

source/ada/lsp-ada_completions-filters.adb

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,11 @@ package body LSP.Ada_Completions.Filters is
4242
------------------
4343

4444
function Is_End_Label (Self : in out Filter'Class) return Boolean is
45+
use Libadalang.Common;
4546
begin
4647
if not Self.Is_End_Label.Is_Set then
4748
declare
48-
use all type Libadalang.Common.Ada_Node_Kind_Type;
49-
50-
Parent : constant Libadalang.Analysis.Ada_Node :=
49+
Parent : constant Libadalang.Analysis.Ada_Node :=
5150
(if Self.Node.Is_Null then Self.Node
5251
else Skip_Dotted_Names (Self.Node.Parent));
5352
-- Skip the outermost dotted name enclosing Node.Parent, so
@@ -69,9 +68,11 @@ package body LSP.Ada_Completions.Filters is
6968
elsif Is_End_Token (Self.Token) then
7069
Self.Is_End_Label := LSP.Constants.True;
7170

72-
elsif Is_End_Token
73-
(Libadalang.Common.Previous
74-
(Self.Token, Exclude_Trivia => True))
71+
elsif Libadalang.Common.Previous
72+
(Self.Token, Exclude_Trivia => True) /= No_Token
73+
and then Is_End_Token
74+
(Libadalang.Common.Previous
75+
(Self.Token, Exclude_Trivia => True))
7576
then
7677
Self.Is_End_Label := LSP.Constants.True;
7778

@@ -217,11 +218,18 @@ package body LSP.Ada_Completions.Filters is
217218
---------------
218219

219220
function Is_Aspect (Self : in out Filter'Class) return Boolean is
221+
use Libadalang.Common;
220222
begin
221223
if not Self.Is_Aspect.Is_Set then
222-
declare
223-
use Libadalang.Common;
224224

225+
if Libadalang.Common.Previous
226+
(Self.Token, Exclude_Trivia => True) = No_Token
227+
then
228+
Self.Is_Aspect := (True, False);
229+
return Self.Is_Aspect.Value;
230+
end if;
231+
232+
declare
225233
Token_Kind : constant Libadalang.Common.Token_Kind :=
226234
Kind (Libadalang.Common.Previous
227235
(Self.Token, Exclude_Trivia => True));

source/ada/lsp-ada_completions-parameters.adb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,10 @@ package body LSP.Ada_Completions.Parameters is
260260
(N : Libadalang.Analysis.Ada_Node'Class)
261261
return Libadalang.Analysis.Aggregate is
262262
begin
263+
if N.Is_Null then
264+
return No_Aggregate;
265+
end if;
266+
263267
if N.Kind in Libadalang.Common.Ada_Aggregate_Range then
264268
return N.As_Aggregate;
265269
end if;
@@ -598,6 +602,10 @@ package body LSP.Ada_Completions.Parameters is
598602
return Libadalang.Analysis.Generic_Package_Instantiation
599603
is
600604
begin
605+
if N.Is_Null then
606+
return No_Generic_Package_Instantiation;
607+
end if;
608+
601609
if N.Kind in Ada_Generic_Package_Instantiation_Range then
602610
return N.As_Generic_Package_Instantiation;
603611
end if;

source/ada/lsp-ada_completions-use_clauses.adb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ package body LSP.Ada_Completions.Use_Clauses is
5555
and then N.Kind = Ada_With_Clause);
5656

5757
With_Node : constant Libadalang.Analysis.Ada_Node :=
58-
Libadalang.Iterators.Find_First
59-
(Node.Unit.Root, Has_With_Clause_Node'Unrestricted_Access);
58+
(if Node.Is_Null then Node
59+
else Libadalang.Iterators.Find_First
60+
(Node.Unit.Root, Has_With_Clause_Node'Unrestricted_Access));
6061
begin
6162
-- Return immediately if we don't have any with-clause node on the same
6263
-- line or if we are still within the with-clause node.

source/ada/lsp-ada_completions.adb

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,23 @@ package body LSP.Ada_Completions is
5353
------------------
5454

5555
function Is_End_Token
56-
(Token : Libadalang.Common.Token_Reference)
57-
return Boolean
56+
(Token : Libadalang.Common.Token_Reference) return Boolean
5857
is
5958
use Libadalang.Common;
60-
End_Token : constant Libadalang.Common.Token_Data_Type :=
61-
Libadalang.Common.Data (Token);
62-
63-
Token_Kind : constant Libadalang.Common.Token_Kind :=
64-
Libadalang.Common.Kind (End_Token);
6559
begin
66-
return Token_Kind = Libadalang.Common.Ada_End;
60+
if Token = No_Token then
61+
return False;
62+
end if;
63+
64+
declare
65+
End_Token : constant Libadalang.Common.Token_Data_Type :=
66+
Libadalang.Common.Data (Token);
67+
68+
Token_Kind : constant Libadalang.Common.Token_Kind :=
69+
Libadalang.Common.Kind (End_Token);
70+
begin
71+
return Token_Kind = Libadalang.Common.Ada_End;
72+
end;
6773
end Is_End_Token;
6874

6975
------------------------

source/ada/lsp-ada_handlers-invisibles.adb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ package body LSP.Ada_Handlers.Invisibles is
4040
is
4141
pragma Unreferenced (Result);
4242
use all type Libadalang.Common.Token_Kind;
43+
use all type Libadalang.Common.Token_Reference;
4344
use type Ada.Containers.Count_Type;
4445

4546
procedure On_Inaccessible_Name
@@ -78,10 +79,13 @@ package body LSP.Ada_Handlers.Invisibles is
7879
end if;
7980
end On_Inaccessible_Name;
8081

81-
Dot_Token : constant Libadalang.Common.Token_Data_Type :=
82+
Previous_Tok : constant Libadalang.Common.Token_Reference :=
83+
Libadalang.Common.Previous (Token, Exclude_Trivia => True);
84+
Dot_Token : constant Libadalang.Common.Token_Data_Type :=
8285
Libadalang.Common.Data
8386
(if Libadalang.Common.Is_Trivia (Token)
84-
then Libadalang.Common.Previous (Token, True)
87+
and then Previous_Tok /= Libadalang.Common.No_Token
88+
then Previous_Tok
8589
else Token);
8690

8791
function Dummy_Canceled return Boolean is (False);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
project Default is
2+
end Default;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
with Ada.Text_IO;
3+
4+
procedure Main is
5+
begin
6+
Ada.Text_IO.Put_Line ("Hello");
7+
end Main;
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
[
2+
{
3+
"comment": ["Check that completion does not crash on file's first token."]
4+
},
5+
{
6+
"start": {
7+
"cmd": ["${ALS}"]
8+
}
9+
},
10+
{
11+
"send": {
12+
"request": {
13+
"jsonrpc": "2.0",
14+
"id": 1,
15+
"method": "initialize",
16+
"params": {
17+
"processId": 257038,
18+
"rootUri": "$URI{.}",
19+
"capabilities": {
20+
"workspace": {
21+
"applyEdit": true,
22+
"workspaceEdit": {
23+
"documentChanges": true,
24+
"resourceOperations": ["rename"]
25+
}
26+
},
27+
"textDocument": {
28+
"synchronization": {},
29+
"completion": {
30+
"dynamicRegistration": true,
31+
"completionItem": {
32+
"snippetSupport": false,
33+
"documentationFormat": ["plaintext", "markdown"],
34+
"resolveSupport": {
35+
"properties": ["detail", "documentation"]
36+
}
37+
}
38+
},
39+
"hover": {},
40+
"signatureHelp": {},
41+
"declaration": {},
42+
"definition": {},
43+
"typeDefinition": {},
44+
"implementation": {},
45+
"documentSymbol": {
46+
"hierarchicalDocumentSymbolSupport": true
47+
},
48+
"formatting": {
49+
"dynamicRegistration": false
50+
},
51+
"rangeFormatting": {
52+
"dynamicRegistration": false
53+
},
54+
"onTypeFormatting": {
55+
"dynamicRegistration": false
56+
},
57+
"foldingRange": {
58+
"lineFoldingOnly": true
59+
}
60+
},
61+
"experimental": {
62+
"advanced_refactorings": ["add_parameter"]
63+
}
64+
}
65+
}
66+
},
67+
"wait": [
68+
{
69+
"id": 1,
70+
"result": {
71+
"capabilities": {
72+
"textDocumentSync": 2,
73+
"completionProvider": {
74+
"triggerCharacters": [".", ",", "'", "("],
75+
"resolveProvider": true
76+
}
77+
}
78+
}
79+
}
80+
]
81+
}
82+
},
83+
{
84+
"send": {
85+
"request": {
86+
"jsonrpc": "2.0",
87+
"method": "initialized"
88+
},
89+
"wait": []
90+
}
91+
},
92+
{
93+
"send": {
94+
"request": {
95+
"jsonrpc": "2.0",
96+
"method": "workspace/didChangeConfiguration",
97+
"params": {
98+
"settings": {
99+
"ada": {
100+
"scenarioVariables": {},
101+
"defaultCharset": "ISO-8859-1",
102+
"enableDiagnostics": true,
103+
"followSymlinks": false,
104+
"documentationStyle": "leading",
105+
"foldComments": false
106+
}
107+
}
108+
}
109+
},
110+
"wait": []
111+
}
112+
},
113+
{
114+
"send": {
115+
"request": {
116+
"jsonrpc": "2.0",
117+
"method": "textDocument/didOpen",
118+
"params": {
119+
"textDocument": {
120+
"uri": "$URI{main.adb}",
121+
"languageId": "Ada",
122+
"version": 0,
123+
"text": "\nwith Ada.Text_IO;\n\nprocedure Main is\nbegin\n Ada.Text_IO.Put_Line (\"Hello\");\nend Main;\n"
124+
}
125+
}
126+
},
127+
"wait": []
128+
}
129+
},
130+
{
131+
"send": {
132+
"request": {
133+
"jsonrpc": "2.0",
134+
"id": 6,
135+
"method": "textDocument/completion",
136+
"params": {
137+
"textDocument": {
138+
"uri": "$URI{main.adb}"
139+
},
140+
"position": {
141+
"line": 0,
142+
"character": 0
143+
},
144+
"context": {
145+
"triggerKind": 1
146+
}
147+
}
148+
},
149+
"wait": [
150+
{
151+
"id": 6,
152+
"result": {
153+
"isIncomplete": false,
154+
"items": []
155+
}
156+
}
157+
]
158+
}
159+
},
160+
{
161+
"send": {
162+
"request": {
163+
"jsonrpc": "2.0",
164+
"method": "textDocument/didClose",
165+
"params": {
166+
"textDocument": {
167+
"uri": "$URI{main.adb}"
168+
}
169+
}
170+
},
171+
"wait": [
172+
{
173+
"method": "textDocument/publishDiagnostics",
174+
"params": {
175+
"uri": "$URI{main.adb}",
176+
"diagnostics": []
177+
}
178+
}
179+
]
180+
}
181+
},
182+
{
183+
"send": {
184+
"request": {
185+
"jsonrpc": "2.0",
186+
"id": 8,
187+
"method": "shutdown"
188+
},
189+
"wait": [
190+
{
191+
"id": 8,
192+
"result": null
193+
}
194+
]
195+
}
196+
},
197+
{
198+
"stop": {
199+
"exit_code": 0
200+
}
201+
}
202+
]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
title: 'completion.first_token'

0 commit comments

Comments
 (0)