[clang] 9939556 - [APINotes] Initial support for C++ namespaces

Egor Zhdan via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 30 05:02:44 PDT 2023


Author: Egor Zhdan
Date: 2023-08-30T12:54:42+01:00
New Revision: 9939556625548d7ba2c3eba4d131b9b4d6bc0c02

URL: https://github.com/llvm/llvm-project/commit/9939556625548d7ba2c3eba4d131b9b4d6bc0c02
DIFF: https://github.com/llvm/llvm-project/commit/9939556625548d7ba2c3eba4d131b9b4d6bc0c02.diff

LOG: [APINotes] Initial support for C++ namespaces

This upstreams a part of the C++ namespaces support in Clang API Notes.

The complete patch was recently merged downstream in the Apple fork: https://github.com/apple/llvm-project/pull/7230.

This patch only adds the parts of the namespace support that can be cleanly applied on top of the API Notes infrastructure that was upstreamed previously.

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

Added: 
    

Modified: 
    clang/include/clang/APINotes/Types.h
    clang/lib/APINotes/APINotesFormat.h
    clang/lib/APINotes/APINotesWriter.cpp
    clang/lib/APINotes/APINotesYAMLCompiler.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index 61f3592ea145b8..817d6ac1bb3fe8 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -727,6 +727,28 @@ inline bool operator==(const TypedefInfo &LHS, const TypedefInfo &RHS) {
 inline bool operator!=(const TypedefInfo &LHS, const TypedefInfo &RHS) {
   return !(LHS == RHS);
 }
+
+/// Opaque context ID used to refer to an Objective-C class or protocol or a C++
+/// namespace.
+class ContextID {
+public:
+  unsigned Value;
+
+  explicit ContextID(unsigned value) : Value(value) {}
+};
+
+enum class ContextKind : uint8_t {
+  ObjCClass = 0,
+  ObjCProtocol = 1,
+  Namespace = 2,
+};
+
+struct Context {
+  ContextID id;
+  ContextKind kind;
+
+  Context(ContextID id, ContextKind kind) : id(id), kind(kind) {}
+};
 } // namespace api_notes
 } // namespace clang
 

diff  --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h
index e18ba2ab337699..1e960773074e26 100644
--- a/clang/lib/APINotes/APINotesFormat.h
+++ b/clang/lib/APINotes/APINotesFormat.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_LIB_APINOTES_APINOTESFORMAT_H
 #define LLVM_CLANG_LIB_APINOTES_APINOTESFORMAT_H
 
+#include "clang/APINotes/Types.h"
 #include "llvm/ADT/PointerEmbeddedInt.h"
 #include "llvm/Bitcode/BitcodeConvenience.h"
 
@@ -249,6 +250,38 @@ struct StoredObjCSelector {
   unsigned NumPieces;
   llvm::SmallVector<IdentifierID, 2> Identifiers;
 };
+
+/// A stored Objective-C or C++ context, represented by the ID of its parent
+/// context, the kind of this context (Objective-C class / C++ namespace / etc),
+/// and the ID of this context.
+struct ContextTableKey {
+  uint32_t parentContextID;
+  uint8_t contextKind;
+  uint32_t contextID;
+
+  ContextTableKey() : parentContextID(-1), contextKind(-1), contextID(-1) {}
+
+  ContextTableKey(uint32_t parentContextID, uint8_t contextKind,
+                  uint32_t contextID)
+      : parentContextID(parentContextID), contextKind(contextKind),
+        contextID(contextID) {}
+
+  ContextTableKey(std::optional<Context> context, IdentifierID nameID)
+      : parentContextID(context ? context->id.Value : (uint32_t)-1),
+        contextKind(context ? (uint8_t)context->kind : (uint8_t)-1),
+        contextID(nameID) {}
+
+  llvm::hash_code hashValue() const {
+    return llvm::hash_value(
+        std::tuple{parentContextID, contextKind, contextID});
+  }
+};
+
+inline bool operator==(const ContextTableKey &lhs, const ContextTableKey &rhs) {
+  return lhs.parentContextID == rhs.parentContextID &&
+         lhs.contextKind == rhs.contextKind && lhs.contextID == rhs.contextID;
+}
+
 } // namespace api_notes
 } // namespace clang
 
