Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[APINotes] Upstream APINotesReader #66769

Merged
merged 1 commit into from
Oct 30, 2023

Conversation

egorzhdan
Copy link
Contributor

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

@llvmbot llvmbot added the clang Clang issues not falling into any other category label Sep 19, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Sep 19, 2023

@llvm/pr-subscribers-clang

Changes

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


Patch is 71.63 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66769.diff

3 Files Affected:

  • (added) clang/include/clang/APINotes/APINotesReader.h (+202)
  • (added) clang/lib/APINotes/APINotesReader.cpp (+2001)
  • (modified) clang/lib/APINotes/CMakeLists.txt (+3)
diff --git a/clang/include/clang/APINotes/APINotesReader.h b/clang/include/clang/APINotes/APINotesReader.h
new file mode 100644
index 000000000000000..35e2ecaf0a55522
--- /dev/null
+++ b/clang/include/clang/APINotes/APINotesReader.h
@@ -0,0 +1,202 @@
+//===--- APINotesReader.h - API Notes Reader --------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the \c APINotesReader class that reads source API notes
+// data providing additional information about source code as a separate input,
+// such as the non-nil/nilable annotations for method parameters.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_APINOTES_READER_H
+#define LLVM_CLANG_APINOTES_READER_H
+
+#include "clang/APINotes/Types.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/VersionTuple.h"
+#include <memory>
+
+namespace clang {
+namespace api_notes {
+
+/// A class that reads API notes data from a binary file that was written by
+/// the \c APINotesWriter.
+class APINotesReader {
+  class Implementation;
+  std::unique_ptr<Implementation> Implementation;
+
+  APINotesReader(llvm::MemoryBuffer *InputBuffer,
+                 llvm::VersionTuple SwiftVersion, bool &Failed);
+
+public:
+  /// Create a new API notes reader from the given member buffer, which
+  /// contains the contents of a binary API notes file.
+  ///
+  /// \returns the new API notes reader, or null if an error occurred.
+  static std::unique_ptr<APINotesReader>
+  get(std::unique_ptr<llvm::MemoryBuffer> InputBuffer,
+      llvm::VersionTuple SwiftVersion);
+
+  ~APINotesReader();
+
+  APINotesReader(const APINotesReader &) = delete;
+  APINotesReader &operator=(const APINotesReader &) = delete;
+
+  /// Captures the completed versioned information for a particular part of
+  /// API notes, including both unversioned API notes and each versioned API
+  /// note for that particular entity.
+  template <typename T> class VersionedInfo {
+    /// The complete set of results.
+    llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1> Results;
+
+    /// The index of the result that is the "selected" set based on the desired
+    /// Swift version, or \c Results.size() if nothing matched.
+    unsigned Selected;
+
+  public:
+    /// Form an empty set of versioned information.
+    VersionedInfo(std::nullopt_t) : Selected(0) {}
+
+    /// Form a versioned info set given the desired version and a set of
+    /// results.
+    VersionedInfo(
+        llvm::VersionTuple Version,
+        llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1> Results);
+
+    /// Retrieve the selected index in the result set.
+    std::optional<unsigned> getSelected() const {
+      if (Selected == Results.size())
+        return std::nullopt;
+      return Selected;
+    }
+
+    /// Return the number of versioned results we know about.
+    unsigned size() const { return Results.size(); }
+
+    /// Access all versioned results.
+    const std::pair<llvm::VersionTuple, T> *begin() const {
+      return Results.begin();
+    }
+    const std::pair<llvm::VersionTuple, T> *end() const {
+      return Results.end();
+    }
+
+    /// Access a specific versioned result.
+    const std::pair<llvm::VersionTuple, T> &operator[](unsigned index) const {
+      return Results[index];
+    }
+  };
+
+  /// Look for the context ID of the given Objective-C class.
+  ///
+  /// \param Name The name of the class we're looking for.
+  ///
+  /// \returns The ID, if known.
+  std::optional<ContextID> lookupObjCClassID(llvm::StringRef Name);
+
+  /// Look for information regarding the given Objective-C class.
+  ///
+  /// \param Name The name of the class we're looking for.
+  ///
+  /// \returns The information about the class, if known.
+  VersionedInfo<ObjCContextInfo> lookupObjCClassInfo(llvm::StringRef Name);
+
+  /// Look for the context ID of the given Objective-C protocol.
+  ///
+  /// \param Name The name of the protocol we're looking for.
+  ///
+  /// \returns The ID of the protocol, if known.
+  std::optional<ContextID> lookupObjCProtocolID(llvm::StringRef Name);
+
+  /// Look for information regarding the given Objective-C protocol.
+  ///
+  /// \param Name The name of the protocol we're looking for.
+  ///
+  /// \returns The information about the protocol, if known.
+  VersionedInfo<ObjCContextInfo> lookupObjCProtocolInfo(llvm::StringRef Name);
+
+  /// Look for information regarding the given Objective-C property in
+  /// the given context.
+  ///
+  /// \param CtxID The ID that references the context we are looking for.
+  /// \param Name The name of the property we're looking for.
+  /// \param IsInstance Whether we are looking for an instance property (vs.
+  /// a class property).
+  ///
+  /// \returns Information about the property, if known.
+  VersionedInfo<ObjCPropertyInfo>
+  lookupObjCProperty(ContextID CtxID, llvm::StringRef Name, bool IsInstance);
+
+  /// Look for information regarding the given Objective-C method in
+  /// the given context.
+  ///
+  /// \param CtxID The ID that references the context we are looking for.
+  /// \param Selector The selector naming the method we're looking for.
+  /// \param IsInstanceMethod Whether we are looking for an instance method.
+  ///
+  /// \returns Information about the method, if known.
+  VersionedInfo<ObjCMethodInfo> lookupObjCMethod(ContextID CtxID,
+                                                 ObjCSelectorRef Selector,
+                                                 bool IsInstanceMethod);
+
+  /// Look for information regarding the given global variable.
+  ///
+  /// \param Name The name of the global variable.
+  ///
+  /// \returns information about the global variable, if known.
+  VersionedInfo<GlobalVariableInfo>
+  lookupGlobalVariable(llvm::StringRef Name,
+                       std::optional<Context> Ctx = std::nullopt);
+
+  /// Look for information regarding the given global function.
+  ///
+  /// \param Name The name of the global function.
+  ///
+  /// \returns information about the global function, if known.
+  VersionedInfo<GlobalFunctionInfo>
+  lookupGlobalFunction(llvm::StringRef Name,
+                       std::optional<Context> Ctx = std::nullopt);
+
+  /// Look for information regarding the given enumerator.
+  ///
+  /// \param Name The name of the enumerator.
+  ///
+  /// \returns information about the enumerator, if known.
+  VersionedInfo<EnumConstantInfo> lookupEnumConstant(llvm::StringRef Name);
+
+  /// Look for information regarding the given tag
+  /// (struct/union/enum/C++ class).
+  ///
+  /// \param Name The name of the tag.
+  ///
+  /// \returns information about the tag, if known.
+  VersionedInfo<TagInfo> lookupTag(llvm::StringRef Name,
+                                   std::optional<Context> Ctx = std::nullopt);
+
+  /// Look for information regarding the given typedef.
+  ///
+  /// \param Name The name of the typedef.
+  ///
+  /// \returns information about the typedef, if known.
+  VersionedInfo<TypedefInfo>
+  lookupTypedef(llvm::StringRef Name,
+                std::optional<Context> Ctx = std::nullopt);
+
+  /// Look for the context ID of the given C++ namespace.
+  ///
+  /// \param Name The name of the class we're looking for.
+  ///
+  /// \returns The ID, if known.
+  std::optional<ContextID>
+  lookupNamespaceID(llvm::StringRef Name,
+                    std::optional<ContextID> ParentNamespaceID = std::nullopt);
+};
+
+} // end namespace api_notes
+} // end namespace clang
+
+#endif // LLVM_CLANG_APINOTES_READER_H
diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp
new file mode 100644
index 000000000000000..cfdb90290834e5d
--- /dev/null
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -0,0 +1,2001 @@
+//===--- APINotesReader.cpp - API Notes Reader ------------------*- 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 "clang/APINotes/APINotesReader.h"
+#include "APINotesFormat.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Bitstream/BitstreamReader.h"
+#include "llvm/Support/DJB.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/OnDiskHashTable.h"
+
+namespace clang {
+namespace api_notes {
+using namespace llvm::support;
+
+namespace {
+/// Deserialize a version tuple.
+llvm::VersionTuple ReadVersionTuple(const uint8_t *&Data) {
+  uint8_t NumVersions = (*Data++) & 0x03;
+
+  unsigned Major = endian::readNext<uint32_t, little, unaligned>(Data);
+  if (NumVersions == 0)
+    return llvm::VersionTuple(Major);
+
+  unsigned Minor = endian::readNext<uint32_t, little, unaligned>(Data);
+  if (NumVersions == 1)
+    return llvm::VersionTuple(Major, Minor);
+
+  unsigned Subminor = endian::readNext<uint32_t, little, unaligned>(Data);
+  if (NumVersions == 2)
+    return llvm::VersionTuple(Major, Minor, Subminor);
+
+  unsigned Build = endian::readNext<uint32_t, little, unaligned>(Data);
+  return llvm::VersionTuple(Major, Minor, Subminor, Build);
+}
+
+/// An on-disk hash table whose data is versioned based on the Swift version.
+template <typename Derived, typename KeyType, typename UnversionedDataType>
+class VersionedTableInfo {
+public:
+  using internal_key_type = KeyType;
+  using external_key_type = KeyType;
+  using data_type =
+      llvm::SmallVector<std::pair<llvm::VersionTuple, UnversionedDataType>, 1>;
+  using hash_value_type = size_t;
+  using offset_type = unsigned;
+
+  internal_key_type GetInternalKey(external_key_type Key) { return Key; }
+
+  external_key_type GetExternalKey(internal_key_type Key) { return Key; }
+
+  static bool EqualKey(internal_key_type LHS, internal_key_type RHS) {
+    return LHS == RHS;
+  }
+
+  static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&Data) {
+    unsigned KeyLength = endian::readNext<uint16_t, little, unaligned>(Data);
+    unsigned DataLength = endian::readNext<uint16_t, little, unaligned>(Data);
+    return {KeyLength, DataLength};
+  }
+
+  static data_type ReadData(internal_key_type Key, const uint8_t *Data,
+                            unsigned Length) {
+    unsigned NumElements = endian::readNext<uint16_t, little, unaligned>(Data);
+    data_type Result;
+    Result.reserve(NumElements);
+    for (unsigned i = 0; i != NumElements; ++i) {
+      auto version = ReadVersionTuple(Data);
+      const auto *DataBefore = Data;
+      (void)DataBefore;
+      auto UnversionedData = Derived::readUnversioned(Key, Data);
+      assert(Data != DataBefore &&
+             "Unversioned data reader didn't move pointer");
+      Result.push_back({version, UnversionedData});
+    }
+    return Result;
+  }
+};
+
+/// Read serialized CommonEntityInfo.
+void ReadCommonEntityInfo(const uint8_t *&Data, CommonEntityInfo &Info) {
+  uint8_t UnavailableBits = *Data++;
+  Info.Unavailable = (UnavailableBits >> 1) & 0x01;
+  Info.UnavailableInSwift = UnavailableBits & 0x01;
+  if ((UnavailableBits >> 2) & 0x01)
+    Info.setSwiftPrivate(static_cast<bool>((UnavailableBits >> 3) & 0x01));
+
+  unsigned MsgLength = endian::readNext<uint16_t, little, unaligned>(Data);
+  Info.UnavailableMsg =
+      std::string(reinterpret_cast<const char *>(Data),
+                  reinterpret_cast<const char *>(Data) + MsgLength);
+  Data += MsgLength;
+
+  unsigned SwiftNameLength =
+      endian::readNext<uint16_t, little, unaligned>(Data);
+  Info.SwiftName =
+      std::string(reinterpret_cast<const char *>(Data),
+                  reinterpret_cast<const char *>(Data) + SwiftNameLength);
+  Data += SwiftNameLength;
+}
+
+/// Read serialized CommonTypeInfo.
+void ReadCommonTypeInfo(const uint8_t *&Data, CommonTypeInfo &Info) {
+  ReadCommonEntityInfo(Data, Info);
+
+  unsigned SwiftBridgeLength =
+      endian::readNext<uint16_t, little, unaligned>(Data);
+  if (SwiftBridgeLength > 0) {
+    Info.setSwiftBridge(std::optional<std::string>(std::string(
+        reinterpret_cast<const char *>(Data), SwiftBridgeLength - 1)));
+    Data += SwiftBridgeLength - 1;
+  }
+
+  unsigned ErrorDomainLength =
+      endian::readNext<uint16_t, little, unaligned>(Data);
+  if (ErrorDomainLength > 0) {
+    Info.setNSErrorDomain(std::optional<std::string>(std::string(
+        reinterpret_cast<const char *>(Data), ErrorDomainLength - 1)));
+    Data += ErrorDomainLength - 1;
+  }
+}
+
+/// Used to deserialize the on-disk identifier table.
+class IdentifierTableInfo {
+public:
+  using internal_key_type = llvm::StringRef;
+  using external_key_type = llvm::StringRef;
+  using data_type = IdentifierID;
+  using hash_value_type = uint32_t;
+  using offset_type = unsigned;
+
+  internal_key_type GetInternalKey(external_key_type Key) { return Key; }
+
+  external_key_type GetExternalKey(internal_key_type Key) { return Key; }
+
+  hash_value_type ComputeHash(internal_key_type Key) {
+    return llvm::djbHash(Key);
+  }
+
+  static bool EqualKey(internal_key_type LHS, internal_key_type RHS) {
+    return LHS == RHS;
+  }
+
+  static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&Data) {
+    unsigned KeyLength = endian::readNext<uint16_t, little, unaligned>(Data);
+    unsigned DataLength = endian::readNext<uint16_t, little, unaligned>(Data);
+    return {KeyLength, DataLength};
+  }
+
+  static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) {
+    return llvm::StringRef(reinterpret_cast<const char *>(Data), Length);
+  }
+
+  static data_type ReadData(internal_key_type key, const uint8_t *Data,
+                            unsigned Length) {
+    return endian::readNext<uint32_t, little, unaligned>(Data);
+  }
+};
+
+/// Used to deserialize the on-disk Objective-C class table.
+class ObjCContextIDTableInfo {
+public:
+  using internal_key_type = ContextTableKey;
+  using external_key_type = internal_key_type;
+  using data_type = unsigned;
+  using hash_value_type = size_t;
+  using offset_type = unsigned;
+
+  internal_key_type GetInternalKey(external_key_type Key) { return Key; }
+
+  external_key_type GetExternalKey(internal_key_type Key) { return Key; }
+
+  hash_value_type ComputeHash(internal_key_type Key) {
+    return static_cast<size_t>(Key.hashValue());
+  }
+
+  static bool EqualKey(internal_key_type LHS, internal_key_type RHS) {
+    return LHS == RHS;
+  }
+
+  static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&Data) {
+    unsigned KeyLength = endian::readNext<uint16_t, little, unaligned>(Data);
+    unsigned DataLength = endian::readNext<uint16_t, little, unaligned>(Data);
+    return {KeyLength, DataLength};
+  }
+
+  static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) {
+    auto ParentCtxID = endian::readNext<uint32_t, little, unaligned>(Data);
+    auto ContextKind = endian::readNext<uint8_t, little, unaligned>(Data);
+    auto NameID = endian::readNext<uint32_t, little, unaligned>(Data);
+    return {ParentCtxID, ContextKind, NameID};
+  }
+
+  static data_type ReadData(internal_key_type Key, const uint8_t *Data,
+                            unsigned Length) {
+    return endian::readNext<uint32_t, little, unaligned>(Data);
+  }
+};
+
+/// Used to deserialize the on-disk Objective-C property table.
+class ObjCContextInfoTableInfo
+    : public VersionedTableInfo<ObjCContextInfoTableInfo, unsigned,
+                                ObjCContextInfo> {
+public:
+  static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) {
+    return endian::readNext<uint32_t, little, unaligned>(Data);
+  }
+
+  hash_value_type ComputeHash(internal_key_type Key) {
+    return static_cast<size_t>(llvm::hash_value(Key));
+  }
+
+  static ObjCContextInfo readUnversioned(internal_key_type Key,
+                                         const uint8_t *&Data) {
+    ObjCContextInfo Info;
+    ReadCommonTypeInfo(Data, Info);
+    uint8_t Payload = *Data++;
+
+    if (Payload & 0x01)
+      Info.setHasDesignatedInits(true);
+    Payload = Payload >> 1;
+
+    if (Payload & 0x4)
+      Info.setDefaultNullability(static_cast<NullabilityKind>(Payload & 0x03));
+    Payload >>= 3;
+
+    if (Payload & (1 << 1))
+      Info.setSwiftObjCMembers(Payload & 1);
+    Payload >>= 2;
+
+    if (Payload & (1 << 1))
+      Info.setSwiftImportAsNonGeneric(Payload & 1);
+
+    return Info;
+  }
+};
+
+/// Read serialized VariableInfo.
+void ReadVariableInfo(const uint8_t *&Data, VariableInfo &Info) {
+  ReadCommonEntityInfo(Data, Info);
+  if (*Data++) {
+    Info.setNullabilityAudited(static_cast<NullabilityKind>(*Data));
+  }
+  ++Data;
+
+  auto TypeLen = endian::readNext<uint16_t, little, unaligned>(Data);
+  Info.setType(std::string(Data, Data + TypeLen));
+  Data += TypeLen;
+}
+
+/// Used to deserialize the on-disk Objective-C property table.
+class ObjCPropertyTableInfo
+    : public VersionedTableInfo<ObjCPropertyTableInfo,
+                                std::tuple<uint32_t, uint32_t, uint8_t>,
+                                ObjCPropertyInfo> {
+public:
+  static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) {
+    auto ClassID = endian::readNext<uint32_t, little, unaligned>(Data);
+    auto NameID = endian::readNext<uint32_t, little, unaligned>(Data);
+    char IsInstance = endian::readNext<uint8_t, little, unaligned>(Data);
+    return {ClassID, NameID, IsInstance};
+  }
+
+  hash_value_type ComputeHash(internal_key_type Key) {
+    return static_cast<size_t>(llvm::hash_value(Key));
+  }
+
+  static ObjCPropertyInfo readUnversioned(internal_key_type Key,
+                                          const uint8_t *&Data) {
+    ObjCPropertyInfo Info;
+    ReadVariableInfo(Data, Info);
+    uint8_t Flags = *Data++;
+    if (Flags & (1 << 0))
+      Info.setSwiftImportAsAccessors(Flags & (1 << 1));
+    return Info;
+  }
+};
+
+/// Read serialized ParamInfo.
+void ReadParamInfo(const uint8_t *&Data, ParamInfo &Info) {
+  ReadVariableInfo(Data, Info);
+
+  uint8_t Payload = endian::readNext<uint8_t, little, unaligned>(Data);
+  if (auto RawConvention = Payload & 0x7) {
+    auto Convention = static_cast<RetainCountConventionKind>(RawConvention - 1);
+    Info.setRetainCountConvention(Convention);
+  }
+  Payload >>= 3;
+  if (Payload & 0x01) {
+    Info.setNoEscape(Payload & 0x02);
+  }
+  Payload >>= 2;
+  assert(Payload == 0 && "Bad API notes");
+}
+
+/// Read serialized FunctionInfo.
+void ReadFunctionInfo(const uint8_t *&Data, FunctionInfo &Info) {
+  ReadCommonEntityInfo(Data, Info);
+
+  uint8_t Payload = endian::readNext<uint8_t, little, unaligned>(Data);
+  if (auto RawConvention = Payload & 0x7) {
+    auto Convention = static_cast<RetainCountConventionKind>(RawConvention - 1);
+    Info.setRetainCountConvention(Convention);
+  }
+  Payload >>= 3;
+  Info.NullabilityAudited = Payload & 0x1;
+  Payload >>= 1;
+  assert(Payload == 0 && "Bad API notes");
+
+  Info.NumAdjustedNullable = endian::readNext<uint8_t, little, unaligned>(Data);
+  Info.NullabilityPayload = endian::readNext<uint64_t, little, unaligned>(Data);
+
+  unsigned NumParams = endian::readNext<uint16_t, little, unaligned>(Data);
+  while (NumParams > 0) {
+    ParamInfo pi;
+    ReadParamInfo(Data, pi);
+    Info.Params.push_back(pi);
+    --NumParams;
+  }
+
+  unsigned ResultTypeLen = endian::readNext<uint16_t, little, unaligned>(Data);
+  Info.ResultType = std::string(Data, Data + ResultTypeLen);
+  Data += ResultTypeLen;
+}
+
+/// Used to deserialize the on-disk Objective-C method table.
+class ObjCMethodTableInfo
+    : public VersionedTableInfo<ObjCMethodTableInfo,
+                                std::tuple<uint32_t, uint32_t, uint8_t>,
+                                ObjCMethodInfo> {
+public:
+  static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) {
+    auto ClassID = endian::readNext<uint32_t, little, unaligned>(Data);
+    auto SelectorID = endian::readNext<uint32_t, little, unaligned>(Data);
+    auto IsInstance = endian:...
[truncated]

@egorzhdan egorzhdan added the clang:frontend Language frontend issues, e.g. anything involving "Sema" label Sep 19, 2023
clang/include/clang/APINotes/APINotesReader.h Outdated Show resolved Hide resolved
clang/include/clang/APINotes/APINotesReader.h Outdated Show resolved Hide resolved
clang/include/clang/APINotes/APINotesReader.h Show resolved Hide resolved
clang/include/clang/APINotes/APINotesReader.h Show resolved Hide resolved
clang/include/clang/APINotes/APINotesReader.h Show resolved Hide resolved
clang/lib/APINotes/APINotesReader.cpp Outdated Show resolved Hide resolved
clang/lib/APINotes/APINotesReader.cpp Show resolved Hide resolved
clang/lib/APINotes/APINotesReader.cpp Outdated Show resolved Hide resolved
clang/lib/APINotes/APINotesReader.cpp Outdated Show resolved Hide resolved
clang/lib/APINotes/APINotesReader.cpp Outdated Show resolved Hide resolved
@github-actions
Copy link

github-actions bot commented Oct 27, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

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
@egorzhdan egorzhdan merged commit bb352b6 into llvm:main Oct 30, 2023
3 checks passed
@egorzhdan egorzhdan deleted the upstream-apinotes-reader branch October 30, 2023 14:36
egorzhdan added a commit to apple/llvm-project that referenced this pull request Oct 31, 2023
APINotesReader was upstreamed in llvm#66769
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants