compnerd updated this revision to Diff 300796.
compnerd added a comment.

Address review comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D88859/new/

https://reviews.llvm.org/D88859

Files:
  clang/include/clang/APINotes/APINotesYAMLCompiler.h
  clang/include/clang/APINotes/Types.h
  clang/lib/APINotes/APINotesYAMLCompiler.cpp
  clang/lib/APINotes/CMakeLists.txt
  clang/lib/CMakeLists.txt
  clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.apinotes
  clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.h
  clang/test/APINotes/yaml-roundtrip.test
  clang/test/CMakeLists.txt
  clang/test/lit.cfg.py
  clang/tools/CMakeLists.txt
  clang/tools/apinotes-test/APINotesTest.cpp
  clang/tools/apinotes-test/CMakeLists.txt

Index: clang/tools/apinotes-test/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang/tools/apinotes-test/CMakeLists.txt
@@ -0,0 +1,6 @@
+set(LLVM_LINK_COMPONENTS
+  Support)
+add_clang_executable(apinotes-test
+  APINotesTest.cpp)
+clang_target_link_libraries(apinotes-test PRIVATE
+  clangAPINotes)
Index: clang/tools/apinotes-test/APINotesTest.cpp
===================================================================
--- /dev/null
+++ clang/tools/apinotes-test/APINotesTest.cpp
@@ -0,0 +1,53 @@
+//===-- APINotesTest.cpp - API Notes Testing Tool ------------------ 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/APINotesYAMLCompiler.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/WithColor.h"
+
+static llvm::cl::list<std::string>
+APINotes(llvm::cl::Positional, llvm::cl::desc("[<apinotes> ...]"),
+         llvm::cl::Required);
+
+static llvm::cl::opt<std::string>
+OutputFileName("o", llvm::cl::desc("output filename"),
+               llvm::cl::value_desc("filename"), llvm::cl::init("-"));
+
+int main(int argc, const char **argv) {
+  const bool DisableCrashReporting = true;
+  llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting);
+  llvm::cl::ParseCommandLineOptions(argc, argv);
+
+  auto Error = [](const llvm::Twine &Msg) {
+    llvm::WithColor::error(llvm::errs(), "apinotes-test") << Msg << '\n';
+  };
+
+  std::error_code EC;
+  auto Out = std::make_unique<llvm::ToolOutputFile>(OutputFileName, EC,
+                                                    llvm::sys::fs::OF_None);
+  if (EC) {
+    Error("failed to open '" + OutputFileName + "': " + EC.message());
+    return EXIT_FAILURE;
+  }
+
+  for (const std::string &Notes : APINotes) {
+    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> NotesOrError =
+        llvm::MemoryBuffer::getFileOrSTDIN(Notes);
+    if (std::error_code EC = NotesOrError.getError()) {
+      llvm::errs() << EC.message() << '\n';
+      return EXIT_FAILURE;
+    }
+
+    clang::api_notes::parseAndDumpAPINotes((*NotesOrError)->getBuffer(),
+                                           Out->os());
+  }
+
+  return EXIT_SUCCESS;
+}
Index: clang/tools/CMakeLists.txt
===================================================================
--- clang/tools/CMakeLists.txt
+++ clang/tools/CMakeLists.txt
@@ -2,6 +2,7 @@
 
 add_clang_subdirectory(diagtool)
 add_clang_subdirectory(driver)
+add_clang_subdirectory(apinotes-test)
 add_clang_subdirectory(clang-diff)
 add_clang_subdirectory(clang-format)
 add_clang_subdirectory(clang-format-vs)
Index: clang/test/lit.cfg.py
===================================================================
--- clang/test/lit.cfg.py
+++ clang/test/lit.cfg.py
@@ -63,7 +63,8 @@
 tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir]
 
 tools = [
-    'c-index-test', 'clang-diff', 'clang-format', 'clang-tblgen', 'opt', 'llvm-ifs',
+    'apinotes-test', 'c-index-test', 'clang-diff', 'clang-format',
+    'clang-tblgen', 'opt', 'llvm-ifs',
     ToolSubst('%clang_extdef_map', command=FindTool(
         'clang-extdef-mapping'), unresolved='ignore'),
 ]
