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