blob: 585001eb0ccc9c4bf1173dd96f2ec3d82bc1c31a [file] [log] [blame]
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef HEADER_CHECKER_PROTOBUF_CONVERTER_H_
#define HEADER_CHECKER_PROTOBUF_CONVERTER_H_
#include "repr/ir_diff_representation.h"
#include "repr/ir_representation.h"
#include "repr/protobuf/abi_diff.h"
#include "repr/protobuf/abi_dump.h"
#include <llvm/Support/raw_ostream.h>
namespace header_checker {
namespace repr {
inline abi_diff::CompatibilityStatus CompatibilityStatusIRToProtobuf(
CompatibilityStatusIR status) {
switch (status) {
case CompatibilityStatusIR::Incompatible:
return abi_diff::CompatibilityStatus::INCOMPATIBLE;
case CompatibilityStatusIR::Extension:
return abi_diff::CompatibilityStatus::EXTENSION;
default:
break;
}
return abi_diff::CompatibilityStatus::COMPATIBLE;
}
inline abi_dump::ElfSymbolBinding ElfSymbolBindingIRToProtobuf(
ElfSymbolIR::ElfSymbolBinding binding) {
switch (binding) {
case ElfSymbolIR::ElfSymbolBinding::Global:
return abi_dump::ElfSymbolBinding::Global;
case ElfSymbolIR::ElfSymbolBinding::Weak:
return abi_dump::ElfSymbolBinding::Weak;
}
// We skip symbols of all other Bindings
// TODO: Add all bindings, don't leave out info
assert(0);
}
inline ElfSymbolIR::ElfSymbolBinding ElfSymbolBindingProtobufToIR(
abi_dump::ElfSymbolBinding binding) {
switch (binding) {
case abi_dump::ElfSymbolBinding::Global:
return ElfSymbolIR::ElfSymbolBinding::Global;
case abi_dump::ElfSymbolBinding::Weak:
return ElfSymbolIR::ElfSymbolBinding::Weak;
}
// We skip symbols of all other Bindings
assert(0);
}
inline abi_dump::AccessSpecifier AccessIRToProtobuf(AccessSpecifierIR access) {
switch (access) {
case AccessSpecifierIR::ProtectedAccess:
return abi_dump::AccessSpecifier::protected_access;
case AccessSpecifierIR::PrivateAccess:
return abi_dump::AccessSpecifier::private_access;
default:
return abi_dump::AccessSpecifier::public_access;
}
return abi_dump::AccessSpecifier::public_access;
}
inline AccessSpecifierIR AccessProtobufToIR(
abi_dump::AccessSpecifier access) {
switch (access) {
case abi_dump::AccessSpecifier::protected_access:
return AccessSpecifierIR::ProtectedAccess;
case abi_dump::AccessSpecifier::private_access:
return AccessSpecifierIR::PrivateAccess;
default:
return AccessSpecifierIR::PublicAccess;
}
return AccessSpecifierIR::PublicAccess;
}
inline abi_dump::RecordKind RecordKindIRToProtobuf(
RecordTypeIR::RecordKind kind) {
switch (kind) {
case RecordTypeIR::RecordKind::struct_kind:
return abi_dump::RecordKind::struct_kind;
case RecordTypeIR::RecordKind::class_kind:
return abi_dump::RecordKind::class_kind;
case RecordTypeIR::RecordKind::union_kind:
return abi_dump::RecordKind::union_kind;
default:
return abi_dump::RecordKind::struct_kind;
}
// Should not be reached
assert(false);
}
inline RecordTypeIR::RecordKind RecordKindProtobufToIR(
abi_dump::RecordKind kind) {
switch (kind) {
case abi_dump::RecordKind::struct_kind:
return RecordTypeIR::struct_kind;
case abi_dump::RecordKind::class_kind:
return RecordTypeIR::class_kind;
case abi_dump::RecordKind::union_kind:
return RecordTypeIR::union_kind;
default:
return RecordTypeIR::struct_kind;
}
// Should not be reached
assert(false);
}
inline abi_dump::VTableComponent::Kind VTableComponentKindIRToProtobuf(
VTableComponentIR::Kind kind) {
switch (kind) {
case VTableComponentIR::Kind::VCallOffset:
return abi_dump::VTableComponent_Kind_VCallOffset;
case VTableComponentIR::Kind::VBaseOffset:
return abi_dump::VTableComponent_Kind_VBaseOffset;
case VTableComponentIR::Kind::OffsetToTop:
return abi_dump::VTableComponent_Kind_OffsetToTop;
case VTableComponentIR::Kind::RTTI:
return abi_dump::VTableComponent_Kind_RTTI;
case VTableComponentIR::Kind::FunctionPointer:
return abi_dump::VTableComponent_Kind_FunctionPointer;
case VTableComponentIR::Kind::CompleteDtorPointer:
return abi_dump::VTableComponent_Kind_CompleteDtorPointer;
case VTableComponentIR::Kind::DeletingDtorPointer:
return abi_dump::VTableComponent_Kind_DeletingDtorPointer;
default:
return abi_dump::VTableComponent_Kind_UnusedFunctionPointer;
}
// Should not be reached
assert(false);
}
inline VTableComponentIR::Kind VTableComponentKindProtobufToIR(
abi_dump::VTableComponent_Kind kind) {
switch (kind) {
case abi_dump::VTableComponent_Kind_VCallOffset:
return VTableComponentIR::Kind::VCallOffset;
case abi_dump::VTableComponent_Kind_VBaseOffset:
return VTableComponentIR::Kind::VBaseOffset;
case abi_dump::VTableComponent_Kind_OffsetToTop:
return VTableComponentIR::Kind::OffsetToTop;
case abi_dump::VTableComponent_Kind_RTTI:
return VTableComponentIR::Kind::RTTI;
case abi_dump::VTableComponent_Kind_FunctionPointer:
return VTableComponentIR::Kind::FunctionPointer;
case abi_dump::VTableComponent_Kind_CompleteDtorPointer:
return VTableComponentIR::Kind::CompleteDtorPointer;
case abi_dump::VTableComponent_Kind_DeletingDtorPointer:
return VTableComponentIR::Kind::DeletingDtorPointer;
default:
return VTableComponentIR::Kind::UnusedFunctionPointer;
}
// Should not be reached
assert(false);
}
class IRToProtobufConverter {
private:
static bool AddTemplateInformation(
abi_dump::TemplateInfo *ti, const TemplatedArtifactIR *ta);
static bool AddTypeInfo(
abi_dump::BasicNamedAndTypedDecl *type_info, const TypeIR *typep);
static bool AddRecordFields(
abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
static bool AddBaseSpecifiers(
abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
static bool AddVTableLayout(
abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
static bool AddEnumFields(abi_dump::EnumType *enum_protobuf,
const EnumTypeIR *enum_ir);
public:
static abi_dump::EnumType ConvertEnumTypeIR(const EnumTypeIR *enump);
static abi_dump::RecordType ConvertRecordTypeIR(const RecordTypeIR *recordp);
static abi_dump::FunctionType ConvertFunctionTypeIR (
const FunctionTypeIR *function_typep);
template <typename CFunctionLikeMessage>
static bool AddFunctionParametersAndSetReturnType(
CFunctionLikeMessage *function_like_protobuf,
const CFunctionLikeIR *cfunction_like_ir);
template <typename CFunctionLikeMessage>
static bool AddFunctionParameters(CFunctionLikeMessage *function_protobuf,
const CFunctionLikeIR *cfunction_like_ir);
static abi_dump::FunctionDecl ConvertFunctionIR(const FunctionIR *functionp);
static abi_dump::GlobalVarDecl ConvertGlobalVarIR(
const GlobalVarIR *global_varp);
static abi_dump::PointerType ConvertPointerTypeIR(
const PointerTypeIR *pointerp);
static abi_dump::QualifiedType ConvertQualifiedTypeIR(
const QualifiedTypeIR *qualtypep);
static abi_dump::BuiltinType ConvertBuiltinTypeIR(
const BuiltinTypeIR *builtin_typep);
static abi_dump::ArrayType ConvertArrayTypeIR(
const ArrayTypeIR *array_typep);
static abi_dump::LvalueReferenceType ConvertLvalueReferenceTypeIR(
const LvalueReferenceTypeIR *lvalue_reference_typep);
static abi_dump::RvalueReferenceType ConvertRvalueReferenceTypeIR(
const RvalueReferenceTypeIR *rvalue_reference_typep);
static abi_dump::ElfFunction ConvertElfFunctionIR(
const ElfFunctionIR *elf_function_ir);
static abi_dump::ElfObject ConvertElfObjectIR(
const ElfObjectIR *elf_object_ir);
};
class IRDiffToProtobufConverter {
private:
static bool AddTypeInfoDiff(
abi_diff::TypeInfoDiff *type_info_diff_protobuf,
const TypeDiffIR *type_diff_ir);
static bool AddVTableLayoutDiff(
abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf,
const VTableLayoutDiffIR *vtable_layout_diff_ir);
static bool AddBaseSpecifierDiffs(
abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf,
const CXXBaseSpecifierDiffIR *base_specifier_diff_ir);
static bool AddRecordFields(
abi_diff::RecordTypeDiff *record_diff_protobuf,
const std::vector<const RecordFieldIR *> &record_fields_removed_ir,
bool removed);
static bool AddRecordFieldDiffs(
abi_diff::RecordTypeDiff *record_diff_protobuf,
const std::vector<RecordFieldDiffIR> &record_field_diff_ir);
static bool AddEnumUnderlyingTypeDiff(
abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf,
const std::pair<std::string, std::string> *underlying_type_diff_ir);
public:
static abi_diff::RecordTypeDiff ConvertRecordTypeDiffIR(
const RecordTypeDiffIR *record_type_diffp);
static abi_diff::EnumTypeDiff ConvertEnumTypeDiffIR(
const EnumTypeDiffIR *enum_type_diffp);
static abi_diff::FunctionDeclDiff ConvertFunctionDiffIR(
const FunctionDiffIR *function_diffp);
static abi_diff::GlobalVarDeclDiff ConvertGlobalVarDiffIR(
const GlobalVarDiffIR *global_var_diffp);
};
inline void SetIRToProtobufRecordField(
abi_dump::RecordFieldDecl *record_field_protobuf,
const RecordFieldIR *record_field_ir) {
record_field_protobuf->set_field_name(record_field_ir->GetName());
record_field_protobuf->set_referenced_type(
record_field_ir->GetReferencedType());
record_field_protobuf->set_access(
AccessIRToProtobuf(record_field_ir->GetAccess()));
record_field_protobuf->set_field_offset(record_field_ir->GetOffset());
}
inline bool SetIRToProtobufBaseSpecifier(
abi_dump::CXXBaseSpecifier *base_specifier_protobuf,
const CXXBaseSpecifierIR &base_specifier_ir) {
if (!base_specifier_protobuf) {
llvm::errs() << "Protobuf base specifier not valid\n";
return false;
}
base_specifier_protobuf->set_referenced_type(
base_specifier_ir.GetReferencedType());
base_specifier_protobuf->set_is_virtual(
base_specifier_ir.IsVirtual());
base_specifier_protobuf->set_access(
AccessIRToProtobuf(base_specifier_ir.GetAccess()));
return true;
}
inline bool SetIRToProtobufVTableLayout(
abi_dump::VTableLayout *vtable_layout_protobuf,
const VTableLayoutIR &vtable_layout_ir) {
if (vtable_layout_protobuf == nullptr) {
llvm::errs() << "vtable layout protobuf not valid\n";
return false;
}
for (auto &&vtable_component_ir : vtable_layout_ir.GetVTableComponents()) {
abi_dump::VTableComponent *added_vtable_component =
vtable_layout_protobuf->add_vtable_components();
if (!added_vtable_component) {
llvm::errs() << "Couldn't add vtable component\n";
return false;
}
added_vtable_component->set_kind(
VTableComponentKindIRToProtobuf(vtable_component_ir.GetKind()));
added_vtable_component->set_component_value(vtable_component_ir.GetValue());
added_vtable_component->set_mangled_component_name(
vtable_component_ir.GetName());
added_vtable_component->set_is_pure(vtable_component_ir.GetIsPure());
}
return true;
}
inline bool SetIRToProtobufEnumField(
abi_dump::EnumFieldDecl *enum_field_protobuf,
const EnumFieldIR *enum_field_ir) {
if (enum_field_protobuf == nullptr) {
return true;
}
enum_field_protobuf->set_name(enum_field_ir->GetName());
// The "enum_field_value" in the .proto is a signed 64-bit integer. An
// unsigned integer >= (1 << 63) is represented with a negative integer in the
// dump file. Despite the wrong representation, the diff result isn't affected
// because every integer has a unique representation.
enum_field_protobuf->set_enum_field_value(enum_field_ir->GetSignedValue());
return true;
}
} // namespace repr
} // namespace header_checker
#endif // HEADER_CHECKER_PROTOBUF_CONVERTER_H_