// Copyright (C) 2017 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 IR_PROTOBUF_
#define IR_PROTOBUF_
#include <ir_representation.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#pragma clang diagnostic ignored "-Wnested-anon-types"
#include "proto/abi_dump.pb.h"
#include "proto/abi_diff.pb.h"
#pragma clang diagnostic pop
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
// Classes which act as middle-men between clang AST parsing routines and
// message format specific dumpers.
namespace abi_util {
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::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 abi_util::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 AddTagTypeInfo(abi_dump::TagType *tag_type_protobuf,
const TagTypeIR *tag_type_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);
};
class ProtobufIRDumper : public IRDumper, public IRToProtobufConverter {
private:
// Types
bool AddRecordTypeIR(const RecordTypeIR *);
bool AddEnumTypeIR(const EnumTypeIR *);
bool AddPointerTypeIR(const PointerTypeIR *);
bool AddQualifiedTypeIR(const QualifiedTypeIR *);
bool AddLvalueReferenceTypeIR(const LvalueReferenceTypeIR *);
bool AddRvalueReferenceTypeIR(const RvalueReferenceTypeIR *);
bool AddArrayTypeIR(const ArrayTypeIR *);
bool AddBuiltinTypeIR(const BuiltinTypeIR *);
bool AddFunctionTypeIR(const FunctionTypeIR *function_typep);
// Functions and global variables.
bool AddFunctionIR(const FunctionIR *);
bool AddGlobalVarIR(const GlobalVarIR *);
bool AddElfFunctionIR(const ElfFunctionIR *);
bool AddElfObjectIR(const ElfObjectIR *);
public:
ProtobufIRDumper(const std::string &dump_path)
: IRDumper(dump_path), tu_ptr_(new abi_dump::TranslationUnit()) { }
bool AddLinkableMessageIR(const LinkableMessageIR *) override;
bool AddElfSymbolMessageIR(const ElfSymbolIR *) override;
bool Dump() override;
~ProtobufIRDumper() override { }
private:
std::unique_ptr<abi_dump::TranslationUnit> tu_ptr_;
};
class ProtobufTextFormatToIRReader : public TextFormatToIRReader {
public:
ProtobufTextFormatToIRReader(const std::set<std::string> *exported_headers)
: TextFormatToIRReader(exported_headers) { }
bool ReadDump(const std::string &dump_file) override;
private:
void ReadFunctions(const abi_dump::TranslationUnit &tu);
void ReadGlobalVariables(const abi_dump::TranslationUnit &tu);
void ReadEnumTypes(const abi_dump::TranslationUnit &tu);
void ReadRecordTypes(const abi_dump::TranslationUnit &tu);
void ReadFunctionTypes(const abi_dump::TranslationUnit &tu);
void ReadPointerTypes(const abi_dump::TranslationUnit &tu);
void ReadBuiltinTypes(const abi_dump::TranslationUnit &tu);
void ReadQualifiedTypes(const abi_dump::TranslationUnit &tu);
void ReadArrayTypes(const abi_dump::TranslationUnit &tu);
void ReadLvalueReferenceTypes(const abi_dump::TranslationUnit &tu);
void ReadRvalueReferenceTypes(const abi_dump::TranslationUnit &tu);
void ReadElfFunctions (const abi_dump::TranslationUnit &tu);
void ReadElfObjects (const abi_dump::TranslationUnit &tu);
void ReadTypeInfo(const abi_dump::BasicNamedAndTypedDecl &type_info,
TypeIR *typep);
FunctionIR FunctionProtobufToIR(const abi_dump::FunctionDecl &);
FunctionTypeIR FunctionTypeProtobufToIR(
const abi_dump::FunctionType &function_type_protobuf);
RecordTypeIR RecordTypeProtobufToIR(
const abi_dump::RecordType &record_type_protobuf);
std::vector<RecordFieldIR> RecordFieldsProtobufToIR(
const google::protobuf::RepeatedPtrField<abi_dump::RecordFieldDecl> &rfp);
std::vector<CXXBaseSpecifierIR> RecordCXXBaseSpecifiersProtobufToIR(
const google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> &rbs);
std::vector<EnumFieldIR> EnumFieldsProtobufToIR(
const google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> &efp);
EnumTypeIR EnumTypeProtobufToIR(
const abi_dump::EnumType &enum_type_protobuf);
VTableLayoutIR VTableLayoutProtobufToIR(
const abi_dump::VTableLayout &vtable_layout_protobuf);
TemplateInfoIR TemplateInfoProtobufToIR(
const abi_dump::TemplateInfo &template_info_protobuf);
};
class ProtobufIRDiffDumper : public IRDiffDumper {
public:
ProtobufIRDiffDumper(const std::string &dump_path)
: IRDiffDumper(dump_path),
diff_tu_(new abi_diff::TranslationUnitDiff()) { }
bool AddDiffMessageIR(const DiffMessageIR *, const std::string &type_stack,
DiffKind diff_kind) override;
bool AddLinkableMessageIR(const LinkableMessageIR *,
DiffKind diff_kind) override;
bool AddElfSymbolMessageIR(const ElfSymbolIR *, DiffKind diff_kind) override;
void AddLibNameIR(const std::string &name) override;
void AddArchIR(const std::string &arch) override;
void AddCompatibilityStatusIR(CompatibilityStatusIR status) override;
bool Dump() override;
CompatibilityStatusIR GetCompatibilityStatusIR() override;
~ProtobufIRDiffDumper() override { }
private:
// User defined types.
bool AddRecordTypeDiffIR(const RecordTypeDiffIR *,
const std::string &type_stack, DiffKind diff_kind);
bool AddEnumTypeDiffIR(const EnumTypeDiffIR *,
const std::string &type_stack, DiffKind diff_kind);
// Functions and global variables.
bool AddFunctionDiffIR(const FunctionDiffIR *,
const std::string &type_stack, DiffKind diff_kind);
bool AddGlobalVarDiffIR(const GlobalVarDiffIR *,
const std::string &type_stack, DiffKind diff_kind);
bool AddLoneRecordTypeDiffIR(const RecordTypeIR *, DiffKind diff_kind);
bool AddLoneEnumTypeDiffIR(const EnumTypeIR *, DiffKind diff_kind);
// Functions and global variables.
bool AddLoneFunctionDiffIR(const FunctionIR *, DiffKind diff_kind);
bool AddLoneGlobalVarDiffIR(const GlobalVarIR *, DiffKind diff_kind);
bool AddElfObjectIR(const ElfObjectIR *elf_object_ir, DiffKind diff_kind);
bool AddElfFunctionIR(const ElfFunctionIR *elf_function_ir,
DiffKind diff_kind);
protected:
std::unique_ptr<abi_diff::TranslationUnitDiff> diff_tu_;
};
} // abi_util
#endif // IR_PROTOBUF_