• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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