• 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 "generate_constructor.h"
17 #include "internal_api.h"
18 #include "compiler/lowering/util.h"
19 #include "public/public.h"
20 #include "class_hierarchy.h"
21 #include "completions.h"
22 #include "quick_info.h"
23 
24 namespace ark::es2panda::lsp {
25 
HasConstructorNode(ir::AstNode * classNode)26 bool HasConstructorNode(ir::AstNode *classNode)
27 {
28     size_t start = classNode->Start().index;
29     size_t end = classNode->End().index;
30     ir::AstNode *constructorNode = classNode->FindChild([start, end](ir::AstNode *node) {
31         if (node == nullptr) {
32             return false;
33         }
34         return node->Start().index >= start && node->End().index <= end && node->IsConstructor();
35     });
36 
37     return constructorNode != nullptr;
38 }
39 
GetClassProperties(ir::AstNode * classNode,const std::vector<std::string> & properties)40 std::vector<ir::AstNode *> GetClassProperties(ir::AstNode *classNode, const std::vector<std::string> &properties)
41 {
42     std::vector<ir::AstNode *> classProperties = {};
43     auto bodyNodes = classNode->AsClassDeclaration()->Definition()->Body();
44     for (const auto &triggerWord : properties) {
45         auto property = ark::es2panda::lsp::FilterFromBody(bodyNodes, triggerWord);
46         for (const auto &node : property) {
47             if (node->IsStatic() || !node->IsClassProperty()) {
48                 continue;
49             }
50             classProperties.emplace_back(node);
51         }
52     }
53 
54     return classProperties;
55 }
56 
GetExtendedClassProperties(ir::AstNode * classNode)57 std::vector<ir::AstNode *> GetExtendedClassProperties(ir::AstNode *classNode)
58 {
59     auto baseNode = ark::es2panda::lsp::GetEffectiveBaseTypeNode(classNode);
60     if (baseNode == nullptr) {
61         return {};
62     }
63     std::vector<ir::AstNode *> extendedClassProperties = {};
64     auto baseNodeBody = baseNode->AsClassDeclaration()->Definition()->Body();
65     for (auto node : baseNodeBody) {
66         if (!node->IsClassProperty()) {
67             continue;
68         }
69         auto tmp = node->AsClassProperty();
70         if (tmp->IsStatic()) {
71             continue;
72         }
73 
74         extendedClassProperties.push_back(node);
75     }
76     return extendedClassProperties;
77 }
78 
RemoveTrailingChar(std::string & str,const std::string & lastChar)79 void RemoveTrailingChar(std::string &str, const std::string &lastChar)
80 {
81     if (!str.empty()) {
82         size_t lastPos = str.find_last_of(lastChar);
83         if (lastPos != std::string::npos) {
84             str.erase(lastPos);
85         }
86     }
87 }
88 
GetParameterListAndFunctionBody(std::string & parameterList,std::string & functionBody,const std::vector<ir::AstNode * > & nodeList,bool isSuper)89 void GetParameterListAndFunctionBody(std::string &parameterList, std::string &functionBody,
90                                      const std::vector<ir::AstNode *> &nodeList, bool isSuper)
91 {
92     if (nodeList.empty()) {
93         return;
94     }
95 
96     std::vector<std::string> strList1 = {};
97     std::vector<std::string> strList2 = {};
98     for (auto propertyNode : nodeList) {
99         auto nodeName = GetIdentifierName(propertyNode);
100         auto typeAnnotation = propertyNode->AsClassProperty()->TypeAnnotation();
101         if (typeAnnotation->IsETSTypeReference()) {
102             auto propertyType = GetNameForTypeReference(typeAnnotation);
103             auto str = nodeName;
104             str += ": ";
105             str += propertyType;
106             str += ", ";
107             strList1.push_back(str);
108             strList2.push_back(nodeName);
109         }
110     }
111 
112     for (const auto &str : strList1) {
113         parameterList += str;
114     }
115 
116     if (isSuper) {
117         functionBody += "  super(";
118         for (const auto &str : strList2) {
119             functionBody += str;
120             functionBody += ", ";
121         }
122         RemoveTrailingChar(functionBody, ",");
123         functionBody += ");\n";
124     } else {
125         for (const auto &str : strList2) {
126             functionBody += "  this.";
127             functionBody += str;
128             functionBody += " = ";
129             functionBody += str;
130             functionBody += ";\n";
131         }
132     }
133 }
134 
CollectConstructorInfo(const std::vector<ir::AstNode * > & classProperties,const std::vector<ir::AstNode * > & extendedClassProperties)135 std::string CollectConstructorInfo(const std::vector<ir::AstNode *> &classProperties,
136                                    const std::vector<ir::AstNode *> &extendedClassProperties)
137 {
138     std::string constructorInfoText = "constructor(";
139     std::string parameterList;
140     std::string functionBody;
141 
142     if (!extendedClassProperties.empty()) {
143         GetParameterListAndFunctionBody(parameterList, functionBody, extendedClassProperties, true);
144     }
145     GetParameterListAndFunctionBody(parameterList, functionBody, classProperties, false);
146     RemoveTrailingChar(parameterList, ",");
147     constructorInfoText += parameterList;
148     constructorInfoText += ") {\n";
149     constructorInfoText += functionBody;
150     constructorInfoText += "}";
151     return constructorInfoText;
152 }
153 
GetInsertNodePosition(ir::AstNode * classNode,size_t & insertPosition)154 void GetInsertNodePosition(ir::AstNode *classNode, size_t &insertPosition)
155 {
156     if (classNode == nullptr || !classNode->IsClassDeclaration()) {
157         return;
158     }
159 
160     bool isExitProperty = false;
161     auto classBody = classNode->AsClassDeclaration()->Definition()->Body();
162     for (auto node : classBody) {
163         if (node->IsClassProperty() && !isExitProperty) {
164             insertPosition = node->AsClassProperty()->Start().index;
165             isExitProperty = true;
166             break;
167         }
168     }
169 
170     if (!isExitProperty) {
171         const int offset = 2;
172         insertPosition = classNode->End().index - offset;
173     }
174 }
175 
GetRefactorActionsToGenerateConstructor(es2panda_Context * context,size_t position,const std::vector<std::string> & properties)176 std::vector<FileTextChanges> GetRefactorActionsToGenerateConstructor(es2panda_Context *context, size_t position,
177                                                                      const std::vector<std::string> &properties)
178 {
179     if (context == nullptr) {
180         return {};
181     }
182     auto ctx = reinterpret_cast<public_lib::Context *>(context);
183     if (ctx->parserProgram == nullptr || ctx->parserProgram->Ast() == nullptr) {
184         return {};
185     }
186 
187     ir::AstNode *classDeclaration = ark::es2panda::lsp::GetTargetDeclarationNodeByPosition(context, position);
188     if (!IsDefinedClassOrStruct(classDeclaration)) {
189         return {};
190     }
191 
192     if (HasConstructorNode(classDeclaration)) {
193         return {};
194     }
195 
196     std::vector<ir::AstNode *> classProperties = GetClassProperties(classDeclaration, properties);
197     std::vector<ir::AstNode *> extendedClassProperties = GetExtendedClassProperties(classDeclaration);
198 
199     std::string text = CollectConstructorInfo(classProperties, extendedClassProperties);
200     size_t insertPosition = 0;
201     GetInsertNodePosition(classDeclaration, insertPosition);
202 
203     std::vector<FileTextChanges> fileTextChanges;
204     TextSpan span(insertPosition, text.size());
205     std::vector<TextChange> textChanges;
206     textChanges.emplace_back(TextChange(span, text));
207     auto fileName = ctx->sourceFileName;
208     FileTextChanges textChange(fileName, textChanges);
209     fileTextChanges.push_back(textChange);
210 
211     return fileTextChanges;
212 }
213 
214 }  // namespace ark::es2panda::lsp