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 <gtest/gtest.h>
16 #include <cstddef>
17 #include <cstdio>
18 #include <string>
19 #include <vector>
20
21 #include "es2panda.h"
22 #include "lsp/include/find_references.h"
23 #include "lsp/include/cancellation_token.h"
24 #include "lsp_api_test.h"
25
26 // NOLINTBEGIN
27 using ark::es2panda::SourceFile;
28 using ark::es2panda::lexer::SourcePosition;
29 using ark::es2panda::lsp::FindReferences;
30 using std::string;
31 using std::vector;
32
testCase(vector<SourceFile> & sourceFiles,SourceFile selectedFile,size_t tokenOffset,std::set<ark::es2panda::lsp::ReferencedNode> expected)33 static auto testCase(vector<SourceFile> &sourceFiles, SourceFile selectedFile, size_t tokenOffset,
34 std::set<ark::es2panda::lsp::ReferencedNode> expected)
35 {
36 auto cancellationToken = ark::es2panda::lsp::CancellationToken(123, nullptr);
37 auto res = FindReferences(&cancellationToken, sourceFiles, selectedFile, tokenOffset);
38
39 (void)res;
40
41 ASSERT_EQ(res.size(), expected.size());
42
43 for (const ark::es2panda::lsp::ReferencedNode &reference : res) {
44 auto found = expected.find(reference);
45 ASSERT_NE(found, expected.end());
46 }
47 }
48
49 vector<string> fileNames = {"findReferencesOne.ets", "findReferencesTwo.ets"};
50 vector<string> fileContents = {
51 R"(
52 export function abc(x: number): void {
53 }
54
55 export function dummy(x: number): void {
56 }
57
58 export class Foo {
59 name: string = "unassigned";
60 x: number = 1;
61 y: number = 2;
62 z: number = 3;
63 constructor(name: string, x: number, y: number, z: number) {
64 this.name = name;
65 this.x = x;
66 this.y = y;
67 this.z = z;
68 }
69 };
70
71 export class Oranges {
72 name: string = "unassigned";
73 x: number = 1;
74 y: number = 2;
75 z: number = 3;
76 constructor(name: string, x: number, y: number, z: number) {
77 this.name = name;
78 this.x = x;
79 this.y = y;
80 this.z = z;
81 }
82 };
83
84 dummy(0);
85 dummy(1);
86 abc(2);
87 abc(3);
88 abc(4);
89 )",
90 R"(
91 import { dummy, abc, Foo } from "./findReferencesOne.ets";
92
93 dummy(4);
94 dummy(44);
95 abc(5);
96 abc(55);
97 abc(555);
98
99 let myfoo = new Foo("apples", 1, 2, 3);
100 let otherfoo = new Foo("oranges", 4, 5, 6);
101
102 console.log(myfoo)
103 console.log(otherfoo)
104 console.log(myfoo.name)
105 )"};
106
107 std::set<ark::es2panda::lsp::ReferencedNode> expected_dummy = {
108 {"/tmp/findReferencesOne.ets", 83, 88, 4, true}, {"/tmp/findReferencesOne.ets", 863, 868, 33, false},
109 {"/tmp/findReferencesOne.ets", 881, 886, 34, false}, {"/tmp/findReferencesTwo.ets", 18, 23, 1, false},
110 {"/tmp/findReferencesTwo.ets", 78, 83, 3, false}, {"/tmp/findReferencesTwo.ets", 96, 101, 4, false},
111 };
112
113 std::set<ark::es2panda::lsp::ReferencedNode> expected_abc = {
114 {"/tmp/findReferencesOne.ets", 25, 28, 1, true}, {"/tmp/findReferencesOne.ets", 899, 902, 35, false},
115 {"/tmp/findReferencesOne.ets", 915, 918, 36, false}, {"/tmp/findReferencesOne.ets", 931, 934, 37, false},
116 {"/tmp/findReferencesTwo.ets", 25, 28, 1, false}, {"/tmp/findReferencesTwo.ets", 115, 118, 5, false},
117 {"/tmp/findReferencesTwo.ets", 131, 134, 6, false}, {"/tmp/findReferencesTwo.ets", 148, 151, 7, false},
118 };
119
120 std::set<ark::es2panda::lsp::ReferencedNode> expected_myfoo = {
121 {"/tmp/findReferencesTwo.ets", 171, 176, 9, true},
122 {"/tmp/findReferencesTwo.ets", 280, 285, 12, false},
123 {"/tmp/findReferencesTwo.ets", 337, 342, 14, false},
124 };
125
126 std::set<ark::es2panda::lsp::ReferencedNode> expected_Foo = {
127 {"/tmp/findReferencesOne.ets", 140, 143, 7, true},
128 {"/tmp/findReferencesTwo.ets", 30, 33, 1, false},
129 {"/tmp/findReferencesTwo.ets", 183, 186, 9, false},
130 {"/tmp/findReferencesTwo.ets", 234, 237, 10, false},
131 };
132
133 std::set<ark::es2panda::lsp::ReferencedNode> expected_name = {
134 {"/tmp/findReferencesOne.ets", 158, 162, 8, true},
135 {"/tmp/findReferencesOne.ets", 362, 366, 13, false},
136 {"/tmp/findReferencesTwo.ets", 343, 347, 14, false},
137 };
138
139 class LspFindRefTests : public LSPAPITests {};
140
TEST_F(LspFindRefTests,FindReferencesMethodDefinition1)141 TEST_F(LspFindRefTests, FindReferencesMethodDefinition1)
142 {
143 // Create the files
144 auto filePaths = CreateTempFile(fileNames, fileContents);
145 vector<SourceFile> sourceFiles;
146 for (size_t i = 0; i < filePaths.size(); ++i) {
147 sourceFiles.emplace_back(SourceFile {filePaths[i], fileContents[i]});
148 }
149 ASSERT_TRUE(sourceFiles.size() == fileNames.size());
150
151 // Case 1: Search for the first occurance of "abc" within "findReferencesOne.ets" which is a method definition
152 {
153 auto srcIndex = 0;
154 size_t tokenOffset = 25;
155 testCase(sourceFiles, sourceFiles[srcIndex], tokenOffset, expected_abc);
156 }
157 }
158
TEST_F(LspFindRefTests,FindReferencesMethodDefinition2)159 TEST_F(LspFindRefTests, FindReferencesMethodDefinition2)
160 {
161 // Create the files
162 auto filePaths = CreateTempFile(fileNames, fileContents);
163 vector<SourceFile> sourceFiles;
164 for (size_t i = 0; i < filePaths.size(); ++i) {
165 sourceFiles.emplace_back(SourceFile {filePaths[i], fileContents[i]});
166 }
167 ASSERT_TRUE(sourceFiles.size() == fileNames.size());
168
169 // Case 2: Search for the first occurance of "dummy" within "findReferencesOne.ets" which is a method definition
170 {
171 auto srcIndex = 0;
172 size_t tokenOffset = 83;
173 testCase(sourceFiles, sourceFiles[srcIndex], tokenOffset, expected_dummy);
174 }
175 }
176
TEST_F(LspFindRefTests,FindReferencesImportSpecifier)177 TEST_F(LspFindRefTests, FindReferencesImportSpecifier)
178 {
179 // Create the files
180 auto filePaths = CreateTempFile(fileNames, fileContents);
181 vector<SourceFile> sourceFiles;
182 for (size_t i = 0; i < filePaths.size(); ++i) {
183 sourceFiles.emplace_back(SourceFile {filePaths[i], fileContents[i]});
184 }
185 ASSERT_TRUE(sourceFiles.size() == fileNames.size());
186
187 // Case 3: Search for the first occurance of "abc" within "findReferencesTwo.ets" which is an import specifier
188 {
189 auto srcIndex = 1;
190 size_t tokenOffset = 25;
191 testCase(sourceFiles, sourceFiles[srcIndex], tokenOffset, expected_abc);
192 }
193 }
194
TEST_F(LspFindRefTests,FindReferencesCallExpression1)195 TEST_F(LspFindRefTests, FindReferencesCallExpression1)
196 {
197 // Create the files
198 auto filePaths = CreateTempFile(fileNames, fileContents);
199 vector<SourceFile> sourceFiles;
200 for (size_t i = 0; i < filePaths.size(); ++i) {
201 sourceFiles.emplace_back(SourceFile {filePaths[i], fileContents[i]});
202 }
203 ASSERT_TRUE(sourceFiles.size() == fileNames.size());
204
205 // Case 4: Search for the second occurance of "abc" within "findReferencesTwo.ets" which is a function call
206 // expression
207 {
208 auto srcIndex = 1;
209 size_t tokenOffset = 115;
210 testCase(sourceFiles, sourceFiles[srcIndex], tokenOffset, expected_abc);
211 }
212 }
213
TEST_F(LspFindRefTests,FindReferencesCallExpression2)214 TEST_F(LspFindRefTests, FindReferencesCallExpression2)
215 {
216 // Create the files
217 auto filePaths = CreateTempFile(fileNames, fileContents);
218 vector<SourceFile> sourceFiles;
219 for (size_t i = 0; i < filePaths.size(); ++i) {
220 sourceFiles.emplace_back(SourceFile {filePaths[i], fileContents[i]});
221 }
222 ASSERT_TRUE(sourceFiles.size() == fileNames.size());
223
224 // Case 5: Search for the second occurance of "dummy" within "findReferencesTwo.ets" which is a function call
225 // expression
226 {
227 auto srcIndex = 1;
228 size_t tokenOffset = 78;
229 testCase(sourceFiles, sourceFiles[srcIndex], tokenOffset, expected_dummy);
230 }
231 }
232
TEST_F(LspFindRefTests,FindReferencesVariableDefinition)233 TEST_F(LspFindRefTests, FindReferencesVariableDefinition)
234 {
235 // Create the files
236 auto filePaths = CreateTempFile(fileNames, fileContents);
237 vector<SourceFile> sourceFiles;
238 for (size_t i = 0; i < filePaths.size(); ++i) {
239 sourceFiles.emplace_back(SourceFile {filePaths[i], fileContents[i]});
240 }
241 ASSERT_TRUE(sourceFiles.size() == fileNames.size());
242
243 // Case 6: Search for the first occurance of "myfoo" within "findReferencesTwo.ets" which is a variable definition
244 {
245 auto srcIndex = 1;
246 size_t tokenOffset = 171;
247 testCase(sourceFiles, sourceFiles[srcIndex], tokenOffset, expected_myfoo);
248 }
249 }
250
TEST_F(LspFindRefTests,FindReferencesInstanceCreation)251 TEST_F(LspFindRefTests, FindReferencesInstanceCreation)
252 {
253 // Create the files
254 auto filePaths = CreateTempFile(fileNames, fileContents);
255 vector<SourceFile> sourceFiles;
256 for (size_t i = 0; i < filePaths.size(); ++i) {
257 sourceFiles.emplace_back(SourceFile {filePaths[i], fileContents[i]});
258 }
259 ASSERT_TRUE(sourceFiles.size() == fileNames.size());
260
261 // Case 7: Search for the first occurance of "Foo" within "findReferencesTwo.ets" which is a class instance creation
262 {
263 auto srcIndex = 1;
264 size_t tokenOffset = 30;
265 testCase(sourceFiles, sourceFiles[srcIndex], tokenOffset, expected_Foo);
266 }
267 }
268
TEST_F(LspFindRefTests,FindReferencesMemberAccess)269 TEST_F(LspFindRefTests, FindReferencesMemberAccess)
270 {
271 // Create the files
272 auto filePaths = CreateTempFile(fileNames, fileContents);
273 vector<SourceFile> sourceFiles;
274 for (size_t i = 0; i < filePaths.size(); ++i) {
275 sourceFiles.emplace_back(SourceFile {filePaths[i], fileContents[i]});
276 }
277 ASSERT_TRUE(sourceFiles.size() == fileNames.size());
278
279 // Case 7: Search for the first occurance of "name" within "findReferencesTwo.ets" which is a reference to a member
280 {
281 auto srcIndex = 1;
282 size_t tknIndex = 343;
283
284 testCase(sourceFiles, sourceFiles[srcIndex], tknIndex, expected_name);
285 }
286 }
287
288 // NOLINTEND
289