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 <cstddef>
17 #include <string>
18 #include <vector>
19 #include "lsp_api_test.h"
20 #include "lsp/include/internal_api.h"
21 #include "lsp/include/references.h"
22 #include "public/es2panda_lib.h"
23
24 using ark::es2panda::lsp::Initializer;
25
26 class LSPGetReferencesAtPositionTests : public LSPAPITests {
27 public:
28 LSPGetReferencesAtPositionTests() = default;
29 ~LSPGetReferencesAtPositionTests() override = default;
30
31 NO_COPY_SEMANTIC(LSPGetReferencesAtPositionTests);
32 NO_MOVE_SEMANTIC(LSPGetReferencesAtPositionTests);
33
MockGetReferencesAtPosition(char const * fileName,size_t position,const std::vector<std::string> & filePaths)34 References MockGetReferencesAtPosition(char const *fileName, size_t position,
35 const std::vector<std::string> &filePaths)
36 {
37 Initializer initializer = Initializer();
38 auto context = initializer.CreateContext(fileName, ES2PANDA_STATE_CHECKED);
39 auto astNode = ark::es2panda::lsp::GetTouchingToken(context, position, false);
40 auto declInfo = ark::es2panda::lsp::GetDeclInfoImpl(astNode);
41 initializer.DestroyContext(context);
42
43 References result {};
44 for (auto const &file : filePaths) {
45 auto fileContext = initializer.CreateContext(file.c_str(), ES2PANDA_STATE_CHECKED);
46 auto refInfo = ark::es2panda::lsp::GetReferencesAtPositionImpl(fileContext, declInfo);
47 result.referenceInfos.insert(result.referenceInfos.end(), refInfo.referenceInfos.begin(),
48 refInfo.referenceInfos.end());
49 initializer.DestroyContext(fileContext);
50 }
51 auto comp = [](const ReferenceInfo &lhs, const ReferenceInfo &rhs) {
52 if (lhs.fileName != rhs.fileName) {
53 return lhs.fileName < rhs.fileName;
54 }
55 if (lhs.start != rhs.start) {
56 return lhs.start < rhs.start;
57 }
58 return lhs.length < rhs.length;
59 };
60 ark::es2panda::lsp::RemoveDuplicates(result.referenceInfos, comp);
61 return result;
62 }
63 };
64
TEST_F(LSPGetReferencesAtPositionTests,GetReferencesAtPosition1)65 TEST_F(LSPGetReferencesAtPositionTests, GetReferencesAtPosition1)
66 {
67 std::vector<std::string> files = {"references1.ets"};
68 std::vector<std::string> texts = {R"(let a = 1;;)"};
69 auto filePaths = CreateTempFile(files, texts);
70 size_t const expectedFileCount = 1;
71 ASSERT_EQ(filePaths.size(), expectedFileCount);
72
73 size_t const position = 4;
74 References result = MockGetReferencesAtPosition(filePaths[0].c_str(), position, filePaths);
75 // NOLINTBEGIN(readability-magic-numbers)
76 std::vector<ReferenceInfo> expectedResult {{filePaths[0], 4, 1}};
77 // NOLINTEND(readability-magic-numbers)
78 ASSERT_EQ(result.referenceInfos.size(), expectedResult.size());
79 for (size_t i = 0; i < expectedResult.size(); i++) {
80 ASSERT_EQ(result.referenceInfos[i].fileName, expectedResult[i].fileName);
81 ASSERT_EQ(result.referenceInfos[i].start, expectedResult[i].start);
82 ASSERT_EQ(result.referenceInfos[i].length, expectedResult[i].length);
83 }
84 }
85
TEST_F(LSPGetReferencesAtPositionTests,GetReferencesAtPosition2)86 TEST_F(LSPGetReferencesAtPositionTests, GetReferencesAtPosition2)
87 {
88 std::vector<std::string> files = {"references2.ets", "references3.ets"};
89 std::vector<std::string> texts = {R"(export let a = 1;
90 let b = a;
91 function C() {
92 let c = a;
93 };
94 function D() {
95 let a = 1;
96 };)",
97 R"(import {a} from './references2';
98 console.log(a);)"};
99 auto filePaths = CreateTempFile(files, texts);
100 size_t const expectedFileCount = 2;
101 ASSERT_EQ(filePaths.size(), expectedFileCount);
102
103 size_t const position = 26;
104 References result = MockGetReferencesAtPosition(filePaths[0].c_str(), position, filePaths);
105 // NOLINTBEGIN(readability-magic-numbers)
106 std::vector<ReferenceInfo> expectedResult {{filePaths[0], 11, 1},
107 {filePaths[0], 26, 1},
108 {filePaths[0], 56, 1},
109 {filePaths[1], 8, 1},
110 {filePaths[1], 45, 1}};
111 // NOLINTEND(readability-magic-numbers)
112 ASSERT_EQ(result.referenceInfos.size(), expectedResult.size());
113 for (size_t i = 0; i < expectedResult.size(); i++) {
114 ASSERT_EQ(result.referenceInfos[i].fileName, expectedResult[i].fileName);
115 ASSERT_EQ(result.referenceInfos[i].start, expectedResult[i].start);
116 ASSERT_EQ(result.referenceInfos[i].length, expectedResult[i].length);
117 }
118 }
119
TEST_F(LSPGetReferencesAtPositionTests,GetReferencesAtPosition3)120 TEST_F(LSPGetReferencesAtPositionTests, GetReferencesAtPosition3)
121 {
122 std::vector<std::string> files = {"references4.ets", "references5.ets"};
123 std::vector<std::string> texts = {R"(export function A(){};)", R"(import {A} from './references4';
124 A();)"};
125 auto filePaths = CreateTempFile(files, texts);
126 size_t const expectedFileCount = 2;
127 ASSERT_EQ(filePaths.size(), expectedFileCount);
128
129 size_t const position = 16;
130 References result = MockGetReferencesAtPosition(filePaths[0].c_str(), position, filePaths);
131 // NOLINTBEGIN(readability-magic-numbers)
132 std::vector<ReferenceInfo> expectedResult {{filePaths[0], 16, 1}, {filePaths[1], 8, 1}, {filePaths[1], 33, 1}};
133 // NOLINTEND(readability-magic-numbers)
134 ASSERT_EQ(result.referenceInfos.size(), expectedResult.size());
135 for (size_t i = 0; i < expectedResult.size(); i++) {
136 ASSERT_EQ(result.referenceInfos[i].fileName, expectedResult[i].fileName);
137 ASSERT_EQ(result.referenceInfos[i].start, expectedResult[i].start);
138 ASSERT_EQ(result.referenceInfos[i].length, expectedResult[i].length);
139 }
140 }
141