xref: /aosp_15_r20/development/vndk/tools/header-checker/src/repr/json/ir_dumper.cpp (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1 // Copyright (C) 2019 The Android Open Source Project
2 //
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 #include "repr/json/ir_dumper.h"
16 
17 #include "repr/ir_dumper.h"
18 #include "repr/ir_representation.h"
19 #include "repr/json/api.h"
20 #include "repr/json/converter.h"
21 
22 #include <json/writer.h>
23 
24 #include <fstream>
25 #include <string>
26 
27 
28 namespace header_checker {
29 namespace repr {
30 
31 
AddAccess(JsonObject & type_decl,AccessSpecifierIR value)32 static void AddAccess(JsonObject &type_decl, AccessSpecifierIR value) {
33   if (value != default_access_ir) {
34     type_decl.Set("access",
35                   FindInMap(access_ir_to_json, value,
36                             "Failed to convert AccessSpecifierIR to JSON"));
37   }
38 }
39 
AddRecordKind(JsonObject & record_type,RecordTypeIR::RecordKind value)40 static void AddRecordKind(JsonObject &record_type,
41                           RecordTypeIR::RecordKind value) {
42   if (value != default_record_kind_ir) {
43     record_type.Set("record_kind",
44                     FindInMap(record_kind_ir_to_json, value,
45                               "Failed to convert RecordKind to JSON"));
46   }
47 }
48 
AddAvailabilityAttrs(JsonObject & decl,const HasAvailabilityAttrs * decl_ir)49 static void AddAvailabilityAttrs(JsonObject &decl,
50                                  const HasAvailabilityAttrs *decl_ir) {
51   if (decl_ir->GetAvailabilityAttrs().empty()) {
52     return;
53   }
54   JsonArray attrs;
55   for (auto &&attr_ir : decl_ir->GetAvailabilityAttrs()) {
56     JsonObject attr;
57     if (auto introduced = attr_ir.GetIntroduced(); introduced.has_value()) {
58       attr.Set("introduced_major", (uint64_t)introduced.value());
59     }
60     if (auto deprecated = attr_ir.GetDeprecated(); deprecated.has_value()) {
61       attr.Set("deprecated_major", (uint64_t)deprecated.value());
62     }
63     if (auto obsoleted = attr_ir.GetObsoleted(); obsoleted.has_value()) {
64       attr.Set("obsoleted_major", (uint64_t)obsoleted.value());
65     }
66     if (attr_ir.IsUnavailable()) {
67       attr.Set("unavailable", true);
68     }
69     attrs.append(std::move(attr));
70   }
71   decl.Set("availability_attrs", attrs);
72 }
73 
AddVtableComponentKind(JsonObject & vtable_component,VTableComponentIR::Kind value)74 static void AddVtableComponentKind(JsonObject &vtable_component,
75                                    VTableComponentIR::Kind value) {
76   if (value != default_vtable_component_kind_ir) {
77     vtable_component.Set(
78         "kind", FindInMap(vtable_component_kind_ir_to_json, value,
79                           "Failed to convert VTableComponentIR::Kind to JSON"));
80   }
81 }
82 
AddElfSymbolBinding(JsonObject & elf_symbol,ElfSymbolIR::ElfSymbolBinding value)83 static void AddElfSymbolBinding(JsonObject &elf_symbol,
84                                 ElfSymbolIR::ElfSymbolBinding value) {
85   if (value != default_elf_symbol_binding_ir) {
86     elf_symbol.Set("binding",
87                    FindInMap(elf_symbol_binding_ir_to_json, value,
88                              "Failed to convert ElfSymbolBinding to JSON"));
89   }
90 }
91 
AddTemplateInfo(JsonObject & type_decl,const TemplatedArtifactIR * template_ir)92 static void AddTemplateInfo(JsonObject &type_decl,
93                             const TemplatedArtifactIR *template_ir) {
94   JsonArray args;
95   for (auto &&template_element_ir : template_ir->GetTemplateElements()) {
96     args.append(template_element_ir.GetReferencedType());
97   }
98   type_decl.Set("template_args", args);
99 }
100 
AddTypeInfo(JsonObject & type_decl,const TypeIR * type_ir)101 static void AddTypeInfo(JsonObject &type_decl, const TypeIR *type_ir) {
102   // LinkableMessageIR
103   type_decl.Set("source_file", type_ir->GetSourceFile());
104   const std::string &linker_set_key = type_ir->GetLinkerSetKey();
105   type_decl.Set("linker_set_key", linker_set_key);
106   // TypeIR
107   type_decl.Set("name", type_ir->GetName());
108   type_decl.Set("size", (uint64_t)type_ir->GetSize());
109   type_decl.Set("alignment", (uint64_t)type_ir->GetAlignment());
110   const std::string &self_type = type_ir->GetSelfType();
111   if (self_type != linker_set_key) {
112     type_decl.Set("self_type", self_type);
113   }
114   // ReferencesOtherType
115   const std::string &referenced_type = type_ir->GetReferencedType();
116   if (referenced_type != self_type) {
117     type_decl.Set("referenced_type", referenced_type);
118   }
119 }
120 
ConvertRecordFieldIR(const RecordFieldIR * record_field_ir)121 static JsonObject ConvertRecordFieldIR(const RecordFieldIR *record_field_ir) {
122   JsonObject record_field;
123   record_field.Set("field_name", record_field_ir->GetName());
124   record_field.Set("referenced_type", record_field_ir->GetReferencedType());
125   AddAccess(record_field, record_field_ir->GetAccess());
126   record_field.Set("field_offset", (uint64_t)record_field_ir->GetOffset());
127   record_field.Set("is_bit_field", record_field_ir->IsBitField());
128   record_field.Set("bit_width", (uint64_t)record_field_ir->GetBitWidth());
129   AddAvailabilityAttrs(record_field, record_field_ir);
130   return record_field;
131 }
132 
AddRecordFields(JsonObject & record_type,const RecordTypeIR * record_ir)133 static void AddRecordFields(JsonObject &record_type,
134                             const RecordTypeIR *record_ir) {
135   JsonArray fields;
136   for (auto &&field_ir : record_ir->GetFields()) {
137     fields.append(ConvertRecordFieldIR(&field_ir));
138   }
139   record_type.Set("fields", fields);
140 }
141 
142 static JsonObject
ConvertBaseSpecifierIR(const CXXBaseSpecifierIR & base_specifier_ir)143 ConvertBaseSpecifierIR(const CXXBaseSpecifierIR &base_specifier_ir) {
144   JsonObject base_specifier;
145   base_specifier.Set("referenced_type", base_specifier_ir.GetReferencedType());
146   base_specifier.Set("is_virtual", base_specifier_ir.IsVirtual());
147   AddAccess(base_specifier, base_specifier_ir.GetAccess());
148   return base_specifier;
149 }
150 
AddBaseSpecifiers(JsonObject & record_type,const RecordTypeIR * record_ir)151 static void AddBaseSpecifiers(JsonObject &record_type,
152                               const RecordTypeIR *record_ir) {
153   JsonArray base_specifiers;
154   for (auto &&base_ir : record_ir->GetBases()) {
155     base_specifiers.append(ConvertBaseSpecifierIR(base_ir));
156   }
157   record_type.Set("base_specifiers", base_specifiers);
158 }
159 
160 static JsonObject
ConvertVTableComponentIR(const VTableComponentIR & vtable_component_ir)161 ConvertVTableComponentIR(const VTableComponentIR &vtable_component_ir) {
162   JsonObject vtable_component;
163   AddVtableComponentKind(vtable_component, vtable_component_ir.GetKind());
164   vtable_component.Set("component_value",
165                        (int64_t)vtable_component_ir.GetValue());
166   vtable_component.Set("mangled_component_name", vtable_component_ir.GetName());
167   vtable_component.Set("is_pure", vtable_component_ir.GetIsPure());
168   return vtable_component;
169 }
170 
AddVTableLayout(JsonObject & record_type,const RecordTypeIR * record_ir)171 static void AddVTableLayout(JsonObject &record_type,
172                             const RecordTypeIR *record_ir) {
173   JsonArray vtable_components;
174   for (auto &&vtable_component_ir :
175        record_ir->GetVTableLayout().GetVTableComponents()) {
176     vtable_components.append(ConvertVTableComponentIR(vtable_component_ir));
177   }
178   record_type.Set("vtable_components", vtable_components);
179 }
180 
ConvertRecordTypeIR(const RecordTypeIR * recordp)181 static JsonObject ConvertRecordTypeIR(const RecordTypeIR *recordp) {
182   JsonObject record_type;
183 
184   AddAccess(record_type, recordp->GetAccess());
185   AddRecordKind(record_type, recordp->GetRecordKind());
186   record_type.Set("is_anonymous", recordp->IsAnonymous());
187   AddTypeInfo(record_type, recordp);
188   AddRecordFields(record_type, recordp);
189   AddBaseSpecifiers(record_type, recordp);
190   AddVTableLayout(record_type, recordp);
191   AddTemplateInfo(record_type, recordp);
192   AddAvailabilityAttrs(record_type, recordp);
193   return record_type;
194 }
195 
AddFunctionParameters(JsonObject & function,const CFunctionLikeIR * cfunction_like_ir)196 static void AddFunctionParameters(JsonObject &function,
197                                   const CFunctionLikeIR *cfunction_like_ir) {
198   JsonArray parameters;
199   for (auto &&parameter_ir : cfunction_like_ir->GetParameters()) {
200     JsonObject parameter;
201     parameter.Set("referenced_type", parameter_ir.GetReferencedType());
202     parameter.Set("default_arg", parameter_ir.GetIsDefault());
203     parameter.Set("is_this_ptr", parameter_ir.GetIsThisPtr());
204     parameters.append(parameter);
205   }
206   function.Set("parameters", parameters);
207 }
208 
AddFunctionParametersAndSetReturnType(JsonObject & function,const CFunctionLikeIR * cfunction_like_ir)209 static void AddFunctionParametersAndSetReturnType(
210     JsonObject &function, const CFunctionLikeIR *cfunction_like_ir) {
211   function.Set("return_type", cfunction_like_ir->GetReturnType());
212   AddFunctionParameters(function, cfunction_like_ir);
213 }
214 
ConvertFunctionTypeIR(const FunctionTypeIR * function_typep)215 static JsonObject ConvertFunctionTypeIR(const FunctionTypeIR *function_typep) {
216   JsonObject function_type;
217   AddTypeInfo(function_type, function_typep);
218   AddFunctionParametersAndSetReturnType(function_type, function_typep);
219   return function_type;
220 }
221 
ConvertFunctionIR(const FunctionIR * functionp)222 static JsonObject ConvertFunctionIR(const FunctionIR *functionp) {
223   JsonObject function;
224   AddAccess(function, functionp->GetAccess());
225   function.Set("linker_set_key", functionp->GetLinkerSetKey());
226   function.Set("source_file", functionp->GetSourceFile());
227   function.Set("function_name", functionp->GetName());
228   AddFunctionParametersAndSetReturnType(function, functionp);
229   AddTemplateInfo(function, functionp);
230   AddAvailabilityAttrs(function, functionp);
231   return function;
232 }
233 
ConvertEnumFieldIR(const EnumFieldIR * enum_field_ir)234 static JsonObject ConvertEnumFieldIR(const EnumFieldIR *enum_field_ir) {
235   JsonObject enum_field;
236   enum_field.Set("name", enum_field_ir->GetName());
237   // Never omit enum values.
238   Json::Value &enum_field_value = enum_field["enum_field_value"];
239   if (enum_field_ir->IsSigned()) {
240     enum_field_value = Json::Int64(enum_field_ir->GetSignedValue());
241   } else {
242     enum_field_value = Json::UInt64(enum_field_ir->GetUnsignedValue());
243   }
244   AddAvailabilityAttrs(enum_field, enum_field_ir);
245   return enum_field;
246 }
247 
AddEnumFields(JsonObject & enum_type,const EnumTypeIR * enum_ir)248 static void AddEnumFields(JsonObject &enum_type, const EnumTypeIR *enum_ir) {
249   JsonArray enum_fields;
250   for (auto &&field : enum_ir->GetFields()) {
251     enum_fields.append(ConvertEnumFieldIR(&field));
252   }
253   enum_type.Set("enum_fields", enum_fields);
254 }
255 
ConvertEnumTypeIR(const EnumTypeIR * enump)256 static JsonObject ConvertEnumTypeIR(const EnumTypeIR *enump) {
257   JsonObject enum_type;
258   AddAccess(enum_type, enump->GetAccess());
259   enum_type.Set("underlying_type", enump->GetUnderlyingType());
260   AddTypeInfo(enum_type, enump);
261   AddEnumFields(enum_type, enump);
262   AddAvailabilityAttrs(enum_type, enump);
263   return enum_type;
264 }
265 
ConvertGlobalVarIR(const GlobalVarIR * global_varp)266 static JsonObject ConvertGlobalVarIR(const GlobalVarIR *global_varp) {
267   JsonObject global_var;
268   // GlobalVarIR
269   global_var.Set("name", global_varp->GetName());
270   AddAccess(global_var, global_varp->GetAccess());
271   // LinkableMessageIR
272   global_var.Set("source_file", global_varp->GetSourceFile());
273   const std::string &linker_set_key = global_varp->GetLinkerSetKey();
274   global_var.Set("linker_set_key", linker_set_key);
275   // ReferencesOtherType
276   const std::string &referenced_type = global_varp->GetReferencedType();
277   if (linker_set_key != referenced_type) {
278     global_var.Set("referenced_type", referenced_type);
279   }
280   AddAvailabilityAttrs(global_var, global_varp);
281   return global_var;
282 }
283 
ConvertPointerTypeIR(const PointerTypeIR * pointerp)284 static JsonObject ConvertPointerTypeIR(const PointerTypeIR *pointerp) {
285   JsonObject pointer_type;
286   AddTypeInfo(pointer_type, pointerp);
287   return pointer_type;
288 }
289 
ConvertQualifiedTypeIR(const QualifiedTypeIR * qualtypep)290 static JsonObject ConvertQualifiedTypeIR(const QualifiedTypeIR *qualtypep) {
291   JsonObject qualified_type;
292   AddTypeInfo(qualified_type, qualtypep);
293   qualified_type.Set("is_const", qualtypep->IsConst());
294   qualified_type.Set("is_volatile", qualtypep->IsVolatile());
295   qualified_type.Set("is_restricted", qualtypep->IsRestricted());
296   return qualified_type;
297 }
298 
ConvertBuiltinTypeIR(const BuiltinTypeIR * builtin_typep)299 static JsonObject ConvertBuiltinTypeIR(const BuiltinTypeIR *builtin_typep) {
300   JsonObject builtin_type;
301   builtin_type.Set("is_unsigned", builtin_typep->IsUnsigned());
302   builtin_type.Set("is_integral", builtin_typep->IsIntegralType());
303   AddTypeInfo(builtin_type, builtin_typep);
304   return builtin_type;
305 }
306 
ConvertArrayTypeIR(const ArrayTypeIR * array_typep)307 static JsonObject ConvertArrayTypeIR(const ArrayTypeIR *array_typep) {
308   JsonObject array_type;
309   array_type.Set("is_of_unknown_bound", array_typep->IsOfUnknownBound());
310   AddTypeInfo(array_type, array_typep);
311   return array_type;
312 }
313 
ConvertLvalueReferenceTypeIR(const LvalueReferenceTypeIR * lvalue_reference_typep)314 static JsonObject ConvertLvalueReferenceTypeIR(
315     const LvalueReferenceTypeIR *lvalue_reference_typep) {
316   JsonObject lvalue_reference_type;
317   AddTypeInfo(lvalue_reference_type, lvalue_reference_typep);
318   return lvalue_reference_type;
319 }
320 
ConvertRvalueReferenceTypeIR(const RvalueReferenceTypeIR * rvalue_reference_typep)321 static JsonObject ConvertRvalueReferenceTypeIR(
322     const RvalueReferenceTypeIR *rvalue_reference_typep) {
323   JsonObject rvalue_reference_type;
324   AddTypeInfo(rvalue_reference_type, rvalue_reference_typep);
325   return rvalue_reference_type;
326 }
327 
AddLinkableMessageIR(const LinkableMessageIR * lm)328 bool JsonIRDumper::AddLinkableMessageIR(const LinkableMessageIR *lm) {
329   std::string key;
330   JsonObject converted;
331   // No RTTI
332   switch (lm->GetKind()) {
333   case RecordTypeKind:
334     key = "record_types";
335     converted = ConvertRecordTypeIR(static_cast<const RecordTypeIR *>(lm));
336     break;
337   case EnumTypeKind:
338     key = "enum_types";
339     converted = ConvertEnumTypeIR(static_cast<const EnumTypeIR *>(lm));
340     break;
341   case PointerTypeKind:
342     key = "pointer_types";
343     converted = ConvertPointerTypeIR(static_cast<const PointerTypeIR *>(lm));
344     break;
345   case QualifiedTypeKind:
346     key = "qualified_types";
347     converted =
348         ConvertQualifiedTypeIR(static_cast<const QualifiedTypeIR *>(lm));
349     break;
350   case ArrayTypeKind:
351     key = "array_types";
352     converted = ConvertArrayTypeIR(static_cast<const ArrayTypeIR *>(lm));
353     break;
354   case LvalueReferenceTypeKind:
355     key = "lvalue_reference_types";
356     converted = ConvertLvalueReferenceTypeIR(
357         static_cast<const LvalueReferenceTypeIR *>(lm));
358     break;
359   case RvalueReferenceTypeKind:
360     key = "rvalue_reference_types";
361     converted = ConvertRvalueReferenceTypeIR(
362         static_cast<const RvalueReferenceTypeIR *>(lm));
363     break;
364   case BuiltinTypeKind:
365     key = "builtin_types";
366     converted = ConvertBuiltinTypeIR(static_cast<const BuiltinTypeIR *>(lm));
367     break;
368   case FunctionTypeKind:
369     key = "function_types";
370     converted = ConvertFunctionTypeIR(static_cast<const FunctionTypeIR *>(lm));
371     break;
372   case GlobalVarKind:
373     key = "global_vars";
374     converted = ConvertGlobalVarIR(static_cast<const GlobalVarIR *>(lm));
375     break;
376   case FunctionKind:
377     key = "functions";
378     converted = ConvertFunctionIR(static_cast<const FunctionIR *>(lm));
379     break;
380   default:
381     return false;
382   }
383   translation_unit_[key].append(converted);
384   return true;
385 }
386 
AddElfSymbolMessageIR(const ElfSymbolIR * elf_symbol_ir)387 bool JsonIRDumper::AddElfSymbolMessageIR(const ElfSymbolIR *elf_symbol_ir) {
388   std::string key;
389   switch (elf_symbol_ir->GetKind()) {
390   case ElfSymbolIR::ElfFunctionKind:
391     key = "elf_functions";
392     break;
393   case ElfSymbolIR::ElfObjectKind:
394     key = "elf_objects";
395     break;
396   default:
397     return false;
398   }
399   JsonObject elf_symbol;
400   elf_symbol.Set("name", elf_symbol_ir->GetName());
401   AddElfSymbolBinding(elf_symbol, elf_symbol_ir->GetBinding());
402   translation_unit_[key].append(elf_symbol);
403   return true;
404 }
405 
DumpJson(const JsonObject & obj)406 static std::string DumpJson(const JsonObject &obj) {
407   Json::StreamWriterBuilder factory;
408   factory["indentation"] = " ";
409   return Json::writeString(factory, obj);
410 }
411 
WriteTailTrimmedLinesToFile(const std::string & path,const std::string & output_string)412 static bool WriteTailTrimmedLinesToFile(const std::string &path,
413                                         const std::string &output_string) {
414   std::ofstream output_file(path);
415   size_t line_start = 0;
416   while (line_start < output_string.size()) {
417     size_t trailing_space_start = line_start;
418     size_t index;
419     for (index = line_start;
420          index < output_string.size() && output_string[index] != '\n';
421          index++) {
422       if (output_string[index] != ' ') {
423         trailing_space_start = index + 1;
424       }
425     }
426     // Only write this line if this line contains non-whitespace characters.
427     if (trailing_space_start != line_start) {
428       if (output_file
429               .write(output_string.data() + line_start,
430                      trailing_space_start - line_start)
431               .fail()) {
432         return false;
433       }
434       if (output_file.write("\n", 1).fail()) {
435         return false;
436       }
437     }
438     line_start = index + 1;
439   }
440   return output_file.flush().good();
441 }
442 
Dump(const ModuleIR & module)443 bool JsonIRDumper::Dump(const ModuleIR &module) {
444   DumpModule(module);
445   std::string output_string = DumpJson(translation_unit_);
446   return WriteTailTrimmedLinesToFile(dump_path_, output_string);
447 }
448 
JsonIRDumper(const std::string & dump_path)449 JsonIRDumper::JsonIRDumper(const std::string &dump_path)
450     : IRDumper(dump_path), translation_unit_() {
451   const std::string keys[] = {
452     "record_types",
453     "enum_types",
454     "pointer_types",
455     "lvalue_reference_types",
456     "rvalue_reference_types",
457     "builtin_types",
458     "qualified_types",
459     "array_types",
460     "function_types",
461     "functions",
462     "global_vars",
463     "elf_functions",
464     "elf_objects",
465   };
466   for (auto key : keys) {
467     translation_unit_[key] = JsonArray();
468   }
469 }
470 
CreateJsonIRDumper(const std::string & dump_path)471 std::unique_ptr<IRDumper> CreateJsonIRDumper(const std::string &dump_path) {
472   return std::make_unique<JsonIRDumper>(dump_path);
473 }
474 
475 
476 }  // namespace repr
477 }  // header_checker
478