// 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_
#define IR_
#include <cassert>
#include <map>
#include <unordered_map>
#include <memory>
#include <list>
#include <regex>
#include <set>
#include <string>
#include <vector>
// Classes which act as middle-men between clang AST parsing routines and
// message format specific dumpers.
namespace abi_util {
template <typename T>
using AbiElementMap = std::map<std::string, T>;
template <typename T>
using AbiElementUnorderedMap = std::unordered_map<std::string, T>;
template <typename T>
using AbiElementList = std::list<T>;
enum TextFormatIR {
ProtobufTextFormat = 0,
};
enum CompatibilityStatusIR {
Compatible = 0,
UnreferencedChanges = 1,
Extension = 4,
Incompatible = 8,
ElfIncompatible = 16
};
static inline CompatibilityStatusIR operator|(CompatibilityStatusIR f,
CompatibilityStatusIR s) {
return static_cast<CompatibilityStatusIR>(
static_cast<std::underlying_type<CompatibilityStatusIR>::type>(f) |
static_cast<std::underlying_type<CompatibilityStatusIR>::type>(s));
}
static inline CompatibilityStatusIR operator&(
CompatibilityStatusIR f, CompatibilityStatusIR s) {
return static_cast<CompatibilityStatusIR>(
static_cast<std::underlying_type<CompatibilityStatusIR>::type>(f) &
static_cast<std::underlying_type<CompatibilityStatusIR>::type>(s));
}
enum AccessSpecifierIR {
PublicAccess = 1,
ProtectedAccess = 2,
PrivateAccess = 3
};
enum LinkableMessageKind {
RecordTypeKind,
EnumTypeKind,
PointerTypeKind,
QualifiedTypeKind,
ArrayTypeKind,
LvalueReferenceTypeKind,
RvalueReferenceTypeKind,
BuiltinTypeKind,
FunctionTypeKind,
FunctionKind,
GlobalVarKind
};
class LinkableMessageIR {
public:
const std::string &GetLinkerSetKey() const {
return linker_set_key_;
}
void SetSourceFile(const std::string &source_file) {
source_file_ = source_file;
}
void SetLinkerSetKey(const std::string &linker_set_key) {
linker_set_key_ = linker_set_key;
}
const std::string &GetSourceFile() const {
return source_file_;
}
virtual LinkableMessageKind GetKind() const = 0;
virtual ~LinkableMessageIR() { };
protected:
// The source file where this message comes from. This will be an empty string
// for built-in types.
std::string source_file_;
std::string linker_set_key_;
};
class ReferencesOtherType {
public:
void SetReferencedType(const std::string &referenced_type) {
referenced_type_ = referenced_type;
}
const std::string &GetReferencedType() const {
return referenced_type_;
}
ReferencesOtherType(const std::string &referenced_type)
: referenced_type_(referenced_type) { }
ReferencesOtherType(std::string &&referenced_type)
: referenced_type_(std::move(referenced_type)) { }
ReferencesOtherType() { }
protected:
std::string referenced_type_;
};
// TODO: Break this up into types with sizes and those without types ?
class TypeIR : public LinkableMessageIR , public ReferencesOtherType {
public:
void SetSelfType(const std::string &self_type) {
self_type_ = self_type;
}
const std::string &GetSelfType() const {
return self_type_;
}
void SetName(const std::string &name) {
name_ = name;
}
const std::string &GetName() const {
return name_;
}
void SetSize(uint64_t size) {
size_ = size;
}
uint64_t GetSize() const {
return size_;
}
void SetAlignment(uint32_t alignment) {
alignment_ = alignment;
}
uint32_t GetAlignment() const {
return alignment_;
}
virtual ~TypeIR() { }
protected:
std::string name_;
std::string self_type_;
uint64_t size_ = 0;
uint32_t alignment_ = 0;
};
class TagTypeIR {
public:
const std::string &GetUniqueId() const {
return unique_id_;
}
void SetUniqueId(const std::string &unique_id) {
unique_id_ = unique_id;
}
protected:
std::string unique_id_;
};
class VTableComponentIR {
public:
enum Kind {
VCallOffset = 0,
VBaseOffset = 1,
OffsetToTop = 2,
RTTI = 3,
FunctionPointer = 4,
CompleteDtorPointer = 5,
DeletingDtorPointer = 6,
UnusedFunctionPointer = 7
};
VTableComponentIR(const std::string &name, Kind kind, int64_t value)
: component_name_(name), kind_(kind), value_(value) { }
VTableComponentIR() { }
Kind GetKind() const {
return kind_;
}
int64_t GetValue() const {
return value_;
}
const std::string &GetName() const {
return component_name_;
}
protected:
std::string component_name_;
Kind kind_;
int64_t value_ = 0;
};
class VTableLayoutIR {
public:
void AddVTableComponent(VTableComponentIR &&vtable_component) {
vtable_components_.emplace_back(std::move(vtable_component));
}
const std::vector<VTableComponentIR> &GetVTableComponents() const {
return vtable_components_;
}
uint64_t GetVTableNumEntries() const {
return vtable_components_.size();
}
protected:
std::vector<VTableComponentIR> vtable_components_;
};
class CXXBaseSpecifierIR : public ReferencesOtherType {
public:
CXXBaseSpecifierIR(const std::string &type, bool is_virtual,
AccessSpecifierIR access) :
ReferencesOtherType(type), is_virtual_(is_virtual), access_(access) { }
CXXBaseSpecifierIR() { }
bool IsVirtual() const {
return is_virtual_;
}
AccessSpecifierIR GetAccess() const {
return access_;
}
protected:
bool is_virtual_ = false;
AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess;
};
class TemplateElementIR : public ReferencesOtherType {
public:
TemplateElementIR(std::string &&type)
: ReferencesOtherType(std::move(type)) { }
TemplateElementIR(const std::string &type)
: ReferencesOtherType(type) { }
TemplateElementIR() { }
};
class TemplateInfoIR {
public:
void AddTemplateElement(TemplateElementIR &&element) {
template_elements_.emplace_back(element);
}
const std::vector<TemplateElementIR> &GetTemplateElements() const {
return template_elements_;
}
std::vector<TemplateElementIR> &GetTemplateElements() {
return template_elements_;
}
protected:
std::vector<TemplateElementIR> template_elements_;
};
class TemplatedArtifactIR {
public:
void SetTemplateInfo(TemplateInfoIR &&template_info) {
template_info_ = std::move(template_info);
}
const std::vector<TemplateElementIR> &GetTemplateElements() const {
return template_info_.GetTemplateElements();
}
std::vector<TemplateElementIR> &GetTemplateElements() {
return template_info_.GetTemplateElements();
}
protected:
TemplateInfoIR template_info_;
};
class RecordFieldIR : public ReferencesOtherType {
public:
RecordFieldIR(const std::string &name, const std::string &type,
uint64_t offset, AccessSpecifierIR access)
: ReferencesOtherType(type), name_(name), offset_(offset),
access_(access) { }
RecordFieldIR() { }
const std::string &GetName() const {
return name_;
}
uint64_t GetOffset() const {
return offset_;
}
AccessSpecifierIR GetAccess() const {
return access_;
}
protected:
std::string name_;
uint64_t offset_ = 0;
AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess;
};
class RecordTypeIR: public TypeIR, public TemplatedArtifactIR,
public TagTypeIR {
public:
enum RecordKind {
struct_kind,
class_kind,
union_kind
};
void AddRecordField(RecordFieldIR &&field) {
fields_.emplace_back(std::move(field));
}
void SetRecordFields(std::vector<RecordFieldIR> &&fields) {
fields_ = std::move(fields);
}
void SetVTableLayout(VTableLayoutIR &&vtable_layout) {
vtable_layout_ = std::move(vtable_layout);
}
const VTableLayoutIR &GetVTableLayout() const {
return vtable_layout_;
}
void AddCXXBaseSpecifier(CXXBaseSpecifierIR &&base_specifier) {
bases_.emplace_back(std::move(base_specifier));
}
void SetCXXBaseSpecifiers(std::vector<CXXBaseSpecifierIR> &&bases) {
bases_ = std::move(bases);
}
const std::vector<CXXBaseSpecifierIR> &GetBases() const {
return bases_;
}
std::vector<CXXBaseSpecifierIR> &GetBases() {
return bases_;
}
void SetAccess(AccessSpecifierIR access) { access_ = access;}
AccessSpecifierIR GetAccess() const {
return access_;
}
const std::vector<RecordFieldIR> &GetFields() const {
return fields_;
}
std::vector<RecordFieldIR> &GetFields() {
return fields_;
}
LinkableMessageKind GetKind() const override {
return LinkableMessageKind::RecordTypeKind;
}
uint64_t GetVTableNumEntries() const {
return vtable_layout_.GetVTableNumEntries();
}
void SetRecordKind(RecordKind record_kind) {
record_kind_ = record_kind;
}
RecordKind GetRecordKind() const {
return record_kind_;
}
void SetAnonymity(bool is_anonymous) {
is_anonymous_ = is_anonymous;
}
bool IsAnonymous() const {
return is_anonymous_;
}
protected:
std::vector<RecordFieldIR> fields_;
VTableLayoutIR vtable_layout_;
std::vector<CXXBaseSpecifierIR> bases_;
AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess;
bool is_anonymous_ = false;
RecordKind record_kind_;
};
class EnumFieldIR {
public:
EnumFieldIR(const std::string &name, int value)
: name_(name), value_(value) { }
const std::string &GetName() const {
return name_;
}
int GetValue() const {
return value_;
}
protected:
std::string name_;
int value_ = 0;
};
class EnumTypeIR : public TypeIR, public TagTypeIR {
public:
// Add Methods to get information from the IR.
void AddEnumField(EnumFieldIR &&field) {
fields_.emplace_back(std::move(field));
}
void SetAccess(AccessSpecifierIR access) { access_ = access;}
LinkableMessageKind GetKind() const override {
return LinkableMessageKind::EnumTypeKind;
}
AccessSpecifierIR GetAccess() const {
return access_;
}
void SetUnderlyingType(std::string &&underlying_type) {
underlying_type_ = std::move(underlying_type);
}
void SetUnderlyingType(const std::string &underlying_type) {
underlying_type_ = underlying_type;
}
const std::string &GetUnderlyingType() const {
return underlying_type_;
}
void SetFields(std::vector<EnumFieldIR> &&fields) {
fields_ = std::move(fields);
}
const std::vector<EnumFieldIR> &GetFields() const {
return fields_;
}
protected:
std::vector<EnumFieldIR> fields_;
std::string underlying_type_;
AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess;
};
class ArrayTypeIR : public TypeIR {
public:
LinkableMessageKind GetKind() const override {
return LinkableMessageKind::ArrayTypeKind;
}
};
class PointerTypeIR : public TypeIR {
public:
LinkableMessageKind GetKind() const override {
return LinkableMessageKind::PointerTypeKind;
}
};
class BuiltinTypeIR : public TypeIR {
public:
void SetSignedness(bool is_unsigned) {
is_unsigned_ = is_unsigned;
}
bool IsUnsigned() const {
return is_unsigned_;
}
void SetIntegralType(bool is_integral_type) {
is_integral_type_ = is_integral_type;
}
bool IsIntegralType() const {
return is_integral_type_;
}
public:
LinkableMessageKind GetKind() const override {
return LinkableMessageKind::BuiltinTypeKind;
}
protected:
bool is_unsigned_ = false;
bool is_integral_type_ = false;
};
class LvalueReferenceTypeIR : public TypeIR {
public:
LinkableMessageKind GetKind() const override {
return LinkableMessageKind::LvalueReferenceTypeKind;
}
};
class RvalueReferenceTypeIR : public TypeIR {
public:
LinkableMessageKind GetKind() const override {
return LinkableMessageKind::RvalueReferenceTypeKind;
}
};
class QualifiedTypeIR : public TypeIR {
public:
void SetConstness(bool is_const) {
is_const_ = is_const;
}
bool IsConst() const {
return is_const_;
}
void SetRestrictedness(bool is_restricted) {
is_restricted_ = is_restricted;
}
bool IsRestricted() const {
return is_restricted_;
}
void SetVolatility(bool is_volatile) {
is_volatile_ = is_volatile;
}
bool IsVolatile() const {
return is_volatile_;
}
public:
LinkableMessageKind GetKind() const override {
return LinkableMessageKind::QualifiedTypeKind;
}
protected:
bool is_const_;
bool is_restricted_;
bool is_volatile_;
};
class GlobalVarIR: public LinkableMessageIR , public ReferencesOtherType {
public:
// Add Methods to get information from the IR.
void SetName(std::string &&name) {
name_ = std::move(name);
}
void SetName(const std::string &name) {
name_ = name;
}
const std::string &GetName() const {
return name_;
}
void SetAccess(AccessSpecifierIR access) {
access_ = access;
}
AccessSpecifierIR GetAccess() const {
return access_;
}
LinkableMessageKind GetKind() const override {
return LinkableMessageKind::GlobalVarKind;
}
protected:
std::string name_;
AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess;
};
class ParamIR : public ReferencesOtherType {
public:
ParamIR(const std::string &type, bool is_default, bool is_this_ptr) :
ReferencesOtherType(type) , is_default_(is_default),
is_this_ptr_(is_this_ptr) {}
bool GetIsDefault() const {
return is_default_;
}
bool GetIsThisPtr() const {
return is_this_ptr_;
}
protected:
bool is_default_ = false;
bool is_this_ptr_ = false;
};
class CFunctionLikeIR {
public:
void SetReturnType(const std::string &type) {
return_type_ = type;
}
const std::string &GetReturnType() const {
return return_type_;
}
void AddParameter(ParamIR &¶meter) {
parameters_.emplace_back(std::move(parameter));
}
const std::vector<ParamIR> &GetParameters() const {
return parameters_;
}
std::vector<ParamIR> &GetParameters() {
return parameters_;
}
protected:
std::string return_type_; // return type reference
std::vector<ParamIR> parameters_;
};
class FunctionTypeIR : public TypeIR, public CFunctionLikeIR {
public:
LinkableMessageKind GetKind() const override {
return LinkableMessageKind::FunctionTypeKind;
}
};
class FunctionIR : public LinkableMessageIR, public TemplatedArtifactIR,
public CFunctionLikeIR {
public:
void SetAccess(AccessSpecifierIR access) {
access_ = access;
}
AccessSpecifierIR GetAccess() const {
return access_;
}
LinkableMessageKind GetKind() const override {
return LinkableMessageKind::FunctionKind;
}
void SetName(const std::string &name) {
name_ = name;
}
const std::string &GetName() const {
return name_;
}
protected:
std::string linkage_name_;
std::string name_;
AccessSpecifierIR access_ = AccessSpecifierIR::PublicAccess;
};
class ElfSymbolIR {
public:
enum ElfSymbolKind {
ElfFunctionKind,
ElfObjectKind
};
const std::string GetName() const {
return name_;
}
ElfSymbolIR(const std::string &name) : name_(name) { }
virtual ElfSymbolKind GetKind() const = 0;
virtual ~ElfSymbolIR() { }
protected:
std::string name_;
};
class ElfFunctionIR : public ElfSymbolIR{
public:
ElfSymbolKind GetKind() const override {
return ElfFunctionKind;
}
ElfFunctionIR(const std::string &name) : ElfSymbolIR(name) { }
};
class ElfObjectIR : public ElfSymbolIR {
public:
ElfSymbolKind GetKind() const override {
return ElfObjectKind;
}
ElfObjectIR(const std::string &name) : ElfSymbolIR(name) { }
};
class IRDumper {
public:
IRDumper(const std::string &dump_path) : dump_path_(dump_path) { }
static std::unique_ptr<IRDumper> CreateIRDumper(
TextFormatIR text_format, const std::string &dump_path);
virtual bool AddLinkableMessageIR(const LinkableMessageIR *) = 0;
virtual bool AddElfSymbolMessageIR(const ElfSymbolIR *) = 0;
virtual bool Dump() = 0;
virtual ~IRDumper() {}
protected:
const std::string &dump_path_;
};
template <typename T>
inline std::string GetReferencedTypeMapKey(
T &element) {
return element.GetReferencedType();
}
template <>
inline std::string GetReferencedTypeMapKey<ArrayTypeIR>(
ArrayTypeIR &element) {
return element.GetReferencedType() + ":" + std::to_string(element.GetSize());
}
template <>
inline std::string GetReferencedTypeMapKey<BuiltinTypeIR>(
BuiltinTypeIR &element) {
return element.GetLinkerSetKey();
}
inline static std::string BoolToString(bool val) {
return val ? "true" : "false";
}
template <>
inline std::string GetReferencedTypeMapKey<QualifiedTypeIR>(
QualifiedTypeIR &element) {
return element.GetReferencedType() + BoolToString(element.IsRestricted()) +
BoolToString(element.IsVolatile()) + BoolToString(element.IsConst());
}
inline std::string GetODRListMapKey(const RecordTypeIR *record_type_ir) {
if (record_type_ir->IsAnonymous()) {
return record_type_ir->GetLinkerSetKey() + record_type_ir->GetUniqueId();
}
return record_type_ir->GetUniqueId() + record_type_ir->GetSourceFile();
}
inline std::string GetODRListMapKey(const EnumTypeIR *enum_type_ir) {
return enum_type_ir->GetUniqueId() + enum_type_ir->GetSourceFile();
}
inline std::string GetODRListMapKey(const FunctionTypeIR *function_type_ir) {
return function_type_ir->GetLinkerSetKey();
}
// The map that is being updated maps special_key -> Type / Function/ GlobVar
// This special key is needed to distinguish what is being referenced.
template <typename T>
typename AbiElementMap<T>::iterator AddToMapAndTypeGraph(
T &&element, AbiElementMap<T> *map_to_update,
AbiElementMap<const TypeIR *> *type_graph) {
auto it = map_to_update->emplace(GetReferencedTypeMapKey(element),
std::move(element));
type_graph->emplace(it.first->second.GetSelfType(), &(it.first->second));
return it.first;
}
class TextFormatToIRReader {
public:
struct MergeStatus {
// type_id_ always has the global_type_id corresponding to the type this
// MergeStatus corresponds to. For
// generic reference types (pointers, qual types, l(r)value references etc),
// this will be a proactively added type_id, which will be added to the
// parent type_graph if the we decide to add the referencing type to the
// parent post ODR checking.
bool was_newly_added_ = false;
std::string type_id_;
MergeStatus(bool was_newly_added, const std::string &type_id)
: was_newly_added_(was_newly_added), type_id_(type_id) { }
MergeStatus() { }
};
TextFormatToIRReader(const std::set<std::string> *exported_headers)
: exported_headers_(exported_headers) { }
const AbiElementMap<FunctionIR> &GetFunctions() const {
return functions_;
}
const AbiElementMap<GlobalVarIR> &GetGlobalVariables() const {
return global_variables_;
}
const AbiElementMap<RecordTypeIR> &GetRecordTypes() const {
return record_types_;
}
const AbiElementMap<FunctionTypeIR> &GetFunctionTypes() const {
return function_types_;
}
const AbiElementMap<EnumTypeIR> &GetEnumTypes() const {
return enum_types_;
}
const AbiElementMap<LvalueReferenceTypeIR> &
GetLvalueReferenceTypes() const {
return lvalue_reference_types_;
}
const AbiElementMap<RvalueReferenceTypeIR> &
GetRvalueReferenceTypes() const {
return rvalue_reference_types_;
}
const AbiElementMap<QualifiedTypeIR> &GetQualifiedTypes() const {
return qualified_types_;
}
const AbiElementMap<ArrayTypeIR> &GetArrayTypes() const {
return array_types_;
}
const AbiElementMap<PointerTypeIR> &GetPointerTypes() const {
return pointer_types_;
}
const AbiElementMap<BuiltinTypeIR> &GetBuiltinTypes() const {
return builtin_types_;
}
const AbiElementMap<ElfFunctionIR> &GetElfFunctions() const {
return elf_functions_;
}
const AbiElementMap<ElfObjectIR> &GetElfObjects() const {
return elf_objects_;
}
const AbiElementMap<const TypeIR *> &GetTypeGraph() const {
return type_graph_;
}
const AbiElementUnorderedMap<std::list<const TypeIR *>> &
GetODRListMap() const {
return odr_list_map_;
}
virtual bool ReadDump(const std::string &dump_file) = 0;
template <typename Iterator>
bool ReadDumps(Iterator begin, Iterator end) {
Iterator it = begin;
while(it != end) {
if (!ReadDump(*it)) {
return false;
}
++it;
}
return true;
}
virtual ~TextFormatToIRReader() { }
void Merge(TextFormatToIRReader &&addend) {
MergeElements(&functions_, std::move(addend.functions_));
MergeElements(&global_variables_, std::move(addend.global_variables_));
MergeElements(&record_types_, std::move(addend.record_types_));
MergeElements(&enum_types_, std::move(addend.enum_types_));
MergeElements(&pointer_types_, std::move(addend.pointer_types_));
MergeElements(&lvalue_reference_types_,
std::move(addend.lvalue_reference_types_));
MergeElements(&rvalue_reference_types_,
std::move(addend.rvalue_reference_types_));
MergeElements(&array_types_, std::move(addend.array_types_));
MergeElements(&builtin_types_, std::move(addend.builtin_types_));
MergeElements(&qualified_types_, std::move(addend.qualified_types_));
}
void AddToODRListMap(const std::string &key, const TypeIR *value);
template <typename T>
MergeStatus MergeReferencingTypeInternalAndUpdateParent(
const TextFormatToIRReader &addend, const T *addend_node,
AbiElementMap<MergeStatus> *local_to_global_type_id_map,
AbiElementMap<T> *parent_map, const std::string &updated_self_type_id);
MergeStatus DoesUDTypeODRViolationExist(
const TypeIR *ud_type, const TextFormatToIRReader &addend,
const std::string ud_type_unique_id,
AbiElementMap<MergeStatus> *local_to_global_type_id_map_);
MergeStatus MergeReferencingTypeInternal(
const TextFormatToIRReader &addend, ReferencesOtherType *references_type,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
MergeStatus MergeReferencingType(
const TextFormatToIRReader &addend, const TypeIR *addend_node,
AbiElementMap<MergeStatus> *local_to_global_type_id_map,
const std::string &updated_self_type_id);
MergeStatus MergeGenericReferringType(
const TextFormatToIRReader &addend, const TypeIR *addend_node,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
template <typename T>
std::pair<MergeStatus, typename AbiElementMap<T>::iterator>
UpdateUDTypeAccounting(
const T *addend_node, const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *local_to_global_type_id_map,
AbiElementMap<T> *specific_type_map);
MergeStatus MergeTypeInternal(
const TypeIR *addend_node, const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
void MergeCFunctionLikeDeps(
const TextFormatToIRReader &addend, CFunctionLikeIR *cfunction_like_ir,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
MergeStatus MergeFunctionType(
const FunctionTypeIR *addend_node, const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
MergeStatus MergeEnumType(
const EnumTypeIR *addend_node, const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
void MergeEnumDependencies(
const TextFormatToIRReader &addend, EnumTypeIR *added_node,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
MergeStatus MergeRecordAndDependencies(
const RecordTypeIR *addend_node, const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
void MergeRecordDependencies(
const TextFormatToIRReader &addend, RecordTypeIR *added_node,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
void MergeRecordFields(
const TextFormatToIRReader &addend, RecordTypeIR *added_node,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
void MergeRecordCXXBases(
const TextFormatToIRReader &addend, RecordTypeIR *added_node,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
void MergeRecordTemplateElements(
const TextFormatToIRReader &addend, RecordTypeIR *added_node,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
MergeStatus IsBuiltinTypeNodePresent(
const BuiltinTypeIR *builtin_type, const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
void MergeGlobalVariable(
const GlobalVarIR *addend_node, const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
void MergeGlobalVariables(
const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
void MergeFunctionDeps(
FunctionIR *added_node, const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
void MergeFunction(
const FunctionIR *addend_node, const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
void MergeGraphs(const TextFormatToIRReader &addend);
void UpdateTextFormatToIRReaderTypeGraph(
const TypeIR *addend_node, const std::string &added_type_id,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
MergeStatus IsTypeNodePresent(
const TypeIR *addend_node, const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
MergeStatus MergeType(const TypeIR *addend_type,
const TextFormatToIRReader &addend,
AbiElementMap<MergeStatus> *merged_types_cache);
std::string AllocateNewTypeId();
static std::unique_ptr<TextFormatToIRReader> CreateTextFormatToIRReader(
TextFormatIR text_format,
const std::set<std::string> *exported_headers = nullptr);
protected:
template <typename Augend, typename Addend>
inline void MergeElements(Augend *augend, Addend &&addend) {
augend->insert(std::make_move_iterator(addend.begin()),
std::make_move_iterator(addend.end()));
}
AbiElementList<RecordTypeIR> record_types_list_;
AbiElementMap<FunctionIR> functions_;
AbiElementMap<GlobalVarIR> global_variables_;
AbiElementMap<RecordTypeIR> record_types_;
AbiElementMap<FunctionTypeIR> function_types_;
AbiElementMap<EnumTypeIR> enum_types_;
// These maps which contain generic referring types as values are used while
// looking up whether in the parent graph, a particular reffering type refers
// to a certain type id. The mechanism is useful while trying to determine
// whether a generic referring type needs to be newly added to the parent
// graph or not.
AbiElementMap<PointerTypeIR> pointer_types_;
AbiElementMap<LvalueReferenceTypeIR> lvalue_reference_types_;
AbiElementMap<RvalueReferenceTypeIR> rvalue_reference_types_;
AbiElementMap<ArrayTypeIR> array_types_;
AbiElementMap<BuiltinTypeIR> builtin_types_;
AbiElementMap<QualifiedTypeIR> qualified_types_;
AbiElementMap<ElfFunctionIR> elf_functions_;
AbiElementMap<ElfObjectIR> elf_objects_;
// type-id -> LinkableMessageIR * map
AbiElementMap<const TypeIR *> type_graph_;
// maps unique_id + source_file -> const TypeIR *
AbiElementUnorderedMap<std::list<const TypeIR *>> odr_list_map_;
const std::set<std::string> *exported_headers_;
uint64_t max_type_id_ = 0;
};
class DiffMessageIR {
public:
enum DiffKind {
Extension, // Applicable for enums.
Added,
Removed,
Referenced,
Unreferenced
};
virtual LinkableMessageKind Kind() const = 0;
void SetName(const std::string &name) {
name_ = name;
}
const std::string &GetName() const {
return name_;
}
virtual ~DiffMessageIR() { }
protected:
std::string name_;
};
class AccessSpecifierDiffIR {
public:
AccessSpecifierDiffIR(AccessSpecifierIR old_access,
AccessSpecifierIR new_access)
: old_access_(old_access), new_access_(new_access) { }
protected:
AccessSpecifierIR old_access_;
AccessSpecifierIR new_access_;
};
class TypeDiffIR {
public:
TypeDiffIR(std::pair<uint64_t, uint64_t> &&sizes,
std::pair<uint32_t, uint32_t> &&alignment)
: sizes_(std::move(sizes)), alignments_(std::move(alignment)) { }
const std::pair<uint64_t, uint64_t> &GetSizes() const {
return sizes_;
}
const std::pair<uint32_t, uint32_t> &GetAlignments() const {
return alignments_;
}
protected:
std::pair<uint64_t, uint64_t> sizes_;
std::pair<uint32_t, uint32_t> alignments_;
};
class VTableLayoutDiffIR {
public:
VTableLayoutDiffIR(const VTableLayoutIR &old_layout,
const VTableLayoutIR &new_layout)
: old_layout_(old_layout), new_layout_(new_layout) { }
const VTableLayoutIR &GetOldVTable() const {
return old_layout_;
}
const VTableLayoutIR &GetNewVTable() const {
return new_layout_;
}
protected:
const VTableLayoutIR &old_layout_;
const VTableLayoutIR &new_layout_;
};
class RecordFieldDiffIR {
public:
RecordFieldDiffIR(const RecordFieldIR *old_field,
const RecordFieldIR *new_field)
: old_field_(old_field), new_field_(new_field) { }
const RecordFieldIR *GetOldField() const {
return old_field_;
}
const RecordFieldIR *GetNewField() const {
return new_field_;
}
const RecordFieldIR *old_field_;
const RecordFieldIR *new_field_;
};
class CXXBaseSpecifierDiffIR {
public:
CXXBaseSpecifierDiffIR(
const std::vector<CXXBaseSpecifierIR> &old_base_specifiers,
const std::vector<CXXBaseSpecifierIR> &new_base_specifiers)
: old_base_specifiers_(old_base_specifiers),
new_base_specifiers_(new_base_specifiers) { }
const std::vector<CXXBaseSpecifierIR> &GetOldBases() const {
return old_base_specifiers_;
}
const std::vector<CXXBaseSpecifierIR> &GetNewBases() const {
return new_base_specifiers_;
}
protected:
const std::vector<CXXBaseSpecifierIR> &old_base_specifiers_;
const std::vector<CXXBaseSpecifierIR> &new_base_specifiers_;
};
class RecordTypeDiffIR : public DiffMessageIR {
public:
LinkableMessageKind Kind() const override {
return LinkableMessageKind::RecordTypeKind;
}
void SetFieldDiffs(std::vector<RecordFieldDiffIR> &&field_diffs) {
field_diffs_ = std::move(field_diffs);
}
const std::vector<RecordFieldDiffIR> &GetFieldDiffs() const {
return field_diffs_;
}
void SetFieldsRemoved(std::vector<const RecordFieldIR *> &&fields_removed) {
fields_removed_ = std::move(fields_removed);
}
void SetFieldsAdded(std::vector<const RecordFieldIR *> &&fields_added) {
fields_added_ = std::move(fields_added);
}
const std::vector<const RecordFieldIR *> &GetFieldsRemoved() const {
return fields_removed_;
}
const std::vector<const RecordFieldIR *> &GetFieldsAdded() const {
return fields_added_;
}
void SetVTableLayoutDiff(std::unique_ptr<VTableLayoutDiffIR> &&vtable_diffs) {
vtable_diffs_ = std::move(vtable_diffs);
}
void SetTypeDiff(std::unique_ptr<TypeDiffIR> &&type_diff) {
type_diff_ = std::move(type_diff);
}
void SetAccessDiff(std::unique_ptr<AccessSpecifierDiffIR> &&access_diff) {
access_diff_ = std::move(access_diff);
}
void SetBaseSpecifierDiffs(
std::unique_ptr<CXXBaseSpecifierDiffIR> &&base_diffs) {
base_specifier_diffs_ = std::move(base_diffs);
}
bool DiffExists() const {
return (type_diff_ != nullptr) || (vtable_diffs_ != nullptr) ||
(fields_removed_.size() != 0) || (field_diffs_.size() != 0) ||
(access_diff_ != nullptr) || (base_specifier_diffs_ != nullptr);
}
const TypeDiffIR *GetTypeDiff() const {
return type_diff_.get();
}
const VTableLayoutDiffIR *GetVTableLayoutDiff() const {
return vtable_diffs_.get();
}
const CXXBaseSpecifierDiffIR *GetBaseSpecifiers() const {
return base_specifier_diffs_.get();
}
protected:
// optional implemented with vector / std::unique_ptr.
std::unique_ptr<TypeDiffIR> type_diff_;
std::unique_ptr<VTableLayoutDiffIR> vtable_diffs_;
std::vector<RecordFieldDiffIR> field_diffs_;
std::vector<const RecordFieldIR *> fields_removed_;
std::vector<const RecordFieldIR *> fields_added_;
std::unique_ptr<AccessSpecifierDiffIR> access_diff_;
std::unique_ptr<CXXBaseSpecifierDiffIR> base_specifier_diffs_;
// Template Diffs are not needed since they will show up in the linker set
// key.
};
class EnumFieldDiffIR {
public:
EnumFieldDiffIR(const EnumFieldIR *old_field, const EnumFieldIR *new_field)
: old_field_(old_field), new_field_(new_field) { }
const EnumFieldIR *GetOldField() const {
return old_field_;
}
const EnumFieldIR *GetNewField() const {
return new_field_;
}
protected:
const EnumFieldIR *old_field_;
const EnumFieldIR *new_field_;
};
class EnumTypeDiffIR : public DiffMessageIR {
public:
void SetFieldsRemoved(std::vector<const EnumFieldIR *> &&fields_removed) {
fields_removed_ = std::move(fields_removed);
}
const std::vector<const EnumFieldIR *> &GetFieldsRemoved() const {
return fields_removed_;
}
void SetFieldsAdded(std::vector<const EnumFieldIR *> &&fields_added) {
fields_added_ = std::move(fields_added);
}
const std::vector<const EnumFieldIR *> &GetFieldsAdded() const {
return fields_added_;
}
void SetFieldsDiff(std::vector<EnumFieldDiffIR> &&fields_diff) {
fields_diff_ = std::move(fields_diff);
}
const std::vector<EnumFieldDiffIR> &GetFieldsDiff() const {
return fields_diff_;
}
void SetUnderlyingTypeDiff(
std::unique_ptr<std::pair<std::string, std::string>> &&utype_diff) {
underlying_type_diff_ = std::move(utype_diff);
}
const std::pair<std::string, std::string> *GetUnderlyingTypeDiff() const {
return underlying_type_diff_.get();
}
bool IsExtended() const {
if (fields_removed_.size() == 0 && fields_diff_.size() == 0 &&
fields_added_.size() != 0) {
return true;
}
return false;
}
bool IsIncompatible() const {
if (fields_removed_.size() != 0 || fields_diff_.size() != 0) {
return true;
}
return false;
}
LinkableMessageKind Kind() const override {
return LinkableMessageKind::EnumTypeKind;
}
protected:
// The underlying type can only be integral, so we just need to check for
// referenced type.
std::unique_ptr<std::pair<std::string, std::string>> underlying_type_diff_;
std::vector<const EnumFieldIR *> fields_removed_;
std::vector<const EnumFieldIR *> fields_added_;
std::vector<EnumFieldDiffIR> fields_diff_;
// Modifiable to allow implicit construction.
std::string name_;
};
class GlobalVarDiffIR : public DiffMessageIR {
public:
LinkableMessageKind Kind() const override {
return LinkableMessageKind::GlobalVarKind;
}
GlobalVarDiffIR(const GlobalVarIR *old_global_var,
const GlobalVarIR *new_global_var)
: old_global_var_(old_global_var), new_global_var_(new_global_var) { }
const GlobalVarIR *GetOldGlobalVar() const {
return old_global_var_;
}
const GlobalVarIR *GetNewGlobalVar() const {
return new_global_var_;
}
protected:
const GlobalVarIR *old_global_var_;
const GlobalVarIR *new_global_var_;
};
class FunctionDiffIR : public DiffMessageIR {
public:
LinkableMessageKind Kind() const override {
return LinkableMessageKind::FunctionKind;
}
FunctionDiffIR(const FunctionIR *old_function,
const FunctionIR *new_function)
: old_function_(old_function), new_function_(new_function) { }
const FunctionIR *GetOldFunction() const {
return old_function_;
}
const FunctionIR *GetNewFunction() const {
return new_function_;
}
protected:
const FunctionIR *old_function_;
const FunctionIR *new_function_;
};
class IRDiffDumper {
public:
typedef DiffMessageIR::DiffKind DiffKind;
IRDiffDumper(const std::string &dump_path) : dump_path_(dump_path) { }
virtual bool AddDiffMessageIR(const DiffMessageIR *,
const std::string &type_stack,
DiffKind diff_kind) = 0;
virtual bool AddLinkableMessageIR(const LinkableMessageIR *,
DiffKind diff_kind) = 0;
virtual bool AddElfSymbolMessageIR(const ElfSymbolIR *,
DiffKind diff_kind) = 0;
virtual void AddLibNameIR(const std::string &name) = 0;
virtual void AddArchIR(const std::string &arch) = 0;
virtual void AddCompatibilityStatusIR(CompatibilityStatusIR status) = 0;
virtual bool Dump() = 0;
virtual CompatibilityStatusIR GetCompatibilityStatusIR() = 0;
virtual ~IRDiffDumper() {}
static std::unique_ptr<IRDiffDumper> CreateIRDiffDumper(
TextFormatIR, const std::string &dump_path);
protected:
const std::string &dump_path_;
};
} // namespace abi_util
#endif // IR_