C/C++ adjustments and bug fixes.

Bug: 37751376

Test: dumped the abi of libminijail, removed the "struct" keyword from
the abi-dump and confirmed that this did not result in an abi breakage
getting reported.

Bug: 37749718

Test: manually invoked header-abi-diff with file containing a list of
symbols to omit abi checks on from libminijail after changing sizes and
alignments of those symbols from libminijail's abi dumps. Diffs were not
reported.

Bug: 37918686

Test: dumped the abi of libbcinfo, it contains records as well as
symbols which adhere to the regex in the symbol file.

Also make function signature diffing independent of C++ name mangling.

Change-Id: Id34209ef24d1202745ca69765a4e2a96d1a05c2a
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 2a61357..ebe782e 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
@@ -50,22 +50,24 @@
 
   Status record_status = Collect<abi_dump::RecordDecl>(
       diff_tu->mutable_records_added(), diff_tu->mutable_records_removed(),
-      diff_tu->mutable_records_diff(), old_tu.records(), new_tu.records());
+      diff_tu->mutable_records_diff(), old_tu.records(), new_tu.records(),
+      ignored_symbols_);
 
   Status function_status = Collect<abi_dump::FunctionDecl>(
       diff_tu->mutable_functions_added(), diff_tu->mutable_functions_removed(),
       diff_tu->mutable_functions_diff(), old_tu.functions(),
-      new_tu.functions());
+      new_tu.functions(), ignored_symbols_);
 
   Status enum_status = Collect<abi_dump::EnumDecl>(
       diff_tu->mutable_enums_added(), diff_tu->mutable_enums_removed(),
-      diff_tu->mutable_enums_diff(), old_tu.enums(), new_tu.enums());
+      diff_tu->mutable_enums_diff(), old_tu.enums(), new_tu.enums(),
+      ignored_symbols_);
 
   Status global_var_status = Collect<abi_dump::GlobalVarDecl>(
       diff_tu->mutable_global_vars_added(),
       diff_tu->mutable_global_vars_removed(),
       diff_tu->mutable_global_vars_diff(), old_tu.global_vars(),
-      new_tu.global_vars());
+      new_tu.global_vars(), ignored_symbols_);
 
   Status combined_status =
       record_status | function_status | enum_status | global_var_status;
@@ -92,7 +94,8 @@
     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 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);
@@ -103,11 +106,11 @@
   AddToMap(&new_elements_map, new_srcs);
 
   if (!PopulateRemovedElements(elements_removed, old_elements_map,
-                               new_elements_map) ||
+                               new_elements_map, ignored_symbols) ||
       !PopulateRemovedElements(elements_added, new_elements_map,
-                               old_elements_map) ||
+                               old_elements_map, ignored_symbols) ||
       !PopulateCommonElements(elements_diff, old_elements_map,
-                              new_elements_map)) {
+                              new_elements_map, ignored_symbols)) {
     llvm::errs() << "Populating functions in report failed\n";
     ::exit(1);
   }
@@ -124,7 +127,8 @@
 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::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) {
@@ -135,7 +139,7 @@
         removed_elements.emplace_back(element);
       }
   }
-  if (!DumpLoneElements(dst, removed_elements)) {
+  if (!DumpLoneElements(dst, removed_elements, ignored_symbols)) {
     llvm::errs() << "Dumping added / removed element to report failed\n";
     return false;
   }
@@ -146,7 +150,8 @@
 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::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();
@@ -167,7 +172,7 @@
       new_element++;
     }
   }
-  if (!DumpDiffElements(dst, common_elements)) {
+  if (!DumpDiffElements(dst, common_elements, ignored_symbols)) {
     llvm::errs() << "Dumping difference in common element to report failed\n";
     return false;
   }
@@ -175,9 +180,14 @@
 }
 
 template <typename T>
