1 //===-- APINotesYAMLCompiler.cpp - API Notes YAML Format Reader -*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // The types defined locally are designed to represent the YAML state, which 10 // adds an additional bit of state: e.g. a tri-state boolean attribute (yes, no, 11 // not applied) becomes a tri-state boolean + present. As a result, while these 12 // enumerations appear to be redefining constants from the attributes table 13 // data, they are distinct. 14 // 15 16 #include "clang/APINotes/APINotesYAMLCompiler.h" 17 #include "clang/APINotes/Types.h" 18 #include "clang/Basic/LLVM.h" 19 #include "clang/Basic/Specifiers.h" 20 #include "llvm/Support/VersionTuple.h" 21 #include "llvm/Support/YAMLParser.h" 22 #include "llvm/Support/YAMLTraits.h" 23 #include <optional> 24 #include <vector> 25 using namespace clang; 26 using namespace api_notes; 27 28 namespace { 29 enum class APIAvailability { 30 Available = 0, 31 OSX, 32 IOS, 33 None, 34 NonSwift, 35 }; 36 } // namespace 37 38 namespace llvm { 39 namespace yaml { 40 template <> struct ScalarEnumerationTraits<APIAvailability> { 41 static void enumeration(IO &IO, APIAvailability &AA) { 42 IO.enumCase(AA, "OSX", APIAvailability::OSX); 43 IO.enumCase(AA, "iOS", APIAvailability::IOS); 44 IO.enumCase(AA, "none", APIAvailability::None); 45 IO.enumCase(AA, "nonswift", APIAvailability::NonSwift); 46 IO.enumCase(AA, "available", APIAvailability::Available); 47 } 48 }; 49 } // namespace yaml 50 } // namespace llvm 51 52 namespace { 53 enum class MethodKind { 54 Class, 55 Instance, 56 }; 57 } // namespace 58 59 namespace llvm { 60 namespace yaml { 61 template <> struct ScalarEnumerationTraits<MethodKind> { 62 static void enumeration(IO &IO, MethodKind &MK) { 63 IO.enumCase(MK, "Class", MethodKind::Class); 64 IO.enumCase(MK, "Instance", MethodKind::Instance); 65 } 66 }; 67 } // namespace yaml 68 } // namespace llvm 69 70 namespace { 71 struct Param { 72 unsigned Position; 73 std::optional<bool> NoEscape = false; 74 std::optional<NullabilityKind> Nullability; 75 std::optional<RetainCountConventionKind> RetainCountConvention; 76 StringRef Type; 77 }; 78 79 typedef std::vector<Param> ParamsSeq; 80 } // namespace 81 82 LLVM_YAML_IS_SEQUENCE_VECTOR(Param) 83 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(NullabilityKind) 84 85 namespace llvm { 86 namespace yaml { 87 template <> struct ScalarEnumerationTraits<NullabilityKind> { 88 static void enumeration(IO &IO, NullabilityKind &NK) { 89 IO.enumCase(NK, "Nonnull", NullabilityKind::NonNull); 90 IO.enumCase(NK, "Optional", NullabilityKind::Nullable); 91 IO.enumCase(NK, "Unspecified", NullabilityKind::Unspecified); 92 IO.enumCase(NK, "NullableResult", NullabilityKind::NullableResult); 93 // TODO: Mapping this to it's own value would allow for better cross 94 // checking. Also the default should be Unknown. 95 IO.enumCase(NK, "Scalar", NullabilityKind::Unspecified); 96 97 // Aliases for compatibility with existing APINotes. 98 IO.enumCase(NK, "N", NullabilityKind::NonNull); 99 IO.enumCase(NK, "O", NullabilityKind::Nullable); 100 IO.enumCase(NK, "U", NullabilityKind::Unspecified); 101 IO.enumCase(NK, "S", NullabilityKind::Unspecified); 102 } 103 }; 104 105 template <> struct ScalarEnumerationTraits<RetainCountConventionKind> { 106 static void enumeration(IO &IO, RetainCountConventionKind &RCCK) { 107 IO.enumCase(RCCK, "none", RetainCountConventionKind::None); 108 IO.enumCase(RCCK, "CFReturnsRetained", 109 RetainCountConventionKind::CFReturnsRetained); 110 IO.enumCase(RCCK, "CFReturnsNotRetained", 111 RetainCountConventionKind::CFReturnsNotRetained); 112 IO.enumCase(RCCK, "NSReturnsRetained", 113 RetainCountConventionKind::NSReturnsRetained); 114 IO.enumCase(RCCK, "NSReturnsNotRetained", 115 RetainCountConventionKind::NSReturnsNotRetained); 116 } 117 }; 118 119 template <> struct MappingTraits<Param> { 120 static void mapping(IO &IO, Param &P) { 121 IO.mapRequired("Position", P.Position); 122 IO.mapOptional("Nullability", P.Nullability, std::nullopt); 123 IO.mapOptional("RetainCountConvention", P.RetainCountConvention); 124 IO.mapOptional("NoEscape", P.NoEscape); 125 IO.mapOptional("Type", P.Type, StringRef("")); 126 } 127 }; 128 } // namespace yaml 129 } // namespace llvm 130 131 namespace { 132 typedef std::vector<NullabilityKind> NullabilitySeq; 133 134 struct AvailabilityItem { 135 APIAvailability Mode = APIAvailability::Available; 136 StringRef Msg; 137 }; 138 139 /// Old attribute deprecated in favor of SwiftName. 140 enum class FactoryAsInitKind { 141 /// Infer based on name and type (the default). 142 Infer, 143 /// Treat as a class method. 144 AsClassMethod, 145 /// Treat as an initializer. 146 AsInitializer, 147 }; 148 149 struct Method { 150 StringRef Selector; 151 MethodKind Kind; 152 ParamsSeq Params; 153 NullabilitySeq Nullability; 154 std::optional<NullabilityKind> NullabilityOfRet; 155 std::optional<RetainCountConventionKind> RetainCountConvention; 156 AvailabilityItem Availability; 157 std::optional<bool> SwiftPrivate; 158 StringRef SwiftName; 159 FactoryAsInitKind FactoryAsInit = FactoryAsInitKind::Infer; 160 bool DesignatedInit = false; 161 bool Required = false; 162 StringRef ResultType; 163 }; 164 165 typedef std::vector<Method> MethodsSeq; 166 } // namespace 167 168 LLVM_YAML_IS_SEQUENCE_VECTOR(Method) 169 170 namespace llvm { 171 namespace yaml { 172 template <> struct ScalarEnumerationTraits<FactoryAsInitKind> { 173 static void enumeration(IO &IO, FactoryAsInitKind &FIK) { 174 IO.enumCase(FIK, "A", FactoryAsInitKind::Infer); 175 IO.enumCase(FIK, "C", FactoryAsInitKind::AsClassMethod); 176 IO.enumCase(FIK, "I", FactoryAsInitKind::AsInitializer); 177 } 178 }; 179 180 template <> struct MappingTraits<Method> { 181 static void mapping(IO &IO, Method &M) { 182 IO.mapRequired("Selector", M.Selector); 183 IO.mapRequired("MethodKind", M.Kind); 184 IO.mapOptional("Parameters", M.Params); 185 IO.mapOptional("Nullability", M.Nullability); 186 IO.mapOptional("NullabilityOfRet", M.NullabilityOfRet, std::nullopt); 187 IO.mapOptional("RetainCountConvention", M.RetainCountConvention); 188 IO.mapOptional("Availability", M.Availability.Mode, 189 APIAvailability::Available); 190 IO.mapOptional("AvailabilityMsg", M.Availability.Msg, StringRef("")); 191 IO.mapOptional("SwiftPrivate", M.SwiftPrivate); 192 IO.mapOptional("SwiftName", M.SwiftName, StringRef("")); 193 IO.mapOptional("FactoryAsInit", M.FactoryAsInit, FactoryAsInitKind::Infer); 194 IO.mapOptional("DesignatedInit", M.DesignatedInit, false); 195 IO.mapOptional("Required", M.Required, false); 196 IO.mapOptional("ResultType", M.ResultType, StringRef("")); 197 } 198 }; 199 } // namespace yaml 200 } // namespace llvm 201 202 namespace { 203 struct Property { 204 StringRef Name; 205 std::optional<MethodKind> Kind; 206 std::optional<NullabilityKind> Nullability; 207 AvailabilityItem Availability; 208 std::optional<bool> SwiftPrivate; 209 StringRef SwiftName; 210 std::optional<bool> SwiftImportAsAccessors; 211 StringRef Type; 212 }; 213 214 typedef std::vector<Property> PropertiesSeq; 215 } // namespace 216 217 LLVM_YAML_IS_SEQUENCE_VECTOR(Property) 218 219 namespace llvm { 220 namespace yaml { 221 template <> struct MappingTraits<Property> { 222 static void mapping(IO &IO, Property &P) { 223 IO.mapRequired("Name", P.Name); 224 IO.mapOptional("PropertyKind", P.Kind); 225 IO.mapOptional("Nullability", P.Nullability, std::nullopt); 226 IO.mapOptional("Availability", P.Availability.Mode, 227 APIAvailability::Available); 228 IO.mapOptional("AvailabilityMsg", P.Availability.Msg, StringRef("")); 229 IO.mapOptional("SwiftPrivate", P.SwiftPrivate); 230 IO.mapOptional("SwiftName", P.SwiftName, StringRef("")); 231 IO.mapOptional("SwiftImportAsAccessors", P.SwiftImportAsAccessors); 232 IO.mapOptional("Type", P.Type, StringRef("")); 233 } 234 }; 235 } // namespace yaml 236 } // namespace llvm 237 238 namespace { 239 struct Class { 240 StringRef Name; 241 bool AuditedForNullability = false; 242 AvailabilityItem Availability; 243 std::optional<bool> SwiftPrivate; 244 StringRef SwiftName; 245 std::optional<StringRef> SwiftBridge; 246 std::optional<StringRef> NSErrorDomain; 247 std::optional<bool> SwiftImportAsNonGeneric; 248 std::optional<bool> SwiftObjCMembers; 249 MethodsSeq Methods; 250 PropertiesSeq Properties; 251 }; 252 253 typedef std::vector<Class> ClassesSeq; 254 } // namespace 255 256 LLVM_YAML_IS_SEQUENCE_VECTOR(Class) 257 258 namespace llvm { 259 namespace yaml { 260 template <> struct MappingTraits<Class> { 261 static void mapping(IO &IO, Class &C) { 262 IO.mapRequired("Name", C.Name); 263 IO.mapOptional("AuditedForNullability", C.AuditedForNullability, false); 264 IO.mapOptional("Availability", C.Availability.Mode, 265 APIAvailability::Available); 266 IO.mapOptional("AvailabilityMsg", C.Availability.Msg, StringRef("")); 267 IO.mapOptional("SwiftPrivate", C.SwiftPrivate); 268 IO.mapOptional("SwiftName", C.SwiftName, StringRef("")); 269 IO.mapOptional("SwiftBridge", C.SwiftBridge); 270 IO.mapOptional("NSErrorDomain", C.NSErrorDomain); 271 IO.mapOptional("SwiftImportAsNonGeneric", C.SwiftImportAsNonGeneric); 272 IO.mapOptional("SwiftObjCMembers", C.SwiftObjCMembers); 273 IO.mapOptional("Methods", C.Methods); 274 IO.mapOptional("Properties", C.Properties); 275 } 276 }; 277 } // namespace yaml 278 } // namespace llvm 279 280 namespace { 281 struct Function { 282 StringRef Name; 283 ParamsSeq Params; 284 NullabilitySeq Nullability; 285 std::optional<NullabilityKind> NullabilityOfRet; 286 std::optional<api_notes::RetainCountConventionKind> RetainCountConvention; 287 AvailabilityItem Availability; 288 std::optional<bool> SwiftPrivate; 289 StringRef SwiftName; 290 StringRef Type; 291 StringRef ResultType; 292 }; 293 294 typedef std::vector<Function> FunctionsSeq; 295 } // namespace 296 297 LLVM_YAML_IS_SEQUENCE_VECTOR(Function) 298 299 namespace llvm { 300 namespace yaml { 301 template <> struct MappingTraits<Function> { 302 static void mapping(IO &IO, Function &F) { 303 IO.mapRequired("Name", F.Name); 304 IO.mapOptional("Parameters", F.Params); 305 IO.mapOptional("Nullability", F.Nullability); 306 IO.mapOptional("NullabilityOfRet", F.NullabilityOfRet, std::nullopt); 307 IO.mapOptional("RetainCountConvention", F.RetainCountConvention); 308 IO.mapOptional("Availability", F.Availability.Mode, 309 APIAvailability::Available); 310 IO.mapOptional("AvailabilityMsg", F.Availability.Msg, StringRef("")); 311 IO.mapOptional("SwiftPrivate", F.SwiftPrivate); 312 IO.mapOptional("SwiftName", F.SwiftName, StringRef("")); 313 IO.mapOptional("ResultType", F.ResultType, StringRef("")); 314 } 315 }; 316 } // namespace yaml 317 } // namespace llvm 318 319 namespace { 320 struct GlobalVariable { 321 StringRef Name; 322 std::optional<NullabilityKind> Nullability; 323 AvailabilityItem Availability; 324 std::optional<bool> SwiftPrivate; 325 StringRef SwiftName; 326 StringRef Type; 327 }; 328 329 typedef std::vector<GlobalVariable> GlobalVariablesSeq; 330 } // namespace 331 332 LLVM_YAML_IS_SEQUENCE_VECTOR(GlobalVariable) 333 334 namespace llvm { 335 namespace yaml { 336 template <> struct MappingTraits<GlobalVariable> { 337 static void mapping(IO &IO, GlobalVariable &GV) { 338 IO.mapRequired("Name", GV.Name); 339 IO.mapOptional("Nullability", GV.Nullability, std::nullopt); 340 IO.mapOptional("Availability", GV.Availability.Mode, 341 APIAvailability::Available); 342 IO.mapOptional("AvailabilityMsg", GV.Availability.Msg, StringRef("")); 343 IO.mapOptional("SwiftPrivate", GV.SwiftPrivate); 344 IO.mapOptional("SwiftName", GV.SwiftName, StringRef("")); 345 IO.mapOptional("Type", GV.Type, StringRef("")); 346 } 347 }; 348 } // namespace yaml 349 } // namespace llvm 350 351 namespace { 352 struct EnumConstant { 353 StringRef Name; 354 AvailabilityItem Availability; 355 std::optional<bool> SwiftPrivate; 356 StringRef SwiftName; 357 }; 358 359 typedef std::vector<EnumConstant> EnumConstantsSeq; 360 } // namespace 361 362 LLVM_YAML_IS_SEQUENCE_VECTOR(EnumConstant) 363 364 namespace llvm { 365 namespace yaml { 366 template <> struct MappingTraits<EnumConstant> { 367 static void mapping(IO &IO, EnumConstant &EC) { 368 IO.mapRequired("Name", EC.Name); 369 IO.mapOptional("Availability", EC.Availability.Mode, 370 APIAvailability::Available); 371 IO.mapOptional("AvailabilityMsg", EC.Availability.Msg, StringRef("")); 372 IO.mapOptional("SwiftPrivate", EC.SwiftPrivate); 373 IO.mapOptional("SwiftName", EC.SwiftName, StringRef("")); 374 } 375 }; 376 } // namespace yaml 377 } // namespace llvm 378 379 namespace { 380 /// Syntactic sugar for EnumExtensibility and FlagEnum 381 enum class EnumConvenienceAliasKind { 382 /// EnumExtensibility: none, FlagEnum: false 383 None, 384 /// EnumExtensibility: open, FlagEnum: false 385 CFEnum, 386 /// EnumExtensibility: open, FlagEnum: true 387 CFOptions, 388 /// EnumExtensibility: closed, FlagEnum: false 389 CFClosedEnum 390 }; 391 } // namespace 392 393 namespace llvm { 394 namespace yaml { 395 template <> struct ScalarEnumerationTraits<EnumConvenienceAliasKind> { 396 static void enumeration(IO &IO, EnumConvenienceAliasKind &ECAK) { 397 IO.enumCase(ECAK, "none", EnumConvenienceAliasKind::None); 398 IO.enumCase(ECAK, "CFEnum", EnumConvenienceAliasKind::CFEnum); 399 IO.enumCase(ECAK, "NSEnum", EnumConvenienceAliasKind::CFEnum); 400 IO.enumCase(ECAK, "CFOptions", EnumConvenienceAliasKind::CFOptions); 401 IO.enumCase(ECAK, "NSOptions", EnumConvenienceAliasKind::CFOptions); 402 IO.enumCase(ECAK, "CFClosedEnum", EnumConvenienceAliasKind::CFClosedEnum); 403 IO.enumCase(ECAK, "NSClosedEnum", EnumConvenienceAliasKind::CFClosedEnum); 404 } 405 }; 406 } // namespace yaml 407 } // namespace llvm 408 409 namespace { 410 struct Tag { 411 StringRef Name; 412 AvailabilityItem Availability; 413 StringRef SwiftName; 414 std::optional<bool> SwiftPrivate; 415 std::optional<StringRef> SwiftBridge; 416 std::optional<StringRef> NSErrorDomain; 417 std::optional<EnumExtensibilityKind> EnumExtensibility; 418 std::optional<bool> FlagEnum; 419 std::optional<EnumConvenienceAliasKind> EnumConvenienceKind; 420 }; 421 422 typedef std::vector<Tag> TagsSeq; 423 } // namespace 424 425 LLVM_YAML_IS_SEQUENCE_VECTOR(Tag) 426 427 namespace llvm { 428 namespace yaml { 429 template <> struct ScalarEnumerationTraits<EnumExtensibilityKind> { 430 static void enumeration(IO &IO, EnumExtensibilityKind &EEK) { 431 IO.enumCase(EEK, "none", EnumExtensibilityKind::None); 432 IO.enumCase(EEK, "open", EnumExtensibilityKind::Open); 433 IO.enumCase(EEK, "closed", EnumExtensibilityKind::Closed); 434 } 435 }; 436 437 template <> struct MappingTraits<Tag> { 438 static void mapping(IO &IO, Tag &T) { 439 IO.mapRequired("Name", T.Name); 440 IO.mapOptional("Availability", T.Availability.Mode, 441 APIAvailability::Available); 442 IO.mapOptional("AvailabilityMsg", T.Availability.Msg, StringRef("")); 443 IO.mapOptional("SwiftPrivate", T.SwiftPrivate); 444 IO.mapOptional("SwiftName", T.SwiftName, StringRef("")); 445 IO.mapOptional("SwiftBridge", T.SwiftBridge); 446 IO.mapOptional("NSErrorDomain", T.NSErrorDomain); 447 IO.mapOptional("EnumExtensibility", T.EnumExtensibility); 448 IO.mapOptional("FlagEnum", T.FlagEnum); 449 IO.mapOptional("EnumKind", T.EnumConvenienceKind); 450 } 451 }; 452 } // namespace yaml 453 } // namespace llvm 454 455 namespace { 456 struct Typedef { 457 StringRef Name; 458 AvailabilityItem Availability; 459 StringRef SwiftName; 460 std::optional<bool> SwiftPrivate; 461 std::optional<StringRef> SwiftBridge; 462 std::optional<StringRef> NSErrorDomain; 463 std::optional<SwiftNewTypeKind> SwiftType; 464 }; 465 466 typedef std::vector<Typedef> TypedefsSeq; 467 } // namespace 468 469 LLVM_YAML_IS_SEQUENCE_VECTOR(Typedef) 470 471 namespace llvm { 472 namespace yaml { 473 template <> struct ScalarEnumerationTraits<SwiftNewTypeKind> { 474 static void enumeration(IO &IO, SwiftNewTypeKind &SWK) { 475 IO.enumCase(SWK, "none", SwiftNewTypeKind::None); 476 IO.enumCase(SWK, "struct", SwiftNewTypeKind::Struct); 477 IO.enumCase(SWK, "enum", SwiftNewTypeKind::Enum); 478 } 479 }; 480 481 template <> struct MappingTraits<Typedef> { 482 static void mapping(IO &IO, Typedef &T) { 483 IO.mapRequired("Name", T.Name); 484 IO.mapOptional("Availability", T.Availability.Mode, 485 APIAvailability::Available); 486 IO.mapOptional("AvailabilityMsg", T.Availability.Msg, StringRef("")); 487 IO.mapOptional("SwiftPrivate", T.SwiftPrivate); 488 IO.mapOptional("SwiftName", T.SwiftName, StringRef("")); 489 IO.mapOptional("SwiftBridge", T.SwiftBridge); 490 IO.mapOptional("NSErrorDomain", T.NSErrorDomain); 491 IO.mapOptional("SwiftWrapper", T.SwiftType); 492 } 493 }; 494 } // namespace yaml 495 } // namespace llvm 496 497 namespace { 498 struct TopLevelItems { 499 ClassesSeq Classes; 500 ClassesSeq Protocols; 501 FunctionsSeq Functions; 502 GlobalVariablesSeq Globals; 503 EnumConstantsSeq EnumConstants; 504 TagsSeq Tags; 505 TypedefsSeq Typedefs; 506 }; 507 } // namespace 508 509 namespace llvm { 510 namespace yaml { 511 static void mapTopLevelItems(IO &IO, TopLevelItems &TLI) { 512 IO.mapOptional("Classes", TLI.Classes); 513 IO.mapOptional("Protocols", TLI.Protocols); 514 IO.mapOptional("Functions", TLI.Functions); 515 IO.mapOptional("Globals", TLI.Globals); 516 IO.mapOptional("Enumerators", TLI.EnumConstants); 517 IO.mapOptional("Tags", TLI.Tags); 518 IO.mapOptional("Typedefs", TLI.Typedefs); 519 } 520 } // namespace yaml 521 } // namespace llvm 522 523 namespace { 524 struct Versioned { 525 VersionTuple Version; 526 TopLevelItems Items; 527 }; 528 529 typedef std::vector<Versioned> VersionedSeq; 530 } // namespace 531 532 LLVM_YAML_IS_SEQUENCE_VECTOR(Versioned) 533 534 namespace llvm { 535 namespace yaml { 536 template <> struct MappingTraits<Versioned> { 537 static void mapping(IO &IO, Versioned &V) { 538 IO.mapRequired("Version", V.Version); 539 mapTopLevelItems(IO, V.Items); 540 } 541 }; 542 } // namespace yaml 543 } // namespace llvm 544 545 namespace { 546 struct Module { 547 StringRef Name; 548 AvailabilityItem Availability; 549 TopLevelItems TopLevel; 550 VersionedSeq SwiftVersions; 551 552 std::optional<bool> SwiftInferImportAsMember; 553 554 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 555 LLVM_DUMP_METHOD void dump() /*const*/; 556 #endif 557 }; 558 } // namespace 559 560 namespace llvm { 561 namespace yaml { 562 template <> struct MappingTraits<Module> { 563 static void mapping(IO &IO, Module &M) { 564 IO.mapRequired("Name", M.Name); 565 IO.mapOptional("Availability", M.Availability.Mode, 566 APIAvailability::Available); 567 IO.mapOptional("AvailabilityMsg", M.Availability.Msg, StringRef("")); 568 IO.mapOptional("SwiftInferImportAsMember", M.SwiftInferImportAsMember); 569 mapTopLevelItems(IO, M.TopLevel); 570 IO.mapOptional("SwiftVersions", M.SwiftVersions); 571 } 572 }; 573 } // namespace yaml 574 } // namespace llvm 575 576 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 577 LLVM_DUMP_METHOD void Module::dump() { 578 llvm::yaml::Output OS(llvm::errs()); 579 OS << *this; 580 } 581 #endif 582 583 namespace { 584 bool parseAPINotes(StringRef YI, Module &M, llvm::SourceMgr::DiagHandlerTy Diag, 585 void *DiagContext) { 586 llvm::yaml::Input IS(YI, nullptr, Diag, DiagContext); 587 IS >> M; 588 return static_cast<bool>(IS.error()); 589 } 590 } // namespace 591 592 bool clang::api_notes::parseAndDumpAPINotes(StringRef YI, 593 llvm::raw_ostream &OS) { 594 Module M; 595 if (parseAPINotes(YI, M, nullptr, nullptr)) 596 return true; 597 598 llvm::yaml::Output YOS(OS); 599 YOS << M; 600 601 return false; 602 } 603