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/rename.h"
17 #include <gtest/gtest.h>
18 #include <cstddef>
19 #include <cstdio>
20 #include <optional>
21 #include <string>
22 #include "lexer/token/letters.h"
23 #include "lsp/include/internal_api.h"
24 #include "lsp_api_test.h"
25
26 using ark::es2panda::lsp::Initializer;
27
28 class LspRenameInfoTests : public LSPAPITests {};
29
TEST_F(LspRenameInfoTests,RenameInfoCreateTriggerSpanForNodeNumberLiteral)30 TEST_F(LspRenameInfoTests, RenameInfoCreateTriggerSpanForNodeNumberLiteral)
31 {
32 Initializer initializer = Initializer();
33
34 es2panda_Context *ctx = initializer.CreateContext("trigger-span-literal.ets", ES2PANDA_STATE_CHECKED,
35 "let number_literal: number = 1234\n");
36 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
37
38 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
39 auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) {
40 return node->IsNumberLiteral() && node->AsNumberLiteral()->Str() == "1234";
41 });
42 ASSERT_NE(targetNode, nullptr);
43
44 auto result = ark::es2panda::lsp::CreateTriggerSpanForNode(targetNode);
45 size_t const expectedStart = 29;
46 size_t const expectedLength = 4;
47 ASSERT_EQ(result.start, expectedStart);
48 ASSERT_EQ(result.length, expectedLength);
49 initializer.DestroyContext(ctx);
50 }
51
TEST_F(LspRenameInfoTests,RenameInfoCreateTriggerSpanForNodeStringLiteral)52 TEST_F(LspRenameInfoTests, RenameInfoCreateTriggerSpanForNodeStringLiteral)
53 {
54 Initializer initializer = Initializer();
55
56 es2panda_Context *ctx = initializer.CreateContext("trigger-span-string-literal.ets", ES2PANDA_STATE_CHECKED,
57 "let string_literal: string = \"hello\";\n");
58 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
59
60 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
61 auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) {
62 return node->IsStringLiteral() && node->AsStringLiteral()->Str() == "hello";
63 });
64 ASSERT_NE(targetNode, nullptr);
65
66 auto result = ark::es2panda::lsp::CreateTriggerSpanForNode(targetNode);
67 size_t const expectedStart = 30;
68 size_t const expectedLength = 5;
69 ASSERT_EQ(result.start, expectedStart);
70 ASSERT_EQ(result.length, expectedLength);
71 initializer.DestroyContext(ctx);
72 }
73
TEST_F(LspRenameInfoTests,RenameInfoCreateTriggerSpanForNodeEmptyStringLiteral)74 TEST_F(LspRenameInfoTests, RenameInfoCreateTriggerSpanForNodeEmptyStringLiteral)
75 {
76 Initializer initializer = Initializer();
77
78 es2panda_Context *ctx =
79 initializer.CreateContext("trigger-span-empty-string.ets", ES2PANDA_STATE_CHECKED, "let emptyStr = \"\";");
80 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
81
82 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
83 auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) {
84 return node->IsStringLiteral() && node->AsStringLiteral()->Str() == "";
85 });
86 ASSERT_NE(targetNode, nullptr);
87
88 auto result = ark::es2panda::lsp::CreateTriggerSpanForNode(targetNode);
89 size_t const expectedStart = 16;
90 size_t const expectedLength = 0;
91 ASSERT_EQ(result.start, expectedStart);
92 ASSERT_EQ(result.length, expectedLength);
93 initializer.DestroyContext(ctx);
94 }
95
TEST_F(LspRenameInfoTests,RenameInfoNodeReturnTrueIfNodeIsNull)96 TEST_F(LspRenameInfoTests, RenameInfoNodeReturnTrueIfNodeIsNull)
97 {
98 ark::es2panda::ir::AstNode *nullNode = nullptr;
99 bool result = ark::es2panda::lsp::NodeIsMissing(nullNode);
100 EXPECT_TRUE(result);
101 }
102
TEST_F(LspRenameInfoTests,RenameInfoNodeReturnTrueIfStartEqualEnd)103 TEST_F(LspRenameInfoTests, RenameInfoNodeReturnTrueIfStartEqualEnd)
104 {
105 Initializer initializer = Initializer();
106
107 es2panda_Context *ctx = initializer.CreateContext("StartEqualEnd.ets", ES2PANDA_STATE_CHECKED, "");
108 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
109
110 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
111 auto program = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx)->parserProgram;
112
113 size_t const expectedIndex = 10;
114 size_t const expectedLength = 20;
115 auto srcPositionStart = ark::es2panda::lexer::SourcePosition(expectedIndex, expectedLength, program);
116 auto srcPositionEnd = ark::es2panda::lexer::SourcePosition(expectedIndex, expectedLength, program);
117 auto srcRange = ark::es2panda::lexer::SourceRange(srcPositionStart, srcPositionEnd);
118
119 ast->SetRange(srcRange);
120 bool result = ark::es2panda::lsp::NodeIsMissing(ast);
121 EXPECT_TRUE(result);
122 initializer.DestroyContext(ctx);
123 }
124
TEST_F(LspRenameInfoTests,RenameInfoNodeReturnFalseIfStartNotEqualEnd)125 TEST_F(LspRenameInfoTests, RenameInfoNodeReturnFalseIfStartNotEqualEnd)
126 {
127 Initializer initializer = Initializer();
128
129 es2panda_Context *ctx = initializer.CreateContext("StartNotEqualEnd.ets", ES2PANDA_STATE_CHECKED, "");
130 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
131
132 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
133 auto program = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx)->parserProgram;
134 size_t const expectedStartIndex = 10;
135 size_t const expectedEndIndex = 15;
136 size_t const expectedLength = 20;
137 auto srcPositionStart = ark::es2panda::lexer::SourcePosition(expectedStartIndex, expectedLength, program);
138 auto srcPositionEnd = ark::es2panda::lexer::SourcePosition(expectedEndIndex, expectedLength, program);
139 auto srcRange = ark::es2panda::lexer::SourceRange(srcPositionStart, srcPositionEnd);
140
141 ast->SetRange(srcRange);
142 bool result = ark::es2panda::lsp::NodeIsMissing(ast);
143 EXPECT_FALSE(result);
144 initializer.DestroyContext(ctx);
145 }
146
TEST_F(LspRenameInfoTests,RenameInfoNodeGetSourceTextOfNodeFromSourceFile)147 TEST_F(LspRenameInfoTests, RenameInfoNodeGetSourceTextOfNodeFromSourceFile)
148 {
149 Initializer initializer = Initializer();
150
151 auto sourceView = ark::es2panda::util::StringView("function A(a:number, b:number) {\n return a + b;\n}\nA(1, 2);");
152 es2panda_Context *ctx = initializer.CreateContext("GetTextOfNodeFromSourceFile.ets", ES2PANDA_STATE_CHECKED,
153 "function A(a:number, b:number) {\n return a + b;\n}\nA(1, 2);");
154 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
155
156 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
157 auto program = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx)->parserProgram;
158 size_t const startIndex = 9;
159 size_t const startLength = 5;
160 size_t const endIndex = 10;
161 size_t const endLength = 5;
162 auto srcPositionStart = ark::es2panda::lexer::SourcePosition(startIndex, startLength, program);
163 auto srcPositionEnd = ark::es2panda::lexer::SourcePosition(endIndex, endLength, program);
164 auto srcRange = ark::es2panda::lexer::SourceRange(srcPositionStart, srcPositionEnd);
165 ast->SetRange(srcRange);
166
167 std::string result = ark::es2panda::lsp::GetSourceTextOfNodeFromSourceFile(sourceView, ast);
168 ASSERT_EQ(result, "A");
169 ASSERT_NE(result, "B");
170 initializer.DestroyContext(ctx);
171 }
172
TEST_F(LspRenameInfoTests,RenameInfoNodeGetSourceTextOfNodeFromSourceFileNullPtr)173 TEST_F(LspRenameInfoTests, RenameInfoNodeGetSourceTextOfNodeFromSourceFileNullPtr)
174 {
175 auto sourceView = ark::es2panda::util::StringView("function A(a:number, b:number) {\n return a + b;\n}\nA(1, 2);");
176 ark::es2panda::ir::AstNode *ast = nullptr;
177 std::string result = ark::es2panda::lsp::GetSourceTextOfNodeFromSourceFile(sourceView, ast);
178 ASSERT_NE(result, "A");
179 }
180
TEST_F(LspRenameInfoTests,RenameInfoNodeIsAncestorType)181 TEST_F(LspRenameInfoTests, RenameInfoNodeIsAncestorType)
182 {
183 ASSERT_EQ(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_ANY_KEYWORD), true);
184 ASSERT_EQ(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_UNKNOWN_KEYWORD), true);
185 ASSERT_EQ(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_NUMBER_KEYWORD), true);
186 ASSERT_EQ(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_BIGINT_KEYWORD), true);
187 ASSERT_EQ(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_OBJECT_KEYWORD), true);
188 ASSERT_EQ(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_BOOLEAN_KEYWORD), true);
189 ASSERT_EQ(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_STRING_KEYWORD), true);
190 ASSERT_EQ(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_VOID_KEYWORD), true);
191 ASSERT_EQ(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_UNDEFINED_KEYWORD), true);
192 ASSERT_EQ(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_NEVER_KEYWORD), true);
193 }
194
TEST_F(LspRenameInfoTests,RenameInfoNodeIsNotAncestorType)195 TEST_F(LspRenameInfoTests, RenameInfoNodeIsNotAncestorType)
196 {
197 ASSERT_NE(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_ARRAY_TYPE), true);
198 ASSERT_NE(ark::es2panda::lsp::IsValidAncestorType(ark::es2panda::ir::AstNodeType::TS_FUNCTION_TYPE), true);
199
200 size_t const invalidNum = 999;
201 auto invalidType = static_cast<ark::es2panda::ir::AstNodeType>(invalidNum);
202 ASSERT_NE(ark::es2panda::lsp::IsValidAncestorType(invalidType), true);
203 }
204
TEST_F(LspRenameInfoTests,RenameInfoNodeIsQuoteOrBacktick)205 TEST_F(LspRenameInfoTests, RenameInfoNodeIsQuoteOrBacktick)
206 {
207 int charCode = ark::es2panda::lexer::LEX_CHAR_DOUBLE_QUOTE;
208 ASSERT_TRUE(ark::es2panda::lsp::IsQuoteOrBacktick(charCode));
209
210 charCode = ark::es2panda::lexer::LEX_CHAR_0;
211 ASSERT_FALSE(ark::es2panda::lsp::IsQuoteOrBacktick(charCode));
212 }
213
TEST_F(LspRenameInfoTests,RenameInfoIsStringOrNumericLiteralLike)214 TEST_F(LspRenameInfoTests, RenameInfoIsStringOrNumericLiteralLike)
215 {
216 Initializer initializer = Initializer();
217
218 es2panda_Context *ctx = initializer.CreateContext("trigger-span-string-literal.ets", ES2PANDA_STATE_CHECKED,
219 "let string_literal: string = \"hello\";\n");
220 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
221
222 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
223 auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) {
224 return node->IsStringLiteral() && node->AsStringLiteral()->Str() == "hello";
225 });
226
227 ASSERT_TRUE(ark::es2panda::lsp::IsStringOrNumericLiteralLike(targetNode));
228 initializer.DestroyContext(ctx);
229 }
230
TEST_F(LspRenameInfoTests,RenameInfoStripQuotes)231 TEST_F(LspRenameInfoTests, RenameInfoStripQuotes)
232 {
233 std::string hello = "'hello'";
234 ASSERT_EQ(ark::es2panda::lsp::StripQuotes(hello), "hello");
235 }
236
TEST_F(LspRenameInfoTests,RenameInfoGetNodeKindForRenameInfo)237 TEST_F(LspRenameInfoTests, RenameInfoGetNodeKindForRenameInfo)
238 {
239 Initializer initializer = Initializer();
240
241 es2panda_Context *ctx = initializer.CreateContext("token-pos-identifier.ets", ES2PANDA_STATE_CHECKED,
242 "function A(a:number, b:number) {\n return a + b;\n}\nA(1, 2);");
243 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
244
245 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
246 ASSERT_EQ(ark::es2panda::lsp::GetNodeKindForRenameInfo(ast), "");
247 initializer.DestroyContext(ctx);
248 }
249
TEST_F(LspRenameInfoTests,RenameInfoGetTextOfNode)250 TEST_F(LspRenameInfoTests, RenameInfoGetTextOfNode)
251 {
252 Initializer initializer = Initializer();
253
254 std::vector<std::string> files = {"reanme_export1.ets"};
255 std::vector<std::string> texts = {
256 R"(export function A(a:number, b:number): number {return a + b;}
257 export function B(a:number, b:number): number {return a + b;})"};
258 auto filePaths = CreateTempFile(files, texts);
259 size_t const expectedFileCount = 1;
260 ASSERT_EQ(filePaths.size(), expectedFileCount);
261
262 char const *fileName = filePaths[0].c_str();
263 auto ctx = initializer.CreateContext(fileName, ES2PANDA_STATE_CHECKED);
264 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
265
266 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
267
268 size_t const startIndex = 16;
269 size_t const startLength = 5;
270 size_t const endIndex = 17;
271 size_t const endLength = 5;
272
273 auto program = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx)->parserProgram;
274 auto srcPositionStart = ark::es2panda::lexer::SourcePosition(startIndex, startLength, program);
275 auto srcPositionEnd = ark::es2panda::lexer::SourcePosition(endIndex, endLength, program);
276 auto srcRange = ark::es2panda::lexer::SourceRange(srcPositionStart, srcPositionEnd);
277 ast->SetRange(srcRange);
278
279 ASSERT_EQ(ark::es2panda::lsp::GetTextOfNode(ast, program), "A");
280 initializer.DestroyContext(ctx);
281 }
282
TEST_F(LspRenameInfoTests,RenameInfoGetRenameInfoError)283 TEST_F(LspRenameInfoTests, RenameInfoGetRenameInfoError)
284 {
285 ark::es2panda::lsp::RenameInfoFailure renameFailureFromFunction =
286 ark::es2panda::lsp::GetRenameInfoError("errorMessage");
287 ark::es2panda::lsp::RenameInfoFailure renameFailure = ark::es2panda::lsp::RenameInfoFailure(false, "errorMessage");
288 ASSERT_EQ(renameFailure.GetLocalizedErrorMessage(), renameFailureFromFunction.GetLocalizedErrorMessage());
289 ASSERT_EQ(renameFailure.GetCanRenameFailure(), renameFailureFromFunction.GetCanRenameFailure());
290 }
291
TEST_F(LspRenameInfoTests,RenameInfoGetRenameInfoSuccess)292 TEST_F(LspRenameInfoTests, RenameInfoGetRenameInfoSuccess)
293 {
294 Initializer initializer = Initializer();
295
296 es2panda_Context *ctx = initializer.CreateContext("token-pos-identifier.ets", ES2PANDA_STATE_CHECKED,
297 "function A(a:number, b:number) {\n return a + b;\n}\nA(1, 2);");
298 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
299
300 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
301
302 ark::es2panda::lsp::RenameInfoSuccess renameSuccessFromFunction =
303 ark::es2panda::lsp::GetRenameInfoSuccess("displayName", "fullDisplayName", "", "", ast);
304
305 ark::es2panda::lsp::RenameInfoSuccess renameSuccess =
306 ark::es2panda::lsp::RenameInfoSuccess(true, "", "", "displayName", "fullDisplayName", "", TextSpan(1, 2));
307
308 ASSERT_EQ(renameSuccess.GetDisplayName(), renameSuccessFromFunction.GetDisplayName());
309 ASSERT_EQ(renameSuccess.GetFullDisplayName(), renameSuccessFromFunction.GetFullDisplayName());
310 ASSERT_EQ(renameSuccess.GetKind(), renameSuccessFromFunction.GetKind());
311 ASSERT_EQ(renameSuccess.GetKindModifiers(), renameSuccessFromFunction.GetKindModifiers());
312 ASSERT_EQ(renameSuccess.GetCanRenameSuccess(), renameSuccessFromFunction.GetCanRenameSuccess());
313
314 initializer.DestroyContext(ctx);
315 }
316
TEST_F(LspRenameInfoTests,RenameInfoTryGetImportFromModuleSpecifier)317 TEST_F(LspRenameInfoTests, RenameInfoTryGetImportFromModuleSpecifier)
318 {
319 Initializer initializer = Initializer();
320
321 std::vector<std::string> files = {"rename-module.ets"};
322 std::vector<std::string> texts = {R"(import { PI } from "std/math";
323 console.log(PI);)"};
324
325 auto filePaths = CreateTempFile(files, texts);
326 int const expectedFileCount = 1;
327 ASSERT_EQ(filePaths.size(), expectedFileCount);
328
329 size_t const startIndex = 0;
330 char const *referenceFileName = filePaths[startIndex].c_str();
331 auto ctx = initializer.CreateContext(referenceFileName, ES2PANDA_STATE_CHECKED);
332 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
333
334 ark::es2panda::ir::AstNode *ast = nullptr;
335 ASSERT_EQ(ark::es2panda::lsp::TryGetImportFromModuleSpecifier(ast), nullptr);
336
337 ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
338 auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) {
339 return node->Type() == ark::es2panda::ir::AstNodeType::IMPORT_SPECIFIER;
340 });
341 ASSERT_EQ(ark::es2panda::lsp::TryGetImportFromModuleSpecifier(targetNode), targetNode->Parent());
342
343 initializer.DestroyContext(ctx);
344 }
345
TEST_F(LspRenameInfoTests,RenameInfoGetRenameInfoForModuleCaseModule1)346 TEST_F(LspRenameInfoTests, RenameInfoGetRenameInfoForModuleCaseModule1)
347 {
348 Initializer initializer = Initializer();
349
350 std::vector<std::string> files = {"rename-module.ets"};
351 std::vector<std::string> texts = {R"(const s = "std/math/index";)"};
352 auto filePaths = CreateTempFile(files, texts);
353 size_t const expectedSize = 1;
354 ASSERT_EQ(filePaths.size(), expectedSize);
355
356 size_t const startIndex = 0;
357 char const *filePath = filePaths[startIndex].c_str();
358 es2panda_Context *ctx = initializer.CreateContext(filePath, ES2PANDA_STATE_CHECKED);
359 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
360
361 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
362 auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) {
363 return node->IsStringLiteral() && node->AsStringLiteral()->ToString() == "std/math/index";
364 });
365 ASSERT_NE(targetNode, nullptr);
366
367 auto renameInfo = ark::es2panda::lsp::GetRenameInfoForModule(
368 targetNode, reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx)->parserProgram);
369 ASSERT_EQ(renameInfo.value().GetDisplayName(), targetNode->AsStringLiteral()->ToString());
370 initializer.DestroyContext(ctx);
371 }
372
TEST_F(LspRenameInfoTests,RenameInfoGetRenameInfoForModuleCaseModule2)373 TEST_F(LspRenameInfoTests, RenameInfoGetRenameInfoForModuleCaseModule2)
374 {
375 Initializer initializer = Initializer();
376
377 std::vector<std::string> files = {"rename-module.ets"};
378 std::vector<std::string> texts = {R"(const s = "std/math.ets";)"};
379 auto filePaths = CreateTempFile(files, texts);
380 size_t const expectedSize = 1;
381 ASSERT_EQ(filePaths.size(), expectedSize);
382
383 size_t const startIndex = 0;
384 char const *filePath = filePaths[startIndex].c_str();
385 es2panda_Context *ctx = initializer.CreateContext(filePath, ES2PANDA_STATE_CHECKED);
386 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
387
388 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
389 auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) {
390 return node->IsStringLiteral() && node->AsStringLiteral()->ToString() == "std/math.ets";
391 });
392 ASSERT_NE(targetNode, nullptr);
393
394 auto renameInfo = ark::es2panda::lsp::GetRenameInfoForModule(
395 targetNode, reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx)->parserProgram);
396 ASSERT_EQ(renameInfo.value().GetDisplayName(), targetNode->AsStringLiteral()->ToString());
397 initializer.DestroyContext(ctx);
398 }
399
TEST_F(LspRenameInfoTests,RenameInfoGetRenameInfoForModuleCaseDirectory)400 TEST_F(LspRenameInfoTests, RenameInfoGetRenameInfoForModuleCaseDirectory)
401 {
402 Initializer initializer = Initializer();
403
404 std::vector<std::string> files = {"rename-directory.ets"};
405 std::vector<std::string> texts = {R"(const s = "std/math/index.ets";)"};
406 auto filePaths = CreateTempFile(files, texts);
407 size_t const expectedSize = 1;
408 ASSERT_EQ(filePaths.size(), expectedSize);
409
410 size_t const startIndex = 0;
411 char const *filePath = filePaths[startIndex].c_str();
412 es2panda_Context *ctx = initializer.CreateContext(filePath, ES2PANDA_STATE_CHECKED);
413 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
414
415 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
416 auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) {
417 return node->IsStringLiteral() && node->AsStringLiteral()->ToString() == "std/math/index.ets";
418 });
419 ASSERT_NE(targetNode, nullptr);
420
421 auto renameInfo = ark::es2panda::lsp::GetRenameInfoForModule(
422 targetNode, reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx)->parserProgram);
423 ASSERT_EQ(renameInfo.value().GetDisplayName(), "std/math");
424 initializer.DestroyContext(ctx);
425 }
426
TEST_F(LspRenameInfoTests,RenameInfoGetRenameInfoForNode1)427 TEST_F(LspRenameInfoTests, RenameInfoGetRenameInfoForNode1)
428 {
429 Initializer initializer = Initializer();
430
431 std::vector<std::string> files = {"rename.ets"};
432 std::vector<std::string> texts = {R"(import { PI } from "std/math"; console.log(PI);)"};
433
434 auto filePaths = CreateTempFile(files, texts);
435 size_t const expectedFileCount = 1;
436 ASSERT_EQ(filePaths.size(), expectedFileCount);
437
438 size_t const startIndex = 0;
439 char const *referenceFileName = filePaths[startIndex].c_str();
440 auto ctx = initializer.CreateContext(referenceFileName, ES2PANDA_STATE_CHECKED);
441 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
442
443 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
444 auto checker = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx)->checker->AsETSChecker();
445 auto program = reinterpret_cast<ark::es2panda::public_lib::Context *>(ctx)->parserProgram;
446
447 auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) {
448 return node->IsIdentifier() && node->AsIdentifier()->ToString() == "PI";
449 });
450 ASSERT_EQ(ark::es2panda::lsp::GetRenameInfoForNode(targetNode, checker, program), std::nullopt);
451 initializer.DestroyContext(ctx);
452 }
453
TEST_F(LspRenameInfoTests,RenameInfoNodeIsEligibleForRenameStringLiteral)454 TEST_F(LspRenameInfoTests, RenameInfoNodeIsEligibleForRenameStringLiteral)
455 {
456 Initializer initializer = Initializer();
457 es2panda_Context *ctx = initializer.CreateContext("trigger-span-string-literal.ets", ES2PANDA_STATE_CHECKED,
458 "let string_literal: string = \"hello\";\n");
459 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
460
461 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
462 auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) {
463 return node->IsStringLiteral() && node->AsStringLiteral()->Str() == "hello";
464 });
465
466 ASSERT_NE(targetNode, nullptr);
467 ASSERT_TRUE(ark::es2panda::lsp::NodeIsEligibleForRename(targetNode));
468 initializer.DestroyContext(ctx);
469 }
470
TEST_F(LspRenameInfoTests,RenameInfoNodeIsEligibleForRenameNumberLiteralEnumMember)471 TEST_F(LspRenameInfoTests, RenameInfoNodeIsEligibleForRenameNumberLiteralEnumMember)
472 {
473 Initializer initializer = Initializer();
474 es2panda_Context *ctx = initializer.CreateContext("trigger-span-literal.ets", ES2PANDA_STATE_CHECKED,
475 "enum MyEnum { FixedValue = 42 }");
476 ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED);
477
478 auto ast = GetAstFromContext<ark::es2panda::ir::AstNode>(ctx);
479 auto enumClass = ast->FindChild([](ark::es2panda::ir::AstNode *child) {
480 return child->IsClassDefinition() && child->AsClassDefinition()->Ident()->Name() == "MyEnum";
481 });
482 auto enumDecl = enumClass->AsClassDefinition()->OrigEnumDecl()->AsTSEnumDeclaration();
483 auto targetNode = enumDecl->FindChild([](ark::es2panda::ir::AstNode *node) {
484 return node->IsNumberLiteral() && node->AsNumberLiteral()->Str() == "42";
485 });
486
487 ASSERT_NE(targetNode, nullptr);
488 ASSERT_FALSE(ark::es2panda::lsp::NodeIsEligibleForRename(targetNode));
489 initializer.DestroyContext(ctx);
490 }
491