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