-bool HeaderAbiDiff::DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
-                                     std::vector<const T *> &elements) {
+bool HeaderAbiDiff::DumpLoneElements(
+    google::protobuf::RepeatedPtrField<T> *dst,
+    std::vector<const T *> &elements,
+    const std::set<std::string> &ignored_symbols) {
   for (auto &&element : elements) {
+    if (abi_diff_wrappers::IgnoreSymbol<T>(element, ignored_symbols)) {
+      continue;
+    }
     T *added_element = dst->Add();
     if (!added_element) {
       llvm::errs() << "Adding element diff failed\n";
@@ -191,12 +201,16 @@
 template <typename T, typename TDiff>
 bool HeaderAbiDiff::DumpDiffElements(
     google::protobuf::RepeatedPtrField<TDiff>  *dst,
-    std::vector<std::pair<const T *,const T *>> &pairs) {
+    std::vector<std::pair<const T *,const T *>> &pairs,
+    const std::set<std::string> &ignored_symbols) {
   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)) {
+      continue;
+    }
     abi_diff_wrappers::DiffWrapper<T, TDiff> diff_wrapper(old_element,
                                                           new_element);
     std::unique_ptr<TDiff> decl_diff_ptr = diff_wrapper.Get();
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 c52476b..c7ee272 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
@@ -38,8 +38,10 @@
 
 
   HeaderAbiDiff(const std::string &old_dump, const std::string &new_dump,
-                const std::string &compatibility_report)
-      : old_dump_(old_dump), new_dump_(new_dump), cr_(compatibility_report) { }
+                const std::string &compatibility_report,
+                const std::set<std::string> &ignored_symbols)
+      : old_dump_(old_dump), new_dump_(new_dump), cr_(compatibility_report),
+        ignored_symbols_(ignored_symbols) { }
 
   Status GenerateCompatibilityReport();
 
@@ -53,7 +55,8 @@
       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 google::protobuf::RepeatedPtrField<T> &new_srcs,
+      const std::set<std::string> &ignored_symbols);
 
   template <typename T>
   static inline void AddToMap(std::map<std::string, const T *> *dst,
@@ -63,27 +66,32 @@
   static bool PopulateRemovedElements(
       google::protobuf::RepeatedPtrField<T> *dst,
       const std::map<std::string, const T *> &old_elements_map,
-      const std::map<std::string, const T *> &new_elements_map);
+      const std::map<std::string, const T *> &new_elements_map,
+      const std::set<std::string> &ignored_symbols);
 
   template <typename T, typename TDiff>
   static bool PopulateCommonElements(
       google::protobuf::RepeatedPtrField<TDiff> *dst,
       const std::map<std::string, const T *> &old_elements_map,
-      const std::map<std::string, const T *> &new_elements_map);
+      const std::map<std::string, const T *> &new_elements_map,
+      const std::set<std::string> &ignored_symbols);
 
   template <typename T, typename TDiff>
   static bool DumpDiffElements(
       google::protobuf::RepeatedPtrField<TDiff> *dst,
-      std::vector<std::pair<const T *, const T *>> &pairs);
+      std::vector<std::pair<const T *, const T *>> &pairs,
+      const std::set<std::string> &ignored_symbols);
 
   template <typename T>
   static bool DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
-                               std::vector<const T *> &elements);
+                               std::vector<const T *> &elements,
+                               const std::set<std::string> &ignored_symbols);
 
  private:
   const std::string &old_dump_;
   const std::string &new_dump_;
   const std::string &cr_;
+  const std::set<std::string> &ignored_symbols_;
 };
 
 typedef HeaderAbiDiff::Status Status;
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 8cb0bc7..36fcd35 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,6 +14,8 @@
 
 #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"
@@ -29,6 +31,7 @@
 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;
@@ -42,6 +45,7 @@
 using abi_dump::VTableComponent;
 using abi_dump::CXXBaseSpecifier;
 using abi_dump::GlobalVarDecl;
+using abi_dump::BasicNamedAndTypedDecl;
 
 namespace abi_diff_wrappers {
 
@@ -65,9 +69,32 @@
   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 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;
+}
+
 static bool DiffBasicTypeAbi(const abi_dump::BasicTypeAbi &old_abi,
                              const abi_dump::BasicTypeAbi &new_abi) {
-  bool name_comparison = (old_abi.name() != new_abi.name());
+  // 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;
@@ -78,6 +105,7 @@
   // 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());
 }
