-
Notifications
You must be signed in to change notification settings - Fork 10.8k
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
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@llvm/pr-subscribers-clang ChangesThis 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:
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
added
the
clang:frontend
Language frontend issues, e.g. anything involving "Sema"
label
Sep 19, 2023
compnerd
reviewed
Oct 9, 2023
egorzhdan
force-pushed
the
upstream-apinotes-reader
branch
from
October 10, 2023 18:05
e0649ee
to
c62e0c4
Compare
egorzhdan
force-pushed
the
upstream-apinotes-reader
branch
from
October 27, 2023 17:08
c62e0c4
to
4561ed8
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
egorzhdan
force-pushed
the
upstream-apinotes-reader
branch
from
October 27, 2023 17:31
4561ed8
to
629a809
Compare
compnerd
approved these changes
Oct 27, 2023
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
force-pushed
the
upstream-apinotes-reader
branch
from
October 30, 2023 12:40
629a809
to
e165261
Compare
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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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