Index: clang/test/CMakeLists.txt
===================================================================
--- clang/test/CMakeLists.txt
+++ clang/test/CMakeLists.txt
@@ -58,6 +58,7 @@
 endif ()
 
 list(APPEND CLANG_TEST_DEPS
+  apinotes-test
   c-index-test
   clang
   clang-resource-headers
Index: clang/test/APINotes/yaml-roundtrip.test
===================================================================
--- /dev/null
+++ clang/test/APINotes/yaml-roundtrip.test
@@ -0,0 +1,26 @@
+RUN: apinotes-test %S/Inputs/Frameworks/Simple.framework/Headers/Simple.apinotes > %t.result
+RUN: not diff %S/Inputs/Frameworks/Simple.framework/Headers/Simple.apinotes %t.result | FileCheck %s
+
+We expect only the nullability to be different as it is canonicalized during the
+roudtrip.
+
+CHECK:      7c8
+CHECK-NEXT: <         Nullability:     N
+CHECK-NEXT: ---
+CHECK-NEXT: >         Nullability:     Nonnull
+CHECK-NEXT: 13c14
+CHECK-NEXT: <         Nullability:     O
+CHECK-NEXT: ---
+CHECK-NEXT: >         Nullability:     Optional
+CHECK-NEXT: 19c20
+CHECK-NEXT: <         Nullability:     U
+CHECK-NEXT: ---
+CHECK-NEXT: >         Nullability:     Unspecified
+CHECK-NEXT: 25c26
+CHECK-NEXT: <         Nullability:     S
+CHECK-NEXT: ---
+CHECK-NEXT: >         Nullability:     Unspecified
+CHECK-NEXT: 28c29,30
+CHECK-NEXT: <         Nullability:     Scalar
+CHECK-NEXT: ---
+CHECK-NEXT: >         Nullability:     Unspecified
Index: clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.h
===================================================================
--- /dev/null
+++ clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.h
@@ -0,0 +1,19 @@
+#ifndef SIMPLE_H
+#define SIMPLE_H
+
+__attribute__((__objc_root__))
+@interface I
+@property(class, nonatomic, readonly) id nonnullProperty;
+@property(class, nonatomic, readonly) id nonnullNewProperty;
+
+@property(class, nonatomic, readonly) id optionalProperty;
+@property(class, nonatomic, readonly) id optionalNewProperty;
+
+@property(nonatomic, readonly) id unspecifiedProperty;
+@property(nonatomic, readonly) id unspecifiedNewProperty;
+
+@property(nonatomic, readonly) id scalarProperty;
+@property(nonatomic, readonly) id scalarNewProperty;
+@end
+
+#endif
Index: clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.apinotes
===================================================================
--- /dev/null
+++ clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.apinotes
@@ -0,0 +1,28 @@
+Name:            SimpleKit
+Classes:
+  - Name:            I
+    Properties:
+      - Name:            nonnullProperty
+        PropertyKind:    Class
+        Nullability:     N
+      - Name:            nonnullNewProperty
+        PropertyKind:    Class
+        Nullability:     Nonnull
+      - Name:            optionalProperty
+        PropertyKind:    Class
+        Nullability:     O
+      - Name:            optionalNewProperty
+        PropertyKind:    Class
+        Nullability:     Optional
+      - Name:            unspecifiedProperty
+        PropertyKind:    Instance
+        Nullability:     U
+      - Name:            unspecifiedNewProperty
+        PropertyKind:    Instance
+        Nullability:     Unspecified
+      - Name:            scalarProperty
+        PropertyKind:    Instance
+        Nullability:     S
+      - Name:            scalarNewProperty
+        PropertyKind:    Instance
+        Nullability:     Scalar
Index: clang/lib/CMakeLists.txt
===================================================================
--- clang/lib/CMakeLists.txt
+++ clang/lib/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_subdirectory(Headers)
 add_subdirectory(Basic)
+add_subdirectory(APINotes)
 add_subdirectory(Lex)
 add_subdirectory(Parse)
 add_subdirectory(AST)
Index: clang/lib/APINotes/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang/lib/APINotes/CMakeLists.txt
@@ -0,0 +1,6 @@
+set(LLVM_LINK_COMPONENTS
+  Support)
+add_clang_library(clangAPINotes
+  APINotesYAMLCompiler.cpp
+  LINK_LIBS
+    clangBasic)
Index: clang/lib/APINotes/APINotesYAMLCompiler.cpp
===================================================================
--- /dev/null
+++ clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -0,0 +1,612 @@
+//===-- APINotesYAMLCompiler.cpp - API Notes YAML Format 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/APINotesYAMLCompiler.h"
+#include "clang/APINotes/Types.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/VersionTuple.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <vector>
+using namespace clang;
+using namespace api_notes;
+
+namespace {
+enum class APIAvailability {
+  Available = 0,
+  OSX,
+  IOS,
+  None,
+  NonSwift,
+};
+} // namespace
+
+namespace llvm {
+namespace yaml {
+template <>
+struct ScalarEnumerationTraits<APIAvailability> {
+  static void enumeration(IO &IO, APIAvailability &AA) {
+    IO.enumCase(AA, "OSX",       APIAvailability::OSX);
+    IO.enumCase(AA, "iOS",       APIAvailability::IOS);
+    IO.enumCase(AA, "none",      APIAvailability::None);
+    IO.enumCase(AA, "nonswift",  APIAvailability::NonSwift);
+    IO.enumCase(AA, "available", APIAvailability::Available);
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+enum class MethodKind {
+  Class,
+  Instance,
+};
+} // namespace
+
+namespace llvm {
+namespace yaml {
+template <>
+struct ScalarEnumerationTraits<MethodKind> {
+  static void enumeration(IO &IO, MethodKind &MK) {
+    IO.enumCase(MK, "Class",    MethodKind::Class);
+    IO.enumCase(MK, "Instance", MethodKind::Instance);
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+struct Param {
+  unsigned Position;
+  Optional<bool> NoEscape = false;
+  Optional<NullabilityKind> Nullability;
+  Optional<RetainCountConventionKind> RetainCountConvention;
+  StringRef Type;
+};
+
+typedef std::vector<Param> ParamsSeq;
+} // namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Param)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(NullabilityKind)
+
+namespace llvm {
+namespace yaml {
+template <>
+struct ScalarEnumerationTraits<NullabilityKind> {
+  static void enumeration(IO &IO, NullabilityKind &NK) {
+    IO.enumCase(NK, "Nonnull", NullabilityKind::NonNull);
+    IO.enumCase(NK, "Optional", NullabilityKind::Nullable);
+    IO.enumCase(NK, "Unspecified", NullabilityKind::Unspecified);
+    // TODO: Mapping this to it's own value would allow for better cross
+    // checking. Also the default should be Unknown.
+    IO.enumCase(NK, "Scalar", NullabilityKind::Unspecified);
+
+    // Aliases for compatibility with existing APINotes.
+    IO.enumCase(NK, "N", NullabilityKind::NonNull);
+    IO.enumCase(NK, "O", NullabilityKind::Nullable);
+    IO.enumCase(NK, "U", NullabilityKind::Unspecified);
+    IO.enumCase(NK, "S", NullabilityKind::Unspecified);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<RetainCountConventionKind> {
+  static void enumeration(IO &IO, RetainCountConventionKind &RCCK) {
+    IO.enumCase(RCCK, "none", RetainCountConventionKind::None);
+    IO.enumCase(RCCK, "CFReturnsRetained",
+                RetainCountConventionKind::CFReturnsRetained);
+    IO.enumCase(RCCK, "CFReturnsNotRetained",
+                RetainCountConventionKind::CFReturnsNotRetained);
+    IO.enumCase(RCCK, "NSReturnsRetained",
+                RetainCountConventionKind::NSReturnsRetained);
+    IO.enumCase(RCCK, "NSReturnsNotRetained",
+                RetainCountConventionKind::NSReturnsNotRetained);
+  }
+};
+
+template <>
+struct MappingTraits<Param> {
+  static void mapping(IO &IO, Param& P) {
+    IO.mapRequired("Position",              P.Position);
+    IO.mapOptional("Nullability",           P.Nullability, llvm::None);
+    IO.mapOptional("RetainCountConvention", P.RetainCountConvention);
+    IO.mapOptional("NoEscape",              P.NoEscape);
+    IO.mapOptional("Type",                  P.Type, StringRef(""));
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+typedef std::vector<NullabilityKind> NullabilitySeq;
+
+struct AvailabilityItem {
+  APIAvailability Mode = APIAvailability::Available;
+  StringRef Msg;
+};
+
+/// Old attribute deprecated in favor of SwiftName.
+enum class FactoryAsInitKind {
+  /// Infer based on name and type (the default).
+  Infer,
+  /// Treat as a class method.
+  AsClassMethod,
+  /// Treat as an initializer.
+  AsInitializer,
+};
+
+struct Method {
+  StringRef Selector;
+  MethodKind Kind;
+  ParamsSeq Params;
+  NullabilitySeq Nullability;
+  Optional<NullabilityKind> NullabilityOfRet;
+  Optional<RetainCountConventionKind> RetainCountConvention;
+  AvailabilityItem Availability;
+  Optional<bool> SwiftPrivate;
+  StringRef SwiftName;
+  FactoryAsInitKind FactoryAsInit = FactoryAsInitKind::Infer;
+  bool DesignatedInit = false;
+  bool Required = false;
+  StringRef ResultType;
+};
+
+typedef std::vector<Method> MethodsSeq;
+} // namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Method)
+
+namespace llvm {
+namespace yaml {
+template <>
+struct ScalarEnumerationTraits<FactoryAsInitKind> {
+  static void enumeration(IO &IO, FactoryAsInitKind &FIK) {
+    IO.enumCase(FIK, "A", FactoryAsInitKind::Infer);
+    IO.enumCase(FIK, "C", FactoryAsInitKind::AsClassMethod);
+    IO.enumCase(FIK, "I", FactoryAsInitKind::AsInitializer);
+  }
+};
+
+template <>
+struct MappingTraits<Method> {
+  static void mapping(IO &IO, Method &M) {
+    IO.mapRequired("Selector",              M.Selector);
+    IO.mapRequired("MethodKind",            M.Kind);
+    IO.mapOptional("Parameters",            M.Params);
+    IO.mapOptional("Nullability",           M.Nullability);
+    IO.mapOptional("NullabilityOfRet",      M.NullabilityOfRet, llvm::None);
+    IO.mapOptional("RetainCountConvention", M.RetainCountConvention);
+    IO.mapOptional("Availability",          M.Availability.Mode,
+                                            APIAvailability::Available);
+    IO.mapOptional("AvailabilityMsg",       M.Availability.Msg, StringRef(""));
+    IO.mapOptional("SwiftPrivate",          M.SwiftPrivate);
+    IO.mapOptional("SwiftName",             M.SwiftName, StringRef(""));
+    IO.mapOptional("FactoryAsInit",         M.FactoryAsInit,
+                                            FactoryAsInitKind::Infer);
+    IO.mapOptional("DesignatedInit",        M.DesignatedInit, false);
+    IO.mapOptional("Required",              M.Required, false);
+    IO.mapOptional("ResultType",            M.ResultType, StringRef(""));
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+struct Property {
+  StringRef Name;
+  llvm::Optional<MethodKind> Kind;
+  llvm::Optional<NullabilityKind> Nullability;
+  AvailabilityItem Availability;
+  Optional<bool> SwiftPrivate;
+  StringRef SwiftName;
+  Optional<bool> SwiftImportAsAccessors;
+  StringRef Type;
+};
+
+typedef std::vector<Property> PropertiesSeq;
+} // namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Property)
+
+namespace llvm {
+namespace yaml {
+template <>
+struct MappingTraits<Property> {
+  static void mapping(IO &IO, Property &P) {
+    IO.mapRequired("Name",                   P.Name);
+    IO.mapOptional("PropertyKind",           P.Kind);
+    IO.mapOptional("Nullability",            P.Nullability, llvm::None);
+    IO.mapOptional("Availability",           P.Availability.Mode,
+                                             APIAvailability::Available);
+    IO.mapOptional("AvailabilityMsg",        P.Availability.Msg, StringRef(""));
+    IO.mapOptional("SwiftPrivate",           P.SwiftPrivate);
+    IO.mapOptional("SwiftName",              P.SwiftName, StringRef(""));
+    IO.mapOptional("SwiftImportAsAccessors", P.SwiftImportAsAccessors);
+    IO.mapOptional("Type",                   P.Type, StringRef(""));
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+struct Class {
+  StringRef Name;
+  bool AuditedForNullability = false;
+  AvailabilityItem Availability;
+  Optional<bool> SwiftPrivate;
+  StringRef SwiftName;
+  Optional<StringRef> SwiftBridge;
+  Optional<StringRef> NSErrorDomain;
+  Optional<bool> SwiftImportAsNonGeneric;
+  Optional<bool> SwiftObjCMembers;
+  MethodsSeq Methods;
+  PropertiesSeq Properties;
+};
+
+typedef std::vector<Class> ClassesSeq;
+} // namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Class)
+
+namespace llvm {
+namespace yaml {
+template <>
+struct MappingTraits<Class> {
+  static void mapping(IO &IO, Class &C) {
+    IO.mapRequired("Name",                    C.Name);
+    IO.mapOptional("AuditedForNullability",   C.AuditedForNullability, false);
+    IO.mapOptional("Availability",            C.Availability.Mode,
+                                              APIAvailability::Available);
+    IO.mapOptional("AvailabilityMsg",         C.Availability.Msg,
+                                              StringRef(""));
+    IO.mapOptional("SwiftPrivate",            C.SwiftPrivate);
+    IO.mapOptional("SwiftName",               C.SwiftName, StringRef(""));
+    IO.mapOptional("SwiftBridge",             C.SwiftBridge);
+    IO.mapOptional("NSErrorDomain",           C.NSErrorDomain);
+    IO.mapOptional("SwiftImportAsNonGeneric", C.SwiftImportAsNonGeneric);
+    IO.mapOptional("SwiftObjCMembers",        C.SwiftObjCMembers);
+    IO.mapOptional("Methods",                 C.Methods);
+    IO.mapOptional("Properties",              C.Properties);
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+struct Function {
+  StringRef Name;
+  ParamsSeq Params;
+  NullabilitySeq Nullability;
+  Optional<NullabilityKind> NullabilityOfRet;
+  Optional<api_notes::RetainCountConventionKind> RetainCountConvention;
+  AvailabilityItem Availability;
+  Optional<bool> SwiftPrivate;
+  StringRef SwiftName;
+  StringRef Type;
+  StringRef ResultType;
+};
+
+typedef std::vector<Function> FunctionsSeq;
+} // namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Function)
+
+namespace llvm {
+namespace yaml {
+template <>
+struct MappingTraits<Function> {
+  static void mapping(IO &IO, Function &F) {
+    IO.mapRequired("Name",                  F.Name);
+    IO.mapOptional("Parameters",            F.Params);
+    IO.mapOptional("Nullability",           F.Nullability);
+    IO.mapOptional("NullabilityOfRet",      F.NullabilityOfRet, llvm::None);
+    IO.mapOptional("RetainCountConvention", F.RetainCountConvention);
+    IO.mapOptional("Availability",          F.Availability.Mode,
+                                            APIAvailability::Available);
+    IO.mapOptional("AvailabilityMsg",       F.Availability.Msg, StringRef(""));
+    IO.mapOptional("SwiftPrivate",          F.SwiftPrivate);
+    IO.mapOptional("SwiftName",             F.SwiftName, StringRef(""));
+    IO.mapOptional("ResultType",            F.ResultType, StringRef(""));
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+struct GlobalVariable {
+  StringRef Name;
+  llvm::Optional<NullabilityKind> Nullability;
+  AvailabilityItem Availability;
+  Optional<bool> SwiftPrivate;
+  StringRef SwiftName;
+  StringRef Type;
+};
+
+typedef std::vector<GlobalVariable> GlobalVariablesSeq;
+} // namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(GlobalVariable)
+
+namespace llvm {
+namespace yaml {
+template <>
+struct MappingTraits<GlobalVariable> {
+  static void mapping(IO &IO, GlobalVariable &GV) {
+    IO.mapRequired("Name",            GV.Name);
+    IO.mapOptional("Nullability",     GV.Nullability, llvm::None);
+    IO.mapOptional("Availability",    GV.Availability.Mode,
+                                      APIAvailability::Available);
+    IO.mapOptional("AvailabilityMsg", GV.Availability.Msg, StringRef(""));
+    IO.mapOptional("SwiftPrivate",    GV.SwiftPrivate);
+    IO.mapOptional("SwiftName",       GV.SwiftName, StringRef(""));
+    IO.mapOptional("Type",            GV.Type, StringRef(""));
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+struct EnumConstant {
+  StringRef Name;
+  AvailabilityItem Availability;
+  Optional<bool> SwiftPrivate;
+  StringRef SwiftName;
+};
+
+typedef std::vector<EnumConstant> EnumConstantsSeq;
+} // namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(EnumConstant)
+
+namespace llvm {
+namespace yaml {
+template <>
+struct MappingTraits<EnumConstant> {
+  static void mapping(IO &IO, EnumConstant& EC) {
+    IO.mapRequired("Name",            EC.Name);
+    IO.mapOptional("Availability",    EC.Availability.Mode,
+                                      APIAvailability::Available);
+    IO.mapOptional("AvailabilityMsg", EC.Availability.Msg, StringRef(""));
+    IO.mapOptional("SwiftPrivate",    EC.SwiftPrivate);
+    IO.mapOptional("SwiftName",       EC.SwiftName, StringRef(""));
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+/// Syntactic sugar for EnumExtensibility and FlagEnum
+enum class EnumConvenienceAliasKind {
+  /// EnumExtensibility: none, FlagEnum: false
+  None,
+  /// EnumExtensibility: open, FlagEnum: false
+  CFEnum,
+  /// EnumExtensibility: open, FlagEnum: true
+  CFOptions,
+  /// EnumExtensibility: closed, FlagEnum: false
+  CFClosedEnum
+};
+} // namespace
+
+namespace llvm {
+namespace yaml {
+template<>
+struct ScalarEnumerationTraits<EnumConvenienceAliasKind> {
+  static void enumeration(IO &IO, EnumConvenienceAliasKind &ECAK) {
+    IO.enumCase(ECAK, "none",         EnumConvenienceAliasKind::None);
+    IO.enumCase(ECAK, "CFEnum",       EnumConvenienceAliasKind::CFEnum);
+    IO.enumCase(ECAK, "NSEnum",       EnumConvenienceAliasKind::CFEnum);
+    IO.enumCase(ECAK, "CFOptions",    EnumConvenienceAliasKind::CFOptions);
+    IO.enumCase(ECAK, "NSOptions",    EnumConvenienceAliasKind::CFOptions);
+    IO.enumCase(ECAK, "CFClosedEnum", EnumConvenienceAliasKind::CFClosedEnum);
+    IO.enumCase(ECAK, "NSClosedEnum", EnumConvenienceAliasKind::CFClosedEnum);
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+struct Tag {
+  StringRef Name;
+  AvailabilityItem Availability;
+  StringRef SwiftName;
+  Optional<bool> SwiftPrivate;
+  Optional<StringRef> SwiftBridge;
+  Optional<StringRef> NSErrorDomain;
+  Optional<EnumExtensibilityKind> EnumExtensibility;
+  Optional<bool> FlagEnum;
+  Optional<EnumConvenienceAliasKind> EnumConvenienceKind;
+};
+
+typedef std::vector<Tag> TagsSeq;
+} // namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Tag)
+
+namespace llvm {
+namespace yaml {
+template <>
+struct ScalarEnumerationTraits<EnumExtensibilityKind> {
+  static void enumeration(IO &IO, EnumExtensibilityKind &EEK) {
+    IO.enumCase(EEK, "none",   EnumExtensibilityKind::None);
+    IO.enumCase(EEK, "open",   EnumExtensibilityKind::Open);
+    IO.enumCase(EEK, "closed", EnumExtensibilityKind::Closed);
+  }
+};
+
+template <>
+struct MappingTraits<Tag> {
+  static void mapping(IO &IO, Tag &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(""));
+    IO.mapOptional("SwiftBridge",       T.SwiftBridge);
+    IO.mapOptional("NSErrorDomain",     T.NSErrorDomain);
+    IO.mapOptional("EnumExtensibility", T.EnumExtensibility);
+    IO.mapOptional("FlagEnum",          T.FlagEnum);
+    IO.mapOptional("EnumKind",          T.EnumConvenienceKind);
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+struct Typedef {
+  StringRef Name;
+  AvailabilityItem Availability;
+  StringRef SwiftName;
+  Optional<bool> SwiftPrivate;
+  Optional<StringRef> SwiftBridge;
+  Optional<StringRef> NSErrorDomain;
+  Optional<SwiftNewTypeKind> SwiftType;
+};
+
+typedef std::vector<Typedef> TypedefsSeq;
+} // namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Typedef)
+
+namespace llvm {
+namespace yaml {
+template <>
+struct ScalarEnumerationTraits<SwiftNewTypeKind> {
+  static void enumeration(IO &IO, SwiftNewTypeKind &SWK) {
+    IO.enumCase(SWK, "none",   SwiftNewTypeKind::None);
+    IO.enumCase(SWK, "struct", SwiftNewTypeKind::Struct);
+    IO.enumCase(SWK, "enum",   SwiftNewTypeKind::Enum);
+  }
+};
+
+template <>
+struct MappingTraits<Typedef> {
+  static void mapping(IO &IO, Typedef &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(""));
+    IO.mapOptional("SwiftBridge",     T.SwiftBridge);
+    IO.mapOptional("NSErrorDomain",   T.NSErrorDomain);
+    IO.mapOptional("SwiftWrapper",    T.SwiftType);
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+struct TopLevelItems {
+  ClassesSeq Classes;
+  ClassesSeq Protocols;
+  FunctionsSeq Functions;
+  GlobalVariablesSeq Globals;
+  EnumConstantsSeq EnumConstants;
+  TagsSeq Tags;
+  TypedefsSeq Typedefs;
+};
+} // namespace
+
+namespace llvm {
+namespace yaml {
+static void mapTopLevelItems(IO &IO, TopLevelItems &TLI) {
+  IO.mapOptional("Classes",     TLI.Classes);
+  IO.mapOptional("Protocols",   TLI.Protocols);
+  IO.mapOptional("Functions",   TLI.Functions);
+  IO.mapOptional("Globals",     TLI.Globals);
+  IO.mapOptional("Enumerators", TLI.EnumConstants);
+  IO.mapOptional("Tags",        TLI.Tags);
+  IO.mapOptional("Typedefs",    TLI.Typedefs);
+}
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+struct Versioned {
+  VersionTuple Version;
+  TopLevelItems Items;
+};
+
+typedef std::vector<Versioned> VersionedSeq;
+} // namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Versioned)
+
+namespace llvm {
+namespace yaml {
+template <>
+struct MappingTraits<Versioned> {
+  static void mapping(IO &IO, Versioned &V) {
+    IO.mapRequired("Version", V.Version);
+    mapTopLevelItems(IO,      V.Items);
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+struct Module {
+  StringRef Name;
+  AvailabilityItem Availability;
+  TopLevelItems TopLevel;
+  VersionedSeq SwiftVersions;
+
+  llvm::Optional<bool> SwiftInferImportAsMember = {llvm::None};
+
+  LLVM_DUMP_METHOD void dump() /*const*/;
+};
+} // namespace
+
+namespace llvm {
+namespace yaml {
+template <>
+struct MappingTraits<Module> {
+  static void mapping(IO &IO, Module &M) {
+    IO.mapRequired("Name",                     M.Name);
+    IO.mapOptional("Availability",             M.Availability.Mode,
+                                               APIAvailability::Available);
+    IO.mapOptional("AvailabilityMsg",          M.Availability.Msg,
+                                               StringRef(""));
+    IO.mapOptional("SwiftInferImportAsMember", M.SwiftInferImportAsMember);
+    mapTopLevelItems(IO,                       M.TopLevel);
+    IO.mapOptional("SwiftVersions",            M.SwiftVersions);
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+void Module::dump() {
+  llvm::yaml::Output OS(llvm::errs());
+  OS << *this;
+}
+
+namespace {
+bool parseAPINotes(StringRef YI, Module &M,
+                   llvm::SourceMgr::DiagHandlerTy Diag, void *DiagContext) {
+  llvm::yaml::Input IS(YI, nullptr, Diag, DiagContext);
+  IS >> M;
+  return static_cast<bool>(IS.error());
+}
+}
+
+bool
+clang::api_notes::parseAndDumpAPINotes(StringRef YI, llvm::raw_ostream &OS) {
+  Module M;
+  if (parseAPINotes(YI, M, nullptr, nullptr))
+    return true;
+
+  llvm::yaml::Output YOS(OS);
+  YOS << M;
+
+  return false;
+}
Index: clang/include/clang/APINotes/Types.h
===================================================================
--- /dev/null
+++ clang/include/clang/APINotes/Types.h
@@ -0,0 +1,40 @@
+//===-- Types.h - API Notes Data Types --------------------------*- 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_CLANG_APINOTES_TYPES_H
+#define LLVM_CLANG_APINOTES_TYPES_H
+
+namespace clang {
+namespace api_notes {
+enum class RetainCountConventionKind {
+  None,
+  CFReturnsRetained,
+  CFReturnsNotRetained,
+  NSReturnsRetained,
+  NSReturnsNotRetained,
+};
+
+/// The payload for an enum_extensibility attribute. This is a tri-state rather
+/// than just a boolean because the presence of the attribute indicates
+/// auditing.
+enum class EnumExtensibilityKind {
+  None,
+  Open,
+  Closed,
+};
+
+/// The kind of a swift_wrapper/swift_newtype.
+enum class SwiftNewTypeKind {
+  None,
+  Struct,
+  Enum,
+};
+} // namespace api_notes
+} // namespace clang
+
+#endif
Index: clang/include/clang/APINotes/APINotesYAMLCompiler.h
===================================================================
--- /dev/null
+++ clang/include/clang/APINotes/APINotesYAMLCompiler.h
@@ -0,0 +1,24 @@
+//===-- APINotesYAMLCompiler.h - API Notes YAML Format 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_APINOTES_APINOTESYAMLCOMPILER_H
+#define LLVM_CLANG_APINOTES_APINOTESYAMLCOMPILER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace api_notes {
+/// Parses the APINotes YAML content and writes the representation back to the
+/// specified stream.  This provides a means of testing the YAML processing of
+/// the APINotes format.
+bool parseAndDumpAPINotes(llvm::StringRef YI, llvm::raw_ostream &OS);
+} // namespace api_notes
+} // namespace clang
+
+#endif
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to