• 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 
16 #include "lsp/include/class_hierarchy_info.h"
17 #include "lsp_api_test.h"
18 #include "lsp/include/internal_api.h"
19 #include <gtest/gtest.h>
20 
21 using ark::es2panda::lsp::Initializer;
22 
23 namespace {
24 
25 class LspGetClassHierarchyInfoTests : public LSPAPITests {};
26 
TEST_F(LspGetClassHierarchyInfoTests,GetClassHierarchyInfo_1)27 TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_1)
28 {
29     LSPAPI const *lspApi = GetImpl();
30     ASSERT_TRUE(lspApi != nullptr);
31     const std::string text = R"(class Parent {
32 private privateMethod(): void {
33   console.log("Parent method");
34 }
35   public publicMethod(): void {
36   console.log("Parent method");
37 }
38   protected action(fileName: string, position: number): number {
39   return position;
40 }
41   static staticMethod(): void {
42   console.log("Parent static method");
43   }
44 }
45   class Child extends Parent {
46   public display(): void {
47     console.log("need display");
48   }
49 })";
50 
51     auto pos = text.find("Child");
52     ASSERT_NE(pos, std::string::npos);
53     Initializer initializer = Initializer();
54     auto context = initializer.CreateContext("class_hierarchy_info_1.ets", ES2PANDA_STATE_CHECKED, text.c_str());
55     auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos);
56 
57     ASSERT_EQ(classHierarchy.size(), 1);
58     ASSERT_EQ(classHierarchy[0].GetClassName(), "Parent");
59     auto methods = classHierarchy[0].GetMethodItemList();
60     auto it = methods.find("publicMethod(): void");
61     ASSERT_TRUE(it != methods.end());
62     ASSERT_TRUE(it->second != nullptr);
63     ASSERT_EQ(it->second->GetSetterStyle(), ark::es2panda::lsp::SetterStyle::NONE);
64     ASSERT_EQ(it->second->GetAccessModifierStyle(), ark::es2panda::lsp::AccessModifierStyle::PUBLIC);
65     it = methods.find("action(fileName: string, position: number): number");
66     ASSERT_TRUE(it != methods.end());
67     ASSERT_TRUE(it->second != nullptr);
68     ASSERT_EQ(it->second->GetSetterStyle(), ark::es2panda::lsp::SetterStyle::NONE);
69     ASSERT_EQ(it->second->GetAccessModifierStyle(), ark::es2panda::lsp::AccessModifierStyle::PROTECTED);
70     initializer.DestroyContext(context);
71 }
72 
TEST_F(LspGetClassHierarchyInfoTests,GetClassHierarchyInfo_2)73 TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_2)
74 {
75     LSPAPI const *lspApi = GetImpl();
76     ASSERT_TRUE(lspApi != nullptr);
77     const std::string text = R"(class Animal {
78 private body_: string = '';
79 
80   protected action(): void {
81     console.log("need Animal action");
82   }
83   protected sleep(): void {
84     console.log("need Animal sleep");
85   }
86 }
87 
88 class Bird extends Animal {
89   action(): void {
90     console.log("need action");
91   }
92 
93   Drink(): void {
94     console.log("need Drink");
95   }
96 }
97 
98 class Magpie extends Bird {
99   public action(): void {}
100   Drink(): void {
101     console.log("need Drink");
102   }
103 })";
104 
105     auto pos = text.find("Magpie");
106     ASSERT_NE(pos, std::string::npos);
107     Initializer initializer = Initializer();
108     auto context = initializer.CreateContext("class_hierarchy_info_2.ets", ES2PANDA_STATE_CHECKED, text.c_str());
109     auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos);
110     ASSERT_EQ(classHierarchy.size(), 1);
111     ASSERT_EQ(classHierarchy[0].GetClassName(), "Animal");
112 
113     auto methods = classHierarchy[0].GetMethodItemList();
114     auto it = methods.find("sleep(): void");
115     ASSERT_TRUE(it != methods.end());
116     ASSERT_TRUE(it->second != nullptr);
117     ASSERT_EQ(it->second->GetSetterStyle(), ark::es2panda::lsp::SetterStyle::NONE);
118     ASSERT_EQ(it->second->GetAccessModifierStyle(), ark::es2panda::lsp::AccessModifierStyle::PROTECTED);
119     initializer.DestroyContext(context);
120 }
121 
TEST_F(LspGetClassHierarchyInfoTests,GetClassHierarchyInfo_3)122 TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_3)
123 {
124     LSPAPI const *lspApi = GetImpl();
125     ASSERT_TRUE(lspApi != nullptr);
126     const std::string text = R"(class Animal {
127   private body_: string = '';
128 
129   protected action(): void {
130     console.log("need action");
131   }
132   protected sleep(): void {
133     console.log("need sleep");
134   }
135 })";
136 
137     auto pos = text.find("Animal");
138     ASSERT_NE(pos, std::string::npos);
139     Initializer initializer = Initializer();
140     auto context = initializer.CreateContext("class_hierarchy_info_3.ets", ES2PANDA_STATE_CHECKED, text.c_str());
141     auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos);
142     ASSERT_TRUE(classHierarchy.empty());
143     initializer.DestroyContext(context);
144 }
145 
TEST_F(LspGetClassHierarchyInfoTests,GetClassHierarchyInfo_4)146 TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_4)
147 {
148     LSPAPI const *lspApi = GetImpl();
149     ASSERT_TRUE(lspApi != nullptr);
150     const std::string text = R"(class ii {
151   private body_: string = '';
152 
153   action(): void {
154     console.log("need sleep");
155   }
156 
157   set Body(value: string) {
158     this.body_ = value;
159   }
160   get Body(): string {
161     return this.body_;
162   }
163 }
164 
165   class jj extends ii {
166   private age_: number = 18;
167   public action(): void {
168     console.log("need sleep and fly");
169   }
170 })";
171 
172     auto pos = text.find("jj");
173     ASSERT_NE(pos, std::string::npos);
174     Initializer initializer = Initializer();
175     auto context = initializer.CreateContext("class_hierarchy_info_4.ets", ES2PANDA_STATE_CHECKED, text.c_str());
176     auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos);
177     ASSERT_EQ(classHierarchy.size(), 1);
178     ASSERT_EQ(classHierarchy[0].GetClassName(), "ii");
179 
180     auto methods = classHierarchy[0].GetMethodItemList();
181     auto it = methods.find("Body(): string");
182     ASSERT_TRUE(it != methods.end());
183     ASSERT_TRUE(it->second != nullptr);
184     ASSERT_EQ(it->second->GetSetterStyle(), ark::es2panda::lsp::SetterStyle::GETTER);
185     ASSERT_EQ(it->second->GetAccessModifierStyle(), ark::es2panda::lsp::AccessModifierStyle::PUBLIC);
186     it = methods.find("Body(value: string)");
187     ASSERT_TRUE(it != methods.end());
188     ASSERT_TRUE(it->second != nullptr);
189     ASSERT_EQ(it->second->GetSetterStyle(), ark::es2panda::lsp::SetterStyle::SETTER);
190     ASSERT_EQ(it->second->GetAccessModifierStyle(), ark::es2panda::lsp::AccessModifierStyle::PUBLIC);
191     initializer.DestroyContext(context);
192 }
193 
TEST_F(LspGetClassHierarchyInfoTests,GetClassHierarchyInfo_5)194 TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_5)
195 {
196     LSPAPI const *lspApi = GetImpl();
197     ASSERT_TRUE(lspApi != nullptr);
198     const std::string text = R"(class C<T, M> {
199   func1(): void {}
200   func2(): string {
201     return "1";
202   }
203   func3(): number {
204     return 1;
205   }
206   func4(): boolean {
207     return false;
208   }
209   func5(): Array<number> {
210     return [1, 2];
211   }
212 }
213 
214 class B<T, M> extends C<T, M> {
215   method1(): void {}
216   method2(parameter1: string, callBack: () => void): void {}
217 }
218 
219 class A extends B<string, number> {/*1*/};)";
220 
221     auto pos = text.find("/*1*/");
222     ASSERT_NE(pos, std::string::npos);
223     Initializer initializer = Initializer();
224     auto context = initializer.CreateContext("class_hierarchy_info_5.ets", ES2PANDA_STATE_CHECKED, text.c_str());
225     auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos);
226     size_t expectInfoListSize = 2;
227     ASSERT_EQ(classHierarchy.size(), expectInfoListSize);
228     ASSERT_EQ(classHierarchy[0].GetClassName(), "B");
229     ASSERT_EQ(classHierarchy[1].GetClassName(), "C");
230     auto classBItems = classHierarchy[0].GetMethodItemList();
231     ASSERT_TRUE(classBItems.find("method1(): void") != classBItems.end());
232     ASSERT_TRUE(classBItems.find("method2(parameter1: string, callBack: (() => void)): void") != classBItems.end());
233     auto classCItems = classHierarchy[1].GetMethodItemList();
234     ASSERT_TRUE(classCItems.find("func1(): void") != classCItems.end());
235     ASSERT_TRUE(classCItems.find("func2(): string") != classCItems.end());
236     ASSERT_TRUE(classCItems.find("func3(): number") != classCItems.end());
237     ASSERT_TRUE(classCItems.find("func4(): boolean") != classCItems.end());
238     ASSERT_TRUE(classCItems.find("func5(): Array<number>") != classCItems.end());
239     initializer.DestroyContext(context);
240 }
241 
TEST_F(LspGetClassHierarchyInfoTests,GetClassHierarchyInfo_6)242 TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_6)
243 {
244     LSPAPI const *lspApi = GetImpl();
245     ASSERT_TRUE(lspApi != nullptr);
246     const std::string text = R"(type parameter = number;
247 
248 class B {
249   public method1(parameter1: number): parameter {
250     return 1;
251   }
252   method2(parameter1: number): number {
253     return parameter1 as number;
254   }
255   async method3(parameter1: string): Promise<string> {
256     return '1';
257   }
258 }
259 
260 class A extends B {/*1*/};)";
261 
262     auto pos = text.find("/*1*/");
263     ASSERT_NE(pos, std::string::npos);
264     Initializer initializer = Initializer();
265     auto context = initializer.CreateContext("class_hierarchy_info_6.ets", ES2PANDA_STATE_CHECKED, text.c_str());
266     auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos);
267     ASSERT_FALSE(classHierarchy.empty());
268     ASSERT_EQ(classHierarchy[0].GetClassName(), "B");
269     auto classBItems = classHierarchy[0].GetMethodItemList();
270     ASSERT_TRUE(classBItems.find("method1(parameter1: number): parameter") != classBItems.end());
271     ASSERT_TRUE(classBItems.find("method2(parameter1: number): number") != classBItems.end());
272     ASSERT_TRUE(classBItems.find("method3(parameter1: string): Promise<string>") != classBItems.end());
273     initializer.DestroyContext(context);
274 }
275 
TEST_F(LspGetClassHierarchyInfoTests,GetClassHierarchyInfo_7)276 TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_7)
277 {
278     LSPAPI const *lspApi = GetImpl();
279     ASSERT_TRUE(lspApi != nullptr);
280     const std::string text = R"(class C <T, M> {
281   func1(): void {}
282 
283   func2(): boolean {
284     return false;
285   }
286 
287   func3(): Array<number> {
288     return [1, 2];
289   }
290 };
291 
292 class B<T, M> extends C<T, M> {
293   method1() {}
294   func2(): boolean {
295     return false;
296   }
297 }
298 
299 class A extends B<string, number> {
300   method1() {}
301   func3(): Array<number> {
302     return [1, 2];
303   }/*1*/
304 })";
305 
306     auto pos = text.find("/*1*/");
307     ASSERT_NE(pos, std::string::npos);
308     Initializer initializer = Initializer();
309     auto context = initializer.CreateContext("class_hierarchy_info_7.ets", ES2PANDA_STATE_CHECKED, text.c_str());
310     auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos);
311     size_t expectInfoListSize = 2;
312     ASSERT_EQ(classHierarchy.size(), expectInfoListSize);
313     ASSERT_EQ(classHierarchy[0].GetClassName(), "B");
314     ASSERT_EQ(classHierarchy[1].GetClassName(), "C");
315     auto classBItems = classHierarchy[0].GetMethodItemList();
316     ASSERT_EQ(classBItems.size(), 1);
317     ASSERT_TRUE(classBItems.find("func2(): boolean") != classBItems.end());
318     auto classCItems = classHierarchy[1].GetMethodItemList();
319     ASSERT_EQ(classCItems.size(), 1);
320     ASSERT_TRUE(classCItems.find("func1(): void") != classCItems.end());
321     initializer.DestroyContext(context);
322 }
323 
TEST_F(LspGetClassHierarchyInfoTests,GetClassHierarchyInfo_8)324 TEST_F(LspGetClassHierarchyInfoTests, GetClassHierarchyInfo_8)
325 {
326     LSPAPI const *lspApi = GetImpl();
327     ASSERT_TRUE(lspApi != nullptr);
328     const std::string text = R"(class Parent {
329   public property1: number = 1;
330   protected property2: string = '1';
331   private property3: boolean = true;
332   readonly property4: number = 1;
333   static property5: number = 1;
334 }
335 
336 class Son extends Parent {
337   property1: number = 2;
338   ChildExtraProperty1: number = 2;
339   ChildExtraProperty2: number = 2;
340 }
341 
342 class GrandSon extends Son {/*1*/
343   public property2: string = '2';
344   ChildExtraProperty1: number = 3;
345 })";
346 
347     auto pos = text.find("/*1*/");
348     ASSERT_NE(pos, std::string::npos);
349     Initializer initializer = Initializer();
350     auto context = initializer.CreateContext("class_hierarchy_info_8.ets", ES2PANDA_STATE_CHECKED, text.c_str());
351     auto classHierarchy = lspApi->getClassHierarchyInfo(context, pos);
352     size_t expectInfoListSize = 2;
353     ASSERT_EQ(classHierarchy.size(), expectInfoListSize);
354     ASSERT_EQ(classHierarchy[0].GetClassName(), "Son");
355     ASSERT_EQ(classHierarchy[1].GetClassName(), "Parent");
356     auto sonItems = classHierarchy[0].GetPropertyItemList();
357     size_t expectPropertyListSize = 2;
358     ASSERT_EQ(sonItems.size(), expectPropertyListSize);
359     ASSERT_TRUE(sonItems.find("property1: number") != sonItems.end());
360     ASSERT_TRUE(sonItems.find("ChildExtraProperty2: number") != sonItems.end());
361     auto parentItems = classHierarchy[1].GetPropertyItemList();
362     ASSERT_EQ(parentItems.size(), 1);
363     ASSERT_TRUE(parentItems.find("property4: number") != parentItems.end());
364     initializer.DestroyContext(context);
365 }
366 }  // namespace
367