@@ -88,7 +116,16 @@
   // 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.enum_field_value() != new_element.enum_field_value()) ||
+      (old_element.basic_abi().name() != new_element.basic_abi().name());
+}
+
+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());
 }
 
 template <>
@@ -185,10 +222,27 @@
  }
 }
 
+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_;
+    return true;
+  }
+  return false;
+}
+
 template <>
-std::unique_ptr<RecordDeclDiff> DiffWrapper<RecordDecl, RecordDeclDiff>::Get() {
+std::unique_ptr<RecordDeclDiff>
+DiffWrapper<RecordDecl, RecordDeclDiff>::Get() {
   std::unique_ptr<RecordDeclDiff> record_diff(new RecordDeclDiff());
-  assert(oldp_->basic_abi().name() == newp_->basic_abi().name());
+  assert(oldp_->mangled_record_name() ==
+         newp_->mangled_record_name());
   record_diff->set_name(oldp_->basic_abi().name());
   google::protobuf::RepeatedPtrField<RecordFieldDeclDiff> *fdiffs =
       record_diff->mutable_field_diffs();
@@ -203,20 +257,30 @@
       GetElementDiffs(bdiffs, oldp_->base_specifiers(),
                       newp_->base_specifiers()) ||
       GetElementDiffs(vtdiffs, oldp_->vtable_layout().vtable_components(),
-                      newp_->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;
   }
   return nullptr;
 }
 
 template <>
-std::unique_ptr<EnumDeclDiff> DiffWrapper<EnumDecl, EnumDeclDiff>::Get() {
+std::unique_ptr<EnumDeclDiff>
+DiffWrapper<EnumDecl, EnumDeclDiff>::Get() {
   std::unique_ptr<EnumDeclDiff> enum_diff(new EnumDeclDiff());
-  assert(oldp_->basic_abi().name() == newp_->basic_abi().name());
+  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);
-  if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields())) {
+  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;
   }
   return nullptr;
