Added More Abi information.
Make Messages mirror clang Types better. Added type size and alignments for independent and complete types. Added vtable layout for CXXRecordDecls. Added abi information for variables with global storage. Added new return status to signify abi extension. Added checks for access specifier downgrades. Removed repeated code from header-abi-diff. Test: header-abi-dumper -o example1.dump tests/input/example1.cpp -I tests -- -x c++ -std=c++11 -I . -I ~/android/aosp/external/clang/lib/Headers Change-Id: I21b5a8ef6dff92ecae47a0b1c46342862c5e0ebd
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,
|
||||
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:
|
||||
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 1;
|
||||
}
|
||||
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