• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/get_adjusted_location.h"
17 #include "gtest/gtest.h"
18 #include "lsp_api_test.h"
19 #include "public/es2panda_lib.h"
20 #include "test/utils/ast_verifier_test.h"
21 #include "lsp/include/internal_api.h"
22 
23 using ark::es2panda::ir::AstNode;
24 using ark::es2panda::ir::AstNodeType;
25 
26 namespace {
27 constexpr size_t PROPERTY_POS = 23;
28 constexpr size_t FUNCTION_POS = 10;
29 constexpr size_t PRIVATE_POS = 25;
30 constexpr size_t PUBLIC_POS = 47;
31 constexpr size_t STATIC_POS = 69;
32 constexpr size_t CLASS_POS = 6;
33 constexpr size_t METHOD_POS = 23;
34 constexpr size_t VARIABLE_POS = 5;
35 constexpr size_t MEMBER_POS = 28;
36 constexpr size_t TYPE_PARAM_POS = 7;
37 constexpr size_t ARRAY_TYPE_POS = 25;
38 constexpr size_t HERITAGE_POS = 45;
39 constexpr size_t EXPRESSION_POS = 9;
40 constexpr size_t IMPORT_POS = 7;
41 constexpr size_t EXPORT_POS = 7;
42 }  // namespace
43 
44 class LspGetAdjustedLocation : public LSPAPITests {};
45 
TEST_F(LspGetAdjustedLocation,GetAdjustedLocationForVariableTest)46 TEST_F(LspGetAdjustedLocation, GetAdjustedLocationForVariableTest)
47 {
48     const char *source = R"(
49 let x = 42;
50 function test() {
51     let y = x;
52     return y;
53 }
54 let z = x;
55 )";
56 
57     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
58     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
59     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
60     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
61     auto *varNode = ark::es2panda::lsp::GetTouchingPropertyName(ctx, VARIABLE_POS);
62     ASSERT_NE(varNode, nullptr);
63     auto adjustedVar = ark::es2panda::lsp::GetAdjustedLocation(varNode, true, context->allocator);
64     ASSERT_TRUE(adjustedVar.has_value());
65     EXPECT_TRUE((*adjustedVar)->IsIdentifier());
66     EXPECT_EQ((*adjustedVar)->AsIdentifier()->Name(), "x");
67     initializer.DestroyContext(ctx);
68 }
69 
TEST_F(LspGetAdjustedLocation,GetTouchingPropertyNameTest)70 TEST_F(LspGetAdjustedLocation, GetTouchingPropertyNameTest)
71 {
72     const char *source = R"(
73 class Example {
74     property = "test";
75 }
76 )";
77 
78     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
79     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_PARSED, source);
80     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_PARSED);
81     auto *node = ark::es2panda::lsp::GetTouchingPropertyName(ctx, PROPERTY_POS);
82     ASSERT_NE(node, nullptr);
83     EXPECT_TRUE(node->IsIdentifier());
84     EXPECT_EQ(node->AsIdentifier()->Name(), "property");
85     initializer.DestroyContext(ctx);
86 }
87 
TEST_F(LspGetAdjustedLocation,GetAdjustedLocationForClassTest)88 TEST_F(LspGetAdjustedLocation, GetAdjustedLocationForClassTest)
89 {
90     const char *source = R"(
91 class MyClass {
92     prop = 0;
93     method() {
94         return this.prop;
95     }
96 }
97 let instance = new MyClass();
98 )";
99     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
100     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
101     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
102     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
103     AstNode *classNode = ark::es2panda::lsp::GetTouchingPropertyName(ctx, CLASS_POS);
104     ASSERT_NE(classNode, nullptr);
105     ASSERT_TRUE(classNode->IsClassDeclaration());
106     auto adjustedClass = ark::es2panda::lsp::GetAdjustedLocationForClass(classNode, context->allocator);
107     ASSERT_TRUE(adjustedClass.has_value());
108     ASSERT_NE(*adjustedClass, nullptr);
109     EXPECT_TRUE((*adjustedClass)->IsIdentifier());
110     EXPECT_EQ((*adjustedClass)->AsIdentifier()->Name(), "MyClass");
111     initializer.DestroyContext(ctx);
112 }
113 
TEST_F(LspGetAdjustedLocation,GetAdjustedLocationForFunctionTest)114 TEST_F(LspGetAdjustedLocation, GetAdjustedLocationForFunctionTest)
115 {
116     const char *source = R"(
117 function testFunc(param: number) {
118     return param * 2;
119 }
120 let result = testFunc(21);
121 )";
122     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
123     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_PARSED, source);
124     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_PARSED);
125     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
126     auto *funcNode = ark::es2panda::lsp::GetTouchingPropertyName(ctx, FUNCTION_POS);
127     ASSERT_NE(funcNode, nullptr);
128     ASSERT_TRUE(funcNode->IsIdentifier());
129     EXPECT_EQ(funcNode->AsIdentifier()->Name(), "testFunc");
130     auto *parent = funcNode->Parent();
131     ASSERT_NE(parent, nullptr);
132     auto adjustedFunc = ark::es2panda::lsp::GetAdjustedLocationForFunction(parent, context->allocator);
133     ASSERT_TRUE(adjustedFunc.has_value());
134     ASSERT_NE(*adjustedFunc, nullptr);
135     EXPECT_TRUE((*adjustedFunc)->IsIdentifier());
136     EXPECT_EQ((*adjustedFunc)->AsIdentifier()->Name(), "testFunc");
137     initializer.DestroyContext(ctx);
138 }
139 
TEST_F(LspGetAdjustedLocation,GetChildrenTest)140 TEST_F(LspGetAdjustedLocation, GetChildrenTest)
141 {
142     const char *source = R"(
143 class Test {
144     x = 1;
145     y = "test";
146     method() {}
147 }
148 )";
149     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
150     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
151     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
152     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
153     auto *classNode = ark::es2panda::lsp::GetTouchingPropertyName(ctx, CLASS_POS);
154     ASSERT_NE(classNode, nullptr);
155     auto children = ark::es2panda::lsp::GetChildren(classNode, context->allocator);
156     bool hasXProperty = false;
157     bool hasYProperty = false;
158     bool hasMethod = false;
159     for (const auto *child : children) {
160         if (child->IsIdentifier()) {
161             auto name = child->AsIdentifier()->Name();
162             if (name == "x") {
163                 hasXProperty = true;
164             }
165             if (name == "y") {
166                 hasYProperty = true;
167             }
168             if (name == "method") {
169                 hasMethod = true;
170             }
171         }
172     }
173     EXPECT_TRUE(hasXProperty) << "x property not found";
174     EXPECT_TRUE(hasYProperty) << "y property not found";
175     EXPECT_TRUE(hasMethod) << "method not found";
176     initializer.DestroyContext(ctx);
177 }
178 
TEST_F(LspGetAdjustedLocation,IsModifierTest)179 TEST_F(LspGetAdjustedLocation, IsModifierTest)
180 {
181     const char *source = R"(
182 class Test {
183     private x: number;
184     public y: string;
185     static z: boolean;
186 }
187 )";
188     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
189     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_PARSED, source);
190     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_PARSED);
191     auto *privateNode = ark::es2panda::lsp::GetTouchingPropertyName(ctx, PRIVATE_POS);
192     auto *publicNode = ark::es2panda::lsp::GetTouchingPropertyName(ctx, PUBLIC_POS);
193     auto *staticNode = ark::es2panda::lsp::GetTouchingPropertyName(ctx, STATIC_POS);
194     auto *nonModifierNode1 = ark::es2panda::lsp::GetTouchingPropertyName(ctx, PRIVATE_POS + 1);
195     auto *nonModifierNode2 = ark::es2panda::lsp::GetTouchingPropertyName(ctx, PUBLIC_POS + 1);
196     auto *nonModifierNode3 = ark::es2panda::lsp::GetTouchingPropertyName(ctx, STATIC_POS + 1);
197     if (privateNode != nullptr) {
198         EXPECT_TRUE(ark::es2panda::lsp::IsModifier(privateNode));
199     }
200     if (publicNode != nullptr) {
201         EXPECT_TRUE(ark::es2panda::lsp::IsModifier(publicNode));
202     }
203     if (staticNode != nullptr) {
204         EXPECT_TRUE(ark::es2panda::lsp::IsModifier(staticNode));
205     }
206     if (nonModifierNode1 != nullptr) {
207         EXPECT_FALSE(ark::es2panda::lsp::IsModifier(nonModifierNode1));
208     }
209     if (nonModifierNode2 != nullptr) {
210         EXPECT_FALSE(ark::es2panda::lsp::IsModifier(nonModifierNode2));
211     }
212     if (nonModifierNode3 != nullptr) {
213         EXPECT_FALSE(ark::es2panda::lsp::IsModifier(nonModifierNode3));
214     }
215     initializer.DestroyContext(ctx);
216 }
217 
TEST_F(LspGetAdjustedLocation,GetAdjustedLocationForNestedScopeTest)218 TEST_F(LspGetAdjustedLocation, GetAdjustedLocationForNestedScopeTest)
219 {
220     const char *source =
221         "let x = 1;\n"
222         "class Test {\n"
223         "    x: number = 2;\n"
224         "    method() {\n"
225         "        let x = 3;\n"
226         "        return x;\n"
227         "    }\n"
228         "}\n";
229     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
230     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
231     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
232     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
233     auto *globalVar = ark::es2panda::lsp::GetTouchingPropertyName(ctx, VARIABLE_POS);
234     if (globalVar != nullptr) {
235         auto adjustedGlobal = ark::es2panda::lsp::GetAdjustedLocation(globalVar, true, context->allocator);
236         if (adjustedGlobal.has_value()) {
237             EXPECT_TRUE((*adjustedGlobal)->IsIdentifier());
238             EXPECT_EQ((*adjustedGlobal)->AsIdentifier()->Name(), "x");
239         }
240     }
241     auto *memberVar = ark::es2panda::lsp::GetTouchingPropertyName(ctx, MEMBER_POS);
242     if (memberVar != nullptr) {
243         auto adjustedMember = ark::es2panda::lsp::GetAdjustedLocation(memberVar, true, context->allocator);
244         if (adjustedMember.has_value()) {
245             EXPECT_TRUE((*adjustedMember)->IsIdentifier());
246             EXPECT_EQ((*adjustedMember)->AsIdentifier()->Name(), "x");
247         }
248     }
249     initializer.DestroyContext(ctx);
250 }
251 
TEST_F(LspGetAdjustedLocation,GetAdjustedLocationForImportTest)252 TEST_F(LspGetAdjustedLocation, GetAdjustedLocationForImportTest)
253 {
254     const char *source = R"(
255 class MyClass {
256     method() {}
257 }
258 let instance = new MyClass();
259 )";
260     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
261     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
262     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
263     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
264     auto *node = ark::es2panda::lsp::GetTouchingPropertyName(ctx, IMPORT_POS);
265     ASSERT_NE(node, nullptr);
266     auto adjusted = ark::es2panda::lsp::GetAdjustedLocation(node, true, context->allocator);
267     ASSERT_TRUE(adjusted.has_value());
268     EXPECT_TRUE((*adjusted)->IsIdentifier());
269     EXPECT_EQ((*adjusted)->AsIdentifier()->Name(), "MyClass");
270     initializer.DestroyContext(ctx);
271 }
272 
TEST_F(LspGetAdjustedLocation,GetAdjustedLocationForExportTest)273 TEST_F(LspGetAdjustedLocation, GetAdjustedLocationForExportTest)
274 {
275     const char *source = R"(
276 class MyClass {
277     method() {}
278 }
279 let instance = new MyClass();
280 )";
281     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
282     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
283     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
284     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
285     auto *node = ark::es2panda::lsp::GetTouchingPropertyName(ctx, EXPORT_POS);
286     ASSERT_NE(node, nullptr);
287     auto adjusted = ark::es2panda::lsp::GetAdjustedLocation(node, true, context->allocator);
288     ASSERT_TRUE(adjusted.has_value());
289     EXPECT_TRUE((*adjusted)->IsIdentifier());
290     EXPECT_EQ((*adjusted)->AsIdentifier()->Name(), "MyClass");
291     initializer.DestroyContext(ctx);
292 }
293 
TEST_F(LspGetAdjustedLocation,GetAdjustedLocationForHeritageTest)294 TEST_F(LspGetAdjustedLocation, GetAdjustedLocationForHeritageTest)
295 {
296     const char *source = R"(
297 class BaseClass {}
298 class ChildClass extends BaseClass {}
299 )";
300     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
301     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
302     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
303     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
304     auto *node = ark::es2panda::lsp::GetTouchingPropertyName(ctx, HERITAGE_POS);
305     ASSERT_NE(node, nullptr);
306     auto adjusted = ark::es2panda::lsp::GetAdjustedLocation(node, true, context->allocator);
307     ASSERT_TRUE(adjusted.has_value());
308     EXPECT_TRUE((*adjusted)->IsIdentifier());
309     EXPECT_EQ((*adjusted)->AsIdentifier()->Name(), "BaseClass");
310     initializer.DestroyContext(ctx);
311 }
312 
TEST_F(LspGetAdjustedLocation,FindTypeReferenceTest)313 TEST_F(LspGetAdjustedLocation, FindTypeReferenceTest)
314 {
315     const char *source = R"(
316 class MyType {}
317 let variable: MyType;
318 )";
319     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
320     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
321     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
322     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
323     auto *node = ark::es2panda::lsp::GetTouchingPropertyName(ctx, TYPE_PARAM_POS);
324     ASSERT_NE(node, nullptr);
325     auto adjusted = ark::es2panda::lsp::GetAdjustedLocation(node, true, context->allocator);
326     ASSERT_TRUE(adjusted.has_value());
327     EXPECT_TRUE((*adjusted)->IsIdentifier());
328     EXPECT_EQ((*adjusted)->AsIdentifier()->Name(), "MyType");
329     initializer.DestroyContext(ctx);
330 }
331 
TEST_F(LspGetAdjustedLocation,FindArrayTypeTest)332 TEST_F(LspGetAdjustedLocation, FindArrayTypeTest)
333 {
334     const char *source = R"(
335 type NumArray = number[];
336 let numbers: NumArray;
337 )";
338     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
339     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_PARSED, source);
340     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_PARSED);
341     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
342     auto *node = ark::es2panda::lsp::GetTouchingToken(ctx, ARRAY_TYPE_POS, true);
343     ASSERT_NE(node, nullptr);
344     auto children = ark::es2panda::lsp::GetChildren(node, context->allocator);
345     auto *arrayType = ark::es2panda::lsp::FindArrayType(node, children);
346     ASSERT_NE(arrayType, nullptr);
347     EXPECT_TRUE(arrayType->IsTSArrayType());
348     initializer.DestroyContext(ctx);
349 }
350 
TEST_F(LspGetAdjustedLocation,SkipOuterExpressionsTest)351 TEST_F(LspGetAdjustedLocation, SkipOuterExpressionsTest)
352 {
353     const char *source = R"(
354 let x = (((42)));
355 )";
356     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
357     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
358     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
359     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
360     auto *node = ark::es2panda::lsp::GetTouchingPropertyName(ctx, VARIABLE_POS);
361     ASSERT_NE(node, nullptr);
362     auto adjusted = ark::es2panda::lsp::GetAdjustedLocation(node, true, context->allocator);
363     ASSERT_TRUE(adjusted.has_value());
364     EXPECT_TRUE((*adjusted)->IsIdentifier());
365     EXPECT_EQ((*adjusted)->AsIdentifier()->Name(), "x");
366     initializer.DestroyContext(ctx);
367 }
368 
TEST_F(LspGetAdjustedLocation,FindFirstExpressionTest)369 TEST_F(LspGetAdjustedLocation, FindFirstExpressionTest)
370 {
371     const char *source = R"(
372 let x = 42 + (5 * 3);
373 )";
374     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
375     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
376     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
377     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
378     auto *node = ark::es2panda::lsp::GetTouchingPropertyName(ctx, VARIABLE_POS);
379     ASSERT_NE(node, nullptr);
380     auto children = ark::es2panda::lsp::GetChildren(node, context->allocator);
381     auto *found = ark::es2panda::lsp::FindFirstExpression(node, children);
382     ASSERT_NE(found, nullptr);
383     EXPECT_TRUE(found->IsExpression());
384     initializer.DestroyContext(ctx);
385 }
386 
TEST_F(LspGetAdjustedLocation,FindFirstExpressionAfterTest)387 TEST_F(LspGetAdjustedLocation, FindFirstExpressionAfterTest)
388 {
389     const char *source = R"(let x = 1 + 2 + 3;)";
390     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
391     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
392     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
393     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
394     auto *node = ark::es2panda::lsp::GetTouchingToken(ctx, EXPRESSION_POS, true);
395     ASSERT_NE(node, nullptr);
396     auto children = ark::es2panda::lsp::GetChildren(node, context->allocator);
397     auto *firstExpr = ark::es2panda::lsp::FindFirstExpression(node, children);
398     ASSERT_NE(firstExpr, nullptr);
399     auto *afterFirst = ark::es2panda::lsp::FindFirstExpressionAfter(node, firstExpr, children);
400     ASSERT_NE(afterFirst, nullptr);
401     EXPECT_TRUE(afterFirst->IsExpression());
402     initializer.DestroyContext(ctx);
403 }
404 
TEST_F(LspGetAdjustedLocation,FindNodeOfTypeTest)405 TEST_F(LspGetAdjustedLocation, FindNodeOfTypeTest)
406 {
407     const char *source = R"(
408 class TestClass {
409     method() {
410         return 42;
411     }
412 }
413 )";
414     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
415     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
416     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
417     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
418     auto *node = ark::es2panda::lsp::GetTouchingToken(ctx, METHOD_POS, true);
419     ASSERT_NE(node, nullptr);
420     auto children = ark::es2panda::lsp::GetChildren(node, context->allocator);
421     auto *methodBody = ark::es2panda::lsp::FindNodeOfType(node, AstNodeType::BLOCK_STATEMENT, children);
422     ASSERT_NE(methodBody, nullptr);
423     auto methodChildren = ark::es2panda::lsp::GetChildren(methodBody, context->allocator);
424     auto *found = ark::es2panda::lsp::FindNodeOfType(methodBody, AstNodeType::RETURN_STATEMENT, methodChildren);
425     ASSERT_NE(found, nullptr);
426     EXPECT_TRUE(found->IsReturnStatement());
427     initializer.DestroyContext(ctx);
428 }
429 
TEST_F(LspGetAdjustedLocation,FindTypeParameterTest)430 TEST_F(LspGetAdjustedLocation, FindTypeParameterTest)
431 {
432     const char *source = R"(
433 class Container<T> {
434     value: T;
435 }
436 )";
437     ark::es2panda::lsp::Initializer initializer = ark::es2panda::lsp::Initializer();
438     es2panda_Context *ctx = initializer.CreateContext("test.ets", ES2PANDA_STATE_CHECKED, source);
439     ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
440     auto *context = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx);
441     auto *node = ark::es2panda::lsp::GetTouchingToken(ctx, TYPE_PARAM_POS, true);
442     ASSERT_NE(node, nullptr);
443     auto children = ark::es2panda::lsp::GetChildren(node, context->allocator);
444     auto *typeParam = ark::es2panda::lsp::FindTypeParameter(node, children);
445     ASSERT_NE(typeParam, nullptr);
446     EXPECT_TRUE(typeParam->IsTSTypeParameterDeclaration() || typeParam->IsIdentifier());
447     if (typeParam->IsIdentifier()) {
448         EXPECT_EQ(typeParam->AsIdentifier()->Name(), "T");
449     }
450     initializer.DestroyContext(ctx);
451 }