//===--- 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 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: ExportedModules: [ * ] (default: none) nested-decls ::= NestedDecls: (all unordered, default: none) Structs: [ * ] Enums: [ * ] Classes: [ * ] Protocols: [ * ] Typealiases: [ * ] AssociatedTypes: [ * ] Vars: [ * ] Lets: [ * ] Functions: [ * ] Initializers: [ * ] Deinitializers: [ * ] generic-signature ::= GenericSignature: GenericParams: (ordered) - Name: ConformanceRequirements: - Type: ProtocolOrClass: SameTypeRequirements: - FirstType: SecondType: struct-decl ::= Name: ? ConformsToProtocols: [ * ] (default: none) ? enum-case-decl ::= Name: ArgumentType: (default: none) RawValue: (default: none) ? enum-decl ::= Name: ? RawType: ? (default: none) ConformsToProtocols: [ * ] (default: none) ? Cases: [ * ] (default: none) class-decl ::= Name: ? Superclass: ? (default: none) ConformsToProtocols: [ * ] (default: none) ? protocol-decl ::= Name: ConformsToProtocols: [ * ] (default: none) ? typealias-decl ::= Name: Type: ? associated-type-decl ::= Name: Superclass: ? (default: none) DefaultDefinition: ? (default: none) ? var-decl ::= Name: Type: IsSettable: IsStored: ? let-decl ::= Name: Type: ? func-param ::= Name: Type: IsInout: (default: false) ? func-decl ::= IsStatic: (default: false) Name: ? Params: [ [ * ]* ] ResultType: ? init-decl ::= InitializerKind: (Designated|Convenience) InitializerFailability: (None|Optional|ImplicitlyUnwrappedOptional) (default: None) ? Params: [ * ] IsTrappingStub: (default: false) ? deinit-decl ::= Name: deinit (always 'deinit'; introduced so that the decl is non-empty) ? identifier ::= // A sequence of dot-separated identifiers. submodule-name ::= type-name ::= decl-attributes ::= Attributes: (default: false) IsClassProtocol: IsDynamic: IsFinal: IsLazy: IsMutating: IsObjC: IsOptional: IsRequired: IsRequiresStoredPropertyInits: IsTransparent: IsWeak: */ // 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::output(Val.STRING_MEMBER_NAME, Context, Out); \ } \ static StringRef input(StringRef Scalar, void *Context, \ ::swift::sma::TYPE_NAME &Val) { \ return ScalarTraits::input(Scalar, Context, \ Val.STRING_MEMBER_NAME); \ } \ static bool mustQuote(StringRef S) { \ return ScalarTraits::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> Structs; std::vector> Enums; std::vector> Classes; std::vector> Protocols; std::vector> Typealiases; std::vector> AssociatedTypes; std::vector> Vars; std::vector> Lets; std::vector> Functions; std::vector> Initializers; std::vector> 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 GenericParams; std::vector ConformanceRequirements; std::vector SameTypeRequirements; }; struct Module { Identifier Name; std::vector ExportedModules; NestedDecls Decls; }; struct StructDecl { Identifier Name; Optional TheGenericSignature; std::vector ConformsToProtocols; DeclAttributes Attributes; NestedDecls Decls; }; struct EnumCaseDecl { Identifier Name; TypeName ArgumentType; std::string RawValue; DeclAttributes Attributes; }; struct EnumDecl { Identifier Name; Optional TheGenericSignature; Optional RawType; std::vector ConformsToProtocols; DeclAttributes Attributes; std::vector> Cases; NestedDecls Decls; }; struct ClassDecl { Identifier Name; Optional TheGenericSignature; Optional Superclass; std::vector ConformsToProtocols; DeclAttributes Attributes; NestedDecls Decls; }; struct ProtocolDecl { Identifier Name; std::vector ConformsToProtocols; DeclAttributes Attributes; NestedDecls Decls; }; struct TypealiasDecl { Identifier Name; TypeName Type; DeclAttributes Attributes; }; struct AssociatedTypeDecl { Identifier Name; Optional Superclass; Optional 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 TheGenericSignature; std::vector> Params; TypeName ResultType; DeclAttributes Attributes; }; enum class InitializerKind { Designated, Convenience, }; enum class InitializerFailability { None, // default Optional, ImplicitlyUnwrappedOptional, }; struct InitDecl { InitializerKind TheInitializerKind; InitializerFailability TheInitializerFailability; Optional TheGenericSignature; std::vector Params; bool IsTrappingStub = false; DeclAttributes Attributes; }; struct DeinitDecl { Identifier Name; DeclAttributes Attributes; }; } // namespace sma } // namespace swift namespace llvm { namespace yaml { template struct MappingTraits> { static void mapping(IO &io, std::shared_ptr &Ptr) { MappingTraits::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 { sma::NestedDecls Result; public: void visit(const Decl *D) { DeclVisitor::visit(const_cast(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 convertToOptionalTypeName(Type T) const { if (!T) return None; return convertToTypeName(T); } llvm::Optional 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 collectProtocolConformances(NominalTypeDecl *NTD) { std::vector Result; for (const auto *PD : NTD->getAllProtocols()) { Result.emplace_back(convertToTypeName(PD->getDeclaredType())); } return Result; } void visitDecl(Decl *D) { // FIXME: maybe don't have a default case } void visitStructDecl(StructDecl *SD) { auto ResultSD = std::make_shared(); 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(); 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(); 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(); 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(); ResultTD->Name = convertToIdentifier(TAD->getName()); ResultTD->Type = convertToTypeName(TAD->getUnderlyingTypeLoc().getType()); // FIXME // ResultTD->Attributes = ?; Result.Typealiases.emplace_back(std::move(ResultTD)); } void visitAssociatedTypeDecl(AssociatedTypeDecl *ATD) { auto ResultATD = std::make_shared(); 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(); // FIXME Result.Functions.emplace_back(std::move(ResultFD)); } void visitConstructorDecl(ConstructorDecl *CD) { auto ResultID = std::make_shared(); // FIXME Result.Initializers.emplace_back(std::move(ResultID)); } void visitDestructorDecl(DestructorDecl *DD) { auto ResultDD = std::make_shared(); ResultDD->Name.Name = "deinit"; // FIXME // ResultDD->Attributes = ?; Result.Deinitializers.emplace_back(std::move(ResultDD)); } }; std::shared_ptr createSMAModel(ModuleDecl *M) { SmallVector Decls; M->getDisplayDecls(Decls); SMAModelGenerator Generator; for (auto *D : Decls) { Generator.visit(D); } auto ResultM = std::make_shared(); ResultM->Name = Generator.convertToIdentifier(M->getName()); // FIXME: // ResultM->ExportedModules = ?; ResultM->Decls = Generator.takeNestedDecls(); return ResultM; } } // unnamed namespace int swift::doGenerateModuleAPIDescription(StringRef MainExecutablePath, ArrayRef Args) { std::vector CStringArgs; for (auto &S : Args) { CStringArgs.push_back(S.c_str()); } PrintingDiagnosticConsumer PDC; SourceManager SM; DiagnosticEngine Diags(SM); Diags.addConsumer(PDC); std::unique_ptr Invocation = driver::createCompilerInvocation(CStringArgs, Diags); if (!Invocation) { 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(Invocation->getSourceFileKind()).print(llvm::outs(), Options); auto SMAModel = createSMAModel(M); llvm::yaml::Output YOut(llvm::outs()); YOut << *SMAModel.get(); return 0; }