[llvm] 0882c70 - [TextAPI] Introduce SymbolSet

Cyndy Ishida via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 24 12:02:28 PDT 2023


Author: Cyndy Ishida
Date: 2023-07-24T12:01:25-07:00
New Revision: 0882c70df222a89c15f2776b85a60696e6ecd712

URL: https://github.com/llvm/llvm-project/commit/0882c70df222a89c15f2776b85a60696e6ecd712
DIFF: https://github.com/llvm/llvm-project/commit/0882c70df222a89c15f2776b85a60696e6ecd712.diff

LOG: [TextAPI] Introduce SymbolSet

SymbolSet is a structure that acts as a simple container class for exported symbols that
belong to a library interface. It allows tapi to decouple the globals
from the other library attributes. It's uniqued by symbol name and `kind`, which all contain their assigned target triples.

Reviewed By: zixuw

Differential Revision: https://reviews.llvm.org/D149860

Added: 
    llvm/include/llvm/TextAPI/SymbolSet.h
    llvm/lib/TextAPI/SymbolSet.cpp

Modified: 
    llvm/include/llvm/TextAPI/InterfaceFile.h
    llvm/include/llvm/TextAPI/Symbol.h
    llvm/lib/TextAPI/CMakeLists.txt
    llvm/lib/TextAPI/InterfaceFile.cpp
    llvm/lib/TextAPI/Symbol.cpp
    llvm/unittests/TextAPI/TextStubV5Tests.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/TextAPI/InterfaceFile.h b/llvm/include/llvm/TextAPI/InterfaceFile.h
index 7d20c6f6348607..7b0cd6109a2f15 100644
--- a/llvm/include/llvm/TextAPI/InterfaceFile.h
+++ b/llvm/include/llvm/TextAPI/InterfaceFile.h
@@ -24,6 +24,7 @@
 #include "llvm/TextAPI/PackedVersion.h"
 #include "llvm/TextAPI/Platform.h"
 #include "llvm/TextAPI/Symbol.h"