@@ -282,6 +315,28 @@ template <> struct DenseMapInfo<clang::api_notes::StoredObjCSelector> {
     return LHS.NumPieces == RHS.NumPieces && LHS.Identifiers == RHS.Identifiers;
   }
 };
+
+template <> struct DenseMapInfo<clang::api_notes::ContextTableKey> {
+  static inline clang::api_notes::ContextTableKey getEmptyKey() {
+    return clang::api_notes::ContextTableKey();
+  }
+
+  static inline clang::api_notes::ContextTableKey getTombstoneKey() {
+    return clang::api_notes::ContextTableKey{
+        DenseMapInfo<uint32_t>::getTombstoneKey(),
+        DenseMapInfo<uint8_t>::getTombstoneKey(),
+        DenseMapInfo<uint32_t>::getTombstoneKey()};
+  }
+
+  static unsigned getHashValue(const clang::api_notes::ContextTableKey &value) {
+    return value.hashValue();
+  }
+
+  static bool isEqual(const clang::api_notes::ContextTableKey &lhs,
+                      const clang::api_notes::ContextTableKey &rhs) {
+    return lhs == rhs;
+  }
+};
 } // namespace llvm
 
 #endif

diff  --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp
index 3f2454c47df3b9..f357af90f949c8 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -33,15 +33,21 @@ class APINotesWriter::Implementation {
   /// Mapping from strings to identifier IDs.
   llvm::StringMap<IdentifierID> IdentifierIDs;
 
-  /// Information about Objective-C contexts (classes or protocols).
+  /// Information about contexts (Objective-C classes or protocols or C++
+  /// namespaces).
   ///
-  /// Indexed by the identifier ID and a bit indication whether we're looking
-  /// for a class (0) or protocol (1) and provides both the context ID and
-  /// information describing the context within that module.
-  llvm::DenseMap<std::pair<unsigned, char>,
+  /// Indexed by the parent context ID, context kind and the identifier ID of
+  /// this context and provides both the context ID and information describing
+  /// the context within that module.
+  llvm::DenseMap<ContextTableKey,
                  std::pair<unsigned, VersionedSmallVector<ObjCContextInfo>>>
       ObjCContexts;
 
+  /// Information about parent contexts for each context.
+  ///
+  /// Indexed by context ID, provides the parent context ID.
+  llvm::DenseMap<uint32_t, uint32_t> ParentContexts;
+
   /// Information about Objective-C properties.
   ///
   /// Indexed by the context ID, property name, and whether this is an
@@ -64,16 +70,18 @@ class APINotesWriter::Implementation {
 
   /// Information about global variables.
   ///
-  /// Indexed by the identifier ID.
-  llvm::DenseMap<unsigned, llvm::SmallVector<
-                               std::pair<VersionTuple, GlobalVariableInfo>, 1>>
+  /// Indexed by the context ID, contextKind, identifier ID.
+  llvm::DenseMap<
+      ContextTableKey,
+      llvm::SmallVector<std::pair<VersionTuple, GlobalVariableInfo>, 1>>
       GlobalVariables;
 
   /// Information about global functions.
   ///
-  /// Indexed by the identifier ID.
-  llvm::DenseMap<unsigned, llvm::SmallVector<
-                               std::pair<VersionTuple, GlobalFunctionInfo>, 1>>
+  /// Indexed by the context ID, contextKind, identifier ID.
+  llvm::DenseMap<
+      ContextTableKey,
+      llvm::SmallVector<std::pair<VersionTuple, GlobalFunctionInfo>, 1>>
       GlobalFunctions;
 
   /// Information about enumerators.
@@ -85,15 +93,15 @@ class APINotesWriter::Implementation {
 
   /// Information about tags.
   ///
-  /// Indexed by the identifier ID.
-  llvm::DenseMap<unsigned,
+  /// Indexed by the context ID, contextKind, identifier ID.
+  llvm::DenseMap<ContextTableKey,
                  llvm::SmallVector<std::pair<VersionTuple, TagInfo>, 1>>
       Tags;
 
   /// Information about typedefs.
   ///
-  /// Indexed by the identifier ID.
-  llvm::DenseMap<unsigned,
+  /// Indexed by the context ID, contextKind, identifier ID.
+  llvm::DenseMap<ContextTableKey,
                  llvm::SmallVector<std::pair<VersionTuple, TypedefInfo>, 1>>
       Typedefs;
 
@@ -292,7 +300,7 @@ namespace {
 /// Used to serialize the on-disk Objective-C context table.
 class ObjCContextIDTableInfo {
 public:
-  using key_type = std::pair<unsigned, char>; // identifier ID, is-protocol
+  using key_type = ContextTableKey;
   using key_type_ref = key_type;
   using data_type = unsigned;
   using data_type_ref = const data_type &;
@@ -300,12 +308,12 @@ class ObjCContextIDTableInfo {
   using offset_type = unsigned;
 
   hash_value_type ComputeHash(key_type_ref Key) {
-    return static_cast<size_t>(llvm::hash_value(Key));
+    return static_cast<size_t>(Key.hashValue());
   }
 
   std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &OS, key_type_ref,
                                                   data_type_ref) {
-    uint32_t KeyLength = sizeof(uint32_t) + 1;
+    uint32_t KeyLength = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
     uint32_t DataLength = sizeof(uint32_t);
 
     llvm::support::endian::Writer writer(OS, llvm::support::little);
@@ -316,8 +324,9 @@ class ObjCContextIDTableInfo {
 
   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
     llvm::support::endian::Writer writer(OS, llvm::support::little);
-    writer.write<uint32_t>(Key.first);
-    writer.write<uint8_t>(Key.second);
+    writer.write<uint32_t>(Key.parentContextID);
+    writer.write<uint8_t>(Key.contextKind);
+    writer.write<uint32_t>(Key.contextID);
   }
 
   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
@@ -519,6 +528,10 @@ class ObjCContextInfoTableInfo
     writer.write<uint32_t>(Key);
   }
 
+  hash_value_type ComputeHash(key_type_ref Key) {
+    return static_cast<size_t>(llvm::hash_value(Key));
+  }
+
   unsigned getUnversionedInfoSize(const ObjCContextInfo &OCI) {
     return getCommonTypeInfoSize(OCI) + 1;
   }
@@ -631,6 +644,10 @@ class ObjCPropertyTableInfo
     writer.write<uint8_t>(std::get<2>(Key));
   }
 
+  hash_value_type ComputeHash(key_type_ref Key) {
+    return static_cast<size_t>(llvm::hash_value(Key));
+  }
+
   unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {
     return getVariableInfoSize(OPI) + 1;
   }
@@ -696,6 +713,10 @@ class ObjCMethodTableInfo
     writer.write<uint8_t>(std::get<2>(Key));
   }
 
+  hash_value_type ComputeHash(key_type_ref key) {
+    return static_cast<size_t>(llvm::hash_value(key));
+  }
+
   unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {
     return getFunctionInfoSize(OMI) + 1;
   }
@@ -810,14 +831,22 @@ void APINotesWriter::Implementation::writeObjCSelectorBlock(
 namespace {
 /// Used to serialize the on-disk global variable table.
 class GlobalVariableTableInfo
-    : public VersionedTableInfo<GlobalVariableTableInfo, unsigned,
+    : public VersionedTableInfo<GlobalVariableTableInfo, ContextTableKey,
                                 GlobalVariableInfo> {
 public:
-  unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
+  unsigned getKeyLength(key_type_ref) {
+    return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
+  }
 
   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
     llvm::support::endian::Writer writer(OS, llvm::support::little);
-    writer.write<uint32_t>(Key);
+    writer.write<uint32_t>(Key.parentContextID);
+    writer.write<uint8_t>(Key.contextKind);
+    writer.write<uint32_t>(Key.contextID);
+  }
+
+  hash_value_type ComputeHash(key_type_ref Key) {
+    return static_cast<size_t>(Key.hashValue());
   }
 
   unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) {
@@ -916,14 +945,22 @@ void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {
 
 /// Used to serialize the on-disk global function table.
 class GlobalFunctionTableInfo
-    : public VersionedTableInfo<GlobalFunctionTableInfo, unsigned,
+    : public VersionedTableInfo<GlobalFunctionTableInfo, ContextTableKey,
                                 GlobalFunctionInfo> {
 public:
-  unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
+  unsigned getKeyLength(key_type_ref) {
+    return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
+  }
 
   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
     llvm::support::endian::Writer writer(OS, llvm::support::little);
-    writer.write<uint32_t>(Key);
+    writer.write<uint32_t>(Key.parentContextID);
+    writer.write<uint8_t>(Key.contextKind);
+    writer.write<uint32_t>(Key.contextID);
+  }
+
+  hash_value_type ComputeHash(key_type_ref Key) {
+    return static_cast<size_t>(Key.hashValue());
   }
 
   unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) {
@@ -976,6 +1013,10 @@ class EnumConstantTableInfo
     writer.write<uint32_t>(Key);
   }
 
+  hash_value_type ComputeHash(key_type_ref Key) {
+    return static_cast<size_t>(llvm::hash_value(Key));
+  }
+
   unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {
     return getCommonEntityInfoSize(ECI);
   }
@@ -1016,15 +1057,24 @@ void APINotesWriter::Implementation::writeEnumConstantBlock(
 namespace {
 template <typename Derived, typename UnversionedDataType>
 class CommonTypeTableInfo
-    : public VersionedTableInfo<Derived, unsigned, UnversionedDataType> {
+    : public VersionedTableInfo<Derived, ContextTableKey, UnversionedDataType> {
 public:
   using key_type_ref = typename CommonTypeTableInfo::key_type_ref;
+  using hash_value_type = typename CommonTypeTableInfo::hash_value_type;
 
-  unsigned getKeyLength(key_type_ref) { return sizeof(IdentifierID); }
+  unsigned getKeyLength(key_type_ref) {
+    return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(IdentifierID);
+  }
 
   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
     llvm::support::endian::Writer writer(OS, llvm::support::little);
-    writer.write<IdentifierID>(Key);
+    writer.write<uint32_t>(Key.parentContextID);
+    writer.write<uint8_t>(Key.contextKind);
+    writer.write<IdentifierID>(Key.contextID);
+  }
+
+  hash_value_type ComputeHash(key_type_ref Key) {
+    return static_cast<size_t>(Key.hashValue());
   }
 
   unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) {

diff  --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index ff94f61940bfb8..7cfdefc2e3de82 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -495,6 +495,9 @@ template <> struct MappingTraits<Typedef> {
 } // namespace llvm
 
 namespace {
+struct Namespace;
+typedef std::vector<Namespace> NamespacesSeq;
+
 struct TopLevelItems {
   ClassesSeq Classes;
   ClassesSeq Protocols;
@@ -503,6 +506,7 @@ struct TopLevelItems {
   EnumConstantsSeq EnumConstants;
   TagsSeq Tags;
   TypedefsSeq Typedefs;
+  NamespacesSeq Namespaces;
 };
 } // namespace
 
@@ -516,10 +520,39 @@ static void mapTopLevelItems(IO &IO, TopLevelItems &TLI) {
   IO.mapOptional("Enumerators", TLI.EnumConstants);
   IO.mapOptional("Tags", TLI.Tags);
   IO.mapOptional("Typedefs", TLI.Typedefs);
+  IO.mapOptional("Namespaces", TLI.Namespaces);
 }
 } // namespace yaml
 } // namespace llvm
 
+namespace {
+struct Namespace {
+  StringRef Name;
+  AvailabilityItem Availability;
+  StringRef SwiftName;
+  std::optional<bool> SwiftPrivate;
+  TopLevelItems Items;
+};
+} // namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Namespace)
+
+namespace llvm {
+namespace yaml {
+template <> struct MappingTraits<Namespace> {
+  static void mapping(IO &IO, Namespace &T) {
+    IO.mapRequired("Name", T.Name);
+    IO.mapOptional("Availability", T.Availability.Mode,
+                   APIAvailability::Available);
+    IO.mapOptional("AvailabilityMsg", T.Availability.Msg, StringRef(""));
+    IO.mapOptional("SwiftPrivate", T.SwiftPrivate);
+    IO.mapOptional("SwiftName", T.SwiftName, StringRef(""));
+    mapTopLevelItems(IO, T.Items);
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
 namespace {
 struct Versioned {
   VersionTuple Version;


        


More information about the cfe-commits mailing list