[clang] [APINotes] Upstream APINotesWriter (PR #65187)
Egor Zhdan via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 4 04:10:49 PDT 2023
https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/65187:
>From e2150c20056e44a6ecbc82c63f499b6010c37930 Mon Sep 17 00:00:00 2001
From: Egor Zhdan <e_zhdan at apple.com>
Date: Fri, 1 Sep 2023 22:07:47 +0100
Subject: [PATCH] [APINotes] Upstream APINotesWriter
This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes
---
clang/include/clang/APINotes/APINotesWriter.h | 75 +++++++-
clang/include/clang/APINotes/Types.h | 11 ++
clang/lib/APINotes/APINotesFormat.h | 3 +-
clang/lib/APINotes/APINotesWriter.cpp | 174 +++++++++++++++++-
4 files changed, 253 insertions(+), 10 deletions(-)
diff --git a/clang/include/clang/APINotes/APINotesWriter.h b/clang/include/clang/APINotes/APINotesWriter.h
index eab03a2a830125..dad44623e16aeb 100644
--- a/clang/include/clang/APINotes/APINotesWriter.h
+++ b/clang/include/clang/APINotes/APINotesWriter.h
@@ -9,7 +9,9 @@
#ifndef LLVM_CLANG_APINOTES_WRITER_H
#define LLVM_CLANG_APINOTES_WRITER_H
+#include "clang/APINotes/Types.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/VersionTuple.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
@@ -30,8 +32,79 @@ class APINotesWriter {
APINotesWriter &operator=(const APINotesWriter &) = delete;
void writeToStream(llvm::raw_ostream &OS);
+
+ /// Add information about a specific Objective-C class or protocol or a C++
+ /// namespace.
+ ///
+ /// \param Name The name of this class/protocol/namespace.
+ /// \param Kind Whether this is a class, a protocol, or a namespace.
+ /// \param Info Information about this class/protocol/namespace.
+ ///
+ /// \returns the ID of the class, protocol, or namespace, which can be used to
+ /// add properties and methods to the class/protocol/namespace.
+ ContextID addObjCContext(std::optional<ContextID> ParentCtxID,
+ llvm::StringRef Name, ContextKind Kind,
+ const ObjCContextInfo &Info,
+ llvm::VersionTuple SwiftVersion);
+
+ /// Add information about a specific Objective-C property.
+ ///
+ /// \param CtxID The context in which this property resides.
+ /// \param Name The name of this property.
+ /// \param Info Information about this property.
+ void addObjCProperty(ContextID CtxID, llvm::StringRef Name,
+ bool IsInstanceProperty, const ObjCPropertyInfo &Info,
+ llvm::VersionTuple SwiftVersion);
+
+ /// Add information about a specific Objective-C method.
+ ///
+ /// \param CtxID The context in which this method resides.
+ /// \param Selector The selector that names this method.
+ /// \param IsInstanceMethod Whether this method is an instance method
+ /// (vs. a class method).
+ /// \param Info Information about this method.
+ void addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,
+ bool IsInstanceMethod, const ObjCMethodInfo &Info,
+ llvm::VersionTuple SwiftVersion);
+
+ /// Add information about a global variable.
+ ///
+ /// \param Name The name of this global variable.
+ /// \param Info Information about this global variable.
+ void addGlobalVariable(std::optional<Context> Ctx, llvm::StringRef Name,
+ const GlobalVariableInfo &Info,
+ llvm::VersionTuple SwiftVersion);
+
+ /// Add information about a global function.
+ ///
+ /// \param Name The name of this global function.
+ /// \param Info Information about this global function.
+ void addGlobalFunction(std::optional<Context> Ctx, llvm::StringRef Name,
+ const GlobalFunctionInfo &Info,
+ llvm::VersionTuple SwiftVersion);
+
+ /// Add information about an enumerator.
+ ///
+ /// \param Name The name of this enumerator.
+ /// \param Info Information about this enumerator.
+ void addEnumConstant(llvm::StringRef Name, const EnumConstantInfo &Info,
+ llvm::VersionTuple SwiftVersion);
+
+ /// Add information about a tag (struct/union/enum/C++ class).
+ ///
+ /// \param Name The name of this tag.
+ /// \param Info Information about this tag.
+ void addTag(std::optional<Context> Ctx, llvm::StringRef Name,
+ const TagInfo &Info, llvm::VersionTuple SwiftVersion);
+
+ /// Add information about a typedef.
+ ///
+ /// \param Name The name of this typedef.
+ /// \param Info Information about this typedef.
+ void addTypedef(std::optional<Context> Ctx, llvm::StringRef Name,
+ const TypedefInfo &Info, llvm::VersionTuple SwiftVersion);
};
} // namespace api_notes
} // namespace clang
-#endif
+#endif // LLVM_CLANG_APINOTES_WRITER_H
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index 817d6ac1bb3fe8..79c8079191fef3 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_APINOTES_TYPES_H
#include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include <climits>
#include <optional>
@@ -749,6 +750,16 @@ struct Context {
Context(ContextID id, ContextKind kind) : id(id), kind(kind) {}
};
+
+/// A temporary reference to an Objective-C selector, suitable for
+/// referencing selector data on the stack.
+///
+/// Instances of this struct do not store references to any of the
+/// data they contain; it is up to the user to ensure that the data
+/// referenced by the identifier list persists.
+struct ObjCSelectorRef {
+ llvm::ArrayRef<llvm::StringRef> Identifiers;
+};
} // namespace api_notes
} // namespace clang
diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h
index 1e960773074e26..b52f017901dbca 100644
--- a/clang/lib/APINotes/APINotesFormat.h
+++ b/clang/lib/APINotes/APINotesFormat.h
@@ -268,7 +268,8 @@ struct ContextTableKey {
ContextTableKey(std::optional<Context> context, IdentifierID nameID)
: parentContextID(context ? context->id.Value : (uint32_t)-1),
- contextKind(context ? (uint8_t)context->kind : (uint8_t)-1),
+ contextKind(context ? static_cast<uint8_t>(context->kind)
+ : static_cast<uint8_t>(-1)),
contextID(nameID) {}
llvm::hash_code hashValue() const {
diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp
index f357af90f949c8..726d827aabf591 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -19,11 +19,11 @@
namespace clang {
namespace api_notes {
-class APINotesWriter::Implementation {
- template <typename T>
- using VersionedSmallVector =
- llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1>;
+template <typename T>
+using VersionedSmallVector =
+ llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1>;
+class APINotesWriter::Implementation {
std::string ModuleName;
const FileEntry *SourceFile;
@@ -33,6 +33,7 @@ class APINotesWriter::Implementation {
/// Mapping from strings to identifier IDs.
llvm::StringMap<IdentifierID> IdentifierIDs;
+public:
/// Information about contexts (Objective-C classes or protocols or C++
/// namespaces).
///
@@ -48,6 +49,9 @@ class APINotesWriter::Implementation {
/// Indexed by context ID, provides the parent context ID.
llvm::DenseMap<uint32_t, uint32_t> ParentContexts;
+ /// Mapping from context IDs to the identifier ID holding the name.
+ llvm::DenseMap<unsigned, unsigned> ObjCContextNames;
+
/// Information about Objective-C properties.
///
/// Indexed by the context ID, property name, and whether this is an
@@ -105,6 +109,40 @@ class APINotesWriter::Implementation {
llvm::SmallVector<std::pair<VersionTuple, TypedefInfo>, 1>>
Typedefs;
+ /// Retrieve the ID for the given identifier.
+ IdentifierID getIdentifier(StringRef Identifier) {
+ if (Identifier.empty())
+ return 0;
+
+ auto Known = IdentifierIDs.find(Identifier);
+ if (Known != IdentifierIDs.end())
+ return Known->second;
+
+ // Add to the identifier table.
+ Known = IdentifierIDs.insert({Identifier, IdentifierIDs.size() + 1}).first;
+ return Known->second;
+ }
+
+ /// Retrieve the ID for the given selector.
+ SelectorID getSelector(ObjCSelectorRef SelectorRef) {
+ // Translate the selector reference into a stored selector.
+ StoredObjCSelector Selector;
+ Selector.Identifiers.reserve(SelectorRef.Identifiers.size());
+ for (auto piece : SelectorRef.Identifiers) {
+ Selector.Identifiers.push_back(getIdentifier(piece));
+ }
+
+ // Look for the stored selector.
+ auto Known = SelectorIDs.find(Selector);
+ if (Known != SelectorIDs.end())
+ return Known->second;
+
+ // Add to the selector table.
+ Known = SelectorIDs.insert({Selector, SelectorIDs.size()}).first;
+ return Known->second;
+ }
+
+private:
void writeBlockInfoBlock(llvm::BitstreamWriter &Stream);
void writeControlBlock(llvm::BitstreamWriter &Stream);
void writeIdentifierBlock(llvm::BitstreamWriter &Stream);
@@ -433,10 +471,6 @@ class VersionedTableInfo {
using hash_value_type = size_t;
using offset_type = unsigned;
- hash_value_type ComputeHash(key_type_ref Key) {
- return llvm::hash_value(Key);
- }
-
std::pair<unsigned, unsigned>
EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref Data) {
uint32_t KeyLength = asDerived().getKeyLength(Key);
@@ -1200,5 +1234,129 @@ APINotesWriter::~APINotesWriter() = default;
void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {
Implementation->writeToStream(OS);
}
+
+ContextID APINotesWriter::addObjCContext(std::optional<ContextID> ParentCtxID,
+ StringRef Name, ContextKind Kind,
+ const ObjCContextInfo &Info,
+ VersionTuple SwiftVersion) {
+ IdentifierID NameID = Implementation->getIdentifier(Name);
+
+ uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;
+ ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);
+ auto Known = Implementation->ObjCContexts.find(Key);
+ if (Known == Implementation->ObjCContexts.end()) {
+ unsigned NextID = Implementation->ObjCContexts.size() + 1;
+
+ VersionedSmallVector<ObjCContextInfo> EmptyVersionedInfo;
+ Known = Implementation->ObjCContexts
+ .insert(std::make_pair(
+ Key, std::make_pair(NextID, EmptyVersionedInfo)))
+ .first;
+
+ Implementation->ObjCContextNames[NextID] = NameID;
+ Implementation->ParentContexts[NextID] = RawParentCtxID;
+ }
+
+ // Add this version information.
+ auto &VersionedVec = Known->second.second;
+ bool Found = false;
+ for (auto &Versioned : VersionedVec) {
+ if (Versioned.first == SwiftVersion) {
+ Versioned.second |= Info;
+ Found = true;
+ break;
+ }
+ }
+
+ if (!Found)
+ VersionedVec.push_back({SwiftVersion, Info});
+
+ return ContextID(Known->second.first);
+}
+
+void APINotesWriter::addObjCProperty(ContextID CtxID, StringRef Name,
+ bool IsInstanceProperty,
+ const ObjCPropertyInfo &Info,
+ VersionTuple SwiftVersion) {
+ IdentifierID NameID = Implementation->getIdentifier(Name);
+ Implementation
+ ->ObjCProperties[std::make_tuple(CtxID.Value, NameID, IsInstanceProperty)]
+ .push_back({SwiftVersion, Info});
+}
+
+void APINotesWriter::addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,
+ bool IsInstanceMethod,
+ const ObjCMethodInfo &Info,
+ VersionTuple SwiftVersion) {
+ SelectorID SelID = Implementation->getSelector(Selector);
+ auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,
+ IsInstanceMethod};
+ Implementation->ObjCMethods[Key].push_back({SwiftVersion, Info});
+
+ // If this method is a designated initializer, update the class to note that
+ // it has designated initializers.
+ if (Info.DesignatedInit) {
+ assert(Implementation->ParentContexts.contains(CtxID.Value));
+ uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];
+ ContextTableKey CtxKey(ParentCtxID,
+ static_cast<uint8_t>(ContextKind::ObjCClass),
+ Implementation->ObjCContextNames[CtxID.Value]);
+ assert(Implementation->ObjCContexts.contains(CtxKey));
+ auto &VersionedVec = Implementation->ObjCContexts[CtxKey].second;
+ bool Found = false;
+ for (auto &Versioned : VersionedVec) {
+ if (Versioned.first == SwiftVersion) {
+ Versioned.second.setHasDesignatedInits(true);
+ Found = true;
+ break;
+ }
+ }
+
+ if (!Found) {
+ VersionedVec.push_back({SwiftVersion, ObjCContextInfo()});
+ VersionedVec.back().second.setHasDesignatedInits(true);
+ }
+ }
+}
+
+void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,
+ llvm::StringRef Name,
+ const GlobalVariableInfo &Info,
+ VersionTuple SwiftVersion) {
+ IdentifierID VariableID = Implementation->getIdentifier(Name);
+ ContextTableKey Key(Ctx, VariableID);
+ Implementation->GlobalVariables[Key].push_back({SwiftVersion, Info});
+}
+
+void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
+ llvm::StringRef Name,
+ const GlobalFunctionInfo &Info,
+ VersionTuple SwiftVersion) {
+ IdentifierID NameID = Implementation->getIdentifier(Name);
+ ContextTableKey Key(Ctx, NameID);
+ Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
+}
+
+void APINotesWriter::addEnumConstant(llvm::StringRef Name,
+ const EnumConstantInfo &Info,
+ VersionTuple SwiftVersion) {
+ IdentifierID EnumConstantID = Implementation->getIdentifier(Name);
+ Implementation->EnumConstants[EnumConstantID].push_back({SwiftVersion, Info});
+}
+
+void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,
+ const TagInfo &Info, VersionTuple SwiftVersion) {
+ IdentifierID TagID = Implementation->getIdentifier(Name);
+ ContextTableKey Key(Ctx, TagID);
+ Implementation->Tags[Key].push_back({SwiftVersion, Info});
+}
+
+void APINotesWriter::addTypedef(std::optional<Context> Ctx,
+ llvm::StringRef Name, const TypedefInfo &Info,
+ VersionTuple SwiftVersion) {
+ IdentifierID TypedefID = Implementation->getIdentifier(Name);
+ ContextTableKey Key(Ctx, TypedefID);
+ Implementation->Typedefs[Key].push_back({SwiftVersion, Info});
+}
} // namespace api_notes
} // namespace clang
More information about the cfe-commits
mailing list