[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)

Egor Zhdan via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 10 05:17:02 PST 2023


================
@@ -635,3 +638,496 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI,
 
   return false;
 }
+
+namespace {
+using namespace api_notes;
+
+class YAMLConverter {
+  const Module &TheModule;
+  APINotesWriter Writer;
+  llvm::raw_ostream &OS;
+  llvm::SourceMgr::DiagHandlerTy DiagHandler;
+  void *DiagHandlerCtxt;
+  bool ErrorOccured;
+
+  /// Emit a diagnostic
+  bool emitError(llvm::Twine Message) {
+    DiagHandler(
+        llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Message.str()),
+        DiagHandlerCtxt);
+    ErrorOccured = true;
+    return true;
+  }
+
+public:
+  YAMLConverter(const Module &TheModule, const FileEntry *SourceFile,
+                llvm::raw_ostream &OS,
+                llvm::SourceMgr::DiagHandlerTy DiagHandler,
+                void *DiagHandlerCtxt)
+      : TheModule(TheModule), Writer(TheModule.Name, SourceFile), OS(OS),
+        DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt),
+        ErrorOccured(false) {}
+
+  bool convertAvailability(const AvailabilityItem &In,
+                           CommonEntityInfo &OutInfo, llvm::StringRef APIName) {
+    // Populate the unavailability information.
+    OutInfo.Unavailable = (In.Mode == APIAvailability::None);
+    OutInfo.UnavailableInSwift = (In.Mode == APIAvailability::NonSwift);
+    if (OutInfo.Unavailable || OutInfo.UnavailableInSwift) {
+      OutInfo.UnavailableMsg = std::string(In.Msg);
+    } else {
+      if (!In.Msg.empty()) {
+        emitError("availability message for available API '" + APIName +
+                  "' will not be used");
+      }
+    }
+    return false;
+  }
+
+  void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo) {
+    for (const auto &P : Params) {
+      ParamInfo PI;
+      if (P.Nullability)
+        PI.setNullabilityAudited(*P.Nullability);
+      PI.setNoEscape(P.NoEscape);
+      PI.setType(std::string(P.Type));
+      PI.setRetainCountConvention(P.RetainCountConvention);
+      while (OutInfo.Params.size() <= P.Position) {
+        OutInfo.Params.push_back(ParamInfo());
+      }
+      OutInfo.Params[P.Position] |= PI;
+    }
+  }
+
+  void convertNullability(const NullabilitySeq &Nullability,
+                          std::optional<NullabilityKind> NullabilityOfRet,
+                          FunctionInfo &OutInfo, llvm::StringRef APIName) {
+    if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) {
+      emitError("nullability info for " + APIName + " does not fit");
+      return;
+    }
+
+    bool audited = false;
+    unsigned int idx = 1;
+    for (auto i = Nullability.begin(), e = Nullability.end(); i != e;
+         ++i, ++idx) {
+      OutInfo.addTypeInfo(idx, *i);
+      audited = true;
+    }
+    if (NullabilityOfRet) {
+      OutInfo.addTypeInfo(0, *NullabilityOfRet);
+      audited = true;
+    } else if (audited) {
+      OutInfo.addTypeInfo(0, NullabilityKind::NonNull);
+    }
+    if (audited) {
+      OutInfo.NullabilityAudited = audited;
+      OutInfo.NumAdjustedNullable = idx;
+    }
+  }
+
+  /// Convert the common parts of an entity from YAML.
+  template <typename T>
+  bool convertCommon(const T &Common, CommonEntityInfo &Info,
+                     StringRef APIName) {
+    convertAvailability(Common.Availability, Info, APIName);
+    Info.setSwiftPrivate(Common.SwiftPrivate);
+    Info.SwiftName = std::string(Common.SwiftName);
+    return false;
+  }
+
+  /// Convert the common parts of a type entity from YAML.
+  template <typename T>
+  bool convertCommonType(const T &Common, CommonTypeInfo &Info,
+                         StringRef APIName) {
+    if (convertCommon(Common, Info, APIName))
+      return true;
+
+    if (Common.SwiftBridge)
+      Info.setSwiftBridge(std::string(*Common.SwiftBridge));
+    Info.setNSErrorDomain(Common.NSErrorDomain);
+    return false;
+  }
+
+  // Translate from Method into ObjCMethodInfo and write it out.
+  void convertMethod(const Method &TheMethod, ContextID ClassID,
+                     StringRef ClassName, VersionTuple SwiftVersion) {
+    ObjCMethodInfo MInfo;
+
+    if (convertCommon(TheMethod, MInfo, TheMethod.Selector))
+      return;
+
+    // Check if the selector ends with ':' to determine if it takes arguments.
+    bool takesArguments = TheMethod.Selector.endswith(":");
+
+    // Split the selector into pieces.
+    llvm::SmallVector<StringRef, 4> a;
+    TheMethod.Selector.split(a, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+    if (!takesArguments && a.size() > 1) {
+      emitError("selector " + TheMethod.Selector +
+                "is missing a ':' at the end");
+      return;
+    }
+
+    // Construct ObjCSelectorRef.
+    api_notes::ObjCSelectorRef selectorRef;
+    selectorRef.NumArgs = !takesArguments ? 0 : a.size();
+    selectorRef.Identifiers = a;
+
+    // Translate the initializer info.
+    MInfo.DesignatedInit = TheMethod.DesignatedInit;
+    MInfo.RequiredInit = TheMethod.Required;
+    if (TheMethod.FactoryAsInit != FactoryAsInitKind::Infer) {
+      emitError("'FactoryAsInit' is no longer valid; "
+                "use 'SwiftName' instead");
+    }
+    MInfo.ResultType = std::string(TheMethod.ResultType);
+
+    // Translate parameter information.
+    convertParams(TheMethod.Params, MInfo);
+
+    // Translate nullability info.
+    convertNullability(TheMethod.Nullability, TheMethod.NullabilityOfRet, MInfo,
+                       TheMethod.Selector);
+
+    MInfo.setRetainCountConvention(TheMethod.RetainCountConvention);
+
+    // Write it.
+    Writer.addObjCMethod(ClassID, selectorRef,
+                         TheMethod.Kind == MethodKind::Instance, MInfo,
+                         SwiftVersion);
+  }
+
+  void convertContext(std::optional<ContextID> ParentContextID,
+                      const Class &TheClass, ContextKind Kind,
+                      VersionTuple SwiftVersion) {
+    // Write the class.
+    ObjCContextInfo CInfo;
----------------
egorzhdan wrote:

Renamed this to `CI` for consistency with the rest of the methods here

https://github.com/llvm/llvm-project/pull/71413


More information about the cfe-commits mailing list