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/ADT/Optional.h"
21#include "llvm/Support/VersionTuple.h"
22#include "llvm/Support/YAMLParser.h"
23#include "llvm/Support/YAMLTraits.h"
24#include <vector>
25using namespace clang;
26using namespace api_notes;
27
28namespace {
29enum class APIAvailability {
30  Available = 0,
31  OSX,
32  IOS,
33  None,
34  NonSwift,
35};
36} // namespace
37
38namespace llvm {
39namespace yaml {
40template <> 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
52namespace {
53enum class MethodKind {
54  Class,
55  Instance,
56};
57} // namespace
58
59namespace llvm {
60namespace yaml {
61template <> 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
70namespace {
71struct Param {
72  unsigned Position;
73  Optional<bool> NoEscape = false;
74  Optional<NullabilityKind> Nullability;
75  Optional<RetainCountConventionKind> RetainCountConvention;
76  StringRef Type;
77};
78
79typedef std::vector<Param> ParamsSeq;
80} // namespace
81
82LLVM_YAML_IS_SEQUENCE_VECTOR(Param)
83LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(NullabilityKind)
84
85namespace llvm {
86namespace yaml {
87template <> 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
105template <> 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
119template <> struct MappingTraits<Param> {
120  static void mapping(IO &IO, Param &P) {
121    IO.mapRequired("Position", P.Position);
122    IO.mapOptional("Nullability", P.Nullability, llvm::None);
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
131namespace {
132typedef std::vector<NullabilityKind> NullabilitySeq;
133
134struct AvailabilityItem {
135  APIAvailability Mode = APIAvailability::Available;
136  StringRef Msg;
137};
138
139/// Old attribute deprecated in favor of SwiftName.
140enum 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
149struct Method {
150  StringRef Selector;
151  MethodKind Kind;
152  ParamsSeq Params;
153  NullabilitySeq Nullability;
154  Optional<NullabilityKind> NullabilityOfRet;
155  Optional<RetainCountConventionKind> RetainCountConvention;
156  AvailabilityItem Availability;
157  Optional<bool> SwiftPrivate;
158  StringRef SwiftName;
159  FactoryAsInitKind FactoryAsInit = FactoryAsInitKind::Infer;
160  bool DesignatedInit = false;
161  bool Required = false;
162  StringRef ResultType;
163};
164
165typedef std::vector<Method> MethodsSeq;
166} // namespace
167
168LLVM_YAML_IS_SEQUENCE_VECTOR(Method)
169
170namespace llvm {
171namespace yaml {
172template <> 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
180template <> 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, llvm::None);
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
202namespace {
203struct Property {
204  StringRef Name;
205  llvm::Optional<MethodKind> Kind;
206  llvm::Optional<NullabilityKind> Nullability;
207  AvailabilityItem Availability;
208  Optional<bool> SwiftPrivate;
209  StringRef SwiftName;
210  Optional<bool> SwiftImportAsAccessors;
211  StringRef Type;
212};
213
214typedef std::vector<Property> PropertiesSeq;
215} // namespace
216
217LLVM_YAML_IS_SEQUENCE_VECTOR(Property)
218
219namespace llvm {
220namespace yaml {
221template <> 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, llvm::None);
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
238namespace {
239struct Class {
240  StringRef Name;
241  bool AuditedForNullability = false;
242  AvailabilityItem Availability;
243  Optional<bool> SwiftPrivate;
244  StringRef SwiftName;
245  Optional<StringRef> SwiftBridge;
246  Optional<StringRef> NSErrorDomain;
247  Optional<bool> SwiftImportAsNonGeneric;
248  Optional<bool> SwiftObjCMembers;
249  MethodsSeq Methods;
250  PropertiesSeq Properties;
251};
252
253typedef std::vector<Class> ClassesSeq;
254} // namespace
255
256LLVM_YAML_IS_SEQUENCE_VECTOR(Class)
257
258namespace llvm {
259namespace yaml {
260template <> 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
280namespace {
281struct Function {
282  StringRef Name;
283  ParamsSeq Params;
284  NullabilitySeq Nullability;
285  Optional<NullabilityKind> NullabilityOfRet;
286  Optional<api_notes::RetainCountConventionKind> RetainCountConvention;
287  AvailabilityItem Availability;
288  Optional<bool> SwiftPrivate;
289  StringRef SwiftName;
290  StringRef Type;
291  StringRef ResultType;
292};
293
294typedef std::vector<Function> FunctionsSeq;
295} // namespace
296
297LLVM_YAML_IS_SEQUENCE_VECTOR(Function)
298
299namespace llvm {
300namespace yaml {
301template <> 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, llvm::None);
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
319namespace {
320struct GlobalVariable {
321  StringRef Name;
322  llvm::Optional<NullabilityKind> Nullability;
323  AvailabilityItem Availability;
324  Optional<bool> SwiftPrivate;
325  StringRef SwiftName;
326  StringRef Type;
327};
328
329typedef std::vector<GlobalVariable> GlobalVariablesSeq;
330} // namespace
331
332LLVM_YAML_IS_SEQUENCE_VECTOR(GlobalVariable)
333
334namespace llvm {
335namespace yaml {
336template <> struct MappingTraits<GlobalVariable> {
337  static void mapping(IO &IO, GlobalVariable &GV) {
338    IO.mapRequired("Name", GV.Name);
339    IO.mapOptional("Nullability", GV.Nullability, llvm::None);
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
351namespace {
352struct EnumConstant {
353  StringRef Name;
354  AvailabilityItem Availability;
355  Optional<bool> SwiftPrivate;
356  StringRef SwiftName;
357};
358
359typedef std::vector<EnumConstant> EnumConstantsSeq;
360} // namespace
361
362LLVM_YAML_IS_SEQUENCE_VECTOR(EnumConstant)
363
364namespace llvm {
365namespace yaml {
366template <> 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
379namespace {
380/// Syntactic sugar for EnumExtensibility and FlagEnum
381enum 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
393namespace llvm {
394namespace yaml {
395template <> 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
409namespace {
410struct Tag {
411  StringRef Name;
412  AvailabilityItem Availability;
413  StringRef SwiftName;
414  Optional<bool> SwiftPrivate;
415  Optional<StringRef> SwiftBridge;
416  Optional<StringRef> NSErrorDomain;
417  Optional<EnumExtensibilityKind> EnumExtensibility;
418  Optional<bool> FlagEnum;
419  Optional<EnumConvenienceAliasKind> EnumConvenienceKind;
420};
421
422typedef std::vector<Tag> TagsSeq;
423} // namespace
424
425LLVM_YAML_IS_SEQUENCE_VECTOR(Tag)
426
427namespace llvm {
428namespace yaml {
429template <> 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
437template <> 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
455namespace {
456struct Typedef {
457  StringRef Name;
458  AvailabilityItem Availability;
459  StringRef SwiftName;
460  Optional<bool> SwiftPrivate;
461  Optional<StringRef> SwiftBridge;
462  Optional<StringRef> NSErrorDomain;
463  Optional<SwiftNewTypeKind> SwiftType;
464};
465
466typedef std::vector<Typedef> TypedefsSeq;
467} // namespace
468
469LLVM_YAML_IS_SEQUENCE_VECTOR(Typedef)
470
471namespace llvm {
472namespace yaml {
473template <> 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
481template <> 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
497namespace {
498struct 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
509namespace llvm {
510namespace yaml {
511static 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
523namespace {
524struct Versioned {
525  VersionTuple Version;
526  TopLevelItems Items;
527};
528
529typedef std::vector<Versioned> VersionedSeq;
530} // namespace
531
532LLVM_YAML_IS_SEQUENCE_VECTOR(Versioned)
533
534namespace llvm {
535namespace yaml {
536template <> 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
545namespace {
546struct Module {
547  StringRef Name;
548  AvailabilityItem Availability;
549  TopLevelItems TopLevel;
550  VersionedSeq SwiftVersions;
551
552  llvm::Optional<bool> SwiftInferImportAsMember = {llvm::None};
553
554#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
555  LLVM_DUMP_METHOD void dump() /*const*/;
556#endif
557};
558} // namespace
559
560namespace llvm {
561namespace yaml {
562template <> 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)
577LLVM_DUMP_METHOD void Module::dump() {
578  llvm::yaml::Output OS(llvm::errs());
579  OS << *this;
580}
581#endif
582
583namespace {
584bool 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
592bool 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