[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
Egor Zhdan via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 13 07:47:49 PST 2023
================
@@ -635,3 +638,478 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI,
return false;
}
+
+namespace {
+using namespace api_notes;
+
+class YAMLConverter {
+ const Module &M;
+ 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)
+ : M(TheModule), Writer(TheModule.Name, SourceFile), OS(OS),
+ DiagHandler(DiagHandler), DiagHandlerCtxt(DiagHandlerCtxt),
+ ErrorOccured(false) {}
+
+ void convertAvailability(const AvailabilityItem &Availability,
+ CommonEntityInfo &CEI, llvm::StringRef APIName) {
+ // Populate the unavailability information.
+ CEI.Unavailable = (Availability.Mode == APIAvailability::None);
+ CEI.UnavailableInSwift = (Availability.Mode == APIAvailability::NonSwift);
+ if (CEI.Unavailable || CEI.UnavailableInSwift) {
+ CEI.UnavailableMsg = std::string(Availability.Msg);
+ } else {
+ if (!Availability.Msg.empty()) {
+ emitError(llvm::Twine("availability message for available API '") +
+ APIName + "' will not be used");
+ }
+ }
+ }
+
+ 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);
+ if (OutInfo.Params.size() <= P.Position) {
+ OutInfo.Params.resize(P.Position + 1);
+ }
+ OutInfo.Params[P.Position] |= PI;
+ }
+ }
+
+ void convertNullability(const NullabilitySeq &Nullability,
+ std::optional<NullabilityKind> ReturnNullability,
+ FunctionInfo &OutInfo, llvm::StringRef APIName) {
+ if (Nullability.size() > FunctionInfo::getMaxNullabilityIndex()) {
+ emitError(llvm::Twine("nullability info for '") + APIName +
+ "' does not fit");
+ return;
+ }
+
+ bool audited = false;
+ unsigned int idx = 1;
+ for (const auto &N : Nullability)
+ OutInfo.addTypeInfo(idx++, N);
+ audited = Nullability.size() > 0 || ReturnNullability;
+ if (audited)
+ OutInfo.addTypeInfo(0, ReturnNullability ? *ReturnNullability
+ : NullabilityKind::NonNull);
+ if (!audited)
+ return;
+ OutInfo.NullabilityAudited = audited;
+ OutInfo.NumAdjustedNullable = idx;
+ }
+
+ /// Convert the common parts of an entity from YAML.
+ template <typename T>
+ void convertCommonEntity(const T &Common, CommonEntityInfo &Info,
+ StringRef APIName) {
+ convertAvailability(Common.Availability, Info, APIName);
+ Info.setSwiftPrivate(Common.SwiftPrivate);
+ Info.SwiftName = std::string(Common.SwiftName);
+ }
+
+ /// Convert the common parts of a type entity from YAML.
+ template <typename T>
+ void convertCommonType(const T &Common, CommonTypeInfo &Info,
+ StringRef APIName) {
+ convertCommonEntity(Common, Info, APIName);
+ if (Common.SwiftBridge)
+ Info.setSwiftBridge(std::string(*Common.SwiftBridge));
+ Info.setNSErrorDomain(Common.NSErrorDomain);
+ }
+
+ // Translate from Method into ObjCMethodInfo and write it out.
+ void convertMethod(const Method &M, ContextID ClassID, StringRef ClassName,
+ VersionTuple SwiftVersion) {
+ ObjCMethodInfo MI;
+ convertCommonEntity(M, MI, M.Selector);
+
+ // Check if the selector ends with ':' to determine if it takes arguments.
+ bool takesArguments = M.Selector.endswith(":");
+
+ // Split the selector into pieces.
+ llvm::SmallVector<StringRef, 4> Args;
+ M.Selector.split(Args, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+ if (!takesArguments && Args.size() > 1) {
+ emitError("selector '" + M.Selector + "' is missing a ':' at the end");
+ return;
+ }
+
+ // Construct ObjCSelectorRef.
+ api_notes::ObjCSelectorRef Selector;
+ Selector.NumArgs = !takesArguments ? 0 : Args.size();
+ Selector.Identifiers = Args;
+
+ // Translate the initializer info.
+ MI.DesignatedInit = M.DesignatedInit;
+ MI.RequiredInit = M.Required;
+ if (M.FactoryAsInit != FactoryAsInitKind::Infer)
+ emitError("'FactoryAsInit' is no longer valid; use 'SwiftName' instead");
+
+ MI.ResultType = std::string(M.ResultType);
+
+ // Translate parameter information.
+ convertParams(M.Params, MI);
+
+ // Translate nullability info.
+ convertNullability(M.Nullability, M.NullabilityOfRet, MI, M.Selector);
+
+ MI.setRetainCountConvention(M.RetainCountConvention);
+
+ // Write it.
+ Writer.addObjCMethod(ClassID, Selector, M.Kind == MethodKind::Instance, MI,
+ SwiftVersion);
+ }
+
+ void convertContext(std::optional<ContextID> ParentContextID, const Class &C,
+ ContextKind Kind, VersionTuple SwiftVersion) {
+ // Write the class.
+ ObjCContextInfo CI;
+ convertCommonType(C, CI, C.Name);
+
+ if (C.AuditedForNullability)
+ CI.setDefaultNullability(NullabilityKind::NonNull);
+ if (C.SwiftImportAsNonGeneric)
+ CI.setSwiftImportAsNonGeneric(*C.SwiftImportAsNonGeneric);
+ if (C.SwiftObjCMembers)
+ CI.setSwiftObjCMembers(*C.SwiftObjCMembers);
+
+ ContextID CtxID =
+ Writer.addObjCContext(ParentContextID, C.Name, Kind, CI, SwiftVersion);
+
+ // Write all methods.
+ llvm::StringMap<std::pair<bool, bool>> KnownMethods;
+ for (const auto &method : C.Methods) {
+ // Check for duplicate method definitions.
+ bool IsInstanceMethod = method.Kind == MethodKind::Instance;
+ bool &Known = IsInstanceMethod ? KnownMethods[method.Selector].first
+ : KnownMethods[method.Selector].second;
+ if (Known) {
+ emitError(llvm::Twine("duplicate definition of method '") +
+ (IsInstanceMethod ? "-" : "+") + "[" + C.Name + " " +
+ method.Selector + "]'");
+ continue;
+ }
+ Known = true;
+
+ convertMethod(method, CtxID, C.Name, SwiftVersion);
+ }
+
+ // Write all properties.
+ llvm::StringSet<> KnownInstanceProperties;
+ llvm::StringSet<> KnownClassProperties;
+ for (const auto &Property : C.Properties) {
+ // Check for duplicate property definitions.
+ if ((!Property.Kind || *Property.Kind == MethodKind::Instance) &&
+ !KnownInstanceProperties.insert(Property.Name).second) {
+ emitError(llvm::Twine("duplicate definition of instance property '") +
+ C.Name + "." + Property.Name + "'");
+ continue;
+ }
+
+ if ((!Property.Kind || *Property.Kind == MethodKind::Class) &&
+ !KnownClassProperties.insert(Property.Name).second) {
+ emitError(llvm::Twine("duplicate definition of class property '") +
+ C.Name + "." + Property.Name + "'");
+ continue;
+ }
+
+ // Translate from Property into ObjCPropertyInfo.
+ ObjCPropertyInfo PI;
+ convertAvailability(Property.Availability, PI, Property.Name);
+ PI.setSwiftPrivate(Property.SwiftPrivate);
+ PI.SwiftName = std::string(Property.SwiftName);
+ if (Property.Nullability)
+ PI.setNullabilityAudited(*Property.Nullability);
+ if (Property.SwiftImportAsAccessors)
+ PI.setSwiftImportAsAccessors(*Property.SwiftImportAsAccessors);
+ PI.setType(std::string(Property.Type));
+ if (Property.Kind) {
+ Writer.addObjCProperty(CtxID, Property.Name,
+ *Property.Kind == MethodKind::Instance, PI,
+ SwiftVersion);
+ } else {
+ // Add both instance and class properties with this name.
+ Writer.addObjCProperty(CtxID, Property.Name, true, PI, SwiftVersion);
+ Writer.addObjCProperty(CtxID, Property.Name, false, PI, SwiftVersion);
+ }
+ }
+ }
+
+ void convertNamespaceContext(std::optional<ContextID> ParentContextID,
+ const Namespace &TheNamespace,
+ VersionTuple SwiftVersion) {
+ // Write the namespace.
+ ObjCContextInfo CI;
+ convertCommonEntity(TheNamespace, CI, TheNamespace.Name);
+
+ ContextID CtxID =
+ Writer.addObjCContext(ParentContextID, TheNamespace.Name,
+ ContextKind::Namespace, CI, SwiftVersion);
+
+ convertTopLevelItems(Context(CtxID, ContextKind::Namespace),
+ TheNamespace.Items, SwiftVersion);
+ }
+
+ void convertTopLevelItems(std::optional<Context> Ctx,
+ const TopLevelItems &TLItems,
+ VersionTuple SwiftVersion) {
+ std::optional<ContextID> CtxID =
+ Ctx ? std::optional(Ctx->id) : std::nullopt;
+
+ // Write all classes.
+ llvm::StringSet<> KnownClasses;
+ for (const auto &Class : TLItems.Classes) {
+ // Check for duplicate class definitions.
+ if (!KnownClasses.insert(Class.Name).second) {
+ emitError(llvm::Twine("multiple definitions of class '") + Class.Name +
+ "'");
+ continue;
+ }
+
+ convertContext(CtxID, Class, ContextKind::ObjCClass, SwiftVersion);
+ }
+
+ // Write all protocols.
+ llvm::StringSet<> KnownProtocols;
+ for (const auto &Protocol : TLItems.Protocols) {
+ // Check for duplicate protocol definitions.
+ if (!KnownProtocols.insert(Protocol.Name).second) {
+ emitError(llvm::Twine("multiple definitions of protocol '") +
+ Protocol.Name + "'");
+ continue;
+ }
+
+ convertContext(CtxID, Protocol, ContextKind::ObjCProtocol, SwiftVersion);
+ }
+
+ // Write all namespaces.
+ llvm::StringSet<> KnownNamespaces;
+ for (const auto &Namespace : TLItems.Namespaces) {
+ // Check for duplicate namespace definitions.
+ if (!KnownNamespaces.insert(Namespace.Name).second) {
+ emitError(llvm::Twine("multiple definitions of namespace '") +
+ Namespace.Name + "'");
+ continue;
+ }
+
+ convertNamespaceContext(CtxID, Namespace, SwiftVersion);
+ }
+
+ // Write all global variables.
+ llvm::StringSet<> KnownGlobals;
+ for (const auto &Global : TLItems.Globals) {
+ // Check for duplicate global variables.
+ if (!KnownGlobals.insert(Global.Name).second) {
+ emitError(llvm::Twine("multiple definitions of global variable '") +
+ Global.Name + "'");
+ continue;
+ }
+
+ GlobalVariableInfo GVI;
+ convertAvailability(Global.Availability, GVI, Global.Name);
+ GVI.setSwiftPrivate(Global.SwiftPrivate);
+ GVI.SwiftName = std::string(Global.SwiftName);
+ if (Global.Nullability)
+ GVI.setNullabilityAudited(*Global.Nullability);
+ GVI.setType(std::string(Global.Type));
+ Writer.addGlobalVariable(Ctx, Global.Name, GVI, SwiftVersion);
+ }
+
+ // Write all global functions.
+ llvm::StringSet<> KnownFunctions;
+ for (const auto &Function : TLItems.Functions) {
+ // Check for duplicate global functions.
+ if (!KnownFunctions.insert(Function.Name).second) {
+ emitError(llvm::Twine("multiple definitions of global function '") +
+ Function.Name + "'");
+ continue;
+ }
+
+ GlobalFunctionInfo GFI;
+ convertAvailability(Function.Availability, GFI, Function.Name);
+ GFI.setSwiftPrivate(Function.SwiftPrivate);
+ GFI.SwiftName = std::string(Function.SwiftName);
+ convertParams(Function.Params, GFI);
+ convertNullability(Function.Nullability, Function.NullabilityOfRet, GFI,
+ Function.Name);
+ GFI.ResultType = std::string(Function.ResultType);
+ GFI.setRetainCountConvention(Function.RetainCountConvention);
+ Writer.addGlobalFunction(Ctx, Function.Name, GFI, SwiftVersion);
+ }
+
+ // Write all enumerators.
+ llvm::StringSet<> KnownEnumConstants;
+ for (const auto &EnumConstant : TLItems.EnumConstants) {
+ // Check for duplicate enumerators
+ if (!KnownEnumConstants.insert(EnumConstant.Name).second) {
+ emitError(llvm::Twine("multiple definitions of enumerator '") +
+ EnumConstant.Name + "'");
+ continue;
+ }
+
+ EnumConstantInfo ECI;
+ convertAvailability(EnumConstant.Availability, ECI, EnumConstant.Name);
+ ECI.setSwiftPrivate(EnumConstant.SwiftPrivate);
+ ECI.SwiftName = std::string(EnumConstant.SwiftName);
+ Writer.addEnumConstant(EnumConstant.Name, ECI, SwiftVersion);
+ }
+
+ // Write all tags.
+ llvm::StringSet<> KnownTags;
+ for (const auto &Tag : TLItems.Tags) {
+ // Check for duplicate tag definitions.
+ if (!KnownTags.insert(Tag.Name).second) {
+ emitError(llvm::Twine("multiple definitions of tag '") + Tag.Name +
+ "'");
+ continue;
+ }
+
+ TagInfo TI;
+ convertCommonType(Tag, TI, Tag.Name);
+
+ if ((Tag.SwiftRetainOp || Tag.SwiftReleaseOp) && !Tag.SwiftImportAs) {
+ emitError(llvm::Twine("should declare SwiftImportAs to use "
+ "SwiftRetainOp and SwiftReleaseOp (for ") +
+ Tag.Name + ")");
+ continue;
+ }
+ if (Tag.SwiftReleaseOp.has_value() != Tag.SwiftRetainOp.has_value()) {
+ emitError(llvm::Twine("should declare both SwiftReleaseOp and "
+ "SwiftRetainOp (for ") +
+ Tag.Name + ")");
+ continue;
+ }
+
+ if (Tag.SwiftImportAs)
+ TI.SwiftImportAs = Tag.SwiftImportAs;
+ if (Tag.SwiftRetainOp)
+ TI.SwiftRetainOp = Tag.SwiftRetainOp;
+ if (Tag.SwiftReleaseOp)
+ TI.SwiftReleaseOp = Tag.SwiftReleaseOp;
+
+ if (Tag.EnumConvenienceKind) {
+ if (Tag.EnumExtensibility) {
+ emitError(
+ llvm::Twine("cannot mix EnumKind and EnumExtensibility (for ") +
+ Tag.Name + ")");
+ continue;
+ }
+ if (Tag.FlagEnum) {
+ emitError(llvm::Twine("cannot mix EnumKind and FlagEnum (for ") +
+ Tag.Name + ")");
+ continue;
+ }
+ switch (*Tag.EnumConvenienceKind) {
+ case EnumConvenienceAliasKind::None:
+ TI.EnumExtensibility = EnumExtensibilityKind::None;
+ TI.setFlagEnum(false);
+ break;
+ case EnumConvenienceAliasKind::CFEnum:
+ TI.EnumExtensibility = EnumExtensibilityKind::Open;
+ TI.setFlagEnum(false);
+ break;
+ case EnumConvenienceAliasKind::CFOptions:
+ TI.EnumExtensibility = EnumExtensibilityKind::Open;
+ TI.setFlagEnum(true);
+ break;
+ case EnumConvenienceAliasKind::CFClosedEnum:
+ TI.EnumExtensibility = EnumExtensibilityKind::Closed;
+ TI.setFlagEnum(false);
+ break;
+ }
+ } else {
+ TI.EnumExtensibility = Tag.EnumExtensibility;
+ TI.setFlagEnum(Tag.FlagEnum);
+ }
+
+ Writer.addTag(Ctx, Tag.Name, TI, SwiftVersion);
+ }
+
+ // Write all typedefs.
+ llvm::StringSet<> KnownTypedefs;
+ for (const auto &Typedef : TLItems.Typedefs) {
+ // Check for duplicate typedef definitions.
+ if (!KnownTypedefs.insert(Typedef.Name).second) {
+ emitError(llvm::Twine("multiple definitions of typedef '") +
+ Typedef.Name + "'");
+ continue;
+ }
+
+ TypedefInfo TInfo;
+ convertCommonType(Typedef, TInfo, Typedef.Name);
+ TInfo.SwiftWrapper = Typedef.SwiftType;
+
+ Writer.addTypedef(Ctx, Typedef.Name, TInfo, SwiftVersion);
+ }
+ }
+
+ bool convertModule() {
+ // Write the top-level items.
+ convertTopLevelItems(/* context */ std::nullopt, M.TopLevel,
+ VersionTuple());
+
+ // Convert the versioned information.
+ for (const auto &Versioned : M.SwiftVersions) {
+ convertTopLevelItems(/* context */ std::nullopt, Versioned.Items,
+ Versioned.Version);
+ }
----------------
egorzhdan wrote:
Done
https://github.com/llvm/llvm-project/pull/71413
More information about the cfe-commits
mailing list