mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 07:16:07 +00:00

Adding support to APINotes to annotate C++ methods and functions with `swift_attr("returns_retained")` and `swift_attr("returns_unretained")` rdar://141007510
1227 lines
40 KiB
C++
1227 lines
40 KiB
C++
//===-- APINotesYAMLCompiler.cpp - API Notes YAML Format Reader -*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// The types defined locally are designed to represent the YAML state, which
|
|
// adds an additional bit of state: e.g. a tri-state boolean attribute (yes, no,
|
|
// not applied) becomes a tri-state boolean + present. As a result, while these
|
|
// enumerations appear to be redefining constants from the attributes table
|
|
// data, they are distinct.
|
|
//
|
|
|
|
#include "clang/APINotes/APINotesYAMLCompiler.h"
|
|
#include "clang/APINotes/APINotesWriter.h"
|
|
#include "clang/APINotes/Types.h"
|
|
#include "clang/Basic/LLVM.h"
|
|
#include "clang/Basic/Specifiers.h"
|
|
#include "llvm/ADT/StringSet.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/Support/VersionTuple.h"
|
|
#include "llvm/Support/YAMLTraits.h"
|
|
#include <optional>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
using namespace clang;
|
|
using namespace api_notes;
|
|
|
|
namespace {
|
|
enum class APIAvailability {
|
|
Available = 0,
|
|
None,
|
|
NonSwift,
|
|
};
|
|
} // namespace
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct ScalarEnumerationTraits<APIAvailability> {
|
|
static void enumeration(IO &IO, APIAvailability &AA) {
|
|
IO.enumCase(AA, "none", APIAvailability::None);
|
|
IO.enumCase(AA, "nonswift", APIAvailability::NonSwift);
|
|
IO.enumCase(AA, "available", APIAvailability::Available);
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
enum class MethodKind {
|
|
Class,
|
|
Instance,
|
|
};
|
|
} // namespace
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct ScalarEnumerationTraits<MethodKind> {
|
|
static void enumeration(IO &IO, MethodKind &MK) {
|
|
IO.enumCase(MK, "Class", MethodKind::Class);
|
|
IO.enumCase(MK, "Instance", MethodKind::Instance);
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct Param {
|
|
int Position;
|
|
std::optional<bool> NoEscape = false;
|
|
std::optional<bool> Lifetimebound = false;
|
|
std::optional<NullabilityKind> Nullability;
|
|
std::optional<RetainCountConventionKind> RetainCountConvention;
|
|
StringRef Type;
|
|
};
|
|
|
|
typedef std::vector<Param> ParamsSeq;
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Param)
|
|
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(NullabilityKind)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct ScalarEnumerationTraits<NullabilityKind> {
|
|
static void enumeration(IO &IO, NullabilityKind &NK) {
|
|
IO.enumCase(NK, "Nonnull", NullabilityKind::NonNull);
|
|
IO.enumCase(NK, "Optional", NullabilityKind::Nullable);
|
|
IO.enumCase(NK, "Unspecified", NullabilityKind::Unspecified);
|
|
IO.enumCase(NK, "NullableResult", NullabilityKind::NullableResult);
|
|
// TODO: Mapping this to it's own value would allow for better cross
|
|
// checking. Also the default should be Unknown.
|
|
IO.enumCase(NK, "Scalar", NullabilityKind::Unspecified);
|
|
|
|
// Aliases for compatibility with existing APINotes.
|
|
IO.enumCase(NK, "N", NullabilityKind::NonNull);
|
|
IO.enumCase(NK, "O", NullabilityKind::Nullable);
|
|
IO.enumCase(NK, "U", NullabilityKind::Unspecified);
|
|
IO.enumCase(NK, "S", NullabilityKind::Unspecified);
|
|
}
|
|
};
|
|
|
|
template <> struct ScalarEnumerationTraits<RetainCountConventionKind> {
|
|
static void enumeration(IO &IO, RetainCountConventionKind &RCCK) {
|
|
IO.enumCase(RCCK, "none", RetainCountConventionKind::None);
|
|
IO.enumCase(RCCK, "CFReturnsRetained",
|
|
RetainCountConventionKind::CFReturnsRetained);
|
|
IO.enumCase(RCCK, "CFReturnsNotRetained",
|
|
RetainCountConventionKind::CFReturnsNotRetained);
|
|
IO.enumCase(RCCK, "NSReturnsRetained",
|
|
RetainCountConventionKind::NSReturnsRetained);
|
|
IO.enumCase(RCCK, "NSReturnsNotRetained",
|
|
RetainCountConventionKind::NSReturnsNotRetained);
|
|
}
|
|
};
|
|
|
|
template <> struct MappingTraits<Param> {
|
|
static void mapping(IO &IO, Param &P) {
|
|
IO.mapRequired("Position", P.Position);
|
|
IO.mapOptional("Nullability", P.Nullability, std::nullopt);
|
|
IO.mapOptional("RetainCountConvention", P.RetainCountConvention);
|
|
IO.mapOptional("NoEscape", P.NoEscape);
|
|
IO.mapOptional("Lifetimebound", P.Lifetimebound);
|
|
IO.mapOptional("Type", P.Type, StringRef(""));
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
typedef std::vector<NullabilityKind> NullabilitySeq;
|
|
|
|
struct AvailabilityItem {
|
|
APIAvailability Mode = APIAvailability::Available;
|
|
StringRef Msg;
|
|
};
|
|
|
|
/// Old attribute deprecated in favor of SwiftName.
|
|
enum class FactoryAsInitKind {
|
|
/// Infer based on name and type (the default).
|
|
Infer,
|
|
/// Treat as a class method.
|
|
AsClassMethod,
|
|
/// Treat as an initializer.
|
|
AsInitializer,
|
|
};
|
|
|
|
struct Method {
|
|
StringRef Selector;
|
|
MethodKind Kind;
|
|
ParamsSeq Params;
|
|
NullabilitySeq Nullability;
|
|
std::optional<NullabilityKind> NullabilityOfRet;
|
|
std::optional<RetainCountConventionKind> RetainCountConvention;
|
|
AvailabilityItem Availability;
|
|
std::optional<bool> SwiftPrivate;
|
|
StringRef SwiftName;
|
|
FactoryAsInitKind FactoryAsInit = FactoryAsInitKind::Infer;
|
|
bool DesignatedInit = false;
|
|
bool Required = false;
|
|
StringRef ResultType;
|
|
StringRef SwiftReturnOwnership;
|
|
};
|
|
|
|
typedef std::vector<Method> MethodsSeq;
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Method)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct ScalarEnumerationTraits<FactoryAsInitKind> {
|
|
static void enumeration(IO &IO, FactoryAsInitKind &FIK) {
|
|
IO.enumCase(FIK, "A", FactoryAsInitKind::Infer);
|
|
IO.enumCase(FIK, "C", FactoryAsInitKind::AsClassMethod);
|
|
IO.enumCase(FIK, "I", FactoryAsInitKind::AsInitializer);
|
|
}
|
|
};
|
|
|
|
template <> struct MappingTraits<Method> {
|
|
static void mapping(IO &IO, Method &M) {
|
|
IO.mapRequired("Selector", M.Selector);
|
|
IO.mapRequired("MethodKind", M.Kind);
|
|
IO.mapOptional("Parameters", M.Params);
|
|
IO.mapOptional("Nullability", M.Nullability);
|
|
IO.mapOptional("NullabilityOfRet", M.NullabilityOfRet, std::nullopt);
|
|
IO.mapOptional("RetainCountConvention", M.RetainCountConvention);
|
|
IO.mapOptional("Availability", M.Availability.Mode,
|
|
APIAvailability::Available);
|
|
IO.mapOptional("AvailabilityMsg", M.Availability.Msg, StringRef(""));
|
|
IO.mapOptional("SwiftPrivate", M.SwiftPrivate);
|
|
IO.mapOptional("SwiftName", M.SwiftName, StringRef(""));
|
|
IO.mapOptional("FactoryAsInit", M.FactoryAsInit, FactoryAsInitKind::Infer);
|
|
IO.mapOptional("DesignatedInit", M.DesignatedInit, false);
|
|
IO.mapOptional("Required", M.Required, false);
|
|
IO.mapOptional("ResultType", M.ResultType, StringRef(""));
|
|
IO.mapOptional("SwiftReturnOwnership", M.SwiftReturnOwnership,
|
|
StringRef(""));
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct Property {
|
|
StringRef Name;
|
|
std::optional<MethodKind> Kind;
|
|
std::optional<NullabilityKind> Nullability;
|
|
AvailabilityItem Availability;
|
|
std::optional<bool> SwiftPrivate;
|
|
StringRef SwiftName;
|
|
std::optional<bool> SwiftImportAsAccessors;
|
|
StringRef Type;
|
|
};
|
|
|
|
typedef std::vector<Property> PropertiesSeq;
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Property)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct MappingTraits<Property> {
|
|
static void mapping(IO &IO, Property &P) {
|
|
IO.mapRequired("Name", P.Name);
|
|
IO.mapOptional("PropertyKind", P.Kind);
|
|
IO.mapOptional("Nullability", P.Nullability, std::nullopt);
|
|
IO.mapOptional("Availability", P.Availability.Mode,
|
|
APIAvailability::Available);
|
|
IO.mapOptional("AvailabilityMsg", P.Availability.Msg, StringRef(""));
|
|
IO.mapOptional("SwiftPrivate", P.SwiftPrivate);
|
|
IO.mapOptional("SwiftName", P.SwiftName, StringRef(""));
|
|
IO.mapOptional("SwiftImportAsAccessors", P.SwiftImportAsAccessors);
|
|
IO.mapOptional("Type", P.Type, StringRef(""));
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct Class {
|
|
StringRef Name;
|
|
bool AuditedForNullability = false;
|
|
AvailabilityItem Availability;
|
|
std::optional<bool> SwiftPrivate;
|
|
StringRef SwiftName;
|
|
std::optional<StringRef> SwiftBridge;
|
|
std::optional<StringRef> NSErrorDomain;
|
|
std::optional<bool> SwiftImportAsNonGeneric;
|
|
std::optional<bool> SwiftObjCMembers;
|
|
MethodsSeq Methods;
|
|
PropertiesSeq Properties;
|
|
};
|
|
|
|
typedef std::vector<Class> ClassesSeq;
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Class)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct MappingTraits<Class> {
|
|
static void mapping(IO &IO, Class &C) {
|
|
IO.mapRequired("Name", C.Name);
|
|
IO.mapOptional("AuditedForNullability", C.AuditedForNullability, false);
|
|
IO.mapOptional("Availability", C.Availability.Mode,
|
|
APIAvailability::Available);
|
|
IO.mapOptional("AvailabilityMsg", C.Availability.Msg, StringRef(""));
|
|
IO.mapOptional("SwiftPrivate", C.SwiftPrivate);
|
|
IO.mapOptional("SwiftName", C.SwiftName, StringRef(""));
|
|
IO.mapOptional("SwiftBridge", C.SwiftBridge);
|
|
IO.mapOptional("NSErrorDomain", C.NSErrorDomain);
|
|
IO.mapOptional("SwiftImportAsNonGeneric", C.SwiftImportAsNonGeneric);
|
|
IO.mapOptional("SwiftObjCMembers", C.SwiftObjCMembers);
|
|
IO.mapOptional("Methods", C.Methods);
|
|
IO.mapOptional("Properties", C.Properties);
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct Function {
|
|
StringRef Name;
|
|
ParamsSeq Params;
|
|
NullabilitySeq Nullability;
|
|
std::optional<NullabilityKind> NullabilityOfRet;
|
|
std::optional<api_notes::RetainCountConventionKind> RetainCountConvention;
|
|
AvailabilityItem Availability;
|
|
std::optional<bool> SwiftPrivate;
|
|
StringRef SwiftName;
|
|
StringRef Type;
|
|
StringRef ResultType;
|
|
StringRef SwiftReturnOwnership;
|
|
};
|
|
|
|
typedef std::vector<Function> FunctionsSeq;
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Function)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct MappingTraits<Function> {
|
|
static void mapping(IO &IO, Function &F) {
|
|
IO.mapRequired("Name", F.Name);
|
|
IO.mapOptional("Parameters", F.Params);
|
|
IO.mapOptional("Nullability", F.Nullability);
|
|
IO.mapOptional("NullabilityOfRet", F.NullabilityOfRet, std::nullopt);
|
|
IO.mapOptional("RetainCountConvention", F.RetainCountConvention);
|
|
IO.mapOptional("Availability", F.Availability.Mode,
|
|
APIAvailability::Available);
|
|
IO.mapOptional("AvailabilityMsg", F.Availability.Msg, StringRef(""));
|
|
IO.mapOptional("SwiftPrivate", F.SwiftPrivate);
|
|
IO.mapOptional("SwiftName", F.SwiftName, StringRef(""));
|
|
IO.mapOptional("ResultType", F.ResultType, StringRef(""));
|
|
IO.mapOptional("SwiftReturnOwnership", F.SwiftReturnOwnership,
|
|
StringRef(""));
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct GlobalVariable {
|
|
StringRef Name;
|
|
std::optional<NullabilityKind> Nullability;
|
|
AvailabilityItem Availability;
|
|
std::optional<bool> SwiftPrivate;
|
|
StringRef SwiftName;
|
|
StringRef Type;
|
|
};
|
|
|
|
typedef std::vector<GlobalVariable> GlobalVariablesSeq;
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(GlobalVariable)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct MappingTraits<GlobalVariable> {
|
|
static void mapping(IO &IO, GlobalVariable &GV) {
|
|
IO.mapRequired("Name", GV.Name);
|
|
IO.mapOptional("Nullability", GV.Nullability, std::nullopt);
|
|
IO.mapOptional("Availability", GV.Availability.Mode,
|
|
APIAvailability::Available);
|
|
IO.mapOptional("AvailabilityMsg", GV.Availability.Msg, StringRef(""));
|
|
IO.mapOptional("SwiftPrivate", GV.SwiftPrivate);
|
|
IO.mapOptional("SwiftName", GV.SwiftName, StringRef(""));
|
|
IO.mapOptional("Type", GV.Type, StringRef(""));
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct EnumConstant {
|
|
StringRef Name;
|
|
AvailabilityItem Availability;
|
|
std::optional<bool> SwiftPrivate;
|
|
StringRef SwiftName;
|
|
};
|
|
|
|
typedef std::vector<EnumConstant> EnumConstantsSeq;
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(EnumConstant)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct MappingTraits<EnumConstant> {
|
|
static void mapping(IO &IO, EnumConstant &EC) {
|
|
IO.mapRequired("Name", EC.Name);
|
|
IO.mapOptional("Availability", EC.Availability.Mode,
|
|
APIAvailability::Available);
|
|
IO.mapOptional("AvailabilityMsg", EC.Availability.Msg, StringRef(""));
|
|
IO.mapOptional("SwiftPrivate", EC.SwiftPrivate);
|
|
IO.mapOptional("SwiftName", EC.SwiftName, StringRef(""));
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
/// Syntactic sugar for EnumExtensibility and FlagEnum
|
|
enum class EnumConvenienceAliasKind {
|
|
/// EnumExtensibility: none, FlagEnum: false
|
|
None,
|
|
/// EnumExtensibility: open, FlagEnum: false
|
|
CFEnum,
|
|
/// EnumExtensibility: open, FlagEnum: true
|
|
CFOptions,
|
|
/// EnumExtensibility: closed, FlagEnum: false
|
|
CFClosedEnum
|
|
};
|
|
} // namespace
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct ScalarEnumerationTraits<EnumConvenienceAliasKind> {
|
|
static void enumeration(IO &IO, EnumConvenienceAliasKind &ECAK) {
|
|
IO.enumCase(ECAK, "none", EnumConvenienceAliasKind::None);
|
|
IO.enumCase(ECAK, "CFEnum", EnumConvenienceAliasKind::CFEnum);
|
|
IO.enumCase(ECAK, "NSEnum", EnumConvenienceAliasKind::CFEnum);
|
|
IO.enumCase(ECAK, "CFOptions", EnumConvenienceAliasKind::CFOptions);
|
|
IO.enumCase(ECAK, "NSOptions", EnumConvenienceAliasKind::CFOptions);
|
|
IO.enumCase(ECAK, "CFClosedEnum", EnumConvenienceAliasKind::CFClosedEnum);
|
|
IO.enumCase(ECAK, "NSClosedEnum", EnumConvenienceAliasKind::CFClosedEnum);
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct Field {
|
|
StringRef Name;
|
|
std::optional<NullabilityKind> Nullability;
|
|
AvailabilityItem Availability;
|
|
std::optional<bool> SwiftPrivate;
|
|
StringRef SwiftName;
|
|
StringRef Type;
|
|
};
|
|
|
|
typedef std::vector<Field> FieldsSeq;
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Field)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct MappingTraits<Field> {
|
|
static void mapping(IO &IO, Field &F) {
|
|
IO.mapRequired("Name", F.Name);
|
|
IO.mapOptional("Nullability", F.Nullability, std::nullopt);
|
|
IO.mapOptional("Availability", F.Availability.Mode,
|
|
APIAvailability::Available);
|
|
IO.mapOptional("AvailabilityMsg", F.Availability.Msg, StringRef(""));
|
|
IO.mapOptional("SwiftPrivate", F.SwiftPrivate);
|
|
IO.mapOptional("SwiftName", F.SwiftName, StringRef(""));
|
|
IO.mapOptional("Type", F.Type, StringRef(""));
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct Tag;
|
|
typedef std::vector<Tag> TagsSeq;
|
|
|
|
struct Tag {
|
|
StringRef Name;
|
|
AvailabilityItem Availability;
|
|
StringRef SwiftName;
|
|
std::optional<bool> SwiftPrivate;
|
|
std::optional<StringRef> SwiftBridge;
|
|
std::optional<StringRef> NSErrorDomain;
|
|
std::optional<std::string> SwiftImportAs;
|
|
std::optional<std::string> SwiftRetainOp;
|
|
std::optional<std::string> SwiftReleaseOp;
|
|
std::optional<std::string> SwiftConformance;
|
|
std::optional<EnumExtensibilityKind> EnumExtensibility;
|
|
std::optional<bool> FlagEnum;
|
|
std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
|
|
std::optional<bool> SwiftCopyable;
|
|
std::optional<bool> SwiftEscapable;
|
|
FunctionsSeq Methods;
|
|
FieldsSeq Fields;
|
|
|
|
/// Tags that are declared within the current tag. Only the tags that have
|
|
/// corresponding API Notes will be listed.
|
|
TagsSeq Tags;
|
|
};
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Tag)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct ScalarEnumerationTraits<EnumExtensibilityKind> {
|
|
static void enumeration(IO &IO, EnumExtensibilityKind &EEK) {
|
|
IO.enumCase(EEK, "none", EnumExtensibilityKind::None);
|
|
IO.enumCase(EEK, "open", EnumExtensibilityKind::Open);
|
|
IO.enumCase(EEK, "closed", EnumExtensibilityKind::Closed);
|
|
}
|
|
};
|
|
|
|
template <> struct MappingTraits<Tag> {
|
|
static void mapping(IO &IO, Tag &T) {
|
|
IO.mapRequired("Name", T.Name);
|
|
IO.mapOptional("Availability", T.Availability.Mode,
|
|
APIAvailability::Available);
|
|
IO.mapOptional("AvailabilityMsg", T.Availability.Msg, StringRef(""));
|
|
IO.mapOptional("SwiftPrivate", T.SwiftPrivate);
|
|
IO.mapOptional("SwiftName", T.SwiftName, StringRef(""));
|
|
IO.mapOptional("SwiftBridge", T.SwiftBridge);
|
|
IO.mapOptional("NSErrorDomain", T.NSErrorDomain);
|
|
IO.mapOptional("SwiftImportAs", T.SwiftImportAs);
|
|
IO.mapOptional("SwiftReleaseOp", T.SwiftReleaseOp);
|
|
IO.mapOptional("SwiftRetainOp", T.SwiftRetainOp);
|
|
IO.mapOptional("SwiftConformsTo", T.SwiftConformance);
|
|
IO.mapOptional("EnumExtensibility", T.EnumExtensibility);
|
|
IO.mapOptional("FlagEnum", T.FlagEnum);
|
|
IO.mapOptional("EnumKind", T.EnumConvenienceKind);
|
|
IO.mapOptional("SwiftCopyable", T.SwiftCopyable);
|
|
IO.mapOptional("SwiftEscapable", T.SwiftEscapable);
|
|
IO.mapOptional("Methods", T.Methods);
|
|
IO.mapOptional("Fields", T.Fields);
|
|
IO.mapOptional("Tags", T.Tags);
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct Typedef {
|
|
StringRef Name;
|
|
AvailabilityItem Availability;
|
|
StringRef SwiftName;
|
|
std::optional<bool> SwiftPrivate;
|
|
std::optional<StringRef> SwiftBridge;
|
|
std::optional<StringRef> NSErrorDomain;
|
|
std::optional<SwiftNewTypeKind> SwiftType;
|
|
};
|
|
|
|
typedef std::vector<Typedef> TypedefsSeq;
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Typedef)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct ScalarEnumerationTraits<SwiftNewTypeKind> {
|
|
static void enumeration(IO &IO, SwiftNewTypeKind &SWK) {
|
|
IO.enumCase(SWK, "none", SwiftNewTypeKind::None);
|
|
IO.enumCase(SWK, "struct", SwiftNewTypeKind::Struct);
|
|
IO.enumCase(SWK, "enum", SwiftNewTypeKind::Enum);
|
|
}
|
|
};
|
|
|
|
template <> struct MappingTraits<Typedef> {
|
|
static void mapping(IO &IO, Typedef &T) {
|
|
IO.mapRequired("Name", T.Name);
|
|
IO.mapOptional("Availability", T.Availability.Mode,
|
|
APIAvailability::Available);
|
|
IO.mapOptional("AvailabilityMsg", T.Availability.Msg, StringRef(""));
|
|
IO.mapOptional("SwiftPrivate", T.SwiftPrivate);
|
|
IO.mapOptional("SwiftName", T.SwiftName, StringRef(""));
|
|
IO.mapOptional("SwiftBridge", T.SwiftBridge);
|
|
IO.mapOptional("NSErrorDomain", T.NSErrorDomain);
|
|
IO.mapOptional("SwiftWrapper", T.SwiftType);
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct Namespace;
|
|
typedef std::vector<Namespace> NamespacesSeq;
|
|
|
|
struct TopLevelItems {
|
|
ClassesSeq Classes;
|
|
ClassesSeq Protocols;
|
|
FunctionsSeq Functions;
|
|
GlobalVariablesSeq Globals;
|
|
EnumConstantsSeq EnumConstants;
|
|
TagsSeq Tags;
|
|
TypedefsSeq Typedefs;
|
|
NamespacesSeq Namespaces;
|
|
};
|
|
} // namespace
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
static void mapTopLevelItems(IO &IO, TopLevelItems &TLI) {
|
|
IO.mapOptional("Classes", TLI.Classes);
|
|
IO.mapOptional("Protocols", TLI.Protocols);
|
|
IO.mapOptional("Functions", TLI.Functions);
|
|
IO.mapOptional("Globals", TLI.Globals);
|
|
IO.mapOptional("Enumerators", TLI.EnumConstants);
|
|
IO.mapOptional("Tags", TLI.Tags);
|
|
IO.mapOptional("Typedefs", TLI.Typedefs);
|
|
IO.mapOptional("Namespaces", TLI.Namespaces);
|
|
}
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct Namespace {
|
|
StringRef Name;
|
|
AvailabilityItem Availability;
|
|
StringRef SwiftName;
|
|
std::optional<bool> SwiftPrivate;
|
|
TopLevelItems Items;
|
|
};
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Namespace)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct MappingTraits<Namespace> {
|
|
static void mapping(IO &IO, Namespace &T) {
|
|
IO.mapRequired("Name", T.Name);
|
|
IO.mapOptional("Availability", T.Availability.Mode,
|
|
APIAvailability::Available);
|
|
IO.mapOptional("AvailabilityMsg", T.Availability.Msg, StringRef(""));
|
|
IO.mapOptional("SwiftPrivate", T.SwiftPrivate);
|
|
IO.mapOptional("SwiftName", T.SwiftName, StringRef(""));
|
|
mapTopLevelItems(IO, T.Items);
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct Versioned {
|
|
VersionTuple Version;
|
|
TopLevelItems Items;
|
|
};
|
|
|
|
typedef std::vector<Versioned> VersionedSeq;
|
|
} // namespace
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Versioned)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct MappingTraits<Versioned> {
|
|
static void mapping(IO &IO, Versioned &V) {
|
|
IO.mapRequired("Version", V.Version);
|
|
mapTopLevelItems(IO, V.Items);
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
namespace {
|
|
struct Module {
|
|
StringRef Name;
|
|
AvailabilityItem Availability;
|
|
TopLevelItems TopLevel;
|
|
VersionedSeq SwiftVersions;
|
|
|
|
std::optional<bool> SwiftInferImportAsMember;
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
LLVM_DUMP_METHOD void dump() /*const*/;
|
|
#endif
|
|
};
|
|
} // namespace
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
template <> struct MappingTraits<Module> {
|
|
static void mapping(IO &IO, Module &M) {
|
|
IO.mapRequired("Name", M.Name);
|
|
IO.mapOptional("Availability", M.Availability.Mode,
|
|
APIAvailability::Available);
|
|
IO.mapOptional("AvailabilityMsg", M.Availability.Msg, StringRef(""));
|
|
IO.mapOptional("SwiftInferImportAsMember", M.SwiftInferImportAsMember);
|
|
mapTopLevelItems(IO, M.TopLevel);
|
|
IO.mapOptional("SwiftVersions", M.SwiftVersions);
|
|
}
|
|
};
|
|
} // namespace yaml
|
|
} // namespace llvm
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
LLVM_DUMP_METHOD void Module::dump() {
|
|
llvm::yaml::Output OS(llvm::errs());
|
|
OS << *this;
|
|
}
|
|
#endif
|
|
|
|
namespace {
|
|
bool parseAPINotes(StringRef YI, Module &M, llvm::SourceMgr::DiagHandlerTy Diag,
|
|
void *DiagContext) {
|
|
llvm::yaml::Input IS(YI, nullptr, Diag, DiagContext);
|
|
IS >> M;
|
|
return static_cast<bool>(IS.error());
|
|
}
|
|
} // namespace
|
|
|
|
bool clang::api_notes::parseAndDumpAPINotes(StringRef YI,
|
|
llvm::raw_ostream &OS) {
|
|
Module M;
|
|
if (parseAPINotes(YI, M, nullptr, nullptr))
|
|
return true;
|
|
|
|
llvm::yaml::Output YOS(OS);
|
|
YOS << M;
|
|
|
|
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,
|
|
std::optional<ParamInfo> &thisOrSelf) {
|
|
for (const auto &P : Params) {
|
|
ParamInfo PI;
|
|
if (P.Nullability)
|
|
PI.setNullabilityAudited(*P.Nullability);
|
|
PI.setNoEscape(P.NoEscape);
|
|
PI.setLifetimebound(P.Lifetimebound);
|
|
PI.setType(std::string(P.Type));
|
|
PI.setRetainCountConvention(P.RetainCountConvention);
|
|
if (static_cast<int>(OutInfo.Params.size()) <= P.Position)
|
|
OutInfo.Params.resize(P.Position + 1);
|
|
if (P.Position == -1)
|
|
thisOrSelf = PI;
|
|
else if (P.Position >= 0)
|
|
OutInfo.Params[P.Position] |= PI;
|
|
else
|
|
emitError("invalid parameter position " + llvm::itostr(P.Position));
|
|
}
|
|
}
|
|
|
|
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.value_or(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.ends_with(":");
|
|
|
|
// 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);
|
|
MI.SwiftReturnOwnership = std::string(M.SwiftReturnOwnership);
|
|
|
|
// Translate parameter information.
|
|
convertParams(M.Params, MI, MI.Self);
|
|
|
|
// 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);
|
|
}
|
|
|
|
template <typename T>
|
|
void convertVariable(const T &Entity, VariableInfo &VI) {
|
|
convertAvailability(Entity.Availability, VI, Entity.Name);
|
|
VI.setSwiftPrivate(Entity.SwiftPrivate);
|
|
VI.SwiftName = std::string(Entity.SwiftName);
|
|
if (Entity.Nullability)
|
|
VI.setNullabilityAudited(*Entity.Nullability);
|
|
VI.setType(std::string(Entity.Type));
|
|
}
|
|
|
|
void convertContext(std::optional<ContextID> ParentContextID, const Class &C,
|
|
ContextKind Kind, VersionTuple SwiftVersion) {
|
|
// Write the class.
|
|
ContextInfo 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.addContext(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;
|
|
convertVariable(Property, PI);
|
|
if (Property.SwiftImportAsAccessors)
|
|
PI.setSwiftImportAsAccessors(*Property.SwiftImportAsAccessors);
|
|
|
|
// Add both instance and class properties with this name.
|
|
if (Property.Kind) {
|
|
Writer.addObjCProperty(CtxID, Property.Name,
|
|
*Property.Kind == MethodKind::Instance, PI,
|
|
SwiftVersion);
|
|
} else {
|
|
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.
|
|
ContextInfo CI;
|
|
convertCommonEntity(TheNamespace, CI, TheNamespace.Name);
|
|
|
|
ContextID CtxID =
|
|
Writer.addContext(ParentContextID, TheNamespace.Name,
|
|
ContextKind::Namespace, CI, SwiftVersion);
|
|
|
|
convertTopLevelItems(Context(CtxID, ContextKind::Namespace),
|
|
TheNamespace.Items, SwiftVersion);
|
|
}
|
|
|
|
template <typename FuncOrMethodInfo>
|
|
void convertFunction(const Function &Function, FuncOrMethodInfo &FI) {
|
|
convertAvailability(Function.Availability, FI, Function.Name);
|
|
FI.setSwiftPrivate(Function.SwiftPrivate);
|
|
FI.SwiftName = std::string(Function.SwiftName);
|
|
std::optional<ParamInfo> This;
|
|
convertParams(Function.Params, FI, This);
|
|
if constexpr (std::is_same_v<FuncOrMethodInfo, CXXMethodInfo>)
|
|
FI.This = This;
|
|
else if (This)
|
|
emitError("implicit instance parameter is only permitted on C++ and "
|
|
"Objective-C methods");
|
|
convertNullability(Function.Nullability, Function.NullabilityOfRet, FI,
|
|
Function.Name);
|
|
FI.ResultType = std::string(Function.ResultType);
|
|
FI.SwiftReturnOwnership = std::string(Function.SwiftReturnOwnership);
|
|
FI.setRetainCountConvention(Function.RetainCountConvention);
|
|
}
|
|
|
|
void convertTagContext(std::optional<Context> ParentContext, const Tag &T,
|
|
VersionTuple SwiftVersion) {
|
|
TagInfo TI;
|
|
std::optional<ContextID> ParentContextID =
|
|
ParentContext ? std::optional<ContextID>(ParentContext->id)
|
|
: std::nullopt;
|
|
convertCommonType(T, TI, T.Name);
|
|
|
|
if ((T.SwiftRetainOp || T.SwiftReleaseOp) && !T.SwiftImportAs) {
|
|
emitError(llvm::Twine("should declare SwiftImportAs to use "
|
|
"SwiftRetainOp and SwiftReleaseOp (for ") +
|
|
T.Name + ")");
|
|
return;
|
|
}
|
|
if (T.SwiftReleaseOp.has_value() != T.SwiftRetainOp.has_value()) {
|
|
emitError(llvm::Twine("should declare both SwiftReleaseOp and "
|
|
"SwiftRetainOp (for ") +
|
|
T.Name + ")");
|
|
return;
|
|
}
|
|
|
|
if (T.SwiftImportAs)
|
|
TI.SwiftImportAs = T.SwiftImportAs;
|
|
if (T.SwiftRetainOp)
|
|
TI.SwiftRetainOp = T.SwiftRetainOp;
|
|
if (T.SwiftReleaseOp)
|
|
TI.SwiftReleaseOp = T.SwiftReleaseOp;
|
|
if (T.SwiftConformance)
|
|
TI.SwiftConformance = T.SwiftConformance;
|
|
|
|
if (T.SwiftCopyable)
|
|
TI.setSwiftCopyable(T.SwiftCopyable);
|
|
if (T.SwiftEscapable)
|
|
TI.setSwiftEscapable(T.SwiftEscapable);
|
|
|
|
if (T.EnumConvenienceKind) {
|
|
if (T.EnumExtensibility) {
|
|
emitError(
|
|
llvm::Twine("cannot mix EnumKind and EnumExtensibility (for ") +
|
|
T.Name + ")");
|
|
return;
|
|
}
|
|
if (T.FlagEnum) {
|
|
emitError(llvm::Twine("cannot mix EnumKind and FlagEnum (for ") +
|
|
T.Name + ")");
|
|
return;
|
|
}
|
|
switch (*T.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 = T.EnumExtensibility;
|
|
TI.setFlagEnum(T.FlagEnum);
|
|
}
|
|
|
|
Writer.addTag(ParentContext, T.Name, TI, SwiftVersion);
|
|
|
|
ContextInfo CI;
|
|
auto TagCtxID = Writer.addContext(ParentContextID, T.Name, ContextKind::Tag,
|
|
CI, SwiftVersion);
|
|
Context TagCtx(TagCtxID, ContextKind::Tag);
|
|
|
|
for (const auto &Field : T.Fields) {
|
|
FieldInfo FI;
|
|
convertVariable(Field, FI);
|
|
Writer.addField(TagCtxID, Field.Name, FI, SwiftVersion);
|
|
}
|
|
|
|
for (const auto &CXXMethod : T.Methods) {
|
|
CXXMethodInfo MI;
|
|
convertFunction(CXXMethod, MI);
|
|
Writer.addCXXMethod(TagCtxID, CXXMethod.Name, MI, SwiftVersion);
|
|
}
|
|
|
|
// Convert nested tags.
|
|
for (const auto &Tag : T.Tags)
|
|
convertTagContext(TagCtx, Tag, 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;
|
|
convertVariable(Global, GVI);
|
|
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;
|
|
convertFunction(Function, GFI);
|
|
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;
|
|
}
|
|
|
|
convertTagContext(Ctx, Tag, 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);
|
|
|
|
if (!ErrorOccured)
|
|
Writer.writeToStream(OS);
|
|
|
|
return ErrorOccured;
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
static bool compile(const Module &M, const FileEntry *SourceFile,
|
|
llvm::raw_ostream &OS,
|
|
llvm::SourceMgr::DiagHandlerTy DiagHandler,
|
|
void *DiagHandlerCtxt) {
|
|
YAMLConverter C(M, SourceFile, OS, DiagHandler, DiagHandlerCtxt);
|
|
return C.convertModule();
|
|
}
|
|
|
|
/// Simple diagnostic handler that prints diagnostics to standard error.
|
|
static void printDiagnostic(const llvm::SMDiagnostic &Diag, void *Context) {
|
|
Diag.print(nullptr, llvm::errs());
|
|
}
|
|
|
|
bool api_notes::compileAPINotes(StringRef YAMLInput,
|
|
const FileEntry *SourceFile,
|
|
llvm::raw_ostream &OS,
|
|
llvm::SourceMgr::DiagHandlerTy DiagHandler,
|
|
void *DiagHandlerCtxt) {
|
|
Module TheModule;
|
|
|
|
if (!DiagHandler)
|
|
DiagHandler = &printDiagnostic;
|
|
|
|
if (parseAPINotes(YAMLInput, TheModule, DiagHandler, DiagHandlerCtxt))
|
|
return true;
|
|
|
|
return compile(TheModule, SourceFile, OS, DiagHandler, DiagHandlerCtxt);
|
|
}
|