[clang] [APINotes] Upstream APINotes YAML compiler (PR #71413)
Saleem Abdulrasool via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 13 07:40:58 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;
+
+ if (convertCommonType(TheClass, CInfo, TheClass.Name))
+ return;
+
+ if (TheClass.AuditedForNullability)
+ CInfo.setDefaultNullability(NullabilityKind::NonNull);
+ if (TheClass.SwiftImportAsNonGeneric)
+ CInfo.setSwiftImportAsNonGeneric(*TheClass.SwiftImportAsNonGeneric);
+ if (TheClass.SwiftObjCMembers)
+ CInfo.setSwiftObjCMembers(*TheClass.SwiftObjCMembers);
+
+ ContextID CtxID = Writer.addObjCContext(ParentContextID, TheClass.Name,
+ Kind, CInfo, SwiftVersion);
+
+ // Write all methods.
+ llvm::StringMap<std::pair<bool, bool>> KnownMethods;
+ for (const auto &method : TheClass.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 ? "-" : "+") + "[" + TheClass.Name + " " +
+ method.Selector + "]'");
+ continue;
+ }
+ Known = true;
+
+ convertMethod(method, CtxID, TheClass.Name, SwiftVersion);
+ }
+
+ // Write all properties.
+ llvm::StringSet<> KnownInstanceProperties;
+ llvm::StringSet<> KnownClassProperties;
+ for (const auto &Property : TheClass.Properties) {
+ // Check for duplicate property definitions.
+ if ((!Property.Kind || *Property.Kind == MethodKind::Instance) &&
+ !KnownInstanceProperties.insert(Property.Name).second) {
+ emitError("duplicate definition of instance property '" +
+ TheClass.Name + "." + Property.Name + "'");
+ continue;
+ }
+
+ if ((!Property.Kind || *Property.Kind == MethodKind::Class) &&
+ !KnownClassProperties.insert(Property.Name).second) {
+ emitError("duplicate definition of class property '" + TheClass.Name +
+ "." + Property.Name + "'");
+ continue;
+ }
+
+ // Translate from Property into ObjCPropertyInfo.
+ ObjCPropertyInfo PInfo;
+ convertAvailability(Property.Availability, PInfo, Property.Name);
+ PInfo.setSwiftPrivate(Property.SwiftPrivate);
+ PInfo.SwiftName = std::string(Property.SwiftName);
+ if (Property.Nullability)
+ PInfo.setNullabilityAudited(*Property.Nullability);
+ if (Property.SwiftImportAsAccessors)
+ PInfo.setSwiftImportAsAccessors(*Property.SwiftImportAsAccessors);
+ PInfo.setType(std::string(Property.Type));
+ if (Property.Kind) {
+ Writer.addObjCProperty(CtxID, Property.Name,
+ *Property.Kind == MethodKind::Instance, PInfo,
+ SwiftVersion);
+ } else {
+ // Add both instance and class properties with this name.
+ Writer.addObjCProperty(CtxID, Property.Name, true, PInfo, SwiftVersion);
+ Writer.addObjCProperty(CtxID, Property.Name, false, PInfo,
+ SwiftVersion);
+ }
----------------
compnerd wrote:
Okay - well, then I would say that it might be nice to hoist the comment from the else-case to before the condition.
https://github.com/llvm/llvm-project/pull/71413
More information about the cfe-commits
mailing list