Merge changes I0d65bcdc,I7499691c
* changes:
vndk-def: Generalize FWK-ONLY-RS / VNDK-SP
vndk-def: Support Treble VNDK directory layout
diff --git a/vndk/tools/header-checker/Android.bp b/vndk/tools/header-checker/Android.bp
index 71cf175..3f29d06 100644
--- a/vndk/tools/header-checker/Android.bp
+++ b/vndk/tools/header-checker/Android.bp
@@ -24,11 +24,14 @@
cflags: [
"-Wall",
"-Werror",
- "-std=c++11",
"-DGOOGLE_PROTOBUF_NO_RTTI",
"-UNDEBUG"
],
+ cppflags: [
+ "-std=c++14",
+ ],
+
target: {
windows: {
enabled: false
@@ -40,8 +43,8 @@
name: "header-checker-lib-defaults",
static_libs: [
- "libclangTooling",
"libclangToolingCore",
+ "libclangTooling",
"libclangFrontendTool",
"libclangFrontend",
"libclangDriver",
@@ -134,8 +137,8 @@
],
static_libs: [
- "libheader-checker-proto",
"libheader-abi-util",
+ "libheader-checker-proto",
],
target: {
@@ -269,8 +272,14 @@
"libLLVMMCParser",
"libLLVMCore",
"libLLVMSupport",
+ "libheader-checker-proto",
],
+ shared_libs: [
+ "libprotobuf-cpp-full",
+ ],
+
+
cflags: [
"-Wcast-qual",
"-Wno-long-long",
diff --git a/vndk/tools/header-checker/README.md b/vndk/tools/header-checker/README.md
index 9412f60..242786a 100644
--- a/vndk/tools/header-checker/README.md
+++ b/vndk/tools/header-checker/README.md
@@ -7,6 +7,7 @@
## Usage
header-abi-dumper -o <dump-file> <source_file> -I <export-include-dir-1> -I
<export-include-dir-2>.. -- <cflags>
+ For options : header-abi-dumper --help
# VNDK Header Abi Linker
@@ -16,6 +17,7 @@
## Usage
header-abi-linker -o <linked-abi-dump> <abi-dump1> <abi-dump2> <abi-dump3> ...
+ For options : header-abi-linker --help
# VNDK Header Abi Diff
@@ -24,10 +26,13 @@
abi's exposed by the two dumps.
# Return Value
- 1: InCompatible
- 0: Compatible or Compatible Extension.
+ 0: Compatible
+ 1: Changes to APIs unreferenced by symbols in the .dynsym table
+ 4: Compatible Extension
+ 8: Incompatible
## Usage
header-abi-diff -old <old-abi-dump> -new <new-abi-dump> -o <report>
+ For options : header-abi-diff --help
diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff.cpp b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.cpp
index 45aac64..7d21566 100644
--- a/vndk/tools/header-checker/header-abi-diff/src/abi_diff.cpp
+++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.cpp
@@ -14,169 +14,262 @@
#include "abi_diff.h"
+#include <header_abi_util.h>
+
#include <llvm/Support/raw_ostream.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <memory>
-#include <fstream>
-#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
-CompatibilityStatus HeaderAbiDiff::GenerateCompatibilityReport() {
- abi_dump::TranslationUnit old_tu;
- abi_dump::TranslationUnit new_tu;
- std::ifstream old_input(old_dump_);
- std::ifstream new_input(new_dump_);
- google::protobuf::io::IstreamInputStream text_iso(&old_input);
- google::protobuf::io::IstreamInputStream text_isn(&new_input);
-
- if (!google::protobuf::TextFormat::Parse(&text_iso, &old_tu) ||
- !google::protobuf::TextFormat::Parse(&text_isn, &new_tu)) {
- llvm::errs() << "Failed to generate compatibility report\n";
+abi_util::CompatibilityStatusIR HeaderAbiDiff::GenerateCompatibilityReport() {
+ using abi_util::TextFormatToIRReader;
+ std::unique_ptr<abi_util::TextFormatToIRReader> old_reader =
+ TextFormatToIRReader::CreateTextFormatToIRReader("protobuf", old_dump_);
+ std::unique_ptr<abi_util::TextFormatToIRReader> new_reader =
+ TextFormatToIRReader::CreateTextFormatToIRReader("protobuf", new_dump_);
+ if (!old_reader || !new_reader || !old_reader->ReadDump() ||
+ !new_reader->ReadDump()) {
+ llvm::errs() << "Could not create Text Format readers\n";
::exit(1);
}
- return CompareTUs(old_tu, new_tu);
+ std::unique_ptr<abi_util::IRDiffDumper> ir_diff_dumper =
+ abi_util::IRDiffDumper::CreateIRDiffDumper("protobuf", cr_);
+ abi_util::CompatibilityStatusIR status =
+ CompareTUs(old_reader.get(), new_reader.get(), ir_diff_dumper.get());
+ if (!ir_diff_dumper->Dump()) {
+ llvm::errs() << "Could not dump diff report\n";
+ ::exit(1);
+ }
+ return status;
}
-CompatibilityStatus HeaderAbiDiff::CompareTUs(
- const abi_dump::TranslationUnit &old_tu,
- const abi_dump::TranslationUnit &new_tu) {
- std::unique_ptr<abi_diff::TranslationUnitDiff> diff_tu(
- new abi_diff::TranslationUnitDiff);
- CompatibilityStatus 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(),
- ignored_symbols_);
+template <typename F>
+static void AddTypesToMap(std::map<std::string, const abi_util::TypeIR *> *dst,
+ const abi_util::TextFormatToIRReader *tu, F func) {
+ AddToMap(dst, tu->GetRecordTypes(), func);
+ AddToMap(dst, tu->GetEnumTypes(), func);
+ AddToMap(dst, tu->GetPointerTypes(), func);
+ AddToMap(dst, tu->GetBuiltinTypes(), func);
+ AddToMap(dst, tu->GetArrayTypes(), func);
+ AddToMap(dst, tu->GetLvalueReferenceTypes(), func);
+ AddToMap(dst, tu->GetRvalueReferenceTypes(), func);
+ AddToMap(dst, tu->GetQualifiedTypes(), func);
+}
- CompatibilityStatus 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(), ignored_symbols_);
+abi_util::CompatibilityStatusIR HeaderAbiDiff::CompareTUs(
+ const abi_util::TextFormatToIRReader *old_tu,
+ const abi_util::TextFormatToIRReader *new_tu,
+ abi_util::IRDiffDumper *ir_diff_dumper) {
+ // Collect all old and new types in maps, so that we can refer to them by
+ // type name / linker_set_key later.
+ std::map<std::string, const abi_util::TypeIR *> old_types;
+ std::map<std::string, const abi_util::TypeIR *> new_types;
+ AddTypesToMap(&old_types, old_tu,
+ [](const abi_util::TypeIR *e) {return e->GetLinkerSetKey();});
+ AddTypesToMap(&new_types, new_tu,
+ [](const abi_util::TypeIR *e) {return e->GetLinkerSetKey();});
- CompatibilityStatus 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(),
- ignored_symbols_);
-
- CompatibilityStatus 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(), ignored_symbols_);
-
- CompatibilityStatus combined_status =
- record_status | function_status | enum_status | global_var_status;
-
- if (combined_status & CompatibilityStatus::INCOMPATIBLE) {
- combined_status = CompatibilityStatus::INCOMPATIBLE;
- } else if (combined_status & CompatibilityStatus::EXTENSION) {
- combined_status = CompatibilityStatus::EXTENSION;
- } else {
- combined_status = CompatibilityStatus::COMPATIBLE;
- }
- diff_tu->set_compatibility_status(combined_status);
- diff_tu->set_lib_name(lib_name_);
- diff_tu->set_arch(arch_);
- std::ofstream text_output(cr_);
- google::protobuf::io::OstreamOutputStream text_os(&text_output);
-
- if(!google::protobuf::TextFormat::Print(*diff_tu, &text_os)) {
- llvm::errs() << "Unable to dump report\n";
+ // Collect fills in added, removed ,unsafe and safe function diffs.
+ if (!CollectDynsymExportables(old_tu->GetFunctions(), new_tu->GetFunctions(),
+ old_tu->GetElfFunctions(),
+ new_tu->GetElfFunctions(),
+ old_types, new_types,
+ ir_diff_dumper) ||
+ !CollectDynsymExportables(old_tu->GetGlobalVariables(),
+ new_tu->GetGlobalVariables(),
+ old_tu->GetElfObjects(),
+ new_tu->GetElfObjects(),
+ old_types, new_types,
+ ir_diff_dumper)) {
+ llvm::errs() << "Unable to collect dynsym exportables\n";
::exit(1);
}
+
+ // By the time this call is reached, all referenced types have been diffed.
+ // So all additional calls on ir_diff_dumper get DiffKind::Unreferenced.
+ if (check_all_apis_ && !CollectUserDefinedTypes(old_tu, new_tu, old_types,
+ new_types, ir_diff_dumper)) {
+ llvm::errs() << "Unable to collect user defined types\n";
+ ::exit(1);
+ }
+
+ abi_util::CompatibilityStatusIR combined_status =
+ ir_diff_dumper->GetCompatibilityStatusIR();
+
+ ir_diff_dumper->AddLibNameIR(lib_name_);
+ ir_diff_dumper->AddArchIR(arch_);
+ ir_diff_dumper->AddCompatibilityStatusIR(combined_status);
return combined_status;
}
-template <typename T, typename TDiff>
-abi_diff::CompatibilityStatus 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,
- const std::set<std::string> &ignored_symbols) {
- assert(elements_added != nullptr);
- assert(elements_removed != nullptr);
- assert(elements_diff != nullptr);
+bool HeaderAbiDiff::CollectUserDefinedTypes(
+ const abi_util::TextFormatToIRReader *old_tu,
+ const abi_util::TextFormatToIRReader *new_tu,
+ const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+ abi_util::IRDiffDumper *ir_diff_dumper) {
+ return CollectUserDefinedTypesInternal(
+ old_tu->GetRecordTypes(), new_tu->GetRecordTypes(), old_types_map,
+ new_types_map, ir_diff_dumper) &&
+ CollectUserDefinedTypesInternal(old_tu->GetEnumTypes(),
+ new_tu->GetEnumTypes(), old_types_map,
+ new_types_map, ir_diff_dumper);
+}
- 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);
+template <typename T>
+bool HeaderAbiDiff::CollectUserDefinedTypesInternal(
+ const std::vector<T> &old_ud_types,
+ const std::vector<T> &new_ud_types,
+ const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+ abi_util::IRDiffDumper *ir_diff_dumper) {
+ // No elf information for records and enums.
+ std::map<std::string, const T *> old_ud_types_map;
+ std::map<std::string, const T *> new_ud_types_map;
- if (!PopulateRemovedElements(elements_removed, old_elements_map,
- new_elements_map, ignored_symbols) ||
- !PopulateRemovedElements(elements_added, new_elements_map,
- old_elements_map, ignored_symbols) ||
- !PopulateCommonElements(elements_diff, old_elements_map,
- new_elements_map, ignored_symbols)) {
+ abi_util::AddToMap(&old_ud_types_map, old_ud_types,
+ [](const T *e)
+ { return e->GetLinkerSetKey();});
+
+ abi_util::AddToMap(&new_ud_types_map, new_ud_types,
+ [](const T *e)
+ { return e->GetLinkerSetKey();});
+
+ return Collect(old_ud_types_map, new_ud_types_map, nullptr, nullptr,
+ ir_diff_dumper) &&
+ PopulateCommonElements(old_ud_types_map, new_ud_types_map, old_types_map,
+ new_types_map, ir_diff_dumper,
+ abi_util::IRDiffDumper::Unreferenced);
+}
+
+template <typename T, typename ElfSymbolType>
+bool HeaderAbiDiff::CollectDynsymExportables(
+ const std::vector<T> &old_exportables,
+ const std::vector<T> &new_exportables,
+ const std::vector<ElfSymbolType> &old_elf_symbols,
+ const std::vector<ElfSymbolType> &new_elf_symbols,
+ const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+ abi_util::IRDiffDumper *ir_diff_dumper) {
+ std::map<std::string, const T *> old_exportables_map;
+ std::map<std::string, const T *> new_exportables_map;
+ std::map<std::string, const abi_util::ElfSymbolIR *> old_elf_symbol_map;
+ std::map<std::string, const abi_util::ElfSymbolIR *> new_elf_symbol_map;
+
+ abi_util::AddToMap(&old_exportables_map, old_exportables,
+ [](const T *e)
+ { return e->GetLinkerSetKey();});
+ abi_util::AddToMap(&new_exportables_map, new_exportables,
+ [](const T *e)
+ { return e->GetLinkerSetKey();});
+ abi_util::AddToMap(
+ &old_elf_symbol_map, old_elf_symbols,
+ [](const ElfSymbolType *symbol) { return symbol->GetName();});
+ abi_util::AddToMap(
+ &new_elf_symbol_map, new_elf_symbols,
+ [](const ElfSymbolType *symbol) { return symbol->GetName();});
+
+ if (!Collect(old_exportables_map,
+ new_exportables_map, &old_elf_symbol_map, &new_elf_symbol_map,
+ ir_diff_dumper) ||
+ !CollectElfSymbols(old_elf_symbol_map, new_elf_symbol_map,
+ ir_diff_dumper) ||
+ !PopulateCommonElements(old_exportables_map, new_exportables_map,
+ old_types_map, new_types_map, ir_diff_dumper,
+ abi_util::IRDiffDumper::Referenced)) {
+ llvm::errs() << "Diffing dynsym exportables failed\n";
+ return false;
+ }
+ return true;
+}
+
+// Collect added and removed Elements. The elf set is needed since some symbols
+// might not have meta-data about them collected through the AST. For eg: if a
+// function Foo is defined in an assembly file on target A, but in a c/c++ file
+// on target B, foo does not have meta-data surrounding it when building target
+// A, this does not mean it is not in the ABI + API of the library.
+
+template <typename T>
+bool HeaderAbiDiff::Collect(
+ const std::map<std::string, const T*> &old_elements_map,
+ const std::map<std::string, const T*> &new_elements_map,
+ const std::map<std::string, const abi_util::ElfSymbolIR *> *old_elf_map,
+ const std::map<std::string, const abi_util::ElfSymbolIR *> *new_elf_map,
+ abi_util::IRDiffDumper *ir_diff_dumper) {
+ if (!PopulateRemovedElements(
+ old_elements_map, new_elements_map, new_elf_map, ir_diff_dumper,
+ abi_util::IRDiffDumper::Removed) ||
+ !PopulateRemovedElements(new_elements_map, old_elements_map, old_elf_map,
+ ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind::Added)) {
llvm::errs() << "Populating functions in report failed\n";
- ::exit(1);
+ return false;
}
- if (elements_diff->size() || elements_removed->size()) {
- return CompatibilityStatus::INCOMPATIBLE;
+ return true;
+}
+
+bool HeaderAbiDiff::CollectElfSymbols(
+ const std::map<std::string, const abi_util::ElfSymbolIR *> &old_symbols,
+ const std::map<std::string, const abi_util::ElfSymbolIR *> &new_symbols,
+ abi_util::IRDiffDumper *ir_diff_dumper) {
+ std::vector<const abi_util::ElfSymbolIR *> removed_elements =
+ abi_util::FindRemovedElements(old_symbols, new_symbols);
+
+ std::vector<const abi_util::ElfSymbolIR *> added_elements =
+ abi_util::FindRemovedElements(new_symbols, old_symbols);
+
+ return PopulateElfElements(removed_elements, ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind::Removed) &&
+ PopulateElfElements(added_elements, ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind::Added);
+}
+
+bool HeaderAbiDiff::PopulateElfElements(
+ std::vector<const abi_util::ElfSymbolIR *> &elf_elements,
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ for (auto &&elf_element : elf_elements) {
+ if (!ir_diff_dumper->AddElfSymbolMessageIR(elf_element, diff_kind)) {
+ return false;
+ }
}
- if (elements_added->size()) {
- return CompatibilityStatus::EXTENSION;
- }
- return CompatibilityStatus::COMPATIBLE;
+ return true;
}
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 std::set<std::string> &ignored_symbols) {
-
- 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->basic_abi().linker_set_key());
- if (new_element == new_elements_map.end()) {
- removed_elements.emplace_back(element);
- }
- }
- if (!DumpLoneElements(dst, removed_elements, ignored_symbols)) {
+ const std::map<std::string, const abi_util::ElfSymbolIR *> *elf_map,
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ std::vector<const T *> removed_elements =
+ abi_util::FindRemovedElements(old_elements_map, new_elements_map);
+ if (!DumpLoneElements(removed_elements, elf_map, ir_diff_dumper, diff_kind)) {
llvm::errs() << "Dumping added / removed element to report failed\n";
return false;
}
return true;
}
-template <typename T, typename TDiff>
+template <typename T>
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 std::set<std::string> &ignored_symbols) {
- 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();
- typename std::map<std::string, const T *>::const_iterator new_element =
- new_elements_map.begin();
- while (old_element != old_elements_map.end() &&
- new_element != new_elements_map.end()) {
- if (old_element->first == new_element->first) {
- common_elements.emplace_back(std::make_pair(
- old_element->second, new_element->second));
- old_element++;
- new_element++;
- continue;
- }
- if (old_element->first < new_element->first) {
- old_element++;
- } else {
- new_element++;
- }
- }
- if (!DumpDiffElements(dst, common_elements, ignored_symbols)) {
+ const std::map<std::string, const abi_util::TypeIR *> &old_types,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types,
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ std::vector<std::pair<const T *, const T *>> common_elements =
+ abi_util::FindCommonElements(old_elements_map, new_elements_map);
+ if (!DumpDiffElements(common_elements, old_types, new_types,
+ ir_diff_dumper, diff_kind)) {
llvm::errs() << "Dumping difference in common element to report failed\n";
return false;
}
@@ -185,48 +278,62 @@
template <typename T>
bool HeaderAbiDiff::DumpLoneElements(
- google::protobuf::RepeatedPtrField<T> *dst,
std::vector<const T *> &elements,
- const std::set<std::string> &ignored_symbols) {
+ const std::map<std::string, const abi_util::ElfSymbolIR *> *elf_map,
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ // If the record / enum has source file information, skip it.
+ std::smatch source_file_match;
+ std::regex source_file_regex(" at ");
for (auto &&element : elements) {
- if (abi_diff_wrappers::IgnoreSymbol<T>(element, ignored_symbols)) {
+ if (abi_diff_wrappers::IgnoreSymbol<T>(
+ element, ignored_symbols_,
+ [](const T *e) {return e->GetLinkerSetKey();})) {
continue;
}
- T *added_element = dst->Add();
- if (!added_element) {
- llvm::errs() << "Adding element diff failed\n";
+ // The element does exist in the .dynsym table, we do not have meta-data
+ // surrounding the element.
+ const std::string &element_linker_set_key = element->GetLinkerSetKey();
+ if ((elf_map != nullptr) &&
+ (elf_map->find(element_linker_set_key) != elf_map->end())) {
+ continue;
+ }
+ if (std::regex_search(element_linker_set_key, source_file_match,
+ source_file_regex)) {
+ continue;
+ }
+ if (!ir_diff_dumper->AddLinkableMessageIR(element, diff_kind)) {
+ llvm::errs() << "Couldn't dump added /removed element\n";
return false;
}
- *added_element = *element;
}
return true;
}
-template <typename T, typename TDiff>
+
+template <typename T>
bool HeaderAbiDiff::DumpDiffElements(
- google::protobuf::RepeatedPtrField<TDiff> *dst,
std::vector<std::pair<const T *,const T *>> &pairs,
- const std::set<std::string> &ignored_symbols) {
+ const std::map<std::string, const abi_util::TypeIR *> &old_types,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types,
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
for (auto &&pair : pairs) {
const T *old_element = pair.first;
const T *new_element = pair.second;
- // Not having inheritance from protobuf messages makes this
- // restrictive code.
- if (abi_diff_wrappers::IgnoreSymbol<T>(old_element, ignored_symbols)) {
+
+ if (abi_diff_wrappers::IgnoreSymbol<T>(
+ old_element, ignored_symbols_,
+ [](const T *e) {return e->GetLinkerSetKey();})) {
continue;
}
- abi_diff_wrappers::DiffWrapper<T, TDiff> diff_wrapper(old_element,
- new_element);
- std::unique_ptr<TDiff> decl_diff_ptr = diff_wrapper.Get();
- if (!decl_diff_ptr) {
- continue;
- }
- TDiff *added_element_diff = dst->Add();
- if (!added_element_diff) {
- llvm::errs() << "Adding element diff failed\n";
+ abi_diff_wrappers::DiffWrapper<T> diff_wrapper(old_element, new_element,
+ ir_diff_dumper, old_types,
+ new_types, &type_cache_);
+ if (!diff_wrapper.DumpDiff(diff_kind)) {
+ llvm::errs() << "Failed to diff elements\n";
return false;
}
- *added_element_diff = *decl_diff_ptr;
}
return true;
}
diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff.h b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.h
index df8a6d1..3cabc8b 100644
--- a/vndk/tools/header-checker/header-abi-diff/src/abi_diff.h
+++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.h
@@ -14,6 +14,8 @@
#include "abi_diff_wrappers.h"
+#include <ir_representation.h>
+
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#pragma clang diagnostic ignored "-Wnested-anon-types"
@@ -21,68 +23,102 @@
#include "proto/abi_diff.pb.h"
#pragma clang diagnostic pop
-#include <memory>
-#include <fstream>
-#include <iostream>
#include <string>
#include <vector>
-
-typedef abi_diff::CompatibilityStatus CompatibilityStatus;
-
class HeaderAbiDiff {
public:
HeaderAbiDiff(const std::string &lib_name, const std::string &arch,
const std::string &old_dump, const std::string &new_dump,
const std::string &compatibility_report,
- const std::set<std::string> &ignored_symbols)
+ const std::set<std::string> &ignored_symbols,
+ bool check_all_apis)
: lib_name_(lib_name), arch_(arch), old_dump_(old_dump),
new_dump_(new_dump), cr_(compatibility_report),
- ignored_symbols_(ignored_symbols) { }
+ ignored_symbols_(ignored_symbols), check_all_apis_(check_all_apis) { }
- CompatibilityStatus GenerateCompatibilityReport();
+ abi_util::CompatibilityStatusIR GenerateCompatibilityReport();
private:
- CompatibilityStatus CompareTUs(const abi_dump::TranslationUnit &old_tu,
- const abi_dump::TranslationUnit &new_tu);
- // Collect* methods fill in the diff_tu.
- template <typename T, typename TDiff>
- static CompatibilityStatus 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,
- const std::set<std::string> &ignored_symbols);
+ abi_util::CompatibilityStatusIR CompareTUs(
+ const abi_util::TextFormatToIRReader *old_tu,
+ const abi_util::TextFormatToIRReader *new_tu,
+ abi_util::IRDiffDumper *ir_diff_dumper);
+
+ template <typename T, typename ElfSymbolType>
+ bool CollectDynsymExportables(
+ const std::vector<T> &old_exportables,
+ const std::vector<T> &new_exportables,
+ const std::vector<ElfSymbolType> &old_elf_symbols,
+ const std::vector<ElfSymbolType> &new_elf_symbols,
+ const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+ abi_util::IRDiffDumper *ir_diff_dumper);
template <typename T>
- static inline void AddToMap(std::map<std::string, const T *> *dst,
- const google::protobuf::RepeatedPtrField<T> &src);
+ bool Collect(
+ const std::map<std::string, const T *> &old_elements_map,
+ const std::map<std::string, const T *> &new_elements_map,
+ const std::map<std::string, const abi_util::ElfSymbolIR *> *old_elf_map,
+ const std::map<std::string, const abi_util::ElfSymbolIR *> *new_elf_map,
+ abi_util::IRDiffDumper *ir_diff_dumper);
+
+ bool CollectElfSymbols(
+ const std::map<std::string, const abi_util::ElfSymbolIR *> &old_symbols,
+ const std::map<std::string, const abi_util::ElfSymbolIR *> &new_symbols,
+ abi_util::IRDiffDumper *ir_diff_dumper);
+
+ bool PopulateElfElements(
+ std::vector<const abi_util::ElfSymbolIR *> &elf_elements,
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
template <typename T>
- static bool PopulateRemovedElements(
- google::protobuf::RepeatedPtrField<T> *dst,
+ bool PopulateRemovedElements(
const std::map<std::string, const T *> &old_elements_map,
const std::map<std::string, const T *> &new_elements_map,
- const std::set<std::string> &ignored_symbols);
+ const std::map<std::string, const abi_util::ElfSymbolIR *> *elf_map,
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
- template <typename T, typename TDiff>
- static bool PopulateCommonElements(
- google::protobuf::RepeatedPtrField<TDiff> *dst,
+ template <typename T>
+ bool PopulateCommonElements(
const std::map<std::string, const T *> &old_elements_map,
const std::map<std::string, const T *> &new_elements_map,
- const std::set<std::string> &ignored_symbols);
+ const std::map<std::string, const abi_util::TypeIR *> &old_types,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types,
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
- template <typename T, typename TDiff>
- static bool DumpDiffElements(
- google::protobuf::RepeatedPtrField<TDiff> *dst,
+ template <typename T>
+ bool DumpDiffElements(
std::vector<std::pair<const T *, const T *>> &pairs,
- const std::set<std::string> &ignored_symbols);
+ const std::map<std::string, const abi_util::TypeIR *> &old_types,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types,
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
template <typename T>
- static bool DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
- std::vector<const T *> &elements,
- const std::set<std::string> &ignored_symbols);
+ bool DumpLoneElements(
+ std::vector<const T *> &elements,
+ const std::map<std::string, const abi_util::ElfSymbolIR *> *elf_map,
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+ bool CollectUserDefinedTypes(
+ const abi_util::TextFormatToIRReader *old_tu,
+ const abi_util::TextFormatToIRReader *new_tu,
+ const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+ abi_util::IRDiffDumper *ir_diff_dumper);
+
+ template <typename T>
+ bool CollectUserDefinedTypesInternal(
+ const std::vector<T> &old_ud_types,
+ const std::vector<T> &new_ud_types,
+ const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+ abi_util::IRDiffDumper *ir_diff_dumper);
private:
const std::string &lib_name_;
@@ -91,27 +127,6 @@
const std::string &new_dump_;
const std::string &cr_;
const std::set<std::string> &ignored_symbols_;
+ bool check_all_apis_;
+ std::set<std::string> type_cache_;
};
-
-template <typename T>
-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.basic_abi().linker_set_key(), &element));
- }
-}
-
-static inline CompatibilityStatus operator|(CompatibilityStatus f,
- CompatibilityStatus s) {
- return static_cast<CompatibilityStatus>(
- static_cast<std::underlying_type<CompatibilityStatus>::type>(f) |
- static_cast<std::underlying_type<CompatibilityStatus>::type>(s));
-}
-
-static inline CompatibilityStatus operator&(
- CompatibilityStatus f, CompatibilityStatus s) {
- return static_cast<CompatibilityStatus>(
- static_cast<std::underlying_type<CompatibilityStatus>::type>(f) &
- static_cast<std::underlying_type<CompatibilityStatus>::type>(s));
-}
diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.cpp b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.cpp
index e75d4ce..e9a0047 100644
--- a/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.cpp
+++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.cpp
@@ -14,52 +14,23 @@
#include "abi_diff_wrappers.h"
-#include<header_abi_util.h>
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-parameter"
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#include "proto/abi_dump.pb.h"
-#include "proto/abi_diff.pb.h"
-#pragma clang diagnostic pop
+#include <header_abi_util.h>
#include <llvm/Support/raw_ostream.h>
-using abi_diff::RecordDeclDiff;
-using abi_diff::RecordFieldDeclDiff;
-using abi_diff::CXXBaseSpecifierDiff;
-using abi_diff::CXXVTableDiff;
-using abi_diff::EnumDeclDiff;
-using abi_diff::ReturnTypeDiff;
-using abi_diff::ParamDeclDiff;
-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;
-using abi_dump::BasicNamedAndTypedDecl;
-
namespace abi_diff_wrappers {
-static bool IsAccessDownGraded(abi_dump::AccessSpecifier old_access,
- abi_dump::AccessSpecifier new_access) {
+static bool IsAccessDownGraded(abi_util::AccessSpecifierIR old_access,
+ abi_util::AccessSpecifierIR new_access) {
bool access_downgraded = false;
switch (old_access) {
- case abi_dump::AccessSpecifier::protected_access:
- if (new_access == abi_dump::AccessSpecifier::private_access) {
+ case abi_util::AccessSpecifierIR::ProtectedAccess:
+ if (new_access == abi_util::AccessSpecifierIR::PrivateAccess) {
access_downgraded = true;
}
break;
- case abi_dump::AccessSpecifier::public_access:
- if (new_access != abi_dump::AccessSpecifier::public_access) {
+ case abi_util::AccessSpecifierIR::PublicAccess:
+ if (new_access != abi_util::AccessSpecifierIR::PublicAccess) {
access_downgraded = true;
}
break;
@@ -69,255 +40,590 @@
return access_downgraded;
}
-static std::string CpptoCAdjustment(const std::string &type) {
- std::string adjusted_type_name =
- abi_util::FindAndReplace(type, "\\bstruct ", "");
-
- return adjusted_type_name;
+static std::string Unwind(const std::deque<std::string> *type_queue) {
+ if (!type_queue) {
+ return "";
+ }
+ std::string stack_str;
+ std::deque<std::string> type_queue_copy = *type_queue;
+ while (!type_queue_copy.empty()) {
+ stack_str += type_queue_copy.front() + "-> ";
+ type_queue_copy.pop_front();
+ }
+ return stack_str;
}
-static bool CompareTypeNames(const abi_dump::BasicTypeAbi &old_abi,
- const abi_dump::BasicTypeAbi &new_abi) {
- // Strip of leading 'struct' keyword from type names
- std::string old_type = old_abi.name();
- std::string new_type = new_abi.name();
- old_type = CpptoCAdjustment(old_type);
- new_type = CpptoCAdjustment(new_type);
- // TODO: Add checks for C++ built-in types vs C corresponding types.
- return old_type != new_type;
+void DiffWrapperBase::CompareEnumFields(
+ const std::vector<abi_util::EnumFieldIR> &old_fields,
+ const std::vector<abi_util::EnumFieldIR> &new_fields,
+ abi_util::EnumTypeDiffIR *enum_type_diff_ir) {
+ std::map<std::string, const abi_util::EnumFieldIR *> old_fields_map;
+ std::map<std::string, const abi_util::EnumFieldIR *> new_fields_map;
+ abi_util::AddToMap(&old_fields_map, old_fields,
+ [](const abi_util::EnumFieldIR *f)
+ {return f->GetName();});
+ abi_util::AddToMap(&new_fields_map, new_fields,
+ [](const abi_util::EnumFieldIR *f)
+ {return f->GetName();});
+ std::vector<const abi_util::EnumFieldIR *> removed_fields =
+ abi_util::FindRemovedElements(old_fields_map, new_fields_map);
+
+ std::vector<const abi_util::EnumFieldIR *> added_fields =
+ abi_util::FindRemovedElements(new_fields_map, old_fields_map);
+
+ enum_type_diff_ir->SetFieldsAdded(std::move(added_fields));
+
+ enum_type_diff_ir->SetFieldsRemoved(std::move(removed_fields));
+
+ std::vector<std::pair<
+ const abi_util::EnumFieldIR *, const abi_util::EnumFieldIR *>> cf =
+ abi_util::FindCommonElements(old_fields_map, new_fields_map);
+ std::vector<abi_util::EnumFieldDiffIR> enum_field_diffs;
+ for (auto &&common_fields : cf) {
+ if (common_fields.first->GetValue() != common_fields.second->GetValue()) {
+ abi_util::EnumFieldDiffIR enum_field_diff_ir(common_fields.first,
+ common_fields.second);
+ enum_field_diffs.emplace_back(std::move(enum_field_diff_ir));
+ }
+ }
+ enum_type_diff_ir->SetFieldsDiff(std::move(enum_field_diffs));
}
-static bool DiffBasicTypeAbi(const abi_dump::BasicTypeAbi &old_abi,
- const abi_dump::BasicTypeAbi &new_abi) {
- // We need to add a layer of indirection to account for issues when C and C++
- // are mixed. For example some types like wchar_t are in-built types for C++
- // but not for C. Another example would be clang reporting C structures
- // without the leading "struct" keyword when headers defining them are
- // included in C++ files.
- bool name_comparison = CompareTypeNames(old_abi, new_abi);
- 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;
+DiffStatus DiffWrapperBase::CompareEnumTypes(
+ const abi_util::EnumTypeIR *old_type, const abi_util::EnumTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ if (old_type->GetName() != new_type->GetName()) {
+ return DiffStatus::direct_diff;
+ }
+ auto enum_type_diff_ir = std::make_unique<abi_util::EnumTypeDiffIR>();
+ enum_type_diff_ir->SetName(old_type->GetName());
+ const std::string &old_underlying_type = old_type->GetUnderlyingType();
+ const std::string &new_underlying_type = new_type->GetUnderlyingType();
+ if (old_underlying_type != new_underlying_type) {
+ enum_type_diff_ir->SetUnderlyingTypeDiff(
+ std::make_unique<std::pair<std::string, std::string>>(
+ old_underlying_type, new_underlying_type));
+ }
+ CompareEnumFields(old_type->GetFields(), new_type->GetFields(),
+ enum_type_diff_ir.get());
+ if ((enum_type_diff_ir->IsExtended() ||
+ enum_type_diff_ir->IsIncompatible()) &&
+ !ir_diff_dumper_->AddDiffMessageIR(enum_type_diff_ir.get(),
+ Unwind(type_queue), diff_kind)) {
+ llvm::errs() << "AddDiffMessage on EnumTypeDiffIR failed\n";
+ ::exit(1);
+ }
+ return DiffStatus::no_diff;
}
-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()) ||
- (old_element.basic_abi().name() != new_element.basic_abi().name()) ||
- IsAccessDownGraded(old_element.basic_abi().access(),
- new_element.basic_abi().access());
+bool DiffWrapperBase::CompareVTableComponents(
+ const abi_util::VTableComponentIR &old_component,
+ const abi_util::VTableComponentIR &new_component) {
+ return old_component.GetName() == new_component.GetName() &&
+ old_component.GetValue() == new_component.GetValue() &&
+ old_component.GetKind() == new_component.GetKind();
}
-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()) ||
- (old_element.basic_abi().name() != new_element.basic_abi().name());
+bool DiffWrapperBase::CompareVTables(
+ const abi_util::RecordTypeIR *old_record,
+ const abi_util::RecordTypeIR *new_record) {
+
+ const std::vector<abi_util::VTableComponentIR> &old_components =
+ old_record->GetVTableLayout().GetVTableComponents();
+ const std::vector<abi_util::VTableComponentIR> &new_components =
+ new_record->GetVTableLayout().GetVTableComponents();
+ if (old_components.size() > new_components.size()) {
+ // Something in the vtable got deleted.
+ return false;
+ }
+ uint32_t i = 0;
+ while (i < old_components.size()) {
+ auto &old_element = old_components.at(i);
+ auto &new_element = new_components.at(i);
+ if (!CompareVTableComponents(old_element, new_element)) {
+ return false;
+ }
+ i++;
+ }
+ return true;
}
-template <>
-bool Diff<ParamDecl>(const ParamDecl &old_element,
- const ParamDecl &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());
+bool DiffWrapperBase::CompareSizeAndAlignment(
+ const abi_util::TypeIR *old_type,
+ const abi_util::TypeIR *new_type) {
+ return old_type->GetSize() == new_type->GetSize() &&
+ old_type->GetAlignment() == new_type->GetAlignment();
}
-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());
+std::unique_ptr<abi_util::RecordFieldDiffIR>
+DiffWrapperBase::CompareCommonRecordFields(
+ const abi_util::RecordFieldIR *old_field,
+ const abi_util::RecordFieldIR *new_field,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ if (old_field->GetOffset() != new_field->GetOffset() ||
+ // TODO: Should this be an inquality check instead ? Some compilers can
+ // make signatures dependant on absolute values of access specifiers.
+ IsAccessDownGraded(old_field->GetAccess(), new_field->GetAccess()) ||
+ CompareAndDumpTypeDiff(old_field->GetReferencedType(),
+ new_field->GetReferencedType(),
+ type_queue, diff_kind) ==
+ DiffStatus::direct_diff) {
+ return std::make_unique<abi_util::RecordFieldDiffIR>(old_field, new_field);
+ }
+ return nullptr;
}
-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.component_value() != new_element.component_value();
- return kind_comparison || mangled_name_comparison || value_comparison;
+std::pair<std::vector<abi_util::RecordFieldDiffIR>,
+ std::vector<const abi_util::RecordFieldIR *>>
+DiffWrapperBase::CompareRecordFields(
+ const std::vector<abi_util::RecordFieldIR> &old_fields,
+ const std::vector<abi_util::RecordFieldIR> &new_fields,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ std::pair<std::vector<abi_util::RecordFieldDiffIR>,
+ std::vector<const abi_util::RecordFieldIR *>> diffed_and_removed_fields;
+ std::map<std::string, const abi_util::RecordFieldIR *> old_fields_map;
+ std::map<std::string, const abi_util::RecordFieldIR *> new_fields_map;
+ std::map<uint64_t, const abi_util::RecordFieldIR *> old_fields_offset_map;
+ std::map<uint64_t, const abi_util::RecordFieldIR *> new_fields_offset_map;
+
+ abi_util::AddToMap(&old_fields_map, old_fields,
+ [](const abi_util::RecordFieldIR *f)
+ {return f->GetName();});
+ abi_util::AddToMap(&new_fields_map, new_fields,
+ [](const abi_util::RecordFieldIR *f)
+ {return f->GetName();});
+ abi_util::AddToMap(&old_fields_offset_map, old_fields,
+ [](const abi_util::RecordFieldIR *f)
+ {return f->GetOffset();});
+ abi_util::AddToMap(&new_fields_offset_map, new_fields,
+ [](const abi_util::RecordFieldIR *f)
+ {return f->GetOffset();});
+ // If a field is removed from the map field_name -> offset see if another
+ // field is present at the same offset and compare the size and type etc,
+ // remove it from the removed fields if they're compatible.
+ std::vector<const abi_util::RecordFieldIR *> removed_fields =
+ abi_util::FindRemovedElements(old_fields_map, new_fields_map);
+ uint32_t i = 0;
+ for (auto &&removed_field : removed_fields) {
+ // For the removed field, get the corresponding offset from the old map.
+ // Compare the fields from old map and new map if there's a direct diff,
+ // continue, otherwise remove that field from the removed fields map.
+ uint64_t old_field_offset = removed_field->GetOffset();
+ auto corresponding_field_at_same_offset =
+ new_fields_offset_map.find(old_field_offset);
+ // Correctly reported as removed.
+ if (corresponding_field_at_same_offset == new_fields_offset_map.end()) {
+ continue;
+ }
+ auto comparison_result = CompareCommonRecordFields(
+ removed_field, corresponding_field_at_same_offset->second,
+ type_queue, diff_kind);
+ if (comparison_result != nullptr) {
+ continue;
+ }
+ removed_fields.erase(removed_fields.begin() + i);
+ i++;
+ }
+ diffed_and_removed_fields.second = std::move(removed_fields);
+ std::vector<std::pair<
+ const abi_util::RecordFieldIR *, const abi_util::RecordFieldIR *>> cf =
+ abi_util::FindCommonElements(old_fields_map, new_fields_map);
+ for (auto &&common_fields : cf) {
+ std::unique_ptr<abi_util::RecordFieldDiffIR> diffed_field_ptr =
+ CompareCommonRecordFields(common_fields.first, common_fields.second,
+ type_queue, diff_kind);
+ if (diffed_field_ptr != nullptr) {
+ diffed_and_removed_fields.first.emplace_back(
+ std::move(*(diffed_field_ptr.release())));
+ }
+ }
+ return diffed_and_removed_fields;
}
-// This function fills in a *Diff Message's repeated field. For eg:
-// RecordDeclDiff's CXXBaseSpecifierDiff fields and well as FieldDeclDiff
-// fields.
-template <typename T, typename TDiff>
-template <typename Element, typename ElementDiff>
-bool DiffWrapperBase<T, TDiff>::GetElementDiffs(
- google::protobuf::RepeatedPtrField<ElementDiff> *dst,
- const google::protobuf::RepeatedPtrField<Element> &old_elements,
- const google::protobuf::RepeatedPtrField<Element> &new_elements) {
- bool differs = false;
- assert(dst != nullptr);
+bool DiffWrapperBase::CompareBaseSpecifiers(
+ const std::vector<abi_util::CXXBaseSpecifierIR> &old_base_specifiers,
+ const std::vector<abi_util::CXXBaseSpecifierIR> &new_base_specifiers,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ if (old_base_specifiers.size() != new_base_specifiers.size()) {
+ return false;
+ }
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 (Diff(old_element, new_element)) {
- ElementDiff *diff = dst->Add();
- Element *old_elementp = nullptr;
- Element *new_elementp = nullptr;
- if (!diff || !(old_elementp = diff->mutable_old()) ||
- !(new_elementp = diff->mutable_new_())) {
- llvm::errs() << "Failed to add diff element\n";
- ::exit(1);
- }
- *old_elementp = old_element;
- *new_elementp = new_element;
- diff->set_index(i);
- differs = true;
+ while (i < old_base_specifiers.size()) {
+ if (CompareAndDumpTypeDiff(old_base_specifiers.at(i).GetReferencedType(),
+ new_base_specifiers.at(i).GetReferencedType(),
+ type_queue, diff_kind) ==
+ DiffStatus::direct_diff ||
+ (old_base_specifiers.at(i).GetAccess() !=
+ new_base_specifiers.at(i).GetAccess())) {
+ return false;
}
i++;
- j++;
}
- if (old_elements.size() != new_elements.size()) {
- GetExtraElementDiffs(dst, i, j, old_elements, new_elements);
- differs = true;
- }
- return differs;
+ return true;
}
-template <typename T, typename TDiff>
-template <typename Element, typename ElementDiff>
-void DiffWrapperBase<T, TDiff>::GetExtraElementDiffs(
- google::protobuf::RepeatedPtrField<ElementDiff> *dst, int i, int j,
- const google::protobuf::RepeatedPtrField<Element> &old_elements,
- const google::protobuf::RepeatedPtrField<Element> &new_elements) {
- assert(dst != nullptr);
- while (i < old_elements.size()) {
- const Element &old_element = old_elements.Get(i);
- ElementDiff *diff = dst->Add();
- Element *old_elementp = nullptr;
- if (!diff || !(old_elementp = diff->mutable_old())) {
- llvm::errs() << "Failed to add diff element\n";
- ::exit(1);
- }
- *old_elementp = old_element;
- diff->set_index(i);
+void DiffWrapperBase::CompareTemplateInfo(
+ const std::vector<abi_util::TemplateElementIR> &old_template_elements,
+ const std::vector<abi_util::TemplateElementIR> &new_template_elements,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ uint32_t old_template_size = old_template_elements.size();
+ assert(old_template_size == new_template_elements.size());
+ uint32_t i = 0;
+ while (i < old_template_size) {
+ const abi_util::TemplateElementIR &old_template_element =
+ old_template_elements[i];
+ const abi_util::TemplateElementIR &new_template_element =
+ new_template_elements[i];
+ CompareAndDumpTypeDiff(old_template_element.GetReferencedType(),
+ new_template_element.GetReferencedType(),
+ type_queue, diff_kind);
i++;
- }
- while (j < new_elements.size()) {
- const Element &new_element = new_elements.Get(j);
- ElementDiff *diff = dst->Add();
- Element *new_elementp = nullptr;
- if (!diff || !(new_elementp = diff->mutable_new_())) {
- llvm::errs() << "Failed to add diff element\n";
- ::exit(1);
- }
- *new_elementp = new_element;
- diff->set_index(j);
- j++;
- }
+ }
}
-static bool DiffBasicNamedAndTypedDecl(BasicNamedAndTypedDecl *type_diff_old,
- BasicNamedAndTypedDecl *type_diff_new,
- const BasicNamedAndTypedDecl &old,
- const BasicNamedAndTypedDecl &new_) {
- assert(type_diff_old != nullptr);
- assert(type_diff_new != nullptr);
- if (DiffBasicTypeAbi(old.type_abi(), new_.type_abi()) ||
- IsAccessDownGraded(old.access(), new_.access())) {
- *(type_diff_old) = old;
- *(type_diff_new) = new_;
+DiffStatus DiffWrapperBase::CompareRecordTypes(
+ const abi_util::RecordTypeIR *old_type,
+ const abi_util::RecordTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ auto record_type_diff_ir = std::make_unique<abi_util::RecordTypeDiffIR>();
+ // Compare names.
+ if (old_type->GetName() != new_type->GetName()) {
+ // Do not dump anything since the record types themselves are fundamentally
+ // different.
+ return DiffStatus::direct_diff;
+ }
+ record_type_diff_ir->SetName(old_type->GetName());
+ if (old_type->GetAccess() != new_type->GetAccess()) {
+ record_type_diff_ir->SetAccessDiff(
+ std::make_unique<abi_util::AccessSpecifierDiffIR>(
+ old_type->GetAccess(), new_type->GetAccess()));
+ }
+
+ if (!CompareSizeAndAlignment(old_type, new_type)) {
+ record_type_diff_ir->SetTypeDiff(
+ std::make_unique<abi_util::TypeDiffIR>(
+ std::make_pair(old_type->GetSize(), new_type->GetSize()),
+ std::make_pair(old_type->GetAlignment(),
+ new_type->GetAlignment())));
+ }
+ if (!CompareVTables(old_type, new_type)) {
+ record_type_diff_ir->SetVTableLayoutDiff(
+ std::make_unique<abi_util::VTableLayoutDiffIR>(
+ old_type->GetVTableLayout(), new_type->GetVTableLayout()));
+ }
+ std::pair<std::vector<abi_util::RecordFieldDiffIR>,
+ std::vector<const abi_util::RecordFieldIR *>> field_diffs;
+ field_diffs = CompareRecordFields(old_type->GetFields(),
+ new_type->GetFields(), type_queue,
+ diff_kind);
+ record_type_diff_ir->SetFieldDiffs(std::move(field_diffs.first));
+ record_type_diff_ir->SetFieldsRemoved(std::move(field_diffs.second));
+ const std::vector<abi_util::CXXBaseSpecifierIR> &old_bases =
+ old_type->GetBases();
+ const std::vector<abi_util::CXXBaseSpecifierIR> &new_bases =
+ new_type->GetBases();
+
+ if (!CompareBaseSpecifiers(old_bases, new_bases, type_queue, diff_kind)) {
+ record_type_diff_ir->SetBaseSpecifierDiffs(
+ std::make_unique<abi_util::CXXBaseSpecifierDiffIR>(old_bases,
+ new_bases));
+ }
+ if (record_type_diff_ir->DiffExists() &&
+ !ir_diff_dumper_->AddDiffMessageIR(record_type_diff_ir.get(),
+ Unwind(type_queue), diff_kind)) {
+ llvm::errs() << "AddDiffMessage on record type failed\n";
+ ::exit(1);
+ } // No need to add a dump for an extension since records can't be "extended".
+
+ CompareTemplateInfo(old_type->GetTemplateElements(),
+ new_type->GetTemplateElements(),
+ type_queue, diff_kind);
+
+ return DiffStatus::no_diff;
+}
+
+DiffStatus DiffWrapperBase::CompareLvalueReferenceTypes(
+ const abi_util::LvalueReferenceTypeIR *old_type,
+ const abi_util::LvalueReferenceTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
+ new_type->GetReferencedType(),
+ type_queue, diff_kind);
+}
+
+DiffStatus DiffWrapperBase::CompareRvalueReferenceTypes(
+ const abi_util::RvalueReferenceTypeIR *old_type,
+ const abi_util::RvalueReferenceTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
+ new_type->GetReferencedType(),
+ type_queue, diff_kind);
+}
+
+DiffStatus DiffWrapperBase::CompareQualifiedTypes(
+ const abi_util::QualifiedTypeIR *old_type,
+ const abi_util::QualifiedTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ // If all the qualifiers are not the same, return direct_diff, else
+ // recursively compare the unqualified types.
+ if (old_type->IsConst() != new_type->IsConst() ||
+ old_type->IsVolatile() != new_type->IsVolatile() ||
+ old_type->IsRestricted() != new_type->IsRestricted()) {
+ return DiffStatus::direct_diff;
+ }
+ return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
+ new_type->GetReferencedType(),
+ type_queue, diff_kind);
+}
+
+DiffStatus DiffWrapperBase::ComparePointerTypes(
+ const abi_util::PointerTypeIR *old_type,
+ const abi_util::PointerTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ // The following need to be the same for two pointer types to be considered
+ // equivalent:
+ // 1) Number of pointer indirections are the same.
+ // 2) The ultimate pointee is the same.
+ assert(CompareSizeAndAlignment(old_type, new_type));
+ return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
+ new_type->GetReferencedType(),
+ type_queue, diff_kind);
+}
+
+DiffStatus DiffWrapperBase::CompareBuiltinTypes(
+ const abi_util::BuiltinTypeIR *old_type,
+ const abi_util::BuiltinTypeIR *new_type) {
+ // If the size, alignment and is_unsigned are the same, return no_diff
+ // else return direct_diff.
+ uint64_t old_signedness = old_type->IsUnsigned();
+ uint64_t new_signedness = new_type->IsUnsigned();
+
+ if (!CompareSizeAndAlignment(old_type, new_type) ||
+ old_signedness != new_signedness ||
+ old_type->IsIntegralType() != new_type->IsIntegralType()) {
+ return DiffStatus::direct_diff;
+ }
+ return DiffStatus::no_diff;
+}
+
+DiffStatus DiffWrapperBase::CompareFunctionParameters(
+ const std::vector<abi_util::ParamIR> &old_parameters,
+ const std::vector<abi_util::ParamIR> &new_parameters,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ size_t old_parameters_size = old_parameters.size();
+ if (old_parameters_size != new_parameters.size()) {
+ return DiffStatus::direct_diff;
+ }
+ uint64_t i = 0;
+ while (i < old_parameters_size) {
+ const abi_util::ParamIR &old_parameter = old_parameters.at(i);
+ const abi_util::ParamIR &new_parameter = new_parameters.at(i);
+ if ((CompareAndDumpTypeDiff(old_parameter.GetReferencedType(),
+ new_parameter.GetReferencedType(),
+ type_queue, diff_kind) ==
+ DiffStatus::direct_diff) ||
+ (old_parameter.GetIsDefault() != new_parameter.GetIsDefault())) {
+ return DiffStatus::direct_diff;
+ }
+ i++;
+ }
+ return DiffStatus::no_diff;
+}
+
+DiffStatus DiffWrapperBase::CompareAndDumpTypeDiff(
+ const abi_util::TypeIR *old_type, const abi_util::TypeIR *new_type,
+ abi_util::LinkableMessageKind kind, std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ if (kind == abi_util::LinkableMessageKind::BuiltinTypeKind) {
+ return CompareBuiltinTypes(
+ static_cast<const abi_util::BuiltinTypeIR *>(old_type),
+ static_cast<const abi_util::BuiltinTypeIR *>(new_type));
+ }
+
+ if (kind == abi_util::LinkableMessageKind::QualifiedTypeKind) {
+ return CompareQualifiedTypes(
+ static_cast<const abi_util::QualifiedTypeIR *>(old_type),
+ static_cast<const abi_util::QualifiedTypeIR *>(new_type),
+ type_queue, diff_kind);
+ }
+
+ if (kind == abi_util::LinkableMessageKind::EnumTypeKind) {
+ return CompareEnumTypes(
+ static_cast<const abi_util::EnumTypeIR *>(old_type),
+ static_cast<const abi_util::EnumTypeIR *>(new_type),
+ type_queue, diff_kind);
+
+ }
+
+ if (kind == abi_util::LinkableMessageKind::LvalueReferenceTypeKind) {
+ return CompareLvalueReferenceTypes(
+ static_cast<const abi_util::LvalueReferenceTypeIR *>(old_type),
+ static_cast<const abi_util::LvalueReferenceTypeIR *>(new_type),
+ type_queue, diff_kind);
+
+ }
+
+ if (kind == abi_util::LinkableMessageKind::RvalueReferenceTypeKind) {
+ return CompareRvalueReferenceTypes(
+ static_cast<const abi_util::RvalueReferenceTypeIR *>(old_type),
+ static_cast<const abi_util::RvalueReferenceTypeIR *>(new_type),
+ type_queue, diff_kind);
+ }
+
+ if (kind == abi_util::LinkableMessageKind::PointerTypeKind) {
+ return ComparePointerTypes(
+ static_cast<const abi_util::PointerTypeIR *>(old_type),
+ static_cast<const abi_util::PointerTypeIR *>(new_type),
+ type_queue, diff_kind);
+ }
+
+ if (kind == abi_util::LinkableMessageKind::RecordTypeKind) {
+ return CompareRecordTypes(
+ static_cast<const abi_util::RecordTypeIR *>(old_type),
+ static_cast<const abi_util::RecordTypeIR *>(new_type),
+ type_queue, diff_kind);
+ }
+ return DiffStatus::no_diff;
+}
+
+static DiffStatus CompareDistinctKindMessages(
+ const abi_util::TypeIR *old_type, const abi_util::TypeIR *new_type) {
+ // For these types to be considered ABI compatible, the very least requirement
+ // is that their sizes and alignments should be equal.
+ // TODO: Fill in
+ return DiffStatus::direct_diff;
+}
+
+DiffStatus DiffWrapperBase::CompareAndDumpTypeDiff(
+ const std::string &old_type_str, const std::string &new_type_str,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ // If either of the types are not found in their respective maps, the type
+ // was not exposed in a public header and we do a simple string comparison.
+ // Any diff found using a simple string comparison will be a direct diff.
+
+ // Check the map for types which have already been compared
+ bool same_type_str = (old_type_str == new_type_str);
+ if (same_type_str) {
+ // These types have already been diffed, return without further comparison.
+ if (!type_cache_->insert(old_type_str).second) {
+ return DiffStatus::no_diff;
+ }
+ type_queue->push_back(old_type_str);
+ }
+ std::map<std::string, const abi_util::TypeIR *>::const_iterator old_it =
+ old_types_.find(old_type_str);
+ std::map<std::string, const abi_util::TypeIR *>::const_iterator new_it =
+ new_types_.find(new_type_str);
+ if (old_it == old_types_.end() || new_it == new_types_.end()) {
+ // Do a simple string comparison.
+ if (!type_queue->empty()) {
+ type_queue->pop_back();
+ }
+ return (old_type_str == new_type_str) ?
+ DiffStatus::no_diff : DiffStatus::direct_diff;
+ }
+ abi_util::LinkableMessageKind old_kind =
+ old_it->second->GetKind();
+ abi_util::LinkableMessageKind new_kind =
+ new_it->second->GetKind();
+ DiffStatus diff_status = DiffStatus::no_diff;
+ if (old_kind != new_kind) {
+ diff_status = CompareDistinctKindMessages(old_it->second, new_it->second);
+ } else {
+ diff_status = CompareAndDumpTypeDiff(old_it->second , new_it->second ,
+ old_kind, type_queue, diff_kind);
+ }
+ if (!type_queue->empty()) {
+ type_queue->pop_back();
+ }
+ return diff_status;
+}
+
+template <>
+bool DiffWrapper<abi_util::RecordTypeIR>::DumpDiff(
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ std::deque<std::string> type_queue;
+ if (oldp_->GetName() != newp_->GetName()) {
+ llvm::errs() << "Comparing two different unreferenced records\n";
+ return false;
+ }
+ if (!type_cache_->insert(oldp_->GetName()).second) {
return true;
}
- return false;
+ CompareRecordTypes(oldp_, newp_, &type_queue, diff_kind);
+ return true;
}
template <>
-std::unique_ptr<RecordDeclDiff>
-DiffWrapper<RecordDecl, RecordDeclDiff>::Get() {
- std::unique_ptr<RecordDeclDiff> record_diff(new RecordDeclDiff());
- assert(oldp_->basic_abi().linker_set_key() ==
- newp_->basic_abi().linker_set_key());
- 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()) ||
- GetElementDiffs(vtdiffs, oldp_->vtable_layout().vtable_components(),
- newp_->vtable_layout().vtable_components()) ||
- DiffBasicNamedAndTypedDecl(
- record_diff->mutable_type_diff()->mutable_old(),
- record_diff->mutable_type_diff()->mutable_new_(),
- oldp_->basic_abi(), newp_->basic_abi())) {
- return record_diff;
+bool DiffWrapper<abi_util::EnumTypeIR>::DumpDiff(
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ std::deque<std::string> type_queue;
+ if (oldp_->GetName() != newp_->GetName()) {
+ llvm::errs() << "Comparing two different unreferenced enums\n";
+ return false;
}
- return nullptr;
+ if (!type_cache_->insert(oldp_->GetName()).second) {
+ return true;
+ }
+ CompareEnumTypes(oldp_, newp_, &type_queue, diff_kind);
+ return true;
}
template <>
-std::unique_ptr<EnumDeclDiff>
-DiffWrapper<EnumDecl, EnumDeclDiff>::Get() {
- std::unique_ptr<EnumDeclDiff> enum_diff(new EnumDeclDiff());
- assert(oldp_->basic_abi().linker_set_key() ==
- newp_->basic_abi().linker_set_key());
- google::protobuf::RepeatedPtrField<EnumFieldDeclDiff> *fdiffs =
- enum_diff->mutable_field_diffs();
- assert(fdiffs != nullptr);
- enum_diff->set_name(oldp_->basic_abi().name());
- if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields()) ||
- DiffBasicNamedAndTypedDecl(
- enum_diff->mutable_type_diff()->mutable_old(),
- enum_diff->mutable_type_diff()->mutable_new_(),
- oldp_->basic_abi(), newp_->basic_abi())) {
- return enum_diff;
+bool DiffWrapper<abi_util::GlobalVarIR>::DumpDiff(
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ std::deque<std::string> type_queue;
+ type_queue.push_back(oldp_->GetName());
+ DiffStatus type_diff = CompareAndDumpTypeDiff(oldp_->GetReferencedType(),
+ newp_->GetReferencedType(),
+ &type_queue, diff_kind);
+ DiffStatus access_diff = (oldp_->GetAccess() == newp_->GetAccess()) ?
+ DiffStatus::no_diff : DiffStatus::direct_diff;
+ if ((type_diff | access_diff) & DiffStatus::direct_diff) {
+ abi_util::GlobalVarDiffIR global_var_diff_ir(oldp_, newp_);
+ global_var_diff_ir.SetName(oldp_->GetName());
+ return ir_diff_dumper_->AddDiffMessageIR(&global_var_diff_ir,
+ Unwind(&type_queue), diff_kind);
}
- return nullptr;
+ return true;
}
template <>
-std::unique_ptr<FunctionDeclDiff>
-DiffWrapper<FunctionDecl, FunctionDeclDiff>::Get() {
- std::unique_ptr<FunctionDeclDiff> func_diff(new FunctionDeclDiff());
- google::protobuf::RepeatedPtrField<ParamDeclDiff> *pdiffs =
- func_diff->mutable_param_diffs();
- assert(func_diff->mutable_return_type_diffs() != nullptr);
- func_diff->set_name(oldp_->basic_abi().linker_set_key());
- if (DiffBasicNamedAndTypedDecl(
- func_diff->mutable_return_type_diffs()->mutable_old(),
- func_diff->mutable_return_type_diffs()->mutable_new_(),
- oldp_->basic_abi(), newp_->basic_abi()) ||
- GetElementDiffs(pdiffs, oldp_->parameters(), newp_->parameters())) {
- return func_diff;
- }
- return nullptr;
-}
+bool DiffWrapper<abi_util::FunctionIR>::DumpDiff(
+ abi_util::IRDiffDumper::DiffKind diff_kind) {
+ std::deque<std::string> type_queue;
+ type_queue.push_back(oldp_->GetName());
+ DiffStatus param_diffs = CompareFunctionParameters(oldp_->GetParameters(),
+ newp_->GetParameters(),
+ &type_queue, diff_kind);
+ DiffStatus return_type_diff =
+ CompareAndDumpTypeDiff(oldp_->GetReturnType(),
+ newp_->GetReturnType(),
+ &type_queue, diff_kind);
+ CompareTemplateInfo(oldp_->GetTemplateElements(),
+ newp_->GetTemplateElements(),
+ &type_queue, diff_kind);
-template <>
-std::unique_ptr<GlobalVarDeclDiff>
-DiffWrapper<GlobalVarDecl, GlobalVarDeclDiff>::Get() {
- std::unique_ptr<GlobalVarDeclDiff> global_var_diff(new GlobalVarDeclDiff());
- assert(global_var_diff->mutable_type_diff() != nullptr);
- if (DiffBasicNamedAndTypedDecl(
- global_var_diff->mutable_type_diff()->mutable_old(),
- global_var_diff->mutable_type_diff()->mutable_new_(),
- oldp_->basic_abi(), newp_->basic_abi())) {
- return global_var_diff;
+ if ((param_diffs == DiffStatus::direct_diff ||
+ return_type_diff == DiffStatus::direct_diff) ||
+ (oldp_->GetAccess() != newp_->GetAccess())) {
+ abi_util::FunctionDiffIR function_diff_ir(oldp_, newp_);
+ function_diff_ir.SetName(oldp_->GetName());
+ return ir_diff_dumper_->AddDiffMessageIR(&function_diff_ir,
+ Unwind(&type_queue), diff_kind);
}
- return nullptr;
+ return true;
}
-
} // abi_diff_wrappers
diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.h b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.h
index 8cf4699..9b0a7f5 100644
--- a/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.h
+++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.h
@@ -22,45 +22,160 @@
#include "proto/abi_diff.pb.h"
#pragma clang diagnostic pop
+#include <ir_representation.h>
+
+#include <deque>
+
namespace abi_diff_wrappers {
-template <typename T>
+template <typename T, typename F>
static bool IgnoreSymbol(const T *element,
- const std::set<std::string> &ignored_symbols) {
- return ignored_symbols.find(element->basic_abi().linker_set_key()) !=
+ const std::set<std::string> &ignored_symbols,
+ F func) {
+ return ignored_symbols.find(func(element)) !=
ignored_symbols.end();
}
-template <typename T, typename TDiff>
-class DiffWrapperBase {
- public:
- virtual std::unique_ptr<TDiff> Get() = 0 ;
- protected:
- DiffWrapperBase(const T *oldp, const T *newp) : oldp_(oldp), newp_(newp) { }
- template <typename Element, typename ElementDiff>
- bool GetElementDiffs(
- google::protobuf::RepeatedPtrField<ElementDiff> *dst,
- const google::protobuf::RepeatedPtrField<Element> &old_elements,
- const google::protobuf::RepeatedPtrField<Element> &new_elements);
-
- private:
- template <typename Element, typename ElementDiff>
- void GetExtraElementDiffs(
- google::protobuf::RepeatedPtrField<ElementDiff> *dst, int i, int j,
- const google::protobuf::RepeatedPtrField<Element> &old_elements,
- const google::protobuf::RepeatedPtrField<Element> &new_elements);
-
- protected:
- const T *oldp_;
- const T *newp_;
+enum DiffStatus {
+ // Previous stages of CompareAndTypeDiff should not dump the diff.
+ no_diff = 0,
+ // Previous stages of CompareAndTypeDiff should dump the diff if required.
+ direct_diff = 1,
};
-template <typename T, typename TDiff>
-class DiffWrapper : public DiffWrapperBase<T, TDiff> {
+class DiffWrapperBase {
public:
- DiffWrapper(const T *oldp, const T *newp)
- : DiffWrapperBase<T, TDiff>(oldp, newp) { }
- std::unique_ptr<TDiff> Get() override;
+ virtual bool DumpDiff(abi_util::IRDiffDumper::DiffKind diff_kind) = 0;
+ virtual ~DiffWrapperBase() { }
+ protected:
+ DiffWrapperBase(
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ const std::map<std::string, const abi_util::TypeIR *> &old_types,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types,
+ std::set<std::string> *type_cache)
+ : ir_diff_dumper_(ir_diff_dumper),
+ old_types_(old_types), new_types_(new_types),
+ type_cache_(type_cache) { }
+
+ DiffStatus CompareAndDumpTypeDiff(const std::string &old_type_str,
+ const std::string &new_type_str,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+ DiffStatus CompareAndDumpTypeDiff(
+ const abi_util::TypeIR *old_type, const abi_util::TypeIR *new_type,
+ abi_util::LinkableMessageKind kind, std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+
+ DiffStatus CompareRecordTypes(const abi_util::RecordTypeIR *old_type,
+ const abi_util::RecordTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+ DiffStatus CompareQualifiedTypes(const abi_util::QualifiedTypeIR *old_type,
+ const abi_util::QualifiedTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+ DiffStatus ComparePointerTypes(const abi_util::PointerTypeIR *old_type,
+ const abi_util::PointerTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+ DiffStatus CompareLvalueReferenceTypes(
+ const abi_util::LvalueReferenceTypeIR *old_type,
+ const abi_util::LvalueReferenceTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+ DiffStatus CompareRvalueReferenceTypes(
+ const abi_util::RvalueReferenceTypeIR *old_type,
+ const abi_util::RvalueReferenceTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+
+ DiffStatus CompareBuiltinTypes(const abi_util::BuiltinTypeIR *old_type,
+ const abi_util::BuiltinTypeIR *new_type);
+ static void CompareEnumFields(
+ const std::vector<abi_util::EnumFieldIR> &old_fields,
+ const std::vector<abi_util::EnumFieldIR> &new_fields,
+ abi_util::EnumTypeDiffIR *enum_type_diff_ir);
+
+ DiffStatus CompareEnumTypes(const abi_util::EnumTypeIR *old_type,
+ const abi_util::EnumTypeIR *new_type,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+ std::unique_ptr<abi_util::RecordFieldDiffIR> CompareCommonRecordFields(
+ const abi_util::RecordFieldIR *old_field,
+ const abi_util::RecordFieldIR *new_field,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+ std::pair<std::vector<abi_util::RecordFieldDiffIR>,
+ std::vector<const abi_util::RecordFieldIR *>>
+ CompareRecordFields(
+ const std::vector<abi_util::RecordFieldIR> &old_fields,
+ const std::vector<abi_util::RecordFieldIR> &new_fields,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+ DiffStatus CompareFunctionParameters(
+ const std::vector<abi_util::ParamIR> &old_parameters,
+ const std::vector<abi_util::ParamIR> &new_parameters,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+ bool CompareBaseSpecifiers(
+ const std::vector<abi_util::CXXBaseSpecifierIR> &old_base_specifiers,
+ const std::vector<abi_util::CXXBaseSpecifierIR> &new_base_specifiers,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+ bool CompareVTables(const abi_util::RecordTypeIR *old_record,
+ const abi_util::RecordTypeIR *new_record);
+
+ bool CompareVTableComponents(
+ const abi_util::VTableComponentIR &old_component,
+ const abi_util::VTableComponentIR &new_component);
+
+ void CompareTemplateInfo(
+ const std::vector<abi_util::TemplateElementIR> &old_template_elements,
+ const std::vector<abi_util::TemplateElementIR> &new_template_elements,
+ std::deque<std::string> *type_queue,
+ abi_util::IRDiffDumper::DiffKind diff_kind);
+
+
+ bool CompareSizeAndAlignment(const abi_util::TypeIR *old_ti,
+ const abi_util::TypeIR *new_ti);
+
+ template <typename DiffType, typename DiffElement>
+ bool AddToDiff(DiffType *mutable_diff, const DiffElement *oldp,
+ const DiffElement *newp,
+ std::deque<std::string> *type_queue = nullptr);
+ protected:
+ abi_util::IRDiffDumper *ir_diff_dumper_;
+ const std::map<std::string, const abi_util::TypeIR *> &old_types_;
+ const std::map<std::string, const abi_util::TypeIR *> &new_types_;
+ std::set<std::string> *type_cache_;
+};
+
+template <typename T>
+class DiffWrapper : public DiffWrapperBase {
+ public:
+ DiffWrapper(const T *oldp, const T *newp,
+ abi_util::IRDiffDumper *ir_diff_dumper,
+ const std::map<std::string, const abi_util::TypeIR *> &old_types,
+ const std::map<std::string, const abi_util::TypeIR *> &new_types,
+ std::set<std::string> *type_cache)
+ : DiffWrapperBase(ir_diff_dumper, old_types, new_types, type_cache),
+ oldp_(oldp), newp_(newp) { }
+ bool DumpDiff(abi_util::IRDiffDumper::DiffKind diff_kind) override;
+ private:
+ const T *oldp_;
+ const T *newp_;
};
} // abi_diff_wrappers
diff --git a/vndk/tools/header-checker/header-abi-diff/src/header_abi_diff.cpp b/vndk/tools/header-checker/header-abi-diff/src/header_abi_diff.cpp
index 7281c09..813ea75 100644
--- a/vndk/tools/header-checker/header-abi-diff/src/header_abi_diff.cpp
+++ b/vndk/tools/header-checker/header-abi-diff/src/header_abi_diff.cpp
@@ -14,6 +14,8 @@
#include "abi_diff.h"
+#include <fstream>
+
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_ostream.h>
@@ -49,6 +51,12 @@
"advice-only", llvm::cl::desc("Advisory mode only"), llvm::cl::Optional,
llvm::cl::cat(header_checker_category));
+static llvm::cl::opt<bool> check_all_apis(
+ "check-all-apis",
+ llvm::cl::desc("All apis, whether referenced or not, by exported symbols in"
+ " the dynsym table of a shared library are checked"),
+ llvm::cl::Optional, llvm::cl::cat(header_checker_category));
+
static llvm::cl::opt<bool> suppress_local_warnings(
"suppress_local_warnings", llvm::cl::desc("suppress local warnings"),
llvm::cl::Optional, llvm::cl::cat(header_checker_category));
@@ -58,6 +66,13 @@
llvm::cl::desc("Do not return a non zero status on extensions"),
llvm::cl::Optional, llvm::cl::cat(header_checker_category));
+static llvm::cl::opt<bool> allow_unreferenced_changes(
+ "allow-unreferenced-changes",
+ llvm::cl::desc("Do not return a non zero status on changes to data"
+ " structures which are not directly referenced by exported"
+ " APIs."),
+ llvm::cl::Optional, llvm::cl::cat(header_checker_category));
+
static std::set<std::string> LoadIgnoredSymbols(std::string &symbol_list_path) {
std::ifstream symbol_ifstream(symbol_list_path);
std::set<std::string> ignored_symbols;
@@ -80,38 +95,50 @@
ignored_symbols = LoadIgnoredSymbols(ignore_symbol_list);
}
HeaderAbiDiff judge(lib_name, arch, old_dump, new_dump, compatibility_report,
- ignored_symbols);
+ ignored_symbols, check_all_apis);
- CompatibilityStatus status = judge.GenerateCompatibilityReport();
+ abi_util::CompatibilityStatusIR status = judge.GenerateCompatibilityReport();
std::string status_str = "";
- switch (status) {
- case CompatibilityStatus::INCOMPATIBLE:
- status_str = "broken";
- break;
- case CompatibilityStatus::EXTENSION:
- status_str = "extended";
- break;
- default:
- break;
- }
+ std::string unreferenced_change_str = "";
+ std::string error_or_warning_str = "\033[36;1mwarning: \033[0m";
+ if (status == abi_util::CompatibilityStatusIR::Incompatible) {
+ error_or_warning_str = "\033[31;1merror: \033[0m";
+ status_str = " INCOMPATIBLE CHANGES";
+ } else if (status & abi_util::CompatibilityStatusIR::Extension) {
+ status_str = "EXTENDING CHANGES";
+ }
+ if (status & abi_util::CompatibilityStatusIR::UnreferencedChanges) {
+ unreferenced_change_str = ", changes in exported headers, which are";
+ unreferenced_change_str += " not directly referenced by exported symbols.";
+ unreferenced_change_str += " This MIGHT be an ABI breaking change due to";
+ unreferenced_change_str += " internal typecasts.";
+
+ }
if (!suppress_local_warnings && status) {
llvm::errs() << "******************************************************\n"
- << "VNDK Abi "
+ << error_or_warning_str
+ << "VNDK library: "
+ << lib_name
+ << "'s ABI has "
<< status_str
- << ":"
+ << unreferenced_change_str
<< " Please check compatiblity report at : "
<< compatibility_report << "\n"
- << "*****************************************************\n";
+ << "******************************************************\n";
+ }
+
+ if ((allow_extensions &&
+ (status & abi_util::CompatibilityStatusIR::Extension)) ||
+ (allow_unreferenced_changes &&
+ (status & abi_util::CompatibilityStatusIR::UnreferencedChanges))) {
+ return abi_util::CompatibilityStatusIR::Compatible;
}
if (advice_only) {
- return CompatibilityStatus::COMPATIBLE;
+ return abi_util::CompatibilityStatusIR::Compatible;
}
- if (allow_extensions && status == CompatibilityStatus::EXTENSION) {
- return CompatibilityStatus::COMPATIBLE;
- }
return status;
}
diff --git a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp
index 32bb3c7..b0d4e23 100644
--- a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp
+++ b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp
@@ -28,10 +28,26 @@
ABIWrapper::ABIWrapper(
clang::MangleContext *mangle_contextp,
clang::ASTContext *ast_contextp,
- const clang::CompilerInstance *cip)
+ const clang::CompilerInstance *cip,
+ std::set<std::string> *type_cache,
+ abi_util::IRDumper *ir_dumper,
+ std::map<const clang::Decl *, std::string> &decl_to_source_cache)
: cip_(cip),
mangle_contextp_(mangle_contextp),
- ast_contextp_(ast_contextp) { }
+ ast_contextp_(ast_contextp),
+ type_cache_(type_cache),
+ ir_dumper_(ir_dumper),
+ decl_to_source_file_cache_(decl_to_source_cache) { }
+
+std::string ABIWrapper::GetCachedDeclSourceFile(
+ const clang::Decl *decl, const clang::CompilerInstance *cip) {
+ assert(decl != nullptr);
+ auto result = decl_to_source_file_cache_.find(decl);
+ if (result == decl_to_source_file_cache_.end()) {
+ return GetDeclSourceFile(decl, cip);
+ }
+ return result->second;
+}
std::string ABIWrapper::GetDeclSourceFile(const clang::Decl *decl,
const clang::CompilerInstance *cip) {
@@ -53,85 +69,174 @@
return file_abs_path;
}
-abi_dump::AccessSpecifier ABIWrapper::AccessClangToDump(
- const clang::AccessSpecifier sp) const {
+static abi_util::AccessSpecifierIR AccessClangToIR(
+ const clang::AccessSpecifier sp) {
switch (sp) {
case clang::AS_private: {
- return abi_dump::AccessSpecifier::private_access;
+ return abi_util::AccessSpecifierIR::PrivateAccess;
break;
}
case clang::AS_protected: {
- return abi_dump::AccessSpecifier::protected_access;
+ return abi_util::AccessSpecifierIR::ProtectedAccess;
break;
}
default: {
- return abi_dump::AccessSpecifier::public_access;
+ return abi_util::AccessSpecifierIR::PublicAccess;
break;
}
}
}
-// Dumping the size and alignment is optional. This is since clang can lazily
-// instantiate records as incomplete and therefore their sizes 'may' not be
-// computable. b/62307940
-bool ABIWrapper::SetupBasicTypeAbi(abi_dump::BasicTypeAbi *type_abi,
- const clang::QualType type,
- bool dump_size) const {
- if (!type_abi) {
+// Get type 'referenced' by qual_type. Referenced type implies, in order:
+// 1) Strip off all qualifiers if qual_type has CVR qualifiers.
+// 2) Strip off a pointer level if qual_type is a pointer.
+// 3) Strip off the reference if qual_type is a reference.
+// Note: qual_type is expected to be a canonical type.
+clang::QualType ABIWrapper::GetReferencedType(const clang::QualType qual_type) {
+ const clang::Type *type_ptr = qual_type.getTypePtr();
+ if (qual_type.hasLocalQualifiers()) {
+ return qual_type.getLocalUnqualifiedType();
+ }
+ if (type_ptr->isPointerType()) {
+ return type_ptr->getPointeeType();
+ }
+ if (type_ptr->isArrayType()) {
+ return
+ type_ptr->getArrayElementTypeNoTypeQual()->getCanonicalTypeInternal();
+ }
+ return qual_type.getNonReferenceType();
+}
+
+bool ABIWrapper::CreateExtendedType(
+ clang::QualType qual_type,
+ abi_util::TypeIR *typep) {
+ std::string type_name = QualTypeToString(qual_type);
+ if (!type_cache_->insert(type_name).second) {
+ return true;
+ }
+ const clang::QualType canonical_type = qual_type.getCanonicalType();
+ return CreateBasicNamedAndTypedDecl(canonical_type, typep, "");
+}
+
+//This overload takes in a qualtype and adds its information to the abi-dump on
+//its own.
+bool ABIWrapper::CreateBasicNamedAndTypedDecl(clang::QualType qual_type,
+ const std::string &source_file) {
+ std::string type_name = QualTypeToString(qual_type);
+ const clang::QualType canonical_type = qual_type.getCanonicalType();
+ const clang::Type *base_type = canonical_type.getTypePtr();
+ bool is_ptr = base_type->isPointerType();
+ bool is_reference = base_type->isReferenceType();
+ bool is_array = base_type->isArrayType();
+ bool is_builtin = base_type->isBuiltinType();
+ bool has_referenced_type =
+ is_ptr || is_reference || is_array ||
+ canonical_type.hasLocalQualifiers() || is_builtin;
+ if (!has_referenced_type || !type_cache_->insert(type_name).second) {
+ return true;
+ }
+ // Do something similar to what is being done right now. Create an object
+ // extending Type and return a pointer to that and pass it to CreateBasic...
+ // CreateBasic...(qualtype, Type *) fills in size, alignemnt etc.
+ std::unique_ptr<abi_util::TypeIR> typep = SetTypeKind(canonical_type,
+ source_file);
+ if (!base_type->isVoidType() && !typep) {
return false;
}
- const clang::QualType canonical_type = type.getCanonicalType();
- type_abi->set_name(QualTypeToString(canonical_type));
+ return CreateBasicNamedAndTypedDecl(canonical_type, typep.get(),
+ source_file) &&
+ ir_dumper_->AddLinkableMessageIR(typep.get());
+}
+
+// CreateBasicNamedAndTypedDecl creates a BasicNamedAndTypedDecl : that'll
+// include all the generic information a basic type will have:
+// abi_dump::BasicNamedAndTypedDecl. Other methods fill in more specific
+// information, eg: RecordDecl, EnumDecl.
+bool ABIWrapper::CreateBasicNamedAndTypedDecl(
+ clang::QualType canonical_type,
+ abi_util::TypeIR *typep, const std::string &source_file) {
// Cannot determine the size and alignment for template parameter dependent
// types as well as incomplete types.
const clang::Type *base_type = canonical_type.getTypePtr();
+ assert(base_type != nullptr);
clang::Type::TypeClass type_class = base_type->getTypeClass();
// Temporary Hack for auto type sizes. Not determinable.
- if (dump_size && base_type && !(base_type->isDependentType()) &&
- !(base_type->isIncompleteType()) && (type_class != clang::Type::Auto)) {
+ if ((type_class != clang::Type::Auto) && !base_type->isIncompleteType() &&
+ !(base_type->isDependentType())) {
std::pair<clang::CharUnits, clang::CharUnits> size_and_alignment =
ast_contextp_->getTypeInfoInChars(canonical_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);
+ size_t size = size_and_alignment.first.getQuantity();
+ size_t alignment = size_and_alignment.second.getQuantity();
+ typep->SetSize(size);
+ typep->SetAlignment(alignment);
}
- return true;
+ typep->SetName(QualTypeToString(canonical_type));
+ typep->SetLinkerSetKey(QualTypeToString(canonical_type));
+ // default values are false, we don't set them since explicitly doing that
+ // makes the abi dumps more verbose.
+ // This type has a reference type if its a pointer / reference OR it has CVR
+ // qualifiers.
+ clang::QualType referenced_type = GetReferencedType(canonical_type);
+ typep->SetReferencedType(QualTypeToString(referenced_type));
+ // Create the type for referenced type.
+ return CreateBasicNamedAndTypedDecl(referenced_type, source_file);
}
-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,
- bool dump_size) 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, dump_size);
-}
-
-static bool ShouldDumpSize(clang::QualType qt) {
- const clang::Type *type_ptr = qt.getTypePtr();
- assert(type_ptr != nullptr);
- if (type_ptr->isBuiltinType() || type_ptr->isPointerType()) {
- return true;
- }
- return false;
-}
-
-std::string ABIWrapper::GetTypeLinkageName(const clang::Type *typep) const {
+std::string ABIWrapper::GetTypeLinkageName(const clang::Type *typep) {
assert(typep != nullptr);
clang::QualType qt = typep->getCanonicalTypeInternal();
return QualTypeToString(qt);
}
+std::unique_ptr<abi_util::TypeIR> ABIWrapper::SetTypeKind(
+ const clang::QualType canonical_type, const std::string &source_file) {
+ if (canonical_type.hasLocalQualifiers()) {
+ auto qual_type_ir =
+ std::make_unique<abi_util::QualifiedTypeIR>();
+ qual_type_ir->SetConstness(canonical_type.isConstQualified());
+ qual_type_ir->SetRestrictedness(canonical_type.isRestrictQualified());
+ qual_type_ir->SetVolatility(canonical_type.isVolatileQualified());
+ qual_type_ir->SetSourceFile(source_file);
+ return qual_type_ir;
+ }
+ const clang::Type *type_ptr = canonical_type.getTypePtr();
+ if (type_ptr->isPointerType()) {
+ auto pointer_type_ir = std::make_unique<abi_util::PointerTypeIR>();
+ pointer_type_ir->SetSourceFile(source_file);
+ return pointer_type_ir;
+ }
+ if (type_ptr->isLValueReferenceType()) {
+ auto lvalue_reference_type_ir =
+ std::make_unique<abi_util::LvalueReferenceTypeIR>();
+ lvalue_reference_type_ir->SetSourceFile(source_file);
+ return lvalue_reference_type_ir;
+ }
+ if (type_ptr->isRValueReferenceType()) {
+ auto rvalue_reference_type_ir =
+ std::make_unique<abi_util::RvalueReferenceTypeIR>();
+ rvalue_reference_type_ir->SetSourceFile(source_file);
+ return rvalue_reference_type_ir;
+ }
+ if (type_ptr->isArrayType()) {
+ auto array_type_ir = std::make_unique<abi_util::ArrayTypeIR>();
+ array_type_ir->SetSourceFile(source_file);
+ return array_type_ir;
+ }
+ if (type_ptr->isEnumeralType()) {
+ return std::make_unique<abi_util::EnumTypeIR>();
+ }
+ if (type_ptr->isRecordType()) {
+ return std::make_unique<abi_util::RecordTypeIR>();
+ }
+ if (type_ptr->isBuiltinType()) {
+ auto builtin_type_ir = std::make_unique<abi_util::BuiltinTypeIR>();
+ builtin_type_ir->SetSignedness(type_ptr->isUnsignedIntegerType());
+ builtin_type_ir->SetIntegralType(type_ptr->isIntegralType(*ast_contextp_));
+ return builtin_type_ir;
+ }
+ return nullptr;
+}
+
std::string ABIWrapper::GetMangledNameDecl(
const clang::NamedDecl *decl, clang::MangleContext *mangle_contextp) {
if (!mangle_contextp->shouldMangleDeclName(decl)) {
@@ -145,36 +250,8 @@
return mangled_name;
}
-bool ABIWrapper::SetupTemplateParamNames(
- abi_dump::TemplateInfo *tinfo,
- clang::TemplateParameterList *pl) const {
- if (tinfo->elements_size() > 0) {
- return true;
- }
-
- clang::TemplateParameterList::iterator template_it = pl->begin();
- while (template_it != pl->end()) {
- abi_dump::TemplateElement *template_parameterp =
- tinfo->add_elements();
- if (!template_parameterp) {
- return false;
- }
- 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;
-}
-
std::string ABIWrapper::GetTagDeclQualifiedName(
- const clang::TagDecl *decl) const {
+ const clang::TagDecl *decl) {
if (decl->getTypedefNameForAnonDecl()) {
return decl->getTypedefNameForAnonDecl()->getQualifiedNameAsString();
}
@@ -182,8 +259,10 @@
}
bool ABIWrapper::SetupTemplateArguments(
- abi_dump::TemplateInfo *tinfo,
- const clang::TemplateArgumentList *tl) const {
+ const clang::TemplateArgumentList *tl,
+ abi_util::TemplatedArtifactIR *ta,
+ const std::string &source_file) {
+ abi_util::TemplateInfoIR template_info;
for (int i = 0; i < tl->size(); i++) {
const clang::TemplateArgument &arg = (*tl)[i];
//TODO: More comprehensive checking needed.
@@ -191,25 +270,33 @@
continue;
}
clang::QualType type = arg.getAsType();
- abi_dump::TemplateElement *template_parameterp =
- tinfo->add_elements();
- if (!template_parameterp) {
+ template_info.AddTemplateElement(
+ abi_util::TemplateElementIR(QualTypeToString(type)));
+ if (!CreateBasicNamedAndTypedDecl(type, source_file)) {
return false;
}
- abi_dump::TemplateElement::BasicTemplateElementAbi *basic_abi =
- template_parameterp->mutable_basic_abi();
- if (!basic_abi || !SetupBasicTypeAbi(basic_abi->mutable_type_abi(), type,
- false)) {
- return false;
- }
- // TODO : default arg
- basic_abi->set_linker_set_key(QualTypeToString(type));
}
+ ta->SetTemplateInfo(std::move(template_info));
return true;
}
+static const clang::EnumDecl *GetAnonymousEnum(
+ const clang::QualType qual_type) {
+ const clang::Type *type_ptr = qual_type.getTypePtr();
+ assert(type_ptr != nullptr);
+ const clang::TagDecl *tag_decl = type_ptr->getAsTagDecl();
+ if (!tag_decl) {
+ return nullptr;
+ }
+ const clang::EnumDecl *enum_decl = llvm::dyn_cast<clang::EnumDecl>(tag_decl);
+ if (!enum_decl || enum_decl->hasNameForLinkage()) {
+ return nullptr;
+ }
+ return enum_decl;
+}
+
std::string ABIWrapper::QualTypeToString(
- const clang::QualType &sweet_qt) const {
+ const clang::QualType &sweet_qt) {
const clang::QualType salty_qt = sweet_qt.getCanonicalType();
// clang::TypeName::getFullyQualifiedName removes the part of the type related
// to it being a template parameter. Don't use it for dependent types.
@@ -223,75 +310,84 @@
clang::MangleContext *mangle_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
- const clang::FunctionDecl *decl)
- : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
+ const clang::FunctionDecl *decl,
+ std::set<std::string> *type_cache,
+ abi_util::IRDumper *ir_dumper,
+ std::map<const clang::Decl *, std::string> &decl_to_source_cache)
+ : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p,
+ type_cache, ir_dumper, decl_to_source_cache),
function_decl_(decl) { }
+bool FunctionDeclWrapper::SetupThisParameter(abi_util::FunctionIR *functionp,
+ const std::string &source_file) {
+ const clang::CXXMethodDecl *cxx_method_decl =
+ llvm::dyn_cast<clang::CXXMethodDecl>(function_decl_);
+ // No this pointer for static methods.
+ if (!cxx_method_decl || cxx_method_decl->isStatic()) {
+ return true;
+ }
+ clang::QualType this_type = cxx_method_decl->getThisType(*ast_contextp_);
+ return SetupFunctionParameter(functionp, this_type, false, source_file);
+}
+
+bool FunctionDeclWrapper::SetupFunctionParameter(
+ abi_util::FunctionIR *functionp, const clang::QualType qual_type,
+ bool has_default_arg, const std::string &source_file) {
+ if (!CreateBasicNamedAndTypedDecl(qual_type, source_file)) {
+ return false;
+ }
+ functionp->AddParameter(abi_util::ParamIR(QualTypeToString(qual_type),
+ has_default_arg));
+ return true;
+}
+
bool FunctionDeclWrapper::SetupFunctionParameters(
- abi_dump::FunctionDecl *functionp) const {
+ abi_util::FunctionIR *functionp,
+ const std::string &source_file) {
clang::FunctionDecl::param_const_iterator param_it =
function_decl_->param_begin();
+ // If this is a CXXMethodDecl, we need to add the "this" pointer.
+ if (!SetupThisParameter(functionp, source_file)) {
+ return false;
+ }
+
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();
clang::QualType param_qt = (*param_it)->getType();
- bool should_dump_size = ShouldDumpSize(param_qt);
- if (!SetupBasicNamedAndTypedDecl(
- function_fieldp->mutable_basic_abi(),
- (*param_it)->getType(), (*param_it)->getName(),
- (*param_it)->getAccess(), has_default_arg ? "true" : "false",
- should_dump_size)) {
+ if (!SetupFunctionParameter(functionp, param_qt, has_default_arg,
+ source_file)) {
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 {
+bool FunctionDeclWrapper::SetupFunction(abi_util::FunctionIR *functionp,
+ const std::string &source_file) {
// Go through all the parameters in the method and add them to the fields.
// Also get the fully qualfied name.
- functionp->set_source_file(source_file);
- // Combine the function name and return type to form a NamedAndTypedDecl
+ functionp->SetSourceFile(source_file);
+ functionp->SetName(function_decl_->getQualifiedNameAsString());
clang::QualType return_type = function_decl_->getReturnType();
- bool should_dump_size = ShouldDumpSize(return_type);
- return SetupBasicNamedAndTypedDecl(
- functionp->mutable_basic_abi(),
- return_type, function_decl_->getQualifiedNameAsString(),
- function_decl_->getAccess(), "", should_dump_size) &&
- SetupTemplateInfo(functionp) && SetupFunctionParameters(functionp);
+
+ functionp->SetReturnType(QualTypeToString(return_type));
+ functionp->SetAccess(AccessClangToIR(function_decl_->getAccess()));
+ return CreateBasicNamedAndTypedDecl(return_type, source_file) &&
+ SetupFunctionParameters(functionp, source_file) &&
+ SetupTemplateInfo(functionp, source_file);
}
bool FunctionDeclWrapper::SetupTemplateInfo(
- abi_dump::FunctionDecl *functionp) const {
+ abi_util::FunctionIR *functionp,
+ const std::string &source_file) {
switch (function_decl_->getTemplatedKind()) {
- case clang::FunctionDecl::TK_FunctionTemplate: {
- clang::FunctionTemplateDecl *template_decl =
- function_decl_->getDescribedFunctionTemplate();
- if (template_decl) {
- clang::TemplateParameterList *template_parameter_list =
- template_decl->getTemplateParameters();
- if (template_parameter_list &&
- !SetupTemplateParamNames(functionp->mutable_template_info(),
- template_parameter_list)) {
- return false;
- }
- }
- break;
- }
case clang::FunctionDecl::TK_FunctionTemplateSpecialization: {
const clang::TemplateArgumentList *arg_list =
function_decl_->getTemplateSpecializationArgs();
- if (arg_list &&
- !SetupTemplateArguments(functionp->mutable_template_info(),
- arg_list)) {
+ if (arg_list && !SetupTemplateArguments(arg_list, functionp,
+ source_file)) {
return false;
}
break;
@@ -303,11 +399,9 @@
return true;
}
-std::unique_ptr<abi_dump::FunctionDecl>
-FunctionDeclWrapper::GetFunctionDecl() const {
- std::unique_ptr<abi_dump::FunctionDecl> abi_decl(
- new abi_dump::FunctionDecl());
- std::string source_file = GetDeclSourceFile(function_decl_, cip_);
+std::unique_ptr<abi_util::FunctionIR> FunctionDeclWrapper::GetFunctionDecl() {
+ auto abi_decl = std::make_unique<abi_util::FunctionIR>();
+ std::string source_file = GetCachedDeclSourceFile(function_decl_, cip_);
if (!SetupFunction(abi_decl.get(), source_file)) {
return nullptr;
}
@@ -318,59 +412,110 @@
clang::MangleContext *mangle_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) { }
+ const clang::RecordDecl *decl,
+ std::set<std::string> *type_cache,
+ abi_util::IRDumper *ir_dumper,
+ std::map<const clang::Decl *, std::string> &decl_to_source_cache,
+ const std::string &previous_record_stages)
+ : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p,
+ type_cache, ir_dumper, decl_to_source_cache),
+ record_decl_(decl), previous_record_stages_(previous_record_stages) { }
-bool RecordDeclWrapper::SetupRecordFields(abi_dump::RecordDecl *recordp) const {
+bool RecordDeclWrapper::CreateAnonymousRecord(
+ const clang::RecordDecl *record_decl, const std::string &linker_set_key) {
+ RecordDeclWrapper record_decl_wrapper(mangle_contextp_, ast_contextp_, cip_,
+ record_decl, type_cache_, ir_dumper_,
+ decl_to_source_file_cache_,
+ linker_set_key);
+ return record_decl_wrapper.GetRecordDecl();
+}
+
+static const clang::RecordDecl *GetAnonymousRecord(clang::QualType type) {
+ const clang::Type *type_ptr = type.getTypePtr();
+ assert(type_ptr != nullptr);
+ if (!type_ptr->isRecordType()) {
+ return nullptr;
+ }
+ const clang::TagDecl *tag_decl = type_ptr->getAsTagDecl();
+ if (!tag_decl) {
+ return nullptr;
+ }
+ const clang::RecordDecl *record_decl =
+ llvm::dyn_cast<clang::RecordDecl>(tag_decl);
+
+ if (record_decl != nullptr && (!record_decl->hasNameForLinkage() ||
+ record_decl->isAnonymousStructOrUnion())) {
+ return record_decl;
+ }
+ return nullptr;
+}
+
+bool RecordDeclWrapper::SetupRecordFields(abi_util::RecordTypeIR *recordp,
+ const std::string &source_file) {
clang::RecordDecl::field_iterator field = record_decl_->field_begin();
+ uint32_t field_index = 0;
+ const clang::ASTRecordLayout &record_layout =
+ ast_contextp_->getASTRecordLayout(record_decl_);
while (field != record_decl_->field_end()) {
- abi_dump::RecordFieldDecl *record_fieldp = recordp->add_fields();
- if (!record_fieldp) {
- llvm::errs() << " Couldn't add record field: " << field->getName()
- << " to reference dump\n";
+ clang::QualType field_type = field->getType();
+ if (!CreateBasicNamedAndTypedDecl(field_type, source_file)) {
+ llvm::errs() << "Creation of Type failed\n";
return false;
}
- if (!SetupBasicNamedAndTypedDecl(record_fieldp->mutable_basic_abi(),
- field->getType(), field->getName(),
- field->getAccess(), "", true)) {
+ std::string field_type_str = QualTypeToString(field_type);
+ std::string field_name = field->getName();
+ // Handle anoymous structs / unions as fields.
+ if (const clang::RecordDecl *anon_record_decl =
+ GetAnonymousRecord(field_type)) {
+ // We need to create a unique linker set key for anonymous structs / enums
+ // since clang just names them with fully_qualified_scope::anonymous.
+ field_type_str =
+ previous_record_stages_ + "::(anonymous)" +
+ std::to_string(field_index);
+ if (!CreateAnonymousRecord(anon_record_decl, field_type_str)) {
return false;
+ }
+ } else if (const clang::EnumDecl *enum_decl =
+ GetAnonymousEnum(field_type)) {
+ // Handle anonymous enums.
+ field_type_str = QualTypeToString(enum_decl->getIntegerType());
}
+ uint64_t field_offset = record_layout.getFieldOffset(field_index);
+ recordp->AddRecordField(abi_util::RecordFieldIR(
+ field_name, field_type_str, field_offset,
+ AccessClangToIR(field->getAccess())));
field++;
+ field_index++;
}
return true;
}
bool RecordDeclWrapper::SetupCXXBases(
- abi_dump::RecordDecl *cxxp,
- const clang::CXXRecordDecl *cxx_record_decl) const {
- assert(cxx_record_decl != nullptr);
+ abi_util::RecordTypeIR *cxxp,
+ const clang::CXXRecordDecl *cxx_record_decl) {
+ if (!cxx_record_decl || !cxxp) {
+ return false;
+ }
clang::CXXRecordDecl::base_class_const_iterator base_class =
cxx_record_decl->bases_begin();
while (base_class != cxx_record_decl->bases_end()) {
- abi_dump::CXXBaseSpecifier *base_specifierp = cxxp->add_base_specifiers();
- if (!base_specifierp) {
- llvm::errs() << " Couldn't add base specifier to reference dump\n";
- return false;
- }
std::string name = QualTypeToString(base_class->getType());
bool is_virtual = base_class->isVirtual();
- if (!SetupBasicNamedAndTypedDecl(base_specifierp->mutable_basic_abi(),
- base_class->getType(),
- "", base_class->getAccessSpecifier(),
- "", false)) {
- return false;
- }
- base_specifierp->set_is_virtual(is_virtual);
+ abi_util::AccessSpecifierIR access =
+ AccessClangToIR(base_class->getAccessSpecifier());
+ cxxp->AddCXXBaseSpecifier(abi_util::CXXBaseSpecifierIR(name, is_virtual,
+ access));
base_class++;
}
return true;
}
bool RecordDeclWrapper::SetupRecordVTable(
- abi_dump::RecordDecl *record_declp,
- const clang::CXXRecordDecl *cxx_record_decl) const {
- assert(cxx_record_decl != nullptr);
+ abi_util::RecordTypeIR *record_declp,
+ const clang::CXXRecordDecl *cxx_record_decl) {
+ if (!cxx_record_decl || !record_declp) {
+ return false;
+ }
clang::VTableContextBase *base_vtable_contextp =
ast_contextp_->getVTableContext();
const clang::Type *typep = cxx_record_decl->getTypeForDecl();
@@ -386,263 +531,254 @@
}
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;
- }
+ abi_util::VTableLayoutIR vtable_ir_layout;
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)) {
+ abi_util::VTableComponentIR added_component=
+ SetupRecordVTableComponent(vtable_component);
+ vtable_ir_layout.AddVTableComponent(std::move(added_component));
+ }
+ record_declp->SetVTableLayout(std::move(vtable_ir_layout));
+ return true;
+}
+
+abi_util::VTableComponentIR RecordDeclWrapper::SetupRecordVTableComponent(
+ const clang::VTableComponent &vtable_component) {
+ abi_util::VTableComponentIR::Kind kind =
+ abi_util::VTableComponentIR::Kind::RTTI;
+ std::string mangled_component_name = "";
+ llvm::raw_string_ostream ostream(mangled_component_name);
+ int64_t value = 0;
+ clang::VTableComponent::Kind clang_component_kind =
+ vtable_component.getKind();
+ switch (clang_component_kind) {
+ case clang::VTableComponent::CK_VCallOffset:
+ kind = abi_util::VTableComponentIR::Kind::VCallOffset;
+ value = vtable_component.getVCallOffset().getQuantity();
+ break;
+ case clang::VTableComponent::CK_VBaseOffset:
+ kind = abi_util::VTableComponentIR::Kind::VBaseOffset;
+ value = vtable_component.getVBaseOffset().getQuantity();
+ break;
+ case clang::VTableComponent::CK_OffsetToTop:
+ kind = abi_util::VTableComponentIR::Kind::OffsetToTop;
+ value = vtable_component.getOffsetToTop().getQuantity();
+ break;
+ case clang::VTableComponent::CK_RTTI:
+ {
+ kind = abi_util::VTableComponentIR::Kind::RTTI;
+ const clang::CXXRecordDecl *rtti_decl =
+ vtable_component.getRTTIDecl();
+ assert(rtti_decl != nullptr);
+ mangled_component_name =
+ ABIWrapper::GetTypeLinkageName(rtti_decl->getTypeForDecl());
+ }
+ 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);
+ switch (clang_component_kind) {
+ case clang::VTableComponent::CK_FunctionPointer:
+ kind = abi_util::VTableComponentIR::Kind::FunctionPointer;
+ mangled_component_name = GetMangledNameDecl(method_decl,
+ mangle_contextp_);
+ break;
+ case clang::VTableComponent::CK_CompleteDtorPointer:
+ kind = abi_util::VTableComponentIR::Kind::CompleteDtorPointer;
+ mangle_contextp_->mangleCXXDtor(
+ vtable_component.getDestructorDecl(),
+ clang::CXXDtorType::Dtor_Complete, ostream);
+ ostream.flush();
+ break;
+ case clang::VTableComponent::CK_DeletingDtorPointer:
+ kind = abi_util::VTableComponentIR::Kind::DeletingDtorPointer;
+ mangle_contextp_->mangleCXXDtor(
+ vtable_component.getDestructorDecl(),
+ clang::CXXDtorType::Dtor_Deleting, ostream);
+ ostream.flush();
+ break;
+ case clang::VTableComponent::CK_UnusedFunctionPointer:
+ kind = abi_util::VTableComponentIR::Kind::UnusedFunctionPointer;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return abi_util::VTableComponentIR(mangled_component_name, kind, value);
+}
+
+bool RecordDeclWrapper::SetupTemplateInfo(
+ abi_util::RecordTypeIR *record_declp,
+ const clang::CXXRecordDecl *cxx_record_decl,
+ const std::string &source_file) {
+ assert(cxx_record_decl != nullptr);
+ const clang::ClassTemplateSpecializationDecl *specialization_decl =
+ clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cxx_record_decl);
+ if (specialization_decl) {
+ const clang::TemplateArgumentList *arg_list =
+ &specialization_decl->getTemplateArgs();
+ if (arg_list &&
+ !SetupTemplateArguments(arg_list, record_declp, source_file)) {
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 = "";
- llvm::raw_string_ostream ostream(mangled_component_name);
- int64_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 =
- ABIWrapper::GetTypeLinkageName(rtti_decl->getTypeForDecl());
- }
- 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);
- switch (clang_component_kind) {
- case clang::VTableComponent::CK_FunctionPointer:
- kind = abi_dump::VTableComponent_Kind_FunctionPointer;
- mangled_component_name = GetMangledNameDecl(method_decl,
- mangle_contextp_);
- break;
- case clang::VTableComponent::CK_CompleteDtorPointer:
- kind = abi_dump::VTableComponent_Kind_CompleteDtorPointer;
- mangle_contextp_->mangleCXXDtor(
- vtable_component.getDestructorDecl(),
- clang::CXXDtorType::Dtor_Complete, ostream);
- ostream.flush();
-
- break;
- case clang::VTableComponent::CK_DeletingDtorPointer:
- kind = abi_dump::VTableComponent_Kind_DeletingDtorPointer;
- mangle_contextp_->mangleCXXDtor(
- vtable_component.getDestructorDecl(),
- clang::CXXDtorType::Dtor_Deleting, ostream);
- ostream.flush();
- break;
- 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_component_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();
- if (template_decl) {
- clang::TemplateParameterList *template_parameter_list =
- template_decl->getTemplateParameters();
- if (template_parameter_list &&
- !SetupTemplateParamNames(record_declp->mutable_template_info(),
- template_parameter_list)) {
- return false;
- }
- }
- } else {
- const clang::ClassTemplateSpecializationDecl *specialization_decl =
- clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
- cxx_record_decl);
- if(specialization_decl) {
- const clang::TemplateArgumentList *arg_list =
- &specialization_decl->getTemplateArgs();
- if (arg_list &&
- !SetupTemplateArguments(record_declp->mutable_template_info(),
- arg_list)) {
- return false;
- }
- }
+bool RecordDeclWrapper::SetupRecordInfo(abi_util::RecordTypeIR *record_declp,
+ const std::string &source_file) {
+ if (!record_declp) {
+ return false;
}
- return true;
-}
-bool RecordDeclWrapper::SetupRecordInfo(abi_dump::RecordDecl *record_declp,
- const std::string &source_file) const {
- std::string qualified_name = GetTagDeclQualifiedName(record_decl_);
+ if (record_decl_->isStruct()) {
+ record_declp->SetRecordKind(
+ abi_util::RecordTypeIR::RecordKind::struct_kind);
+ } else if (record_decl_->isClass()) {
+ record_declp->SetRecordKind(
+ abi_util::RecordTypeIR::RecordKind::class_kind);
+ } else {
+ record_declp->SetRecordKind(
+ abi_util::RecordTypeIR::RecordKind::union_kind);
+ }
+
const clang::Type *basic_type = nullptr;
if (!(basic_type = record_decl_->getTypeForDecl())) {
return false;
}
- std::string mangled_name = ABIWrapper::GetTypeLinkageName(basic_type);
- clang::QualType type = basic_type->getCanonicalTypeInternal();
- std::string linker_key = (mangled_name == "") ? qualified_name : mangled_name;
- if (!SetupBasicNamedAndTypedDecl(record_declp->mutable_basic_abi(),
- type, qualified_name,
- record_decl_->getAccess(), linker_key,
- true)) {
+ clang::QualType qual_type = basic_type->getCanonicalTypeInternal();
+ if (!CreateExtendedType(qual_type, record_declp)) {
return false;
}
- record_declp->set_mangled_record_name(mangled_name);
- record_declp->set_source_file(source_file);
- return true;
+ std::string record_qual_type_str = QualTypeToString(qual_type);
+ record_declp->SetSourceFile(source_file);
+ if (!record_decl_->hasNameForLinkage() ||
+ record_decl_->isAnonymousStructOrUnion()) {
+ record_declp->SetLinkerSetKey(previous_record_stages_);
+ record_declp->SetAnonymity(true);
+ } else {
+ previous_record_stages_ = record_qual_type_str;
+ record_declp->SetLinkerSetKey(record_qual_type_str);
+ }
+ record_declp->SetAccess(AccessClangToIR(record_decl_->getAccess()));
+ return SetupRecordFields(record_declp, source_file) &&
+ SetupCXXRecordInfo(record_declp, source_file);
}
bool RecordDeclWrapper::SetupCXXRecordInfo(
- abi_dump::RecordDecl *record_declp) const {
+ abi_util::RecordTypeIR *record_declp, const std::string &source_file) {
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) &&
+ return SetupTemplateInfo(record_declp, cxx_record_decl, source_file) &&
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_);
- abi_dump::RecordDecl *record_declp = abi_decl.get();
- if (!SetupRecordInfo(record_declp, source_file) ||
- !SetupRecordFields(record_declp) ||
- !SetupCXXRecordInfo(abi_decl.get())) {
+bool RecordDeclWrapper::GetRecordDecl() {
+ auto abi_decl = std::make_unique<abi_util::RecordTypeIR>();
+ std::string source_file = GetCachedDeclSourceFile(record_decl_, cip_);
+ if (!SetupRecordInfo(abi_decl.get(), source_file)) {
llvm::errs() << "Setting up CXX Bases / Template Info failed\n";
- return nullptr;
+ return false;
}
- return abi_decl;
+ return ir_dumper_->AddLinkableMessageIR(abi_decl.get());
}
EnumDeclWrapper::EnumDeclWrapper(
clang::MangleContext *mangle_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
- const clang::EnumDecl *decl)
- : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
+ const clang::EnumDecl *decl,
+ std::set<std::string> *type_cache,
+ abi_util::IRDumper *ir_dumper,
+ std::map<const clang::Decl *, std::string> &decl_to_source_cache)
+ : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p,
+ type_cache, ir_dumper, decl_to_source_cache),
enum_decl_(decl) { }
-bool EnumDeclWrapper::SetupEnumFields(abi_dump::EnumDecl *enump) const {
+bool EnumDeclWrapper::SetupEnumFields(abi_util::EnumTypeIR *enump) {
+ if (!enump) {
+ return false;
+ }
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();
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), true)) {
- return false;
- }
- enum_fieldp->set_enum_field_value(field_value);
+ enump->AddEnumField(abi_util::EnumFieldIR(name, field_value));
enum_it++;
}
return true;
}
-bool EnumDeclWrapper::SetupEnum(abi_dump::EnumDecl *enump,
- const std::string &source_file) const {
+bool EnumDeclWrapper::SetupEnum(abi_util::EnumTypeIR *enum_type,
+ const std::string &source_file) {
std::string enum_name = GetTagDeclQualifiedName(enum_decl_);
- clang::QualType enum_type = enum_decl_->getIntegerType();
- if (!SetupBasicNamedAndTypedDecl(enump->mutable_basic_abi(), enum_type,
- enum_name, enum_decl_->getAccess(),
- enum_name, true) ||
- !SetupEnumFields(enump)) {
+ clang::QualType enum_qual_type =
+ enum_decl_->getTypeForDecl()->getCanonicalTypeInternal();
+ if (!CreateExtendedType(enum_qual_type, enum_type)) {
return false;
}
- enump->set_source_file(source_file);
- return true;
+ enum_type->SetSourceFile(source_file);
+ enum_type->SetUnderlyingType(QualTypeToString(enum_decl_->getIntegerType()));
+ enum_type->SetAccess(AccessClangToIR(enum_decl_->getAccess()));
+ return SetupEnumFields(enum_type) &&
+ CreateBasicNamedAndTypedDecl(enum_decl_->getIntegerType(), "");
}
-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_);
+bool EnumDeclWrapper::GetEnumDecl() {
+ auto abi_decl = std::make_unique<abi_util::EnumTypeIR>();
+ std::string source_file = GetCachedDeclSourceFile(enum_decl_, cip_);
if (!SetupEnum(abi_decl.get(), source_file)) {
- llvm::errs() << "Setting up Enum fields failed\n";
- return nullptr;
+ llvm::errs() << "Setting up Enum failed\n";
+ return false;
}
- return abi_decl;
+ return ir_dumper_->AddLinkableMessageIR(abi_decl.get());
}
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),
+ const clang::VarDecl *decl,std::set<std::string> *type_cache,
+ abi_util::IRDumper *ir_dumper,
+ std::map<const clang::Decl *, std::string> &decl_to_source_cache)
+ : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, type_cache,
+ ir_dumper, decl_to_source_cache),
global_var_decl_(decl) { }
bool GlobalVarDeclWrapper::SetupGlobalVar(
- abi_dump::GlobalVarDecl *global_varp,
- const std::string &source_file) const {
+ abi_util::GlobalVarIR *global_varp,
+ const std::string &source_file) {
// Temporary fix : clang segfaults on trying to mangle global variable which
// is a dependent sized array type.
- std::string qualified_name = global_var_decl_->getQualifiedNameAsString();
std::string mangled_name =
GetMangledNameDecl(global_var_decl_, mangle_contextp_);
- if (!SetupBasicNamedAndTypedDecl(
- global_varp->mutable_basic_abi(),global_var_decl_->getType(),
- qualified_name, global_var_decl_->getAccess(),
- mangled_name, true)) {
+ if (!CreateBasicNamedAndTypedDecl(global_var_decl_->getType(), source_file)) {
return false;
}
- global_varp->set_source_file(source_file);
+ global_varp->SetSourceFile(source_file);
+ global_varp->SetName(global_var_decl_->getQualifiedNameAsString());
+ global_varp->SetLinkerSetKey(mangled_name);
+ global_varp->SetReferencedType(
+ QualTypeToString(global_var_decl_->getType()));
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;
+bool GlobalVarDeclWrapper::GetGlobalVarDecl() {
+ auto abi_decl = std::make_unique<abi_util::GlobalVarIR>();
+ std::string source_file = GetCachedDeclSourceFile(global_var_decl_, cip_);
+ return SetupGlobalVar(abi_decl.get(), source_file) &&
+ ir_dumper_->AddLinkableMessageIR(abi_decl.get());
}
diff --git a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h
index 262c9cf..af222b0 100644
--- a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h
+++ b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h
@@ -15,6 +15,8 @@
#ifndef ABI_WRAPPERS_H_
#define ABI_WRAPPERS_H_
+#include <ir_representation.h>
+
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#pragma clang diagnostic ignored "-Wnested-anon-types"
@@ -32,7 +34,10 @@
public:
ABIWrapper(clang::MangleContext *mangle_contextp,
clang::ASTContext *ast_contextp,
- const clang::CompilerInstance *cip);
+ const clang::CompilerInstance *cip,
+ std::set<std::string> *type_cache,
+ abi_util::IRDumper *ir_dumper,
+ std::map<const clang::Decl *, std::string> &decl_to_source_cache);
static std::string GetDeclSourceFile(const clang::Decl *decl,
const clang::CompilerInstance *cip);
@@ -41,123 +46,161 @@
clang::MangleContext *mangle_context);
protected:
abi_dump::AccessSpecifier AccessClangToDump(
- const clang::AccessSpecifier sp) const;
+ const clang::AccessSpecifier sp);
+ std::string GetCachedDeclSourceFile(const clang::Decl *decl,
+ const clang::CompilerInstance *cip);
- bool SetupTemplateParamNames(abi_dump::TemplateInfo *tinfo,
- clang::TemplateParameterList *pl) const;
+ bool SetupTemplateArguments(const clang::TemplateArgumentList *tl,
+ abi_util::TemplatedArtifactIR *ta,
+ const std::string &source_file);
- bool SetupTemplateArguments(abi_dump::TemplateInfo *tinfo,
- const clang::TemplateArgumentList *tl) const;
+ std::string QualTypeToString(const clang::QualType &sweet_qt);
- std::string QualTypeToString(const clang::QualType &sweet_qt) const;
+ std::string GetTagDeclQualifiedName(const clang::TagDecl *decl);
- std::string GetTagDeclQualifiedName(const clang::TagDecl *decl) const;
+ bool CreateBasicNamedAndTypedDecl(clang::QualType,
+ const std::string &source_file);
+ bool CreateBasicNamedAndTypedDecl(
+ clang::QualType canonical_type,
+ abi_util::TypeIR *typep,
+ const std::string &source_file);
- bool SetupBasicTypeAbi(abi_dump::BasicTypeAbi *type_abi,
- const clang::QualType type, bool dump_size) const;
+ bool CreateExtendedType(
+ clang::QualType canonical_type,
+ abi_util::TypeIR *typep);
- 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,
- bool dump_size) const;
+ clang::QualType GetReferencedType(const clang::QualType qual_type);
- std::string GetTypeLinkageName(const clang::Type *typep) const;
+ std::string GetTypeLinkageName(const clang::Type *typep);
-protected:
+ std::unique_ptr<abi_util::TypeIR> SetTypeKind(const clang::QualType qtype,
+ const std::string &source_file);
+
+
+ protected:
const clang::CompilerInstance *cip_;
clang::MangleContext *mangle_contextp_;
clang::ASTContext *ast_contextp_;
+ std::set<std::string> *type_cache_;
+ abi_util::IRDumper *ir_dumper_;
+ std::map<const clang::Decl *, std::string> &decl_to_source_file_cache_;
};
class RecordDeclWrapper : public ABIWrapper {
public:
- RecordDeclWrapper(clang::MangleContext *mangle_contextp,
- clang::ASTContext *ast_contextp,
- const clang::CompilerInstance *compiler_instance_p,
- const clang::RecordDecl *decl);
+ RecordDeclWrapper(
+ clang::MangleContext *mangle_contextp, clang::ASTContext *ast_contextp,
+ const clang::CompilerInstance *compiler_instance_p,
+ const clang::RecordDecl *decl, std::set<std::string> *type_cache,
+ abi_util::IRDumper *ir_dumper,
+ std::map<const clang::Decl *, std::string> &decl_to_source_cache_,
+ const std::string &previous_record_stages);
- std::unique_ptr<abi_dump::RecordDecl> GetRecordDecl() const;
+ bool GetRecordDecl();
private:
const clang::RecordDecl *record_decl_;
+ std::string previous_record_stages_;
private:
- bool SetupRecordInfo(abi_dump::RecordDecl *record_declp,
- const std::string &source_file) const;
+ bool SetupRecordInfo(abi_util::RecordTypeIR *type,
+ const std::string &source_file);
- bool SetupRecordFields(abi_dump::RecordDecl *record_declp) const;
+ bool SetupRecordFields(abi_util::RecordTypeIR *record_declp,
+ const std::string &source_file);
- bool SetupCXXBases(abi_dump::RecordDecl *cxxp,
- const clang::CXXRecordDecl *cxx_record_decl) const;
+ bool SetupCXXBases(abi_util::RecordTypeIR *cxxp,
+ const clang::CXXRecordDecl *cxx_record_decl);
- bool SetupTemplateInfo(abi_dump::RecordDecl *record_declp,
- const clang::CXXRecordDecl *cxx_record_decl) const;
+ bool SetupTemplateInfo(abi_util::RecordTypeIR *record_declp,
+ const clang::CXXRecordDecl *cxx_record_decl,
+ const std::string &source_file);
- 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 SetupRecordVTable(abi_util::RecordTypeIR *record_declp,
+ const clang::CXXRecordDecl *cxx_record_decl);
+ abi_util::VTableComponentIR SetupRecordVTableComponent(
+ const clang::VTableComponent &vtable_component);
- bool SetupCXXRecordInfo(abi_dump::RecordDecl *record_declp) const;
+ bool SetupCXXRecordInfo(abi_util::RecordTypeIR *record_declp,
+ const std::string &source_file);
+
+ bool CreateAnonymousRecord(
+ const clang::RecordDecl *decl, const std::string &linker_set_key);
};
class FunctionDeclWrapper : public ABIWrapper {
public:
- FunctionDeclWrapper(clang::MangleContext *mangle_contextp,
- clang::ASTContext *ast_contextp,
- const clang::CompilerInstance *compiler_instance_p,
- const clang::FunctionDecl *decl);
+ FunctionDeclWrapper(
+ clang::MangleContext *mangle_contextp, clang::ASTContext *ast_contextp,
+ const clang::CompilerInstance *compiler_instance_p,
+ const clang::FunctionDecl *decl, std::set<std::string> *type_cache,
+ abi_util::IRDumper *ir_dumper,
+ std::map<const clang::Decl *, std::string> &decl_to_source_cache_);
- std::unique_ptr<abi_dump::FunctionDecl> GetFunctionDecl() const;
+ std::unique_ptr<abi_util::FunctionIR> GetFunctionDecl();
private:
const clang::FunctionDecl *function_decl_;
private:
- bool SetupFunction(abi_dump::FunctionDecl *methodp,
- const std::string &source_file) const;
+ bool SetupFunction(abi_util::FunctionIR *methodp,
+ const std::string &source_file);
- bool SetupTemplateInfo(abi_dump::FunctionDecl *functionp) const;
+ bool SetupTemplateInfo(abi_util::FunctionIR *functionp,
+ const std::string &source_file);
- bool SetupFunctionParameters(abi_dump::FunctionDecl *functionp) const;
+ bool SetupFunctionParameters(abi_util::FunctionIR *functionp,
+ const std::string &source_file);
+
+ bool SetupFunctionParameter(abi_util::FunctionIR *functionp,
+ const clang::QualType qual_type,
+ bool has_default_arg,
+ const std::string &source_file);
+
+ bool SetupThisParameter(abi_util::FunctionIR *functionp,
+ const std::string &source_file);
+
};
class EnumDeclWrapper : public ABIWrapper {
public:
- EnumDeclWrapper(clang::MangleContext *mangle_contextp,
- clang::ASTContext *ast_contextp,
- const clang::CompilerInstance *compiler_instance_p,
- const clang::EnumDecl *decl);
+ EnumDeclWrapper(
+ clang::MangleContext *mangle_contextp, clang::ASTContext *ast_contextp,
+ const clang::CompilerInstance *compiler_instance_p,
+ const clang::EnumDecl *decl,
+ std::set<std::string> *type_cache, abi_util::IRDumper *ir_dumper,
+ std::map<const clang::Decl *, std::string> &decl_to_source_cache_);
- std::unique_ptr<abi_dump::EnumDecl> GetEnumDecl() const;
+ bool GetEnumDecl();
private:
const clang::EnumDecl *enum_decl_;
private:
- bool SetupEnum(abi_dump::EnumDecl *enump,
- const std::string &source_file) const;
- bool SetupEnumFields(abi_dump::EnumDecl *enump) const;
+ bool SetupEnum(abi_util::EnumTypeIR *type,
+ const std::string &source_file);
+
+ bool SetupEnumFields(abi_util::EnumTypeIR *enump);
};
class GlobalVarDeclWrapper : public ABIWrapper {
public:
- GlobalVarDeclWrapper(clang::MangleContext *mangle_contextp,
- clang::ASTContext *ast_contextp,
- const clang::CompilerInstance *compiler_instance_p,
- const clang::VarDecl *decl);
+ GlobalVarDeclWrapper(
+ clang::MangleContext *mangle_contextp, clang::ASTContext *ast_contextp,
+ const clang::CompilerInstance *compiler_instance_p,
+ const clang::VarDecl *decl,
+ std::set<std::string> *type_cache, abi_util::IRDumper *ir_dumper,
+ std::map<const clang::Decl *, std::string> &decl_to_source_cache_);
- std::unique_ptr<abi_dump::GlobalVarDecl> GetGlobalVarDecl() const;
+ bool GetGlobalVarDecl();
private:
const clang::VarDecl *global_var_decl_;
private:
- bool SetupGlobalVar(abi_dump::GlobalVarDecl *global_varp,
- const std::string &source_file) const;
+ bool SetupGlobalVar(abi_util::GlobalVarIR *global_varp,
+ const std::string &source_file);
};
} //end namespace abi_wrapper
-#endif // ABI_WRAPPERS_H_
+#endif // ABI_WRAPPERS_H_
diff --git a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp
index 66b3e9d..abf58ed 100644
--- a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp
+++ b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp
@@ -19,9 +19,6 @@
#include <clang/Tooling/Core/QualTypeNames.h>
#include <clang/Index/CodegenNameGenerator.h>
-#include <google/protobuf/text_format.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-
#include <fstream>
#include <iostream>
#include <string>
@@ -33,83 +30,64 @@
using abi_wrapper::GlobalVarDeclWrapper;
HeaderASTVisitor::HeaderASTVisitor(
- abi_dump::TranslationUnit *tu_ptr,
clang::MangleContext *mangle_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
const std::string ¤t_file_name,
const std::set<std::string> &exported_headers,
- const clang::Decl *tu_decl)
- : tu_ptr_(tu_ptr),
- mangle_contextp_(mangle_contextp),
+ const clang::Decl *tu_decl,
+ std::set<std::string> *type_cache,
+ abi_util::IRDumper *ir_dumper)
+ : mangle_contextp_(mangle_contextp),
ast_contextp_(ast_contextp),
cip_(compiler_instance_p),
current_file_name_(current_file_name),
exported_headers_(exported_headers),
- tu_decl_(tu_decl) { }
+ tu_decl_(tu_decl),
+ type_cache_(type_cache),
+ ir_dumper_(ir_dumper) { }
bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
- // Skip forward declaration.
+ // Skip forward declarations, dependent records. Also skip anonymous records
+ // as they will be traversed through record fields.
if (!decl->isThisDeclarationADefinition() ||
- decl->getTypeForDecl()->isDependentType()) {
+ decl->getTypeForDecl()->isDependentType() ||
+ decl->isAnonymousStructOrUnion() ||
+ !decl->hasNameForLinkage()) {
return true;
}
RecordDeclWrapper record_decl_wrapper(
- mangle_contextp_, ast_contextp_, cip_, decl);
- std::unique_ptr<abi_dump::RecordDecl> wrapped_record_decl =
- record_decl_wrapper.GetRecordDecl();
- if (!wrapped_record_decl) {
- llvm::errs() << "Getting Record Decl failed\n";
- return false;
- }
- abi_dump::RecordDecl *added_record_declp = tu_ptr_->add_records();
- if (!added_record_declp) {
- return false;
- }
- *added_record_declp = *wrapped_record_decl;
- return true;
+ mangle_contextp_, ast_contextp_, cip_, decl, type_cache_,
+ ir_dumper_, decl_to_source_file_cache_, "");
+ return record_decl_wrapper.GetRecordDecl();
}
bool HeaderASTVisitor::VisitEnumDecl(const clang::EnumDecl *decl) {
if (!decl->isThisDeclarationADefinition() ||
- decl->getTypeForDecl()->isDependentType()) {
+ decl->getTypeForDecl()->isDependentType() ||
+ !decl->hasNameForLinkage()) {
return true;
}
EnumDeclWrapper enum_decl_wrapper(
- mangle_contextp_, ast_contextp_, cip_, decl);
- std::unique_ptr<abi_dump::EnumDecl> wrapped_enum_decl =
- enum_decl_wrapper.GetEnumDecl();
- if (!wrapped_enum_decl) {
- llvm::errs() << "Getting Enum Decl failed\n";
- return false;
- }
- abi_dump::EnumDecl *added_enum_declp = tu_ptr_->add_enums();
- if (!added_enum_declp) {
- return false;
- }
- *added_enum_declp = *wrapped_enum_decl;
- return true;
-}
+ mangle_contextp_, ast_contextp_, cip_, decl, type_cache_,
+ ir_dumper_, decl_to_source_file_cache_);
+ return enum_decl_wrapper.GetEnumDecl();
+ }
-static bool MutateFunctionWithLinkageName(abi_dump::TranslationUnit *tu_ptr,
- const abi_dump::FunctionDecl *fd,
+static bool MutateFunctionWithLinkageName(const abi_util::FunctionIR *function,
+ abi_util::IRDumper *ir_dumper,
std::string &linkage_name) {
- abi_dump::FunctionDecl *added_function_declp = tu_ptr->add_functions();
- if (!added_function_declp) {
- return false;
- }
- *added_function_declp = *fd;
- added_function_declp->set_mangled_function_name(linkage_name);
- assert(added_function_declp->mutable_basic_abi() != nullptr);
- added_function_declp->mutable_basic_abi()->set_linker_set_key(linkage_name);
- return true;
+ auto added_function = std::make_unique<abi_util::FunctionIR>();
+ *added_function = *function;
+ added_function->SetLinkerSetKey(linkage_name);
+ return ir_dumper->AddLinkableMessageIR(added_function.get());
}
-static bool AddMangledFunctions(abi_dump::TranslationUnit *tu_ptr,
- const abi_dump::FunctionDecl *fd,
+static bool AddMangledFunctions(const abi_util::FunctionIR *function,
+ abi_util:: IRDumper *ir_dumper,
std::vector<std::string> &manglings) {
for (auto &&mangling : manglings) {
- if (!MutateFunctionWithLinkageName(tu_ptr, fd, mangling)) {
+ if (!MutateFunctionWithLinkageName(function, ir_dumper, mangling)) {
return false;
}
}
@@ -139,23 +117,20 @@
return true;
}
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;
- }
+ cip_, decl, type_cache_,
+ ir_dumper_,
+ decl_to_source_file_cache_);
+ auto function_wrapper = function_decl_wrapper.GetFunctionDecl();
// Destructors and Constructors can have more than 1 symbol generated from the
// same Decl.
clang::index::CodegenNameGenerator cg(*ast_contextp_);
std::vector<std::string> manglings = cg.getAllManglings(decl);
if (!manglings.empty()) {
- return AddMangledFunctions(tu_ptr_, wrapped_function_decl.get(), manglings);
+ return AddMangledFunctions(function_wrapper.get(), ir_dumper_, manglings);
}
std::string linkage_name =
ABIWrapper::GetMangledNameDecl(decl, mangle_contextp_);
- return MutateFunctionWithLinkageName(tu_ptr_, wrapped_function_decl.get(),
+ return MutateFunctionWithLinkageName(function_wrapper.get(), ir_dumper_,
linkage_name);
}
@@ -166,19 +141,10 @@
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;
+ cip_, decl, type_cache_,
+ ir_dumper_,
+ decl_to_source_file_cache_);
+ return global_var_decl_wrapper.GetGlobalVarDecl();
}
static bool AreHeadersExported(const std::set<std::string> &exported_headers) {
@@ -191,6 +157,7 @@
return true;
}
std::string source_file = ABIWrapper::GetDeclSourceFile(decl, cip_);
+ decl_to_source_file_cache_.insert(std::make_pair(decl, source_file));
// If no exported headers are specified we assume the whole AST is exported.
if ((decl != tu_decl_) && AreHeadersExported(exported_headers_) &&
(exported_headers_.find(source_file) == exported_headers_.end())) {
@@ -210,18 +177,19 @@
exported_headers_(exported_headers) { }
void HeaderASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) {
- GOOGLE_PROTOBUF_VERIFY_VERSION;
- std::ofstream text_output(out_dump_name_);
- google::protobuf::io::OstreamOutputStream text_os(&text_output);
+ clang::PrintingPolicy policy(ctx.getPrintingPolicy());
+ policy.SuppressTagKeyword = true;
+ ctx.setPrintingPolicy(policy);
clang::TranslationUnitDecl *translation_unit = ctx.getTranslationUnitDecl();
std::unique_ptr<clang::MangleContext> mangle_contextp(
ctx.createMangleContext());
- abi_dump::TranslationUnit tu;
- std::string str_out;
- HeaderASTVisitor v(&tu, mangle_contextp.get(), &ctx, cip_, file_name_,
- exported_headers_, translation_unit);
- if (!v.TraverseDecl(translation_unit) ||
- !google::protobuf::TextFormat::Print(tu, &text_os)) {
+ std::set<std::string> type_cache;
+ std::unique_ptr<abi_util::IRDumper> ir_dumper =
+ abi_util::IRDumper::CreateIRDumper("protobuf", out_dump_name_);
+ HeaderASTVisitor v(mangle_contextp.get(), &ctx, cip_, file_name_,
+ exported_headers_, translation_unit, &type_cache,
+ ir_dumper.get());
+ if (!v.TraverseDecl(translation_unit) || !ir_dumper->Dump()) {
llvm::errs() << "Serialization to ostream failed\n";
::exit(1);
}
diff --git a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h
index f3e6f8c..569936b 100644
--- a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h
+++ b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h
@@ -21,6 +21,8 @@
#include "proto/abi_dump.pb.h"
#pragma clang diagnostic pop
+#include <ir_representation.h>
+
#include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/Mangle.h>
@@ -33,13 +35,14 @@
class HeaderASTVisitor
: public clang::RecursiveASTVisitor<HeaderASTVisitor> {
public:
- HeaderASTVisitor(abi_dump::TranslationUnit *tu_ptr,
- clang::MangleContext *mangle_contextp,
+ HeaderASTVisitor(clang::MangleContext *mangle_contextp,
clang::ASTContext *ast_contextp,
const clang::CompilerInstance *compiler_instance_p,
const std::string ¤t_file_name,
const std::set<std::string> &exported_headers,
- const clang::Decl *tu_decl);
+ const clang::Decl *tu_decl,
+ std::set<std::string> *type_cache,
+ abi_util::IRDumper *ir_dumper);
bool VisitRecordDecl(const clang::RecordDecl *decl);
@@ -57,7 +60,6 @@
}
private:
- abi_dump::TranslationUnit *tu_ptr_;
clang::MangleContext *mangle_contextp_;
clang::ASTContext *ast_contextp_;
const clang::CompilerInstance *cip_;
@@ -65,6 +67,11 @@
const std::set<std::string> &exported_headers_;
// To optimize recursion into only exported abi.
const clang::Decl *tu_decl_;
+ std::set<std::string> *type_cache_;
+ abi_util::IRDumper *ir_dumper_;
+ // We cache the source file an AST node corresponds to, to avoid repeated
+ // calls to "realpath".
+ std::map<const clang::Decl *, std::string> decl_to_source_file_cache_;
};
class HeaderASTConsumer : public clang::ASTConsumer {
@@ -83,4 +90,4 @@
std::set<std::string> exported_headers_;
};
-#endif // AST_PROCESSING_H_
+#endif // AST_PROCESSING_H_
diff --git a/vndk/tools/header-checker/header-abi-linker/src/header_abi_linker.cpp b/vndk/tools/header-checker/header-abi-linker/src/header_abi_linker.cpp
index 96616d1..b02092d 100644
--- a/vndk/tools/header-checker/header-abi-linker/src/header_abi_linker.cpp
+++ b/vndk/tools/header-checker/header-abi-linker/src/header_abi_linker.cpp
@@ -85,16 +85,20 @@
bool LinkAndDump();
+ template <typename T>
+ static std::string GetLinkageName(T &element) {
+ return element.type_info().linker_set_key();
+ }
+ template <typename T>
+ static std::string GetSourceFile(T &element) {
+ return element.type_info().source_file();
+ }
private:
- bool LinkRecords(const abi_dump::TranslationUnit &dump_tu,
- abi_dump::TranslationUnit *linked_tu);
-
+ bool LinkTypes(const abi_dump::TranslationUnit &dump_tu,
+ abi_dump::TranslationUnit *linked_tu);
bool LinkFunctions(const abi_dump::TranslationUnit &dump_tu,
abi_dump::TranslationUnit *linked_tu);
- 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);
@@ -110,6 +114,8 @@
bool ParseSoFile();
+ bool AddElfSymbols(abi_dump::TranslationUnit *linked_tu);
+
private:
const std::vector<std::string> &dump_files_;
const std::vector<std::string> &exported_header_dirs_;
@@ -120,9 +126,8 @@
const std::string &api_;
// TODO: Add to a map of std::sets instead.
std::set<std::string> exported_headers_;
- std::set<std::string> record_decl_set_;
+ std::set<std::string> types_set_;
std::set<std::string> function_decl_set_;
- std::set<std::string> enum_decl_set_;
std::set<std::string> globvar_decl_set_;
// Version Script Regex Matching.
std::set<std::string> functions_regex_matched_set;
@@ -132,12 +137,32 @@
std::regex globvars_vs_regex_;
};
+template <typename T, typename Iterable>
+static bool AddElfSymbols(google::protobuf::RepeatedPtrField<T> *dst,
+ Iterable symbols) {
+ for (auto &&symbol : symbols) {
+ auto *added_symbol = dst->Add();
+ if (added_symbol == nullptr) {
+ return false;
+ }
+ added_symbol->set_name(symbol);
+ }
+ return true;
+}
+
+// To be called right after parsing the .so file / version script.
+bool HeaderAbiLinker::AddElfSymbols(abi_dump::TranslationUnit *linked_tu) {
+
+ return ::AddElfSymbols(linked_tu->mutable_elf_functions(), function_decl_set_)
+ && ::AddElfSymbols(linked_tu->mutable_elf_objects(), globvar_decl_set_);
+}
+
bool HeaderAbiLinker::LinkAndDump() {
abi_dump::TranslationUnit linked_tu;
std::ofstream text_output(out_dump_name_);
google::protobuf::io::OstreamOutputStream text_os(&text_output);
- // If a version script is available, we use that as a filter.
- if (version_script.empty()) {
+ // If the user specifies that a version script should be used, use that.
+ if (!so_file_.empty()) {
exported_headers_ =
abi_util::CollectAllExportedHeaders(exported_header_dirs_);
if (!ParseSoFile()) {
@@ -149,20 +174,20 @@
return false;
}
+ AddElfSymbols(&linked_tu);
+
for (auto &&i : dump_files_) {
abi_dump::TranslationUnit dump_tu;
std::ifstream input(i);
google::protobuf::io::IstreamInputStream text_is(&input);
if (!google::protobuf::TextFormat::Parse(&text_is, &dump_tu) ||
- !LinkRecords(dump_tu, &linked_tu) ||
+ !LinkTypes(dump_tu, &linked_tu) ||
!LinkFunctions(dump_tu, &linked_tu) ||
- !LinkEnums(dump_tu, &linked_tu) ||
!LinkGlobalVars(dump_tu, &linked_tu)) {
llvm::errs() << "Failed to link elements\n";
return false;
}
}
-
if (!google::protobuf::TextFormat::Print(linked_tu, &text_os)) {
llvm::errs() << "Serialization to ostream failed\n";
return false;
@@ -170,22 +195,6 @@
return true;
}
-static std::string GetSymbol(const abi_dump::RecordDecl &element) {
- return element.mangled_record_name();
-}
-
-static std::string GetSymbol(const abi_dump::FunctionDecl &element) {
- return element.mangled_function_name();
-}
-
-static std::string GetSymbol(const abi_dump::EnumDecl &element) {
- return element.basic_abi().linker_set_key();
-}
-
-static std::string GetSymbol(const abi_dump::GlobalVarDecl &element) {
- return element.basic_abi().linker_set_key();
-}
-
static bool QueryRegexMatches(std::set<std::string> *regex_matched_link_set,
const std::regex *vs_regex,
const std::string &symbol) {
@@ -219,10 +228,10 @@
return std::regex(all_regex_match_str);
}
+//TODO: make linking decls multi-threaded b/63590537.
template <typename T>
inline bool HeaderAbiLinker::LinkDecl(
- google::protobuf::RepeatedPtrField<T> *dst,
- std::set<std::string> *link_set,
+ google::protobuf::RepeatedPtrField<T> *dst, std::set<std::string> *link_set,
std::set<std::string> *regex_matched_link_set, const std::regex *vs_regex,
const google::protobuf::RepeatedPtrField<T> &src, bool use_version_script) {
assert(dst != nullptr);
@@ -230,18 +239,20 @@
for (auto &&element : src) {
// If we are not using a version script and exported headers are available,
// filter out unexported abi.
- if (!exported_headers_.empty() &&
- exported_headers_.find(element.source_file()) ==
+ std::string source_file = GetSourceFile(element);
+ // Builtin types will not have source file information.
+ if (!exported_headers_.empty() && !source_file.empty() &&
+ exported_headers_.find(source_file) ==
exported_headers_.end()) {
continue;
}
+ std::string element_str = GetLinkageName(element);
// Check for the existence of the element in linked dump / symbol file.
if (!use_version_script) {
- if (!link_set->insert(element.basic_abi().linker_set_key()).second) {
+ if (!link_set->insert(element_str).second) {
continue;
- }
+ }
} else {
- std::string element_str = GetSymbol(element);
std::set<std::string>::iterator it =
link_set->find(element_str);
if (it == link_set->end()) {
@@ -263,13 +274,52 @@
return true;
}
-bool HeaderAbiLinker::LinkRecords(const abi_dump::TranslationUnit &dump_tu,
- abi_dump::TranslationUnit *linked_tu) {
+
+template<>
+std::string HeaderAbiLinker::GetLinkageName<const abi_dump::FunctionDecl> (
+ const abi_dump::FunctionDecl &element) {
+ return element.linker_set_key();
+}
+
+template<>
+std::string HeaderAbiLinker::GetSourceFile<const abi_dump::FunctionDecl> (
+ const abi_dump::FunctionDecl &element) {
+ return element.source_file();
+}
+
+template<>
+std::string HeaderAbiLinker::GetLinkageName<const abi_dump::GlobalVarDecl> (
+ const abi_dump::GlobalVarDecl &element) {
+ return element.linker_set_key();
+}
+
+template<>
+std::string HeaderAbiLinker::GetSourceFile<const abi_dump::GlobalVarDecl> (
+ const abi_dump::GlobalVarDecl &element) {
+ return element.source_file();
+}
+
+bool HeaderAbiLinker::LinkTypes(const abi_dump::TranslationUnit &dump_tu,
+ abi_dump::TranslationUnit *linked_tu) {
assert(linked_tu != nullptr);
- // Even if version scripts are available we take in records, since the symbols
- // in the version script might reference a record exposed by the library.
- return LinkDecl(linked_tu->mutable_records(), &record_decl_set_, nullptr,
- nullptr, dump_tu.records(), false);
+ // Even if version scripts are available we take in types, since the symbols
+ // in the version script might reference a type exposed by the library.
+ return LinkDecl(linked_tu->mutable_record_types(), &types_set_, nullptr,
+ nullptr, dump_tu.record_types(), false) &&
+ LinkDecl(linked_tu->mutable_enum_types(), &types_set_, nullptr,
+ nullptr, dump_tu.enum_types(), false) &&
+ LinkDecl(linked_tu->mutable_builtin_types(), &types_set_, nullptr,
+ nullptr, dump_tu.builtin_types(), false) &&
+ LinkDecl(linked_tu->mutable_pointer_types(), &types_set_, nullptr,
+ nullptr, dump_tu.pointer_types(), false) &&
+ LinkDecl(linked_tu->mutable_rvalue_reference_types(), &types_set_, nullptr,
+ nullptr, dump_tu.rvalue_reference_types(), false) &&
+ LinkDecl(linked_tu->mutable_lvalue_reference_types(), &types_set_, nullptr,
+ nullptr, dump_tu.lvalue_reference_types(), false) &&
+ LinkDecl(linked_tu->mutable_array_types(), &types_set_, nullptr,
+ nullptr, dump_tu.array_types(), false) &&
+ LinkDecl(linked_tu->mutable_qualified_types(), &types_set_, nullptr,
+ nullptr, dump_tu.qualified_types(), false);
}
bool HeaderAbiLinker::LinkFunctions(const abi_dump::TranslationUnit &dump_tu,
@@ -281,15 +331,6 @@
(!version_script_.empty() || !so_file_.empty()));
}
-bool HeaderAbiLinker::LinkEnums(const abi_dump::TranslationUnit &dump_tu,
- abi_dump::TranslationUnit *linked_tu) {
- assert(linked_tu != nullptr);
- // Even if version scripts are available we take in records, since the symbols
- // in the version script might reference an enum exposed by the library.
- return LinkDecl(linked_tu->mutable_enums(), &enum_decl_set_, nullptr,
- nullptr, dump_tu.enums(), false);
-}
-
bool HeaderAbiLinker::LinkGlobalVars(const abi_dump::TranslationUnit &dump_tu,
abi_dump::TranslationUnit *linked_tu) {
assert(linked_tu != nullptr);
@@ -345,6 +386,10 @@
int main(int argc, const char **argv) {
GOOGLE_PROTOBUF_VERIFY_VERSION;
llvm::cl::ParseCommandLineOptions(argc, argv, "header-linker");
+ if (so_file.empty() && version_script.empty()) {
+ llvm::errs() << "One of -so or -v needs to be specified\n";
+ return -1;
+ }
if (no_filter) {
static_cast<std::vector<std::string> &>(exported_header_dirs).clear();
}
diff --git a/vndk/tools/header-checker/header-abi-util/include/header_abi_util.h b/vndk/tools/header-checker/header-abi-util/include/header_abi_util.h
index b335cdd..5f18ab7 100644
--- a/vndk/tools/header-checker/header-abi-util/include/header_abi_util.h
+++ b/vndk/tools/header-checker/header-abi-util/include/header_abi_util.h
@@ -18,6 +18,7 @@
#include <llvm/Support/Endian.h>
#include <llvm/Support/raw_ostream.h>
+#include <map>
#include <regex>
#include <set>
#include <string>
@@ -128,4 +129,60 @@
bool IsSymbolExported(const Elf_Sym *elf_sym) const;
};
+template <typename T, typename K>
+std::vector<T> FindRemovedElements(
+ const std::map<K, T> &old_elements_map,
+ const std::map<K, T> &new_elements_map) {
+ std::vector<T> removed_elements;
+ for (auto &&map_element : old_elements_map) {
+ auto element_key = map_element.first;
+ auto new_element = new_elements_map.find(element_key);
+ if (new_element == new_elements_map.end()) {
+ removed_elements.emplace_back(map_element.second);
+ }
+ }
+ return removed_elements;
+}
+
+template <typename T, typename F, typename K, typename Iterable>
+inline void AddToMap(std::map<K, T> *dst, Iterable &src, F get_key) {
+ for (auto &&element : src) {
+ dst->insert(std::make_pair(get_key(&element), &element));
+ }
+}
+
+template <typename F, typename K, typename Iterable>
+inline void AddToSet(std::set<K> *dst, Iterable &src, F get_key) {
+ for (auto &&element : src) {
+ dst->insert(get_key(element));
+ }
+}
+
+template <typename K, typename T>
+std::vector<std::pair<T, T>> FindCommonElements(
+ const std::map<K, T> &old_elements_map,
+ const std::map<K, T> &new_elements_map) {
+ std::vector<std::pair<T, T>> common_elements;
+ typename std::map<K, T>::const_iterator old_element =
+ old_elements_map.begin();
+ typename std::map<K, T>::const_iterator new_element =
+ new_elements_map.begin();
+ while (old_element != old_elements_map.end() &&
+ new_element != new_elements_map.end()) {
+ if (old_element->first == new_element->first) {
+ common_elements.emplace_back(std::make_pair(
+ old_element->second, new_element->second));
+ old_element++;
+ new_element++;
+ continue;
+ }
+ if (old_element->first < new_element->first) {
+ old_element++;
+ } else {
+ new_element++;
+ }
+ }
+ return common_elements;
+}
+
} // namespace abi_util
diff --git a/vndk/tools/header-checker/header-abi-util/include/ir_representation.h b/vndk/tools/header-checker/header-abi-util/include/ir_representation.h
new file mode 100644
index 0000000..0567d0e
--- /dev/null
+++ b/vndk/tools/header-checker/header-abi-util/include/ir_representation.h
@@ -0,0 +1,1126 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef IR_
+#define IR_
+
+#include <map>
+#include <regex>
+#include <set>
+#include <string>
+#include <vector>
+#include <memory>
+
+// Classes which act as middle-men between clang AST parsing routines and
+// message format specific dumpers.
+namespace abi_util {
+
+enum CompatibilityStatusIR {
+ Compatible = 0,
+ UnreferencedChanges = 1,
+ Extension = 4,
+ Incompatible = 8
+};
+
+static inline CompatibilityStatusIR operator|(CompatibilityStatusIR f,
+ CompatibilityStatusIR s) {
+ return static_cast<CompatibilityStatusIR>(
+ static_cast<std::underlying_type<CompatibilityStatusIR>::type>(f) |
+ static_cast<std::underlying_type<CompatibilityStatusIR>::type>(s));
+}
+
+static inline CompatibilityStatusIR operator&(
+ CompatibilityStatusIR f, CompatibilityStatusIR s) {
+ return static_cast<CompatibilityStatusIR>(
+ static_cast<std::underlying_type<CompatibilityStatusIR>::type>(f) &
+ static_cast<std::underlying_type<CompatibilityStatusIR>::type>(s));
+}
+
+enum AccessSpecifierIR {
+ PublicAccess = 1,
+ ProtectedAccess = 2,
+ PrivateAccess = 3
+};
+
+enum LinkableMessageKind {
+ RecordTypeKind,
+ EnumTypeKind,
+ PointerTypeKind,
+ QualifiedTypeKind,
+ ArrayTypeKind,
+ LvalueReferenceTypeKind,
+ RvalueReferenceTypeKind,
+ BuiltinTypeKind,
+ FunctionKind,
+ GlobalVarKind
+};
+
+class LinkableMessageIR {
+ public:
+ const std::string &GetLinkerSetKey() const {
+ return linker_set_key_;
+ }
+
+ void SetSourceFile(const std::string &source_file) {
+ source_file_ = source_file;
+ }
+
+ void SetLinkerSetKey(const std::string &linker_set_key) {
+ linker_set_key_ = linker_set_key;
+ }
+
+ const std::string &GetSourceFile() const {
+ return source_file_;
+ }
+
+ virtual LinkableMessageKind GetKind() const = 0;
+
+ virtual ~LinkableMessageIR() {}
+
+ protected:
+ // The source file where this message comes from. This will be an empty string
+ // for built-in types
+ std::string source_file_;
+ std::string linker_set_key_;
+};
+
+class BasicTypeInfoIR {
+ public:
+ BasicTypeInfoIR(const std::string &name, const std::string &type,
+ const std::string linker_set_key, uint64_t size,
+ uint32_t alignment)
+ : name_(name), referenced_type_(type), linker_set_key_(linker_set_key) ,
+ size_(size), alignment_(alignment) { }
+
+ BasicTypeInfoIR() { }
+
+ std::string GetLinkerSetKey() {
+ return linker_set_key_;
+ }
+
+ protected:
+ std::string name_;
+ std::string referenced_type_;
+ std::string linker_set_key_;
+ uint64_t size_;
+ uint32_t alignment_;
+};
+
+// TODO: Break this up into types with sizes and those without types ?
+class TypeIR : public LinkableMessageIR {
+ public:
+ void SetName(const std::string &name) {
+ name_ = name;
+ }
+
+ const std::string &GetName() const {
+ return name_;
+ }
+
+ void SetReferencedType(const std::string &type) {
+ referenced_type_ = type;
+ }
+
+ const std::string &GetReferencedType() const {
+ return referenced_type_;
+ }
+
+ void SetSize(uint64_t size) {
+ size_ = size;
+ }
+ uint64_t GetSize() const {
+ return size_;
+ }
+ void SetAlignment(uint32_t alignment) {
+ alignment_ = alignment;
+ }
+ uint32_t GetAlignment() const {
+ return alignment_;
+ }
+ ~TypeIR() override { }
+
+ protected:
+ std::string name_;
+ std::string referenced_type_;
+ uint64_t size_;
+ uint32_t alignment_;
+};
+
+class VTableComponentIR {
+ public:
+ enum Kind {
+ VCallOffset = 0,
+ VBaseOffset = 1,
+ OffsetToTop = 2,
+ RTTI = 3,
+ FunctionPointer = 4,
+ CompleteDtorPointer = 5,
+ DeletingDtorPointer = 6,
+ UnusedFunctionPointer = 7
+ };
+
+ VTableComponentIR(const std::string &name, Kind kind, int64_t value)
+ : component_name_(name), kind_(kind), value_(value) { }
+
+ VTableComponentIR() { }
+
+ Kind GetKind() const {
+ return kind_;
+ }
+
+ int64_t GetValue() const {
+ return value_;
+ }
+
+ const std::string &GetName() const {
+ return component_name_;
+ }
+
+ protected:
+ std::string component_name_;
+ Kind kind_;
+ int64_t value_;
+};
+
+class VTableLayoutIR {
+ public:
+ void AddVTableComponent(VTableComponentIR &&vtable_component) {
+ vtable_components_.emplace_back(std::move(vtable_component));
+ }
+
+ const std::vector<VTableComponentIR> &GetVTableComponents() const {
+ return vtable_components_;
+ }
+
+ uint64_t GetVTableNumEntries() const {
+ return vtable_components_.size();
+ }
+
+ protected:
+ std::vector<VTableComponentIR> vtable_components_;
+};
+
+class CXXBaseSpecifierIR {
+ public:
+ CXXBaseSpecifierIR(const std::string &type, bool is_virtual,
+ AccessSpecifierIR access) :
+ referenced_type_(type), is_virtual_(is_virtual), access_(access) { }
+
+ CXXBaseSpecifierIR() { }
+
+ const std::string &GetReferencedType() const {
+ return referenced_type_;
+ }
+
+ bool IsVirtual() const {
+ return is_virtual_;
+ }
+
+ AccessSpecifierIR GetAccess() const {
+ return access_;
+ }
+
+ protected:
+ std::string referenced_type_;
+ bool is_virtual_;
+ AccessSpecifierIR access_;
+};
+
+class TemplateElementIR {
+ public:
+ TemplateElementIR(std::string &&type)
+ : referenced_type_(std::move(type)) { }
+
+ TemplateElementIR(const std::string &type)
+ : referenced_type_(type) { }
+
+ TemplateElementIR() { }
+
+ const std::string &GetReferencedType() const {
+ return referenced_type_;
+ }
+
+ protected:
+ std::string referenced_type_;
+};
+
+class TemplateInfoIR {
+ public:
+ void AddTemplateElement(TemplateElementIR &&element) {
+ template_elements_.emplace_back(element);
+ }
+
+ const std::vector<TemplateElementIR> &GetTemplateElements() const {
+ return template_elements_;
+ }
+
+ protected:
+ std::vector<TemplateElementIR> template_elements_;
+};
+
+class TemplatedArtifactIR {
+ public:
+ void SetTemplateInfo(TemplateInfoIR &&template_info) {
+ template_info_ = std::move(template_info);
+ }
+
+ const std::vector<TemplateElementIR> &GetTemplateElements() const {
+ return template_info_.GetTemplateElements();
+ }
+
+ protected:
+ TemplateInfoIR template_info_;
+};
+
+class RecordFieldIR {
+ public:
+ RecordFieldIR(const std::string &name, const std::string &type,
+ uint64_t offset, AccessSpecifierIR access)
+ : name_(name), referenced_type_(type), offset_(offset),
+ access_(access) { }
+
+ RecordFieldIR() { }
+
+ const std::string &GetName() const {
+ return name_;
+ }
+
+ const std::string &GetReferencedType() const {
+ return referenced_type_;
+ }
+
+ uint64_t GetOffset() const {
+ return offset_;
+ }
+
+ AccessSpecifierIR GetAccess() const {
+ return access_;
+ }
+
+ protected:
+ std::string name_;
+ std::string referenced_type_;
+ uint64_t offset_;
+ AccessSpecifierIR access_;
+};
+
+class RecordTypeIR: public TypeIR, public TemplatedArtifactIR {
+ public:
+ enum RecordKind {
+ struct_kind,
+ class_kind,
+ union_kind
+ };
+
+ void AddRecordField(RecordFieldIR &&field) {
+ fields_.emplace_back(std::move(field));
+ }
+
+ void SetRecordFields(std::vector<RecordFieldIR> &&fields) {
+ fields_ = std::move(fields);
+ }
+
+ void SetVTableLayout(VTableLayoutIR &&vtable_layout) {
+ vtable_layout_ = std::move(vtable_layout);
+ }
+
+ const VTableLayoutIR &GetVTableLayout() const {
+ return vtable_layout_;
+ }
+
+ void AddCXXBaseSpecifier(CXXBaseSpecifierIR &&base_specifier) {
+ bases_.emplace_back(std::move(base_specifier));
+ }
+
+ void SetCXXBaseSpecifiers(std::vector<CXXBaseSpecifierIR> &&bases) {
+ bases_ = std::move(bases);
+ }
+
+ const std::vector<CXXBaseSpecifierIR> &GetBases() const {
+ return bases_;
+ }
+
+ void SetAccess(AccessSpecifierIR access) { access_ = access;}
+
+ AccessSpecifierIR GetAccess() const {
+ return access_;
+ }
+
+ const std::vector<RecordFieldIR> &GetFields() const {
+ return fields_;
+ }
+
+ LinkableMessageKind GetKind() const override {
+ return LinkableMessageKind::RecordTypeKind;
+ }
+
+ uint64_t GetVTableNumEntries() const {
+ return vtable_layout_.GetVTableNumEntries();
+ }
+
+ void SetRecordKind(RecordKind record_kind) {
+ record_kind_ = record_kind;
+ }
+
+ RecordKind GetRecordKind() const {
+ return record_kind_;
+ }
+
+ void SetAnonymity(bool is_anonymous) {
+ is_anonymous_ = is_anonymous;
+ }
+
+ bool IsAnonymous() const {
+ return is_anonymous_;
+ }
+
+ protected:
+ std::vector<RecordFieldIR> fields_;
+ VTableLayoutIR vtable_layout_;
+ std::vector<CXXBaseSpecifierIR> bases_;
+ AccessSpecifierIR access_;
+ bool is_anonymous_;
+ RecordKind record_kind_;
+};
+
+class EnumFieldIR {
+ public:
+ EnumFieldIR(const std::string &name, int value)
+ : name_(name), value_(value) { }
+ const std::string &GetName() const {
+ return name_;
+ }
+
+ int GetValue() const {
+ return value_;
+ }
+
+ protected:
+ std::string name_;
+ int value_;
+};
+
+class EnumTypeIR : public TypeIR {
+ public:
+ // Add Methods to get information from the IR.
+ void AddEnumField(EnumFieldIR &&field) {
+ fields_.emplace_back(std::move(field));
+ }
+
+ void SetAccess(AccessSpecifierIR access) { access_ = access;}
+
+ LinkableMessageKind GetKind() const override {
+ return LinkableMessageKind::EnumTypeKind;
+ }
+
+ AccessSpecifierIR GetAccess() const {
+ return access_;
+ }
+
+ void SetUnderlyingType(std::string &&underlying_type) {
+ underlying_type_ = std::move(underlying_type);
+ }
+
+ void SetUnderlyingType(const std::string &underlying_type) {
+ underlying_type_ = underlying_type;
+ }
+
+ const std::string &GetUnderlyingType() const {
+ return underlying_type_;
+ }
+
+ void SetFields(std::vector<EnumFieldIR> &&fields) {
+ fields_ = std::move(fields);
+ }
+
+ const std::vector<EnumFieldIR> &GetFields() const {
+ return fields_;
+ }
+
+ protected:
+ std::vector<EnumFieldIR> fields_;
+ std::string underlying_type_;
+ AccessSpecifierIR access_;
+};
+
+class ArrayTypeIR : public TypeIR {
+ public:
+ LinkableMessageKind GetKind() const override {
+ return LinkableMessageKind::ArrayTypeKind;
+ }
+};
+
+class PointerTypeIR : public TypeIR {
+ public:
+ LinkableMessageKind GetKind() const override {
+ return LinkableMessageKind::PointerTypeKind;
+ }
+};
+
+class BuiltinTypeIR : public TypeIR {
+ public:
+ void SetSignedness(bool is_unsigned) {
+ is_unsigned_ = is_unsigned;
+ }
+
+ bool IsUnsigned() const {
+ return is_unsigned_;
+ }
+
+ void SetIntegralType(bool is_integral_type) {
+ is_integral_type_ = is_integral_type;
+ }
+
+ bool IsIntegralType() const {
+ return is_integral_type_;
+ }
+
+ public:
+ LinkableMessageKind GetKind() const override {
+ return LinkableMessageKind::BuiltinTypeKind;
+ }
+
+ protected:
+ bool is_unsigned_;
+ bool is_integral_type_;
+};
+
+class LvalueReferenceTypeIR : public TypeIR {
+ public:
+ LinkableMessageKind GetKind() const override {
+ return LinkableMessageKind::LvalueReferenceTypeKind;
+ }
+};
+
+class RvalueReferenceTypeIR : public TypeIR {
+ public:
+ LinkableMessageKind GetKind() const override {
+ return LinkableMessageKind::RvalueReferenceTypeKind;
+ }
+};
+
+class QualifiedTypeIR : public TypeIR {
+ public:
+ void SetConstness(bool is_const) {
+ is_const_ = is_const;
+ }
+
+ bool IsConst() const {
+ return is_const_;
+ }
+
+ void SetRestrictedness(bool is_restricted) {
+ is_restricted_ = is_restricted;
+ }
+
+ bool IsRestricted() const {
+ return is_restricted_;
+ }
+
+ void SetVolatility(bool is_volatile) {
+ is_volatile_ = is_volatile;
+ }
+
+ bool IsVolatile() const {
+ return is_volatile_;
+ }
+
+ public:
+ LinkableMessageKind GetKind() const override {
+ return LinkableMessageKind::QualifiedTypeKind;
+ }
+
+ protected:
+ bool is_const_;
+ bool is_restricted_;
+ bool is_volatile_;
+};
+
+class GlobalVarIR: public LinkableMessageIR {
+ public:
+ // Add Methods to get information from the IR.
+ void SetReferencedType(const std::string &type) {
+ referenced_type_ = type;
+ }
+
+ const std::string &GetReferencedType() const {
+ return referenced_type_;
+ }
+
+ void SetName(std::string &&name) {
+ name_ = std::move(name);
+ }
+
+ void SetName(const std::string &name) {
+ name_ = name;
+ }
+
+ const std::string &GetName() const {
+ return name_;
+ }
+
+ AccessSpecifierIR GetAccess() const {
+ return access_;
+ }
+
+ LinkableMessageKind GetKind() const override {
+ return LinkableMessageKind::GlobalVarKind;
+ }
+
+ protected:
+ std::string referenced_type_; // underlying type
+ std::string name_;
+ AccessSpecifierIR access_;
+};
+
+class ParamIR {
+ public:
+ ParamIR(const std::string &type, bool is_default) :
+ referenced_type_(type) , is_default_(is_default) {}
+
+ const std::string &GetReferencedType() const {
+ return referenced_type_;
+ }
+
+ bool GetIsDefault() const {
+ return is_default_;
+ }
+
+ protected:
+ std::string referenced_type_;
+ bool is_default_;
+};
+
+class FunctionIR : public LinkableMessageIR, public TemplatedArtifactIR {
+ public:
+ void SetReturnType(const std::string &type) {
+ return_type_ = type;
+ }
+
+ const std::string &GetReturnType() const {
+ return return_type_;
+ }
+
+ void AddParameter(ParamIR &¶meter) {
+ parameters_.emplace_back(std::move(parameter));
+ }
+
+ void SetAccess(AccessSpecifierIR access) {
+ access_ = access;
+ }
+
+ AccessSpecifierIR GetAccess() const {
+ return access_;
+ }
+
+ LinkableMessageKind GetKind() const override {
+ return LinkableMessageKind::FunctionKind;
+ }
+
+ const std::vector<ParamIR> &GetParameters() const {
+ return parameters_;
+ }
+
+ void SetName(const std::string &name) {
+ name_ = name;
+ }
+
+ const std::string &GetName() const {
+ return name_;
+ }
+
+ protected:
+ std::string return_type_; // return type reference
+ std::string linkage_name_;
+ std::string name_;
+ std::vector<ParamIR> parameters_;
+ AccessSpecifierIR access_;
+};
+
+class ElfSymbolIR {
+ public:
+ enum ElfSymbolKind {
+ ElfFunctionKind,
+ ElfObjectKind
+ };
+
+ const std::string GetName() const {
+ return name_;
+ }
+
+ ElfSymbolIR(const std::string &name) : name_(name) { }
+
+ virtual ElfSymbolKind GetKind() const = 0;
+
+ virtual ~ElfSymbolIR() { }
+
+ protected:
+ std::string name_;
+};
+
+class ElfFunctionIR : public ElfSymbolIR{
+ public:
+ ElfSymbolKind GetKind() const override {
+ return ElfFunctionKind;
+ }
+
+ ElfFunctionIR(const std::string &name) : ElfSymbolIR(name) { }
+};
+
+class ElfObjectIR : public ElfSymbolIR {
+ public:
+ ElfSymbolKind GetKind() const override {
+ return ElfObjectKind;
+ }
+
+ ElfObjectIR(const std::string &name) : ElfSymbolIR(name) { }
+};
+
+class IRDumper {
+ public:
+ IRDumper(const std::string &dump_path) : dump_path_(dump_path) { }
+
+ static std::unique_ptr<IRDumper> CreateIRDumper(const std::string &type,
+ const std::string &dump_path);
+
+ virtual bool AddLinkableMessageIR(const LinkableMessageIR *) = 0;
+
+ virtual bool Dump() = 0;
+
+ virtual ~IRDumper() {}
+
+ protected:
+ const std::string &dump_path_;
+};
+
+class TextFormatToIRReader {
+ public:
+ TextFormatToIRReader(const std::string &dump_path) : dump_path_(dump_path) { }
+
+ const std::vector<FunctionIR> &GetFunctions() const {
+ return functions_;
+ }
+
+ const std::vector<GlobalVarIR> &GetGlobalVariables() const {
+ return global_variables_;
+ }
+
+ const std::vector<RecordTypeIR> &GetRecordTypes() const {
+ return record_types_;
+ }
+
+ const std::vector<EnumTypeIR> &GetEnumTypes() const {
+ return enum_types_;
+ }
+
+ const std::vector<LvalueReferenceTypeIR> &GetLvalueReferenceTypes() const {
+ return lvalue_reference_types_;
+ }
+
+ const std::vector<RvalueReferenceTypeIR> &GetRvalueReferenceTypes() const {
+ return rvalue_reference_types_;
+ }
+
+ const std::vector<QualifiedTypeIR> &GetQualifiedTypes() const {
+ return qualified_types_;
+ }
+
+ const std::vector<ArrayTypeIR> &GetArrayTypes() const {
+ return array_types_;
+ }
+
+ const std::vector<PointerTypeIR> &GetPointerTypes() const {
+ return pointer_types_;
+ }
+
+ const std::vector<BuiltinTypeIR> &GetBuiltinTypes() const {
+ return builtin_types_;
+ }
+
+ const std::vector<ElfFunctionIR> &GetElfFunctions() const {
+ return elf_functions_;
+ }
+
+ const std::vector<ElfObjectIR> &GetElfObjects() const {
+ return elf_objects_;
+ }
+
+ virtual bool ReadDump() = 0;
+
+ virtual ~TextFormatToIRReader() { }
+
+ static std::unique_ptr<TextFormatToIRReader> CreateTextFormatToIRReader(
+ const std::string &text_format, const std::string &dump_path);
+
+ protected:
+ const std::string &dump_path_;
+ std::vector<FunctionIR> functions_;
+ std::vector<GlobalVarIR> global_variables_;
+ std::vector<RecordTypeIR> record_types_;
+ std::vector<EnumTypeIR> enum_types_;
+ std::vector<PointerTypeIR> pointer_types_;
+ std::vector<LvalueReferenceTypeIR> lvalue_reference_types_;
+ std::vector<RvalueReferenceTypeIR> rvalue_reference_types_;
+ std::vector<ArrayTypeIR> array_types_;
+ std::vector<BuiltinTypeIR> builtin_types_;
+ std::vector<QualifiedTypeIR> qualified_types_;
+ std::vector<ElfFunctionIR> elf_functions_;
+ std::vector<ElfObjectIR> elf_objects_;
+};
+
+class DiffMessageIR {
+ public:
+ virtual LinkableMessageKind Kind() const = 0;
+ void SetName(const std::string &name) {
+ name_ = name;
+ }
+
+ const std::string &GetName() const {
+ return name_;
+ }
+
+ virtual ~DiffMessageIR() { }
+
+ protected:
+ std::string name_;
+};
+
+class AccessSpecifierDiffIR {
+ public:
+ AccessSpecifierDiffIR(AccessSpecifierIR old_access,
+ AccessSpecifierIR new_access)
+ : old_access_(old_access), new_access_(new_access) { }
+
+ protected:
+ AccessSpecifierIR old_access_;
+ AccessSpecifierIR new_access_;
+};
+
+class TypeDiffIR {
+ public:
+ TypeDiffIR(std::pair<uint64_t, uint64_t> &&sizes,
+ std::pair<uint32_t, uint32_t> &&alignment)
+ : sizes_(std::move(sizes)), alignments_(std::move(alignment)) { }
+
+ const std::pair<uint64_t, uint64_t> &GetSizes() const {
+ return sizes_;
+ }
+
+ const std::pair<uint32_t, uint32_t> &GetAlignments() const {
+ return alignments_;
+ }
+
+ protected:
+ std::pair<uint64_t, uint64_t> sizes_;
+ std::pair<uint32_t, uint32_t> alignments_;
+};
+
+class VTableLayoutDiffIR {
+ public:
+ VTableLayoutDiffIR(const VTableLayoutIR &old_layout,
+ const VTableLayoutIR &new_layout)
+ : old_layout_(old_layout), new_layout_(new_layout) { }
+
+ const VTableLayoutIR &GetOldVTable() const {
+ return old_layout_;
+ }
+
+ const VTableLayoutIR &GetNewVTable() const {
+ return new_layout_;
+ }
+
+ protected:
+ const VTableLayoutIR &old_layout_;
+ const VTableLayoutIR &new_layout_;
+};
+
+class RecordFieldDiffIR {
+ public:
+ RecordFieldDiffIR(const RecordFieldIR *old_field,
+ const RecordFieldIR *new_field)
+ : old_field_(old_field), new_field_(new_field) { }
+ const RecordFieldIR *GetOldField() const {
+ return old_field_;
+ }
+
+ const RecordFieldIR *GetNewField() const {
+ return new_field_;
+ }
+
+ protected:
+ const RecordFieldIR *old_field_;
+ const RecordFieldIR *new_field_;
+};
+
+class CXXBaseSpecifierDiffIR {
+ public:
+ CXXBaseSpecifierDiffIR(
+ const std::vector<CXXBaseSpecifierIR> &old_base_specifiers,
+ const std::vector<CXXBaseSpecifierIR> &new_base_specifiers)
+ : old_base_specifiers_(old_base_specifiers),
+ new_base_specifiers_(new_base_specifiers) { }
+ const std::vector<CXXBaseSpecifierIR> &GetOldBases() const {
+ return old_base_specifiers_;
+ }
+
+ const std::vector<CXXBaseSpecifierIR> &GetNewBases() const {
+ return new_base_specifiers_;
+ }
+
+ protected:
+ const std::vector<CXXBaseSpecifierIR> &old_base_specifiers_;
+ const std::vector<CXXBaseSpecifierIR> &new_base_specifiers_;
+};
+
+class RecordTypeDiffIR : public DiffMessageIR {
+ public:
+ LinkableMessageKind Kind() const override {
+ return LinkableMessageKind::RecordTypeKind;
+ }
+
+ void SetFieldDiffs(std::vector<RecordFieldDiffIR> &&field_diffs) {
+ field_diffs_ = std::move(field_diffs);
+ }
+
+ const std::vector<RecordFieldDiffIR> &GetFieldDiffs() const {
+ return field_diffs_;
+ }
+
+ void SetFieldsRemoved(std::vector<const RecordFieldIR *> &&fields_removed) {
+ fields_removed_ = std::move(fields_removed);
+ }
+
+ const std::vector<const RecordFieldIR *> &GetFieldsRemoved() const {
+ return fields_removed_;
+ }
+
+ void SetVTableLayoutDiff(std::unique_ptr<VTableLayoutDiffIR> &&vtable_diffs) {
+ vtable_diffs_ = std::move(vtable_diffs);
+ }
+
+ void SetTypeDiff(std::unique_ptr<TypeDiffIR> &&type_diff) {
+ type_diff_ = std::move(type_diff);
+ }
+
+ void SetAccessDiff(std::unique_ptr<AccessSpecifierDiffIR> &&access_diff) {
+ access_diff_ = std::move(access_diff);
+ }
+
+ void SetBaseSpecifierDiffs(
+ std::unique_ptr<CXXBaseSpecifierDiffIR> &&base_diffs) {
+ base_specifier_diffs_ = std::move(base_diffs);
+ }
+
+ bool DiffExists() const {
+ return (type_diff_ != nullptr) || (vtable_diffs_ != nullptr) ||
+ (fields_removed_.size() != 0) || (field_diffs_.size() != 0) ||
+ (access_diff_ != nullptr) || (base_specifier_diffs_ != nullptr);
+ }
+
+ const TypeDiffIR *GetTypeDiff() const {
+ return type_diff_.get();
+ }
+
+ const VTableLayoutDiffIR *GetVTableLayoutDiff() const {
+ return vtable_diffs_.get();
+ }
+
+ const CXXBaseSpecifierDiffIR *GetBaseSpecifiers() const {
+ return base_specifier_diffs_.get();
+ }
+
+ protected:
+ // optional implemented with vector / std::unique_ptr.
+ std::unique_ptr<TypeDiffIR> type_diff_;
+ std::unique_ptr<VTableLayoutDiffIR> vtable_diffs_;
+ std::vector<RecordFieldDiffIR> field_diffs_;
+ std::vector<const RecordFieldIR *> fields_removed_;
+ std::unique_ptr<AccessSpecifierDiffIR> access_diff_;
+ std::unique_ptr<CXXBaseSpecifierDiffIR> base_specifier_diffs_;
+ // Template Diffs are not needed since they will show up in the linker set
+ // key.
+};
+
+class EnumFieldDiffIR {
+ public:
+ EnumFieldDiffIR(const EnumFieldIR *old_field, const EnumFieldIR *new_field)
+ : old_field_(old_field), new_field_(new_field) { }
+
+ const EnumFieldIR *GetOldField() const {
+ return old_field_;
+ }
+
+ const EnumFieldIR *GetNewField() const {
+ return new_field_;
+ }
+
+ protected:
+ const EnumFieldIR *old_field_;
+ const EnumFieldIR *new_field_;
+};
+
+class EnumTypeDiffIR : public DiffMessageIR {
+ public:
+ void SetFieldsRemoved(std::vector<const EnumFieldIR *> &&fields_removed) {
+ fields_removed_ = std::move(fields_removed);
+ }
+
+ const std::vector<const EnumFieldIR *> &GetFieldsRemoved() const {
+ return fields_removed_;
+ }
+
+ void SetFieldsAdded(std::vector<const EnumFieldIR *> &&fields_added) {
+ fields_added_ = std::move(fields_added);
+ }
+
+ const std::vector<const EnumFieldIR *> &GetFieldsAdded() const {
+ return fields_added_;
+ }
+
+ void SetFieldsDiff(std::vector<EnumFieldDiffIR> &&fields_diff) {
+ fields_diff_ = std::move(fields_diff);
+ }
+
+ const std::vector<EnumFieldDiffIR> &GetFieldsDiff() const {
+ return fields_diff_;
+ }
+
+ void SetUnderlyingTypeDiff(
+ std::unique_ptr<std::pair<std::string, std::string>> &&utype_diff) {
+ underlying_type_diff_ = std::move(utype_diff);
+ }
+
+ const std::pair<std::string, std::string> *GetUnderlyingTypeDiff() const {
+ return underlying_type_diff_.get();
+ }
+
+ bool IsExtended() const {
+ if (fields_removed_.size() == 0 && fields_diff_.size() == 0 &&
+ fields_added_.size() != 0) {
+ return true;
+ }
+
+ return false;
+ }
+
+ bool IsIncompatible() const {
+ if (fields_removed_.size() != 0 || fields_diff_.size() != 0) {
+ return true;
+ }
+
+ return false;
+ }
+
+ LinkableMessageKind Kind() const override {
+ return LinkableMessageKind::EnumTypeKind;
+ }
+
+ protected:
+ // The underlying type can only be integral, so we just need to check for
+ // referenced type.
+ std::unique_ptr<std::pair<std::string, std::string>> underlying_type_diff_;
+ std::vector<const EnumFieldIR *> fields_removed_;
+ std::vector<const EnumFieldIR *> fields_added_;
+ std::vector<EnumFieldDiffIR> fields_diff_;
+ // Modifiable to allow implicit construction.
+ std::string name_;
+};
+
+class GlobalVarDiffIR : public DiffMessageIR {
+ public:
+ LinkableMessageKind Kind() const override {
+ return LinkableMessageKind::GlobalVarKind;
+ }
+
+ GlobalVarDiffIR(const GlobalVarIR *old_global_var,
+ const GlobalVarIR *new_global_var)
+ : old_global_var_(old_global_var), new_global_var_(new_global_var) { }
+
+ const GlobalVarIR *GetOldGlobalVar() const {
+ return old_global_var_;
+ }
+
+ const GlobalVarIR *GetNewGlobalVar() const {
+ return new_global_var_;
+ }
+
+ protected:
+ const GlobalVarIR *old_global_var_;
+ const GlobalVarIR *new_global_var_;
+};
+
+class FunctionDiffIR : public DiffMessageIR {
+ public:
+ LinkableMessageKind Kind() const override {
+ return LinkableMessageKind::FunctionKind;
+ }
+
+ FunctionDiffIR(const FunctionIR *old_function,
+ const FunctionIR *new_function)
+ : old_function_(old_function), new_function_(new_function) { }
+
+ const FunctionIR *GetOldFunction() const {
+ return old_function_;
+ }
+
+ const FunctionIR *GetNewFunction() const {
+ return new_function_;
+ }
+
+ protected:
+ const FunctionIR *old_function_;
+ const FunctionIR *new_function_;
+};
+
+class IRDiffDumper {
+ public:
+ enum DiffKind {
+ Extension, // Applicable for enums.
+ Added,
+ Removed,
+ Referenced,
+ Unreferenced
+ };
+
+ IRDiffDumper(const std::string &dump_path) : dump_path_(dump_path) { }
+
+ virtual bool AddDiffMessageIR(const DiffMessageIR *,
+ const std::string &type_stack,
+ DiffKind diff_kind) = 0;
+
+ virtual bool AddLinkableMessageIR(const LinkableMessageIR *,
+ DiffKind diff_kind) = 0;
+
+ virtual bool AddElfSymbolMessageIR(const ElfSymbolIR *,
+ DiffKind diff_kind) = 0;
+
+ virtual void AddLibNameIR(const std::string &name) = 0;
+
+ virtual void AddArchIR(const std::string &arch) = 0;
+
+ virtual void AddCompatibilityStatusIR(CompatibilityStatusIR status) = 0;
+
+ virtual bool Dump() = 0;
+
+ virtual CompatibilityStatusIR GetCompatibilityStatusIR() = 0;
+
+ virtual ~IRDiffDumper() {}
+ static std::unique_ptr<IRDiffDumper> CreateIRDiffDumper(
+ const std::string &type, const std::string &dump_path);
+ protected:
+ const std::string &dump_path_;
+};
+
+} // namespace abi_util
+
+#endif // IR_
diff --git a/vndk/tools/header-checker/header-abi-util/include/ir_representation_protobuf.h b/vndk/tools/header-checker/header-abi-util/include/ir_representation_protobuf.h
new file mode 100644
index 0000000..e5cf61e
--- /dev/null
+++ b/vndk/tools/header-checker/header-abi-util/include/ir_representation_protobuf.h
@@ -0,0 +1,418 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef IR_PROTOBUF_
+#define IR_PROTOBUF_
+
+#include <ir_representation.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+#include "proto/abi_dump.pb.h"
+#include "proto/abi_diff.pb.h"
+#pragma clang diagnostic pop
+
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+
+// Classes which act as middle-men between clang AST parsing routines and
+// message format specific dumpers.
+namespace abi_util {
+
+inline abi_diff::CompatibilityStatus CompatibilityStatusIRToProtobuf(
+ CompatibilityStatusIR status) {
+ switch(status) {
+ case CompatibilityStatusIR::Incompatible:
+ return abi_diff::CompatibilityStatus::INCOMPATIBLE;
+ case CompatibilityStatusIR::Extension:
+ return abi_diff::CompatibilityStatus::EXTENSION;
+ default:
+ break;
+ }
+ return abi_diff::CompatibilityStatus::COMPATIBLE;
+}
+
+inline abi_dump::AccessSpecifier AccessIRToProtobuf(AccessSpecifierIR access) {
+ switch (access) {
+ case AccessSpecifierIR::ProtectedAccess:
+ return abi_dump::AccessSpecifier::protected_access;
+ case AccessSpecifierIR::PrivateAccess:
+ return abi_dump::AccessSpecifier::private_access;
+ default:
+ return abi_dump::AccessSpecifier::public_access;
+ }
+ return abi_dump::AccessSpecifier::public_access;
+}
+
+inline AccessSpecifierIR AccessProtobufToIR(
+ abi_dump::AccessSpecifier access) {
+ switch (access) {
+ case abi_dump::AccessSpecifier::protected_access:
+ return AccessSpecifierIR::ProtectedAccess;
+ case abi_dump::AccessSpecifier::private_access:
+ return AccessSpecifierIR::PrivateAccess;
+ default:
+ return AccessSpecifierIR::PublicAccess;
+ }
+ return AccessSpecifierIR::PublicAccess;
+}
+
+inline abi_dump::RecordKind RecordKindIRToProtobuf(
+ RecordTypeIR::RecordKind kind) {
+ switch (kind) {
+ case RecordTypeIR::RecordKind::struct_kind:
+ return abi_dump::RecordKind::struct_kind;
+
+ case RecordTypeIR::RecordKind::class_kind:
+ return abi_dump::RecordKind::class_kind;
+
+ case RecordTypeIR::RecordKind::union_kind:
+ return abi_dump::RecordKind::union_kind;
+
+ default:
+ return abi_dump::RecordKind::struct_kind;
+ }
+ // Should not be reached
+ assert(false);
+}
+
+inline abi_dump::VTableComponent::Kind VTableComponentKindIRToProtobuf(
+ VTableComponentIR::Kind kind) {
+ switch (kind) {
+ case VTableComponentIR::Kind::VCallOffset:
+ return abi_dump::VTableComponent_Kind_VCallOffset;
+
+ case VTableComponentIR::Kind::VBaseOffset:
+ return abi_dump::VTableComponent_Kind_VBaseOffset;
+
+ case VTableComponentIR::Kind::OffsetToTop:
+ return abi_dump::VTableComponent_Kind_OffsetToTop;
+
+ case VTableComponentIR::Kind::RTTI:
+ return abi_dump::VTableComponent_Kind_RTTI;
+
+ case VTableComponentIR::Kind::FunctionPointer:
+ return abi_dump::VTableComponent_Kind_FunctionPointer;
+
+ case VTableComponentIR::Kind::CompleteDtorPointer:
+ return abi_dump::VTableComponent_Kind_CompleteDtorPointer;
+
+ case VTableComponentIR::Kind::DeletingDtorPointer:
+ return abi_dump::VTableComponent_Kind_DeletingDtorPointer;
+
+ default:
+ return abi_dump::VTableComponent_Kind_UnusedFunctionPointer;
+ }
+ // Should not be reached
+ assert(false);
+}
+
+inline VTableComponentIR::Kind VTableComponentKindProtobufToIR(
+ abi_dump::VTableComponent_Kind kind) {
+ switch (kind) {
+ case abi_dump::VTableComponent_Kind_VCallOffset:
+ return VTableComponentIR::Kind::VCallOffset;
+
+ case abi_dump::VTableComponent_Kind_VBaseOffset:
+ return VTableComponentIR::Kind::VBaseOffset;
+
+ case abi_dump::VTableComponent_Kind_OffsetToTop:
+ return VTableComponentIR::Kind::OffsetToTop;
+
+ case abi_dump::VTableComponent_Kind_RTTI:
+ return VTableComponentIR::Kind::RTTI;
+
+ case abi_dump::VTableComponent_Kind_FunctionPointer:
+ return VTableComponentIR::Kind::FunctionPointer;
+
+ case abi_dump::VTableComponent_Kind_CompleteDtorPointer:
+ return VTableComponentIR::Kind::CompleteDtorPointer;
+
+ case abi_dump::VTableComponent_Kind_DeletingDtorPointer:
+ return VTableComponentIR::Kind::DeletingDtorPointer;
+
+ default:
+ return VTableComponentIR::Kind::UnusedFunctionPointer;
+ }
+ // Should not be reached
+ assert(false);
+}
+
+class IRToProtobufConverter {
+ private:
+ static bool AddTemplateInformation(
+ abi_dump::TemplateInfo *ti, const abi_util::TemplatedArtifactIR *ta);
+
+ static bool AddTypeInfo(
+ abi_dump::BasicNamedAndTypedDecl *type_info, const TypeIR *typep);
+
+ static bool AddRecordFields(
+ abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
+
+ static bool AddBaseSpecifiers(
+ abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
+
+ static bool AddVTableLayout(
+ abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
+
+ static bool AddEnumFields(abi_dump::EnumType *enum_protobuf,
+ const EnumTypeIR *enum_ir);
+ public:
+ static abi_dump::EnumType ConvertEnumTypeIR(const EnumTypeIR *enump);
+
+ static abi_dump::RecordType ConvertRecordTypeIR(const RecordTypeIR *recordp);
+
+ static bool AddFunctionParameters(abi_dump::FunctionDecl *function_protobuf,
+ const FunctionIR *function_ir);
+
+ static abi_dump::FunctionDecl ConvertFunctionIR(const FunctionIR *functionp);
+
+ static abi_dump::GlobalVarDecl ConvertGlobalVarIR(
+ const GlobalVarIR *global_varp);
+
+ static abi_dump::PointerType ConvertPointerTypeIR(
+ const PointerTypeIR *pointerp);
+
+ static abi_dump::QualifiedType ConvertQualifiedTypeIR(
+ const QualifiedTypeIR *qualtypep);
+
+ static abi_dump::BuiltinType ConvertBuiltinTypeIR(
+ const BuiltinTypeIR *builtin_typep);
+
+ static abi_dump::ArrayType ConvertArrayTypeIR(
+ const ArrayTypeIR *array_typep);
+
+ static abi_dump::LvalueReferenceType ConvertLvalueReferenceTypeIR(
+ const LvalueReferenceTypeIR *lvalue_reference_typep);
+
+ static abi_dump::RvalueReferenceType ConvertRvalueReferenceTypeIR(
+ const RvalueReferenceTypeIR *rvalue_reference_typep);
+
+ static abi_dump::ElfFunction ConvertElfFunctionIR(
+ const ElfFunctionIR *elf_function_ir);
+
+ static abi_dump::ElfObject ConvertElfObjectIR(
+ const ElfObjectIR *elf_object_ir);
+};
+
+class IRDiffToProtobufConverter {
+ private:
+ static bool AddTypeInfoDiff(abi_diff::TypeInfoDiff *type_info_diff_protobuf,
+ const TypeDiffIR *type_diff_ir);
+
+ static bool AddVTableLayoutDiff(
+ abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf,
+ const VTableLayoutDiffIR *vtable_layout_diff_ir);
+
+ static bool AddBaseSpecifierDiffs(
+ abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf,
+ const CXXBaseSpecifierDiffIR *base_specifier_diff_ir);
+
+ static bool AddRecordFieldsRemoved(
+ abi_diff::RecordTypeDiff *record_diff_protobuf,
+ const std::vector<const RecordFieldIR *> &record_fields_removed_ir);
+
+ static bool AddRecordFieldDiffs(
+ abi_diff::RecordTypeDiff *record_diff_protobuf,
+ const std::vector<RecordFieldDiffIR> &record_field_diff_ir);
+
+ static bool AddEnumUnderlyingTypeDiff(
+ abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf,
+ const std::pair<std::string, std::string> *underlying_type_diff_ir);
+
+ public:
+ static abi_diff::RecordTypeDiff ConvertRecordTypeDiffIR(
+ const RecordTypeDiffIR *record_type_diffp);
+
+ static abi_diff::EnumTypeDiff ConvertEnumTypeDiffIR(
+ const EnumTypeDiffIR *enum_type_diffp);
+
+ static abi_diff::FunctionDeclDiff ConvertFunctionDiffIR(
+ const FunctionDiffIR *function_diffp);
+
+ static abi_diff::GlobalVarDeclDiff ConvertGlobalVarDiffIR(
+ const GlobalVarDiffIR *global_var_diffp);
+};
+
+class ProtobufIRDumper : public IRDumper, public IRToProtobufConverter {
+ private:
+ // Types
+ bool AddRecordTypeIR(const RecordTypeIR *);
+
+ bool AddEnumTypeIR(const EnumTypeIR *);
+
+ bool AddPointerTypeIR(const PointerTypeIR *);
+
+ bool AddQualifiedTypeIR(const QualifiedTypeIR *);
+
+ bool AddLvalueReferenceTypeIR(const LvalueReferenceTypeIR *);
+
+ bool AddRvalueReferenceTypeIR(const RvalueReferenceTypeIR *);
+
+ bool AddArrayTypeIR(const ArrayTypeIR *);
+
+ bool AddBuiltinTypeIR(const BuiltinTypeIR *);
+
+ // Functions and global variables.
+ bool AddFunctionIR(const FunctionIR *);
+
+ bool AddGlobalVarIR(const GlobalVarIR *);
+
+ public:
+ ProtobufIRDumper(const std::string &dump_path)
+ : IRDumper(dump_path), tu_ptr_(new abi_dump::TranslationUnit()) { }
+
+ bool AddLinkableMessageIR(const LinkableMessageIR *);
+
+ bool Dump() override;
+
+ ~ProtobufIRDumper() override { }
+
+ private:
+ std::unique_ptr<abi_dump::TranslationUnit> tu_ptr_;
+};
+
+
+class ProtobufTextFormatToIRReader : public TextFormatToIRReader {
+ public:
+
+ virtual bool ReadDump() override;
+
+ ProtobufTextFormatToIRReader(const std::string &dump_path)
+ : TextFormatToIRReader(dump_path) { }
+
+ private:
+ std::vector<FunctionIR> ReadFunctions(
+ const abi_dump::TranslationUnit &tu);
+
+ std::vector<GlobalVarIR> ReadGlobalVariables(
+ const abi_dump::TranslationUnit &tu);
+
+ std::vector<EnumTypeIR> ReadEnumTypes(const abi_dump::TranslationUnit &tu);
+
+ std::vector<RecordTypeIR> ReadRecordTypes(
+ const abi_dump::TranslationUnit &tu);
+
+ std::vector<PointerTypeIR> ReadPointerTypes(
+ const abi_dump::TranslationUnit &tu);
+
+ std::vector<BuiltinTypeIR> ReadBuiltinTypes(
+ const abi_dump::TranslationUnit &tu);
+
+ std::vector<QualifiedTypeIR> ReadQualifiedTypes(
+ const abi_dump::TranslationUnit &tu);
+
+ std::vector<ArrayTypeIR> ReadArrayTypes(const abi_dump::TranslationUnit &tu);
+
+ std::vector<LvalueReferenceTypeIR> ReadLvalueReferenceTypes(
+ const abi_dump::TranslationUnit &tu);
+
+ std::vector<RvalueReferenceTypeIR> ReadRvalueReferenceTypes(
+ const abi_dump::TranslationUnit &tu);
+
+ std::vector<ElfFunctionIR> ReadElfFunctions (
+ const abi_dump::TranslationUnit &tu);
+
+ std::vector<ElfObjectIR> ReadElfObjects (const abi_dump::TranslationUnit &tu);
+
+ void ReadTypeInfo(const abi_dump::BasicNamedAndTypedDecl &type_info,
+ TypeIR *typep);
+
+ FunctionIR FunctionProtobufToIR(const abi_dump::FunctionDecl &);
+
+ RecordTypeIR RecordTypeProtobufToIR(
+ const abi_dump::RecordType &record_type_protobuf);
+
+ std::vector<RecordFieldIR> RecordFieldsProtobufToIR(
+ const google::protobuf::RepeatedPtrField<abi_dump::RecordFieldDecl> &rfp);
+
+ std::vector<CXXBaseSpecifierIR> RecordCXXBaseSpecifiersProtobufToIR(
+ const google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> &rbs);
+
+ std::vector<EnumFieldIR> EnumFieldsProtobufToIR(
+ const google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> &efp);
+
+ EnumTypeIR EnumTypeProtobufToIR(
+ const abi_dump::EnumType &enum_type_protobuf);
+
+ VTableLayoutIR VTableLayoutProtobufToIR(
+ const abi_dump::VTableLayout &vtable_layout_protobuf);
+
+ TemplateInfoIR TemplateInfoProtobufToIR(
+ const abi_dump::TemplateInfo &template_info_protobuf);
+};
+
+class ProtobufIRDiffDumper : public IRDiffDumper {
+ public:
+ ProtobufIRDiffDumper(const std::string &dump_path)
+ : IRDiffDumper(dump_path),
+ diff_tu_(new abi_diff::TranslationUnitDiff()) { }
+
+ bool AddDiffMessageIR(const DiffMessageIR *, const std::string &type_stack,
+ DiffKind diff_kind) override;
+
+ bool AddLinkableMessageIR(const LinkableMessageIR *,
+ DiffKind diff_kind) override;
+
+ bool AddElfSymbolMessageIR(const ElfSymbolIR *, DiffKind diff_kind) override;
+
+ void AddLibNameIR(const std::string &name) override;
+
+ void AddArchIR(const std::string &arch) override;
+
+ void AddCompatibilityStatusIR(CompatibilityStatusIR status) override;
+
+ bool Dump() override;
+
+ CompatibilityStatusIR GetCompatibilityStatusIR() override;
+
+ ~ProtobufIRDiffDumper() override { }
+
+ private:
+ // User defined types.
+ bool AddRecordTypeDiffIR(const RecordTypeDiffIR *,
+ const std::string &type_stack, DiffKind diff_kind);
+
+ bool AddEnumTypeDiffIR(const EnumTypeDiffIR *,
+ const std::string &type_stack, DiffKind diff_kind);
+
+ // Functions and global variables.
+ bool AddFunctionDiffIR(const FunctionDiffIR *,
+ const std::string &type_stack, DiffKind diff_kind);
+
+ bool AddGlobalVarDiffIR(const GlobalVarDiffIR *,
+ const std::string &type_stack, DiffKind diff_kind);
+
+ bool AddLoneRecordTypeDiffIR(const RecordTypeIR *, DiffKind diff_kind);
+
+ bool AddLoneEnumTypeDiffIR(const EnumTypeIR *, DiffKind diff_kind);
+
+ // Functions and global variables.
+ bool AddLoneFunctionDiffIR(const FunctionIR *, DiffKind diff_kind);
+
+ bool AddLoneGlobalVarDiffIR(const GlobalVarIR *, DiffKind diff_kind);
+
+ bool AddElfObjectIR(const ElfObjectIR *elf_object_ir, DiffKind diff_kind);
+
+ bool AddElfFunctionIR(const ElfFunctionIR *elf_function_ir,
+ DiffKind diff_kind);
+
+ protected:
+ std::unique_ptr<abi_diff::TranslationUnitDiff> diff_tu_;
+};
+
+} // abi_util
+
+#endif // IR_PROTOBUF_
diff --git a/vndk/tools/header-checker/header-abi-util/src/ir_representation.cpp b/vndk/tools/header-checker/header-abi-util/src/ir_representation.cpp
new file mode 100644
index 0000000..0cf58e1
--- /dev/null
+++ b/vndk/tools/header-checker/header-abi-util/src/ir_representation.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <ir_representation.h>
+#include <ir_representation_protobuf.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+#include "proto/abi_dump.pb.h"
+#pragma clang diagnostic pop
+
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+#include <llvm/Support/raw_ostream.h>
+
+#include <string>
+#include <memory>
+
+
+namespace abi_util {
+
+std::unique_ptr<IRDumper> IRDumper::CreateIRDumper(
+ const std::string &type, const std::string &dump_path) {
+ if (type == "protobuf") {
+ return std::make_unique<ProtobufIRDumper>(dump_path);
+ }
+ // Nothing else is supported yet.
+ llvm::errs() << type << " message format is not supported yet!\n";
+ return nullptr;
+}
+
+std::unique_ptr<IRDiffDumper> IRDiffDumper::CreateIRDiffDumper(
+ const std::string &type, const std::string &dump_path) {
+ if (type == "protobuf") {
+ return std::make_unique<ProtobufIRDiffDumper>(dump_path);
+ }
+ // Nothing else is supported yet.
+ llvm::errs() << type << " message format is not supported yet!\n";
+ return nullptr;
+}
+
+std::unique_ptr<TextFormatToIRReader>
+TextFormatToIRReader::CreateTextFormatToIRReader(
+ const std::string &type, const std::string &dump_path) {
+ if (type == "protobuf") {
+ return std::make_unique<ProtobufTextFormatToIRReader>(dump_path);
+ }
+ // Nothing else is supported yet.
+ llvm::errs() << type << " message format is not supported yet!\n";
+ return nullptr;
+}
+
+} // namespace abi_util
+
diff --git a/vndk/tools/header-checker/header-abi-util/src/ir_representation_protobuf.cpp b/vndk/tools/header-checker/header-abi-util/src/ir_representation_protobuf.cpp
new file mode 100644
index 0000000..f3958d8
--- /dev/null
+++ b/vndk/tools/header-checker/header-abi-util/src/ir_representation_protobuf.cpp
@@ -0,0 +1,1353 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <ir_representation_protobuf.h>
+
+#include <llvm/Support/raw_ostream.h>
+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <memory>
+
+namespace abi_util {
+
+void ProtobufTextFormatToIRReader::ReadTypeInfo(
+ const abi_dump::BasicNamedAndTypedDecl &type_info,
+ TypeIR *typep) {
+ typep->SetLinkerSetKey(type_info.linker_set_key());
+ typep->SetName(type_info.linker_set_key());
+ typep->SetSourceFile(type_info.source_file());
+ typep->SetReferencedType(type_info.referenced_type());
+ typep->SetSize(type_info.size());
+ typep->SetAlignment(type_info.alignment());
+}
+
+bool ProtobufTextFormatToIRReader::ReadDump() {
+ abi_dump::TranslationUnit tu;
+ std::ifstream input(dump_path_);
+ google::protobuf::io::IstreamInputStream text_is(&input);
+
+ if (!google::protobuf::TextFormat::Parse(&text_is, &tu)) {
+ llvm::errs() << "Failed to parse protobuf TextFormat file\n";
+ return false;
+ }
+
+ functions_ = ReadFunctions(tu);
+ global_variables_ = ReadGlobalVariables(tu);
+
+ enum_types_ = ReadEnumTypes(tu);
+ record_types_ = ReadRecordTypes(tu);
+ array_types_ = ReadArrayTypes(tu);
+ pointer_types_ = ReadPointerTypes(tu);
+ qualified_types_ = ReadQualifiedTypes(tu);
+ builtin_types_ = ReadBuiltinTypes(tu);
+ lvalue_reference_types_ = ReadLvalueReferenceTypes(tu);
+ rvalue_reference_types_ = ReadRvalueReferenceTypes(tu);
+
+ elf_functions_ = ReadElfFunctions(tu);
+ elf_objects_ = ReadElfObjects(tu);
+
+ return true;
+}
+
+TemplateInfoIR ProtobufTextFormatToIRReader::TemplateInfoProtobufToIR(
+ const abi_dump::TemplateInfo &template_info_protobuf) {
+ TemplateInfoIR template_info_ir;
+ for (auto &&template_element : template_info_protobuf.elements()) {
+ TemplateElementIR template_element_ir(template_element.referenced_type());
+ template_info_ir.AddTemplateElement(std::move(template_element_ir));
+ }
+ return template_info_ir;
+}
+
+FunctionIR ProtobufTextFormatToIRReader::FunctionProtobufToIR(
+ const abi_dump::FunctionDecl &function_protobuf) {
+ FunctionIR function_ir;
+ function_ir.SetReturnType(function_protobuf.return_type());
+ function_ir.SetLinkerSetKey(function_protobuf.linker_set_key());
+ function_ir.SetName(function_protobuf.function_name());
+ function_ir.SetAccess(AccessProtobufToIR(function_protobuf.access()));
+ function_ir.SetSourceFile(function_protobuf.source_file());
+ // Set parameters
+ for (auto &¶meter: function_protobuf.parameters()) {
+ ParamIR param_ir(parameter.referenced_type(), parameter.default_arg());
+ function_ir.AddParameter(std::move(param_ir));
+ }
+ // Set Template info
+ function_ir.SetTemplateInfo(
+ TemplateInfoProtobufToIR(function_protobuf.template_info()));
+ return function_ir;
+}
+
+VTableLayoutIR ProtobufTextFormatToIRReader::VTableLayoutProtobufToIR(
+ const abi_dump::VTableLayout &vtable_layout_protobuf) {
+ VTableLayoutIR vtable_layout_ir;
+ for (auto &&vtable_component : vtable_layout_protobuf.vtable_components()) {
+ VTableComponentIR vtable_component_ir(
+ vtable_component.mangled_component_name(),
+ VTableComponentKindProtobufToIR(vtable_component.kind()),
+ vtable_component.component_value());
+ vtable_layout_ir.AddVTableComponent(std::move(vtable_component_ir));
+ }
+ return vtable_layout_ir;
+}
+
+std::vector<RecordFieldIR>
+ProtobufTextFormatToIRReader::RecordFieldsProtobufToIR(
+ const google::protobuf::RepeatedPtrField<abi_dump::RecordFieldDecl> &rfp) {
+ std::vector<RecordFieldIR> record_type_fields_ir;
+ for (auto &&field : rfp) {
+ RecordFieldIR record_field_ir(field.field_name(), field.referenced_type(),
+ field.field_offset(),
+ AccessProtobufToIR(field.access()));
+ record_type_fields_ir.emplace_back(std::move(record_field_ir));
+ }
+ return record_type_fields_ir;
+}
+
+std::vector<CXXBaseSpecifierIR>
+ProtobufTextFormatToIRReader::RecordCXXBaseSpecifiersProtobufToIR(
+ const google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> &rbs) {
+ std::vector<CXXBaseSpecifierIR> record_type_bases_ir;
+ for (auto &&base : rbs) {
+ CXXBaseSpecifierIR record_base_ir(
+ base.referenced_type(), base.is_virtual(),
+ AccessProtobufToIR(base.access()));
+ record_type_bases_ir.emplace_back(std::move(record_base_ir));
+ }
+ return record_type_bases_ir;
+}
+
+RecordTypeIR ProtobufTextFormatToIRReader::RecordTypeProtobufToIR(
+ const abi_dump::RecordType &record_type_protobuf) {
+ RecordTypeIR record_type_ir;
+ ReadTypeInfo(record_type_protobuf.type_info(), &record_type_ir);
+ record_type_ir.SetTemplateInfo(
+ TemplateInfoProtobufToIR(record_type_protobuf.template_info()));
+ record_type_ir.SetAccess(AccessProtobufToIR(record_type_protobuf.access()));
+ record_type_ir.SetVTableLayout(
+ VTableLayoutProtobufToIR(record_type_protobuf.vtable_layout()));
+ // Get fields
+ record_type_ir.SetRecordFields(RecordFieldsProtobufToIR(
+ record_type_protobuf.fields()));
+ // Base Specifiers
+ record_type_ir.SetCXXBaseSpecifiers(RecordCXXBaseSpecifiersProtobufToIR(
+ record_type_protobuf.base_specifiers()));
+
+ return record_type_ir;
+}
+
+std::vector<EnumFieldIR>
+ProtobufTextFormatToIRReader::EnumFieldsProtobufToIR(
+ const google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> &efp) {
+ std::vector<EnumFieldIR> enum_type_fields_ir;
+ for (auto &&field : efp) {
+ EnumFieldIR enum_field_ir(field.name(), field.enum_field_value());
+ enum_type_fields_ir.emplace_back(std::move(enum_field_ir));
+ }
+ return enum_type_fields_ir;
+}
+
+EnumTypeIR ProtobufTextFormatToIRReader::EnumTypeProtobufToIR(
+ const abi_dump::EnumType &enum_type_protobuf) {
+ EnumTypeIR enum_type_ir;
+ ReadTypeInfo(enum_type_protobuf.type_info(), &enum_type_ir);
+ enum_type_ir.SetUnderlyingType(enum_type_protobuf.underlying_type());
+ enum_type_ir.SetAccess(AccessProtobufToIR(enum_type_protobuf.access()));
+ enum_type_ir.SetFields(
+ EnumFieldsProtobufToIR(enum_type_protobuf.enum_fields()));
+ return enum_type_ir;
+}
+
+std::vector<GlobalVarIR> ProtobufTextFormatToIRReader::ReadGlobalVariables(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<GlobalVarIR> global_variables;
+ for (auto &&global_variable_protobuf : tu.global_vars()) {
+ GlobalVarIR global_variable_ir;
+ global_variable_ir.SetName(global_variable_protobuf.name());
+ global_variable_ir.SetSourceFile(global_variable_protobuf.source_file());
+ global_variable_ir.SetReferencedType(
+ global_variable_protobuf.referenced_type());
+ global_variable_ir.SetLinkerSetKey(
+ global_variable_protobuf.linker_set_key());
+ global_variables.emplace_back(std::move(global_variable_ir));
+ }
+ return global_variables;
+}
+
+std::vector<PointerTypeIR> ProtobufTextFormatToIRReader::ReadPointerTypes(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<PointerTypeIR> pointer_types;
+ for (auto &&pointer_type_protobuf : tu.pointer_types()) {
+ PointerTypeIR pointer_type_ir;
+ ReadTypeInfo(pointer_type_protobuf.type_info(), &pointer_type_ir);
+ pointer_types.emplace_back(std::move(pointer_type_ir));
+ }
+ return pointer_types;
+}
+
+std::vector<BuiltinTypeIR> ProtobufTextFormatToIRReader::ReadBuiltinTypes(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<BuiltinTypeIR> builtin_types;
+ for (auto &&builtin_type_protobuf : tu.builtin_types()) {
+ BuiltinTypeIR builtin_type_ir;
+ ReadTypeInfo(builtin_type_protobuf.type_info(), &builtin_type_ir);
+ builtin_type_ir.SetSignedness(builtin_type_protobuf.is_unsigned());
+ builtin_type_ir.SetIntegralType(builtin_type_protobuf.is_integral());
+ builtin_types.emplace_back(std::move(builtin_type_ir));
+ }
+ return builtin_types;
+}
+
+std::vector<QualifiedTypeIR> ProtobufTextFormatToIRReader::ReadQualifiedTypes(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<QualifiedTypeIR> qualified_types;
+ for (auto &&qualified_type_protobuf : tu.qualified_types()) {
+ QualifiedTypeIR qualified_type_ir;
+ ReadTypeInfo(qualified_type_protobuf.type_info(), &qualified_type_ir);
+ qualified_types.emplace_back(std::move(qualified_type_ir));
+ }
+ return qualified_types;
+}
+
+std::vector<ArrayTypeIR> ProtobufTextFormatToIRReader::ReadArrayTypes(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<ArrayTypeIR> array_types;
+ for (auto &&array_type_protobuf : tu.array_types()) {
+ ArrayTypeIR array_type_ir;
+ ReadTypeInfo(array_type_protobuf.type_info(), &array_type_ir);
+ array_types.emplace_back(std::move(array_type_ir));
+ }
+ return array_types;
+}
+
+std::vector<LvalueReferenceTypeIR>
+ProtobufTextFormatToIRReader::ReadLvalueReferenceTypes(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<LvalueReferenceTypeIR> lvalue_reference_types;
+ for (auto &&lvalue_reference_type_protobuf : tu.lvalue_reference_types()) {
+ LvalueReferenceTypeIR lvalue_reference_type_ir;
+ ReadTypeInfo(lvalue_reference_type_protobuf.type_info(),
+ &lvalue_reference_type_ir);
+ lvalue_reference_types.emplace_back(std::move(lvalue_reference_type_ir));
+ }
+ return lvalue_reference_types;
+}
+
+std::vector<RvalueReferenceTypeIR>
+ProtobufTextFormatToIRReader::ReadRvalueReferenceTypes(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<RvalueReferenceTypeIR> rvalue_reference_types;
+ for (auto &&rvalue_reference_type_protobuf : tu.rvalue_reference_types()) {
+ RvalueReferenceTypeIR rvalue_reference_type_ir;
+ ReadTypeInfo(rvalue_reference_type_protobuf.type_info(),
+ &rvalue_reference_type_ir);
+ rvalue_reference_types.emplace_back(std::move(rvalue_reference_type_ir));
+ }
+ return rvalue_reference_types;
+}
+
+std::vector<FunctionIR> ProtobufTextFormatToIRReader::ReadFunctions(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<FunctionIR> functions;
+ for (auto &&function_protobuf : tu.functions()) {
+ FunctionIR function_ir = FunctionProtobufToIR(function_protobuf);
+ functions.emplace_back(std::move(function_ir));
+ }
+ return functions;
+}
+
+std::vector<RecordTypeIR> ProtobufTextFormatToIRReader::ReadRecordTypes(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<RecordTypeIR> record_types;
+ for (auto &&record_type_protobuf : tu.record_types()) {
+ RecordTypeIR record_type_ir = RecordTypeProtobufToIR(record_type_protobuf);
+ record_types.emplace_back(std::move(record_type_ir));
+ }
+ return record_types;
+}
+
+std::vector<EnumTypeIR> ProtobufTextFormatToIRReader::ReadEnumTypes(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<EnumTypeIR> enum_types;
+ for (auto &&enum_type_protobuf : tu.enum_types()) {
+ EnumTypeIR enum_type_ir = EnumTypeProtobufToIR(enum_type_protobuf);
+ enum_types.emplace_back(std::move(enum_type_ir));
+ }
+ return enum_types;
+}
+
+std::vector<ElfFunctionIR> ProtobufTextFormatToIRReader::ReadElfFunctions(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<ElfFunctionIR> elf_functions;
+ for (auto &&elf_function : tu.elf_functions()) {
+ elf_functions.emplace_back(ElfFunctionIR(elf_function.name()));
+ }
+ return elf_functions;
+}
+
+std::vector<ElfObjectIR> ProtobufTextFormatToIRReader::ReadElfObjects(
+ const abi_dump::TranslationUnit &tu) {
+ std::vector<ElfObjectIR> elf_objects;
+ for (auto &&elf_object : tu.elf_objects()) {
+ elf_objects.emplace_back(ElfObjectIR(elf_object.name()));
+ }
+ return elf_objects;
+}
+
+bool IRToProtobufConverter::AddTemplateInformation(
+ abi_dump::TemplateInfo *ti, const abi_util::TemplatedArtifactIR *ta) {
+ for (auto &&template_element : ta->GetTemplateElements()) {
+ abi_dump::TemplateElement *added_element = ti->add_elements();
+ if (!added_element) {
+ llvm::errs() << "Failed to add template element\n";
+ return false;
+ }
+ added_element->set_referenced_type(template_element.GetReferencedType());
+ }
+ return true;
+}
+
+bool IRToProtobufConverter::AddTypeInfo(
+ abi_dump::BasicNamedAndTypedDecl *type_info,
+ const TypeIR *typep) {
+ if (!type_info || !typep) {
+ llvm::errs() << "Typeinfo not valid\n";
+ return false;
+ }
+ type_info->set_linker_set_key(typep->GetLinkerSetKey());
+ type_info->set_source_file(typep->GetSourceFile());
+ type_info->set_name(typep->GetName());
+ type_info->set_size(typep->GetSize());
+ type_info->set_alignment(typep->GetAlignment());
+ type_info->set_referenced_type(typep->GetReferencedType());
+ return true;
+}
+
+static void SetIRToProtobufRecordField(
+ abi_dump::RecordFieldDecl *record_field_protobuf,
+ const RecordFieldIR *record_field_ir) {
+ record_field_protobuf->set_field_name(record_field_ir->GetName());
+ record_field_protobuf->set_referenced_type(
+ record_field_ir->GetReferencedType());
+ record_field_protobuf->set_access(
+ AccessIRToProtobuf(record_field_ir->GetAccess()));
+ record_field_protobuf->set_field_offset(record_field_ir->GetOffset());
+}
+
+bool IRToProtobufConverter::AddRecordFields(
+ abi_dump::RecordType *record_protobuf,
+ const RecordTypeIR *record_ir) {
+ // Iterate through the fields and create corresponding ones for the protobuf
+ // record
+ for (auto &&field_ir : record_ir->GetFields()) {
+ abi_dump::RecordFieldDecl *added_field = record_protobuf->add_fields();
+ if (!added_field) {
+ llvm::errs() << "Couldn't add record field\n";
+ }
+ SetIRToProtobufRecordField(added_field, &field_ir);
+ }
+ return true;
+}
+
+static bool SetIRToProtobufBaseSpecifier(
+ abi_dump::CXXBaseSpecifier *base_specifier_protobuf,
+ const CXXBaseSpecifierIR &base_specifier_ir) {
+ if (!base_specifier_protobuf) {
+ llvm::errs() << "Protobuf base specifier not valid\n";
+ return false;
+ }
+ base_specifier_protobuf->set_referenced_type(
+ base_specifier_ir.GetReferencedType());
+ base_specifier_protobuf->set_is_virtual(
+ base_specifier_ir.IsVirtual());
+ base_specifier_protobuf->set_access(
+ AccessIRToProtobuf(base_specifier_ir.GetAccess()));
+ return true;
+}
+
+bool IRToProtobufConverter::AddBaseSpecifiers(
+ abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir) {
+ for (auto &&base_ir : record_ir->GetBases()) {
+ abi_dump::CXXBaseSpecifier *added_base =
+ record_protobuf->add_base_specifiers();
+ if (!SetIRToProtobufBaseSpecifier(added_base, base_ir)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool SetIRToProtobufVTableLayout(
+ abi_dump::VTableLayout *vtable_layout_protobuf,
+ const VTableLayoutIR &vtable_layout_ir) {
+ if (vtable_layout_protobuf == nullptr) {
+ llvm::errs() << "vtable layout protobuf not valid\n";
+ return false;
+ }
+ for (auto &&vtable_component_ir : vtable_layout_ir.GetVTableComponents()) {
+ abi_dump::VTableComponent *added_vtable_component =
+ vtable_layout_protobuf->add_vtable_components();
+ if (!added_vtable_component) {
+ llvm::errs() << "Couldn't add vtable component\n";
+ return false;
+ }
+ added_vtable_component->set_kind(
+ VTableComponentKindIRToProtobuf(vtable_component_ir.GetKind()));
+ added_vtable_component->set_component_value(vtable_component_ir.GetValue());
+ added_vtable_component->set_mangled_component_name(
+ vtable_component_ir.GetName());
+ }
+ return true;
+}
+
+bool IRToProtobufConverter::AddVTableLayout(
+ abi_dump::RecordType *record_protobuf,
+ const RecordTypeIR *record_ir) {
+ // If there are no entries in the vtable, just return.
+ if (record_ir->GetVTableNumEntries() == 0) {
+ return true;
+ }
+ const VTableLayoutIR &vtable_layout_ir = record_ir->GetVTableLayout();
+ abi_dump::VTableLayout *vtable_layout_protobuf =
+ record_protobuf->mutable_vtable_layout();
+ if (!SetIRToProtobufVTableLayout(vtable_layout_protobuf, vtable_layout_ir)) {
+ return false;
+ }
+ return true;
+}
+
+abi_dump::RecordType IRToProtobufConverter::ConvertRecordTypeIR(
+ const RecordTypeIR *recordp) {
+ abi_dump::RecordType added_record_type;
+ added_record_type.set_access(AccessIRToProtobuf(recordp->GetAccess()));
+ added_record_type.set_record_kind(
+ RecordKindIRToProtobuf(recordp->GetRecordKind()));
+ if (recordp->IsAnonymous()) {
+ added_record_type.set_is_anonymous(true);
+ }
+ if (!AddTypeInfo(added_record_type.mutable_type_info(), recordp) ||
+ !AddRecordFields(&added_record_type, recordp) ||
+ !AddBaseSpecifiers(&added_record_type, recordp) ||
+ !AddVTableLayout(&added_record_type, recordp) ||
+ !(recordp->GetTemplateElements().size() ?
+ AddTemplateInformation(added_record_type.mutable_template_info(),
+ recordp) : true)) {
+ llvm::errs() << "Template information could not be added\n";
+ ::exit(1);
+ }
+ return added_record_type;
+}
+
+
+abi_dump::ElfObject IRToProtobufConverter::ConvertElfObjectIR(
+ const ElfObjectIR *elf_object_ir) {
+ abi_dump::ElfObject elf_object_protobuf;
+ elf_object_protobuf.set_name(elf_object_ir->GetName());
+ return elf_object_protobuf;
+}
+
+abi_dump::ElfFunction IRToProtobufConverter::ConvertElfFunctionIR(
+ const ElfFunctionIR *elf_function_ir) {
+ abi_dump::ElfFunction elf_function_protobuf;
+ elf_function_protobuf.set_name(elf_function_ir->GetName());
+ return elf_function_protobuf;
+}
+
+bool IRToProtobufConverter::AddFunctionParameters(
+ abi_dump::FunctionDecl *function_protobuf,
+ const FunctionIR *function_ir) {
+ for (auto &¶meter : function_ir->GetParameters()) {
+ abi_dump::ParamDecl *added_parameter = function_protobuf->add_parameters();
+ if (!added_parameter) {
+ return false;
+ }
+ added_parameter->set_referenced_type(
+ parameter.GetReferencedType());
+ added_parameter->set_default_arg(parameter.GetIsDefault());
+ }
+ return true;
+}
+
+abi_dump::FunctionDecl IRToProtobufConverter::ConvertFunctionIR(
+ const FunctionIR *functionp) {
+ abi_dump::FunctionDecl added_function;
+ added_function.set_access(AccessIRToProtobuf(functionp->GetAccess()));
+ added_function.set_linker_set_key(functionp->GetLinkerSetKey());
+ added_function.set_source_file(functionp->GetSourceFile());
+ added_function.set_function_name(functionp->GetName());
+ added_function.set_return_type(functionp->GetReturnType());
+ if (!AddFunctionParameters(&added_function, functionp) ||
+ !(functionp->GetTemplateElements().size() ?
+ AddTemplateInformation(added_function.mutable_template_info(), functionp)
+ : true)) {
+ llvm::errs() << "Template information could not be added\n";
+ ::exit(1);
+ }
+ return added_function;
+}
+
+static bool SetIRToProtobufEnumField(
+ abi_dump::EnumFieldDecl *enum_field_protobuf,
+ const EnumFieldIR *enum_field_ir) {
+ if (enum_field_protobuf == nullptr) {
+ return true;
+ }
+ enum_field_protobuf->set_name(enum_field_ir->GetName());
+ enum_field_protobuf->set_enum_field_value(enum_field_ir->GetValue());
+ return true;
+}
+
+bool IRToProtobufConverter::AddEnumFields(abi_dump::EnumType *enum_protobuf,
+ const EnumTypeIR *enum_ir) {
+ for (auto &&field : enum_ir->GetFields()) {
+ abi_dump::EnumFieldDecl *enum_fieldp = enum_protobuf->add_enum_fields();
+ if (!SetIRToProtobufEnumField(enum_fieldp, &field)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+abi_dump::EnumType IRToProtobufConverter::ConvertEnumTypeIR(
+ const EnumTypeIR *enump) {
+ abi_dump::EnumType added_enum_type;
+ added_enum_type.set_access(AccessIRToProtobuf(enump->GetAccess()));
+ added_enum_type.set_underlying_type(enump->GetUnderlyingType());
+ if (!AddTypeInfo(added_enum_type.mutable_type_info(), enump) ||
+ !AddEnumFields(&added_enum_type, enump)) {
+ llvm::errs() << "EnumTypeIR could not be converted\n";
+ ::exit(1);
+ }
+ return added_enum_type;
+}
+
+abi_dump::GlobalVarDecl IRToProtobufConverter::ConvertGlobalVarIR(
+ const GlobalVarIR *global_varp) {
+ abi_dump::GlobalVarDecl added_global_var;
+ added_global_var.set_referenced_type(global_varp->GetReferencedType());
+ added_global_var.set_source_file(global_varp->GetSourceFile());
+ added_global_var.set_name(global_varp->GetName());
+ added_global_var.set_linker_set_key(global_varp->GetLinkerSetKey());
+ added_global_var.set_access(
+ AccessIRToProtobuf(global_varp->GetAccess()));
+ return added_global_var;
+}
+
+abi_dump::PointerType IRToProtobufConverter::ConvertPointerTypeIR(
+ const PointerTypeIR *pointerp) {
+ abi_dump::PointerType added_pointer_type;
+ if (!AddTypeInfo(added_pointer_type.mutable_type_info(), pointerp)) {
+ llvm::errs() << "PointerTypeIR could not be converted\n";
+ ::exit(1);
+ }
+ return added_pointer_type;
+}
+
+abi_dump::QualifiedType IRToProtobufConverter::ConvertQualifiedTypeIR(
+ const QualifiedTypeIR *qualtypep) {
+ abi_dump::QualifiedType added_qualified_type;
+ if (!AddTypeInfo(added_qualified_type.mutable_type_info(), qualtypep)) {
+ llvm::errs() << "QualifiedTypeIR could not be converted\n";
+ ::exit(1);
+ }
+ added_qualified_type.set_is_const(qualtypep->IsConst());
+ added_qualified_type.set_is_volatile(qualtypep->IsVolatile());
+ added_qualified_type.set_is_restricted(qualtypep->IsRestricted());
+ return added_qualified_type;
+}
+
+abi_dump::BuiltinType IRToProtobufConverter::ConvertBuiltinTypeIR(
+ const BuiltinTypeIR *builtin_typep) {
+ abi_dump::BuiltinType added_builtin_type;
+ added_builtin_type.set_is_unsigned(builtin_typep->IsUnsigned());
+ added_builtin_type.set_is_integral(builtin_typep->IsIntegralType());
+ if (!AddTypeInfo(added_builtin_type.mutable_type_info(), builtin_typep)) {
+ llvm::errs() << "BuiltinTypeIR could not be converted\n";
+ ::exit(1);
+ }
+ return added_builtin_type;
+}
+
+abi_dump::ArrayType IRToProtobufConverter::ConvertArrayTypeIR(
+ const ArrayTypeIR *array_typep) {
+ abi_dump::ArrayType added_array_type;
+ if (!AddTypeInfo(added_array_type.mutable_type_info(), array_typep)) {
+ llvm::errs() << "ArrayTypeIR could not be converted\n";
+ ::exit(1);
+ }
+ return added_array_type;
+}
+
+abi_dump::LvalueReferenceType
+IRToProtobufConverter::ConvertLvalueReferenceTypeIR(
+ const LvalueReferenceTypeIR *lvalue_reference_typep) {
+ abi_dump::LvalueReferenceType added_lvalue_reference_type;
+ if (!AddTypeInfo(added_lvalue_reference_type.mutable_type_info(),
+ lvalue_reference_typep)) {
+ llvm::errs() << "LvalueReferenceTypeIR could not be converted\n";
+ ::exit(1);
+ }
+ return added_lvalue_reference_type;
+}
+
+abi_dump::RvalueReferenceType
+IRToProtobufConverter::ConvertRvalueReferenceTypeIR(
+ const RvalueReferenceTypeIR *rvalue_reference_typep) {
+ abi_dump::RvalueReferenceType added_rvalue_reference_type;
+ if (!AddTypeInfo(added_rvalue_reference_type.mutable_type_info(),
+ rvalue_reference_typep)) {
+ llvm::errs() << "RvalueReferenceTypeIR could not be converted\n";
+ ::exit(1);
+ }
+ return added_rvalue_reference_type;
+}
+
+
+bool IRDiffToProtobufConverter::AddTypeInfoDiff(
+ abi_diff::TypeInfoDiff *type_info_diff_protobuf,
+ const TypeDiffIR *type_diff_ir) {
+ abi_diff::TypeInfo *old_type_info_protobuf =
+ type_info_diff_protobuf->mutable_old_type_info();
+ abi_diff::TypeInfo *new_type_info_protobuf =
+ type_info_diff_protobuf->mutable_new_type_info();
+ if (old_type_info_protobuf == nullptr || new_type_info_protobuf == nullptr) {
+ return false;
+ }
+ const std::pair<uint64_t, uint64_t> &sizes = type_diff_ir->GetSizes();
+ const std::pair<uint32_t, uint32_t> &alignments =
+ type_diff_ir->GetAlignments();
+ old_type_info_protobuf->set_size(sizes.first);
+ new_type_info_protobuf->set_size(sizes.second);
+
+ old_type_info_protobuf->set_alignment(alignments.first);
+ new_type_info_protobuf->set_alignment(alignments.second);
+ return true;
+}
+
+bool IRDiffToProtobufConverter::AddVTableLayoutDiff(
+ abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf,
+ const VTableLayoutDiffIR *vtable_layout_diff_ir) {
+ abi_dump:: VTableLayout *old_vtable =
+ vtable_layout_diff_protobuf->mutable_old_vtable();
+ abi_dump:: VTableLayout *new_vtable =
+ vtable_layout_diff_protobuf->mutable_new_vtable();
+ if (old_vtable == nullptr || new_vtable == nullptr ||
+ !SetIRToProtobufVTableLayout(old_vtable,
+ vtable_layout_diff_ir->GetOldVTable()) ||
+ !SetIRToProtobufVTableLayout(new_vtable,
+ vtable_layout_diff_ir->GetNewVTable())) {
+ return false;
+ }
+ return true;
+}
+
+template <typename T>
+static bool CopyBaseSpecifiersDiffIRToProtobuf(
+ google::protobuf::RepeatedPtrField<T> *dst,
+ const std::vector<CXXBaseSpecifierIR> &bases_ir) {
+ for (auto &&base_ir : bases_ir) {
+ T *added_base = dst->Add();
+ if (!SetIRToProtobufBaseSpecifier(added_base, base_ir)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool IRDiffToProtobufConverter::AddBaseSpecifierDiffs(
+ abi_diff::CXXBaseSpecifierDiff *base_specifiers_diff_protobuf,
+ const CXXBaseSpecifierDiffIR *base_specifiers_diff_ir) {
+ if (!CopyBaseSpecifiersDiffIRToProtobuf(
+ base_specifiers_diff_protobuf->mutable_old_bases(),
+ base_specifiers_diff_ir->GetOldBases()) ||
+ !CopyBaseSpecifiersDiffIRToProtobuf(
+ base_specifiers_diff_protobuf->mutable_new_bases(),
+ base_specifiers_diff_ir->GetNewBases())) {
+ return false;
+ }
+ return true;
+}
+
+bool IRDiffToProtobufConverter::AddRecordFieldsRemoved(
+ abi_diff::RecordTypeDiff *record_diff_protobuf,
+ const std::vector<const RecordFieldIR *> &record_fields_removed_ir) {
+ for (auto &&record_field_ir : record_fields_removed_ir) {
+ abi_dump::RecordFieldDecl *field_removed =
+ record_diff_protobuf->add_fields_removed();
+ if (field_removed == nullptr) {
+ return false;
+ }
+ SetIRToProtobufRecordField(field_removed, record_field_ir);
+ }
+ return true;
+}
+
+bool IRDiffToProtobufConverter::AddRecordFieldDiffs(
+ abi_diff::RecordTypeDiff *record_diff_protobuf,
+ const std::vector<RecordFieldDiffIR> &record_field_diffs_ir) {
+ for (auto &&record_field_diff_ir : record_field_diffs_ir) {
+ abi_diff::RecordFieldDeclDiff *record_field_diff =
+ record_diff_protobuf->add_fields_diff();
+ if (record_field_diff == nullptr) {
+ return false;
+ }
+ abi_dump::RecordFieldDecl *old_field =
+ record_field_diff->mutable_old_field();
+ abi_dump::RecordFieldDecl *new_field =
+ record_field_diff->mutable_new_field();
+ if (old_field == nullptr || new_field == nullptr) {
+ return false;
+ }
+ SetIRToProtobufRecordField(old_field,
+ record_field_diff_ir.GetOldField());
+ SetIRToProtobufRecordField(new_field,
+ record_field_diff_ir.GetNewField());
+ }
+ return true;
+}
+
+abi_diff::RecordTypeDiff IRDiffToProtobufConverter::ConvertRecordTypeDiffIR(
+ const RecordTypeDiffIR *record_type_diff_ir) {
+ abi_diff::RecordTypeDiff record_type_diff_protobuf;
+ record_type_diff_protobuf.set_name(record_type_diff_ir->GetName());
+ const TypeDiffIR *type_diff_ir = record_type_diff_ir->GetTypeDiff();
+ // If a type_info diff exists
+ if (type_diff_ir != nullptr) {
+ abi_diff::TypeInfoDiff *type_info_diff =
+ record_type_diff_protobuf.mutable_type_info_diff();
+ if (!AddTypeInfoDiff(type_info_diff, type_diff_ir)) {
+ llvm::errs() << "RecordType could not be converted\n";
+ ::exit(1);
+ }
+ }
+ // If vtables differ.
+ const VTableLayoutDiffIR *vtable_layout_diff_ir =
+ record_type_diff_ir->GetVTableLayoutDiff();
+ if (vtable_layout_diff_ir != nullptr) {
+ abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf =
+ record_type_diff_protobuf.mutable_vtable_layout_diff();
+ if (!AddVTableLayoutDiff(vtable_layout_diff_protobuf,
+ vtable_layout_diff_ir)) {
+ llvm::errs() << "VTable layout diff could not be added\n";
+ ::exit(1);
+ }
+ }
+ // If base specifiers differ.
+ const CXXBaseSpecifierDiffIR *base_specifier_diff_ir =
+ record_type_diff_ir->GetBaseSpecifiers();
+ if ( base_specifier_diff_ir != nullptr) {
+ abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf =
+ record_type_diff_protobuf.mutable_bases_diff();
+ if (!AddBaseSpecifierDiffs(base_specifier_diff_protobuf,
+ base_specifier_diff_ir)) {
+ llvm::errs() << "Base Specifier diff could not be added\n";
+ ::exit(1);
+ }
+ }
+ // Field diffs
+ if (!AddRecordFieldsRemoved(&record_type_diff_protobuf,
+ record_type_diff_ir->GetFieldsRemoved()) ||
+ !AddRecordFieldDiffs(&record_type_diff_protobuf,
+ record_type_diff_ir->GetFieldDiffs())) {
+ llvm::errs() << "Record Field diff could not be added\n";
+ ::exit(1);
+ }
+ return record_type_diff_protobuf;
+}
+
+bool IRDiffToProtobufConverter::AddEnumUnderlyingTypeDiff(
+ abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf,
+ const std::pair<std::string, std::string> *underlying_type_diff_ir) {
+ if (underlying_type_diff_protobuf == nullptr) {
+ return false;
+ }
+ underlying_type_diff_protobuf->set_old_type(underlying_type_diff_ir->first);
+ underlying_type_diff_protobuf->set_new_type(underlying_type_diff_ir->second);
+ return true;
+}
+
+static bool AddEnumFields(
+ google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> *dst,
+ const std::vector<const EnumFieldIR *> &enum_fields) {
+ for (auto &&enum_field : enum_fields) {
+ abi_dump::EnumFieldDecl *added_enum_field = dst->Add();
+ if (!SetIRToProtobufEnumField(added_enum_field, enum_field)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool AddEnumFieldDiffs(
+ google::protobuf::RepeatedPtrField<abi_diff::EnumFieldDeclDiff> *dst,
+ const std::vector<EnumFieldDiffIR> &fields_diff_ir) {
+ for (auto &&field_diff_ir : fields_diff_ir) {
+ abi_diff::EnumFieldDeclDiff *field_diff_protobuf = dst->Add();
+ if (field_diff_protobuf == nullptr) {
+ return false;
+ }
+ if (!SetIRToProtobufEnumField(field_diff_protobuf->mutable_old_field(),
+ field_diff_ir.GetOldField()) ||
+ !SetIRToProtobufEnumField(field_diff_protobuf->mutable_new_field(),
+ field_diff_ir.GetNewField())) {
+ return false;
+ }
+ }
+ return true;
+}
+
+abi_diff::EnumTypeDiff IRDiffToProtobufConverter::ConvertEnumTypeDiffIR(
+ const EnumTypeDiffIR *enum_type_diff_ir) {
+ abi_diff::EnumTypeDiff enum_type_diff_protobuf;
+ enum_type_diff_protobuf.set_name(enum_type_diff_ir->GetName());
+ const std::pair<std::string, std::string> *underlying_type_diff =
+ enum_type_diff_ir->GetUnderlyingTypeDiff();
+ if ((underlying_type_diff != nullptr &&
+ !AddEnumUnderlyingTypeDiff(
+ enum_type_diff_protobuf.mutable_underlying_type_diff(),
+ underlying_type_diff)) ||
+ !AddEnumFields(enum_type_diff_protobuf.mutable_fields_removed(),
+ enum_type_diff_ir->GetFieldsRemoved()) ||
+ !AddEnumFields(enum_type_diff_protobuf.mutable_fields_added(),
+ enum_type_diff_ir->GetFieldsAdded()) ||
+ !AddEnumFieldDiffs(enum_type_diff_protobuf.mutable_fields_diff(),
+ enum_type_diff_ir->GetFieldsDiff())) {
+ llvm::errs() << "Enum field diff could not be added\n";
+ ::exit(1);
+ }
+ return enum_type_diff_protobuf;
+}
+
+abi_diff::GlobalVarDeclDiff IRDiffToProtobufConverter::ConvertGlobalVarDiffIR(
+ const GlobalVarDiffIR *global_var_diff_ir) {
+ abi_diff::GlobalVarDeclDiff global_var_diff;
+ global_var_diff.set_name(global_var_diff_ir->GetName());
+ abi_dump::GlobalVarDecl *old_global_var = global_var_diff.mutable_old();
+ abi_dump::GlobalVarDecl *new_global_var = global_var_diff.mutable_new_();
+ if (old_global_var == nullptr || new_global_var == nullptr) {
+ llvm::errs() << "Globar Var diff could not be added\n";
+ ::exit(1);
+ }
+ *old_global_var =
+ IRToProtobufConverter::ConvertGlobalVarIR(
+ global_var_diff_ir->GetOldGlobalVar());
+ *new_global_var =
+ IRToProtobufConverter::ConvertGlobalVarIR(
+ global_var_diff_ir->GetNewGlobalVar());
+ return global_var_diff;
+}
+
+abi_diff::FunctionDeclDiff IRDiffToProtobufConverter::ConvertFunctionDiffIR(
+ const FunctionDiffIR *function_diff_ir) {
+ abi_diff::FunctionDeclDiff function_diff;
+ function_diff.set_name(function_diff_ir->GetName());
+ abi_dump::FunctionDecl *old_function = function_diff.mutable_old();
+ abi_dump::FunctionDecl *new_function = function_diff.mutable_new_();
+ if (old_function == nullptr || new_function == nullptr) {
+ llvm::errs() << "Function diff could not be added\n";
+ ::exit(1);
+ }
+ *old_function =
+ IRToProtobufConverter::ConvertFunctionIR(
+ function_diff_ir->GetOldFunction());
+ *new_function =
+ IRToProtobufConverter::ConvertFunctionIR(
+ function_diff_ir->GetNewFunction());
+ return function_diff;
+}
+
+bool ProtobufIRDumper::AddLinkableMessageIR (const LinkableMessageIR *lm) {
+ // No RTTI
+ switch (lm->GetKind()) {
+ case RecordTypeKind:
+ return AddRecordTypeIR(static_cast<const RecordTypeIR *>(lm));
+ case EnumTypeKind:
+ return AddEnumTypeIR(static_cast<const EnumTypeIR *>(lm));
+ case PointerTypeKind:
+ return AddPointerTypeIR(static_cast<const PointerTypeIR *>(lm));
+ case QualifiedTypeKind:
+ return AddQualifiedTypeIR(static_cast<const QualifiedTypeIR *>(lm));
+ case ArrayTypeKind:
+ return AddArrayTypeIR(static_cast<const ArrayTypeIR *>(lm));
+ case LvalueReferenceTypeKind:
+ return AddLvalueReferenceTypeIR(
+ static_cast<const LvalueReferenceTypeIR *>(lm));
+ case RvalueReferenceTypeKind:
+ return AddRvalueReferenceTypeIR(
+ static_cast<const RvalueReferenceTypeIR*>(lm));
+ case BuiltinTypeKind:
+ return AddBuiltinTypeIR(static_cast<const BuiltinTypeIR*>(lm));
+ case GlobalVarKind:
+ return AddGlobalVarIR(static_cast<const GlobalVarIR*>(lm));
+ case FunctionKind:
+ return AddFunctionIR(static_cast<const FunctionIR*>(lm));
+ }
+ return false;
+}
+
+bool ProtobufIRDumper::AddRecordTypeIR(const RecordTypeIR *recordp) {
+ abi_dump::RecordType *added_record_type = tu_ptr_->add_record_types();
+ if (!added_record_type) {
+ return false;
+ }
+ *added_record_type = ConvertRecordTypeIR(recordp);
+ return true;
+}
+
+bool ProtobufIRDumper::AddFunctionIR(const FunctionIR *functionp) {
+ abi_dump::FunctionDecl *added_function = tu_ptr_->add_functions();
+ if (!added_function) {
+ return false;
+ }
+ *added_function = ConvertFunctionIR(functionp);
+ return true;
+}
+
+bool ProtobufIRDumper::AddEnumTypeIR(const EnumTypeIR *enump) {
+ abi_dump::EnumType *added_enum_type = tu_ptr_->add_enum_types();
+ if (!added_enum_type) {
+ return false;
+ }
+ *added_enum_type = ConvertEnumTypeIR(enump);
+ return true;
+}
+
+bool ProtobufIRDumper::AddGlobalVarIR(const GlobalVarIR *global_varp) {
+ abi_dump::GlobalVarDecl *added_global_var = tu_ptr_->add_global_vars();
+ if (!added_global_var) {
+ return false;
+ }
+ *added_global_var = ConvertGlobalVarIR(global_varp);
+ return true;
+}
+
+bool ProtobufIRDumper::AddPointerTypeIR(const PointerTypeIR *pointerp) {
+ abi_dump::PointerType *added_pointer_type = tu_ptr_->add_pointer_types();
+ if (!added_pointer_type) {
+ return false;
+ }
+ *added_pointer_type = ConvertPointerTypeIR(pointerp);
+ return true;
+}
+
+bool ProtobufIRDumper::AddQualifiedTypeIR(const QualifiedTypeIR *qualtypep) {
+ abi_dump::QualifiedType *added_qualified_type =
+ tu_ptr_->add_qualified_types();
+ if (!added_qualified_type) {
+ return false;
+ }
+ *added_qualified_type = ConvertQualifiedTypeIR(qualtypep);
+ return true;
+}
+
+bool ProtobufIRDumper::AddBuiltinTypeIR(const BuiltinTypeIR *builtin_typep) {
+ abi_dump::BuiltinType *added_builtin_type =
+ tu_ptr_->add_builtin_types();
+ if (!added_builtin_type) {
+ return false;
+ }
+ *added_builtin_type = ConvertBuiltinTypeIR(builtin_typep);
+ return true;
+}
+
+bool ProtobufIRDumper::AddArrayTypeIR(const ArrayTypeIR *array_typep) {
+ abi_dump::ArrayType *added_array_type =
+ tu_ptr_->add_array_types();
+ if (!added_array_type) {
+ return false;
+ }
+ *added_array_type = ConvertArrayTypeIR(array_typep);
+ return true;
+}
+
+bool ProtobufIRDumper::AddLvalueReferenceTypeIR(
+ const LvalueReferenceTypeIR *lvalue_reference_typep) {
+ abi_dump::LvalueReferenceType *added_lvalue_reference_type =
+ tu_ptr_->add_lvalue_reference_types();
+ if (!added_lvalue_reference_type) {
+ return false;
+ }
+ *added_lvalue_reference_type =
+ ConvertLvalueReferenceTypeIR(lvalue_reference_typep);
+ return true;
+}
+
+bool ProtobufIRDumper::AddRvalueReferenceTypeIR(
+ const RvalueReferenceTypeIR *rvalue_reference_typep) {
+ abi_dump::RvalueReferenceType *added_rvalue_reference_type =
+ tu_ptr_->add_rvalue_reference_types();
+ if (!added_rvalue_reference_type) {
+ return false;
+ }
+ *added_rvalue_reference_type =
+ ConvertRvalueReferenceTypeIR(rvalue_reference_typep);
+ return true;
+}
+
+bool ProtobufIRDumper::Dump() {
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+ assert( tu_ptr_.get() != nullptr);
+ std::ofstream text_output(dump_path_);
+ google::protobuf::io::OstreamOutputStream text_os(&text_output);
+ return google::protobuf::TextFormat::Print(*tu_ptr_.get(), &text_os);
+}
+
+void ProtobufIRDiffDumper::AddLibNameIR(const std::string &name) {
+ diff_tu_->set_lib_name(name);
+}
+
+void ProtobufIRDiffDumper::AddArchIR(const std::string &arch) {
+ diff_tu_->set_arch(arch);
+}
+
+CompatibilityStatusIR ProtobufIRDiffDumper::GetCompatibilityStatusIR() {
+ if (diff_tu_->functions_removed().size() != 0 ||
+ diff_tu_->global_vars_removed().size() != 0 ||
+ diff_tu_->function_diffs().size() != 0 ||
+ diff_tu_->global_var_diffs().size() != 0 ||
+ diff_tu_->enum_type_diffs().size() != 0 ||
+ diff_tu_->record_type_diffs().size() != 0 ||
+ diff_tu_->removed_elf_functions().size() != 0 ||
+ diff_tu_->removed_elf_objects().size() != 0) {
+ return CompatibilityStatusIR::Incompatible;
+ }
+
+ CompatibilityStatusIR combined_status = CompatibilityStatusIR::Compatible;
+
+ if (diff_tu_->enum_type_extension_diffs().size() != 0 ||
+ diff_tu_->functions_added().size() != 0 ||
+ diff_tu_->global_vars_added().size() !=0 ||
+ diff_tu_->added_elf_functions().size() != 0 ||
+ diff_tu_->added_elf_objects().size() != 0) {
+ combined_status = combined_status | CompatibilityStatusIR::Extension;
+ }
+
+ if (diff_tu_->unreferenced_enum_type_diffs().size() != 0 ||
+ diff_tu_->unreferenced_enum_types_removed().size() != 0 ||
+ diff_tu_->unreferenced_record_types_removed().size() != 0 ||
+ diff_tu_->unreferenced_record_type_diffs().size() != 0 ||
+ diff_tu_->unreferenced_enum_type_extension_diffs().size() != 0 ||
+ diff_tu_->unreferenced_record_types_added().size() != 0 ||
+ diff_tu_->unreferenced_enum_types_added().size()) {
+ combined_status =
+ combined_status | CompatibilityStatusIR::UnreferencedChanges;
+ }
+
+ return combined_status;
+}
+
+void ProtobufIRDiffDumper::AddCompatibilityStatusIR(
+ CompatibilityStatusIR status) {
+ diff_tu_->set_compatibility_status(CompatibilityStatusIRToProtobuf(status));
+}
+
+bool ProtobufIRDiffDumper::AddDiffMessageIR(
+ const DiffMessageIR *message,
+ const std::string &type_stack,
+ DiffKind diff_kind) {
+ switch (message->Kind()) {
+ case RecordTypeKind:
+ return AddRecordTypeDiffIR(
+ static_cast<const RecordTypeDiffIR *>(message),
+ type_stack, diff_kind);
+ case EnumTypeKind:
+ return AddEnumTypeDiffIR(
+ static_cast<const EnumTypeDiffIR *>(message),
+ type_stack, diff_kind);
+ case GlobalVarKind:
+ return AddGlobalVarDiffIR(
+ static_cast<const GlobalVarDiffIR*>(message),
+ type_stack, diff_kind);
+ case FunctionKind:
+ return AddFunctionDiffIR(
+ static_cast<const FunctionDiffIR*>(message),
+ type_stack, diff_kind);
+ default:
+ break;
+ }
+ llvm::errs() << "Dump Diff attempted on something not a user defined type" <<
+ "/ function / global variable\n";
+ return false;
+}
+
+bool ProtobufIRDiffDumper::AddLinkableMessageIR(
+ const LinkableMessageIR *message,
+ DiffKind diff_kind) {
+ switch (message->GetKind()) {
+ case RecordTypeKind:
+ return AddLoneRecordTypeDiffIR(
+ static_cast<const RecordTypeIR *>(message), diff_kind);
+ case EnumTypeKind:
+ return AddLoneEnumTypeDiffIR(
+ static_cast<const EnumTypeIR *>(message), diff_kind);
+ case GlobalVarKind:
+ return AddLoneGlobalVarDiffIR(
+ static_cast<const GlobalVarIR*>(message), diff_kind);
+ case FunctionKind:
+ return AddLoneFunctionDiffIR(
+ static_cast<const FunctionIR*>(message), diff_kind);
+ default:
+ break;
+ }
+ llvm::errs() << "Dump Diff attempted on something not a user defined type" <<
+ "/ function / global variable\n";
+ return false;
+}
+
+bool ProtobufIRDiffDumper::AddElfSymbolMessageIR (const ElfSymbolIR *elf_symbol,
+ DiffKind diff_kind) {
+ switch (elf_symbol->GetKind()) {
+ case ElfSymbolIR::ElfFunctionKind:
+ return AddElfFunctionIR(static_cast<const ElfFunctionIR *>(elf_symbol),
+ diff_kind);
+ break;
+ case ElfSymbolIR::ElfObjectKind:
+ return AddElfObjectIR(static_cast<const ElfObjectIR *>(elf_symbol),
+ diff_kind);
+ break;
+ }
+ // Any other kind is invalid
+ return false;
+}
+
+bool ProtobufIRDiffDumper::AddElfFunctionIR(
+ const ElfFunctionIR *elf_function_ir, DiffKind diff_kind) {
+ abi_dump::ElfFunction *added_elf_function = nullptr;
+ switch(diff_kind) {
+ case DiffKind::Removed:
+ added_elf_function = diff_tu_->add_removed_elf_functions();
+ break;
+ case DiffKind::Added:
+ added_elf_function = diff_tu_->add_added_elf_functions();
+ break;
+ default:
+ llvm::errs() << "Invalid call to AddElfFunctionIR\n";
+ return false;
+ }
+ if (added_elf_function == nullptr) {
+ return false;
+ }
+ *added_elf_function =
+ IRToProtobufConverter::ConvertElfFunctionIR(elf_function_ir);
+ return true;
+}
+
+bool ProtobufIRDiffDumper::AddElfObjectIR(
+ const ElfObjectIR *elf_object_ir, DiffKind diff_kind) {
+ abi_dump::ElfObject *added_elf_object = nullptr;
+ switch(diff_kind) {
+ case DiffKind::Removed:
+ added_elf_object = diff_tu_->add_removed_elf_objects();
+ break;
+ case DiffKind::Added:
+ added_elf_object = diff_tu_->add_added_elf_objects();
+ break;
+ default:
+ llvm::errs() << "Invalid call to AddElfObjectIR\n";
+ return false;
+ }
+ if (added_elf_object == nullptr) {
+ return false;
+ }
+ *added_elf_object =
+ IRToProtobufConverter::ConvertElfObjectIR(elf_object_ir);
+ return true;
+}
+
+bool ProtobufIRDiffDumper::AddLoneRecordTypeDiffIR(
+ const RecordTypeIR *record_type_ir,
+ DiffKind diff_kind) {
+ abi_dump::RecordType *added_record_type = nullptr;
+ switch (diff_kind) {
+ case DiffKind::Removed:
+ // Referenced record types do not get reported as added / removed,
+ // the diff shows up in the parent type / function/ global variable
+ // referencing the record.
+ added_record_type = diff_tu_->add_unreferenced_record_types_removed();
+ break;
+ case DiffKind::Added:
+ added_record_type = diff_tu_->add_unreferenced_record_types_added();
+ break;
+ default:
+ llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
+ return false;
+ }
+ if (added_record_type == nullptr) {
+ return false;
+ }
+ *added_record_type =
+ IRToProtobufConverter::ConvertRecordTypeIR(record_type_ir);
+ return true;
+}
+
+bool ProtobufIRDiffDumper::AddLoneFunctionDiffIR(
+ const FunctionIR *function_ir,
+ DiffKind diff_kind) {
+ abi_dump::FunctionDecl *added_function = nullptr;
+ switch (diff_kind) {
+ case DiffKind::Removed:
+ added_function = diff_tu_->add_functions_removed();
+ break;
+ case DiffKind::Added:
+ added_function = diff_tu_->add_functions_added();
+ break;
+ default:
+ llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
+ return false;
+ }
+ *added_function = IRToProtobufConverter::ConvertFunctionIR(function_ir);
+ return true;
+}
+
+bool ProtobufIRDiffDumper::AddLoneEnumTypeDiffIR(
+ const EnumTypeIR *enum_type_ir, DiffKind diff_kind) {
+ abi_dump::EnumType *added_enum_type = nullptr;
+ switch (diff_kind) {
+ case DiffKind::Removed:
+ // Referenced enum types do not get reported as added / removed,
+ // the diff shows up in the parent type / function/ global variable
+ // referencing the enum.
+ added_enum_type = diff_tu_->add_unreferenced_enum_types_removed();
+ break;
+ case DiffKind::Added:
+ added_enum_type = diff_tu_->add_unreferenced_enum_types_added();
+ break;
+ default:
+ llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
+ return false;
+ }
+ if (added_enum_type == nullptr) {
+ return false;
+ }
+ *added_enum_type = IRToProtobufConverter::ConvertEnumTypeIR(enum_type_ir);
+ return true;
+}
+
+bool ProtobufIRDiffDumper::AddLoneGlobalVarDiffIR(
+ const GlobalVarIR *global_var_ir, DiffKind diff_kind) {
+ abi_dump::GlobalVarDecl *added_global_var = nullptr;
+ switch (diff_kind) {
+ case DiffKind::Removed:
+ added_global_var = diff_tu_->add_global_vars_removed();
+ break;
+ case DiffKind::Added:
+ added_global_var = diff_tu_->add_global_vars_added();
+ break;
+ default:
+ llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
+ return false;
+ }
+ *added_global_var = IRToProtobufConverter::ConvertGlobalVarIR(global_var_ir);
+ return true;
+}
+
+bool ProtobufIRDiffDumper::AddRecordTypeDiffIR(
+ const RecordTypeDiffIR *record_diff_ir,
+ const std::string &type_stack,
+ DiffKind diff_kind) {
+ abi_diff::RecordTypeDiff *added_record_type_diff = nullptr;
+ switch (diff_kind) {
+ case DiffKind::Unreferenced:
+ added_record_type_diff = diff_tu_->add_unreferenced_record_type_diffs();
+ break;
+ case DiffKind::Referenced:
+ added_record_type_diff = diff_tu_->add_record_type_diffs();
+ break;
+ default:
+ break;
+ }
+ if (!added_record_type_diff) {
+ return false;
+ }
+
+ *added_record_type_diff =
+ IRDiffToProtobufConverter::ConvertRecordTypeDiffIR(record_diff_ir);
+ added_record_type_diff->set_type_stack(type_stack);
+ return true;
+}
+
+bool ProtobufIRDiffDumper::AddFunctionDiffIR(
+ const FunctionDiffIR *function_diff_ir, const std::string &type_stack,
+ DiffKind diff_kind) {
+ abi_diff::FunctionDeclDiff *added_function_diff =
+ diff_tu_->add_function_diffs();
+ if (!added_function_diff) {
+ return false;
+ }
+ *added_function_diff =
+ IRDiffToProtobufConverter::ConvertFunctionDiffIR(function_diff_ir);
+ return true;
+}
+
+bool ProtobufIRDiffDumper::AddEnumTypeDiffIR(const EnumTypeDiffIR *enum_diff_ir,
+ const std::string &type_stack,
+ DiffKind diff_kind) {
+ abi_diff::EnumTypeDiff *added_enum_type_diff = nullptr;
+ switch (diff_kind) {
+ case DiffKind::Unreferenced:
+ if (enum_diff_ir->IsExtended()) {
+ added_enum_type_diff =
+ diff_tu_->add_unreferenced_enum_type_extension_diffs();
+ } else {
+ added_enum_type_diff =
+ diff_tu_->add_unreferenced_enum_type_diffs();
+ }
+ break;
+ case DiffKind::Referenced:
+ if (enum_diff_ir->IsExtended()) {
+ added_enum_type_diff =
+ diff_tu_->add_enum_type_extension_diffs();
+ } else {
+ added_enum_type_diff =
+ diff_tu_->add_enum_type_diffs();
+ }
+ break;
+ default:
+ break;
+ }
+ if (!added_enum_type_diff) {
+ return false;
+ }
+ *added_enum_type_diff =
+ IRDiffToProtobufConverter::ConvertEnumTypeDiffIR(enum_diff_ir);
+ added_enum_type_diff->set_type_stack(type_stack);
+ return true;
+}
+
+bool ProtobufIRDiffDumper::AddGlobalVarDiffIR(
+ const GlobalVarDiffIR *global_var_diff_ir,
+ const std::string &type_stack,
+ DiffKind diff_kind) {
+ abi_diff::GlobalVarDeclDiff *added_global_var_diff =
+ diff_tu_->add_global_var_diffs();
+ if (!added_global_var_diff) {
+ return false;
+ }
+ *added_global_var_diff =
+ IRDiffToProtobufConverter::ConvertGlobalVarDiffIR(global_var_diff_ir);
+ return true;
+}
+
+bool ProtobufIRDiffDumper::Dump() {
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+ assert(diff_tu_.get() != nullptr);
+ std::ofstream text_output(dump_path_);
+ google::protobuf::io::OstreamOutputStream text_os(&text_output);
+ return google::protobuf::TextFormat::Print(*diff_tu_.get(), &text_os);
+}
+
+} //abi_util
diff --git a/vndk/tools/header-checker/proto/abi_diff.proto b/vndk/tools/header-checker/proto/abi_diff.proto
index 28dbd52..17cfc92 100644
--- a/vndk/tools/header-checker/proto/abi_diff.proto
+++ b/vndk/tools/header-checker/proto/abi_diff.proto
@@ -4,97 +4,112 @@
package abi_diff;
-message RecordFieldDeclDiff {
- optional abi_dump.RecordFieldDecl old = 1;
- optional abi_dump.RecordFieldDecl new = 2;
- optional uint32 index = 3;
+message TypeInfo {
+ optional uint64 size = 1;
+ optional uint32 alignment = 2;
}
-message EnumFieldDeclDiff {
- optional abi_dump.EnumFieldDecl old = 1;
- optional abi_dump.EnumFieldDecl new = 2;
- optional uint32 index = 3;
+message TypeInfoDiff {
+ optional TypeInfo old_type_info = 1;
+ optional TypeInfo new_type_info = 2;
+}
+
+message VTableLayoutDiff {
+ optional abi_dump.VTableLayout old_vtable = 1;
+ optional abi_dump.VTableLayout new_vtable = 2;
+}
+
+message RecordFieldDeclDiff {
+ optional abi_dump.RecordFieldDecl old_field = 1;
+ optional abi_dump.RecordFieldDecl new_field = 2;
}
message CXXBaseSpecifierDiff {
- optional abi_dump.CXXBaseSpecifier old = 1;
- optional abi_dump.CXXBaseSpecifier new = 2;
- optional uint32 index = 3;
+ repeated abi_dump.CXXBaseSpecifier old_bases = 1;
+ repeated abi_dump.CXXBaseSpecifier new_bases = 2;
}
-message CXXVTableDiff {
- optional abi_dump.VTableComponent old = 1;
- optional abi_dump.VTableComponent new = 2;
- optional uint32 index = 3;
+message RecordTypeDiff {
+ optional string name = 1;
+ optional string type_stack = 2;
+ optional TypeInfoDiff type_info_diff = 3;
+ repeated abi_dump.RecordFieldDecl fields_removed = 4;
+ repeated RecordFieldDeclDiff fields_diff = 5;
+ optional CXXBaseSpecifierDiff bases_diff = 6;
+ optional VTableLayoutDiff vtable_layout_diff = 7;
}
-message BasicNamedAndTypedDeclDiff {
- optional abi_dump.BasicNamedAndTypedDecl old = 1;
- optional abi_dump.BasicNamedAndTypedDecl new = 2;
+message UnderlyingTypeDiff {
+ optional string old_type = 1;
+ optional string new_type = 2;
}
-message RecordDeclDiff {
- repeated RecordFieldDeclDiff field_diffs = 1;
- repeated CXXBaseSpecifierDiff base_diffs = 2;
- repeated CXXVTableDiff vtable_diffs = 3;
- optional BasicNamedAndTypedDeclDiff type_diff = 4;
- optional string name = 5;
+message EnumFieldDeclDiff {
+ optional abi_dump.EnumFieldDecl old_field = 1;
+ optional abi_dump.EnumFieldDecl new_field = 2;
}
-message EnumDeclDiff {
- repeated EnumFieldDeclDiff field_diffs = 1;
- optional BasicNamedAndTypedDeclDiff type_diff = 2;
- optional string name = 3;
-}
-
-message ReturnTypeDiff {
- optional abi_dump.BasicNamedAndTypedDecl old = 1;
- optional abi_dump.BasicNamedAndTypedDecl new = 2;
-}
-
-message ParamDeclDiff {
- optional abi_dump.ParamDecl old = 1;
- optional abi_dump.ParamDecl new = 2;
- optional uint32 index = 3;
+message EnumTypeDiff {
+ optional string type_stack = 1;
+ optional string name = 2;
+ repeated EnumFieldDeclDiff fields_diff = 3;
+ optional UnderlyingTypeDiff underlying_type_diff = 4;
+ repeated abi_dump.EnumFieldDecl fields_added = 5;
+ repeated abi_dump.EnumFieldDecl fields_removed = 6;
}
message FunctionDeclDiff {
- optional ReturnTypeDiff return_type_diffs = 1;
- repeated ParamDeclDiff param_diffs = 2;
- optional string name = 3;
+ // Template diffs are not required since in C++, they will show up in mangled
+ // names and in C, templates are not supported.
+ optional string type_stack = 1;
+ optional string name = 2;
+ optional abi_dump.FunctionDecl old = 3;
+ optional abi_dump.FunctionDecl new = 4;
}
message GlobalVarDeclDiff {
- optional BasicNamedAndTypedDeclDiff type_diff = 1;
-}
-
-enum CompatibilityStatus {
- COMPATIBLE = 0;
- EXTENSION = 1;
- INCOMPATIBLE = 4;
+ optional string type_stack = 1;
+ optional string name = 2;
+ optional abi_dump.GlobalVarDecl old = 3; // Old global var
+ optional abi_dump.GlobalVarDecl new = 4; // New global var
}
message TranslationUnitDiff {
// Library Name
optional string lib_name = 1;
optional string arch = 2;
- // Differing Elements.
- repeated RecordDeclDiff records_diff = 3;
- repeated EnumDeclDiff enums_diff = 4;
- repeated FunctionDeclDiff functions_diff = 5;
- repeated GlobalVarDeclDiff global_vars_diff = 6;
- // Removed Elements.
- repeated abi_dump.RecordDecl records_removed = 7;
- repeated abi_dump.FunctionDecl functions_removed = 8;
- repeated abi_dump.EnumDecl enums_removed = 9;
- repeated abi_dump.GlobalVarDecl global_vars_removed = 10;
- // Added Elements.
- repeated abi_dump.RecordDecl records_added = 11;
- repeated abi_dump.FunctionDecl functions_added = 12;
- repeated abi_dump.EnumDecl enums_added = 13;
- repeated abi_dump.GlobalVarDecl global_vars_added = 14;
+ // Records.
+ repeated RecordTypeDiff record_type_diffs = 3;
+ repeated RecordTypeDiff unreferenced_record_type_diffs = 4;
+ repeated abi_dump.RecordType unreferenced_record_types_removed = 5;
+ repeated abi_dump.RecordType unreferenced_record_types_added = 6;
+
+ // Enums
+ repeated EnumTypeDiff enum_type_diffs = 7;
+ repeated EnumTypeDiff enum_type_extension_diffs = 8;
+ repeated EnumTypeDiff unreferenced_enum_type_diffs = 9;
+ repeated EnumTypeDiff unreferenced_enum_type_extension_diffs = 10;
+ repeated abi_dump.EnumType unreferenced_enum_types_removed = 11;
+ repeated abi_dump.EnumType unreferenced_enum_types_added = 12;
+
+ // Functions and Global variables.
+ repeated FunctionDeclDiff function_diffs = 13;
+ repeated GlobalVarDeclDiff global_var_diffs = 14;
+
+ repeated abi_dump.FunctionDecl functions_removed = 15;
+ repeated abi_dump.GlobalVarDecl global_vars_removed = 16;
+
+ repeated abi_dump.FunctionDecl functions_added = 17;
+ repeated abi_dump.GlobalVarDecl global_vars_added = 18;
+
+ repeated abi_dump.ElfFunction added_elf_functions = 19;
+ repeated abi_dump.ElfFunction removed_elf_functions = 20;
+
+ repeated abi_dump.ElfObject added_elf_objects = 21;
+ repeated abi_dump.ElfObject removed_elf_objects = 22;
+
// Compatiblity Status
- optional CompatibilityStatus compatibility_status = 15;
+ optional CompatibilityStatus compatibility_status = 23;
}
// Not merged with TranslationUnitDiff to allow future extensions.
@@ -108,3 +123,9 @@
message MergedTranslationUnitDiff {
repeated ConciseDiffReportInformation diff_reports = 1;
}
+
+enum CompatibilityStatus {
+ COMPATIBLE = 0;
+ EXTENSION = 1;
+ INCOMPATIBLE = 4;
+}
diff --git a/vndk/tools/header-checker/proto/abi_dump.proto b/vndk/tools/header-checker/proto/abi_dump.proto
index 3633d20..870329c 100644
--- a/vndk/tools/header-checker/proto/abi_dump.proto
+++ b/vndk/tools/header-checker/proto/abi_dump.proto
@@ -2,50 +2,84 @@
package abi_dump;
-message BasicTypeAbi {
- // The type's name. for eg : a record field's type.
- optional string name = 1;
- // Optional since templated types will not have this information.
- optional uint64 size = 2 [default = 0];
- optional uint32 alignment = 3 [default = 0];
-}
-
enum AccessSpecifier {
public_access = 1;
private_access = 2;
protected_access = 3;
}
+enum RecordKind {
+ struct_kind = 1;
+ class_kind = 2;
+ union_kind = 3;
+}
+
message BasicNamedAndTypedDecl {
- optional BasicTypeAbi type_abi = 1;
// The TypedDecl's name.
- optional string name = 2;
- optional AccessSpecifier access = 3;
- optional string linker_set_key = 4;
+ optional string name = 1;
+ optional uint64 size = 2 [default = 0];
+ optional uint32 alignment = 3 [default = 0];
+ optional string referenced_type = 4;
+ optional string source_file = 5;
+ optional string linker_set_key = 6;
+}
+
+message ArrayType {
+ optional BasicNamedAndTypedDecl type_info = 1;
+}
+
+message PointerType {
+ optional BasicNamedAndTypedDecl type_info = 1;
+}
+
+message QualifiedType {
+ optional BasicNamedAndTypedDecl type_info = 1;
+ optional bool is_const = 6;
+ optional bool is_volatile = 7;
+ optional bool is_restricted = 8;
+}
+
+message BuiltinType {
+ optional BasicNamedAndTypedDecl type_info = 1;
+ optional bool is_unsigned = 2;
+ optional bool is_integral = 3;
+}
+
+message LvalueReferenceType {
+ optional BasicNamedAndTypedDecl type_info = 1;
+}
+
+message RvalueReferenceType {
+ optional BasicNamedAndTypedDecl type_info = 1;
}
message FunctionDecl {
- optional BasicNamedAndTypedDecl basic_abi = 1;
- // Mangled name.
- optional string mangled_function_name = 2;
+ // Return type reference
+ optional string return_type = 1;
+ optional string function_name = 2;
optional string source_file = 3;
repeated ParamDecl parameters = 4;
optional TemplateInfo template_info = 5;
+ optional string linker_set_key = 6;
+ optional AccessSpecifier access = 7 [default = public_access];
}
message ParamDecl {
- optional BasicNamedAndTypedDecl basic_abi = 1;
+ optional string referenced_type = 1;
optional bool default_arg = 2;
}
message RecordFieldDecl {
// For future additions.
- optional BasicNamedAndTypedDecl basic_abi = 1;
+ optional string referenced_type = 1;
+ optional uint64 field_offset = 2;
+ optional string field_name = 3;
+ optional AccessSpecifier access = 4 [default = public_access];
}
message EnumFieldDecl {
- optional BasicNamedAndTypedDecl basic_abi = 1;
- optional int64 enum_field_value = 2; // assumption: fits int64
+ optional int64 enum_field_value = 1; // assumption: fits int64
+ optional string name = 3;
}
message TemplateInfo {
@@ -53,17 +87,13 @@
}
message TemplateElement {
- optional BasicTemplateElementAbi basic_abi = 1;
- message BasicTemplateElementAbi {
- optional BasicTypeAbi type_abi = 1;
- optional string name = 2;
- optional string linker_set_key = 3;
- }
+ optional string referenced_type = 1;
}
message CXXBaseSpecifier {
- optional BasicNamedAndTypedDecl basic_abi = 1;
+ optional string referenced_type = 1;
optional bool is_virtual = 2;
+ optional AccessSpecifier access = 3;
}
message VTableComponent {
@@ -89,30 +119,51 @@
repeated VTableComponent vtable_components = 1;
}
-message RecordDecl {
- optional BasicNamedAndTypedDecl basic_abi = 1;
+message RecordType {
+ optional BasicNamedAndTypedDecl type_info = 1;
repeated RecordFieldDecl fields = 2;
repeated CXXBaseSpecifier base_specifiers = 3;
- optional string source_file = 4;
optional TemplateInfo template_info = 5;
- optional string mangled_record_name = 6;
optional VTableLayout vtable_layout = 7;
+ optional AccessSpecifier access = 8 [default = public_access];
+ optional bool is_anonymous = 9;
+ optional RecordKind record_kind = 10 [default = struct_kind];
}
-message EnumDecl {
- optional BasicNamedAndTypedDecl basic_abi = 1;
- repeated EnumFieldDecl enum_fields = 2;
- optional string source_file = 3;
+message EnumType {
+ optional BasicNamedAndTypedDecl type_info = 1;
+ optional string underlying_type = 2;
+ repeated EnumFieldDecl enum_fields = 3;
+ optional AccessSpecifier access = 4 [default = public_access];
}
message GlobalVarDecl {
- optional BasicNamedAndTypedDecl basic_abi = 1;
+ optional string name = 1;
optional string source_file = 2;
+ optional string linker_set_key = 3;
+ optional string referenced_type = 4;
+ optional AccessSpecifier access = 5 [default = public_access];
+}
+
+message ElfFunction {
+ optional string name = 1;
+}
+
+message ElfObject {
+ optional string name = 1;
}
message TranslationUnit {
- repeated RecordDecl records = 1;
- repeated FunctionDecl functions = 2;
- repeated EnumDecl enums = 3;
- repeated GlobalVarDecl global_vars = 4;
+ repeated RecordType record_types = 1;
+ repeated EnumType enum_types = 2;
+ repeated PointerType pointer_types = 3;
+ repeated LvalueReferenceType lvalue_reference_types = 4;
+ repeated RvalueReferenceType rvalue_reference_types = 5;
+ repeated BuiltinType builtin_types = 6;
+ repeated QualifiedType qualified_types = 7;
+ repeated ArrayType array_types = 8;
+ repeated FunctionDecl functions = 9;
+ repeated GlobalVarDecl global_vars = 10;
+ repeated ElfFunction elf_functions = 11;
+ repeated ElfObject elf_objects = 12;
}
diff --git a/vndk/tools/header-checker/tests/input/example1.h b/vndk/tools/header-checker/tests/input/example1.h
index c00cf06..1ff0c1c 100644
--- a/vndk/tools/header-checker/tests/input/example1.h
+++ b/vndk/tools/header-checker/tests/input/example1.h
@@ -7,9 +7,21 @@
extern "C" {
#endif
+struct ForwardDeclaration;
+int uses_forward_decl(struct ForwardDeclaration *);
+
struct Hello {
int foo;
int bar;
+ enum {A, B} enum_field;
+ enum {C, D} enum_field2;
+ struct {
+ int a;
+ int b;
+ struct {
+ int c;
+ };
+ };
};
#if defined(__cplusplus)
@@ -24,8 +36,17 @@
cfloat_type cpp_bar;
virtual int again() { return 0; }
CPPHello() : cpp_foo(20), cpp_bar(1.234) { }
+ enum Bla{BLA = 1};
+ int test_enum() {return CPPHello::BLA;}
};
+
+void fooVariadic (int &, int *, ...);
+
+int boo (const CPPHello, int *, float *) {
+ return CPPHello::BLA;
+}
+
template<typename T>
struct StackNode {
public:
@@ -63,7 +84,7 @@
template<typename T>
class List
{
-protected:
+public:
/*
* One element in the list.
*/
@@ -74,6 +95,7 @@
inline T& getRef() { return mVal; }
inline const T& getRef() const { return mVal; }
private:
+ void PrivateNode();
friend class List;
friend class _ListIterator;
T mVal;
@@ -83,11 +105,20 @@
_Node *middle;
};
+
typedef List<float> float_list;
float_list float_list_test;
-
typedef List<int> int_list;
int_list int_list_test;
+List<float>::_Node node(2);
+int ListMangle(int_list *, StackNode<int> *);
+
+template<typename IChild, typename IParent, typename BpChild, typename BpParent>
+List<IChild> castInterface(List<IParent> parent, const char *childIndicator, bool emitError) {return List<IChild>();}
+
+void format() {
+castInterface<float, float, float , float>(List<float>(), "foo", true);
+}
#endif // EXAMPLE1_H_
diff --git a/vndk/tools/header-checker/tests/input/example2.h b/vndk/tools/header-checker/tests/input/example2.h
index acf0f42..bc225eb 100644
--- a/vndk/tools/header-checker/tests/input/example2.h
+++ b/vndk/tools/header-checker/tests/input/example2.h
@@ -22,6 +22,7 @@
int bar_again;
static int hello_forever;
virtual int again();
+ virtual ~HelloAgain() {}
};
struct NowWeCrash;
} // namespace test2
diff --git a/vndk/tools/vndk-compliance/parse-and-fix-errors.sh b/vndk/tools/vndk-compliance/parse-and-fix-errors.sh
index 84c6bbd..b4f6216 100755
--- a/vndk/tools/vndk-compliance/parse-and-fix-errors.sh
+++ b/vndk/tools/vndk-compliance/parse-and-fix-errors.sh
@@ -30,10 +30,10 @@
cat log | grep "FAILED\|error:" > log.error
#libs that should be added to LOCAL_HEADER_LIBRARIES
-ADD_TO_HEADER_LIBS=(hardware system)
+ADD_TO_HEADER_LIBS=(hardware system cutils utils)
#libs that should be added to LOCAL_SHARED_LIBRARIES
-ADD_TO_SHARED_LIBS=(cutils utils log)
+ADD_TO_SHARED_LIBS=(log)
ALL_LIBS=(${ADD_TO_HEADER_LIBS[@]} ${ADD_TO_SHARED_LIBS[@]})