• 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_info.h"
17 #include "internal_api.h"
18 #include "public/public.h"
19 #include "compiler/lowering/util.h"
20 #include "quick_info.h"
21 
22 namespace ark::es2panda::lsp {
GetNameFromIdentifierNode(const ir::AstNode * node)23 std::string GetNameFromIdentifierNode(const ir::AstNode *node)
24 {
25     if (node == nullptr || !node->IsIdentifier()) {
26         return "";
27     }
28     return node->AsIdentifier()->ToString();
29 }
30 
31 // Currently only considering enum scenarios.
IsClassLiteralDefinition(const ir::AstNode * node)32 bool IsClassLiteralDefinition(const ir::AstNode *node)
33 {
34     return !(compiler::ClassDefinitionIsEnumTransformed(node));
35 }
36 
GetClassDefinitionFromIdentifierNode(const ir::AstNode * node)37 ir::ClassDefinition *GetClassDefinitionFromIdentifierNode(const ir::AstNode *node)
38 {
39     auto decl = compiler::DeclarationFromIdentifier(node->AsIdentifier());
40     if (decl == nullptr) {
41         return nullptr;
42     }
43     if (decl->IsClassDeclaration()) {
44         decl = decl->AsClassDeclaration()->Definition();
45     }
46     if (!IsClassLiteralDefinition(decl)) {
47         return nullptr;
48     }
49     return decl->AsClassDefinition();
50 }
51 
SpliceFunctionDetailStr(const std::string & functionName,const std::vector<FunctionParamStyle> & params,const std::string & returnType)52 std::string SpliceFunctionDetailStr(const std::string &functionName, const std::vector<FunctionParamStyle> &params,
53                                     const std::string &returnType)
54 {
55     std::string result;
56     if (functionName.empty()) {
57         return result;
58     }
59     result.append(functionName).append("(");
60     auto iter = params.cbegin();
61     while (iter != params.cend()) {
62         auto name = iter->GetParamName();
63         auto kind = iter->GetParamKind();
64         if (name.empty() || kind.empty()) {
65             ++iter;
66             continue;
67         }
68         result.append(name).append(": ").append(kind);
69         ++iter;
70         if (iter != params.cend()) {
71             result.append(", ");
72         }
73     }
74     result.append(")");
75     if (!returnType.empty()) {
76         result.append(": ").append(returnType);
77     }
78     return result;
79 }
80 
SplicePropertyDetailStr(const std::string & name,const std::string & type)81 std::string SplicePropertyDetailStr(const std::string &name, const std::string &type)
82 {
83     if (name.empty() || type.empty()) {
84         return "";
85     }
86     return name + ": " + type;
87 }
88 
GetFunctionNameFromScriptFunction(const ir::ScriptFunction * function)89 std::string GetFunctionNameFromScriptFunction(const ir::ScriptFunction *function)
90 {
91     if (function == nullptr || function->Id() == nullptr) {
92         return "";
93     }
94     return function->Id()->ToString();
95 }
96 
GetParamListFromScriptFunction(const ir::ScriptFunction * function)97 std::vector<FunctionParamStyle> GetParamListFromScriptFunction(const ir::ScriptFunction *function)
98 {
99     std::vector<FunctionParamStyle> params;
100     if (function == nullptr) {
101         return params;
102     }
103     auto nodeParams = function->Params();
104     for (const auto *it : nodeParams) {
105         if (it == nullptr || !it->IsETSParameterExpression()) {
106             continue;
107         }
108         std::string paramName;
109         std::string paramKind;
110         auto nodeParam = it->AsETSParameterExpression();
111         if (nodeParam->IsRestParameter()) {
112             paramName = nodeParam->RestParameter()->ToString();
113         } else {
114             paramName = GetNameFromIdentifierNode(nodeParam->Ident());
115         }
116         if (paramName == INVALID_EXPRESSION || nodeParam->TypeAnnotation() == nullptr) {
117             continue;
118         }
119         paramKind = GetNameForTypeNode(nodeParam->TypeAnnotation());
120         params.emplace_back(FunctionParamStyle(std::move(paramName), std::move(paramKind)));
121     }
122     return params;
123 }
124 
GetReturnTypeFromScriptFunction(const ir::ScriptFunction * function)125 std::string GetReturnTypeFromScriptFunction(const ir::ScriptFunction *function)
126 {
127     if (function == nullptr) {
128         return "";
129     }
130     auto returnNode = function->ReturnTypeAnnotation();
131     if (returnNode == nullptr) {
132         return "";
133     }
134     auto returnType = GetNameForTypeNode(returnNode);
135     return returnType;
136 }
137 
CreateSetterStyle(ir::MethodDefinitionKind kind)138 SetterStyle CreateSetterStyle(ir::MethodDefinitionKind kind)
139 {
140     SetterStyle setter = SetterStyle::NONE;
141     switch (kind) {
142         case ir::MethodDefinitionKind::GET:
143         case ir::MethodDefinitionKind::EXTENSION_GET:
144             setter = SetterStyle::GETTER;
145             break;
146         case ir::MethodDefinitionKind::SET:
147         case ir::MethodDefinitionKind::EXTENSION_SET:
148             setter = SetterStyle::SETTER;
149             break;
150         default:
151             break;
152     }
153     return setter;
154 }
155 
CreateClassMethodItem(const ir::MethodDefinition * methodDefinition,const std::string & funcName,std::string detail)156 std::shared_ptr<ClassMethodItem> CreateClassMethodItem(const ir::MethodDefinition *methodDefinition,
157                                                        const std::string &funcName, std::string detail)
158 {
159     if (methodDefinition == nullptr || funcName.empty() || detail.empty()) {
160         return nullptr;
161     }
162     auto setter = CreateSetterStyle(methodDefinition->Kind());
163     AccessModifierStyle access = AccessModifierStyle::PUBLIC;
164     if (methodDefinition->IsProtected()) {
165         access = AccessModifierStyle::PROTECTED;
166     }
167     auto item = std::make_shared<ClassMethodItem>(access, std::move(detail), setter);
168     item->SetFunctionName(funcName);
169     return item;
170 }
171 
CreateClassPropertyItem(const ir::ClassProperty * property,const std::string & propertyName,std::string detail)172 std::shared_ptr<ClassPropertyItem> CreateClassPropertyItem(const ir::ClassProperty *property,
173                                                            const std::string &propertyName, std::string detail)
174 {
175     if (property == nullptr || propertyName.empty() || detail.empty()) {
176         return nullptr;
177     }
178     AccessModifierStyle access = AccessModifierStyle::PUBLIC;
179     if (property->IsProtected()) {
180         access = AccessModifierStyle::PROTECTED;
181     }
182     auto item = std::make_shared<ClassPropertyItem>(access, std::move(detail));
183     item->SetVariableName(propertyName);
184     return item;
185 }
186 
ParseFunctionStyleWithCreateItem(const ir::MethodDefinition * methodDefinition,bool isCurrentToken)187 std::shared_ptr<ClassMethodItem> ParseFunctionStyleWithCreateItem(const ir::MethodDefinition *methodDefinition,
188                                                                   bool isCurrentToken)
189 {
190     if (methodDefinition == nullptr) {
191         return nullptr;
192     }
193     if ((isCurrentToken && methodDefinition->IsStatic()) ||
194         (!isCurrentToken &&
195          (methodDefinition->IsPrivate() || methodDefinition->IsStatic() || methodDefinition->IsConstructor()))) {
196         return nullptr;
197     }
198     auto function = methodDefinition->Function();
199     auto functionName = GetFunctionNameFromScriptFunction(function);
200     if (functionName.empty()) {
201         return nullptr;
202     }
203     auto paramList = GetParamListFromScriptFunction(function);
204     auto returnType = GetReturnTypeFromScriptFunction(function);
205     auto functionDetail = SpliceFunctionDetailStr(functionName, paramList, returnType);
206     return CreateClassMethodItem(methodDefinition, functionName, functionDetail);
207 }
208 
GetIdentFromNewClassExprPart(const ir::Expression * value)209 ir::Identifier *GetIdentFromNewClassExprPart(const ir::Expression *value)
210 {
211     if (value == nullptr || !value->IsETSNewClassInstanceExpression()) {
212         return nullptr;
213     }
214     auto typeRef = value->AsETSNewClassInstanceExpression()->GetTypeRef();
215     if (typeRef == nullptr || !typeRef->IsETSTypeReference()) {
216         return nullptr;
217     }
218     auto part = typeRef->AsETSTypeReference()->Part();
219     if (part == nullptr) {
220         return nullptr;
221     }
222     return part->GetIdent();
223 }
224 
ParsePropertyStyleWithCreateItem(const ir::ClassProperty * property,bool isCurrentToken)225 std::shared_ptr<ClassPropertyItem> ParsePropertyStyleWithCreateItem(const ir::ClassProperty *property,
226                                                                     bool isCurrentToken)
227 {
228     if (property == nullptr) {
229         return nullptr;
230     }
231     if ((isCurrentToken && property->IsStatic()) ||
232         (!isCurrentToken && (property->IsPrivate() || property->IsStatic()))) {
233         return nullptr;
234     }
235     std::string propertyName = GetNameFromIdentifierNode(property->Key());
236     std::string type;
237     if (property->TypeAnnotation() == nullptr) {
238         auto value = property->Value();
239         auto ident = GetIdentFromNewClassExprPart(value);
240         type = GetNameFromIdentifierNode(ident);
241     } else {
242         type = GetNameForTypeNode(property->TypeAnnotation());
243     }
244     if (propertyName == INVALID_EXPRESSION || type == INVALID_EXPRESSION) {
245         return nullptr;
246     }
247     auto detail = SplicePropertyDetailStr(propertyName, type);
248     return CreateClassPropertyItem(property, propertyName, detail);
249 }
250 
CreateClassHierarchyInfoFromBody(const ir::ClassDefinition * classDefinition,const std::string & className,bool isCurrentToken)251 ClassHierarchyInfo CreateClassHierarchyInfoFromBody(const ir::ClassDefinition *classDefinition,
252                                                     const std::string &className, bool isCurrentToken)
253 {
254     ClassHierarchyInfo result;
255     if (classDefinition == nullptr) {
256         return result;
257     }
258     result.SetClassName(className);
259     auto bodyNodes = classDefinition->Body();
260     for (const auto &node : bodyNodes) {
261         if (node == nullptr) {
262             continue;
263         }
264         if (node->IsMethodDefinition()) {
265             auto methodDefinition = node->AsMethodDefinition();
266             if (methodDefinition == nullptr) {
267                 continue;
268             }
269             auto item = ParseFunctionStyleWithCreateItem(methodDefinition, isCurrentToken);
270             result.AddItemToMethodList(item);
271             auto overLoads = methodDefinition->Overloads();
272             for (const auto *overLoadMethodDefinition : overLoads) {
273                 auto overLoadItem = ParseFunctionStyleWithCreateItem(overLoadMethodDefinition, isCurrentToken);
274                 result.AddItemToMethodList(overLoadItem);
275             }
276         } else if (node->IsClassProperty()) {
277             auto property = node->AsClassProperty();
278             if (property == nullptr) {
279                 continue;
280             }
281             auto item = ParsePropertyStyleWithCreateItem(property, isCurrentToken);
282             result.AddItemToPropertyList(item);
283         }
284     }
285     return result;
286 }
287 
GetSuperClassNode(const ir::ClassDefinition * classDefinition)288 ir::AstNode *GetSuperClassNode(const ir::ClassDefinition *classDefinition)
289 {
290     if (classDefinition == nullptr) {
291         return nullptr;
292     }
293     auto super = const_cast<ir::Expression *>(classDefinition->Super());
294     if (super == nullptr) {
295         return nullptr;
296     }
297     return GetIdentifierFromSuper(super);
298 }
299 
ComputeClassHierarchyInfo(const ClassHierarchyInfo & deriveInfo,ClassHierarchyInfo & superInfo)300 void ComputeClassHierarchyInfo(const ClassHierarchyInfo &deriveInfo, ClassHierarchyInfo &superInfo)
301 {
302     auto deriveMethods = deriveInfo.GetMethodItemList();
303     for (const auto &method : deriveMethods) {
304         superInfo.DeleteTargetItemInMethodList(method.second);
305     }
306     auto deriveProperties = deriveInfo.GetPropertyItemList();
307     for (const auto &property : deriveProperties) {
308         superInfo.DeleteTargetItemInPropertyList(property.second);
309     }
310 }
311 
FillBaseClassHierarchyInfo(const ClassHierarchyInfo & extraInfo,ClassHierarchyInfo & baseInfo)312 void FillBaseClassHierarchyInfo(const ClassHierarchyInfo &extraInfo, ClassHierarchyInfo &baseInfo)
313 {
314     auto extraMethods = extraInfo.GetMethodItemList();
315     for (const auto &method : extraMethods) {
316         baseInfo.AddItemToMethodList(method.second);
317     }
318     auto extraProperties = extraInfo.GetPropertyItemList();
319     for (const auto &property : extraProperties) {
320         baseInfo.AddItemToPropertyList(property.second);
321     }
322 }
323 
ProcessClassHierarchy(const ir::AstNode * token,ClassHierarchyInfo & baseInfo,ClassHierarchy & result)324 void ProcessClassHierarchy(const ir::AstNode *token, ClassHierarchyInfo &baseInfo, ClassHierarchy &result)
325 {
326     if (token == nullptr || !token->IsIdentifier()) {
327         return;
328     }
329     std::string className = GetNameFromIdentifierNode(token);
330     auto classDefinition = GetClassDefinitionFromIdentifierNode(token);
331     if (classDefinition == nullptr) {
332         return;
333     }
334     auto info = CreateClassHierarchyInfoFromBody(classDefinition, className, false);
335     if (!className.empty()) {
336         // Calculate the difference between the obtained parent class info and the current clicked node class info.
337         ComputeClassHierarchyInfo(baseInfo, info);
338         if (info.GetClassName() == className &&
339             (!info.GetMethodItemList().empty() || !info.GetPropertyItemList().empty())) {
340             result.emplace_back(info);
341             FillBaseClassHierarchyInfo(info, baseInfo);
342         }
343     }
344     auto superClass = GetSuperClassNode(classDefinition);
345     if (superClass == nullptr) {
346         return;
347     }
348     ProcessClassHierarchy(superClass, baseInfo, result);
349 }
350 
GetTargetClassDeclarationByPosition(es2panda_Context * context,size_t position)351 ir::AstNode *GetTargetClassDeclarationByPosition(es2panda_Context *context, size_t position)
352 {
353     if (context == nullptr) {
354         return nullptr;
355     }
356     auto token = GetTouchingToken(context, position, false);
357     auto tmp = token;
358     while (tmp != nullptr) {
359         if (tmp->IsClassDeclaration()) {
360             return tmp;
361         }
362         tmp = tmp->Parent();
363     }
364     return nullptr;
365 }
366 
GetClassHierarchyInfoImpl(es2panda_Context * context,size_t position)367 ClassHierarchy GetClassHierarchyInfoImpl(es2panda_Context *context, size_t position)
368 {
369     ClassHierarchy result;
370     auto classDeclaration = GetTargetClassDeclarationByPosition(context, position);
371     if (classDeclaration == nullptr) {
372         return result;
373     }
374     auto classDefinition = classDeclaration->AsClassDeclaration()->Definition();
375     auto currentInfo = CreateClassHierarchyInfoFromBody(classDefinition, "", true);
376     auto superClass = GetSuperClassNode(classDefinition);
377     if (superClass == nullptr) {
378         return result;
379     }
380     ProcessClassHierarchy(superClass, currentInfo, result);
381     return result;
382 }
383 }  // namespace ark::es2panda::lsp
384