+#include "llvm/TextAPI/SymbolSet.h"
 #include "llvm/TextAPI/Target.h"
 
 namespace llvm {
@@ -123,37 +124,15 @@ class InterfaceFileRef {
 
 } // end namespace MachO.
 
-struct SymbolsMapKey {
-  MachO::SymbolKind Kind;
-  StringRef Name;
-
-  SymbolsMapKey(MachO::SymbolKind Kind, StringRef Name)
-      : Kind(Kind), Name(Name) {}
-};
-template <> struct DenseMapInfo<SymbolsMapKey> {
-  static inline SymbolsMapKey getEmptyKey() {
-    return SymbolsMapKey(MachO::SymbolKind::GlobalSymbol, StringRef{});
-  }
-
-  static inline SymbolsMapKey getTombstoneKey() {
-    return SymbolsMapKey(MachO::SymbolKind::ObjectiveCInstanceVariable,
-                         StringRef{});
-  }
-
-  static unsigned getHashValue(const SymbolsMapKey &Key) {
-    return hash_combine(hash_value(Key.Kind), hash_value(Key.Name));
-  }
-
-  static bool isEqual(const SymbolsMapKey &LHS, const SymbolsMapKey &RHS) {
-    return std::tie(LHS.Kind, LHS.Name) == std::tie(RHS.Kind, RHS.Name);
-  }
-};
-
 namespace MachO {
 
 /// Defines the interface file.
 class InterfaceFile {
 public:
+  InterfaceFile(std::unique_ptr<SymbolSet> &&InputSymbols)
+      : SymbolsSet(std::move(InputSymbols)) {}
+
+  InterfaceFile() : SymbolsSet(std::make_unique<SymbolSet>()){};
   /// Set the path from which this file was generated (if applicable).
   ///
   /// \param Path_ The path to the source file.
@@ -360,66 +339,63 @@ class InterfaceFile {
     return RPaths;
   }
 
-  /// Add a symbol to the symbols list or extend an existing one.
-  void addSymbol(SymbolKind Kind, StringRef Name, const TargetList &Targets,
-                 SymbolFlags Flags = SymbolFlags::None);
-
-  using SymbolMapType = DenseMap<SymbolsMapKey, Symbol *>;
-  struct const_symbol_iterator
-      : public iterator_adaptor_base<
-            const_symbol_iterator, SymbolMapType::const_iterator,
-            std::forward_iterator_tag, const Symbol *, ptr
diff _t,
-            const Symbol *, const Symbol *> {
-    const_symbol_iterator() = default;
-
-    template <typename U>
-    const_symbol_iterator(U &&u)
-        : iterator_adaptor_base(std::forward<U &&>(u)) {}
-
-    reference operator*() const { return I->second; }
-    pointer operator->() const { return I->second; }
-  };
+  /// Get symbol if exists in file.
+  ///
+  /// \param Kind The kind of global symbol to record.
+  /// \param Name The name of the symbol.
+  std::optional<const Symbol *> getSymbol(SymbolKind Kind,
+                                          StringRef Name) const {
+    if (auto *Sym = SymbolsSet->findSymbol(Kind, Name))
+      return Sym;
+    return std::nullopt;
+  }
 
-  using const_symbol_range = iterator_range<const_symbol_iterator>;
+  /// Add a symbol to the symbols list or extend an existing one.
+  template <typename RangeT,
+            typename ElT = typename std::remove_reference<
+                decltype(*std::begin(std::declval<RangeT>()))>::type>
+  void addSymbol(SymbolKind Kind, StringRef Name, RangeT &&Targets,
+                 SymbolFlags Flags = SymbolFlags::None) {
+    SymbolsSet->addGlobal(Kind, Name, Flags, Targets);
+  }
 
-  using const_filtered_symbol_iterator =
-      filter_iterator<const_symbol_iterator,
-                      std::function<bool(const Symbol *)>>;
-  using const_filtered_symbol_range =
-      iterator_range<const_filtered_symbol_iterator>;
+  /// Add Symbol with multiple targets.
+  ///
+  /// \param Kind The kind of global symbol to record.
+  /// \param Name The name of the symbol.
+  /// \param Targets The list of targets the symbol is defined in.
+  /// \param Flags The properties the symbol holds.
+  void addSymbol(SymbolKind Kind, StringRef Name, TargetList &&Targets,
+                 SymbolFlags Flags = SymbolFlags::None) {
+    SymbolsSet->addGlobal(Kind, Name, Flags, Targets);
+  }
 
-  const_symbol_range symbols() const {
-    return {Symbols.begin(), Symbols.end()};
+  /// Add Symbol with single target.
+  ///
+  /// \param Kind The kind of global symbol to record.
+  /// \param Name The name of the symbol.
+  /// \param Target The target the symbol is defined in.
+  /// \param Flags The properties the symbol holds.
+  void addSymbol(SymbolKind Kind, StringRef Name, Target &Target,
+                 SymbolFlags Flags = SymbolFlags::None) {
+    SymbolsSet->addGlobal(Kind, Name, Flags, Target);
   }
 
-  size_t symbolsCount() const { return Symbols.size(); }
+  /// Get size of symbol set.
+  /// \return The number of symbols the file holds.
+  size_t symbolsCount() const { return SymbolsSet->size(); }
 
-  const_filtered_symbol_range exports() const {
-    std::function<bool(const Symbol *)> fn = [](const Symbol *Symbol) {
-      return !Symbol->isUndefined() && !Symbol->isReexported();
-    };
-    return make_filter_range(
-        make_range<const_symbol_iterator>({Symbols.begin()}, {Symbols.end()}),
-        fn);
-  }
+  using const_symbol_range = SymbolSet::const_symbol_range;
+  using const_filtered_symbol_range = SymbolSet::const_filtered_symbol_range;
 
+  const_symbol_range symbols() const { return SymbolsSet->symbols(); };
+  const_filtered_symbol_range exports() const { return SymbolsSet->exports(); };
   const_filtered_symbol_range reexports() const {
-    std::function<bool(const Symbol *)> fn = [](const Symbol *Symbol) {
-      return Symbol->isReexported();
-    };
-    return make_filter_range(
-        make_range<const_symbol_iterator>({Symbols.begin()}, {Symbols.end()}),
-        fn);
-  }
-
+    return SymbolsSet->reexports();
+  };
   const_filtered_symbol_range undefineds() const {
-    std::function<bool(const Symbol *)> fn = [](const Symbol *Symbol) {
-      return Symbol->isUndefined();
-    };
-    return make_filter_range(
-        make_range<const_symbol_iterator>({Symbols.begin()}, {Symbols.end()}),
-        fn);
-  }
+    return SymbolsSet->undefineds();
+  };
 
   /// The equality is determined by attributes that impact linking
   /// compatibilities. UUIDs, Path, & FileKind are irrelevant since these by
@@ -457,23 +433,20 @@ class InterfaceFile {
   std::vector<std::shared_ptr<InterfaceFile>> Documents;
   std::vector<std::pair<Target, std::string>> UUIDs;
   std::vector<std::pair<Target, std::string>> RPaths;
-  SymbolMapType Symbols;
+  std::unique_ptr<SymbolSet> SymbolsSet;
   InterfaceFile *Parent = nullptr;
 };
 
-template <typename DerivedT, typename KeyInfoT, typename BucketT>
-bool operator==(const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
-                                   KeyInfoT, BucketT> &LHS,
-                const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
-                                   KeyInfoT, BucketT> &RHS) {
-  if (LHS.size() != RHS.size())
-    return false;
-  for (const auto &KV : LHS) {
-    auto I = RHS.find(KV.first);
-    if (I == RHS.end() || *I->second != *KV.second)
-      return false;
-  }
-  return true;
+// Keep containers that hold InterfaceFileRefs in sorted order and uniqued.
+template <typename C>
+typename C::iterator addEntry(C &Container, StringRef InstallName) {
+  auto I = partition_point(Container, [=](const InterfaceFileRef &O) {
+    return O.getInstallName() < InstallName;
+  });
+  if (I != Container.end() && I->getInstallName() == InstallName)
+    return I;
+
+  return Container.emplace(I, InstallName);
 }
 
 } // end namespace MachO.

diff  --git a/llvm/include/llvm/TextAPI/Symbol.h b/llvm/include/llvm/TextAPI/Symbol.h
index 48627c3d893a28..a20fcc785b4097 100644
--- a/llvm/include/llvm/TextAPI/Symbol.h
+++ b/llvm/include/llvm/TextAPI/Symbol.h
@@ -65,12 +65,26 @@ constexpr StringLiteral ObjC2EHTypePrefix = "_OBJC_EHTYPE_$_";
 constexpr StringLiteral ObjC2IVarPrefix = "_OBJC_IVAR_$_";
 
 using TargetList = SmallVector<Target, 5>;
+
+// Keep containers that hold Targets in sorted order and uniqued.
+template <typename C>
+typename C::iterator addEntry(C &Container, const Target &Targ) {
+  auto Iter =
+      lower_bound(Container, Targ, [](const Target &LHS, const Target &RHS) {
+        return LHS < RHS;
+      });
+  if ((Iter != std::end(Container)) && !(Targ < *Iter))
+    return Iter;
+
+  return Container.insert(Iter, Targ);
+}
+
 class Symbol {
 public:
   Symbol(SymbolKind Kind, StringRef Name, TargetList Targets, SymbolFlags Flags)
       : Name(Name), Targets(std::move(Targets)), Kind(Kind), Flags(Flags) {}
 
-  void addTarget(Target target) { Targets.emplace_back(target); }
+  void addTarget(Target InputTarget) { addEntry(Targets, InputTarget); }
   SymbolKind getKind() const { return Kind; }
   StringRef getName() const { return Name; }
   ArchitectureSet getArchitectures() const {

diff  --git a/llvm/include/llvm/TextAPI/SymbolSet.h b/llvm/include/llvm/TextAPI/SymbolSet.h
new file mode 100644
index 00000000000000..238385178d605d
--- /dev/null
+++ b/llvm/include/llvm/TextAPI/SymbolSet.h
@@ -0,0 +1,182 @@
+//===- llvm/TextAPI/SymbolSet.h - TAPI Symbol Set --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TEXTAPI_SYMBOLSET_H
+#define LLVM_TEXTAPI_SYMBOLSET_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/TextAPI/Architecture.h"
+#include "llvm/TextAPI/ArchitectureSet.h"
+#include "llvm/TextAPI/Symbol.h"
+#include <stddef.h>
+
+namespace llvm {
+
+struct SymbolsMapKey {
+  MachO::SymbolKind Kind;
+  StringRef Name;
+
+  SymbolsMapKey(MachO::SymbolKind Kind, StringRef Name)
+      : Kind(Kind), Name(Name) {}
+};
+template <> struct DenseMapInfo<SymbolsMapKey> {
+  static inline SymbolsMapKey getEmptyKey() {
+    return SymbolsMapKey(MachO::SymbolKind::GlobalSymbol, StringRef{});
+  }
+
+  static inline SymbolsMapKey getTombstoneKey() {
+    return SymbolsMapKey(MachO::SymbolKind::ObjectiveCInstanceVariable,
+                         StringRef{});
+  }
+
+  static unsigned getHashValue(const SymbolsMapKey &Key) {
+    return hash_combine(hash_value(Key.Kind), hash_value(Key.Name));
+  }
+
+  static bool isEqual(const SymbolsMapKey &LHS, const SymbolsMapKey &RHS) {
+    return std::tie(LHS.Kind, LHS.Name) == std::tie(RHS.Kind, RHS.Name);
+  }
+};
+
+template <typename DerivedT, typename KeyInfoT, typename BucketT>
+bool operator==(const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
+                                   KeyInfoT, BucketT> &LHS,
+                const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
+                                   KeyInfoT, BucketT> &RHS) {
+  if (LHS.size() != RHS.size())
+    return false;
+  for (const auto &KV : LHS) {
+    auto I = RHS.find(KV.first);
+    if (I == RHS.end() || *I->second != *KV.second)
+      return false;
+  }
+  return true;
+}
+
+template <typename DerivedT, typename KeyInfoT, typename BucketT>
+bool operator!=(const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
+                                   KeyInfoT, BucketT> &LHS,
+                const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
+                                   KeyInfoT, BucketT> &RHS) {
+  return !(LHS == RHS);
+}
+
+namespace MachO {
+
+class SymbolSet {
+private:
+  llvm::BumpPtrAllocator Allocator;
+  StringRef copyString(StringRef String) {
+    if (String.empty())
+      return {};
+    void *Ptr = Allocator.Allocate(String.size(), 1);
+    memcpy(Ptr, String.data(), String.size());
+    return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
+  }
+
+  using SymbolsMapType = llvm::DenseMap<SymbolsMapKey, Symbol *>;
+  SymbolsMapType Symbols;
+
+  Symbol *addGlobalImpl(SymbolKind, StringRef Name, SymbolFlags Flags);
+
+public:
+  SymbolSet() = default;
+  Symbol *addGlobal(SymbolKind Kind, StringRef Name, SymbolFlags Flags,
+                    const Target &Targ);
+  size_t size() const { return Symbols.size(); }
+
+  template <typename RangeT,
+            typename ElT = typename std::remove_reference<
+                decltype(*std::begin(std::declval<RangeT>()))>::type>
+  Symbol *addGlobal(SymbolKind Kind, StringRef Name, SymbolFlags Flags,
+                    RangeT &&Targets) {
+    auto *Global = addGlobalImpl(Kind, Name, Flags);
+    for (const auto &Targ : Targets)
+      Global->addTarget(Targ);
+    if (Kind == SymbolKind::ObjectiveCClassEHType)
+      addGlobal(SymbolKind::ObjectiveCClass, Name, Flags, Targets);
+    return Global;
+  }
+
+  const Symbol *findSymbol(SymbolKind Kind, StringRef Name) const;
+
+  struct const_symbol_iterator
+      : public iterator_adaptor_base<
+            const_symbol_iterator, SymbolsMapType::const_iterator,
+            std::forward_iterator_tag, const Symbol *, ptr
diff _t,
+            const Symbol *, const Symbol *> {
+    const_symbol_iterator() = default;
+
+    template <typename U>
+    const_symbol_iterator(U &&u)
+        : iterator_adaptor_base(std::forward<U &&>(u)) {}
+
+    reference operator*() const { return I->second; }
+    pointer operator->() const { return I->second; }
+  };
+
+  using const_symbol_range = iterator_range<const_symbol_iterator>;
+
+  using const_filtered_symbol_iterator =
+      filter_iterator<const_symbol_iterator,
+                      std::function<bool(const Symbol *)>>;
+  using const_filtered_symbol_range =
+      iterator_range<const_filtered_symbol_iterator>;
+
+  // Range that contains all symbols.
+  const_symbol_range symbols() const {
+    return {Symbols.begin(), Symbols.end()};
+  }
+
+  // Range that contains all defined and exported symbols.
+  const_filtered_symbol_range exports() const {
+    std::function<bool(const Symbol *)> fn = [](const Symbol *Symbol) {
+      return !Symbol->isUndefined() && !Symbol->isReexported();
+    };
+    return make_filter_range(
+        make_range<const_symbol_iterator>({Symbols.begin()}, {Symbols.end()}),
+        fn);
+  }
+
+  // Range that contains all reexported symbols.
+  const_filtered_symbol_range reexports() const {
+    std::function<bool(const Symbol *)> fn = [](const Symbol *Symbol) {
+      return Symbol->isReexported();
+    };
+    return make_filter_range(
+        make_range<const_symbol_iterator>({Symbols.begin()}, {Symbols.end()}),
+        fn);
+  }
+
+  // Range that contains all undefined and exported symbols.
+  const_filtered_symbol_range undefineds() const {
+    std::function<bool(const Symbol *)> fn = [](const Symbol *Symbol) {
+      return Symbol->isUndefined();
+    };
+    return make_filter_range(
+        make_range<const_symbol_iterator>({Symbols.begin()}, {Symbols.end()}),
+        fn);
+  }
+
+  bool operator==(const SymbolSet &O) const;
+
+  bool operator!=(const SymbolSet &O) const { return !(Symbols == O.Symbols); }
+
+  void *allocate(size_t Size, unsigned Align = 8) {
+    return Allocator.Allocate(Size, Align);
+  }
+};
+
+} // namespace MachO
+} // namespace llvm
+#endif // LLVM_TEXTAPI_SYMBOLSET_H

diff  --git a/llvm/lib/TextAPI/CMakeLists.txt b/llvm/lib/TextAPI/CMakeLists.txt
index 1714ce33ef205a..647a04f5da7881 100644
--- a/llvm/lib/TextAPI/CMakeLists.txt
+++ b/llvm/lib/TextAPI/CMakeLists.txt
@@ -6,6 +6,7 @@ add_llvm_component_library(LLVMTextAPI
   PackedVersion.cpp
   Platform.cpp
   Symbol.cpp
+  SymbolSet.cpp
   Target.cpp
   TextStub.cpp
   TextStubCommon.cpp

diff  --git a/llvm/lib/TextAPI/InterfaceFile.cpp b/llvm/lib/TextAPI/InterfaceFile.cpp
index 8c0b65916026e0..bb98c92f71782b 100644
--- a/llvm/lib/TextAPI/InterfaceFile.cpp
+++ b/llvm/lib/TextAPI/InterfaceFile.cpp
@@ -17,31 +17,6 @@
 using namespace llvm;
 using namespace llvm::MachO;
 
-namespace {
-template <typename C>
-typename C::iterator addEntry(C &Container, StringRef InstallName) {
-  auto I = partition_point(Container, [=](const InterfaceFileRef &O) {
-    return O.getInstallName() < InstallName;
-  });
-  if (I != Container.end() && I->getInstallName() == InstallName)
-    return I;
-
-  return Container.emplace(I, InstallName);
-}
-
-template <typename C>
-typename C::iterator addEntry(C &Container, const Target &Target_) {
-  auto Iter =
-      lower_bound(Container, Target_, [](const Target &LHS, const Target &RHS) {
-        return LHS < RHS;
-      });
-  if ((Iter != std::end(Container)) && !(Target_ < *Iter))
-    return Iter;
-
-  return Container.insert(Iter, Target_);
-}
-} // end namespace
-
 void InterfaceFileRef::addTarget(const Target &Target) {
   addEntry(Targets, Target);
 }
@@ -120,17 +95,6 @@ InterfaceFile::targets(ArchitectureSet Archs) const {
   return make_filter_range(Targets, fn);
 }
 
-void InterfaceFile::addSymbol(SymbolKind Kind, StringRef Name,
-                              const TargetList &Targets, SymbolFlags Flags) {
-  Name = copyString(Name);
-  auto result = Symbols.try_emplace(SymbolsMapKey{Kind, Name}, nullptr);
-  if (result.second)
-    result.first->second = new (Allocator) Symbol{Kind, Name, Targets, Flags};
-  else
-    for (const auto &Target : Targets)
-      result.first->second->addTarget(Target);
-}
-
 void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {
   auto Pos = llvm::lower_bound(Documents, Document,
                                [](const std::shared_ptr<InterfaceFile> &LHS,
@@ -167,7 +131,7 @@ bool InterfaceFile::operator==(const InterfaceFile &O) const {
     return false;
   if (ReexportedLibraries != O.ReexportedLibraries)
     return false;
-  if (Symbols != O.Symbols)
+  if (*SymbolsSet != *O.SymbolsSet)
     return false;
   // Don't compare run search paths for older filetypes that cannot express
   // them.

diff  --git a/llvm/lib/TextAPI/Symbol.cpp b/llvm/lib/TextAPI/Symbol.cpp
index f56493e54973d0..20fa6362716acf 100644
--- a/llvm/lib/TextAPI/Symbol.cpp
+++ b/llvm/lib/TextAPI/Symbol.cpp
@@ -65,10 +65,9 @@ bool Symbol::operator==(const Symbol &O) const {
   };
   SymbolFlags LHSFlags = Flags;
   SymbolFlags RHSFlags = O.Flags;
-  if ((!O.isData() && !O.isText()) || (!isData() && !isText())) {
-    RemoveFlag(*this, LHSFlags);
-    RemoveFlag(O, RHSFlags);
-  }
+  // Ignore Text and Data for now.
+  RemoveFlag(*this, LHSFlags);
+  RemoveFlag(O, RHSFlags);
   return std::tie(Name, Kind, Targets, LHSFlags) ==
          std::tie(O.Name, O.Kind, O.Targets, RHSFlags);
 }

diff  --git a/llvm/lib/TextAPI/SymbolSet.cpp b/llvm/lib/TextAPI/SymbolSet.cpp
new file mode 100644
index 00000000000000..157e1374972938
--- /dev/null
+++ b/llvm/lib/TextAPI/SymbolSet.cpp
@@ -0,0 +1,36 @@
+//===- lib/TextAPI/SymbolSet.cpp - TAPI Symbol Set ------------*- C++-*----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TextAPI/SymbolSet.h"
+
+using namespace llvm;
+using namespace llvm::MachO;
+
+Symbol *SymbolSet::addGlobalImpl(SymbolKind Kind, StringRef Name,
+                                 SymbolFlags Flags) {
+  Name = copyString(Name);
+  auto Result = Symbols.try_emplace(SymbolsMapKey{Kind, Name}, nullptr);
+  if (Result.second)
+    Result.first->second =
+        new (Allocator) Symbol{Kind, Name, TargetList(), Flags};
+  return Result.first->second;
+}
+
+Symbol *SymbolSet::addGlobal(SymbolKind Kind, StringRef Name, SymbolFlags Flags,
+                             const Target &Targ) {
+  auto *Sym = addGlobalImpl(Kind, Name, Flags);
+  Sym->addTarget(Targ);
+  return Sym;
+}
+
+const Symbol *SymbolSet::findSymbol(SymbolKind Kind, StringRef Name) const {
+  auto It = Symbols.find({Kind, Name});
+  if (It != Symbols.end())
+    return It->second;
+  return nullptr;
+}

diff  --git a/llvm/unittests/TextAPI/TextStubV5Tests.cpp b/llvm/unittests/TextAPI/TextStubV5Tests.cpp
index 5f8d3de991d0d6..782b32444ae33b 100644
--- a/llvm/unittests/TextAPI/TextStubV5Tests.cpp
+++ b/llvm/unittests/TextAPI/TextStubV5Tests.cpp
@@ -124,6 +124,8 @@ TEST(TBDv5, ReadFile) {
               "_globalVar"
           ],
           "objc_class": [
+              "ClassA",
+              "ClassB",
               "ClassData"
           ],
           "objc_eh_type": [
@@ -264,7 +266,18 @@ TEST(TBDv5, ReadFile) {
        false,
        true,
        {Target(AK_x86_64, PLATFORM_MACOS)}},
-      {SymbolKind::ObjectiveCClass, "ClassA", false, false, true, MacOSTargets},
+      {SymbolKind::ObjectiveCClass,
+       "ClassA",
+       false,
+       false,
+       true,
+       {Target(AK_x86_64, PLATFORM_MACOS)}},
+      {SymbolKind::ObjectiveCClass,
+       "ClassB",
+       false,
+       false,
+       true,
+       {Target(AK_x86_64, PLATFORM_MACOS)}},
       {SymbolKind::ObjectiveCClass,
        "ClassData",
        false,
@@ -333,6 +346,9 @@ TEST(TBDv5, ReadFile) {
                          std::begin(ExpectedReexportedSymbols)));
   EXPECT_TRUE(std::equal(Undefineds.begin(), Undefineds.end(),
                          std::begin(ExpectedUndefinedSymbols)));
+
+  EXPECT_TRUE(
+      File->getSymbol(SymbolKind::GlobalSymbol, "_globalBind").has_value());
 }
 
 TEST(TBDv5, ReadMultipleTargets) {
@@ -440,7 +456,7 @@ TEST(TBDv5, ReadMultipleDocuments) {
       {
         "data": {
           "thread_local": [ "_globalVar" ],
-          "objc_class": [ "ClassData" ], 
+          "objc_class": [ "ClassData", "ClassA", "ClassB"], 
           "objc_eh_type": [ "ClassA", "ClassB" ]
         },
         "text": {
@@ -495,6 +511,8 @@ TEST(TBDv5, ReadMultipleDocuments) {
   ExportedSymbolSeq ExpectedExports = {
       {SymbolKind::GlobalSymbol, "_funcFoo", false, false, false, {iOSTarget}},
       {SymbolKind::GlobalSymbol, "_globalVar", false, true, true, {iOSTarget}},
+      {SymbolKind::ObjectiveCClass, "ClassA", false, false, true, {iOSTarget}},
+      {SymbolKind::ObjectiveCClass, "ClassB", false, false, true, {iOSTarget}},
       {SymbolKind::ObjectiveCClass,
        "ClassData",
        false,
@@ -622,6 +640,8 @@ TEST(TBDv5, WriteFile) {
               "_globalVar"
           ],
           "objc_class": [
+              "ClassA",
+              "ClassB",
               "ClassData"
           ],
           "objc_eh_type": [


        


More information about the llvm-commits mailing list