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/include/quick_info.h"
17 #include "lsp_api_test.h"
18 #include "lsp/include/internal_api.h"
19 #include <gtest/gtest.h>
20 namespace {
21 using ark::es2panda::lsp::Initializer;
22
23 class LspQuickInfoTests : public LSPAPITests {};
24
TEST_F(LspQuickInfoTests,CreateDisplayForEnum)25 TEST_F(LspQuickInfoTests, CreateDisplayForEnum)
26 {
27 Initializer initializer = Initializer();
28 es2panda_Context *ctx =
29 initializer.CreateContext("enum-test.ets", ES2PANDA_STATE_CHECKED, "enum MyEnum { A, B, C }");
30 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
31 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
32 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
33 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
34 return node->Type() == ark::es2panda::ir::AstNodeType::CLASS_DEFINITION &&
35 node->AsClassDefinition()->Ident()->Name() == "MyEnum";
36 };
37 auto found = ast->FindChild(checkFunc);
38 auto enumDecl = found->AsClassDefinition()->OrigEnumDecl()->AsTSEnumDeclaration();
39 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForEnum(enumDecl);
40 std::vector<SymbolDisplayPart> expected;
41 expected.emplace_back("enum", "keyword");
42 expected.emplace_back(" ", "space");
43 expected.emplace_back("MyEnum", "enumName");
44 ASSERT_EQ(expected, display);
45 initializer.DestroyContext(ctx);
46 }
47
TEST_F(LspQuickInfoTests,CreateDisplayForClass1)48 TEST_F(LspQuickInfoTests, CreateDisplayForClass1)
49 {
50 Initializer initializer = Initializer();
51 es2panda_Context *ctx =
52 initializer.CreateContext("quick-info-test.ets", ES2PANDA_STATE_CHECKED,
53 "class Test {\n private _a: number = 1;\n public get a(): number {\n "
54 "return this._a;\n }\n public static ccc:number = 1\n\n constructor(a : "
55 "number) {\n }\n}\n\nlet a = 1\nlet test: Test = new Test(a)\nlet t_a = test.a");
56 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
57 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
58 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
59 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
60 return node->Type() == ark::es2panda::ir::AstNodeType::CLASS_DECLARATION &&
61 node->AsClassDeclaration()->Definition()->InternalName() != "quick-info-test.ETSGLOBAL";
62 };
63 auto found = ast->FindChild(checkFunc);
64 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForClass(found);
65 std::vector<SymbolDisplayPart> expected;
66 auto keyword1 = SymbolDisplayPart("class", "keyword");
67 auto keyword2 = SymbolDisplayPart(" ", "space");
68 auto keyword3 = SymbolDisplayPart("Test", "className");
69 expected.push_back(keyword1);
70 expected.push_back(keyword2);
71 expected.push_back(keyword3);
72 ASSERT_EQ(expected, display);
73 initializer.DestroyContext(ctx);
74 }
75
TEST_F(LspQuickInfoTests,CreateDisplayForUnionTypeAlias)76 TEST_F(LspQuickInfoTests, CreateDisplayForUnionTypeAlias)
77 {
78 Initializer initializer = Initializer();
79 es2panda_Context *ctx = initializer.CreateContext("union-type-alias-test.ets", ES2PANDA_STATE_CHECKED,
80 "type TestUnion = string | number;");
81 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
82 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
83 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
84 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
85 return node->Type() == ark::es2panda::ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION;
86 };
87 auto found = ast->FindChild(checkFunc);
88 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForTypeAlias(found);
89 std::vector<SymbolDisplayPart> expected;
90 expected.emplace_back("type", "keyword");
91 expected.emplace_back(" ", "space");
92 expected.emplace_back("TestUnion", "className");
93 expected.emplace_back(" ", "space");
94 expected.emplace_back("=", "operator");
95 expected.emplace_back(" ", "space");
96 expected.emplace_back("string|number", "typeName");
97 ASSERT_EQ(expected, display);
98 initializer.DestroyContext(ctx);
99 }
100
TEST_F(LspQuickInfoTests,CreateDisplayForTypeAlias)101 TEST_F(LspQuickInfoTests, CreateDisplayForTypeAlias)
102 {
103 Initializer initializer = Initializer();
104 es2panda_Context *ctx =
105 initializer.CreateContext("type-alias-test.ets", ES2PANDA_STATE_CHECKED, "type TestType = string;");
106 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
107 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
108 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
109 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
110 return node->Type() == ark::es2panda::ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION;
111 };
112 auto found = ast->FindChild(checkFunc);
113 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForTypeAlias(found);
114 std::vector<SymbolDisplayPart> expected;
115 expected.emplace_back("type", "keyword");
116 expected.emplace_back(" ", "space");
117 expected.emplace_back("TestType", "className");
118 expected.emplace_back(" ", "space");
119 expected.emplace_back("=", "operator");
120 expected.emplace_back(" ", "space");
121 expected.emplace_back("string", "typeName");
122 ASSERT_EQ(expected, display);
123 initializer.DestroyContext(ctx);
124 }
125
TEST_F(LspQuickInfoTests,CreateDisplayForInterface)126 TEST_F(LspQuickInfoTests, CreateDisplayForInterface)
127 {
128 Initializer initializer = Initializer();
129 es2panda_Context *ctx = initializer.CreateContext(
130 "quick-info-test.ets", ES2PANDA_STATE_CHECKED,
131 "interface Inner { key : string; }\ninterface Outer { inner : Inner; keyValue : number; }");
132 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
133 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
134 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
135 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
136 return node->Type() == ark::es2panda::ir::AstNodeType::TS_INTERFACE_DECLARATION;
137 };
138 auto found = ast->FindChild(checkFunc);
139 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForInterface(found);
140 std::vector<SymbolDisplayPart> expected;
141 auto keyword1 = SymbolDisplayPart("interface", "keyword");
142 auto keyword2 = SymbolDisplayPart(" ", "space");
143 auto keyword3 = SymbolDisplayPart("Inner", "className");
144 expected.push_back(keyword1);
145 expected.push_back(keyword2);
146 expected.push_back(keyword3);
147 ASSERT_EQ(expected, display);
148 initializer.DestroyContext(ctx);
149 }
150
TEST_F(LspQuickInfoTests,CreateDisplayForTypeAliasTypeParameter)151 TEST_F(LspQuickInfoTests, CreateDisplayForTypeAliasTypeParameter)
152 {
153 Initializer initializer = Initializer();
154 es2panda_Context *ctx =
155 initializer.CreateContext("type-alias-type-param-test.ets", ES2PANDA_STATE_CHECKED, "type list<T> = T[]");
156 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
157 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
158 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
159 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
160 return node->Type() == ark::es2panda::ir::AstNodeType::TS_TYPE_PARAMETER;
161 };
162 auto found = ast->FindChild(checkFunc);
163 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForTypeParameter(found);
164 std::vector<SymbolDisplayPart> expected;
165 expected.emplace_back("T", "typeParameter");
166 expected.emplace_back(" ", "space");
167 expected.emplace_back("in", "keyword");
168 expected.emplace_back(" ", "space");
169 expected.emplace_back("type", "keyword");
170 expected.emplace_back(" ", "space");
171 expected.emplace_back("list", "typeName");
172 expected.emplace_back("<", "punctuation");
173 expected.emplace_back("T", "typeParameter");
174 expected.emplace_back(">", "punctuation");
175 ASSERT_EQ(expected, display);
176 initializer.DestroyContext(ctx);
177 }
178
TEST_F(LspQuickInfoTests,CreateDisplayForClassDeclarationTypeParameter)179 TEST_F(LspQuickInfoTests, CreateDisplayForClassDeclarationTypeParameter)
180 {
181 Initializer initializer = Initializer();
182 es2panda_Context *ctx = initializer.CreateContext("class-type-param-test.ets", ES2PANDA_STATE_CHECKED,
183 "class Queue<T> { private items: T[] = []; }");
184 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
185 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
186 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
187 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
188 return node->Type() == ark::es2panda::ir::AstNodeType::TS_TYPE_PARAMETER;
189 };
190 auto found = ast->FindChild(checkFunc);
191 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForTypeParameter(found);
192 std::vector<SymbolDisplayPart> expected;
193 expected.emplace_back("T", "typeParameter");
194 expected.emplace_back(" ", "space");
195 expected.emplace_back("in", "keyword");
196 expected.emplace_back(" ", "space");
197 expected.emplace_back("Queue", "className");
198 expected.emplace_back("<", "punctuation");
199 expected.emplace_back("T", "typeParameter");
200 expected.emplace_back(">", "punctuation");
201 ASSERT_EQ(expected, display);
202 initializer.DestroyContext(ctx);
203 }
204
TEST_F(LspQuickInfoTests,CreateDisplayForMethodDefinition)205 TEST_F(LspQuickInfoTests, CreateDisplayForMethodDefinition)
206 {
207 Initializer initializer = Initializer();
208 es2panda_Context *ctx = initializer.CreateContext("method-definition-test.ets", ES2PANDA_STATE_CHECKED,
209 "function func(a: number): string { return 'function1'; }");
210 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
211 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
212 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
213 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
214 return node->Type() == ark::es2panda::ir::AstNodeType::METHOD_DEFINITION &&
215 node->AsMethodDefinition()->Id()->Name() != "main" &&
216 node->AsMethodDefinition()->Id()->Name() != "_$init$_";
217 };
218 auto found = ast->FindChild(checkFunc);
219 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForMethodDefinition(found, "");
220 std::vector<SymbolDisplayPart> expected;
221
222 // Expected parts for the method definition
223 expected.emplace_back("function", "keyword");
224 expected.emplace_back(" ", "space");
225 expected.emplace_back("func", "functionName");
226 expected.emplace_back("(", "punctuation");
227 expected.emplace_back("a", "functionParameter");
228 expected.emplace_back(":", "punctuation");
229 expected.emplace_back(" ", "space");
230 expected.emplace_back("number", "typeParameter");
231 expected.emplace_back(")", "punctuation");
232 expected.emplace_back(":", "punctuation");
233 expected.emplace_back(" ", "space");
234 expected.emplace_back("string", "returnType");
235
236 ASSERT_EQ(expected, display);
237 initializer.DestroyContext(ctx);
238 }
239
TEST_F(LspQuickInfoTests,CreateDisplayForScriptFunctionTypeParameter)240 TEST_F(LspQuickInfoTests, CreateDisplayForScriptFunctionTypeParameter)
241 {
242 Initializer initializer = Initializer();
243 es2panda_Context *ctx = initializer.CreateContext("function-type-param-test.ets", ES2PANDA_STATE_CHECKED,
244 "function identity<T, D>(arg: T): T { return arg }");
245 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
246 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
247 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
248 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
249 return node->Type() == ark::es2panda::ir::AstNodeType::TS_TYPE_PARAMETER;
250 };
251 auto found = ast->FindChild(checkFunc);
252 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForTypeParameter(found);
253 std::vector<SymbolDisplayPart> expected;
254 expected.emplace_back("T", "typeParameter");
255 expected.emplace_back(" ", "space");
256 expected.emplace_back("in", "keyword");
257 expected.emplace_back(" ", "space");
258 expected.emplace_back("identity", "functionName");
259 expected.emplace_back("<", "punctuation");
260 expected.emplace_back("T", "typeParameter");
261 expected.emplace_back(",", "punctuation");
262 expected.emplace_back(" ", "space");
263 expected.emplace_back("D", "typeParameter");
264 expected.emplace_back(">", "punctuation");
265 expected.emplace_back("(", "punctuation");
266 expected.emplace_back("arg", "functionParameter");
267 expected.emplace_back(":", "punctuation");
268 expected.emplace_back(" ", "space");
269 expected.emplace_back("T", "typeParameter");
270 expected.emplace_back(")", "punctuation");
271 expected.emplace_back(":", "punctuation");
272 expected.emplace_back(" ", "space");
273 expected.emplace_back("T", "returnType");
274 ASSERT_EQ(expected, display);
275 initializer.DestroyContext(ctx);
276 }
277
TEST_F(LspQuickInfoTests,CreateDisplayForClassProperty1)278 TEST_F(LspQuickInfoTests, CreateDisplayForClassProperty1)
279 {
280 Initializer initializer = Initializer();
281 es2panda_Context *ctx =
282 initializer.CreateContext("class-property-test.ets", ES2PANDA_STATE_CHECKED,
283 "class MyClass {\n public myProp: number = 0;\n}\n let obj = new MyClass();");
284 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
285 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
286 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
287 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
288 return node->Type() == ark::es2panda::ir::AstNodeType::CLASS_PROPERTY &&
289 node->AsClassProperty()->Key()->AsIdentifier()->Name() != "ETSGLOBAL";
290 };
291 auto found = ast->FindChild(checkFunc);
292 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForClassProperty(found, "const");
293 std::vector<SymbolDisplayPart> expected;
294
295 expected.emplace_back("const", "keyword");
296 expected.emplace_back(" ", "space");
297 expected.emplace_back("obj", "property");
298 expected.emplace_back(":", "punctuation");
299 expected.emplace_back(" ", "space");
300 expected.emplace_back("MyClass", "typeName");
301
302 ASSERT_EQ(expected, display);
303 initializer.DestroyContext(ctx);
304 }
305
TEST_F(LspQuickInfoTests,CreateDisplayForClassProperty2)306 TEST_F(LspQuickInfoTests, CreateDisplayForClassProperty2)
307 {
308 Initializer initializer = Initializer();
309 es2panda_Context *ctx = initializer.CreateContext("class-property-test.ets", ES2PANDA_STATE_CHECKED,
310 "class MyClass {\n public myProp: number = 0;\n}");
311 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
312 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
313 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
314 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
315 return node->Type() == ark::es2panda::ir::AstNodeType::CLASS_PROPERTY &&
316 node->AsClassProperty()->Key()->AsIdentifier()->Name() != "ETSGLOBAL";
317 };
318 auto found = ast->FindChild(checkFunc);
319 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForClassProperty(found, "const");
320 std::vector<SymbolDisplayPart> expected;
321
322 expected.emplace_back("MyClass", "className");
323 expected.emplace_back(".", "punctuation");
324 expected.emplace_back("myProp", "property");
325 expected.emplace_back(":", "punctuation");
326 expected.emplace_back(" ", "space");
327 expected.emplace_back("number", "typeName");
328
329 ASSERT_EQ(expected, display);
330 initializer.DestroyContext(ctx);
331 }
332
TEST_F(LspQuickInfoTests,CreateDisplayForParameterExpression)333 TEST_F(LspQuickInfoTests, CreateDisplayForParameterExpression)
334 {
335 Initializer initializer = Initializer();
336 es2panda_Context *ctx = initializer.CreateContext("parameter-expression-test.ets", ES2PANDA_STATE_CHECKED,
337 "function func(param1: string, param2: number) {}");
338 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
339 auto context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
340 auto ast = reinterpret_cast<ark::es2panda::ir::AstNode *>(context->parserProgram->Ast());
341 auto checkFunc = [](ark::es2panda::ir::AstNode *node) {
342 return node->Type() == ark::es2panda::ir::AstNodeType::ETS_PARAMETER_EXPRESSION &&
343 node->AsETSParameterExpression()->Name() != "param2";
344 };
345 auto found = ast->FindChild(checkFunc);
346 std::vector<SymbolDisplayPart> display = ark::es2panda::lsp::CreateDisplayForETSParameterExpression(found);
347 std::vector<SymbolDisplayPart> expected;
348
349 expected.emplace_back("param1", "functionParameter");
350 expected.emplace_back(":", "punctuation");
351 expected.emplace_back(" ", "space");
352 expected.emplace_back("string", "typeName");
353
354 ASSERT_EQ(expected, display);
355 initializer.DestroyContext(ctx);
356 }
357 } // namespace