• 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 "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 *> &currentMembers,
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 *> &currentMembers,
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 *> &currentMembers,
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 *> &currentMembers;
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 &params)
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