@@ -226,17 +290,14 @@
 std::unique_ptr<FunctionDeclDiff>
 DiffWrapper<FunctionDecl, FunctionDeclDiff>::Get() {
   std::unique_ptr<FunctionDeclDiff> func_diff(new FunctionDeclDiff());
-  if (DiffBasicTypeAbi(oldp_->basic_abi().type_abi(),
-                       newp_->basic_abi().type_abi()) ||
-      IsAccessDownGraded(oldp_->basic_abi().access(),
-                         newp_->basic_abi().access())) {
-    assert(func_diff->mutable_return_type_diffs() != nullptr &&
-           func_diff->mutable_return_type_diffs()->mutable_old() != nullptr &&
-           func_diff->mutable_return_type_diffs()->mutable_new_() != nullptr);
-    *(func_diff->mutable_return_type_diffs()->mutable_old()) =
-        oldp_->basic_abi();
-    *(func_diff->mutable_return_type_diffs()->mutable_new_()) =
-        newp_->basic_abi();
+  google::protobuf::RepeatedPtrField<ParamDeclDiff> *pdiffs =
+      func_diff->mutable_param_diffs();
+  assert(func_diff->mutable_return_type_diffs() != nullptr);
+  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;
@@ -246,14 +307,11 @@
 std::unique_ptr<GlobalVarDeclDiff>
 DiffWrapper<GlobalVarDecl, GlobalVarDeclDiff>::Get() {
   std::unique_ptr<GlobalVarDeclDiff> global_var_diff(new GlobalVarDeclDiff());
-  if (DiffBasicTypeAbi(oldp_->basic_abi().type_abi(),
-                       newp_->basic_abi().type_abi()) ||
-      IsAccessDownGraded(oldp_->basic_abi().access(),
-                         newp_->basic_abi().access())) {
-    assert(global_var_diff->mutable_old() != nullptr);
-    assert(global_var_diff->mutable_new_() != nullptr);
-    *(global_var_diff->mutable_old()) = oldp_->basic_abi();
-    *(global_var_diff->mutable_new_()) = newp_->basic_abi();
+  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;
   }
   return nullptr;
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 c45482c..8cf4699 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
@@ -12,6 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#ifndef ABI_DIFF_WRAPPERS_H
+#define ABI_DIFF_WRAPPERS_H
+
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunused-parameter"
 #pragma clang diagnostic ignored "-Wnested-anon-types"
@@ -21,13 +24,19 @@
 
 namespace abi_diff_wrappers {
 
+template <typename T>
+static bool IgnoreSymbol(const T *element,
+                         const std::set<std::string> &ignored_symbols) {
+  return ignored_symbols.find(element->basic_abi().linker_set_key()) !=
+      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) { }
+  DiffWrapperBase(const T *oldp, const T *newp) : oldp_(oldp), newp_(newp) { }
   template <typename Element, typename ElementDiff>
   bool GetElementDiffs(
       google::protobuf::RepeatedPtrField<ElementDiff> *dst,
@@ -51,10 +60,9 @@
  public:
   DiffWrapper(const T *oldp, const T *newp)
       : DiffWrapperBase<T, TDiff>(oldp, newp) { }
-
   std::unique_ptr<TDiff> Get() override;
 };
 
 } // abi_diff_wrappers
 
-
+#endif // ABI_DIFF_WRAPPERS_H
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 111ef61..10d56dd 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
@@ -15,6 +15,7 @@
 #include "abi_diff.h"
 
 #include <llvm/Support/CommandLine.h>
+#include <llvm/Support/FileSystem.h>
 #include <llvm/Support/raw_ostream.h>
 
 static llvm::cl::OptionCategory header_checker_category(
@@ -36,11 +37,34 @@
     "advice-only", llvm::cl::desc("Advisory mode only"), llvm::cl::Optional,
     llvm::cl::cat(header_checker_category));
 
+static llvm::cl::opt<std::string> ignore_symbol_list(
+    "ignore-symbols", llvm::cl::desc("ignore symbols"), 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;
+  if (!symbol_ifstream) {
+    llvm::errs() << "Failed to open file containing symbols to ignore\n";
+    ::exit(1);
+  }
+  std::string line = "";
+  while (std::getline(symbol_ifstream, line)) {
+    ignored_symbols.insert(line);
+  }
+  return ignored_symbols;
+}
+
 int main(int argc, const char **argv) {
   GOOGLE_PROTOBUF_VERIFY_VERSION;
   llvm::cl::ParseCommandLineOptions(argc, argv, "header-checker");
   uint8_t extension_or_incompatible = 0;
-  HeaderAbiDiff judge(old_dump, new_dump, compatibility_report);
+  std::set<std::string> ignored_symbols;
+  if (llvm::sys::fs::exists(ignore_symbol_list)) {
+    ignored_symbols = LoadIgnoredSymbols(ignore_symbol_list);
+  }
+  HeaderAbiDiff judge(old_dump, new_dump, compatibility_report,
+                      ignored_symbols);
   switch (judge.GenerateCompatibilityReport()) {
     case HeaderAbiDiff::COMPATIBLE:
       break;
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 5ceca8f..d23d86e 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
@@ -14,6 +14,10 @@
 
 #include "abi_wrappers.h"
 
+#include <header_abi_util.h>
+
+#include <limits.h>
+#include <stdlib.h>
 #include <clang/Tooling/Core/QualTypeNames.h>
 
 #include <string>
@@ -32,12 +36,20 @@
                                           const clang::CompilerInstance *cip) {
   clang::SourceManager &sm = cip->getSourceManager();
   clang::SourceLocation location = decl->getLocation();
-  llvm::StringRef file_name = sm.getFilename(location);
-  llvm::SmallString<128> abs_path(file_name.str());
-  if (llvm::sys::fs::make_absolute(abs_path)) {
+  // We need to use the expansion location to identify whether we should recurse
+  // into the AST Node or not. For eg: macros specifying LinkageSpecDecl can
+  // have their spelling location defined somewhere outside a source / header
+  // file belonging to a library. This should not allow the AST node to be
+  // skipped. Its expansion location will still be the source-file / header
+  // belonging to the library.
+  clang::SourceLocation expansion_location = sm.getExpansionLoc(location);
+  llvm::StringRef file_name = sm.getFilename(expansion_location);
+  std::string file_name_adjusted = "";
+  char file_abs_path[PATH_MAX];
+  if (realpath(file_name.str().c_str(), file_abs_path) == nullptr) {
     return "";
   }
-  return abs_path.str();
+  return file_abs_path;
 }
 
 abi_dump::AccessSpecifier ABIWrapper::AccessClangToDump(
@@ -177,6 +189,11 @@
 std::string ABIWrapper::QualTypeToString(
     const clang::QualType &sweet_qt) const {
   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.
+  if (salty_qt.getTypePtr()->isDependentType()) {
+    return salty_qt.getAsString();
+  }
   return clang::TypeName::getFullyQualifiedName(salty_qt, *ast_contextp_);
 }
 
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 6e34be8..be370c4 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
@@ -127,7 +127,7 @@
 }
 
 static bool AreHeadersExported(const std::set<std::string> &exported_headers) {
-  return exported_headers.empty();
+  return !exported_headers.empty();
 }
 
 // We don't need to recurse into Declarations which are not exported.
@@ -137,7 +137,7 @@
   }
   std::string source_file = ABIWrapper::GetDeclSourceFile(decl, cip_);
   // If no exported headers are specified we assume the whole AST is exported.
-  if ((decl != tu_decl_) && !AreHeadersExported(exported_headers_) &&
+  if ((decl != tu_decl_) && AreHeadersExported(exported_headers_) &&
       (exported_headers_.find(source_file) == exported_headers_.end())) {
     return true;
   }
@@ -171,8 +171,3 @@
     ::exit(1);
   }
 }
-
-void HeaderASTPPCallbacks::MacroDefined(const clang::Token &macro_name_tok,
-                                        const clang::MacroDirective *) {
-  assert(macro_name_tok.getLength() != 0);
-}
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 038918b..f3e6f8c 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
@@ -83,10 +83,4 @@
   std::set<std::string> exported_headers_;
 };
 
-class HeaderASTPPCallbacks : public clang::PPCallbacks {
- public:
-  void MacroDefined(const clang::Token &macro_name_tok,
-                    const clang::MacroDirective *) override;
-};
-
 #endif  // AST_PROCESSING_H_
diff --git a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.cpp b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.cpp
index 69d6491..8f17328 100644
--- a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.cpp
+++ b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.cpp
@@ -26,20 +26,13 @@
 
 HeaderCheckerFrontendAction::HeaderCheckerFrontendAction(
     const std::string &dump_name, const std::vector<std::string> &exports)
-  : dump_name_(dump_name), export_header_dirs_(exports) { }
+  : dump_name_(dump_name), exported_header_dirs_(exports) { }
 
 std::unique_ptr<clang::ASTConsumer>
 HeaderCheckerFrontendAction::CreateASTConsumer(clang::CompilerInstance &ci,
                                                llvm::StringRef header_file) {
-  // Add preprocessor callbacks.
-  clang::Preprocessor &pp = ci.getPreprocessor();
-  pp.addPPCallbacks(llvm::make_unique<HeaderASTPPCallbacks>());
   std::set<std::string> exported_headers;
-  for (auto &&dir_name : export_header_dirs_) {
-    if (!abi_util::CollectExportedHeaderSet(dir_name, &exported_headers)) {
-         return nullptr;
-    }
-  }
+  exported_headers = abi_util::CollectAllExportedHeaders(exported_header_dirs_);
   // Create AST consumers.
   return llvm::make_unique<HeaderASTConsumer>(header_file,
                                               &ci, dump_name_,
diff --git a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.h b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.h
index 85afe23..61e4e4c 100644
--- a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.h
+++ b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.h
@@ -31,7 +31,7 @@
 class HeaderCheckerFrontendAction : public clang::ASTFrontendAction {
  private:
   std::string dump_name_;
-  const std::vector<std::string> &export_header_dirs_;
+  const std::vector<std::string> &exported_header_dirs_;
 
  public:
   HeaderCheckerFrontendAction(
diff --git a/vndk/tools/header-checker/header-abi-dumper/src/header_checker.cpp b/vndk/tools/header-checker/header-abi-dumper/src/header_checker.cpp
index 217b21e..626b76b 100644
--- a/vndk/tools/header-checker/header-abi-dumper/src/header_checker.cpp
+++ b/vndk/tools/header-checker/header-abi-dumper/src/header_checker.cpp
@@ -41,8 +41,8 @@
     llvm::cl::cat(header_checker_category));
 
 static llvm::cl::list<std::string> exported_header_dirs(
-    "I", llvm::cl::desc("<export_include_dirs>"), llvm::cl::ZeroOrMore,
-    llvm::cl::cat(header_checker_category));
+    "I", llvm::cl::desc("<export_include_dirs>"), llvm::cl::Prefix,
+    llvm::cl::ZeroOrMore, llvm::cl::cat(header_checker_category));
 
 // Hide irrelevant command line options defined in LLVM libraries.
 static void HideIrrelevantCommandLineOptions() {
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 b67e647..399b658 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
@@ -46,8 +46,8 @@
     llvm::cl::cat(header_linker_category));
 
 static llvm::cl::list<std::string> exported_header_dirs(
-    "I", llvm::cl::desc("<export_include_dirs>"), llvm::cl::ZeroOrMore,
-    llvm::cl::cat(header_linker_category));
+    "I", llvm::cl::desc("<export_include_dirs>"), llvm::cl::Prefix,
+    llvm::cl::ZeroOrMore, llvm::cl::cat(header_linker_category));
 
 static llvm::cl::opt<std::string> version_script(
     "v", llvm::cl::desc("<version_script>"), llvm::cl::Optional,
@@ -109,22 +109,23 @@
   std::set<std::string> function_decl_set_;
   std::set<std::string> enum_decl_set_;
   std::set<std::string> globvar_decl_set_;
+  // Version Script regex matched link set.
+  std::set<std::string> vs_regex_matched_link_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 (!version_script_.empty() && !ParseVersionScriptFiles()) {
+  // If a version script is available, we use that as a filter.
+  if (version_script.empty()) {
+    exported_headers_ =
+        abi_util::CollectAllExportedHeaders(exported_header_dirs_);
+  } else if (!ParseVersionScriptFiles()) {
     llvm::errs() << "Failed to parse stub files for exported symbols\n";
     return false;
   }
-  for (auto &&dir : exported_header_dirs_) {
-    if (!abi_util::CollectExportedHeaderSet(dir, &exported_headers_)) {
-      llvm::errs() << "Couldn't collect exported headers\n";
-      return false;
-    }
-  }
+
   for (auto &&i : dump_files_) {
     abi_dump::TranslationUnit dump_tu;
     std::ifstream input(i);
@@ -162,6 +163,27 @@
   return element.basic_abi().linker_set_key();
 }
 
+static bool QueryRegexMatches(std::set<std::string> *regex_matched_link_set,
+                              const std::set<std::string> &link_set,
+                              const std::string &symbol) {
+  if (regex_matched_link_set->find(symbol) != regex_matched_link_set->end()) {
+    return false;
+  }
+  // Go through each element in link_set, if there is a regex match, add the
+  // symbol to regex_matched_link_set and return true;
+  for (auto &&regex_match_str : link_set) {
+    std::smatch matcher;
+    std::string regex_match_str_find_glob =
+        abi_util::FindAndReplace(regex_match_str, "\\*", ".*");
+    std::regex match_clause("\\b" + regex_match_str_find_glob + "\\b");
+    if (std::regex_search(symbol, matcher, match_clause)) {
+      regex_matched_link_set->insert(symbol);
+      return true;
+    }
+  }
+  return false;
+}
+
 template <typename T>
 inline bool HeaderAbiLinker::LinkDecl(
     google::protobuf::RepeatedPtrField<T> *dst,
@@ -171,7 +193,8 @@
   assert(dst != nullptr);
   assert(link_set != nullptr);
   for (auto &&element : src) {
-    // If exported headers are available, filter out unexported abi.
+    // 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()) ==
         exported_headers_.end()) {
@@ -183,11 +206,16 @@
         continue;
         }
     } else {
+      std::string element_str = GetSymbol(element);
       std::set<std::string>::iterator it =
-          link_set->find(GetSymbol(element));
+          link_set->find(element_str);
       if (it == link_set->end()) {
-        continue;
+        if (!QueryRegexMatches(&vs_regex_matched_link_set_, *link_set,
+                               element_str)) {
+          continue;
+        }
       } else {
+        // We get a pre-filled link name set while using version script.
         link_set->erase(*it); // Avoid multiple instances of the same symbol.
       }
     }
@@ -204,10 +232,8 @@
 bool HeaderAbiLinker::LinkRecords(const abi_dump::TranslationUnit &dump_tu,
                                   abi_dump::TranslationUnit *linked_tu) {
   assert(linked_tu != nullptr);
-  if (!version_script_.empty()) {
-    // version scripts do not have record tags.
-    return true;
-  }
+  // 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_,
                   dump_tu.records(), false);
 }
@@ -222,10 +248,8 @@
 bool HeaderAbiLinker::LinkEnums(const abi_dump::TranslationUnit &dump_tu,
                                 abi_dump::TranslationUnit *linked_tu) {
   assert(linked_tu != nullptr);
-  if (!version_script.empty()) {
-    // version scripts do not have enum tags.
-    return true;
-  }
+  // 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_,
                   dump_tu.enums(), false);
 }
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 789e310..3db87d0 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
@@ -12,14 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <regex>
 #include <set>
 #include <string>
 #include <vector>
 
 namespace abi_util {
 
-bool CollectExportedHeaderSet(const std::string &dir_name,
-                              std::set<std::string> *exported_headers);
+std::set<std::string> CollectAllExportedHeaders(
+    const std::vector<std::string> &exported_header_dirs);
 class VersionScriptParser {
  public:
 
@@ -61,4 +62,13 @@
   int api_;
 };
 
+inline std::string FindAndReplace(const std::string &candidate_str,
+                                  const std::string &find_str,
+                                  const std::string &replace_str) {
+  // Find all matches of find_str in candidate_str and return a new string with
+  // all the matches replaced with replace_str
+  std::regex match_expr(find_str);
+  return std::regex_replace(candidate_str, match_expr, replace_str);
+}
+
 } // namespace abi_util
diff --git a/vndk/tools/header-checker/header-abi-util/src/collect_exported_headers.cpp b/vndk/tools/header-checker/header-abi-util/src/collect_exported_headers.cpp
index 13a7072..4663208 100644
--- a/vndk/tools/header-checker/header-abi-util/src/collect_exported_headers.cpp
+++ b/vndk/tools/header-checker/header-abi-util/src/collect_exported_headers.cpp
@@ -81,4 +81,16 @@
   return true;
 }
 
+std::set<std::string> CollectAllExportedHeaders(
+    const std::vector<std::string> &exported_header_dirs) {
+  std::set<std::string> exported_headers;
+  for (auto &&dir : exported_header_dirs) {
+    if (!abi_util::CollectExportedHeaderSet(dir, &exported_headers)) {
+      llvm::errs() << "Couldn't collect exported headers\n";
+      ::exit(1);
+    }
+  }
+  return exported_headers;
+}
+
 } // namespace abi_util
diff --git a/vndk/tools/header-checker/header-abi-util/src/version_script_parser.cpp b/vndk/tools/header-checker/header-abi-util/src/version_script_parser.cpp
index d651d07..9b0034e 100644
--- a/vndk/tools/header-checker/header-abi-util/src/version_script_parser.cpp
+++ b/vndk/tools/header-checker/header-abi-util/src/version_script_parser.cpp
@@ -88,10 +88,9 @@
     LineSatisfiesArch(line, arch)) {
     matched_api = std::stoi(matcher2.str(1));
   }
