| //===--- ModuleAPIDiff.cpp - Swift Module API I/O -------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ModuleAPIDiff.h" |
| #include "swift/AST/DiagnosticEngine.h" |
| #include "swift/AST/GenericSignature.h" |
| #include "swift/AST/ASTVisitor.h" |
| #include "swift/Basic/SourceManager.h" |
| #include "swift/Driver/FrontendUtil.h" |
| #include "swift/Frontend/Frontend.h" |
| #include "swift/Frontend/PrintingDiagnosticConsumer.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/Optional.h" |
| #include "llvm/Support/YAMLTraits.h" |
| #include <memory> |
| |
| using namespace swift; |
| |
| /* |
| |
| Machine-Readable Representation of API and ABI of a Swift Module (SMA) |
| ====================================================================== |
| |
| SMA stands for Swift Module API/ABI. |
| |
| This format is designed to accurately represent API (and, in future, ABI) of a |
| Swift module. Design constraints are as follows: |
| |
| - the format should allow comparing API and ABI of two different modules |
| produced by two different compilers; |
| |
| - the comparison procedure should be as simple as possible (ideally, applying |
| diff(1) to the files should produce reasonable results; next preference is a |
| simple, generic, tree diffing algorithm that is not actually aware of the |
| data model); |
| |
| - a comparison that is aware of the data model should be able to automatically |
| judge if two modules are ABI- or ABI-compatible; |
| |
| - the format should be machine-readable; |
| |
| - the format should be human-readable as long as it does not hurt other goals; |
| |
| - the format should be able to sustain significant changes (within reason) to |
| any aspects of the Swift language, including syntax changes, type system |
| changes, AST representation changes within the compiler etc. |
| |
| - the immediate goal is to capture the module API, but we would like to be able |
| to extend this format to carry ABI information in future. |
| |
| If you find this format useful for any other purpose (for example, generating |
| documentation), it is completely incidental; we recommend not to rely on this |
| facility for other purposes. |
| |
| module ::= |
| Name: <identifier> |
| ExportedModules: [ <submodule-name>* ] (default: none) |
| <nested-decls> |
| |
| nested-decls ::= |
| NestedDecls: (all unordered, default: none) |
| Structs: [ <struct-decl>* ] |
| Enums: [ <enum-decl>* ] |
| Classes: [ <class-decl>* ] |
| Protocols: [ <protocol-decl>* ] |
| Typealiases: [ <typealias-decl>* ] |
| AssociatedTypes: [ <associated-type-decl>* ] |
| Vars: [ <var-decl>* ] |
| Lets: [ <let-decl>* ] |
| Functions: [ <func-decl>* ] |
| Initializers: [ <init-decl>* ] |
| Deinitializers: [ <deinit-decl>* ] |
| |
| generic-signature ::= |
| GenericSignature: |
| GenericParams: (ordered) |
| - Name: <identifier> |
| ConformanceRequirements: |
| - Type: <type-name> |
| ProtocolOrClass: <type-name> |
| SameTypeRequirements: |
| - FirstType: <type-name> |
| SecondType: <type-name> |
| |
| struct-decl ::= |
| Name: <identifier> |
| <generic-signature>? |
| ConformsToProtocols: [ <type-name>* ] (default: none) |
| <decl-attributes>? |
| <nested-decls> |
| |
| enum-case-decl ::= |
| Name: <identifier> |
| ArgumentType: <type-name> (default: none) |
| RawValue: <string> (default: none) |
| <decl-attributes>? |
| |
| enum-decl ::= |
| Name: <identifier> |
| <generic-signature>? |
| RawType: <type-name>? (default: none) |
| ConformsToProtocols: [ <type-name>* ] (default: none) |
| <decl-attributes>? |
| Cases: [ <enum-case-decl>* ] (default: none) |
| <nested-decls> |
| |
| class-decl ::= |
| Name: <identifier> |
| <generic-signature>? |
| Superclass: <type-name>? (default: none) |
| ConformsToProtocols: [ <type-name>* ] (default: none) |
| <decl-attributes>? |
| <nested-decls> |
| |
| protocol-decl ::= |
| Name: <identifier> |
| ConformsToProtocols: [ <type-name>* ] (default: none) |
| <decl-attributes>? |
| <nested-decls> |
| |
| typealias-decl ::= |
| Name: <identifier> |
| Type: <type-name> |
| <decl-attributes>? |
| |
| associated-type-decl ::= |
| Name: <identifier> |
| Superclass: <type-name>? (default: none) |
| DefaultDefinition: <type-name>? (default: none) |
| <decl-attributes>? |
| |
| var-decl ::= |
| Name: <identifier> |
| Type: <type-name> |
| IsSettable: <bool> |
| IsStored: <bool> |
| <decl-attributes>? |
| |
| let-decl ::= |
| Name: <identifier> |
| Type: <type-name> |
| <decl-attributes>? |
| |
| func-param ::= |
| Name: <identifier> |
| Type: <type-name> |
| IsInout: <bool> (default: false) |
| <decl-attributes>? |
| |
| func-decl ::= |
| IsStatic: <bool> (default: false) |
| Name: <function-name> |
| <generic-signature>? |
| Params: |
| [ [ <func-param>* ]* ] |
| ResultType: <type-name> |
| <decl-attributes>? |
| |
| init-decl ::= |
| InitializerKind: (Designated|Convenience) |
| InitializerFailability: (None|Optional|ImplicitlyUnwrappedOptional) (default: None) |
| <generic-signature>? |
| Params: |
| [ <func-param>* ] |
| IsTrappingStub: <bool> (default: false) |
| <decl-attributes>? |
| |
| deinit-decl ::= |
| Name: deinit (always 'deinit'; introduced so that the decl is non-empty) |
| <decl-attributes>? |
| |
| identifier ::= <string> |
| |
| // A sequence of dot-separated identifiers. |
| submodule-name ::= <string> |
| |
| type-name ::= <string> |
| |
| decl-attributes ::= |
| Attributes: (default: false) |
| IsClassProtocol: <bool> |
| IsDynamic: <bool> |
| IsFinal: <bool> |
| IsLazy: <bool> |
| IsMutating: <bool> |
| IsObjC: <bool> |
| IsOptional: <bool> |
| IsRequired: <bool> |
| IsRequiresStoredPropertyInits: <bool> |
| IsTransparent: <bool> |
| IsWeak: <bool> |
| |
| */ |
| |
| // SMA data model is defined in 'swift::sma' namespace. |
| // |
| // Never 'use namespace swift::sma'. |
| // |
| // It is fine to shadow names from the 'swift' namespace in 'swift::sma'. |
| // |
| // Don't use any AST types in 'swift::sma'. Only use simple types like |
| // 'std::string', 'std::vector', 'std::map' etc. |
| |
| /// Define a type 'swift::sma::TYPE_NAME' that is a "strong typedef" for |
| /// 'std::string'. |
| #define DEFINE_SMA_STRING_STRONG_TYPEDEF(TYPE_NAME, STRING_MEMBER_NAME) \ |
| namespace swift { \ |
| namespace sma { \ |
| struct TYPE_NAME { \ |
| std::string STRING_MEMBER_NAME; \ |
| }; \ |
| } /* namespace sma */ \ |
| } /* namespace swift */ \ |
| \ |
| namespace llvm { \ |
| namespace yaml { \ |
| template <> struct ScalarTraits<::swift::sma::TYPE_NAME> { \ |
| static void output(const ::swift::sma::TYPE_NAME &Val, void *Context, \ |
| llvm::raw_ostream &Out) { \ |
| ScalarTraits<std::string>::output(Val.STRING_MEMBER_NAME, Context, Out); \ |
| } \ |
| static StringRef input(StringRef Scalar, void *Context, \ |
| ::swift::sma::TYPE_NAME &Val) { \ |
| return ScalarTraits<std::string>::input(Scalar, Context, \ |
| Val.STRING_MEMBER_NAME); \ |
| } \ |
| static QuotingType mustQuote(StringRef S) { \ |
| return ScalarTraits<std::string>::mustQuote(S); \ |
| } \ |
| }; \ |
| } /* namespace yaml */ \ |
| } /* namespace llvm */ |
| |
| DEFINE_SMA_STRING_STRONG_TYPEDEF(Identifier, Name) |
| DEFINE_SMA_STRING_STRONG_TYPEDEF(FunctionName, Name) |
| DEFINE_SMA_STRING_STRONG_TYPEDEF(TypeName, Name) |
| DEFINE_SMA_STRING_STRONG_TYPEDEF(SubmoduleName, Name) |
| |
| #undef DEFINE_SMA_STRING_STRONG_TYPEDEF |
| |
| namespace swift { |
| namespace sma { |
| |
| using llvm::Optional; |
| |
| #define SMA_FOR_EVERY_DECL_ATTRIBUTE(MACRO) \ |
| MACRO(IsDynamic) \ |
| MACRO(IsFinal) \ |
| MACRO(IsLazy) \ |
| MACRO(IsMutating) \ |
| MACRO(IsObjC) \ |
| MACRO(IsOptional) \ |
| MACRO(IsRequired) \ |
| MACRO(IsRequiresStoredPropertyInits) \ |
| MACRO(IsTransparent) \ |
| MACRO(IsWeak) |
| |
| struct DeclAttributes { |
| #define DEFINE_MEMBER(NAME) bool NAME = false; |
| SMA_FOR_EVERY_DECL_ATTRIBUTE(DEFINE_MEMBER) |
| #undef DEFINE_MEMBER |
| }; |
| |
| bool operator==(const DeclAttributes &LHS, const DeclAttributes &RHS) { |
| return |
| #define PROCESS_MEMBER(NAME) LHS.NAME == RHS.NAME && |
| SMA_FOR_EVERY_DECL_ATTRIBUTE(PROCESS_MEMBER) |
| #undef PROCESS_MEMBER |
| // Add an identity element for && over bools. |
| true; |
| } |
| |
| struct StructDecl; |
| struct EnumDecl; |
| struct ClassDecl; |
| struct ProtocolDecl; |
| struct TypealiasDecl; |
| struct AssociatedTypeDecl; |
| struct VarDecl; |
| struct LetDecl; |
| struct FuncDecl; |
| struct InitDecl; |
| struct DeinitDecl; |
| |
| /// A container for declarations contained in some declaration context. |
| struct NestedDecls { |
| std::vector<std::shared_ptr<StructDecl>> Structs; |
| std::vector<std::shared_ptr<EnumDecl>> Enums; |
| std::vector<std::shared_ptr<ClassDecl>> Classes; |
| std::vector<std::shared_ptr<ProtocolDecl>> Protocols; |
| std::vector<std::shared_ptr<TypealiasDecl>> Typealiases; |
| std::vector<std::shared_ptr<AssociatedTypeDecl>> AssociatedTypes; |
| std::vector<std::shared_ptr<VarDecl>> Vars; |
| std::vector<std::shared_ptr<LetDecl>> Lets; |
| std::vector<std::shared_ptr<FuncDecl>> Functions; |
| std::vector<std::shared_ptr<InitDecl>> Initializers; |
| std::vector<std::shared_ptr<DeinitDecl>> Deinitializers; |
| |
| bool isEmpty() const { |
| return Structs.empty() && Enums.empty() && Classes.empty() && |
| Protocols.empty() && Typealiases.empty() && |
| AssociatedTypes.empty() && Vars.empty() && Lets.empty() && |
| Functions.empty() && Initializers.empty() && Deinitializers.empty(); |
| } |
| }; |
| |
| bool operator==(const NestedDecls &LHS, const NestedDecls &RHS) { |
| // Only empty instances compare equal. |
| return LHS.isEmpty() && RHS.isEmpty(); |
| } |
| |
| struct GenericParam { |
| Identifier Name; |
| }; |
| |
| struct ConformanceRequirement { |
| TypeName Type; |
| TypeName Protocol; |
| }; |
| |
| struct SameTypeRequirement { |
| TypeName FirstType; |
| TypeName SecondType; |
| }; |
| |
| struct GenericSignature { |
| std::vector<GenericParam> GenericParams; |
| std::vector<ConformanceRequirement> ConformanceRequirements; |
| std::vector<SameTypeRequirement> SameTypeRequirements; |
| }; |
| |
| struct Module { |
| Identifier Name; |
| std::vector<SubmoduleName> ExportedModules; |
| NestedDecls Decls; |
| }; |
| |
| struct StructDecl { |
| Identifier Name; |
| Optional<GenericSignature> TheGenericSignature; |
| std::vector<TypeName> ConformsToProtocols; |
| DeclAttributes Attributes; |
| NestedDecls Decls; |
| }; |
| |
| struct EnumCaseDecl { |
| Identifier Name; |
| TypeName ArgumentType; |
| std::string RawValue; |
| DeclAttributes Attributes; |
| }; |
| |
| struct EnumDecl { |
| Identifier Name; |
| Optional<GenericSignature> TheGenericSignature; |
| Optional<TypeName> RawType; |
| std::vector<TypeName> ConformsToProtocols; |
| DeclAttributes Attributes; |
| std::vector<std::shared_ptr<EnumCaseDecl>> Cases; |
| NestedDecls Decls; |
| }; |
| |
| struct ClassDecl { |
| Identifier Name; |
| Optional<GenericSignature> TheGenericSignature; |
| Optional<TypeName> Superclass; |
| std::vector<TypeName> ConformsToProtocols; |
| DeclAttributes Attributes; |
| NestedDecls Decls; |
| }; |
| |
| struct ProtocolDecl { |
| Identifier Name; |
| std::vector<TypeName> ConformsToProtocols; |
| DeclAttributes Attributes; |
| NestedDecls Decls; |
| }; |
| |
| struct TypealiasDecl { |
| Identifier Name; |
| TypeName Type; |
| DeclAttributes Attributes; |
| }; |
| |
| struct AssociatedTypeDecl { |
| Identifier Name; |
| Optional<TypeName> Superclass; |
| Optional<TypeName> DefaultDefinition; |
| DeclAttributes Attributes; |
| }; |
| |
| struct VarDecl { |
| Identifier Name; |
| TypeName Type; |
| bool IsSettable = false; |
| bool IsStored = false; |
| DeclAttributes Attributes; |
| }; |
| |
| struct LetDecl { |
| Identifier Name; |
| TypeName Type; |
| DeclAttributes Attributes; |
| }; |
| |
| struct FuncParam { |
| Identifier Name; |
| TypeName Type; |
| bool IsInout = false; |
| DeclAttributes Attributes; |
| }; |
| |
| struct FuncDecl { |
| FunctionName Name; |
| bool IsStatic = false; |
| Optional<GenericSignature> TheGenericSignature; |
| std::vector<std::vector<FuncParam>> Params; |
| TypeName ResultType; |
| DeclAttributes Attributes; |
| }; |
| |
| enum class InitializerKind { |
| Designated, |
| Convenience, |
| }; |
| |
| enum class InitializerFailability { |
| None, // default |
| Optional, |
| ImplicitlyUnwrappedOptional, |
| }; |
| |
| struct InitDecl { |
| InitializerKind TheInitializerKind; |
| InitializerFailability TheInitializerFailability; |
| Optional<GenericSignature> TheGenericSignature; |
| std::vector<FuncParam> Params; |
| bool IsTrappingStub = false; |
| DeclAttributes Attributes; |
| }; |
| |
| struct DeinitDecl { |
| Identifier Name; |
| DeclAttributes Attributes; |
| }; |
| |
| } // namespace sma |
| } // namespace swift |
| |
| namespace llvm { |
| namespace yaml { |
| template <typename T> struct MappingTraits<std::shared_ptr<T>> { |
| static void mapping(IO &io, std::shared_ptr<T> &Ptr) { |
| MappingTraits<T>::mapping(io, *Ptr.get()); |
| } |
| }; |
| } // namespace yaml |
| } // namespace llvm |
| |
| LLVM_YAML_IS_SEQUENCE_VECTOR(::swift::sma::TypeName) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(::swift::sma::SubmoduleName) |
| |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::StructDecl>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::EnumCaseDecl>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::EnumDecl>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::ClassDecl>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::ProtocolDecl>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::TypealiasDecl>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::AssociatedTypeDecl>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::VarDecl>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::LetDecl>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(::swift::sma::FuncParam) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::vector<::swift::sma::FuncParam>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::FuncDecl>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::InitDecl>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<::swift::sma::DeinitDecl>) |
| |
| LLVM_YAML_IS_SEQUENCE_VECTOR(::swift::sma::GenericParam) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(::swift::sma::ConformanceRequirement) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(::swift::sma::SameTypeRequirement) |
| |
| namespace llvm { |
| namespace yaml { |
| template <> struct MappingTraits<::swift::sma::DeclAttributes> { |
| static void mapping(IO &io, ::swift::sma::DeclAttributes &DA) { |
| #define SERIALIZE_MEMBER(NAME) io.mapOptional(#NAME, DA.NAME, false); |
| SMA_FOR_EVERY_DECL_ATTRIBUTE(SERIALIZE_MEMBER) |
| #undef SERIALIZE_MEMBER |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::NestedDecls> { |
| // Defined out of line to break circular dependency. |
| static void mapping(IO &io, ::swift::sma::NestedDecls &ND); |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::GenericParam> { |
| static void mapping(IO &io, ::swift::sma::GenericParam &ND) { |
| io.mapRequired("Name", ND.Name); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::ConformanceRequirement> { |
| static void mapping(IO &io, ::swift::sma::ConformanceRequirement &CR) { |
| io.mapRequired("Type", CR.Type); |
| io.mapRequired("Protocol", CR.Protocol); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::SameTypeRequirement> { |
| static void mapping(IO &io, ::swift::sma::SameTypeRequirement &STR) { |
| io.mapRequired("FirstType", STR.FirstType); |
| io.mapRequired("SecondType", STR.SecondType); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::GenericSignature> { |
| static void mapping(IO &io, ::swift::sma::GenericSignature &GS) { |
| io.mapOptional("GenericParams", GS.GenericParams); |
| io.mapOptional("ConformanceRequirements", GS.ConformanceRequirements); |
| io.mapOptional("SameTypeRequirements", GS.SameTypeRequirements); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::Module> { |
| static void mapping(IO &io, ::swift::sma::Module &M) { |
| io.mapRequired("Name", M.Name); |
| io.mapOptional("ExportedModules", M.ExportedModules); |
| io.mapOptional("NestedDecls", M.Decls, ::swift::sma::NestedDecls()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::StructDecl> { |
| static void mapping(IO &io, ::swift::sma::StructDecl &SD) { |
| io.mapRequired("Name", SD.Name); |
| io.mapOptional("GenericSignature", SD.TheGenericSignature); |
| io.mapOptional("ConformsToProtocols", SD.ConformsToProtocols); |
| io.mapOptional("Attributes", SD.Attributes, ::swift::sma::DeclAttributes()); |
| io.mapOptional("NestedDecls", SD.Decls, ::swift::sma::NestedDecls()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::EnumCaseDecl> { |
| static void mapping(IO &io, ::swift::sma::EnumCaseDecl &ECD) { |
| io.mapRequired("Name", ECD.Name); |
| io.mapOptional("ArgumentType", ECD.ArgumentType); |
| io.mapOptional("RawValue", ECD.RawValue); |
| io.mapOptional("Attributes", ECD.Attributes, |
| ::swift::sma::DeclAttributes()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::EnumDecl> { |
| static void mapping(IO &io, ::swift::sma::EnumDecl &ED) { |
| io.mapRequired("Name", ED.Name); |
| io.mapOptional("GenericSignature", ED.TheGenericSignature); |
| io.mapOptional("RawType", ED.RawType); |
| io.mapOptional("ConformsToProtocols", ED.ConformsToProtocols); |
| io.mapOptional("Attributes", ED.Attributes, ::swift::sma::DeclAttributes()); |
| io.mapOptional("Cases", ED.Cases); |
| io.mapOptional("NestedDecls", ED.Decls, ::swift::sma::NestedDecls()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::ClassDecl> { |
| static void mapping(IO &io, ::swift::sma::ClassDecl &CD) { |
| io.mapRequired("Name", CD.Name); |
| io.mapOptional("GenericSignature", CD.TheGenericSignature); |
| io.mapOptional("Superclass", CD.Superclass); |
| io.mapOptional("ConformsToProtocols", CD.ConformsToProtocols); |
| io.mapOptional("Attributes", CD.Attributes, ::swift::sma::DeclAttributes()); |
| io.mapOptional("NestedDecls", CD.Decls, ::swift::sma::NestedDecls()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::ProtocolDecl> { |
| static void mapping(IO &io, ::swift::sma::ProtocolDecl &PD) { |
| io.mapRequired("Name", PD.Name); |
| io.mapOptional("ConformsToProtocols", PD.ConformsToProtocols); |
| io.mapOptional("Attributes", PD.Attributes, ::swift::sma::DeclAttributes()); |
| io.mapOptional("NestedDecls", PD.Decls, ::swift::sma::NestedDecls()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::TypealiasDecl> { |
| static void mapping(IO &io, ::swift::sma::TypealiasDecl &TD) { |
| io.mapRequired("Name", TD.Name); |
| io.mapRequired("Type", TD.Type); |
| io.mapOptional("Attributes", TD.Attributes, ::swift::sma::DeclAttributes()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::AssociatedTypeDecl> { |
| static void mapping(IO &io, ::swift::sma::AssociatedTypeDecl &ATD) { |
| io.mapRequired("Name", ATD.Name); |
| io.mapOptional("Superclass", ATD.Superclass); |
| io.mapOptional("DefaultDefinition", ATD.DefaultDefinition); |
| io.mapOptional("Attributes", ATD.Attributes, |
| ::swift::sma::DeclAttributes()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::VarDecl> { |
| static void mapping(IO &io, ::swift::sma::VarDecl &VD) { |
| io.mapRequired("Name", VD.Name); |
| io.mapRequired("Type", VD.Type); |
| io.mapOptional("IsSettable", VD.IsSettable, false); |
| io.mapOptional("IsStored", VD.IsStored, false); |
| io.mapOptional("Attributes", VD.Attributes, ::swift::sma::DeclAttributes()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::LetDecl> { |
| static void mapping(IO &io, ::swift::sma::LetDecl &LD) { |
| io.mapRequired("Name", LD.Name); |
| io.mapRequired("Type", LD.Type); |
| io.mapOptional("Attributes", LD.Attributes, ::swift::sma::DeclAttributes()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::FuncParam> { |
| static void mapping(IO &io, ::swift::sma::FuncParam &FP) { |
| io.mapRequired("Name", FP.Name); |
| io.mapRequired("Type", FP.Type); |
| io.mapOptional("IsInout", FP.IsInout, false); |
| io.mapOptional("Attributes", FP.Attributes, ::swift::sma::DeclAttributes()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::FuncDecl> { |
| static void mapping(IO &io, ::swift::sma::FuncDecl &FD) { |
| io.mapRequired("Name", FD.Name); |
| io.mapOptional("IsStatic", FD.IsStatic, false); |
| io.mapOptional("GenericSignature", FD.TheGenericSignature); |
| io.mapRequired("Params", FD.Params); |
| io.mapRequired("ResultType", FD.ResultType); |
| io.mapOptional("Attributes", FD.Attributes, ::swift::sma::DeclAttributes()); |
| } |
| }; |
| |
| template <> struct ScalarEnumerationTraits<::swift::sma::InitializerKind> { |
| static void enumeration(IO &io, ::swift::sma::InitializerKind &Value) { |
| io.enumCase(Value, "Designated", ::swift::sma::InitializerKind::Designated); |
| io.enumCase(Value, "Convenience", |
| ::swift::sma::InitializerKind::Convenience); |
| } |
| }; |
| |
| template <> |
| struct ScalarEnumerationTraits<::swift::sma::InitializerFailability> { |
| static void enumeration(IO &io, ::swift::sma::InitializerFailability &Value) { |
| io.enumCase(Value, "None", ::swift::sma::InitializerFailability::None); |
| io.enumCase(Value, "Optional", |
| ::swift::sma::InitializerFailability::Optional); |
| io.enumCase( |
| Value, "ImplicitlyUnwrappedOptional", |
| ::swift::sma::InitializerFailability::ImplicitlyUnwrappedOptional); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::InitDecl> { |
| static void mapping(IO &io, ::swift::sma::InitDecl &ID) { |
| io.mapRequired("InitializerKind", ID.TheInitializerKind); |
| io.mapRequired("InitializerFailability", ID.TheInitializerFailability); |
| io.mapOptional("GenericSignature", ID.TheGenericSignature); |
| io.mapRequired("Params", ID.Params); |
| io.mapOptional("IsTrappingStub", ID.IsTrappingStub); |
| io.mapOptional("Attributes", ID.Attributes, ::swift::sma::DeclAttributes()); |
| } |
| }; |
| |
| template <> struct MappingTraits<::swift::sma::DeinitDecl> { |
| static void mapping(IO &io, ::swift::sma::DeinitDecl &DD) { |
| io.mapRequired("Name", DD.Name); |
| io.mapOptional("Attributes", DD.Attributes, ::swift::sma::DeclAttributes()); |
| } |
| }; |
| |
| void MappingTraits<::swift::sma::NestedDecls>::mapping( |
| IO &io, ::swift::sma::NestedDecls &ND) { |
| io.mapOptional("Structs", ND.Structs); |
| io.mapOptional("Enums", ND.Enums); |
| io.mapOptional("Classes", ND.Classes); |
| io.mapOptional("Protocols", ND.Protocols); |
| io.mapOptional("Typealiases", ND.Typealiases); |
| io.mapOptional("AssociatedTypes", ND.AssociatedTypes); |
| io.mapOptional("Vars", ND.Vars); |
| io.mapOptional("Lets", ND.Lets); |
| io.mapOptional("Functions", ND.Functions); |
| io.mapOptional("Initializers", ND.Initializers); |
| io.mapOptional("Deinitializers", ND.Deinitializers); |
| } |
| |
| } // namespace yaml |
| } // namespace llvm |
| |
| namespace { |
| |
| class SMAModelGenerator : public DeclVisitor<SMAModelGenerator> { |
| sma::NestedDecls Result; |
| |
| public: |
| void visit(const Decl *D) { |
| DeclVisitor<SMAModelGenerator>::visit(const_cast<Decl *>(D)); |
| } |
| |
| sma::NestedDecls &&takeNestedDecls() { return std::move(Result); } |
| |
| sma::Identifier convertToIdentifier(Identifier I) const { |
| return sma::Identifier{I.str().str()}; |
| } |
| |
| sma::TypeName convertToTypeName(Type T) const { |
| PrintOptions Options; |
| Options.PreferTypeRepr = true; |
| |
| sma::TypeName ResultTN; |
| llvm::raw_string_ostream OS(ResultTN.Name); |
| T.print(OS, Options); |
| return ResultTN; |
| } |
| |
| llvm::Optional<sma::TypeName> convertToOptionalTypeName(Type T) const { |
| if (!T) |
| return None; |
| return convertToTypeName(T); |
| } |
| |
| llvm::Optional<sma::GenericSignature> |
| convertToGenericSignature(GenericSignature GS) { |
| if (!GS) |
| return None; |
| sma::GenericSignature ResultGS; |
| for (auto *GTPT : GS->getGenericParams()) { |
| sma::GenericParam ResultGP; |
| ResultGP.Name = convertToIdentifier(GTPT->getName()); |
| ResultGS.GenericParams.emplace_back(std::move(ResultGP)); |
| } |
| for (auto &Req : GS->getRequirements()) { |
| switch (Req.getKind()) { |
| case RequirementKind::Superclass: |
| case RequirementKind::Conformance: |
| ResultGS.ConformanceRequirements.emplace_back( |
| sma::ConformanceRequirement{ |
| convertToTypeName(Req.getFirstType()), |
| convertToTypeName(Req.getSecondType())}); |
| break; |
| case RequirementKind::Layout: |
| // FIXME |
| assert(false && "Not implemented"); |
| break; |
| case RequirementKind::SameType: |
| ResultGS.SameTypeRequirements.emplace_back( |
| sma::SameTypeRequirement{convertToTypeName(Req.getFirstType()), |
| convertToTypeName(Req.getSecondType())}); |
| break; |
| } |
| } |
| return ResultGS; |
| } |
| |
| std::vector<sma::TypeName> collectProtocolConformances(NominalTypeDecl *NTD) { |
| const auto AllProtocols = NTD->getAllProtocols(); |
| std::vector<sma::TypeName> Result; |
| Result.reserve(AllProtocols.size()); |
| for (const auto *PD : AllProtocols) { |
| Result.emplace_back(convertToTypeName(PD->getDeclaredInterfaceType())); |
| } |
| return Result; |
| } |
| |
| void visitDecl(Decl *D) { |
| // FIXME: maybe don't have a default case |
| } |
| |
| void visitStructDecl(StructDecl *SD) { |
| auto ResultSD = std::make_shared<sma::StructDecl>(); |
| ResultSD->Name = convertToIdentifier(SD->getName()); |
| ResultSD->TheGenericSignature = |
| convertToGenericSignature(SD->getGenericSignature()); |
| ResultSD->ConformsToProtocols = collectProtocolConformances(SD); |
| // FIXME |
| // ResultSD->Attributes = ?; |
| // ResultSD->Decls = ?; |
| Result.Structs.emplace_back(std::move(ResultSD)); |
| } |
| |
| void visitEnumDecl(EnumDecl *ED) { |
| auto ResultED = std::make_shared<sma::EnumDecl>(); |
| ResultED->Name = convertToIdentifier(ED->getName()); |
| ResultED->TheGenericSignature = |
| convertToGenericSignature(ED->getGenericSignature()); |
| ResultED->RawType = convertToOptionalTypeName(ED->getRawType()); |
| ResultED->ConformsToProtocols = collectProtocolConformances(ED); |
| // FIXME |
| // ResultED->Attributes = ?; |
| // ResultED->Decls = ?; |
| Result.Enums.emplace_back(std::move(ResultED)); |
| } |
| |
| void visitClassDecl(ClassDecl *CD) { |
| auto ResultCD = std::make_shared<sma::ClassDecl>(); |
| ResultCD->Name = convertToIdentifier(CD->getName()); |
| ResultCD->TheGenericSignature = |
| convertToGenericSignature(CD->getGenericSignature()); |
| ResultCD->Superclass = convertToOptionalTypeName(CD->getSuperclass()); |
| ResultCD->ConformsToProtocols = collectProtocolConformances(CD); |
| // FIXME |
| // ResultCD->Attributes = ?; |
| // ResultCD->Decls = ?; |
| Result.Classes.emplace_back(std::move(ResultCD)); |
| } |
| |
| void visitProtocolDecl(ProtocolDecl *PD) { |
| auto ResultPD = std::make_shared<sma::ProtocolDecl>(); |
| ResultPD->Name = convertToIdentifier(PD->getName()); |
| ResultPD->ConformsToProtocols = collectProtocolConformances(PD); |
| // FIXME |
| // ResultPD->Attributes = ?; |
| // ResultPD->Decls = ?; |
| Result.Protocols.emplace_back(std::move(ResultPD)); |
| } |
| |
| void visitTypeAliasDecl(TypeAliasDecl *TAD) { |
| auto ResultTD = std::make_shared<sma::TypealiasDecl>(); |
| ResultTD->Name = convertToIdentifier(TAD->getName()); |
| ResultTD->Type = convertToTypeName(TAD->getUnderlyingType()); |
| // FIXME |
| // ResultTD->Attributes = ?; |
| Result.Typealiases.emplace_back(std::move(ResultTD)); |
| } |
| |
| void visitAssociatedTypeDecl(AssociatedTypeDecl *ATD) { |
| auto ResultATD = std::make_shared<sma::AssociatedTypeDecl>(); |
| ResultATD->Name = convertToIdentifier(ATD->getName()); |
| ResultATD->Superclass = convertToOptionalTypeName(ATD->getSuperclass()); |
| ResultATD->DefaultDefinition = |
| convertToOptionalTypeName(ATD->getDefaultDefinitionType()); |
| // FIXME |
| // ResultATD->Attributes = ?; |
| Result.AssociatedTypes.emplace_back(std::move(ResultATD)); |
| } |
| |
| // FIXME |
| // VarDecl |
| // LetDecl |
| |
| void visitFuncDecl(FuncDecl *FD) { |
| auto ResultFD = std::make_shared<sma::FuncDecl>(); |
| // FIXME |
| Result.Functions.emplace_back(std::move(ResultFD)); |
| } |
| |
| void visitConstructorDecl(ConstructorDecl *CD) { |
| auto ResultID = std::make_shared<sma::InitDecl>(); |
| // FIXME |
| Result.Initializers.emplace_back(std::move(ResultID)); |
| } |
| |
| void visitDestructorDecl(DestructorDecl *DD) { |
| auto ResultDD = std::make_shared<sma::DeinitDecl>(); |
| ResultDD->Name.Name = "deinit"; |
| // FIXME |
| // ResultDD->Attributes = ?; |
| Result.Deinitializers.emplace_back(std::move(ResultDD)); |
| } |
| }; |
| |
| std::shared_ptr<sma::Module> createSMAModel(ModuleDecl *M) { |
| SmallVector<Decl *, 1> Decls; |
| M->getDisplayDecls(Decls); |
| |
| SMAModelGenerator Generator; |
| for (auto *D : Decls) { |
| Generator.visit(D); |
| } |
| |
| auto ResultM = std::make_shared<sma::Module>(); |
| ResultM->Name = Generator.convertToIdentifier(M->getName()); |
| |
| // FIXME: |
| // ResultM->ExportedModules = ?; |
| |
| ResultM->Decls = Generator.takeNestedDecls(); |
| |
| return ResultM; |
| } |
| |
| } // unnamed namespace |
| |
| int swift::doGenerateModuleAPIDescription(StringRef MainExecutablePath, |
| ArrayRef<std::string> Args) { |
| std::vector<const char *> CStringArgs; |
| for (auto &S : Args) { |
| CStringArgs.push_back(S.c_str()); |
| } |
| |
| PrintingDiagnosticConsumer PDC; |
| SourceManager SM; |
| DiagnosticEngine Diags(SM); |
| Diags.addConsumer(PDC); |
| |
| CompilerInvocation Invocation; |
| bool HadError = driver::getSingleFrontendInvocationFromDriverArguments( |
| CStringArgs, Diags, [&](ArrayRef<const char *> FrontendArgs) { |
| return Invocation.parseArgs(FrontendArgs, Diags); |
| }); |
| |
| if (HadError) { |
| llvm::errs() << "error: unable to create a CompilerInvocation\n"; |
| return 1; |
| } |
| |
| Invocation.setMainExecutablePath(MainExecutablePath); |
| |
| CompilerInstance CI; |
| CI.addDiagnosticConsumer(&PDC); |
| if (CI.setup(Invocation)) |
| return 1; |
| CI.performSema(); |
| |
| PrintOptions Options = PrintOptions::printEverything(); |
| |
| ModuleDecl *M = CI.getMainModule(); |
| M->getMainSourceFile().print(llvm::outs(), Options); |
| |
| auto SMAModel = createSMAModel(M); |
| llvm::yaml::Output YOut(llvm::outs()); |
| YOut << *SMAModel.get(); |
| |
| return 0; |
| } |
| |