• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024-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 "abc_file_processor.h"
17 #include "abc_file_utils.h"
18 #include "abc_method_processor.h"
19 #include "annotation_data_accessor.h"
20 #include "class_data_accessor.h"
21 
22 namespace ark::abc2program {
GetETSMetadata(const std::map<std::string,pandasm::Function> & functionTable)23 void AbcFileProcessor::GetETSMetadata(const std::map<std::string, pandasm::Function> &functionTable)
24 {
25     for (auto &pair : functionTable) {
26         if (pair.second.language == ark::panda_file::SourceLang::ETS) {
27             const auto methodId = keyData_.GetMethodNameToIdTable()[pair.first];
28 
29             GetETSMetadata(const_cast<pandasm::Function *>(&pair.second), methodId);
30         }
31     }
32 }
33 
34 // CC-OFFNXT(G.FUD.01) project codestyle
GeteTSMetadata()35 void AbcFileProcessor::GeteTSMetadata()
36 {
37     LOG(DEBUG, ABC2PROGRAM) << "\n[getting ETS-specific metadata]\n";
38 
39     for (auto &pair : program_->recordTable) {
40         if (pair.second.language == ark::panda_file::SourceLang::ETS) {
41             const auto recordId = keyData_.GetRecordNameToIdTable()[pair.first];
42             if (file_->IsExternal(recordId)) {
43                 continue;
44             }
45 
46             GetETSMetadata(&pair.second, recordId);
47 
48             panda_file::ClassDataAccessor classAccessor(*file_, recordId);
49 
50             size_t fieldIdx = 0;
51             classAccessor.EnumerateFields([&](panda_file::FieldDataAccessor &fieldAccessor) {
52                 GetETSMetadata(&pair.second.fieldList[fieldIdx++], fieldAccessor.GetFieldId());
53             });
54         }
55     }
56     GetETSMetadata(program_->functionStaticTable);
57     GetETSMetadata(program_->functionInstanceTable);
58 }
59 
GetETSMetadata(pandasm::Record * record,const panda_file::File::EntityId & recordId)60 void AbcFileProcessor::GetETSMetadata(pandasm::Record *record, const panda_file::File::EntityId &recordId)
61 {
62     LOG(DEBUG, ABC2PROGRAM) << "[getting ETS metadata]\nrecord id: " << recordId;
63     if (record == nullptr) {
64         LOG(ERROR, ABC2PROGRAM) << "> nullptr recieved!";
65         return;
66     }
67 
68     panda_file::ClassDataAccessor classAccessor(*file_, recordId);
69     const auto recordName = keyData_.GetFullRecordNameById(classAccessor.GetClassId());
70     SetETSAttributes(record, recordId);
71     AnnotationList annList {};
72     LOG(DEBUG, ABC2PROGRAM) << "[getting ets annotations]\nrecord id: " << recordId;
73 
74     classAccessor.EnumerateAnnotations([&](panda_file::File::EntityId id) {
75         const auto annListPart = GetETSAnnotation(id, "class");
76         annList.reserve(annList.size() + annListPart.size());
77         annList.insert(annList.end(), annListPart.begin(), annListPart.end());
78     });
79 
80     classAccessor.EnumerateRuntimeAnnotations([&](panda_file::File::EntityId id) {
81         const auto annListPart = GetETSAnnotation(id, "runtime");
82         annList.reserve(annList.size() + annListPart.size());
83         annList.insert(annList.end(), annListPart.begin(), annListPart.end());
84     });
85 
86     for (const auto &anno : annList) {
87         AbcFileEntityProcessor::SetEntityAttributeValue(
88             *record, []() { return true; }, anno.first, anno.second.c_str());
89     }
90 }
91 
SetETSAttributes(pandasm::Record * record,const panda_file::File::EntityId & recordId) const92 void AbcFileProcessor::SetETSAttributes(pandasm::Record *record, const panda_file::File::EntityId &recordId) const
93 {
94     // id of std.core.Object
95     [[maybe_unused]] static const size_t OBJ_ENTITY_ID = 0;
96 
97     panda_file::ClassDataAccessor classAccessor(*file_, recordId);
98     uint32_t accFlags = classAccessor.GetAccessFlags();
99     if ((accFlags & ACC_INTERFACE) != 0) {
100         record->metadata->SetAttribute("ets.interface");
101     }
102     if ((accFlags & ACC_ABSTRACT) != 0) {
103         record->metadata->SetAttribute("ets.abstract");
104     }
105     if ((accFlags & ACC_ANNOTATION) != 0) {
106         record->metadata->SetAttribute("ets.annotation");
107     }
108     if ((accFlags & ACC_ENUM) != 0) {
109         record->metadata->SetAttribute("ets.enum");
110     }
111     if ((accFlags & ACC_SYNTHETIC) != 0) {
112         record->metadata->SetAttribute("ets.synthetic");
113     }
114 
115     if (classAccessor.GetSuperClassId().GetOffset() != OBJ_ENTITY_ID) {
116         const auto superClassName = keyData_.GetFullRecordNameById(classAccessor.GetSuperClassId());
117         record->metadata->SetAttributeValue("ets.extends", superClassName);
118     }
119 
120     classAccessor.EnumerateInterfaces([&](panda_file::File::EntityId id) {
121         const auto ifaceName = keyData_.GetFullRecordNameById(id);
122         record->metadata->SetAttributeValue("ets.implements", ifaceName);
123     });
124 }
125 
GetETSMetadata(pandasm::Function * method,const panda_file::File::EntityId & methodId)126 void AbcFileProcessor::GetETSMetadata(pandasm::Function *method, const panda_file::File::EntityId &methodId)
127 {
128     LOG(DEBUG, ABC2PROGRAM) << "[getting ETS metadata]\nmethod id: " << methodId;
129     if (method == nullptr) {
130         LOG(ERROR, ABC2PROGRAM) << "> nullptr recieved!";
131         return;
132     }
133 
134     panda_file::MethodDataAccessor methodAccessor(*file_, methodId);
135     SetETSAttributes(method, methodId);
136     AnnotationList annList {};
137     LOG(DEBUG, ABC2PROGRAM) << "[getting ETS annotations]\nmethod id: " << methodId;
138 
139     methodAccessor.EnumerateAnnotations([&](panda_file::File::EntityId id) {
140         const auto annListPart = GetETSAnnotation(id, "class");
141         annList.reserve(annList.size() + annListPart.size());
142         annList.insert(annList.end(), annListPart.begin(), annListPart.end());
143     });
144 
145     methodAccessor.EnumerateRuntimeAnnotations([&](panda_file::File::EntityId id) {
146         const auto annListPart = GetETSAnnotation(id, "runtime");
147         annList.reserve(annList.size() + annListPart.size());
148         annList.insert(annList.end(), annListPart.begin(), annListPart.end());
149     });
150 
151     for (const auto &anno : annList) {
152         AbcFileEntityProcessor::SetEntityAttributeValue(
153             *method, []() { return true; }, anno.first, anno.second.c_str());
154     }
155 }
156 
SetETSAttributes(pandasm::Function * method,const panda_file::File::EntityId & methodId) const157 void AbcFileProcessor::SetETSAttributes(pandasm::Function *method, const panda_file::File::EntityId &methodId) const
158 {
159     panda_file::MethodDataAccessor methodAccessor(*file_, methodId);
160     uint32_t accFlags = methodAccessor.GetAccessFlags();
161     if ((accFlags & ACC_ABSTRACT) != 0) {
162         method->metadata->SetAttribute("ets.abstract");
163     }
164 }
165 
GetETSMetadata(pandasm::Field * field,const panda_file::File::EntityId & fieldId)166 void AbcFileProcessor::GetETSMetadata(pandasm::Field *field, const panda_file::File::EntityId &fieldId)
167 {
168     LOG(DEBUG, ABC2PROGRAM) << "[getting ETS metadata]\nfield id: " << fieldId;
169     if (field == nullptr) {
170         LOG(ERROR, ABC2PROGRAM) << "> nullptr recieved!";
171         return;
172     }
173 
174     panda_file::FieldDataAccessor fieldAccessor(*file_, fieldId);
175     SetETSAttributes(field, fieldId);
176     AnnotationList annList {};
177 
178     LOG(DEBUG, ABC2PROGRAM) << "[getting ETS annotations]\nfield id: " << fieldId;
179 
180     fieldAccessor.EnumerateAnnotations([&](panda_file::File::EntityId id) {
181         const auto annListPart = GetETSAnnotation(id, "class");
182         annList.reserve(annList.size() + annListPart.size());
183         annList.insert(annList.end(), annListPart.begin(), annListPart.end());
184     });
185 
186     fieldAccessor.EnumerateRuntimeAnnotations([&](panda_file::File::EntityId id) {
187         const auto annListPart = GetETSAnnotation(id, "runtime");
188         annList.reserve(annList.size() + annListPart.size());
189         annList.insert(annList.end(), annListPart.begin(), annListPart.end());
190     });
191 
192     for (const auto &anno : annList) {
193         AbcFileEntityProcessor::SetEntityAttributeValue(
194             *field, []() { return true; }, anno.first, anno.second.c_str());
195     }
196 }
197 
SetETSAttributes(pandasm::Field * field,const panda_file::File::EntityId & fieldId) const198 void AbcFileProcessor::SetETSAttributes(pandasm::Field *field, const panda_file::File::EntityId &fieldId) const
199 {
200     panda_file::FieldDataAccessor fieldAccessor(*file_, fieldId);
201     uint32_t accFlags = fieldAccessor.GetAccessFlags();
202     if ((accFlags & ACC_VOLATILE) != 0) {
203         field->metadata->SetAttribute("ets.volatile");
204     }
205     if ((accFlags & ACC_ENUM) != 0) {
206         field->metadata->SetAttribute("ets.enum");
207     }
208     if ((accFlags & ACC_TRANSIENT) != 0) {
209         field->metadata->SetAttribute("ets.transient");
210     }
211     if ((accFlags & ACC_SYNTHETIC) != 0) {
212         field->metadata->SetAttribute("ets.synthetic");
213     }
214 }
215 
216 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
GetETSAnnotation(const panda_file::File::EntityId & annotationId,const std::string & type)217 AnnotationList AbcFileProcessor::GetETSAnnotation(const panda_file::File::EntityId &annotationId,
218                                                   const std::string &type)
219 {
220     LOG(DEBUG, ABC2PROGRAM) << "[getting ets annotation]\nid: " << annotationId;
221     panda_file::AnnotationDataAccessor annotationAccessor(*file_, annotationId);
222     AnnotationList annList {};
223     // annotation
224 
225     const auto className = keyData_.GetFullRecordNameById(annotationAccessor.GetClassId());
226 
227     if (annotationAccessor.GetCount() == 0) {
228         if (!type.empty()) {
229             annList.push_back({"ets.annotation.type", type});
230         }
231         annList.push_back({"ets.annotation.class", className});
232         annList.push_back({"ets.annotation.id", "id_" + std::to_string(annotationId.GetOffset())});
233     }
234 
235     for (size_t i = 0; i < annotationAccessor.GetCount(); ++i) {
236         // element
237         const auto elemNameId = annotationAccessor.GetElement(i).GetNameId();
238         auto elemType = AnnotationTagToString(annotationAccessor.GetTag(i).GetItem());
239         const bool isArray = elemType.back() == ']';
240         const auto elemCompType =
241             elemType.substr(0, elemType.length() - 2);  // 2 last characters are '[' & ']' if annotation is an array
242         // adding necessary annotations
243         GetETSAnnotationImpl(annList, elemType, annotationAccessor.GetElement(i));
244         if (!type.empty()) {
245             annList.push_back({"ets.annotation.type", type});
246         }
247 
248         annList.push_back({"ets.annotation.class", className});
249 
250         annList.push_back({"ets.annotation.id", "id_" + std::to_string(annotationId.GetOffset())});
251         annList.push_back(
252             {"ets.annotation.element.name", stringTable_->StringDataToString(file_->GetStringData(elemNameId))});
253         // type
254         if (isArray) {
255             elemType = "array";
256             annList.push_back({"ets.annotation.element.type", elemType});
257             annList.push_back({"ets.annotation.element.array.component.type", elemCompType});
258             // values
259             const auto values = annotationAccessor.GetElement(i).GetArrayValue();
260             for (size_t idx = 0; idx < values.GetCount(); ++idx) {
261                 annList.push_back({"ets.annotation.element.value", ArrayValueToString(values, elemCompType, idx)});
262             }
263         } else {
264             annList.push_back({"ets.annotation.element.type", elemType});
265             // value
266             if (elemType != "void") {
267                 const auto value = annotationAccessor.GetElement(i).GetScalarValue();
268                 annList.push_back({"ets.annotation.element.value", ScalarValueToString(value, elemType)});
269             }
270         }
271     }
272     return annList;
273 }
274 
GetETSAnnotationImpl(AnnotationList & annList,const std::string & elemType,const panda_file::AnnotationDataAccessor::Elem & element)275 void AbcFileProcessor::GetETSAnnotationImpl(AnnotationList &annList, const std::string &elemType,
276                                             const panda_file::AnnotationDataAccessor::Elem &element)
277 {
278     const bool isArray = elemType.back() == ']';
279     const auto elemCompType = elemType.substr(0, elemType.length() - 2);
280     if (elemType == "annotations") {
281         const auto val = element.GetScalarValue().Get<panda_file::File::EntityId>();
282         const auto annDefinition = GetETSAnnotation(val, "");
283         for (const auto &elem : annDefinition) {
284             annList.push_back(elem);
285         }
286     }
287     if (isArray && elemCompType == "annotation") {
288         const auto values = element.GetArrayValue();
289         for (size_t idx = 0; idx < values.GetCount(); ++idx) {
290             const auto val = values.Get<panda_file::File::EntityId>(idx);
291             const auto annDefinition = GetETSAnnotation(val, "");
292             for (const auto &elem : annDefinition) {
293                 annList.push_back(elem);
294             }
295         }
296     }
297 }
298 
299 }  // namespace ark::abc2program
300