-  if ( matched_api > 0 && api >= matched_api) {
-    return true;
-  }
-  return false;
+  // If the arch specific tag / version specific tag was found and the api level
+  // required was greater than the api level offered.
+  return (matched_api <=0 || api >= matched_api);
 }
 
 bool VersionScriptParser::SymbolExported(const std::string &line,
diff --git a/vndk/tools/header-checker/proto/abi_diff.proto b/vndk/tools/header-checker/proto/abi_diff.proto
index e8b7570..ababd34 100644
--- a/vndk/tools/header-checker/proto/abi_diff.proto
+++ b/vndk/tools/header-checker/proto/abi_diff.proto
@@ -28,22 +28,22 @@
   required uint32 index = 3;
 }
 
-message AccessDiff {
-  required abi_dump.AccessSpecifier old = 1;
-  required abi_dump.AccessSpecifier new = 2;
+message BasicNamedAndTypedDeclDiff {
+  required abi_dump.BasicNamedAndTypedDecl old = 1;
+  required abi_dump.BasicNamedAndTypedDecl new = 2;
 }
 
 message RecordDeclDiff {
   repeated RecordFieldDeclDiff field_diffs = 1;
   repeated CXXBaseSpecifierDiff base_diffs = 2;
   repeated CXXVTableDiff vtable_diffs = 3;
-  required AccessDiff access_diff = 4;
+  optional BasicNamedAndTypedDeclDiff type_diff = 4;
   required string name = 5;
 }
 
 message EnumDeclDiff {
   repeated EnumFieldDeclDiff field_diffs = 1;
-  optional AccessDiff access_diff = 2;
+  optional BasicNamedAndTypedDeclDiff type_diff = 2;
   required string name = 3;
 }
 
@@ -52,13 +52,19 @@
   required abi_dump.BasicNamedAndTypedDecl new = 2;
 }
 
