• 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 #include <cstddef>
16 #include <cstdio>
17 #include <string>
18 #include <vector>
19 #include <regex>
20 #include "lsp_api_test.h"
21 #include "lsp/include/find_rename_locations.h"
22 #include <gtest/gtest.h>
23 
24 // NOLINTBEGIN
25 std::vector<std::string> fileNames = {"findRenameLocsOne.ets", "findRenameLocsTwo.ets"};
26 std::vector<std::string> fileContents = {
27     R"(
28         export function abc(x: number): void {
29         }
30 
31         export function dummy(x: number): void {
32         }
33 
34         export class Foo {
35             name: string = "unassigned";
36             x: number = 1;
37             y: number = 2;
38             z: number = 3;
39             constructor(name: string, x: number, y: number, z: number) {
40                 this.name = name;
41                 this.x = x;
42                 this.y = y;
43                 this.z = z;
44             }
45         };
46 
47         export class Oranges {
48             name: string = "unassigned";
49             x: number = 1;
50             y: number = 2;
51             z: number = 3;
52             constructor(name: string, x: number, y: number, z: number) {
53                 this.name = name;
54                 this.x = x;
55                 this.y = y;
56                 this.z = z;
57             }
58         };
59 
60         dummy(0);
61         dummy(1);
62         abc(2);
63         abc(3);
64         abc(4);
65         )",
66     R"(
67         import { dummy, abc, Foo  } from "./findRenameLocsOne.ets";
68 
69         dummy(4);
70         dummy(44);
71         abc(5);
72         abc(55);
73         abc(555);
74 
75         let myfoo = new Foo("apples", 1, 2, 3);
76         let otherfoo = new Foo("oranges", 4, 5, 6);
77 
78         console.log(myfoo)
79         console.log(otherfoo)
80         console.log(myfoo.name)
81     )"};
82 
getLine(std::string source,size_t pos)83 static size_t getLine(std::string source, size_t pos)
84 {
85     size_t line = 0;
86     for (auto it = source.begin(); it < source.end() && it < source.begin() + pos; ++it) {
87         if (*it == '\n') {
88             ++line;
89         }
90     }
91     return line;
92 }
93 
getLineStart(std::string source,size_t pos)94 static size_t getLineStart(std::string source, size_t pos)
95 {
96     auto it = source.begin() + pos;
97     while (it > source.begin() && *(it - 1) != '\n') {
98         --it;
99     }
100     return it - source.begin();
101 }
102 
getLineEnd(std::string source,size_t pos)103 static size_t getLineEnd(std::string source, size_t pos)
104 {
105     auto it = source.begin() + pos;
106     while (it < source.end() && *it != '\n') {
107         ++it;
108     }
109     return it - source.begin();
110 }
111 
112 class LspFindRenameLocationsTests : public LSPAPITests {
113 public:
genTestData(std::string word,std::string filePath,std::string source)114     std::set<ark::es2panda::lsp::RenameLocation> genTestData(std::string word, std::string filePath, std::string source)
115     {
116         std::set<ark::es2panda::lsp::RenameLocation> data;
117         std::regex regex {"\\W" + word + "\\W"};
118         auto matchBeg = std::sregex_iterator {source.begin(), source.end(), regex};
119         auto matchEnd = std::sregex_iterator();
120 
121         for (auto it = matchBeg; it != matchEnd; ++it) {
122             size_t pos = it->position() + 1;
123             size_t line = getLine(source, pos);
124             size_t lineStartPos = getLineStart(source, pos);
125             size_t lineEndPos = getLineEnd(source, pos);
126             std::string prefix {source.begin() + lineStartPos, source.begin() + pos};
127             std::string suffix {source.begin() + pos + word.length(), source.begin() + lineEndPos};
128             ark::es2panda::lsp::RenameLocation loc {filePath, pos, pos + word.length(), line, prefix, suffix};
129             printf("{R\"(%s)\", %ld, %ld, %ld, R\"(%s)\", R\"(%s)\"},\n", loc.filePath.c_str(), loc.start, loc.end,
130                    loc.line, loc.prefixText.c_str(), loc.suffixText.c_str());
131             data.insert(loc);
132         }
133 
134         return data;
135     }
136 
genTestData(std::string pattern)137     std::set<ark::es2panda::lsp::RenameLocation> genTestData(std::string pattern)
138     {
139         // Create the files
140         auto filePaths = CreateTempFile(fileNames, fileContents);
141 
142         std::set<ark::es2panda::lsp::RenameLocation> data;
143         printf("std::set<ark::es2panda::lsp::RenameLocation> expected_%s = {\n", pattern.c_str());
144         for (size_t i = 0; i < filePaths.size(); ++i) {
145             auto entries = genTestData(pattern, filePaths[i], fileContents[i]);
146             for (const auto &entry : entries) {
147                 data.insert(entry);
148             }
149         }
150         printf("};\n");
151         return data;
152     }
153 };
154 
TEST_F(LspFindRenameLocationsTests,DISABLED_genTestData)155 TEST_F(LspFindRenameLocationsTests, DISABLED_genTestData)
156 {
157     auto data = genTestData("Foo");
158     data = genTestData("abc");
159     data = genTestData("dummy");
160     data = genTestData("name");
161     (void)data;
162 }
163 
164 std::set<ark::es2panda::lsp::RenameLocation> expected_Foo = {
165     {R"(/tmp/findRenameLocsOne.ets)", 140, 143, 7, R"(        export class )", R"( {)"},
166     {R"(/tmp/findRenameLocsTwo.ets)", 30, 33, 1, R"(        import { dummy, abc, )",
167      R"(  } from "./findRenameLocsOne.ets";)"},
168     {R"(/tmp/findRenameLocsTwo.ets)", 183, 186, 9, R"(        let myfoo = new )", R"(("apples", 1, 2, 3);)"},
169     {R"(/tmp/findRenameLocsTwo.ets)", 234, 237, 10, R"(        let otherfoo = new )", R"(("oranges", 4, 5, 6);)"},
170 };
171 std::set<ark::es2panda::lsp::RenameLocation> expected_abc = {
172     {R"(/tmp/findRenameLocsOne.ets)", 25, 28, 1, R"(        export function )", R"((x: number): void {)"},
173     {R"(/tmp/findRenameLocsOne.ets)", 899, 902, 35, R"(        )", R"((2);)"},
174     {R"(/tmp/findRenameLocsOne.ets)", 915, 918, 36, R"(        )", R"((3);)"},
175     {R"(/tmp/findRenameLocsOne.ets)", 931, 934, 37, R"(        )", R"((4);)"},
176     {R"(/tmp/findRenameLocsTwo.ets)", 25, 28, 1, R"(        import { dummy, )",
177      R"(, Foo  } from "./findRenameLocsOne.ets";)"},
178     {R"(/tmp/findRenameLocsTwo.ets)", 115, 118, 5, R"(        )", R"((5);)"},
179     {R"(/tmp/findRenameLocsTwo.ets)", 131, 134, 6, R"(        )", R"((55);)"},
180     {R"(/tmp/findRenameLocsTwo.ets)", 148, 151, 7, R"(        )", R"((555);)"},
181 };
182 std::set<ark::es2panda::lsp::RenameLocation> expected_dummy = {
183     {R"(/tmp/findRenameLocsOne.ets)", 83, 88, 4, R"(        export function )", R"((x: number): void {)"},
184     {R"(/tmp/findRenameLocsOne.ets)", 863, 868, 33, R"(        )", R"((0);)"},
185     {R"(/tmp/findRenameLocsOne.ets)", 881, 886, 34, R"(        )", R"((1);)"},
186     {R"(/tmp/findRenameLocsTwo.ets)", 18, 23, 1, R"(        import { )",
187      R"(, abc, Foo  } from "./findRenameLocsOne.ets";)"},
188     {R"(/tmp/findRenameLocsTwo.ets)", 78, 83, 3, R"(        )", R"((4);)"},
189     {R"(/tmp/findRenameLocsTwo.ets)", 96, 101, 4, R"(        )", R"((44);)"},
190 };
191 std::set<ark::es2panda::lsp::RenameLocation> expected_name = {
192     {R"(/tmp/findRenameLocsOne.ets)", 158, 162, 8, R"(            )", R"(: string = "unassigned";)"},
193     {R"(/tmp/findRenameLocsOne.ets)", 362, 366, 13, R"(                this.)", R"( = name;)"},
194     {R"(/tmp/findRenameLocsTwo.ets)", 343, 347, 14, R"(        console.log(myfoo.)", R"())"},
195 };
196 
TEST_F(LspFindRenameLocationsTests,FindRenameLocationsClassName)197 TEST_F(LspFindRenameLocationsTests, FindRenameLocationsClassName)
198 {
199     // Create the files
200     auto filePaths = CreateTempFile(fileNames, fileContents);
201     std::vector<ark::es2panda::SourceFile> sourceFiles;
202     for (size_t i = 0; i < filePaths.size(); ++i) {
203         sourceFiles.emplace_back(ark::es2panda::SourceFile {filePaths[i], fileContents[i]});
204     }
205     ASSERT_TRUE(sourceFiles.size() == fileNames.size());
206 
207     // Search for rename locations
208     ark::es2panda::lsp::CancellationToken cancellationToken {123, nullptr};
209     auto res = ark::es2panda::lsp::FindRenameLocations(&cancellationToken, sourceFiles, sourceFiles[1], 30);
210     ASSERT_EQ(res.size(), expected_Foo.size());
211     for (auto renameLoc : res) {
212         auto found = expected_Foo.find(renameLoc);
213         ASSERT_TRUE(found != expected_Foo.end());
214     }
215 }
216 
TEST_F(LspFindRenameLocationsTests,FindRenameLocationsFunctionName)217 TEST_F(LspFindRenameLocationsTests, FindRenameLocationsFunctionName)
218 {
219     // Create the files
220     auto filePaths = CreateTempFile(fileNames, fileContents);
221     std::vector<ark::es2panda::SourceFile> sourceFiles;
222     for (size_t i = 0; i < filePaths.size(); ++i) {
223         sourceFiles.emplace_back(ark::es2panda::SourceFile {filePaths[i], fileContents[i]});
224     }
225     ASSERT_TRUE(sourceFiles.size() == fileNames.size());
226 
227     // Search for rename locations
228     ark::es2panda::lsp::CancellationToken cancellationToken {123, nullptr};
229     auto res = ark::es2panda::lsp::FindRenameLocations(&cancellationToken, sourceFiles, sourceFiles[0], 25);
230     ASSERT_EQ(res.size(), expected_abc.size());
231     for (auto renameLoc : res) {
232         auto found = expected_abc.find(renameLoc);
233         ASSERT_TRUE(found != expected_abc.end());
234     }
235 }
236 
TEST_F(LspFindRenameLocationsTests,FindRenameLocationsFunctionName2)237 TEST_F(LspFindRenameLocationsTests, FindRenameLocationsFunctionName2)
238 {
239     // Create the files
240     auto filePaths = CreateTempFile(fileNames, fileContents);
241     std::vector<ark::es2panda::SourceFile> sourceFiles;
242     for (size_t i = 0; i < filePaths.size(); ++i) {
243         sourceFiles.emplace_back(ark::es2panda::SourceFile {filePaths[i], fileContents[i]});
244     }
245     ASSERT_TRUE(sourceFiles.size() == fileNames.size());
246 
247     // Search for rename locations
248     ark::es2panda::lsp::CancellationToken cancellationToken {123, nullptr};
249     auto res = ark::es2panda::lsp::FindRenameLocations(&cancellationToken, sourceFiles, sourceFiles[0], 83);
250     ASSERT_EQ(res.size(), expected_dummy.size());
251     for (auto renameLoc : res) {
252         auto found = expected_dummy.find(renameLoc);
253         ASSERT_TRUE(found != expected_dummy.end());
254     }
255 }
256 
TEST_F(LspFindRenameLocationsTests,FindRenameLocationsClassMemberName)257 TEST_F(LspFindRenameLocationsTests, FindRenameLocationsClassMemberName)
258 {
259     // Create the files
260     auto filePaths = CreateTempFile(fileNames, fileContents);
261     std::vector<ark::es2panda::SourceFile> sourceFiles;
262     for (size_t i = 0; i < filePaths.size(); ++i) {
263         sourceFiles.emplace_back(ark::es2panda::SourceFile {filePaths[i], fileContents[i]});
264     }
265     ASSERT_TRUE(sourceFiles.size() == fileNames.size());
266 
267     // Search for rename locations
268     ark::es2panda::lsp::CancellationToken cancellationToken {123, nullptr};
269     auto res = ark::es2panda::lsp::FindRenameLocations(&cancellationToken, sourceFiles, sourceFiles[0], 158);
270     ASSERT_EQ(res.size(), expected_name.size());
271     for (auto renameLoc : res) {
272         auto found = expected_name.find(renameLoc);
273         ASSERT_TRUE(found != expected_name.end());
274     }
275 }
276 
277 // NOLINTEND