1 /**
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "lsp_api_test.h"
17 #include "lsp/include/completions.h"
18 #include "lsp/include/internal_api.h"
19 #include "lsp/include/api.h"
20 #include "lsp/include/completions_details.h"
21 #include "lsp/include/quick_info.h"
22 #include "lsp/include/suggestion_diagnostics.h"
23 #include "compiler/lowering/util.h"
24
25 namespace {
26
27 class LSPCompletionsEntryDetailsTests : public LSPAPITests {};
28
29 using ark::es2panda::lsp::Initializer;
30
TEST_F(LSPCompletionsEntryDetailsTests,GetCompletionEntryDetails0)31 TEST_F(LSPCompletionsEntryDetailsTests, GetCompletionEntryDetails0)
32 {
33 Initializer initializer = Initializer();
34 es2panda_Context *ctx = initializer.CreateContext("completion_entry_details.ets", ES2PANDA_STATE_CHECKED,
35 R"(enum MyStrings { A = 'hello' };)");
36 size_t const offset = 17;
37 LSPAPI const *lspApi = GetImpl();
38 const char *entryName = "MyStrings";
39 auto completionEntryDetails =
40 lspApi->getCompletionEntryDetails(entryName, "completion_entry_details.ets", ctx, offset);
41 ASSERT_NE(completionEntryDetails, CompletionEntryDetails());
42 std::vector<SymbolDisplayPart> source {};
43 std::vector<SymbolDisplayPart> sourceDisplay {};
44 std::vector<SymbolDisplayPart> document {};
45 const std::string kind = "class";
46 const std::string kindModifiers = "final";
47 const std::string expectedFileName = "completion_entry_details.ets";
48
49 std::vector<SymbolDisplayPart> expected;
50 expected.emplace_back("enum", "keyword");
51 expected.emplace_back(" ", "space");
52 expected.emplace_back("MyStrings", "className");
53
54 auto expectedCompletionEntryDetails = CompletionEntryDetails(entryName, kind, kindModifiers, expected, document,
55 source, sourceDisplay, expectedFileName);
56 initializer.DestroyContext(ctx);
57 ASSERT_EQ(completionEntryDetails, expectedCompletionEntryDetails);
58 }
59
TEST_F(LSPCompletionsEntryDetailsTests,GetCompletionEntryDetails1)60 TEST_F(LSPCompletionsEntryDetailsTests, GetCompletionEntryDetails1)
61 {
62 Initializer initializer = Initializer();
63 es2panda_Context *ctx = initializer.CreateContext("completion_entry_details1.ets", ES2PANDA_STATE_CHECKED,
64 "class MyClass {\n public myProp: number = 0;\n}");
65 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
66 size_t const offset = 9;
67 LSPAPI const *lspApi = GetImpl();
68 const char *entryName = "MyClass";
69 const std::string fileName = "completion_entry_details1.ets";
70 auto completionEntryDetails =
71 lspApi->getCompletionEntryDetails(entryName, "completion_entry_details1.ets", ctx, offset);
72 ASSERT_NE(completionEntryDetails, CompletionEntryDetails());
73 std::vector<SymbolDisplayPart> source {};
74 std::vector<SymbolDisplayPart> sourceDisplay {};
75 std::vector<SymbolDisplayPart> document {};
76 const std::string kind = "class";
77 const std::string kindModifiers;
78 const std::string expectedFileName = "completion_entry_details1.ets";
79
80 std::vector<SymbolDisplayPart> expected;
81 expected.emplace_back("class", "keyword");
82 expected.emplace_back(" ", "space");
83 expected.emplace_back("MyClass", "className");
84
85 auto expectedCompletionEntryDetails = CompletionEntryDetails(entryName, kind, kindModifiers, expected, document,
86 source, sourceDisplay, expectedFileName);
87 ASSERT_EQ(completionEntryDetails, expectedCompletionEntryDetails);
88
89 initializer.DestroyContext(ctx);
90 }
91
TEST_F(LSPCompletionsEntryDetailsTests,GetCompletionEntryDetails2)92 TEST_F(LSPCompletionsEntryDetailsTests, GetCompletionEntryDetails2)
93 {
94 Initializer initializer = Initializer();
95 es2panda_Context *ctx =
96 initializer.CreateContext("completion_entry_details2.ets", ES2PANDA_STATE_CHECKED,
97 "interface objI { key : string; }\nlet obj : objI = { key:\"valueaaaaaaaaa,\" }");
98 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
99 size_t const offset = 7;
100 LSPAPI const *lspApi = GetImpl();
101 const char *entryName = "objI";
102 const std::string fileName = "completion_entry_details2.ets";
103 auto completionEntryDetails =
104 lspApi->getCompletionEntryDetails(entryName, "completion_entry_details2.ets", ctx, offset);
105 ASSERT_NE(completionEntryDetails, CompletionEntryDetails());
106 std::vector<SymbolDisplayPart> source {};
107 std::vector<SymbolDisplayPart> sourceDisplay {};
108 std::vector<SymbolDisplayPart> document {};
109 const std::string kind = "interface";
110 const std::string kindModifiers = "static public";
111 const std::string expectedFileName = "completion_entry_details2.ets";
112 std::vector<SymbolDisplayPart> expected;
113
114 expected.emplace_back("interface", "keyword");
115 expected.emplace_back(" ", "space");
116 expected.emplace_back("objI", "className");
117
118 auto expectedCompletionEntryDetails = CompletionEntryDetails(entryName, kind, kindModifiers, expected, document,
119 source, sourceDisplay, expectedFileName);
120 ASSERT_EQ(completionEntryDetails, expectedCompletionEntryDetails);
121
122 initializer.DestroyContext(ctx);
123 }
124
TEST_F(LSPCompletionsEntryDetailsTests,GetCompletionEntryDetails3)125 TEST_F(LSPCompletionsEntryDetailsTests, GetCompletionEntryDetails3)
126 {
127 Initializer initializer = Initializer();
128 es2panda_Context *ctx = initializer.CreateContext("completion_entry_details9.ets", ES2PANDA_STATE_CHECKED,
129 R"(function name (params: string) {
130 new CC().getName()
131 }
132
133 class CC {
134 getName() {
135 }
136 })");
137 size_t const offset = 79;
138 LSPAPI const *lspApi = GetImpl();
139 const char *entryName = "getName";
140 auto completionEntryDetails =
141 lspApi->getCompletionEntryDetails(entryName, "completion_entry_details9.ets", ctx, offset);
142 ASSERT_NE(completionEntryDetails, CompletionEntryDetails());
143 std::vector<SymbolDisplayPart> source {};
144 std::vector<SymbolDisplayPart> sourceDisplay {};
145 std::vector<SymbolDisplayPart> document {};
146 const std::string kind = "function";
147 const std::string kindModifiers = "public";
148 const std::string expectedFileName = "completion_entry_details9.ets";
149
150 std::vector<SymbolDisplayPart> expected;
151 expected.emplace_back("CC", "className");
152 expected.emplace_back(".", "punctuation");
153 expected.emplace_back("getName", "functionName");
154 expected.emplace_back("(", "punctuation");
155 expected.emplace_back(")", "punctuation");
156 expected.emplace_back(":", "punctuation");
157 expected.emplace_back(" ", "space");
158 expected.emplace_back("void", "returnType");
159
160 auto expectedCompletionEntryDetails = CompletionEntryDetails(entryName, kind, kindModifiers, expected, document,
161 source, sourceDisplay, expectedFileName);
162 initializer.DestroyContext(ctx);
163 ASSERT_EQ(completionEntryDetails, expectedCompletionEntryDetails);
164 }
165
TEST_F(LSPCompletionsEntryDetailsTests,GetCompletionEntryDetails4)166 TEST_F(LSPCompletionsEntryDetailsTests, GetCompletionEntryDetails4)
167 {
168 Initializer initializer = Initializer();
169 es2panda_Context *ctx = initializer.CreateContext("completion_entry_details10.ets", ES2PANDA_STATE_CHECKED,
170 R"(interface DuttonInterface {
171 ff(): number;
172 }
173
174 declare const Dutton: DuttonInterface;)");
175 size_t const offset = 66;
176 LSPAPI const *lspApi = GetImpl();
177 const char *entryName = "Dutton";
178 auto completionEntryDetails =
179 lspApi->getCompletionEntryDetails(entryName, "completion_entry_details10.ets", ctx, offset);
180 ASSERT_NE(completionEntryDetails, CompletionEntryDetails());
181 std::vector<SymbolDisplayPart> source {};
182 std::vector<SymbolDisplayPart> sourceDisplay {};
183 std::vector<SymbolDisplayPart> document {};
184 const std::string kind = "property";
185 const std::string kindModifiers = "static public declare const";
186 const std::string expectedFileName = "completion_entry_details10.ets";
187
188 std::vector<SymbolDisplayPart> expected;
189 expected.emplace_back("const", "keyword");
190 expected.emplace_back(" ", "space");
191 expected.emplace_back("Dutton", "property");
192 expected.emplace_back(":", "punctuation");
193 expected.emplace_back(" ", "space");
194 expected.emplace_back("DuttonInterface", "typeName");
195
196 auto expectedCompletionEntryDetails = CompletionEntryDetails(entryName, kind, kindModifiers, expected, document,
197 source, sourceDisplay, expectedFileName);
198 initializer.DestroyContext(ctx);
199 ASSERT_EQ(completionEntryDetails, expectedCompletionEntryDetails);
200 }
201
TEST_F(LSPCompletionsEntryDetailsTests,GetCompletionEntryDetails5)202 TEST_F(LSPCompletionsEntryDetailsTests, GetCompletionEntryDetails5)
203 {
204 Initializer initializer = Initializer();
205 es2panda_Context *ctx = initializer.CreateContext("completion_entry_details11.ets", ES2PANDA_STATE_CHECKED,
206 R"(class DuttonInterface {
207 ff : number;
208 constructor(ff:number) {
209 this.ff = ff;
210 }
211 static buttonRun(value: string | number | boolean):number{
212 return 1;
213 }
214 }
215
216 function aa() {
217 let Dutton: DuttonInterface = new DuttonInterface(1);
218 let a = DuttonInterface.buttonRun(1)
219 })");
220 size_t const offset = 280;
221 LSPAPI const *lspApi = GetImpl();
222 const char *entryName = "buttonRun";
223 auto completionEntryDetails =
224 lspApi->getCompletionEntryDetails(entryName, "completion_entry_details11.ets", ctx, offset);
225 ASSERT_NE(completionEntryDetails, CompletionEntryDetails());
226 std::vector<SymbolDisplayPart> source {};
227 std::vector<SymbolDisplayPart> sourceDisplay {};
228 std::vector<SymbolDisplayPart> document {};
229 const std::string kind = "function";
230 const std::string kindModifiers = "static public";
231 const std::string expectedFileName = "completion_entry_details11.ets";
232
233 std::vector<SymbolDisplayPart> expected;
234 expected.emplace_back("DuttonInterface", "className");
235 expected.emplace_back(".", "punctuation");
236 expected.emplace_back("buttonRun", "functionName");
237 expected.emplace_back("(", "punctuation");
238 expected.emplace_back("value", "functionParameter");
239 expected.emplace_back(":", "punctuation");
240 expected.emplace_back(" ", "space");
241 expected.emplace_back("string|number|boolean", "typeParameter");
242 expected.emplace_back(")", "punctuation");
243 expected.emplace_back(":", "punctuation");
244 expected.emplace_back(" ", "space");
245 expected.emplace_back("number", "returnType");
246
247 auto expectedCompletionEntryDetails = CompletionEntryDetails(entryName, kind, kindModifiers, expected, document,
248 source, sourceDisplay, expectedFileName);
249 initializer.DestroyContext(ctx);
250 ASSERT_EQ(completionEntryDetails, expectedCompletionEntryDetails);
251 }
252
TEST_F(LSPCompletionsEntryDetailsTests,CreateDisplayForClass)253 TEST_F(LSPCompletionsEntryDetailsTests, CreateDisplayForClass)
254 {
255 Initializer initializer = Initializer();
256 es2panda_Context *ctx =
257 initializer.CreateContext("completion_entry_details3.ets", ES2PANDA_STATE_CHECKED,
258 "class Test {\n private _a: number = 1;\n public get a(): number {\n "
259 "return this._a;\n }\n public static ccc:number = 1\n\n constructor(a : "
260 "number) {\n }\n}\n\nlet a = 1\nlet test: Test = new Test(a)\nlet t_a = test.a");
261 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
262 const char *entryName = "Test";
263 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
264 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
265 auto checkFunc = [entryName](ark::es2panda::ir::AstNode *node) {
266 return ark::es2panda::lsp::HasPropertyAccessExpressionWithName(node, entryName);
267 };
268 auto found = ast->FindChild(checkFunc);
269 auto targetNode = ark::es2panda::compiler::DeclarationFromIdentifier(found->AsIdentifier());
270 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForClass(targetNode);
271 std::vector<SymbolDisplayPart> expected;
272 auto keyword1 = SymbolDisplayPart("class", "keyword");
273 auto keyword2 = SymbolDisplayPart(" ", "space");
274 auto keyword3 = SymbolDisplayPart("Test", "className");
275 expected.push_back(keyword1);
276 expected.push_back(keyword2);
277 expected.push_back(keyword3);
278 ASSERT_EQ(expected, display);
279 initializer.DestroyContext(ctx);
280 }
281
TEST_F(LSPCompletionsEntryDetailsTests,CreateDisplayForClassDeclarationTypeParameter)282 TEST_F(LSPCompletionsEntryDetailsTests, CreateDisplayForClassDeclarationTypeParameter)
283 {
284 Initializer initializer = Initializer();
285 es2panda_Context *ctx = initializer.CreateContext("completion_entry_details4.ets", ES2PANDA_STATE_CHECKED,
286 "class Queue<T> { private items: T[] = []; }");
287 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
288 const char *entryName = "T";
289 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
290 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
291 auto checkFunc = [entryName](ark::es2panda::ir::AstNode *node) {
292 return ark::es2panda::lsp::HasPropertyAccessExpressionWithName(node, entryName);
293 };
294 auto found = ast->FindChild(checkFunc);
295 auto targetNode = ark::es2panda::compiler::DeclarationFromIdentifier(found->AsIdentifier());
296 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForTypeParameter(targetNode);
297 std::vector<SymbolDisplayPart> expected;
298 expected.emplace_back("T", "typeParameter");
299 expected.emplace_back(" ", "space");
300 expected.emplace_back("in", "keyword");
301 expected.emplace_back(" ", "space");
302 expected.emplace_back("Queue", "className");
303 expected.emplace_back("<", "punctuation");
304 expected.emplace_back("T", "typeParameter");
305 expected.emplace_back(">", "punctuation");
306 ASSERT_EQ(expected, display);
307 initializer.DestroyContext(ctx);
308 }
309
TEST_F(LSPCompletionsEntryDetailsTests,CreateDisplayForUnionTypeAlias)310 TEST_F(LSPCompletionsEntryDetailsTests, CreateDisplayForUnionTypeAlias)
311 {
312 Initializer initializer = Initializer();
313 es2panda_Context *ctx = initializer.CreateContext("completion_entry_details5.ets", ES2PANDA_STATE_CHECKED,
314 "type TestUnion = string | number;");
315 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
316 const char *entryName = "TestUnion";
317 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
318 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
319 auto checkFunc = [entryName](ark::es2panda::ir::AstNode *node) {
320 return ark::es2panda::lsp::HasPropertyAccessExpressionWithName(node, entryName);
321 };
322 auto found = ast->FindChild(checkFunc);
323 auto targetNode = ark::es2panda::compiler::DeclarationFromIdentifier(found->AsIdentifier());
324 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForTypeAlias(targetNode);
325 std::vector<SymbolDisplayPart> expected;
326 expected.emplace_back("type", "keyword");
327 expected.emplace_back(" ", "space");
328 expected.emplace_back("TestUnion", "className");
329 expected.emplace_back(" ", "space");
330 expected.emplace_back("=", "operator");
331 expected.emplace_back(" ", "space");
332 expected.emplace_back("string|number", "typeName");
333 ASSERT_EQ(expected, display);
334 initializer.DestroyContext(ctx);
335 }
336
TEST_F(LSPCompletionsEntryDetailsTests,CreateDisplayForTypeAlias)337 TEST_F(LSPCompletionsEntryDetailsTests, CreateDisplayForTypeAlias)
338 {
339 Initializer initializer = Initializer();
340 es2panda_Context *ctx =
341 initializer.CreateContext("completion_entry_details6.ets", ES2PANDA_STATE_CHECKED, "type TestType = string;");
342 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
343 const char *entryName = "TestType";
344 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
345 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
346 auto checkFunc = [entryName](ark::es2panda::ir::AstNode *node) {
347 return ark::es2panda::lsp::HasPropertyAccessExpressionWithName(node, entryName);
348 };
349 auto found = ast->FindChild(checkFunc);
350 auto targetNode = ark::es2panda::compiler::DeclarationFromIdentifier(found->AsIdentifier());
351 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForTypeAlias(targetNode);
352 std::vector<SymbolDisplayPart> expected;
353 expected.emplace_back("type", "keyword");
354 expected.emplace_back(" ", "space");
355 expected.emplace_back("TestType", "className");
356 expected.emplace_back(" ", "space");
357 expected.emplace_back("=", "operator");
358 expected.emplace_back(" ", "space");
359 expected.emplace_back("string", "typeName");
360 ASSERT_EQ(expected, display);
361 initializer.DestroyContext(ctx);
362 }
363
TEST_F(LSPCompletionsEntryDetailsTests,CreateDisplayForInterface)364 TEST_F(LSPCompletionsEntryDetailsTests, CreateDisplayForInterface)
365 {
366 Initializer initializer = Initializer();
367 es2panda_Context *ctx = initializer.CreateContext(
368 "completion_entry_details7.ets", ES2PANDA_STATE_CHECKED,
369 "interface Inner { key : string; }\ninterface Outer { inner : Inner; keyValue : number; }");
370 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
371 const char *entryName = "Inner";
372 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
373 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
374 auto checkFunc = [entryName](ark::es2panda::ir::AstNode *node) {
375 return ark::es2panda::lsp::HasPropertyAccessExpressionWithName(node, entryName);
376 };
377 auto found = ast->FindChild(checkFunc);
378 auto targetNode = ark::es2panda::compiler::DeclarationFromIdentifier(found->AsIdentifier());
379 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForInterface(targetNode);
380 std::vector<SymbolDisplayPart> expected;
381 auto keyword1 = SymbolDisplayPart("interface", "keyword");
382 auto keyword2 = SymbolDisplayPart(" ", "space");
383 auto keyword3 = SymbolDisplayPart("Inner", "className");
384 expected.push_back(keyword1);
385 expected.push_back(keyword2);
386 expected.push_back(keyword3);
387 ASSERT_EQ(expected, display);
388 initializer.DestroyContext(ctx);
389 }
390
TEST_F(LSPCompletionsEntryDetailsTests,CreateDisplayForTypeAliasTypeParameter)391 TEST_F(LSPCompletionsEntryDetailsTests, CreateDisplayForTypeAliasTypeParameter)
392 {
393 Initializer initializer = Initializer();
394 es2panda_Context *ctx =
395 initializer.CreateContext("completion_entry_details8.ets", ES2PANDA_STATE_CHECKED, "type list<T> = T[]");
396 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
397 const char *entryName = "T";
398 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
399 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
400 auto checkFunc = [entryName](ark::es2panda::ir::AstNode *node) {
401 return ark::es2panda::lsp::HasPropertyAccessExpressionWithName(node, entryName);
402 };
403 auto found = ast->FindChild(checkFunc);
404 auto targetNode = ark::es2panda::compiler::DeclarationFromIdentifier(found->AsIdentifier());
405 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForTypeParameter(targetNode);
406 std::vector<SymbolDisplayPart> expected;
407 expected.emplace_back("T", "typeParameter");
408 expected.emplace_back(" ", "space");
409 expected.emplace_back("in", "keyword");
410 expected.emplace_back(" ", "space");
411 expected.emplace_back("type", "keyword");
412 expected.emplace_back(" ", "space");
413 expected.emplace_back("list", "typeName");
414 expected.emplace_back("<", "punctuation");
415 expected.emplace_back("T", "typeParameter");
416 expected.emplace_back(">", "punctuation");
417 ASSERT_EQ(expected, display);
418 initializer.DestroyContext(ctx);
419 }
420
421 } // namespace