Merge "Added More Abi information." am: 1345214bfc
am: 1b856be6a0
Change-Id: I8611cadd6ee393b85d25c14dc346e9dbbff3e3d0
This commit is contained in:
@@ -26,6 +26,7 @@ cc_defaults {
|
||||
"-Werror",
|
||||
"-std=c++11",
|
||||
"-DGOOGLE_PROTOBUF_NO_RTTI",
|
||||
"-UNDEBUG"
|
||||
],
|
||||
|
||||
target: {
|
||||
|
||||
@@ -45,95 +45,76 @@ Status HeaderAbiDiff::GenerateCompatibilityReport() {
|
||||
|
||||
Status HeaderAbiDiff::CompareTUs(const abi_dump::TranslationUnit &old_tu,
|
||||
const abi_dump::TranslationUnit &new_tu) {
|
||||
abi_diff::TranslationUnitDiff diff_tu;
|
||||
Status record_Status = CollectRecords(&diff_tu, old_tu, new_tu);
|
||||
Status function_Status = CollectFunctions(&diff_tu, old_tu, new_tu);
|
||||
Status enum_Status = CollectEnums(&diff_tu, old_tu, new_tu);
|
||||
std::unique_ptr<abi_diff::TranslationUnitDiff> diff_tu(
|
||||
new abi_diff::TranslationUnitDiff);
|
||||
|
||||
Status combined_Status = record_Status | function_Status | enum_Status;
|
||||
Status record_status = Collect<abi_dump::RecordDecl>(
|
||||
diff_tu->mutable_records_added(), diff_tu->mutable_records_removed(),
|
||||
diff_tu->mutable_records_diff(), old_tu.records(), new_tu.records());
|
||||
|
||||
Status function_status = Collect<abi_dump::FunctionDecl>(
|
||||
diff_tu->mutable_functions_added(), diff_tu->mutable_functions_removed(),
|
||||
diff_tu->mutable_functions_diff(), old_tu.functions(),
|
||||
new_tu.functions());
|
||||
|
||||
Status enum_status = Collect<abi_dump::EnumDecl>(
|
||||
diff_tu->mutable_enums_added(), diff_tu->mutable_enums_removed(),
|
||||
diff_tu->mutable_enums_diff(), old_tu.enums(), new_tu.enums());
|
||||
|
||||
Status global_var_status = Collect<abi_dump::GlobalVarDecl>(
|
||||
diff_tu->mutable_global_vars_added(),
|
||||
diff_tu->mutable_global_vars_removed(),
|
||||
diff_tu->mutable_global_vars_diff(), old_tu.global_vars(),
|
||||
new_tu.global_vars());
|
||||
|
||||
Status combined_status =
|
||||
record_status | function_status | enum_status | global_var_status;
|
||||
|
||||
std::ofstream text_output(cr_);
|
||||
google::protobuf::io::OstreamOutputStream text_os(&text_output);
|
||||
|
||||
if(!google::protobuf::TextFormat::Print(diff_tu, &text_os)) {
|
||||
if(!google::protobuf::TextFormat::Print(*diff_tu, &text_os)) {
|
||||
llvm::errs() << "Unable to dump report\n";
|
||||
::exit(1);
|
||||
}
|
||||
if (combined_Status & INCOMPATIBLE) {
|
||||
if (combined_status & INCOMPATIBLE) {
|
||||
return INCOMPATIBLE;
|
||||
}
|
||||
if (combined_Status & EXTENSION) {
|
||||
if (combined_status & EXTENSION) {
|
||||
return EXTENSION;
|
||||
}
|
||||
return COMPATIBLE;
|
||||
}
|
||||
|
||||
Status HeaderAbiDiff::CollectRecords(abi_diff::TranslationUnitDiff *diff_tu,
|
||||
const abi_dump::TranslationUnit &old_tu,
|
||||
const abi_dump::TranslationUnit &new_tu) {
|
||||
AddToMap(&old_dump_records_, old_tu.records());
|
||||
AddToMap(&new_dump_records_, new_tu.records());
|
||||
template <typename T, typename TDiff>
|
||||
Status HeaderAbiDiff::Collect(
|
||||
google::protobuf::RepeatedPtrField<T> *elements_added,
|
||||
google::protobuf::RepeatedPtrField<T> *elements_removed,
|
||||
google::protobuf::RepeatedPtrField<TDiff> *elements_diff,
|
||||
const google::protobuf::RepeatedPtrField<T> &old_srcs,
|
||||
const google::protobuf::RepeatedPtrField<T> &new_srcs) {
|
||||
assert(elements_added != nullptr);
|
||||
assert(elements_removed != nullptr);
|
||||
assert(elements_diff != nullptr);
|
||||
|
||||
if (!PopulateRemovedElements(diff_tu->mutable_records_removed(),
|
||||
old_dump_records_, new_dump_records_) ||
|
||||
!PopulateRemovedElements(diff_tu->mutable_records_removed(),
|
||||
new_dump_records_, old_dump_records_) ||
|
||||
!PopulateCommonElements(diff_tu->mutable_records_diff(),old_dump_records_,
|
||||
new_dump_records_)) {
|
||||
llvm::errs() << "Populating records in report failed\n";
|
||||
::exit(1);
|
||||
}
|
||||
if (diff_tu->records_diff().size() || diff_tu->records_removed().size()) {
|
||||
return INCOMPATIBLE;
|
||||
}
|
||||
if (diff_tu->records_added().size()) {
|
||||
return EXTENSION;
|
||||
}
|
||||
return COMPATIBLE;
|
||||
}
|
||||
std::map<std::string, const T*> old_elements_map;
|
||||
std::map<std::string, const T*> new_elements_map;
|
||||
AddToMap(&old_elements_map, old_srcs);
|
||||
AddToMap(&new_elements_map, new_srcs);
|
||||
|
||||
Status HeaderAbiDiff::CollectFunctions(
|
||||
abi_diff::TranslationUnitDiff *diff_tu,
|
||||
const abi_dump::TranslationUnit &old_tu,
|
||||
const abi_dump::TranslationUnit &new_tu) {
|
||||
AddToMap(&old_dump_functions_, old_tu.functions());
|
||||
AddToMap(&new_dump_functions_, new_tu.functions());
|
||||
|
||||
if (!PopulateRemovedElements(diff_tu->mutable_functions_removed(),
|
||||
old_dump_functions_, new_dump_functions_) ||
|
||||
!PopulateRemovedElements(diff_tu->mutable_functions_added(),
|
||||
new_dump_functions_, old_dump_functions_)) {
|
||||
if (!PopulateRemovedElements(elements_removed, old_elements_map,
|
||||
new_elements_map) ||
|
||||
!PopulateRemovedElements(elements_added, new_elements_map,
|
||||
old_elements_map) ||
|
||||
!PopulateCommonElements(elements_diff, old_elements_map,
|
||||
new_elements_map)) {
|
||||
llvm::errs() << "Populating functions in report failed\n";
|
||||
::exit(1);
|
||||
}
|
||||
if (diff_tu->functions_removed().size()) {
|
||||
if (elements_diff->size() || elements_removed->size()) {
|
||||
return INCOMPATIBLE;
|
||||
}
|
||||
if (diff_tu->functions_added().size()) {
|
||||
return EXTENSION;
|
||||
}
|
||||
return COMPATIBLE;
|
||||
}
|
||||
|
||||
Status HeaderAbiDiff::CollectEnums(abi_diff::TranslationUnitDiff *diff_tu,
|
||||
const abi_dump::TranslationUnit &old_tu,
|
||||
const abi_dump::TranslationUnit &new_tu) {
|
||||
AddToMap(&old_dump_enums_, old_tu.enums());
|
||||
AddToMap(&new_dump_enums_, new_tu.enums());
|
||||
|
||||
if (!PopulateRemovedElements(diff_tu->mutable_enums_removed(),
|
||||
old_dump_enums_, new_dump_enums_) ||
|
||||
!PopulateRemovedElements(diff_tu->mutable_enums_added(), new_dump_enums_,
|
||||
old_dump_enums_) ||
|
||||
!PopulateCommonElements(diff_tu->mutable_enums_diff(),old_dump_enums_,
|
||||
new_dump_enums_)) {
|
||||
llvm::errs() << "Populating enums in report failed\n";
|
||||
::exit(1);
|
||||
}
|
||||
if (diff_tu->enums_removed().size() || diff_tu->enums_diff().size()) {
|
||||
return INCOMPATIBLE;
|
||||
}
|
||||
if (diff_tu->enums_added().size()) {
|
||||
if (elements_added->size()) {
|
||||
return EXTENSION;
|
||||
}
|
||||
return COMPATIBLE;
|
||||
@@ -143,12 +124,13 @@ template <typename T>
|
||||
bool HeaderAbiDiff::PopulateRemovedElements(
|
||||
google::protobuf::RepeatedPtrField<T> *dst,
|
||||
const std::map<std::string, const T*> &old_elements_map,
|
||||
const std::map<std::string, const T*> &new_elements_map) const {
|
||||
const std::map<std::string, const T*> &new_elements_map) {
|
||||
|
||||
std::vector<const T *> removed_elements;
|
||||
for (auto &&map_element : old_elements_map) {
|
||||
const T *element = map_element.second;
|
||||
auto new_element = new_elements_map.find(element->linker_set_key());
|
||||
auto new_element =
|
||||
new_elements_map.find(element->basic_abi().linker_set_key());
|
||||
if (new_element == new_elements_map.end()) {
|
||||
removed_elements.emplace_back(element);
|
||||
}
|
||||
@@ -164,7 +146,7 @@ template <typename T, typename TDiff>
|
||||
bool HeaderAbiDiff::PopulateCommonElements(
|
||||
google::protobuf::RepeatedPtrField<TDiff> *dst,
|
||||
const std::map<std::string, const T *> &old_elements_map,
|
||||
const std::map<std::string, const T *> &new_elements_map) const {
|
||||
const std::map<std::string, const T *> &new_elements_map) {
|
||||
std::vector<std::pair<const T *, const T *>> common_elements;
|
||||
typename std::map<std::string, const T *>::const_iterator old_element =
|
||||
old_elements_map.begin();
|
||||
@@ -194,7 +176,7 @@ bool HeaderAbiDiff::PopulateCommonElements(
|
||||
|
||||
template <typename T>
|
||||
bool HeaderAbiDiff::DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
|
||||
std::vector<const T *> &elements) const {
|
||||
std::vector<const T *> &elements) {
|
||||
for (auto &&element : elements) {
|
||||
T *added_element = dst->Add();
|
||||
if (!added_element) {
|
||||
@@ -209,7 +191,7 @@ bool HeaderAbiDiff::DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
|
||||
template <typename T, typename TDiff>
|
||||
bool HeaderAbiDiff::DumpDiffElements(
|
||||
google::protobuf::RepeatedPtrField<TDiff> *dst,
|
||||
std::vector<std::pair<const T *,const T *>> &pairs) const {
|
||||
std::vector<std::pair<const T *,const T *>> &pairs) {
|
||||
for (auto &&pair : pairs) {
|
||||
const T *old_element = pair.first;
|
||||
const T *new_element = pair.second;
|
||||
|
||||
@@ -47,58 +47,43 @@ class HeaderAbiDiff {
|
||||
Status CompareTUs(const abi_dump::TranslationUnit &old_tu,
|
||||
const abi_dump::TranslationUnit &new_tu);
|
||||
// Collect* methods fill in the diff_tu.
|
||||
Status CollectRecords(abi_diff::TranslationUnitDiff *abi_diff,
|
||||
const abi_dump::TranslationUnit &old_tu,
|
||||
const abi_dump::TranslationUnit &new_tu);
|
||||
|
||||
Status CollectFunctions(abi_diff::TranslationUnitDiff *abi_diff,
|
||||
const abi_dump::TranslationUnit &old_tu,
|
||||
const abi_dump::TranslationUnit &new_tu);
|
||||
|
||||
Status CollectEnums(abi_diff::TranslationUnitDiff *abi_diff,
|
||||
const abi_dump::TranslationUnit &old_tu,
|
||||
const abi_dump::TranslationUnit &new_tu);
|
||||
|
||||
template <typename T, typename TDiff>
|
||||
static Status Collect(
|
||||
google::protobuf::RepeatedPtrField<T> *elements_added,
|
||||
google::protobuf::RepeatedPtrField<T> *elements_removed,
|
||||
google::protobuf::RepeatedPtrField<TDiff> *elements_diff,
|
||||
const google::protobuf::RepeatedPtrField<T> &old_srcs,
|
||||
const google::protobuf::RepeatedPtrField<T> &new_srcs);
|
||||
|
||||
template <typename T>
|
||||
inline void AddToMap(std::map<std::string, const T *> *dst,
|
||||
const google::protobuf::RepeatedPtrField<T> &src);
|
||||
static inline void AddToMap(std::map<std::string, const T *> *dst,
|
||||
const google::protobuf::RepeatedPtrField<T> &src);
|
||||
|
||||
template <typename T>
|
||||
bool PopulateRemovedElements(
|
||||
static bool PopulateRemovedElements(
|
||||
google::protobuf::RepeatedPtrField<T> *dst,
|
||||
const std::map<std::string, const T *> &old_elements_map,
|
||||
const std::map<std::string, const T *> &new_elements_map) const;
|
||||
const std::map<std::string, const T *> &new_elements_map);
|
||||
|
||||
template <typename T, typename TDiff>
|
||||
bool PopulateCommonElements(
|
||||
static bool PopulateCommonElements(
|
||||
google::protobuf::RepeatedPtrField<TDiff> *dst,
|
||||
const std::map<std::string, const T *> &old_elements_map,
|
||||
const std::map<std::string, const T *> &new_elements_map) const;
|
||||
const std::map<std::string, const T *> &new_elements_map);
|
||||
|
||||
template <typename T, typename TDiff>
|
||||
bool DumpDiffElements(
|
||||
static bool DumpDiffElements(
|
||||
google::protobuf::RepeatedPtrField<TDiff> *dst,
|
||||
std::vector<std::pair<const T *, const T *>> &pairs) const;
|
||||
std::vector<std::pair<const T *, const T *>> &pairs);
|
||||
|
||||
template <typename T>
|
||||
bool DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
|
||||
std::vector<const T *> &elements) const;
|
||||
static bool DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
|
||||
std::vector<const T *> &elements);
|
||||
|
||||
private:
|
||||
const std::string &old_dump_;
|
||||
const std::string &new_dump_;
|
||||
const std::string &cr_;
|
||||
|
||||
// HashMaps for the old tu abis
|
||||
std::map<std::string, const abi_dump::RecordDecl *> old_dump_records_;
|
||||
std::map<std::string, const abi_dump::FunctionDecl *> old_dump_functions_;
|
||||
std::map<std::string, const abi_dump::EnumDecl *> old_dump_enums_;
|
||||
|
||||
// HashMaps for the new tu abis
|
||||
std::map<std::string, const abi_dump::RecordDecl *> new_dump_records_;
|
||||
std::map<std::string, const abi_dump::FunctionDecl *> new_dump_functions_;
|
||||
std::map<std::string, const abi_dump::EnumDecl *> new_dump_enums_;
|
||||
};
|
||||
|
||||
typedef HeaderAbiDiff::Status Status;
|
||||
@@ -108,7 +93,7 @@ inline void HeaderAbiDiff::AddToMap(
|
||||
std::map<std::string, const T *> *dst,
|
||||
const google::protobuf::RepeatedPtrField<T> &src) {
|
||||
for (auto &&element : src) {
|
||||
dst->insert(std::make_pair(element.linker_set_key(), &element));
|
||||
dst->insert(std::make_pair(element.basic_abi().linker_set_key(), &element));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,15 +24,93 @@
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
|
||||
using abi_diff::RecordDeclDiff;
|
||||
using abi_diff::FieldDeclDiff;
|
||||
using abi_diff::RecordFieldDeclDiff;
|
||||
using abi_diff::CXXBaseSpecifierDiff;
|
||||
using abi_diff::CXXVTableDiff;
|
||||
using abi_diff::EnumDeclDiff;
|
||||
using abi_diff::ReturnTypeDiff;
|
||||
using abi_diff::FunctionDeclDiff;
|
||||
using abi_diff::EnumDeclDiff;
|
||||
using abi_diff::EnumFieldDeclDiff;
|
||||
using abi_diff::GlobalVarDeclDiff;
|
||||
using abi_dump::RecordDecl;
|
||||
using abi_dump::RecordFieldDecl;
|
||||
using abi_dump::EnumDecl;
|
||||
using abi_dump::EnumFieldDecl;
|
||||
using abi_dump::FunctionDecl;
|
||||
using abi_dump::ParamDecl;
|
||||
using abi_dump::VTableComponent;
|
||||
using abi_dump::CXXBaseSpecifier;
|
||||
using abi_dump::GlobalVarDecl;
|
||||
|
||||
namespace abi_diff_wrappers {
|
||||
|
||||
static bool IsAccessDownGraded(abi_dump::AccessSpecifier old_access,
|
||||
abi_dump::AccessSpecifier new_access) {
|
||||
bool access_downgraded = false;
|
||||
switch (old_access) {
|
||||
case abi_dump::AccessSpecifier::protected_access:
|
||||
if (new_access == abi_dump::AccessSpecifier::private_access) {
|
||||
access_downgraded = true;
|
||||
}
|
||||
break;
|
||||
case abi_dump::AccessSpecifier::public_access:
|
||||
if (new_access != abi_dump::AccessSpecifier::public_access) {
|
||||
access_downgraded = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return access_downgraded;
|
||||
}
|
||||
|
||||
static bool DiffBasicTypeAbi(const abi_dump::BasicTypeAbi &old_abi,
|
||||
const abi_dump::BasicTypeAbi &new_abi) {
|
||||
bool name_comparison = (old_abi.name() != new_abi.name());
|
||||
bool size_comparison = (old_abi.size() != new_abi.size());
|
||||
bool alignment_comparison = (old_abi.alignment() != new_abi.alignment());
|
||||
return name_comparison || size_comparison || alignment_comparison;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool Diff(const T &old_element, const T &new_element) {
|
||||
// Can be specialized for future changes in the format.
|
||||
return DiffBasicTypeAbi(old_element.basic_abi().type_abi(),
|
||||
new_element.basic_abi().type_abi()) ||
|
||||
IsAccessDownGraded(old_element.basic_abi().access(),
|
||||
new_element.basic_abi().access());
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Diff<EnumFieldDecl>(const EnumFieldDecl &old_element,
|
||||
const EnumFieldDecl &new_element) {
|
||||
// Can be specialized for future changes in the format.
|
||||
return DiffBasicTypeAbi(old_element.basic_abi().type_abi(),
|
||||
new_element.basic_abi().type_abi()) ||
|
||||
(old_element.enum_field_value() != new_element.enum_field_value());
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Diff<CXXBaseSpecifier>(const CXXBaseSpecifier &old_element,
|
||||
const CXXBaseSpecifier &new_element) {
|
||||
// Can be specialized for future changes in the format.
|
||||
return (DiffBasicTypeAbi(old_element.basic_abi().type_abi(),
|
||||
new_element.basic_abi().type_abi()) ||
|
||||
old_element.basic_abi().access() != new_element.basic_abi().access() ||
|
||||
old_element.is_virtual() != new_element.is_virtual());
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Diff<VTableComponent>(const VTableComponent &old_element,
|
||||
const VTableComponent &new_element) {
|
||||
bool kind_comparison = old_element.kind() != new_element.kind();
|
||||
bool mangled_name_comparison = old_element.mangled_component_name() !=
|
||||
new_element.mangled_component_name();
|
||||
bool value_comparison = old_element.value() != new_element.value();
|
||||
return kind_comparison || mangled_name_comparison || value_comparison;
|
||||
}
|
||||
|
||||
// This function fills in a *Diff Message's repeated field. For eg:
|
||||
// RecordDeclDiff's CXXBaseSpecifierDiff fields and well as FieldDeclDiff
|
||||
// fields.
|
||||
@@ -43,13 +121,14 @@ bool DiffWrapperBase<T, TDiff>::GetElementDiffs(
|
||||
const google::protobuf::RepeatedPtrField<Element> &old_elements,
|
||||
const google::protobuf::RepeatedPtrField<Element> &new_elements) {
|
||||
bool differs = false;
|
||||
assert (dst != nullptr);
|
||||
assert(dst != nullptr);
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i < old_elements.size() && j < new_elements.size()) {
|
||||
const Element &old_element = old_elements.Get(i);
|
||||
const Element &new_element = new_elements.Get(i);
|
||||
if (old_element.linker_set_key() != new_element.linker_set_key()) {
|
||||
|
||||
if (Diff(old_element, new_element)) {
|
||||
ElementDiff *diff = dst->Add();
|
||||
Element *old_elementp = nullptr;
|
||||
Element *new_elementp = nullptr;
|
||||
@@ -109,18 +188,22 @@ void DiffWrapperBase<T, TDiff>::GetExtraElementDiffs(
|
||||
template <>
|
||||
std::unique_ptr<RecordDeclDiff> DiffWrapper<RecordDecl, RecordDeclDiff>::Get() {
|
||||
std::unique_ptr<RecordDeclDiff> record_diff(new RecordDeclDiff());
|
||||
assert(oldp_->fully_qualified_name() == newp_->fully_qualified_name());
|
||||
record_diff->set_name(oldp_->fully_qualified_name());
|
||||
google::protobuf::RepeatedPtrField<FieldDeclDiff> *fdiffs =
|
||||
assert(oldp_->basic_abi().name() == newp_->basic_abi().name());
|
||||
record_diff->set_name(oldp_->basic_abi().name());
|
||||
google::protobuf::RepeatedPtrField<RecordFieldDeclDiff> *fdiffs =
|
||||
record_diff->mutable_field_diffs();
|
||||
google::protobuf::RepeatedPtrField<CXXBaseSpecifierDiff> *bdiffs =
|
||||
record_diff->mutable_base_diffs();
|
||||
google::protobuf::RepeatedPtrField<CXXVTableDiff> *vtdiffs =
|
||||
record_diff->mutable_vtable_diffs();
|
||||
assert(fdiffs != nullptr && bdiffs != nullptr);
|
||||
// Template Information isn't diffed since the linker_set_key includes the
|
||||
// mangled name which includes template information.
|
||||
if (GetElementDiffs(fdiffs, oldp_->fields(), newp_->fields()) ||
|
||||
GetElementDiffs(bdiffs, oldp_->base_specifiers(),
|
||||
newp_->base_specifiers())) {
|
||||
newp_->base_specifiers()) ||
|
||||
GetElementDiffs(vtdiffs, oldp_->vtable_layout().vtable_components(),
|
||||
newp_->vtable_layout().vtable_components())) {
|
||||
return record_diff;
|
||||
}
|
||||
return nullptr;
|
||||
@@ -129,15 +212,51 @@ std::unique_ptr<RecordDeclDiff> DiffWrapper<RecordDecl, RecordDeclDiff>::Get() {
|
||||
template <>
|
||||
std::unique_ptr<EnumDeclDiff> DiffWrapper<EnumDecl, EnumDeclDiff>::Get() {
|
||||
std::unique_ptr<EnumDeclDiff> enum_diff(new EnumDeclDiff());
|
||||
assert(oldp_->enum_name() == newp_->enum_name());
|
||||
assert(oldp_->basic_abi().name() == newp_->basic_abi().name());
|
||||
google::protobuf::RepeatedPtrField<EnumFieldDeclDiff> *fdiffs =
|
||||
enum_diff->mutable_field_diffs();
|
||||
assert(fdiffs != nullptr);
|
||||
if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields()) ||
|
||||
(oldp_->enum_type() != newp_->enum_type())) {
|
||||
if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields())) {
|
||||
return enum_diff;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<FunctionDeclDiff>
|
||||
DiffWrapper<FunctionDecl, FunctionDeclDiff>::Get() {
|
||||
std::unique_ptr<FunctionDeclDiff> func_diff(new FunctionDeclDiff());
|
||||
if (DiffBasicTypeAbi(oldp_->basic_abi().type_abi(),
|
||||
newp_->basic_abi().type_abi()) ||
|
||||
IsAccessDownGraded(oldp_->basic_abi().access(),
|
||||
newp_->basic_abi().access())) {
|
||||
assert(func_diff->mutable_return_type_diffs() != nullptr &&
|
||||
func_diff->mutable_return_type_diffs()->mutable_old() != nullptr &&
|
||||
func_diff->mutable_return_type_diffs()->mutable_new_() != nullptr);
|
||||
*(func_diff->mutable_return_type_diffs()->mutable_old()) =
|
||||
oldp_->basic_abi();
|
||||
*(func_diff->mutable_return_type_diffs()->mutable_new_()) =
|
||||
newp_->basic_abi();
|
||||
return func_diff;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<GlobalVarDeclDiff>
|
||||
DiffWrapper<GlobalVarDecl, GlobalVarDeclDiff>::Get() {
|
||||
std::unique_ptr<GlobalVarDeclDiff> global_var_diff(new GlobalVarDeclDiff());
|
||||
if (DiffBasicTypeAbi(oldp_->basic_abi().type_abi(),
|
||||
newp_->basic_abi().type_abi()) ||
|
||||
IsAccessDownGraded(oldp_->basic_abi().access(),
|
||||
newp_->basic_abi().access())) {
|
||||
assert(global_var_diff->mutable_old() != nullptr);
|
||||
assert(global_var_diff->mutable_new_() != nullptr);
|
||||
*(global_var_diff->mutable_old()) = oldp_->basic_abi();
|
||||
*(global_var_diff->mutable_new_()) = newp_->basic_abi();
|
||||
return global_var_diff;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // abi_diff_wrappers
|
||||
|
||||
@@ -35,17 +35,24 @@ static llvm::cl::opt<std::string> old_dump(
|
||||
int main(int argc, const char **argv) {
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv, "header-checker");
|
||||
uint8_t extension_or_incompatible = 0;
|
||||
HeaderAbiDiff judge(old_dump, new_dump, compatibility_report);
|
||||
switch (judge.GenerateCompatibilityReport()) {
|
||||
case HeaderAbiDiff::COMPATIBLE:
|
||||
break;
|
||||
case HeaderAbiDiff::EXTENSION:
|
||||
return 0;
|
||||
extension_or_incompatible = 1;
|
||||
break;
|
||||
default:
|
||||
llvm::errs() << "******************************************************\n"
|
||||
<< "VNDK Abi Compliance breakage:"
|
||||
<< " Please check compatiblity report at : "
|
||||
<< compatibility_report << "\n"
|
||||
<< "*****************************************************\n";
|
||||
return 1;
|
||||
extension_or_incompatible = 2;
|
||||
break;
|
||||
}
|
||||
if (extension_or_incompatible) {
|
||||
llvm::errs() << "******************************************************\n"
|
||||
<< "VNDK Abi Compliance breakage:"
|
||||
<< " Please check compatiblity report at : "
|
||||
<< compatibility_report << "\n"
|
||||
<< "*****************************************************\n";
|
||||
}
|
||||
return extension_or_incompatible;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ using namespace abi_wrapper;
|
||||
|
||||
ABIWrapper::ABIWrapper(
|
||||
clang::MangleContext *mangle_contextp,
|
||||
const clang::ASTContext *ast_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *cip)
|
||||
: cip_(cip),
|
||||
mangle_contextp_(mangle_contextp),
|
||||
@@ -40,26 +40,66 @@ std::string ABIWrapper::GetDeclSourceFile(const clang::Decl *decl,
|
||||
return abs_path.str();
|
||||
}
|
||||
|
||||
std::string ABIWrapper::AccessToString(const clang::AccessSpecifier sp) const {
|
||||
std::string str = "public";
|
||||
abi_dump::AccessSpecifier ABIWrapper::AccessClangToDump(
|
||||
const clang::AccessSpecifier sp) const {
|
||||
switch (sp) {
|
||||
case clang::AS_private: {
|
||||
str = "private";
|
||||
return abi_dump::AccessSpecifier::private_access;
|
||||
break;
|
||||
}
|
||||
case clang::AS_protected: {
|
||||
str = "protected";
|
||||
return abi_dump::AccessSpecifier::protected_access;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return abi_dump::AccessSpecifier::public_access;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
bool ABIWrapper::SetupBasicTypeAbi(abi_dump::BasicTypeAbi *type_abi,
|
||||
const clang::QualType type) const {
|
||||
if (!type_abi) {
|
||||
return false;
|
||||
}
|
||||
type_abi->set_name(QualTypeToString(type));
|
||||
// Cannot determine the size and alignment for template parameter dependent
|
||||
// types as well as incomplete types.
|
||||
const clang::Type *base_type = type.getTypePtr();
|
||||
if (base_type && !(base_type->isDependentType()) &&
|
||||
!(base_type->isIncompleteType())) {
|
||||
std::pair<clang::CharUnits, clang::CharUnits> size_and_alignment =
|
||||
ast_contextp_->getTypeInfoInChars(type);
|
||||
int64_t size = size_and_alignment.first.getQuantity();
|
||||
int64_t alignment = size_and_alignment.second.getQuantity();
|
||||
type_abi->set_size(size);
|
||||
type_abi->set_alignment(alignment);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ABIWrapper::SetupBasicNamedAndTypedDecl(
|
||||
abi_dump::BasicNamedAndTypedDecl *basic_named_and_typed_decl,
|
||||
const clang::QualType type, const std::string &name,
|
||||
const clang::AccessSpecifier &access, std::string key) const {
|
||||
if (!basic_named_and_typed_decl) {
|
||||
return false;
|
||||
}
|
||||
abi_dump::AccessSpecifier access_dump = AccessClangToDump(access);
|
||||
basic_named_and_typed_decl->set_name(name);
|
||||
basic_named_and_typed_decl->set_access(access_dump);
|
||||
if (key != "") {
|
||||
basic_named_and_typed_decl->set_linker_set_key(key);
|
||||
}
|
||||
return SetupBasicTypeAbi(basic_named_and_typed_decl->mutable_type_abi(),
|
||||
type);
|
||||
}
|
||||
|
||||
std::string ABIWrapper::GetMangledNameDecl(const clang::NamedDecl *decl) const {
|
||||
std::string mangled_or_demangled_name = decl->getName();
|
||||
clang::IdentifierInfo *identifier = decl->getIdentifier();
|
||||
std::string mangled_or_demangled_name =
|
||||
identifier ? identifier->getName() : "";
|
||||
if (mangle_contextp_->shouldMangleDeclName(decl)) {
|
||||
llvm::raw_string_ostream ostream(mangled_or_demangled_name);
|
||||
mangle_contextp_->mangleName(decl, ostream);
|
||||
@@ -71,17 +111,26 @@ std::string ABIWrapper::GetMangledNameDecl(const clang::NamedDecl *decl) const {
|
||||
bool ABIWrapper::SetupTemplateParamNames(
|
||||
abi_dump::TemplateInfo *tinfo,
|
||||
clang::TemplateParameterList *pl) const {
|
||||
if (tinfo->template_parameters_size() > 0) {
|
||||
if (tinfo->elements_size() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
clang::TemplateParameterList::iterator template_it = pl->begin();
|
||||
while (template_it != pl->end()) {
|
||||
abi_dump::FieldDecl *template_parameterp = tinfo->add_template_parameters();
|
||||
abi_dump::TemplateElement *template_parameterp =
|
||||
tinfo->add_elements();
|
||||
if (!template_parameterp) {
|
||||
return false;
|
||||
}
|
||||
template_parameterp->set_field_name((*template_it)->getName());
|
||||
abi_dump::TemplateElement::BasicTemplateElementAbi *basic_abi =
|
||||
template_parameterp->mutable_basic_abi();
|
||||
if (!basic_abi) {
|
||||
return false;
|
||||
}
|
||||
std::string name = (*template_it)->getName();
|
||||
basic_abi->set_name(name);
|
||||
// TODO : Default arg ?
|
||||
basic_abi->set_linker_set_key(name);
|
||||
template_it++;
|
||||
}
|
||||
return true;
|
||||
@@ -92,7 +141,6 @@ std::string ABIWrapper::GetTagDeclQualifiedName(
|
||||
if (decl->getTypedefNameForAnonDecl()) {
|
||||
return decl->getTypedefNameForAnonDecl()->getQualifiedNameAsString();
|
||||
}
|
||||
|
||||
return decl->getQualifiedNameAsString();
|
||||
}
|
||||
|
||||
@@ -102,16 +150,22 @@ bool ABIWrapper::SetupTemplateArguments(
|
||||
for (int i = 0; i < tl->size(); i++) {
|
||||
const clang::TemplateArgument &arg = (*tl)[i];
|
||||
//TODO: More comprehensive checking needed.
|
||||
std::string type = " ";
|
||||
if(arg.getKind() == clang::TemplateArgument::Type) {
|
||||
type = QualTypeToString(arg.getAsType());
|
||||
if (arg.getKind() != clang::TemplateArgument::Type) {
|
||||
continue;
|
||||
}
|
||||
abi_dump::FieldDecl *template_parameterp =
|
||||
tinfo->add_template_parameters();
|
||||
clang::QualType type = arg.getAsType();
|
||||
abi_dump::TemplateElement *template_parameterp =
|
||||
tinfo->add_elements();
|
||||
if (!template_parameterp) {
|
||||
return false;
|
||||
}
|
||||
template_parameterp->set_field_type((type));
|
||||
abi_dump::TemplateElement::BasicTemplateElementAbi *basic_abi =
|
||||
template_parameterp->mutable_basic_abi();
|
||||
if (!basic_abi || !SetupBasicTypeAbi(basic_abi->mutable_type_abi(), type)) {
|
||||
return false;
|
||||
}
|
||||
// TODO : default arg
|
||||
basic_abi->set_linker_set_key(QualTypeToString(type));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -124,42 +178,51 @@ std::string ABIWrapper::QualTypeToString(
|
||||
|
||||
FunctionDeclWrapper::FunctionDeclWrapper(
|
||||
clang::MangleContext *mangle_contextp,
|
||||
const clang::ASTContext *ast_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *compiler_instance_p,
|
||||
const clang::FunctionDecl *decl)
|
||||
: ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
|
||||
function_decl_(decl) { }
|
||||
|
||||
bool FunctionDeclWrapper::SetupFunctionParameters(
|
||||
abi_dump::FunctionDecl *functionp) const {
|
||||
clang::FunctionDecl::param_const_iterator param_it =
|
||||
function_decl_->param_begin();
|
||||
while (param_it != function_decl_->param_end()) {
|
||||
abi_dump::ParamDecl *function_fieldp = functionp->add_parameters();
|
||||
if (!function_fieldp) {
|
||||
llvm::errs() << "Couldn't add parameter to method. Aborting\n";
|
||||
return false;
|
||||
}
|
||||
// The linker set key is blank since that shows up in the mangled name.
|
||||
bool has_default_arg = (*param_it)->hasDefaultArg();
|
||||
if (!SetupBasicNamedAndTypedDecl(
|
||||
function_fieldp->mutable_basic_abi(),
|
||||
(*param_it)->getType(), (*param_it)->getName(),
|
||||
(*param_it)->getAccess(), has_default_arg ? "true" : "false")) {
|
||||
return false;
|
||||
}
|
||||
function_fieldp->set_default_arg(has_default_arg);
|
||||
param_it++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FunctionDeclWrapper::SetupFunction(abi_dump::FunctionDecl *functionp,
|
||||
const std::string &source_file) const {
|
||||
// Go through all the parameters in the method and add them to the fields.
|
||||
// Also get the fully qualfied name and mangled name and store them.
|
||||
std::string mangled_name = GetMangledNameDecl(function_decl_);
|
||||
functionp->set_function_name(function_decl_->getQualifiedNameAsString());
|
||||
functionp->set_mangled_function_name(mangled_name);
|
||||
functionp->set_linker_set_key(mangled_name);
|
||||
functionp->set_source_file(source_file);
|
||||
functionp->set_return_type(QualTypeToString(function_decl_->getReturnType()));
|
||||
|
||||
clang::FunctionDecl::param_const_iterator param_it =
|
||||
function_decl_->param_begin();
|
||||
while (param_it != function_decl_->param_end()) {
|
||||
abi_dump::FieldDecl *function_fieldp = functionp->add_parameters();
|
||||
if (!function_fieldp) {
|
||||
llvm::errs() << "Couldn't add parameter to method. Aborting\n";
|
||||
return false;
|
||||
}
|
||||
function_fieldp->set_field_name((*param_it)->getName());
|
||||
function_fieldp->set_default_arg((*param_it)->hasDefaultArg());
|
||||
function_fieldp->set_field_type(QualTypeToString((*param_it)->getType()));
|
||||
param_it++;
|
||||
}
|
||||
functionp->set_access(AccessToString(function_decl_->getAccess()));
|
||||
functionp->set_template_kind(function_decl_->getTemplatedKind());
|
||||
if(!SetupTemplateInfo(functionp)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// Combine the function name and return type to form a NamedAndTypedDecl
|
||||
return SetupBasicNamedAndTypedDecl(
|
||||
functionp->mutable_basic_abi(),
|
||||
function_decl_->getReturnType(),
|
||||
function_decl_->getQualifiedNameAsString(),
|
||||
function_decl_->getAccess(), mangled_name) &&
|
||||
SetupTemplateInfo(functionp) && SetupFunctionParameters(functionp);
|
||||
}
|
||||
|
||||
bool FunctionDeclWrapper::SetupTemplateInfo(
|
||||
@@ -209,42 +272,35 @@ FunctionDeclWrapper::GetFunctionDecl() const {
|
||||
|
||||
RecordDeclWrapper::RecordDeclWrapper(
|
||||
clang::MangleContext *mangle_contextp,
|
||||
const clang::ASTContext *ast_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *compiler_instance_p,
|
||||
const clang::RecordDecl *decl)
|
||||
: ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
|
||||
record_decl_(decl) { }
|
||||
|
||||
bool RecordDeclWrapper::SetupRecordFields(
|
||||
abi_dump::RecordDecl *recordp,
|
||||
const std::string &source_file) const {
|
||||
bool RecordDeclWrapper::SetupRecordFields(abi_dump::RecordDecl *recordp) const {
|
||||
clang::RecordDecl::field_iterator field = record_decl_->field_begin();
|
||||
while (field != record_decl_->field_end()) {
|
||||
abi_dump::FieldDecl *record_fieldp = recordp->add_fields();
|
||||
abi_dump::RecordFieldDecl *record_fieldp = recordp->add_fields();
|
||||
if (!record_fieldp) {
|
||||
llvm::errs() << " Couldn't add record field: " << field->getName()
|
||||
<< " to reference dump\n";
|
||||
return false;
|
||||
}
|
||||
std::string name = field->getName();
|
||||
std::string type = QualTypeToString(field->getType());
|
||||
std::string access = AccessToString(field->getAccess());
|
||||
record_fieldp->set_field_name(name);
|
||||
record_fieldp->set_field_type(type);
|
||||
record_fieldp->set_access(access);
|
||||
record_fieldp->set_linker_set_key(name + type + access);
|
||||
if (!SetupBasicNamedAndTypedDecl(record_fieldp->mutable_basic_abi(),
|
||||
field->getType(), field->getName(),
|
||||
field->getAccess(), "")) {
|
||||
return false;
|
||||
}
|
||||
field++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordDeclWrapper::SetupCXXBases(abi_dump::RecordDecl *cxxp) const {
|
||||
const clang::CXXRecordDecl *cxx_record_decl =
|
||||
clang::dyn_cast<clang::CXXRecordDecl>(record_decl_);
|
||||
if (!cxx_record_decl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordDeclWrapper::SetupCXXBases(
|
||||
abi_dump::RecordDecl *cxxp,
|
||||
const clang::CXXRecordDecl *cxx_record_decl) const {
|
||||
assert(cxx_record_decl != nullptr);
|
||||
clang::CXXRecordDecl::base_class_const_iterator base_class =
|
||||
cxx_record_decl->bases_begin();
|
||||
while (base_class != cxx_record_decl->bases_end()) {
|
||||
@@ -255,25 +311,121 @@ bool RecordDeclWrapper::SetupCXXBases(abi_dump::RecordDecl *cxxp) const {
|
||||
}
|
||||
std::string name = QualTypeToString(base_class->getType());
|
||||
bool is_virtual = base_class->isVirtual();
|
||||
char is_virtual_c = is_virtual ? 't' : 'f';
|
||||
std::string access = AccessToString(base_class->getAccessSpecifier());
|
||||
base_specifierp->set_fully_qualified_name(name);
|
||||
if (!SetupBasicNamedAndTypedDecl(base_specifierp->mutable_basic_abi(),
|
||||
base_class->getType(),
|
||||
"", base_class->getAccessSpecifier(),
|
||||
"")) {
|
||||
return false;
|
||||
}
|
||||
base_specifierp->set_is_virtual(is_virtual);
|
||||
base_specifierp->set_access(access);
|
||||
base_specifierp->set_linker_set_key(name + is_virtual_c + access);
|
||||
base_class++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordDeclWrapper::SetupTemplateInfo(
|
||||
abi_dump::RecordDecl *record_declp) const {
|
||||
const clang::CXXRecordDecl *cxx_record_decl =
|
||||
clang::dyn_cast<clang::CXXRecordDecl>(record_decl_);
|
||||
if (!cxx_record_decl) {
|
||||
bool RecordDeclWrapper::SetupRecordVTable(
|
||||
abi_dump::RecordDecl *record_declp,
|
||||
const clang::CXXRecordDecl *cxx_record_decl) const {
|
||||
assert(cxx_record_decl != nullptr);
|
||||
clang::VTableContextBase *base_vtable_contextp =
|
||||
ast_contextp_->getVTableContext();
|
||||
const clang::Type *typep = cxx_record_decl->getTypeForDecl();
|
||||
if (!base_vtable_contextp || !typep) {
|
||||
return false;
|
||||
}
|
||||
// Skip Microsoft ABI.
|
||||
clang::ItaniumVTableContext *itanium_vtable_contextp =
|
||||
llvm::dyn_cast<clang::ItaniumVTableContext>(base_vtable_contextp);
|
||||
if (!itanium_vtable_contextp || !cxx_record_decl->isPolymorphic() ||
|
||||
typep->isDependentType() || typep->isIncompleteType()) {
|
||||
return true;
|
||||
}
|
||||
const clang::VTableLayout &vtable_layout =
|
||||
itanium_vtable_contextp->getVTableLayout(cxx_record_decl);
|
||||
abi_dump::VTableLayout *vtablep = record_declp->mutable_vtable_layout();
|
||||
if (!vtablep) {
|
||||
return false;
|
||||
}
|
||||
for (const auto &vtable_component : vtable_layout.vtable_components()) {
|
||||
abi_dump::VTableComponent *added_vtable_component =
|
||||
vtablep->add_vtable_components();
|
||||
if (!added_vtable_component ||
|
||||
!SetupRecordVTableComponent(added_vtable_component, vtable_component)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordDeclWrapper::SetupRecordVTableComponent(
|
||||
abi_dump::VTableComponent *added_vtable_component,
|
||||
const clang::VTableComponent &vtable_component) const {
|
||||
assert(added_vtable_component != nullptr);
|
||||
abi_dump::VTableComponent_Kind kind = abi_dump::VTableComponent_Kind_RTTI;
|
||||
std::string mangled_component_name = "";
|
||||
uint64_t value = 0;
|
||||
clang::VTableComponent::Kind clang_component_kind =
|
||||
vtable_component.getKind();
|
||||
switch (clang_component_kind) {
|
||||
case clang::VTableComponent::CK_VCallOffset:
|
||||
kind = abi_dump::VTableComponent_Kind_VCallOffset;
|
||||
value = vtable_component.getVCallOffset().getQuantity();
|
||||
break;
|
||||
case clang::VTableComponent::CK_VBaseOffset:
|
||||
kind = abi_dump::VTableComponent_Kind_VBaseOffset;
|
||||
value = vtable_component.getVBaseOffset().getQuantity();
|
||||
break;
|
||||
case clang::VTableComponent::CK_OffsetToTop:
|
||||
kind = abi_dump::VTableComponent_Kind_OffsetToTop;
|
||||
value = vtable_component.getOffsetToTop().getQuantity();
|
||||
break;
|
||||
case clang::VTableComponent::CK_RTTI:
|
||||
{
|
||||
kind = abi_dump::VTableComponent_Kind_RTTI;
|
||||
const clang::CXXRecordDecl *rtti_decl =
|
||||
vtable_component.getRTTIDecl();
|
||||
assert(rtti_decl != nullptr);
|
||||
mangled_component_name = GetMangledNameDecl(rtti_decl);
|
||||
}
|
||||
break;
|
||||
case clang::VTableComponent::CK_FunctionPointer:
|
||||
case clang::VTableComponent::CK_CompleteDtorPointer:
|
||||
case clang::VTableComponent::CK_DeletingDtorPointer:
|
||||
case clang::VTableComponent::CK_UnusedFunctionPointer:
|
||||
{
|
||||
const clang::CXXMethodDecl *method_decl =
|
||||
vtable_component.getFunctionDecl();
|
||||
assert(method_decl != nullptr);
|
||||
mangled_component_name = GetMangledNameDecl(method_decl);
|
||||
switch (clang_component_kind) {
|
||||
case clang::VTableComponent::CK_FunctionPointer:
|
||||
kind = abi_dump::VTableComponent_Kind_FunctionPointer;
|
||||
break;
|
||||
case clang::VTableComponent::CK_CompleteDtorPointer:
|
||||
kind = abi_dump::VTableComponent_Kind_CompleteDtorPointer;
|
||||
break;
|
||||
case clang::VTableComponent::CK_DeletingDtorPointer:
|
||||
kind = abi_dump::VTableComponent_Kind_DeletingDtorPointer;
|
||||
case clang::VTableComponent::CK_UnusedFunctionPointer:
|
||||
kind = abi_dump::VTableComponent_Kind_UnusedFunctionPointer;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
added_vtable_component->set_kind(kind);
|
||||
added_vtable_component->set_value(value);
|
||||
added_vtable_component->set_mangled_component_name(mangled_component_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordDeclWrapper::SetupTemplateInfo(
|
||||
abi_dump::RecordDecl *record_declp,
|
||||
const clang::CXXRecordDecl *cxx_record_decl) const {
|
||||
assert(cxx_record_decl != nullptr);
|
||||
if (cxx_record_decl->isTemplateDecl()) {
|
||||
clang::ClassTemplateDecl *template_decl =
|
||||
cxx_record_decl->getDescribedClassTemplate();
|
||||
@@ -303,28 +455,45 @@ bool RecordDeclWrapper::SetupTemplateInfo(
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecordDeclWrapper::SetupRecordInfo(abi_dump::RecordDecl *record_declp,
|
||||
bool RecordDeclWrapper::SetupRecordInfo(abi_dump::RecordDecl *record_declp,
|
||||
const std::string &source_file) const {
|
||||
std::string qualified_name = GetTagDeclQualifiedName(record_decl_);
|
||||
std::string mangled_name = GetMangledNameDecl(record_decl_);
|
||||
const clang::Type *basic_type = nullptr;
|
||||
if (!(basic_type = record_decl_->getTypeForDecl())) {
|
||||
return false;
|
||||
}
|
||||
clang::QualType type = basic_type->getCanonicalTypeInternal();
|
||||
std::string linker_key = (mangled_name == "") ? qualified_name : mangled_name;
|
||||
record_declp->set_fully_qualified_name(qualified_name);
|
||||
if (!SetupBasicNamedAndTypedDecl(record_declp->mutable_basic_abi(),
|
||||
type, qualified_name,
|
||||
record_decl_->getAccess(), linker_key)) {
|
||||
return false;
|
||||
}
|
||||
record_declp->set_mangled_record_name(mangled_name);
|
||||
record_declp->set_linker_set_key(linker_key);
|
||||
record_declp->set_source_file(source_file);
|
||||
record_declp->set_access(AccessToString(record_decl_->getAccess()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordDeclWrapper::SetupCXXRecordInfo(
|
||||
abi_dump::RecordDecl *record_declp) const {
|
||||
const clang::CXXRecordDecl *cxx_record_decl =
|
||||
clang::dyn_cast<clang::CXXRecordDecl>(record_decl_);
|
||||
if (!cxx_record_decl) {
|
||||
return true;
|
||||
}
|
||||
return SetupTemplateInfo(record_declp, cxx_record_decl) &&
|
||||
SetupCXXBases(record_declp, cxx_record_decl) &&
|
||||
SetupRecordVTable(record_declp, cxx_record_decl);
|
||||
}
|
||||
|
||||
std::unique_ptr<abi_dump::RecordDecl> RecordDeclWrapper::GetRecordDecl() const {
|
||||
std::unique_ptr<abi_dump::RecordDecl> abi_decl(new abi_dump::RecordDecl());
|
||||
std::string source_file = GetDeclSourceFile(record_decl_, cip_);
|
||||
SetupRecordInfo(abi_decl.get(), source_file);
|
||||
if (!SetupRecordFields(abi_decl.get(), source_file)) {
|
||||
llvm::errs() << "Setting up Record Fields failed\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!SetupCXXBases(abi_decl.get()) || !SetupTemplateInfo(abi_decl.get())) {
|
||||
abi_dump::RecordDecl *record_declp = abi_decl.get();
|
||||
if (!SetupRecordInfo(record_declp, source_file) ||
|
||||
!SetupRecordFields(record_declp) ||
|
||||
!SetupCXXRecordInfo(abi_decl.get())) {
|
||||
llvm::errs() << "Setting up CXX Bases / Template Info failed\n";
|
||||
return nullptr;
|
||||
}
|
||||
@@ -333,34 +502,46 @@ std::unique_ptr<abi_dump::RecordDecl> RecordDeclWrapper::GetRecordDecl() const {
|
||||
|
||||
EnumDeclWrapper::EnumDeclWrapper(
|
||||
clang::MangleContext *mangle_contextp,
|
||||
const clang::ASTContext *ast_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *compiler_instance_p,
|
||||
const clang::EnumDecl *decl)
|
||||
: ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
|
||||
enum_decl_(decl) { }
|
||||
|
||||
bool EnumDeclWrapper::SetupEnum(abi_dump::EnumDecl *enump,
|
||||
const std::string &source_file) const {
|
||||
// Enum's name.
|
||||
std::string enum_name = GetTagDeclQualifiedName(enum_decl_);
|
||||
std::string enum_type = QualTypeToString(enum_decl_->getIntegerType());
|
||||
enump->set_enum_name(enum_name);
|
||||
// Enum's base integer type.
|
||||
enump->set_enum_type(enum_type);
|
||||
enump->set_linker_set_key(enum_name + enum_type);
|
||||
bool EnumDeclWrapper::SetupEnumFields(abi_dump::EnumDecl *enump) const {
|
||||
clang::EnumDecl::enumerator_iterator enum_it = enum_decl_->enumerator_begin();
|
||||
while (enum_it != enum_decl_->enumerator_end()) {
|
||||
abi_dump::EnumFieldDecl *enum_fieldp = enump->add_enum_fields();
|
||||
if (!enum_fieldp) {
|
||||
std::string name = enum_it->getQualifiedNameAsString();
|
||||
uint64_t field_value = enum_it->getInitVal().getExtValue();
|
||||
if (!enum_fieldp ||
|
||||
!SetupBasicNamedAndTypedDecl(enum_fieldp->mutable_basic_abi(),
|
||||
enum_it->getType(), name,
|
||||
enum_it->getAccess(),
|
||||
std::to_string(field_value))) {
|
||||
return false;
|
||||
}
|
||||
enum_fieldp->set_enum_field_name(enum_it->getQualifiedNameAsString());
|
||||
enum_fieldp->set_enum_field_value(enum_it->getInitVal().getExtValue());
|
||||
enum_fieldp->set_enum_field_value(field_value);
|
||||
enum_it++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EnumDeclWrapper::SetupEnum(abi_dump::EnumDecl *enump,
|
||||
const std::string &source_file) const {
|
||||
std::string enum_name = GetTagDeclQualifiedName(enum_decl_);
|
||||
std::string enum_mangled_name = GetMangledNameDecl(enum_decl_);
|
||||
clang::QualType enum_type = enum_decl_->getIntegerType();
|
||||
if (!SetupBasicNamedAndTypedDecl(enump->mutable_basic_abi(), enum_type,
|
||||
enum_name, enum_decl_->getAccess(),
|
||||
enum_mangled_name) ||
|
||||
!SetupEnumFields(enump)) {
|
||||
return false;
|
||||
}
|
||||
enump->set_source_file(source_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<abi_dump::EnumDecl> EnumDeclWrapper::GetEnumDecl() const {
|
||||
std::unique_ptr<abi_dump::EnumDecl> abi_decl(new abi_dump::EnumDecl());
|
||||
std::string source_file = GetDeclSourceFile(enum_decl_, cip_);
|
||||
@@ -371,3 +552,35 @@ std::unique_ptr<abi_dump::EnumDecl> EnumDeclWrapper::GetEnumDecl() const {
|
||||
}
|
||||
return abi_decl;
|
||||
}
|
||||
|
||||
GlobalVarDeclWrapper::GlobalVarDeclWrapper(
|
||||
clang::MangleContext *mangle_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *compiler_instance_p,
|
||||
const clang::VarDecl *decl)
|
||||
: ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
|
||||
global_var_decl_(decl) { }
|
||||
|
||||
bool GlobalVarDeclWrapper::SetupGlobalVar(
|
||||
abi_dump::GlobalVarDecl *global_varp,
|
||||
const std::string &source_file) const {
|
||||
if (!SetupBasicNamedAndTypedDecl(
|
||||
global_varp->mutable_basic_abi(),global_var_decl_->getType(),
|
||||
global_var_decl_->getQualifiedNameAsString(),
|
||||
global_var_decl_->getAccess(), GetMangledNameDecl(global_var_decl_))) {
|
||||
return false;
|
||||
}
|
||||
global_varp->set_source_file(source_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<abi_dump::GlobalVarDecl>
|
||||
GlobalVarDeclWrapper::GetGlobalVarDecl() const {
|
||||
std::unique_ptr<abi_dump::GlobalVarDecl>
|
||||
abi_decl(new abi_dump::GlobalVarDecl);
|
||||
std::string source_file = GetDeclSourceFile(global_var_decl_, cip_);
|
||||
if (!SetupGlobalVar(abi_decl.get(), source_file)) {
|
||||
return nullptr;
|
||||
}
|
||||
return abi_decl;
|
||||
}
|
||||
|
||||
@@ -24,20 +24,22 @@
|
||||
#include <clang/AST/AST.h>
|
||||
#include <clang/AST/ASTConsumer.h>
|
||||
#include <clang/AST/Mangle.h>
|
||||
#include <clang/AST/VTableBuilder.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
|
||||
namespace abi_wrapper {
|
||||
class ABIWrapper {
|
||||
public:
|
||||
ABIWrapper(clang::MangleContext *mangle_contextp,
|
||||
const clang::ASTContext *ast_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *cip);
|
||||
|
||||
static std::string GetDeclSourceFile(const clang::Decl *decl,
|
||||
const clang::CompilerInstance *cip);
|
||||
|
||||
protected:
|
||||
std::string AccessToString(const clang::AccessSpecifier sp) const;
|
||||
abi_dump::AccessSpecifier AccessClangToDump(
|
||||
const clang::AccessSpecifier sp) const;
|
||||
|
||||
std::string GetMangledNameDecl(const clang::NamedDecl *decl) const;
|
||||
|
||||
@@ -51,18 +53,24 @@ class ABIWrapper {
|
||||
|
||||
std::string GetTagDeclQualifiedName(const clang::TagDecl *decl) const;
|
||||
|
||||
protected:
|
||||
const clang::CompilerInstance *cip_;
|
||||
bool SetupBasicTypeAbi(abi_dump::BasicTypeAbi *type_abi,
|
||||
const clang::QualType type) const;
|
||||
|
||||
private:
|
||||
bool SetupBasicNamedAndTypedDecl(
|
||||
abi_dump::BasicNamedAndTypedDecl *basic_named_and_typed_decl,
|
||||
const clang::QualType type, const std::string &name,
|
||||
const clang::AccessSpecifier &access, std::string key) const;
|
||||
|
||||
protected:
|
||||
const clang::CompilerInstance *cip_;
|
||||
clang::MangleContext *mangle_contextp_;
|
||||
const clang::ASTContext *ast_contextp_;
|
||||
clang::ASTContext *ast_contextp_;
|
||||
};
|
||||
|
||||
class RecordDeclWrapper : public ABIWrapper {
|
||||
public:
|
||||
RecordDeclWrapper(clang::MangleContext *mangle_contextp,
|
||||
const clang::ASTContext *ast_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *compiler_instance_p,
|
||||
const clang::RecordDecl *decl);
|
||||
|
||||
@@ -72,21 +80,30 @@ class RecordDeclWrapper : public ABIWrapper {
|
||||
const clang::RecordDecl *record_decl_;
|
||||
|
||||
private:
|
||||
void SetupRecordInfo(abi_dump::RecordDecl *record_declp,
|
||||
bool SetupRecordInfo(abi_dump::RecordDecl *record_declp,
|
||||
const std::string &source_file) const;
|
||||
|
||||
bool SetupRecordFields(abi_dump::RecordDecl *record_declp,
|
||||
const std::string &source_file) const;
|
||||
bool SetupRecordFields(abi_dump::RecordDecl *record_declp) const;
|
||||
|
||||
bool SetupCXXBases(abi_dump::RecordDecl *cxxp) const;
|
||||
bool SetupCXXBases(abi_dump::RecordDecl *cxxp,
|
||||
const clang::CXXRecordDecl *cxx_record_decl) const;
|
||||
|
||||
bool SetupTemplateInfo(abi_dump::RecordDecl *record_declp) const;
|
||||
bool SetupTemplateInfo(abi_dump::RecordDecl *record_declp,
|
||||
const clang::CXXRecordDecl *cxx_record_decl) const;
|
||||
|
||||
bool SetupRecordVTable(abi_dump::RecordDecl *record_declp,
|
||||
const clang::CXXRecordDecl *cxx_record_decl) const;
|
||||
bool SetupRecordVTableComponent(
|
||||
abi_dump::VTableComponent *added_vtable_component,
|
||||
const clang::VTableComponent &vtable_component) const;
|
||||
|
||||
bool SetupCXXRecordInfo(abi_dump::RecordDecl *record_declp) const;
|
||||
};
|
||||
|
||||
class FunctionDeclWrapper : public ABIWrapper {
|
||||
public:
|
||||
FunctionDeclWrapper(clang::MangleContext *mangle_contextp,
|
||||
const clang::ASTContext *ast_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *compiler_instance_p,
|
||||
const clang::FunctionDecl *decl);
|
||||
|
||||
@@ -100,12 +117,14 @@ class FunctionDeclWrapper : public ABIWrapper {
|
||||
const std::string &source_file) const;
|
||||
|
||||
bool SetupTemplateInfo(abi_dump::FunctionDecl *functionp) const;
|
||||
|
||||
bool SetupFunctionParameters(abi_dump::FunctionDecl *functionp) const;
|
||||
};
|
||||
|
||||
class EnumDeclWrapper : public ABIWrapper {
|
||||
public:
|
||||
EnumDeclWrapper(clang::MangleContext *mangle_contextp,
|
||||
const clang::ASTContext *ast_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *compiler_instance_p,
|
||||
const clang::EnumDecl *decl);
|
||||
|
||||
@@ -117,6 +136,23 @@ class EnumDeclWrapper : public ABIWrapper {
|
||||
private:
|
||||
bool SetupEnum(abi_dump::EnumDecl *enump,
|
||||
const std::string &source_file) const;
|
||||
bool SetupEnumFields(abi_dump::EnumDecl *enump) const;
|
||||
};
|
||||
|
||||
class GlobalVarDeclWrapper : public ABIWrapper {
|
||||
public:
|
||||
GlobalVarDeclWrapper(clang::MangleContext *mangle_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *compiler_instance_p,
|
||||
const clang::VarDecl *decl);
|
||||
|
||||
std::unique_ptr<abi_dump::GlobalVarDecl> GetGlobalVarDecl() const;
|
||||
|
||||
private:
|
||||
const clang::VarDecl *global_var_decl_;
|
||||
private:
|
||||
bool SetupGlobalVar(abi_dump::GlobalVarDecl *global_varp,
|
||||
const std::string &source_file) const;
|
||||
};
|
||||
|
||||
} //end namespace abi_wrapper
|
||||
|
||||
@@ -29,11 +29,12 @@ using abi_wrapper::ABIWrapper;
|
||||
using abi_wrapper::FunctionDeclWrapper;
|
||||
using abi_wrapper::RecordDeclWrapper;
|
||||
using abi_wrapper::EnumDeclWrapper;
|
||||
using abi_wrapper::GlobalVarDeclWrapper;
|
||||
|
||||
HeaderASTVisitor::HeaderASTVisitor(
|
||||
abi_dump::TranslationUnit *tu_ptr,
|
||||
clang::MangleContext *mangle_contextp,
|
||||
const clang::ASTContext *ast_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *compiler_instance_p,
|
||||
const std::string ¤t_file_name,
|
||||
const std::set<std::string> &exported_headers,
|
||||
@@ -47,7 +48,7 @@ HeaderASTVisitor::HeaderASTVisitor(
|
||||
tu_decl_(tu_decl) { }
|
||||
|
||||
bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
|
||||
// Forward declaration
|
||||
// Skip forward declaration.
|
||||
if (!decl->isThisDeclarationADefinition()) {
|
||||
return true;
|
||||
}
|
||||
@@ -59,11 +60,11 @@ bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
|
||||
llvm::errs() << "Getting Record Decl failed\n";
|
||||
return false;
|
||||
}
|
||||
abi_dump::RecordDecl *record_declp = tu_ptr_->add_records();
|
||||
if (!record_declp) {
|
||||
abi_dump::RecordDecl *added_record_declp = tu_ptr_->add_records();
|
||||
if (!added_record_declp) {
|
||||
return false;
|
||||
}
|
||||
*record_declp = *wrapped_record_decl;
|
||||
*added_record_declp = *wrapped_record_decl;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -79,35 +80,57 @@ bool HeaderASTVisitor::VisitEnumDecl(const clang::EnumDecl *decl) {
|
||||
llvm::errs() << "Getting Enum Decl failed\n";
|
||||
return false;
|
||||
}
|
||||
abi_dump::EnumDecl *enum_declp = tu_ptr_->add_enums();
|
||||
if (!enum_declp) {
|
||||
abi_dump::EnumDecl *added_enum_declp = tu_ptr_->add_enums();
|
||||
if (!added_enum_declp) {
|
||||
return false;
|
||||
}
|
||||
*enum_declp = *wrapped_enum_decl;
|
||||
*added_enum_declp = *wrapped_enum_decl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HeaderASTVisitor::VisitFunctionDecl(const clang::FunctionDecl *decl) {
|
||||
FunctionDeclWrapper function_decl_wrapper(
|
||||
mangle_contextp_, ast_contextp_, cip_, decl);
|
||||
FunctionDeclWrapper function_decl_wrapper(mangle_contextp_, ast_contextp_,
|
||||
cip_, decl);
|
||||
std::unique_ptr<abi_dump::FunctionDecl> wrapped_function_decl =
|
||||
function_decl_wrapper.GetFunctionDecl();
|
||||
if (!wrapped_function_decl) {
|
||||
llvm::errs() << "Getting Function Decl failed\n";
|
||||
return false;
|
||||
}
|
||||
abi_dump::FunctionDecl *function_declp = tu_ptr_->add_functions();
|
||||
if (!function_declp) {
|
||||
abi_dump::FunctionDecl *added_function_declp = tu_ptr_->add_functions();
|
||||
if (!added_function_declp) {
|
||||
return false;
|
||||
}
|
||||
*function_declp = *wrapped_function_decl;
|
||||
*added_function_declp = *wrapped_function_decl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HeaderASTVisitor::VisitVarDecl(const clang::VarDecl *decl) {
|
||||
if(!decl->hasGlobalStorage()) {
|
||||
// Non global / static variable declarations don't need to be dumped.
|
||||
return true;
|
||||
}
|
||||
GlobalVarDeclWrapper global_var_decl_wrapper(mangle_contextp_, ast_contextp_,
|
||||
cip_, decl);
|
||||
std::unique_ptr<abi_dump::GlobalVarDecl> wrapped_global_var_decl =
|
||||
global_var_decl_wrapper.GetGlobalVarDecl();
|
||||
if (!wrapped_global_var_decl) {
|
||||
llvm::errs() << "Getting Global Var Decl failed\n";
|
||||
return false;
|
||||
}
|
||||
abi_dump::GlobalVarDecl *added_global_var_declp = tu_ptr_->add_global_vars();
|
||||
if (!added_global_var_declp) {
|
||||
return false;
|
||||
}
|
||||
*added_global_var_declp = *wrapped_global_var_decl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We don't need to recurse into Declarations which are not exported.
|
||||
bool HeaderASTVisitor::TraverseDecl(clang::Decl *decl) {
|
||||
if (!decl)
|
||||
if (!decl) {
|
||||
return true;
|
||||
}
|
||||
std::string source_file = ABIWrapper::GetDeclSourceFile(decl, cip_);
|
||||
if ((decl != tu_decl_) &&
|
||||
(exported_headers_.find(source_file) == exported_headers_.end())) {
|
||||
@@ -150,5 +173,5 @@ void HeaderASTConsumer::HandleVTable(clang::CXXRecordDecl *crd) {
|
||||
|
||||
void HeaderASTPPCallbacks::MacroDefined(const clang::Token ¯o_name_tok,
|
||||
const clang::MacroDirective *) {
|
||||
assert(macro_name_tok.isAnyIdentifier());
|
||||
assert(macro_name_tok.getLength() != 0);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class HeaderASTVisitor
|
||||
public:
|
||||
HeaderASTVisitor(abi_dump::TranslationUnit *tu_ptr,
|
||||
clang::MangleContext *mangle_contextp,
|
||||
const clang::ASTContext *ast_contextp,
|
||||
clang::ASTContext *ast_contextp,
|
||||
const clang::CompilerInstance *compiler_instance_p,
|
||||
const std::string ¤t_file_name,
|
||||
const std::set<std::string> &exported_headers,
|
||||
@@ -47,6 +47,8 @@ class HeaderASTVisitor
|
||||
|
||||
bool VisitEnumDecl(const clang::EnumDecl *decl);
|
||||
|
||||
bool VisitVarDecl(const clang::VarDecl *decl);
|
||||
|
||||
bool TraverseDecl(clang::Decl *decl);
|
||||
|
||||
// Enable recursive traversal of template instantiations.
|
||||
@@ -57,7 +59,7 @@ class HeaderASTVisitor
|
||||
private:
|
||||
abi_dump::TranslationUnit *tu_ptr_;
|
||||
clang::MangleContext *mangle_contextp_;
|
||||
const clang::ASTContext *ast_contextp_;
|
||||
clang::ASTContext *ast_contextp_;
|
||||
const clang::CompilerInstance *cip_;
|
||||
const std::string current_file_name_;
|
||||
const std::set<std::string> &exported_headers_;
|
||||
|
||||
@@ -63,6 +63,9 @@ class HeaderAbiLinker {
|
||||
bool LinkEnums(const abi_dump::TranslationUnit &dump_tu,
|
||||
abi_dump::TranslationUnit *linked_tu);
|
||||
|
||||
bool LinkGlobalVars(const abi_dump::TranslationUnit &dump_tu,
|
||||
abi_dump::TranslationUnit *linked_tu);
|
||||
|
||||
template <typename T>
|
||||
static inline bool LinkDecl(
|
||||
google::protobuf::RepeatedPtrField<T> *dst,
|
||||
@@ -75,6 +78,7 @@ class HeaderAbiLinker {
|
||||
std::set<std::string> record_decl_set_;
|
||||
std::set<std::string> function_decl_set_;
|
||||
std::set<std::string> enum_decl_set_;
|
||||
std::set<std::string> globvar_decl_set_;
|
||||
};
|
||||
|
||||
bool HeaderAbiLinker::LinkAndDump() {
|
||||
@@ -88,7 +92,8 @@ bool HeaderAbiLinker::LinkAndDump() {
|
||||
if (!google::protobuf::TextFormat::Parse(&text_is, &dump_tu) ||
|
||||
!LinkRecords(dump_tu, &linked_tu) ||
|
||||
!LinkFunctions(dump_tu, &linked_tu) ||
|
||||
!LinkEnums(dump_tu, &linked_tu)) {
|
||||
!LinkEnums(dump_tu, &linked_tu) ||
|
||||
!LinkGlobalVars(dump_tu, &linked_tu)) {
|
||||
llvm::errs() << "Failed to link elements\n";
|
||||
return false;
|
||||
}
|
||||
@@ -110,7 +115,7 @@ inline bool HeaderAbiLinker::LinkDecl(
|
||||
assert(link_set != nullptr);
|
||||
for (auto &&element : src) {
|
||||
// The element already exists in the linked dump. Skip.
|
||||
if (!link_set->insert(element.linker_set_key()).second) {
|
||||
if (!link_set->insert(element.basic_abi().linker_set_key()).second) {
|
||||
continue;
|
||||
}
|
||||
T *added_element = dst->Add();
|
||||
@@ -144,6 +149,13 @@ bool HeaderAbiLinker::LinkEnums(const abi_dump::TranslationUnit &dump_tu,
|
||||
dump_tu.enums());
|
||||
}
|
||||
|
||||
bool HeaderAbiLinker::LinkGlobalVars(const abi_dump::TranslationUnit &dump_tu,
|
||||
abi_dump::TranslationUnit *linked_tu) {
|
||||
assert(linked_tu != nullptr);
|
||||
return LinkDecl(linked_tu->mutable_global_vars(), &globvar_decl_set_,
|
||||
dump_tu.global_vars());
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv, "header-checker");
|
||||
|
||||
@@ -4,9 +4,9 @@ import "development/vndk/tools/header-checker/proto/abi_dump.proto";
|
||||
|
||||
package abi_diff;
|
||||
|
||||
message FieldDeclDiff {
|
||||
optional abi_dump.FieldDecl old = 1;
|
||||
optional abi_dump.FieldDecl new = 2;
|
||||
message RecordFieldDeclDiff {
|
||||
optional abi_dump.RecordFieldDecl old = 1;
|
||||
optional abi_dump.RecordFieldDecl new = 2;
|
||||
required uint32 index = 3;
|
||||
}
|
||||
|
||||
@@ -22,16 +22,23 @@ message CXXBaseSpecifierDiff {
|
||||
required uint32 index = 3;
|
||||
}
|
||||
|
||||
message CXXVTableDiff {
|
||||
optional abi_dump.VTableComponent old = 1;
|
||||
optional abi_dump.VTableComponent new = 2;
|
||||
required uint32 index = 3;
|
||||
}
|
||||
|
||||
message AccessDiff {
|
||||
required string old = 1;
|
||||
required string new = 2;
|
||||
required abi_dump.AccessSpecifier old = 1;
|
||||
required abi_dump.AccessSpecifier new = 2;
|
||||
}
|
||||
|
||||
message RecordDeclDiff {
|
||||
repeated FieldDeclDiff field_diffs = 1;
|
||||
repeated RecordFieldDeclDiff field_diffs = 1;
|
||||
repeated CXXBaseSpecifierDiff base_diffs = 2;
|
||||
required AccessDiff access_diff = 3;
|
||||
required string name = 4;
|
||||
repeated CXXVTableDiff vtable_diffs = 3;
|
||||
required AccessDiff access_diff = 4;
|
||||
required string name = 5;
|
||||
}
|
||||
|
||||
message EnumDeclDiff {
|
||||
@@ -40,16 +47,34 @@ message EnumDeclDiff {
|
||||
required string name = 3;
|
||||
}
|
||||
|
||||
message ReturnTypeDiff {
|
||||
required abi_dump.BasicNamedAndTypedDecl old = 1;
|
||||
required abi_dump.BasicNamedAndTypedDecl new = 2;
|
||||
}
|
||||
|
||||
message FunctionDeclDiff {
|
||||
required ReturnTypeDiff return_type_diffs = 1;
|
||||
}
|
||||
|
||||
message GlobalVarDeclDiff {
|
||||
required abi_dump.BasicNamedAndTypedDecl old = 1;
|
||||
required abi_dump.BasicNamedAndTypedDecl new = 2;
|
||||
}
|
||||
|
||||
message TranslationUnitDiff {
|
||||
// Differing Elements.
|
||||
repeated RecordDeclDiff records_diff = 1;
|
||||
repeated EnumDeclDiff enums_diff = 3;
|
||||
repeated EnumDeclDiff enums_diff = 2;
|
||||
repeated FunctionDeclDiff functions_diff = 3;
|
||||
repeated GlobalVarDeclDiff global_vars_diff = 4;
|
||||
// Removed Elements.
|
||||
repeated abi_dump.RecordDecl records_removed = 4;
|
||||
repeated abi_dump.FunctionDecl functions_removed = 5;
|
||||
repeated abi_dump.EnumDecl enums_removed = 6;
|
||||
repeated abi_dump.RecordDecl records_removed = 5;
|
||||
repeated abi_dump.FunctionDecl functions_removed = 6;
|
||||
repeated abi_dump.EnumDecl enums_removed = 7;
|
||||
repeated abi_dump.GlobalVarDecl global_vars_removed = 8;
|
||||
// Added Elements.
|
||||
repeated abi_dump.RecordDecl records_added = 7;
|
||||
repeated abi_dump.FunctionDecl functions_added = 8;
|
||||
repeated abi_dump.EnumDecl enums_added = 9;
|
||||
repeated abi_dump.RecordDecl records_added = 9;
|
||||
repeated abi_dump.FunctionDecl functions_added = 10;
|
||||
repeated abi_dump.EnumDecl enums_added = 11;
|
||||
repeated abi_dump.GlobalVarDecl global_vars_added = 12;
|
||||
}
|
||||
|
||||
@@ -2,72 +2,114 @@ syntax = "proto2";
|
||||
|
||||
package abi_dump;
|
||||
|
||||
message FunctionDecl {
|
||||
// Fully Qualified Name.
|
||||
optional string function_name = 1 [default = "NONE"];
|
||||
|
||||
// Mangled name.
|
||||
optional string mangled_function_name = 2 [default = "NONE"];
|
||||
|
||||
optional string source_file = 3;
|
||||
optional string parent_name = 4 [default = "NONE"];
|
||||
repeated string template_arguments = 5 ;
|
||||
repeated FieldDecl parameters = 6;
|
||||
optional string return_type = 7 [default = "VOID"];
|
||||
optional string access = 8 [default = "public"];
|
||||
optional uint32 template_kind = 9 [default = 0];
|
||||
optional TemplateInfo template_info = 10;
|
||||
optional string linker_set_key = 11 [default = "NONE"];
|
||||
message BasicTypeAbi {
|
||||
// The type's name. for eg : a record field's type.
|
||||
required string name = 1;
|
||||
// Optional since templated types will not have this information.
|
||||
optional uint64 size = 2 [default = 0];
|
||||
optional uint32 alignment = 3 [default = 0];
|
||||
}
|
||||
|
||||
message FieldDecl {
|
||||
optional string field_name = 1 [default = "NONE"];
|
||||
optional string field_type = 2 [default = "VOID"];
|
||||
optional string access = 3 [default = "public"];
|
||||
optional bool default_arg = 4 [default = false];
|
||||
optional string linker_set_key = 5 [default = "NONE"];
|
||||
enum AccessSpecifier {
|
||||
public_access = 1;
|
||||
private_access = 2;
|
||||
protected_access = 3;
|
||||
}
|
||||
|
||||
message BasicNamedAndTypedDecl {
|
||||
required BasicTypeAbi type_abi = 1;
|
||||
// The TypedDecl's name.
|
||||
required string name = 2;
|
||||
required AccessSpecifier access = 3;
|
||||
optional string linker_set_key = 4;
|
||||
}
|
||||
|
||||
message FunctionDecl {
|
||||
required BasicNamedAndTypedDecl basic_abi = 1;
|
||||
// Mangled name.
|
||||
required string mangled_function_name = 2;
|
||||
required string source_file = 3;
|
||||
repeated ParamDecl parameters = 4;
|
||||
optional TemplateInfo template_info = 5;
|
||||
}
|
||||
|
||||
message ParamDecl {
|
||||
required BasicNamedAndTypedDecl basic_abi = 1;
|
||||
required bool default_arg = 2;
|
||||
}
|
||||
|
||||
message RecordFieldDecl {
|
||||
// For future additions.
|
||||
required BasicNamedAndTypedDecl basic_abi = 1;
|
||||
}
|
||||
|
||||
message EnumFieldDecl {
|
||||
optional string enum_field_name = 1 [default = "NONE"];
|
||||
optional int64 enum_field_value = 2 [default = 0]; // assumption: fits int64
|
||||
optional string linker_set_key = 3 [default = "NONE"];
|
||||
required BasicNamedAndTypedDecl basic_abi = 1;
|
||||
required int64 enum_field_value = 2; // assumption: fits int64
|
||||
}
|
||||
|
||||
message TemplateInfo {
|
||||
repeated FieldDecl template_parameters = 1;
|
||||
repeated TemplateElement elements = 1;
|
||||
}
|
||||
|
||||
message TemplateElement {
|
||||
required BasicTemplateElementAbi basic_abi = 1;
|
||||
message BasicTemplateElementAbi {
|
||||
optional BasicTypeAbi type_abi = 1;
|
||||
optional string name = 2;
|
||||
required string linker_set_key = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message CXXBaseSpecifier {
|
||||
optional string fully_qualified_name = 1 [default = "NONE"];
|
||||
optional string access = 2 [default = "public"];
|
||||
optional bool is_virtual = 3 [default = false];
|
||||
optional string linker_set_key = 4 [default = "NONE"];
|
||||
required BasicNamedAndTypedDecl basic_abi = 1;
|
||||
required bool is_virtual = 2;
|
||||
}
|
||||
|
||||
message VTableComponent {
|
||||
enum Kind {
|
||||
VCallOffset = 0;
|
||||
VBaseOffset = 1;
|
||||
OffsetToTop = 2;
|
||||
RTTI = 3;
|
||||
FunctionPointer = 4;
|
||||
CompleteDtorPointer = 5;
|
||||
DeletingDtorPointer = 6;
|
||||
UnusedFunctionPointer = 7;
|
||||
}
|
||||
required Kind kind = 1;
|
||||
optional string mangled_component_name = 2 [default = ""];
|
||||
optional uint64 value = 3 [default = 0];
|
||||
}
|
||||
|
||||
message VTableLayout {
|
||||
repeated VTableComponent vtable_components = 1;
|
||||
}
|
||||
|
||||
message RecordDecl {
|
||||
repeated FieldDecl fields = 1;
|
||||
repeated CXXBaseSpecifier base_specifiers = 2;
|
||||
optional string fully_qualified_name = 3 [default = "NONE"];
|
||||
optional string source_file = 4 [default = "NONE"];
|
||||
optional uint32 template_kind = 5 [default = 0];
|
||||
optional TemplateInfo template_info = 6;
|
||||
optional string access = 7 [default = "public"];
|
||||
optional string linker_set_key = 8 [default = "NONE"];
|
||||
optional string mangled_record_name = 9 [default = "NONE"];
|
||||
required BasicNamedAndTypedDecl basic_abi = 1;
|
||||
repeated RecordFieldDecl fields = 2;
|
||||
repeated CXXBaseSpecifier base_specifiers = 3;
|
||||
required string source_file = 4;
|
||||
optional TemplateInfo template_info = 5;
|
||||
required string mangled_record_name = 6;
|
||||
optional VTableLayout vtable_layout = 7;
|
||||
}
|
||||
|
||||
message EnumDecl {
|
||||
optional string enum_name = 1 [default = "NONE"];
|
||||
optional string access = 2 [default = "public"];
|
||||
optional string enum_type = 3 [default = "int"];
|
||||
repeated EnumFieldDecl enum_fields = 4;
|
||||
optional string source_file = 5 [default = "NONE"];
|
||||
optional string linker_set_key = 6 [default = "NONE"];
|
||||
required BasicNamedAndTypedDecl basic_abi = 1;
|
||||
repeated EnumFieldDecl enum_fields = 2;
|
||||
required string source_file = 3;
|
||||
}
|
||||
|
||||
message GlobalVarDecl {
|
||||
required BasicNamedAndTypedDecl basic_abi = 1;
|
||||
required string source_file = 2;
|
||||
}
|
||||
|
||||
message TranslationUnit {
|
||||
repeated RecordDecl records = 1;
|
||||
repeated FunctionDecl functions = 2;
|
||||
repeated EnumDecl enums = 3;
|
||||
repeated GlobalVarDecl global_vars = 4;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "example2.h"
|
||||
#include "example1.h"
|
||||
|
||||
class NotIncluded {
|
||||
int not_included;
|
||||
|
||||
@@ -22,7 +22,7 @@ typedef const float_type cfloat_type;
|
||||
struct CPPHello : private HelloAgain, public ByeAgain<float_type> {
|
||||
const int cpp_foo;
|
||||
cfloat_type cpp_bar;
|
||||
|
||||
virtual int again() { return 0; }
|
||||
CPPHello() : cpp_foo(20), cpp_bar(1.234) { }
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
#ifndef EXAMPLE2_H_
|
||||
#define EXAMPLE2_H_
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "example3.h"
|
||||
|
||||
namespace test2 {
|
||||
struct HelloAgain {
|
||||
std::unique_ptr<HelloAgain> foo_again;
|
||||
std::vector<HelloAgain *> foo_again;
|
||||
int bar_again;
|
||||
static int hello_forever;
|
||||
virtual int again();
|
||||
};
|
||||
struct NowWeCrash;
|
||||
} // namespace test2
|
||||
@@ -16,6 +20,7 @@ enum Foo_s {
|
||||
foosbat
|
||||
};
|
||||
|
||||
|
||||
namespace test3 {
|
||||
template <typename T>
|
||||
struct ByeAgain {
|
||||
@@ -27,6 +32,7 @@ struct ByeAgain {
|
||||
template<>
|
||||
struct ByeAgain<float> {
|
||||
float foo_again;
|
||||
static int foo_forever;
|
||||
float bar_Again;
|
||||
float method_foo(int);
|
||||
};
|
||||
@@ -34,12 +40,11 @@ struct ByeAgain<float> {
|
||||
ByeAgain<double> double_bye;
|
||||
|
||||
template <typename T1, typename T2>
|
||||
bool Begin(T1 arg1, T2 arg2);
|
||||
template <>
|
||||
bool Begin<int, float>(int a, float b);
|
||||
bool Begin( T1 arg1, T2 arg2, int c);
|
||||
|
||||
bool End ( float arg = 2.0) {
|
||||
bool ret = Begin(arg, 2);
|
||||
return ret;
|
||||
bool ret = Begin(arg, 2, 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +62,7 @@ class Outer {
|
||||
};
|
||||
};
|
||||
|
||||
std::vector<int *> Dummy(int t);
|
||||
|
||||
} // namespace test3
|
||||
|
||||
|
||||
Reference in New Issue
Block a user