+message ParamDeclDiff {
+  optional abi_dump.ParamDecl old = 1;
+  optional abi_dump.ParamDecl new = 2;
+  required uint32 index = 3;
+}
+
 message FunctionDeclDiff {
   required ReturnTypeDiff return_type_diffs = 1;
+  repeated ParamDeclDiff param_diffs = 2;
 }
 
 message GlobalVarDeclDiff {
-  required abi_dump.BasicNamedAndTypedDecl old = 1;
-  required abi_dump.BasicNamedAndTypedDecl new = 2;
+  optional BasicNamedAndTypedDeclDiff type_diff = 1;
 }
 
 message TranslationUnitDiff {
diff --git a/vndk/tools/header-checker/tests/input/example1.h b/vndk/tools/header-checker/tests/input/example1.h
index 8653063..c00cf06 100644
--- a/vndk/tools/header-checker/tests/input/example1.h
+++ b/vndk/tools/header-checker/tests/input/example1.h
@@ -59,6 +59,35 @@
   }
 };
 
-const volatile int Global_Foo(int global_bar);
+// Replicated from libsysutils.
+template<typename T>
+class List
+{
+protected:
+    /*
+     * One element in the list.
+     */
+    class _Node {
+    public:
+        explicit _Node(const T& val) : mVal(val) {}
+        ~_Node() {}
+        inline T& getRef() { return mVal; }
+        inline const T& getRef() const { return mVal; }
+    private:
+        friend class List;
+        friend class _ListIterator;
+        T           mVal;
+        _Node*      mpPrev;
+        _Node*      mpNext;
+    };
+    _Node *middle;
+};
+
+typedef List<float> float_list;
+float_list float_list_test;
+
+
+typedef List<int> int_list;
+int_list int_list_test;
 
 #endif  // EXAMPLE1_H_