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 "class_hierarchy.h"
17 #include <iostream>
18 #include <ostream>
19 #include "class_hierarchies.h"
20 #include "compiler/lowering/util.h"
21 #include "public/public.h"
22 #include "lsp/include/internal_api.h"
23 #include "lsp/include/completions.h"
24
25 namespace ark::es2panda::lsp {
26
GetHierarchyDeclarationFileName(const ir::AstNode * node)27 std::string GetHierarchyDeclarationFileName(const ir::AstNode *node)
28 {
29 if (node == nullptr) {
30 return "";
31 }
32 if (node->IsClassDeclaration()) {
33 if (node->AsClassDeclaration()->Definition()->Ident()->Range().start.Program() == nullptr) {
34 return "";
35 }
36 return std::string(node->AsClassDeclaration()->Definition()->Ident()->Range().start.Program()->AbsoluteName());
37 }
38 if (node->IsTSInterfaceDeclaration()) {
39 if (node->AsTSInterfaceDeclaration()->Id()->Range().start.Program() == nullptr) {
40 return "";
41 }
42 return std::string(node->AsTSInterfaceDeclaration()->Id()->Range().start.Program()->AbsoluteName());
43 }
44 return "";
45 }
46
GetHierarchyDeclarationName(const ir::AstNode * node)47 std::string GetHierarchyDeclarationName(const ir::AstNode *node)
48 {
49 if (node == nullptr) {
50 return "";
51 }
52 if (node->IsClassDeclaration()) {
53 return std::string(node->AsClassDeclaration()->Definition()->Ident()->Name());
54 }
55 if (node->IsTSInterfaceDeclaration()) {
56 return std::string(node->AsTSInterfaceDeclaration()->Id()->Name());
57 }
58 return "";
59 }
60
GetHierarchyType(const ir::AstNode * node)61 HierarchyType GetHierarchyType(const ir::AstNode *node)
62 {
63 if (node == nullptr) {
64 return HierarchyType::OTHERS;
65 }
66 if (node->IsClassDeclaration()) {
67 return HierarchyType::CLASS;
68 }
69 if (node->IsTSInterfaceDeclaration()) {
70 return HierarchyType::INTERFACE;
71 }
72 return HierarchyType::OTHERS;
73 }
74
GetPosition(const ir::AstNode * node)75 size_t GetPosition(const ir::AstNode *node)
76 {
77 if (node == nullptr) {
78 return 0;
79 }
80 if (node->IsClassDeclaration()) {
81 return node->AsClassDeclaration()->Definition()->Ident()->Start().index;
82 }
83 if (node->IsTSInterfaceDeclaration()) {
84 return node->AsTSInterfaceDeclaration()->Id()->Start().index;
85 }
86 return 0;
87 }
88
GetEffectiveBaseTypeNode(const ir::AstNode * node)89 const ir::AstNode *GetEffectiveBaseTypeNode(const ir::AstNode *node)
90 {
91 if (node == nullptr || !node->IsClassDeclaration()) {
92 return nullptr;
93 }
94 auto super = node->AsClassDeclaration()->Definition()->Super();
95 if (super == nullptr || !super->IsETSTypeReference()) {
96 return nullptr;
97 }
98 auto id = super->AsETSTypeReference()->Part()->Name();
99 if (id == nullptr || !id->IsIdentifier()) {
100 return nullptr;
101 }
102 auto result = compiler::DeclarationFromIdentifier(id->AsIdentifier());
103 if (result == nullptr || !result->IsClassDefinition()) {
104 return nullptr;
105 }
106 return result->Parent();
107 }
108
GetInterfaceExtendsHeritageElement(const ir::AstNode * node)109 std::vector<const ir::AstNode *> GetInterfaceExtendsHeritageElement(const ir::AstNode *node)
110 {
111 std::vector<const ir::AstNode *> result;
112 if (node == nullptr || !node->IsTSInterfaceDeclaration()) {
113 return result;
114 }
115 auto extends = node->AsTSInterfaceDeclaration()->Extends();
116 for (auto e : extends) {
117 auto id = e->Expr()->AsETSTypeReference()->Part()->Name();
118 result.push_back(compiler::DeclarationFromIdentifier(id->AsIdentifier()));
119 }
120 return result;
121 }
122
FindSuper(const ir::AstNode * node,TypeHierarchies & typeHierarchies,std::set<TypeHierarchies> & superLists)123 void FindSuper(const ir::AstNode *node, TypeHierarchies &typeHierarchies, std::set<TypeHierarchies> &superLists)
124 {
125 auto name = GetHierarchyDeclarationName(node);
126 if (name.empty()) {
127 return;
128 }
129 TypeHierarchies subOrSuper(GetHierarchyDeclarationFileName(node), name, GetHierarchyType(node), GetPosition(node));
130 if (superLists.find(subOrSuper) != superLists.end()) {
131 return;
132 }
133 superLists.insert(subOrSuper);
134 GetSuperTypeHierarchies(node, subOrSuper, superLists);
135 typeHierarchies.subOrSuper.emplace_back(subOrSuper);
136 }
137
GetEffectiveImplementsTypeNodes(const ir::AstNode * node)138 std::vector<ir::AstNode *> GetEffectiveImplementsTypeNodes(const ir::AstNode *node)
139 {
140 std::vector<ir::AstNode *> result;
141 if (node == nullptr || !node->IsClassDeclaration()) {
142 return result;
143 }
144 auto implements = node->AsClassDeclaration()->Definition()->Implements();
145 for (auto imp : implements) {
146 result.emplace_back(compiler::DeclarationFromIdentifier(
147 imp->AsTSClassImplements()->Expr()->AsETSTypeReference()->Part()->Name()->AsIdentifier()));
148 }
149 return result;
150 }
151
GetSuperTypeHierarchies(const ir::AstNode * node,TypeHierarchies & typeHierarchies,std::set<TypeHierarchies> & superLists)152 void GetSuperTypeHierarchies(const ir::AstNode *node, TypeHierarchies &typeHierarchies,
153 std::set<TypeHierarchies> &superLists)
154 {
155 std::set<TypeHierarchies> currentList;
156 auto extendsNode = GetEffectiveBaseTypeNode(node);
157 if (extendsNode != nullptr) {
158 currentList = superLists;
159 FindSuper(extendsNode, typeHierarchies, currentList);
160 }
161 auto implementsNodes = GetEffectiveImplementsTypeNodes(node);
162 for (auto n : implementsNodes) {
163 currentList = superLists;
164 FindSuper(n, typeHierarchies, currentList);
165 }
166 auto extendsNodes = GetInterfaceExtendsHeritageElement(node);
167 for (auto n : extendsNodes) {
168 currentList = superLists;
169 FindSuper(n, typeHierarchies, currentList);
170 }
171 }
172
GetCurrentClassOrInterfaceDeclaration(ir::AstNode * node)173 ir::AstNode *GetCurrentClassOrInterfaceDeclaration(ir::AstNode *node)
174 {
175 auto tmp = node;
176 while (tmp != nullptr) {
177 if (tmp->IsClassDeclaration() || tmp->IsTSInterfaceDeclaration()) {
178 return tmp;
179 }
180 tmp = tmp->Parent();
181 }
182 return nullptr;
183 }
184
GetTargetDeclarationNodeByPosition(es2panda_Context * context,size_t pos)185 ir::AstNode *GetTargetDeclarationNodeByPosition(es2panda_Context *context, size_t pos)
186 {
187 auto node = ark::es2panda::lsp::GetTouchingToken(context, pos, false);
188 if (node == nullptr) {
189 return nullptr;
190 }
191 return GetCurrentClassOrInterfaceDeclaration(node);
192 }
193
IsChildNode(const ir::AstNode * child,const ir::AstNode * parent)194 bool IsChildNode(const ir::AstNode *child, const ir::AstNode *parent)
195 {
196 std::vector<const ir::AstNode *> parentList = GetInterfaceExtendsHeritageElement(child);
197 auto baseNode = GetEffectiveBaseTypeNode(child);
198 if (baseNode != nullptr) {
199 parentList.emplace_back(baseNode);
200 }
201 auto parentName = GetHierarchyDeclarationName(parent);
202 auto parentFileName = GetHierarchyDeclarationFileName(parent);
203 auto parentPosition = GetPosition(parent);
204 auto result = std::find_if(parentList.begin(), parentList.end(), [&](const ir::AstNode *n) {
205 auto p = GetPosition(n);
206 return parentName == GetHierarchyDeclarationName(n) && parentFileName == GetHierarchyDeclarationFileName(n) &&
207 p == parentPosition;
208 });
209 return result != parentList.end();
210 }
211
GetImplementationReferenceEntries(es2panda_Context * context,const ir::AstNode * node,std::set<TypeHierarchies> & subLists)212 std::vector<ir::AstNode *> GetImplementationReferenceEntries(es2panda_Context *context, const ir::AstNode *node,
213 std::set<TypeHierarchies> &subLists)
214 {
215 std::vector<ir::AstNode *> result;
216 if (context == nullptr) {
217 return result;
218 }
219 auto ctx = reinterpret_cast<public_lib::Context *>(context);
220 if (ctx->parserProgram == nullptr || ctx->parserProgram->Ast() == nullptr) {
221 return result;
222 }
223 auto astNode = reinterpret_cast<ir::AstNode *>(ctx->parserProgram->Ast());
224 astNode->IterateRecursively([&subLists, node, &result](ir::AstNode *child) {
225 if (child == nullptr || (!child->IsClassDeclaration() && !child->IsTSInterfaceDeclaration())) {
226 return;
227 }
228 auto name = GetHierarchyDeclarationName(child);
229 if (name.empty()) {
230 return;
231 }
232 auto fileName = GetHierarchyDeclarationFileName(child);
233 if (fileName.empty()) {
234 return;
235 }
236 TypeHierarchies childTypeHierarchies(fileName, name, GetHierarchyType(child), GetPosition(child));
237 if (subLists.find(childTypeHierarchies) != subLists.end()) {
238 return;
239 }
240 if (!IsChildNode(child, node)) {
241 return;
242 }
243 result.emplace_back(child);
244 subLists.insert(childTypeHierarchies);
245 });
246 return result;
247 }
248
GetSubTypeHierarchies(es2panda_Context * context,const ir::AstNode * node,TypeHierarchies & typeHierarchies,std::set<TypeHierarchies> & subLists)249 void GetSubTypeHierarchies(es2panda_Context *context, const ir::AstNode *node, TypeHierarchies &typeHierarchies,
250 std::set<TypeHierarchies> &subLists)
251 {
252 if (node == nullptr || (!node->IsTSInterfaceDeclaration() && !node->IsClassDeclaration())) {
253 return;
254 }
255 auto name = GetHierarchyDeclarationName(node);
256 if (name.empty()) {
257 return;
258 }
259 auto childList = GetImplementationReferenceEntries(context, node, subLists);
260 for (auto child : childList) {
261 TypeHierarchies childType(GetHierarchyDeclarationFileName(child), GetHierarchyDeclarationName(child),
262 GetHierarchyType(child), GetPosition(child));
263 std::set<TypeHierarchies> curList;
264 curList.insert(childType);
265 GetSubTypeHierarchies(context, child, childType, curList);
266 typeHierarchies.subOrSuper.emplace_back(childType);
267 }
268 }
269
InitHierarchies(TypeHierarchies & typeHierarchies,std::string & fileName,std::string & name,HierarchyType type,size_t pos)270 void InitHierarchies(TypeHierarchies &typeHierarchies, std::string &fileName, std::string &name, HierarchyType type,
271 size_t pos)
272 {
273 typeHierarchies.fileName = fileName;
274 typeHierarchies.name = name;
275 typeHierarchies.type = type;
276 typeHierarchies.pos = pos;
277 }
278
GetTypeHierarchiesImpl(es2panda_Context * context,size_t pos,const ir::AstNode * declaration)279 TypeHierarchiesInfo GetTypeHierarchiesImpl(es2panda_Context *context, size_t pos, const ir::AstNode *declaration)
280 {
281 TypeHierarchiesInfo result;
282 if (context == nullptr) {
283 return result;
284 }
285 auto ctx = reinterpret_cast<public_lib::Context *>(context);
286 if (ctx->parserProgram == nullptr || ctx->parserProgram->Ast() == nullptr) {
287 return result;
288 }
289 if (declaration == nullptr) {
290 declaration = GetTargetDeclarationNodeByPosition(context, pos);
291 }
292 if (declaration == nullptr || (!declaration->IsTSInterfaceDeclaration() && !declaration->IsClassDeclaration())) {
293 return result;
294 }
295 result.fileName = GetHierarchyDeclarationFileName(declaration);
296 result.name = GetHierarchyDeclarationName(declaration);
297 result.type = GetHierarchyType(declaration);
298 result.pos = GetPosition(declaration);
299 InitHierarchies(result.superHierarchies, result.fileName, result.name, result.type, result.pos);
300 InitHierarchies(result.subHierarchies, result.fileName, result.name, result.type, result.pos);
301 std::set<TypeHierarchies> superLists;
302 superLists.insert(result.superHierarchies);
303 GetSuperTypeHierarchies(declaration, result.superHierarchies, superLists);
304 std::set<TypeHierarchies> subLists;
305 subLists.insert(result.subHierarchies);
306 GetSubTypeHierarchies(context, declaration, result.subHierarchies, subLists);
307 return result;
308 }
309
310 /**
311 * @brief (查找当前类的父类) Find immediate superclass of current class node
312 * @param node - current class node declaration
313 * @return Pointer to the direct superclass node or nullptr if not found
314 */
GetClassDirectSuperClass(ir::AstNode * node)315 ir::AstNode *GetClassDirectSuperClass(ir::AstNode *node)
316 {
317 if (!node->IsClassDeclaration()) {
318 return nullptr;
319 }
320 auto classNode = node->AsClassDeclaration()->Definition();
321 auto super = classNode->Super();
322 if (super == nullptr || !super->IsETSTypeReference()) {
323 return nullptr;
324 }
325 auto part = super->AsETSTypeReference()->Part();
326 if (part == nullptr || !part->IsETSTypeReferencePart()) {
327 return nullptr;
328 }
329 auto partNode = part->AsETSTypeReferencePart()->Name();
330 if (partNode == nullptr || !partNode->IsIdentifier()) {
331 return nullptr;
332 }
333 auto superClass = compiler::DeclarationFromIdentifier(partNode->AsIdentifier());
334 if (superClass->IsClassDefinition()) {
335 return superClass->Parent();
336 }
337 return nullptr;
338 }
339
340 /**
341 * @brief (1. 查找当前类的(所有)父类) Find all superclasses of the current class node
342 * @param context - Compiler context (unused)
343 * @param node - Current class declaration node
344 * @return Vector of superclass nodes in inheritance order
345 */
GetClassSuperClasses(es2panda_Context * context,ir::AstNode * node)346 std::vector<ir::AstNode *> GetClassSuperClasses([[maybe_unused]] es2panda_Context *context, ir::AstNode *node)
347 {
348 std::vector<ir::AstNode *> res;
349
350 ir::AstNode *subClass = node;
351 ir::AstNode *superClass = nullptr;
352 do {
353 superClass = GetClassDirectSuperClass(subClass);
354 if (superClass != nullptr) {
355 res.push_back(superClass);
356 }
357 subClass = superClass;
358 } while (superClass != nullptr);
359
360 return res;
361 }
362
363 /**
364 * @brief (查找当前类的子类) Find immediate subclass of current class node
365 * @param program - Pointer to the program AST
366 * @param node - Current class declaration node
367 * @return Set of direct subclass nodes
368 */
GetClassDirectSubClasses(ark::es2panda::parser::Program * program,ir::AstNode * node)369 std::unordered_set<ir::AstNode *> GetClassDirectSubClasses(ark::es2panda::parser::Program *program, ir::AstNode *node)
370 {
371 std::unordered_set<ir::AstNode *> res;
372
373 if (node == nullptr) {
374 return res;
375 }
376 if (!node->IsClassDeclaration()) {
377 return res;
378 }
379 auto rootNode = program->Ast();
380 if (rootNode == nullptr) {
381 return res;
382 }
383 auto statements = rootNode->Statements();
384 for (auto statement : statements) {
385 if (!statement->IsClassDeclaration()) {
386 continue;
387 }
388 if (GetClassDirectSuperClass(statement) == node) {
389 res.insert(statement);
390 }
391 }
392
393 return res;
394 }
395
396 /**
397 * @brief (2. 查找当前类的(所有)子类) Find all possible implementing classes of current class node
398 * @param context - Compiler context containing program AST
399 * @param node - Current class declaration node
400 * @return Vector of all subclass nodes
401 */
GetClassSubClasses(es2panda_Context * context,ir::AstNode * node)402 std::vector<ir::AstNode *> GetClassSubClasses(es2panda_Context *context, ir::AstNode *node)
403 {
404 auto pctx = reinterpret_cast<public_lib::Context *>(context);
405 auto program = pctx->parserProgram;
406 std::vector<ir::AstNode *> result;
407 std::unordered_set<ir::AstNode *> resultSet;
408 std::unordered_set<ir::AstNode *> gottenSet;
409 std::unordered_set<ir::AstNode *> superClasses;
410 superClasses.insert(node);
411 std::unordered_set<ir::AstNode *> directSubClasses;
412
413 do {
414 directSubClasses.clear();
415 for (auto superClass : superClasses) {
416 auto it = gottenSet.find(superClass);
417 if (it == gottenSet.end()) {
418 auto subClasses = GetClassDirectSubClasses(program, superClass);
419 directSubClasses.insert(subClasses.begin(), subClasses.end());
420 }
421 }
422 gottenSet.insert(superClasses.begin(), superClasses.end());
423 if (!directSubClasses.empty()) {
424 resultSet.insert(directSubClasses.begin(), directSubClasses.end());
425 superClasses.clear();
426 superClasses.insert(directSubClasses.begin(), directSubClasses.end());
427 }
428 } while (!directSubClasses.empty());
429
430 result.insert(result.end(), resultSet.begin(), resultSet.end());
431 return result;
432 }
433
434 /**
435 * @brief (查找当前类的父接口) Find interface of current class node
436 * @param node - Current class declaration node
437 * @return Set of directly implemented interface nodes
438 */
GetClassDirectImplementedInterfaces(ir::AstNode * node)439 std::unordered_set<ir::AstNode *> GetClassDirectImplementedInterfaces(ir::AstNode *node)
440 {
441 std::unordered_set<ir::AstNode *> res;
442 if (node == nullptr) {
443 return res;
444 }
445 if (!node->IsClassDeclaration()) {
446 return res;
447 }
448 auto classDefinition = node->AsClassDeclaration()->Definition();
449 auto implements = classDefinition->Implements();
450 for (auto implement : implements) {
451 auto partNode = GetIdentifierFromTSInterfaceHeritage(implement);
452 if (partNode == nullptr) {
453 continue;
454 }
455 auto interfaceDecl = compiler::DeclarationFromIdentifier(partNode->AsIdentifier());
456 if (interfaceDecl->IsTSInterfaceDeclaration()) {
457 res.insert(interfaceDecl);
458 }
459 }
460 return res;
461 }
462
463 /**
464 * @brief (查找当前接口的父接口) Find which interfaces current interface node extends
465 * @param node - Current declaration node
466 * @return Set of directly extended interface nodes
467 */
GetInterfaceDirectExtendedInterfaces(ir::AstNode * node)468 std::unordered_set<ir::AstNode *> GetInterfaceDirectExtendedInterfaces(ir::AstNode *node)
469 {
470 std::unordered_set<ir::AstNode *> res;
471 if (node == nullptr) {
472 return res;
473 }
474 if (!node->IsTSInterfaceDeclaration()) {
475 return res;
476 }
477 auto childInterface = node->AsTSInterfaceDeclaration();
478 auto extends = childInterface->Extends();
479 for (auto extend : extends) {
480 auto partNode = GetIdentifierFromTSInterfaceHeritage(extend->AsTSInterfaceHeritage());
481 if (partNode == nullptr || !partNode->IsIdentifier()) {
482 continue;
483 }
484 auto interfaceDecl = compiler::DeclarationFromIdentifier(partNode->AsIdentifier());
485 if (interfaceDecl->IsTSInterfaceDeclaration()) {
486 res.insert(interfaceDecl);
487 }
488 }
489 return res;
490 }
491
492 /**
493 * @brief (3. 查找当前类的(所有)父接口) Find all interfaces extended by current class node
494 * @param context - Compiler context (unused)
495 * @param node - Current class declaration node
496 * @return Vector of implemented interface nodes
497 */
GetClassImplementedInterfaces(es2panda_Context * context,ir::AstNode * node)498 std::vector<ir::AstNode *> GetClassImplementedInterfaces([[maybe_unused]] es2panda_Context *context, ir::AstNode *node)
499 {
500 std::vector<ir::AstNode *> result;
501 std::unordered_set<ir::AstNode *> resultSet;
502 std::unordered_set<ir::AstNode *> subClasses {node};
503 std::unordered_set<ir::AstNode *> subInterfaces;
504 std::unordered_set<ir::AstNode *> gottenSet;
505 std::unordered_set<ir::AstNode *> directSuperClasses;
506 std::unordered_set<ir::AstNode *> directSuperInterfaces;
507 do {
508 directSuperInterfaces.clear();
509 directSuperClasses.clear();
510 for (auto subClass : subClasses) {
511 if (gottenSet.find(subClass) != gottenSet.end()) {
512 continue;
513 }
514 auto superInterfaces = GetClassDirectImplementedInterfaces(subClass);
515 directSuperInterfaces.insert(superInterfaces.begin(), superInterfaces.end());
516 auto superClass = GetClassDirectSuperClass(subClass);
517 if (superClass != nullptr) {
518 directSuperClasses.insert(superClass);
519 }
520 }
521 gottenSet.insert(subClasses.begin(), subClasses.end());
522 for (auto subInterface : subInterfaces) {
523 if (gottenSet.find(subInterface) != gottenSet.end()) {
524 continue;
525 }
526 auto superInterfaces = GetInterfaceDirectExtendedInterfaces(subInterface);
527 directSuperInterfaces.insert(superInterfaces.begin(), superInterfaces.end());
528 }
529 gottenSet.insert(subInterfaces.begin(), subInterfaces.end());
530 if (!directSuperInterfaces.empty()) {
531 resultSet.insert(directSuperInterfaces.begin(), directSuperInterfaces.end());
532 subInterfaces.clear();
533 subInterfaces.insert(directSuperInterfaces.begin(), directSuperInterfaces.end());
534 }
535 if (!directSuperClasses.empty()) {
536 subClasses.clear();
537 subClasses.insert(directSuperClasses.begin(), directSuperClasses.end());
538 }
539 } while (!directSuperInterfaces.empty() || !directSuperClasses.empty());
540 result.insert(result.end(), resultSet.begin(), resultSet.end());
541 return result;
542 }
543
544 /**
545 * @brief (4. 查找当前接口的(所有)父接口) Find all interfaces extended by current interface node
546 * @param context - Compiler context (unused)
547 * @param node - Current interface node
548 * @return Vector of ancestor interface nodes
549 */
GetInterfaceSuperInterfaces(es2panda_Context * context,ir::AstNode * node)550 std::vector<ir::AstNode *> GetInterfaceSuperInterfaces([[maybe_unused]] es2panda_Context *context, ir::AstNode *node)
551 {
552 std::vector<ir::AstNode *> superInterfaces {};
553 std::unordered_set<ir::AstNode *> visited;
554 std::function<void(ir::AstNode *)> findSuperInterfaces = [&](ir::AstNode *currentNode) {
555 if (currentNode == nullptr) {
556 return;
557 }
558 if (!visited.insert(currentNode).second) {
559 return;
560 }
561 auto extends = currentNode->AsTSInterfaceDeclaration()->Extends();
562 for (auto extend : extends) {
563 auto partNode = GetIdentifierFromTSInterfaceHeritage(extend);
564 if (partNode == nullptr) {
565 continue;
566 }
567 auto interfaceDecl = compiler::DeclarationFromIdentifier(partNode->AsIdentifier());
568 if (interfaceDecl->IsTSInterfaceDeclaration()) {
569 ir::AstNode *superInterface = interfaceDecl->AsTSInterfaceDeclaration();
570 superInterfaces.push_back(superInterface);
571 findSuperInterfaces(superInterface);
572 }
573 }
574 };
575 findSuperInterfaces(node);
576 return superInterfaces;
577 }
578
579 /**
580 * @brief Helper function to get directly implemented interfaces
581 * @param node - Class definition node
582 * @return Vector of directly implemented interface nodes
583 */
GetImplements(ir::AstNode * node)584 std::vector<ir::AstNode *> GetImplements(ir::AstNode *node)
585 {
586 std::vector<ir::AstNode *> result {};
587 if (node == nullptr) {
588 return result;
589 }
590 auto classDefinition = node->AsClassDefinition();
591 auto implements = classDefinition->Implements();
592 for (auto implement : implements) {
593 auto partNode = GetIdentifierFromTSInterfaceHeritage(implement);
594 if (partNode == nullptr || !partNode->IsIdentifier()) {
595 continue;
596 }
597 auto interfaceDecl = compiler::DeclarationFromIdentifier(partNode->AsIdentifier());
598 if (interfaceDecl->IsTSInterfaceDeclaration()) {
599 result.push_back(interfaceDecl->AsTSInterfaceDeclaration());
600 }
601 }
602 return result;
603 }
604
GetInterfaceOrClasses(es2panda_Context * context,ir::AstNode * node,bool isInterfaceMode)605 std::vector<ir::AstNode *> GetInterfaceOrClasses(es2panda_Context *context, ir::AstNode *node, bool isInterfaceMode)
606 {
607 std::vector<ir::AstNode *> result;
608 std::unordered_set<ir::AstNode *> parentSet;
609 parentSet.insert(node);
610 auto ctx = reinterpret_cast<public_lib::Context *>(context);
611 auto rootNode = ctx->parserProgram->Ast();
612 if (rootNode == nullptr) {
613 return result;
614 }
615 for (auto statement : rootNode->Statements()) {
616 if (isInterfaceMode) {
617 // The current interface obtains the interface
618 if (!statement->IsTSInterfaceDeclaration()) {
619 continue;
620 }
621 auto child = statement->AsTSInterfaceDeclaration();
622 auto extends = GetInterfaceDirectExtendedInterfaces(child);
623 bool isSubInterface = std::any_of(extends.begin(), extends.end(),
624 [&](ir::AstNode *base) { return parentSet.count(base) > 0; });
625 if (isSubInterface) {
626 result.push_back(child);
627 }
628 } else {
629 // The current interface gets the subclass
630 if (!statement->IsClassDeclaration()) {
631 continue;
632 }
633 auto classDef = statement->AsClassDeclaration()->Definition();
634 auto implements = GetImplements(classDef);
635 bool isImplement = std::any_of(implements.begin(), implements.end(),
636 [&](ir::AstNode *base) { return parentSet.count(base) > 0; });
637 if (isImplement) {
638 result.push_back(classDef);
639 }
640 }
641 }
642 return result;
643 }
644
AddMissingExtends(std::vector<ir::AstNode * > & implementingClasses,const std::vector<ir::AstNode * > & extends)645 void AddMissingExtends(std::vector<ir::AstNode *> &implementingClasses, const std::vector<ir::AstNode *> &extends)
646 {
647 std::unordered_set<ir::AstNode *> existing(implementingClasses.begin(), implementingClasses.end());
648 std::copy_if(extends.begin(), extends.end(), std::back_inserter(implementingClasses),
649 [&existing](ir::AstNode *node) { return existing.find(node) == existing.end(); });
650 }
651
652 /**
653 * @brief (通用函数,用于查找接口的子接口或实现类及其子类) Generic function to find sub-interfaces or implementing
654 * classes and their subclasses of an interface
655 * @param context - Compiler context containing program AST
656 * @param node - Current interface node
657 * @param isInterfaceMode - Flag to determine lookup mode (true for interfaces, false for classes)
658 * @return Vector of found nodes
659 */
GetRelatedNodes(es2panda_Context * context,ir::AstNode * node,bool isInterfaceMode)660 std::vector<ir::AstNode *> GetRelatedNodes(es2panda_Context *context, ir::AstNode *node, bool isInterfaceMode)
661 {
662 std::vector<ir::AstNode *> result;
663 auto ctx = reinterpret_cast<public_lib::Context *>(context);
664 if (ctx->parserProgram->Ast() == nullptr) {
665 return result;
666 }
667 result = GetInterfaceOrClasses(context, node, isInterfaceMode);
668 for (size_t i = 0; i < result.size(); ++i) {
669 auto elem = result[i];
670 if (!isInterfaceMode && elem->IsClassDefinition()) {
671 elem = elem->Parent();
672 result[i] = elem;
673 }
674 std::vector<ir::AstNode *> extends;
675 if (isInterfaceMode) {
676 extends = GetRelatedNodes(context, elem, isInterfaceMode);
677 } else {
678 extends = GetClassSubClasses(context, elem);
679 }
680 AddMissingExtends(result, extends);
681 }
682 return result;
683 }
684
685 /**
686 * @brief (5. 查找当前接口的(所有)子接口) Find all interfaces extended by current interface node
687 * @param context - Compiler context containing program AST
688 * @param node - Current interface node
689 * @return Vector of descendant interface nodes
690 */
GetInterfaceSubInterfaces(es2panda_Context * context,ir::AstNode * node)691 std::vector<ir::AstNode *> GetInterfaceSubInterfaces(es2panda_Context *context, ir::AstNode *node)
692 {
693 return GetRelatedNodes(context, node, true);
694 }
695
696 /**
697 * @brief (6. 查找当前接口的(所有)子类) Find all interfaces current interface node extends & their corresponding
698 * implementation classes
699 * @param context - Compiler context containing program AST
700 * @param node - Current interface node
701 * @return Vector of implementing class nodes
702 */
GetInterfaceImplementingClasses(es2panda_Context * context,ir::AstNode * node)703 std::vector<ir::AstNode *> GetInterfaceImplementingClasses(es2panda_Context *context, ir::AstNode *node)
704 {
705 return GetRelatedNodes(context, node, false);
706 }
707
708 /**
709 * @brief Extracts public, non-static, non-constructor members from a class or interface node.
710 * @param context Unused context pointer.
711 * @param node AST node (TSInterfaceDeclaration or ClassDeclaration).
712 * @return Vector of AST nodes for class properties and filtered methods.
713 */
GetMembers(es2panda_Context * context,ir::AstNode * node)714 std::vector<ir::AstNode *> GetMembers([[maybe_unused]] es2panda_Context *context, ir::AstNode *node)
715 {
716 std::vector<ir::AstNode *> res;
717 std::vector<ir::AstNode *> body;
718 if (node->IsTSInterfaceDeclaration()) {
719 auto interfaceBody = node->AsTSInterfaceDeclaration()->Body()->Body();
720 body.insert(body.end(), interfaceBody.begin(), interfaceBody.end());
721 } else {
722 if (node->IsClassDefinition()) {
723 node = node->Parent();
724 }
725 auto classBody = node->AsClassDeclaration()->Definition()->Body();
726 body.insert(body.end(), classBody.begin(), classBody.end());
727 }
728 for (auto *field : body) {
729 if (field->IsClassProperty()) {
730 res.emplace_back(field);
731 } else if (field->IsMethodDefinition()) {
732 auto *method = field->AsMethodDefinition();
733 if (!method->IsPrivate() && !method->IsStatic() && !method->IsConstructor()) {
734 res.emplace_back(field);
735 }
736 }
737 }
738 return res;
739 }
740
741 /**
742 * @brief Determines if two method nodes have matching signatures
743 * @param a - First method node
744 * @param b - Second method node
745 * @return True if methods have identical identifier names
746 */
IsMethodMatch(ir::AstNode * a,ir::AstNode * b)747 bool IsMethodMatch(ir::AstNode *a, ir::AstNode *b)
748 {
749 return GetIdentifierName(a) == GetIdentifierName(b);
750 }
751
752 /**
753 * @brief Compares member matches and records matched and unmatched items
754 * @param currentMembers the list of members in the current class
755 * @param targetMembers the list of members in the target class
756 * @param matchedContainer the container to record matched members
757 * @param unmatchedContainer the container to record unmatched members
758 * @param fileName the file name, used for recording location information
759 */
CompareMembersCommon(const std::vector<ir::AstNode * > & currentMembers,const std::vector<ir::AstNode * > & targetMembers,std::vector<ClassRelationDetails> & matchedContainer,std::vector<ClassRelationDetails> & unmatchedContainer,const std::string & fileName)760 void CompareMembersCommon(const std::vector<ir::AstNode *> ¤tMembers,
761 const std::vector<ir::AstNode *> &targetMembers,
762 std::vector<ClassRelationDetails> &matchedContainer,
763 std::vector<ClassRelationDetails> &unmatchedContainer, const std::string &fileName)
764 {
765 for (auto *targetMember : targetMembers) {
766 auto kind = targetMember->IsMethodDefinition() ? ClassRelationKind::METHOD : ClassRelationKind::PROPERTY;
767 bool isMatch = false;
768 for (auto *currentMember : currentMembers) {
769 if (IsMethodMatch(currentMember, targetMember)) {
770 isMatch = true;
771 matchedContainer.emplace_back(fileName, currentMember->Start().index, kind);
772 break;
773 }
774 }
775 if (!isMatch) {
776 unmatchedContainer.emplace_back(fileName, targetMember->Start().index, kind);
777 }
778 }
779 }
780
CompareMembersForImplementation(const std::vector<ir::AstNode * > & currentMembers,const std::vector<ir::AstNode * > & interfaceMembers,ClassHierarchyItemInfo & info,const std::string & fileName)781 void CompareMembersForImplementation(const std::vector<ir::AstNode *> ¤tMembers,
782 const std::vector<ir::AstNode *> &interfaceMembers, ClassHierarchyItemInfo &info,
783 const std::string &fileName)
784 {
785 CompareMembersCommon(currentMembers, interfaceMembers, info.implemented, info.implementing, fileName);
786 }
787
CompareMembersForOverride(const std::vector<ir::AstNode * > & currentMembers,const std::vector<ir::AstNode * > & targetMembers,ClassHierarchyItemInfo & info,const std::string & fileName)788 void CompareMembersForOverride(const std::vector<ir::AstNode *> ¤tMembers,
789 const std::vector<ir::AstNode *> &targetMembers, ClassHierarchyItemInfo &info,
790 const std::string &fileName)
791 {
792 CompareMembersCommon(currentMembers, targetMembers, info.overridden, info.overriding, fileName);
793 }
794
795 struct ProcessItemsParams {
796 const std::vector<ir::AstNode *> ¤tMembers;
797 std::vector<ClassHierarchyItemInfo> &result;
798 std::vector<ir::AstNode *> (*getListFunc)(es2panda_Context *, ir::AstNode *);
799 ClassRelationKind kind;
800 bool swapCompareArgs;
801 void (*compareFunc)(const std::vector<ir::AstNode *> &, const std::vector<ir::AstNode *> &,
802 ClassHierarchyItemInfo &, const std::string &);
803 };
804
ProcessItems(es2panda_Context * context,ir::AstNode * node,const std::string & fileName,const ProcessItemsParams & params)805 void ProcessItems(es2panda_Context *context, ir::AstNode *node, const std::string &fileName,
806 const ProcessItemsParams ¶ms)
807 {
808 auto itemList = params.getListFunc(context, node);
809 for (auto *item : itemList) {
810 std::string name = GetIdentifierName(item);
811 ClassHierarchyItemInfo info(name, params.kind, item->Start().index);
812 auto itemMembers = GetMembers(context, item);
813 if (params.swapCompareArgs) {
814 params.compareFunc(itemMembers, params.currentMembers, info, fileName);
815 } else {
816 params.compareFunc(params.currentMembers, itemMembers, info, fileName);
817 }
818 params.result.emplace_back(info);
819 }
820 }
821
GetClassHierarchiesImpl(es2panda_Context * context,const std::string & fileName,size_t pos)822 std::vector<ClassHierarchyItemInfo> GetClassHierarchiesImpl(es2panda_Context *context, const std::string &fileName,
823 size_t pos)
824 {
825 auto pctx = reinterpret_cast<public_lib::Context *>(context);
826 auto program = pctx->parserProgram;
827 std::vector<ClassHierarchyItemInfo> result;
828 if (program == nullptr) {
829 return result;
830 }
831 auto classNode = GetTargetDeclarationNodeByPosition(context, pos);
832 if (classNode == nullptr) {
833 return result;
834 }
835 std::vector<ir::AstNode *> currentMembers = GetMembers(context, classNode);
836 if (classNode->IsClassDeclaration()) {
837 ProcessItems(context, classNode, fileName,
838 ProcessItemsParams {currentMembers, result, GetClassSuperClasses, ClassRelationKind::CLASS, false,
839 CompareMembersForOverride});
840 ProcessItems(context, classNode, fileName,
841 ProcessItemsParams {currentMembers, result, GetClassImplementedInterfaces,
842 ClassRelationKind::INTERFACE, false, CompareMembersForImplementation});
843 ProcessItems(context, classNode, fileName,
844 ProcessItemsParams {currentMembers, result, GetClassSubClasses, ClassRelationKind::CLASS, true,
845 CompareMembersForOverride});
846 } else if (classNode->IsTSInterfaceDeclaration()) {
847 ProcessItems(context, classNode, fileName,
848 ProcessItemsParams {currentMembers, result, GetInterfaceSuperInterfaces,
849 ClassRelationKind::INTERFACE, false, CompareMembersForOverride});
850 ProcessItems(context, classNode, fileName,
851 ProcessItemsParams {currentMembers, result, GetInterfaceSubInterfaces,
852 ClassRelationKind::INTERFACE, true, CompareMembersForOverride});
853 ProcessItems(context, classNode, fileName,
854 ProcessItemsParams {currentMembers, result, GetInterfaceImplementingClasses,
855 ClassRelationKind::CLASS, false, CompareMembersForImplementation});
856 }
857 return result;
858 }
859
860 } // namespace ark::es2panda::lsp