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_api_test.h"
17 #include "lsp/include/internal_api.h"
18
19 using ark::es2panda::lsp::Initializer;
20
21 class LspDocumentHighlights : public LSPAPITests {};
22
TEST_F(LspDocumentHighlights,getDocumentHighlights1)23 TEST_F(LspDocumentHighlights, getDocumentHighlights1)
24 {
25 std::vector<std::string> files = {"getDocumentHighlights1.ets"};
26 std::vector<std::string> texts = {R"delimiter(
27 let aaa = 123;
28 let bbb = aaa + 111;
29 let ccc = bbb + aaa + 234;
30 )delimiter"};
31 auto filePaths = CreateTempFile(files, texts);
32 int const expectedFileCount = 1;
33 ASSERT_EQ(filePaths.size(), expectedFileCount);
34
35 LSPAPI const *lspApi = GetImpl();
36 auto const pos = 6;
37 Initializer initializer = Initializer();
38 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
39 auto result = lspApi->getDocumentHighlights(ctx, pos);
40 initializer.DestroyContext(ctx);
41 auto const expectedHighlightCount = 3;
42 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_.size(), expectedHighlightCount);
43 ASSERT_EQ(result.documentHighlights_[0].fileName_, filePaths[0]);
44 auto const firstHighlightStart = 5;
45 auto const secondHighlightStart = 26;
46 auto const thirdHighlightStart = 53;
47 auto const expectedLength = 3;
48 auto const secondIndex = 2;
49 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.start, firstHighlightStart);
50 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.start, secondHighlightStart);
51 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.start, thirdHighlightStart);
52 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.length, expectedLength);
53 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.length, expectedLength);
54 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.length, expectedLength);
55 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].kind_, HighlightSpanKind::WRITTEN_REFERENCE);
56 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].kind_, HighlightSpanKind::REFERENCE);
57 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].kind_, HighlightSpanKind::REFERENCE);
58 }
59
TEST_F(LspDocumentHighlights,getDocumentHighlights2)60 TEST_F(LspDocumentHighlights, getDocumentHighlights2)
61 {
62 std::vector<std::string> files = {"getDocumentHighlights2.ets"};
63 std::vector<std::string> texts = {R"delimiter(
64 let aaa = 123;
65 let bbb = aaa + 111;
66 let ccc = bbb + aaa + 234;
67 function f1(aaa: number) {
68 return aaa + bbb;})delimiter"};
69 auto filePaths = CreateTempFile(files, texts);
70 int const expectedFileCount = 1;
71 ASSERT_EQ(filePaths.size(), expectedFileCount);
72 LSPAPI const *lspApi = GetImpl();
73 auto const firstPos = 109;
74 Initializer initializer = Initializer();
75 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
76 auto firstResult = lspApi->getDocumentHighlights(ctx, firstPos);
77 auto const firstExpectedHighlightCount = 3;
78 ASSERT_EQ(firstResult.documentHighlights_[0].highlightSpans_.size(), firstExpectedHighlightCount);
79 ASSERT_EQ(firstResult.documentHighlights_[0].fileName_, filePaths[0]);
80 auto const firstFirstHighlightStart = 20;
81 auto const firstSecondHighlightStart = 47;
82 auto const firstThirdHighlightStart = 108;
83 auto const firstExpectedLength = 3;
84 auto const secondIndex = 2;
85 ASSERT_EQ(firstResult.documentHighlights_[0].highlightSpans_[0].textSpan_.start, firstFirstHighlightStart);
86 ASSERT_EQ(firstResult.documentHighlights_[0].highlightSpans_[1].textSpan_.start, firstSecondHighlightStart);
87 ASSERT_EQ(firstResult.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.start,
88 firstThirdHighlightStart);
89 ASSERT_EQ(firstResult.documentHighlights_[0].highlightSpans_[0].textSpan_.length, firstExpectedLength);
90 ASSERT_EQ(firstResult.documentHighlights_[0].highlightSpans_[1].textSpan_.length, firstExpectedLength);
91 ASSERT_EQ(firstResult.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.length, firstExpectedLength);
92 ASSERT_EQ(firstResult.documentHighlights_[0].highlightSpans_[0].kind_, HighlightSpanKind::WRITTEN_REFERENCE);
93 ASSERT_EQ(firstResult.documentHighlights_[0].highlightSpans_[1].kind_, HighlightSpanKind::REFERENCE);
94 ASSERT_EQ(firstResult.documentHighlights_[0].highlightSpans_[secondIndex].kind_, HighlightSpanKind::REFERENCE);
95 auto const secondPos = 77;
96 auto secondResult = lspApi->getDocumentHighlights(ctx, secondPos);
97 initializer.DestroyContext(ctx);
98 auto const secondExpectedHighlightCount = 2;
99 ASSERT_EQ(secondResult.documentHighlights_[0].highlightSpans_.size(), secondExpectedHighlightCount);
100 ASSERT_EQ(secondResult.documentHighlights_[0].fileName_, filePaths[0]);
101 auto const secondFirstHighlightStart = 76;
102 auto const secondSecondHighlightStart = 102;
103 auto const secondExpectedLength = 3;
104 ASSERT_EQ(secondResult.documentHighlights_[0].highlightSpans_[0].textSpan_.start, secondFirstHighlightStart);
105 ASSERT_EQ(secondResult.documentHighlights_[0].highlightSpans_[1].textSpan_.start, secondSecondHighlightStart);
106 ASSERT_EQ(secondResult.documentHighlights_[0].highlightSpans_[0].textSpan_.length, secondExpectedLength);
107 ASSERT_EQ(secondResult.documentHighlights_[0].highlightSpans_[1].textSpan_.length, secondExpectedLength);
108 ASSERT_EQ(secondResult.documentHighlights_[0].highlightSpans_[0].kind_, HighlightSpanKind::WRITTEN_REFERENCE);
109 ASSERT_EQ(secondResult.documentHighlights_[0].highlightSpans_[1].kind_, HighlightSpanKind::REFERENCE);
110 }
111
TEST_F(LspDocumentHighlights,getDocumentHighlights3)112 TEST_F(LspDocumentHighlights, getDocumentHighlights3)
113 {
114 std::vector<std::string> files = {"getDocumentHighlights3.ets"};
115 std::vector<std::string> texts = {R"delimiter(
116 class Foo {
117 aaa: number = 0;
118 }
119
120 let foo1 = new Foo();
121 foo1.aaa = 222
122
123 function f2() {
124 let foo2 = new Foo();
125 return foo2.aaa + foo1.aaa;
126 }
127 )delimiter"};
128 auto filePaths = CreateTempFile(files, texts);
129 int const expectedFileCount = 1;
130 ASSERT_EQ(filePaths.size(), expectedFileCount);
131
132 LSPAPI const *lspApi = GetImpl();
133 auto const pos = 8;
134 Initializer initializer = Initializer();
135 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
136 auto result = lspApi->getDocumentHighlights(ctx, pos);
137 initializer.DestroyContext(ctx);
138 auto const expectedHighlightCount = 3;
139 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_.size(), expectedHighlightCount);
140 ASSERT_EQ(result.documentHighlights_[0].fileName_, filePaths[0]);
141 auto const firstHighlightStart = 7;
142 auto const secondHighlightStart = 52;
143 auto const thirdHighlightStart = 110;
144 auto const expectedLength = 3;
145 auto const secondIndex = 2;
146 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.start, firstHighlightStart);
147 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.start, secondHighlightStart);
148 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.start, thirdHighlightStart);
149 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.length, expectedLength);
150 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.length, expectedLength);
151 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.length, expectedLength);
152 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].kind_, HighlightSpanKind::WRITTEN_REFERENCE);
153 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].kind_, HighlightSpanKind::REFERENCE);
154 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].kind_, HighlightSpanKind::REFERENCE);
155 }
156
TEST_F(LspDocumentHighlights,getDocumentHighlights4)157 TEST_F(LspDocumentHighlights, getDocumentHighlights4)
158 {
159 std::vector<std::string> files = {"getDocumentHighlights3.ets"};
160 std::vector<std::string> texts = {R"delimiter(
161 class Foo {
162 aaa: number = 0;
163 }
164
165 let foo1 = new Foo();
166 foo1.aaa = 222
167
168 function f2() {
169 let foo2 = new Foo();
170 return foo2.aaa + foo1.aaa;
171 }
172 )delimiter"};
173 auto filePaths = CreateTempFile(files, texts);
174 int const expectedFileCount = 1;
175 ASSERT_EQ(filePaths.size(), expectedFileCount);
176
177 LSPAPI const *lspApi = GetImpl();
178 auto const pos = 18;
179 Initializer initializer = Initializer();
180 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
181 auto result = lspApi->getDocumentHighlights(ctx, pos);
182 initializer.DestroyContext(ctx);
183 auto const expectedHighlightCount = 4;
184 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_.size(), expectedHighlightCount);
185 ASSERT_EQ(result.documentHighlights_[0].fileName_, filePaths[0]);
186 auto const firstHighlightStart = 17;
187 auto const secondHighlightStart = 64;
188 auto const thirdHighlightStart = 133;
189 auto const fourthHighlightStart = 144;
190 auto const expectedLength = 3;
191 auto const secondIndex = 2;
192 auto const thirdIndex = 3;
193 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.start, firstHighlightStart);
194 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.start, secondHighlightStart);
195 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.start, thirdHighlightStart);
196 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[thirdIndex].textSpan_.start, fourthHighlightStart);
197 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.length, expectedLength);
198 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.length, expectedLength);
199 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.length, expectedLength);
200 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[thirdIndex].textSpan_.length, expectedLength);
201 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].kind_, HighlightSpanKind::WRITTEN_REFERENCE);
202 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].kind_, HighlightSpanKind::REFERENCE);
203 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].kind_, HighlightSpanKind::REFERENCE);
204 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[thirdIndex].kind_, HighlightSpanKind::REFERENCE);
205 }
206
TEST_F(LspDocumentHighlights,getDocumentHighlights5)207 TEST_F(LspDocumentHighlights, getDocumentHighlights5)
208 {
209 std::vector<std::string> files = {"getDocumentHighlights5.ets"};
210 std::vector<std::string> texts = {R"delimiter(
211 function add(x: number, y: number) {
212 return x + y;
213 }
214
215 function five() {
216 return add(2, 3);
217 }
218
219 class Bar {
220 six: number = add(2, 4);
221 }
222 )delimiter"};
223 auto filePaths = CreateTempFile(files, texts);
224 int const expectedFileCount = 1;
225 ASSERT_EQ(filePaths.size(), expectedFileCount);
226
227 LSPAPI const *lspApi = GetImpl();
228 auto const pos = 11;
229 Initializer initializer = Initializer();
230 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
231 auto result = lspApi->getDocumentHighlights(ctx, pos);
232 initializer.DestroyContext(ctx);
233 auto const expectedHighlightCount = 3;
234 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_.size(), expectedHighlightCount);
235 ASSERT_EQ(result.documentHighlights_[0].fileName_, filePaths[0]);
236 auto const firstHighlightStart = 10;
237 auto const secondHighlightStart = 88;
238 auto const thirdHighlightStart = 132;
239 auto const expectedLength = 3;
240 auto const secondIndex = 2;
241 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.start, firstHighlightStart);
242 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.start, secondHighlightStart);
243 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.start, thirdHighlightStart);
244 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.length, expectedLength);
245 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.length, expectedLength);
246 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.length, expectedLength);
247 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].kind_, HighlightSpanKind::WRITTEN_REFERENCE);
248 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].kind_, HighlightSpanKind::REFERENCE);
249 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].kind_, HighlightSpanKind::REFERENCE);
250 }
251
TEST_F(LspDocumentHighlights,getDocumentHighlights6)252 TEST_F(LspDocumentHighlights, getDocumentHighlights6)
253 {
254 std::vector<std::string> files = {"getDocumentHighlights6.ets"};
255 std::vector<std::string> texts = {R"delimiter(
256 class ListNode<T> {
257 value: T;
258 next: ListNode<T> | null = null;
259
260 constructor(value: T) {
261 this.value = value;
262 }
263 }
264 )delimiter"};
265 auto filePaths = CreateTempFile(files, texts);
266 int const expectedFileCount = 1;
267 ASSERT_EQ(filePaths.size(), expectedFileCount);
268
269 LSPAPI const *lspApi = GetImpl();
270 auto const pos = 49;
271 Initializer initializer = Initializer();
272 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
273 auto result = lspApi->getDocumentHighlights(ctx, pos);
274 initializer.DestroyContext(ctx);
275 auto const expectedHighlightCount = 2;
276 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_.size(), expectedHighlightCount);
277 ASSERT_EQ(result.documentHighlights_[0].fileName_, filePaths[0]);
278 auto const firstHighlightStart = 7;
279 auto const secondHighlightStart = 45;
280 auto const expectedLength = 8;
281 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.start, firstHighlightStart);
282 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.start, secondHighlightStart);
283 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.length, expectedLength);
284 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.length, expectedLength);
285 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].kind_, HighlightSpanKind::WRITTEN_REFERENCE);
286 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].kind_, HighlightSpanKind::REFERENCE);
287 }
288
TEST_F(LspDocumentHighlights,getDocumentHighlights7)289 TEST_F(LspDocumentHighlights, getDocumentHighlights7)
290 {
291 std::vector<std::string> files = {"getDocumentHighlights7.ets"};
292 std::vector<std::string> texts = {R"delimiter(
293 function fib(n: number) {
294 if (n === 0) {
295 return 0;
296 }
297 if (n === 1) {
298 return 1;
299 }
300 return fib(n - 1) + fib(n - 2);
301 }
302 )delimiter"};
303 auto filePaths = CreateTempFile(files, texts);
304 int const expectedFileCount = 1;
305 ASSERT_EQ(filePaths.size(), expectedFileCount);
306
307 LSPAPI const *lspApi = GetImpl();
308 auto const pos = 125;
309 Initializer initializer = Initializer();
310 auto ctx = initializer.CreateContext(filePaths[0].c_str(), ES2PANDA_STATE_CHECKED);
311 auto result = lspApi->getDocumentHighlights(ctx, pos);
312 initializer.DestroyContext(ctx);
313 auto const expectedHighlightCount = 3;
314 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_.size(), expectedHighlightCount);
315 ASSERT_EQ(result.documentHighlights_[0].fileName_, filePaths[0]);
316 auto const firstHighlightStart = 10;
317 auto const secondHighlightStart = 124;
318 auto const thirdHighlightStart = 137;
319 auto const expectedLength = 3;
320 auto const secondIndex = 2;
321 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.start, firstHighlightStart);
322 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.start, secondHighlightStart);
323 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.start, thirdHighlightStart);
324 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].textSpan_.length, expectedLength);
325 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].textSpan_.length, expectedLength);
326 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].textSpan_.length, expectedLength);
327 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[0].kind_, HighlightSpanKind::WRITTEN_REFERENCE);
328 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[1].kind_, HighlightSpanKind::REFERENCE);
329 ASSERT_EQ(result.documentHighlights_[0].highlightSpans_[secondIndex].kind_, HighlightSpanKind::REFERENCE);
330 }
331