//===--- ASTPrinter.cpp - Swift Language AST Printer ----------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements printing for the Swift ASTs. // //===----------------------------------------------------------------------===// #include "swift/AST/ArchetypeBuilder.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PrintOptions.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeVisitor.h" #include "swift/AST/TypeWalker.h" #include "swift/AST/Types.h" #include "swift/Basic/Fallthrough.h" #include "swift/Basic/PrimitiveParsing.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/StringExtras.h" #include "swift/Parse/Lexer.h" #include "swift/Basic/Defer.h" // Must come after include of Tokens.def. #include "swift/Config.h" #include "swift/Sema/IDETypeChecking.h" #include "swift/Strings.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/Basic/Module.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SaveAndRestore.h" #include using namespace swift; namespace swift { std::unique_ptr> collectNameTypeMap(Type Ty, const DeclContext *DC) { std::unique_ptr> IdMap( new llvm::DenseMap()); Type BaseTy = Ty->getRValueType(); do { auto D = BaseTy->getNominalOrBoundGenericNominal(); if (!D || !D->getGenericParams()) continue; SmallVector Scrach; auto Args = BaseTy->getAllGenericArgs(Scrach); const auto ParamDecls = D->getGenericParams()->getParams(); assert(ParamDecls.size() == Args.size()); // Map type parameter names with their instantiating arguments. for(unsigned I = 0, N = ParamDecls.size(); I < N; I ++) { (*IdMap)[ParamDecls[I]->getName().str()] = Args[I]; } } while ((BaseTy = BaseTy->getSuperclass(nullptr))); return IdMap; } class PrinterArchetypeTransformer { public: virtual Type transform(Type Ty) = 0; virtual StringRef transform(StringRef TypeName) = 0; virtual ~PrinterArchetypeTransformer() {}; }; class PrinterArchetypeNameTransformer : public PrinterArchetypeTransformer{ Type BaseTy; llvm::DenseMap Cache; std::unique_ptr> IdMap; public: PrinterArchetypeNameTransformer(Type Ty, const DeclContext *DC) : BaseTy(Ty->getRValueType()), IdMap(collectNameTypeMap(Ty, DC)){} StringRef transform(StringRef TypeName) override { return TypeName; } Type transform(Type Ty) override { return Ty.transform([&](Type Ty) -> Type { if (Ty->getKind() != TypeKind::Archetype) return Ty; // First, we try to find the map from cache. if (Cache.count(Ty.getPointer()) > 0) { return Cache[Ty.getPointer()]; } auto Id = cast(Ty.getPointer())->getName().str(); auto Result = Ty; // Iterate the IdMap to find the argument type of the given param name. for (auto It = IdMap->begin(); It != IdMap->end(); ++ It) { if (Id == It->getFirst()) { Result = It->getSecond(); break; } } // Put the result into cache. Cache[Ty.getPointer()] = Result; return Result; }); } }; class ArchetypeSelfTransformer : public PrinterArchetypeTransformer { Type BaseTy; DeclContext &DC; const ASTContext &Ctx; std::unique_ptr NameTransformer; llvm::StringMap Map; std::vector> Buffers; Type tryNamedArchetypeTransform(Type T) { if (NameTransformer) { return NameTransformer->transform(T); } return T; } StringRef tryNamedArchetypeTransform(StringRef T) { if (NameTransformer) { return NameTransformer->transform(T); } return T; } std::function F = [&] (Type Ty) { auto Original = Ty; Ty = Ty->getDesugaredType(); if (Ty->getKind() != TypeKind::Archetype) return Original; auto ATT = cast(Ty.getPointer()); ArchetypeType *Self = ATT; std::vector Names; for(; Self->getParent(); Self = Self->getParent()) { Names.insert(Names.begin(), Self->getName()); } if (!Self->getSelfProtocol() || Names.empty()) return tryNamedArchetypeTransform(Ty); Type Result = checkMemberType(DC, BaseTy, Names); if (Result) return Type(Result->getDesugaredType()); else return tryNamedArchetypeTransform(Ty); }; public: ArchetypeSelfTransformer(NominalTypeDecl *NTD): BaseTy(NTD->getDeclaredTypeInContext()), DC(*NTD), Ctx(NTD->getASTContext()) {} ArchetypeSelfTransformer(Type BaseTy, DeclContext &DC): BaseTy(BaseTy->getRValueType()), DC(DC), Ctx(DC.getASTContext()), NameTransformer(new PrinterArchetypeNameTransformer(BaseTy, &DC)){} Type transform(Type Ty) override { return Ty.transform(F); } Type checkMemberTypeInternal(StringRef TypeName) { ASTContext &Ctx = DC.getASTContext(); llvm::SmallVector Parts; TypeName.split(Parts, '.'); std::vector Names; for (unsigned I = 0; I < Parts.size(); ++ I) { if (I == 0 && Parts[I] == "Self") continue; Names.push_back(Ctx.getIdentifier(Parts[I])); } return checkMemberType(DC, BaseTy, Names); } StringRef transform(StringRef TypeName) override { if (auto Result = checkMemberTypeInternal(TypeName)) { Result = Result->getDesugaredType(); std::unique_ptr pBuffer(new std::string); llvm::raw_string_ostream OS(*pBuffer); Result.print(OS); OS.str(); Buffers.push_back(std::move(pBuffer)); return StringRef(*Buffers.back()); } return tryNamedArchetypeTransform(TypeName); } }; struct SynthesizedExtensionAnalyzer::Implementation { typedef llvm::MapVector ExtMap; NominalTypeDecl *Target; Type BaseType; DeclContext *DC; std::unique_ptr pTransform; bool IncludeUnconditional; std::unique_ptr Results; Implementation(NominalTypeDecl *Target, bool IncludeUnconditional): Target(Target), BaseType(Target->getDeclaredTypeInContext()), DC(Target), pTransform(new ArchetypeSelfTransformer(Target)), IncludeUnconditional(IncludeUnconditional), Results(collectSynthesizedExtensionInfo()) {} Type checkElementType(StringRef Text) { assert(Text.find('<') == StringRef::npos && "Not element type."); assert(Text.find(',') == StringRef::npos && "Not element type."); if (auto Result = pTransform->checkMemberTypeInternal(Text)) { return Result; } return lookUpTypeInContext(DC, Text); } Type parseComplexTypeString(StringRef Text) { Text = Text.trim(); auto ParamStart = Text.find_first_of('<'); auto ParamEnd = Text.find_last_of('>'); if(StringRef::npos == ParamStart) { return checkElementType(Text); } Type GenericType = checkElementType(StringRef(Text.data(), ParamStart)); if (!GenericType) return Type(); NominalTypeDecl *NTD = GenericType->getAnyNominal(); if (!NTD || NTD->getInnermostGenericParamTypes().empty()) return GenericType; StringRef Param = StringRef(Text.data() + ParamStart + 1, ParamEnd - ParamStart - 1); std::vector Brackets; std::vector Arguments; unsigned CurrentStart = 0; for (unsigned I = 0; I < Param.size(); ++ I) { char C = Param[I]; if (C == '<') Brackets.push_back(C); else if (C == '>') Brackets.pop_back(); else if (C == ',' && Brackets.empty()) { StringRef ArgString(Param.data() + CurrentStart, I - CurrentStart); Type Arg = parseComplexTypeString(ArgString); if (Arg.isNull()) return GenericType; Arguments.push_back(Arg); CurrentStart = I + 1; } } // Add the last argument, or the only argument. StringRef ArgString(Param.data() + CurrentStart, Param.size() - CurrentStart); Type Arg = parseComplexTypeString(ArgString); if (Arg.isNull()) return GenericType; Arguments.push_back(Arg); auto GenericParams = NTD->getInnermostGenericParamTypes(); assert(Arguments.size() == GenericParams.size()); TypeSubstitutionMap Map; for (auto It = GenericParams.begin(); It != GenericParams.end(); ++ It) { auto Index = std::distance(GenericParams.begin(), It); Map[(*It)->getCanonicalType()->castTo()] = Arguments[Index]; } auto MType = NTD->getInterfaceType().subst(DC->getParentModule(), Map, None); return MType->getAs()->getInstanceType(); } SynthesizedExtensionInfo isApplicable(ExtensionDecl *Ext) { SynthesizedExtensionInfo Result; if (!Ext->isConstrainedExtension()) { if (IncludeUnconditional) Result.Ext = Ext; return Result; } assert(Ext->getGenericParams() && "No generic params."); for (auto Req : Ext->getGenericParams()->getRequirements()){ auto TupleOp = Req.getAsAnalyzedWrittenString(); if (!TupleOp) continue; StringRef FirstType = std::get<0>(TupleOp.getValue()); StringRef SecondType = std::get<1>(TupleOp.getValue()); RequirementReprKind Kind = std::get<2>(TupleOp.getValue()); Type First = pTransform->checkMemberTypeInternal(FirstType); Type Second = lookUpTypeInContext(DC, SecondType); if (!First) First = parseComplexTypeString(FirstType); if (!Second) Second = parseComplexTypeString(SecondType); if (First && Second) { First = First->getDesugaredType(); Second = Second->getDesugaredType(); switch (Kind) { case RequirementReprKind::TypeConstraint: if(!canPossiblyConvertTo(First, Second, *DC)) return Result; else if (isConvertibleTo(First, Second, *DC)) Result.KnownSatisfiedRequirements.push_back(Req.getAsWrittenString()); break; case RequirementReprKind::SameType: if (!canPossiblyEqual(First, Second, *DC)) return Result; else if (isEqual(First, Second, *DC)) Result.KnownSatisfiedRequirements.push_back(Req.getAsWrittenString()); break; } } } Result.Ext = Ext; return Result; } std::unique_ptr collectSynthesizedExtensionInfo() { std::unique_ptr pMap(new ExtMap()); if (Target->getKind() == DeclKind::Protocol) return pMap; std::vector Unhandled; auto addTypeLocNominal = [&](TypeLoc TL){ if (TL.getType()) { if (auto D = TL.getType()->getAnyNominal()) { Unhandled.push_back(D); } } }; for (auto TL : Target->getInherited()) { addTypeLocNominal(TL); } while(!Unhandled.empty()) { NominalTypeDecl* Back = Unhandled.back(); Unhandled.pop_back(); for (ExtensionDecl *E : Back->getExtensions()) { if (auto Info = isApplicable(E)) (*pMap)[E] = Info; for (auto TL : Back->getInherited()) { addTypeLocNominal(TL); } } } return pMap; } }; SynthesizedExtensionAnalyzer:: SynthesizedExtensionAnalyzer(NominalTypeDecl *Target, bool IncludeUnconditional): Impl(*(new Implementation(Target, IncludeUnconditional))) {} SynthesizedExtensionAnalyzer::~SynthesizedExtensionAnalyzer() {delete &Impl;} bool SynthesizedExtensionAnalyzer:: isInSynthesizedExtension(const ValueDecl *VD) { if(auto Ext = dyn_cast_or_null(VD->getDeclContext()-> getInnermostTypeContext())) { return Impl.Results->count(Ext) != 0; } return false; } void SynthesizedExtensionAnalyzer:: forEachSynthesizedExtension(llvm::function_ref Fn) { for (auto It = Impl.Results->begin(); It != Impl.Results->end(); ++ It) { Fn(It->first); } } bool SynthesizedExtensionAnalyzer:: shouldPrintRequirement(ExtensionDecl *ED, StringRef Req) { auto Found = Impl.Results->find(ED); if (Found != Impl.Results->end()) { std::vector &KnownReqs = Found->second.KnownSatisfiedRequirements; return KnownReqs.end() == std::find(KnownReqs.begin(), KnownReqs.end(), Req); } return true; } } PrintOptions PrintOptions::printTypeInterface(Type T, const DeclContext *DC) { PrintOptions result = printInterface(); result.TransformContext = std::make_shared( new PrinterArchetypeNameTransformer(T, DC), T); return result; } void PrintOptions::setArchetypeTransform(Type T, const DeclContext *DC) { TransformContext = std::make_shared( new PrinterArchetypeNameTransformer(T, DC)); } void PrintOptions::setArchetypeTransformForQuickHelp(Type T, DeclContext *DC) { TransformContext = std::make_shared( new ArchetypeSelfTransformer(T, *DC)); } void PrintOptions:: initArchetypeTransformerForSynthesizedExtensions(NominalTypeDecl *D, SynthesizedExtensionAnalyzer *Analyzer) { TransformContext = std::make_shared( new ArchetypeSelfTransformer(D), D, Analyzer); } void PrintOptions::clearArchetypeTransformerForSynthesizedExtensions() { TransformContext.reset(); } struct ArchetypeTransformContext::Implementation { std::shared_ptr Transformer; // When printing a type interface, this is the type to print. // When synthesizing extensions, this is the target nominal. llvm::PointerUnion TypeBaseOrNominal; SynthesizedExtensionAnalyzer *SynAnalyzer = nullptr; Implementation(PrinterArchetypeTransformer *Transformer): Transformer(Transformer) {} Implementation(PrinterArchetypeTransformer *Transformer, Type T): Transformer(Transformer), TypeBaseOrNominal(T.getPointer()) {} Implementation(PrinterArchetypeTransformer *Transformer, NominalTypeDecl* NTD, SynthesizedExtensionAnalyzer *SynAnalyzer): Transformer(Transformer), TypeBaseOrNominal(NTD), SynAnalyzer(SynAnalyzer) {} }; ArchetypeTransformContext::~ArchetypeTransformContext() { delete &Impl; } ArchetypeTransformContext::ArchetypeTransformContext( PrinterArchetypeTransformer *Transformer): Impl(* new Implementation(Transformer)){}; ArchetypeTransformContext::ArchetypeTransformContext( PrinterArchetypeTransformer *Transformer, Type T): Impl(* new Implementation(Transformer, T)){}; ArchetypeTransformContext::ArchetypeTransformContext( PrinterArchetypeTransformer *Transformer, NominalTypeDecl *NTD, SynthesizedExtensionAnalyzer *SynAnalyzer) : Impl(* new Implementation(Transformer, NTD, SynAnalyzer)){}; bool ArchetypeTransformContext:: shouldPrintRequirement(ExtensionDecl *ED, StringRef Req) { if (Impl.SynAnalyzer) { return Impl.SynAnalyzer->shouldPrintRequirement(ED, Req); } return true; } NominalTypeDecl *ArchetypeTransformContext::getNominal() { return Impl.TypeBaseOrNominal.get(); } Type ArchetypeTransformContext::getTypeBase() { return Impl.TypeBaseOrNominal.get(); } PrinterArchetypeTransformer* ArchetypeTransformContext::getTransformer() { return Impl.Transformer.get(); } bool ArchetypeTransformContext::isPrintingSynthesizedExtension() { return !Impl.TypeBaseOrNominal.isNull() && Impl.TypeBaseOrNominal.is(); } bool ArchetypeTransformContext::isPrintingTypeInterface() { return !Impl.TypeBaseOrNominal.isNull() && Impl.TypeBaseOrNominal.is(); } Type ArchetypeTransformContext::transform(Type Input) { return Impl.Transformer->transform(Input); } StringRef ArchetypeTransformContext::transform(StringRef Input) { return Impl.Transformer->transform(Input); } std::string ASTPrinter::sanitizeUtf8(StringRef Text) { llvm::SmallString<256> Builder; Builder.reserve(Text.size()); const UTF8* Data = reinterpret_cast(Text.begin()); const UTF8* End = reinterpret_cast(Text.end()); StringRef Replacement = "\ufffd"; while (Data < End) { auto Step = getNumBytesForUTF8(*Data); if (Data + Step > End) { Builder.append(Replacement); break; } if (isLegalUTF8Sequence(Data, Data + Step)) { Builder.append(Data, Data + Step); } else { // If malformed, add replacement characters. Builder.append(Replacement); } Data += Step; } return Builder.str(); } bool ASTPrinter::printTypeInterface(Type Ty, DeclContext *DC, llvm::raw_ostream &OS) { if (!Ty) return false; Ty = Ty->getRValueType(); PrintOptions Options = PrintOptions::printTypeInterface(Ty.getPointer(), DC); if (auto ND = Ty->getNominalOrBoundGenericNominal()) { llvm::SmallPtrSet AllExts; for (auto Ext : ND->getExtensions()) { AllExts.insert(Ext); } Options.printExtensionContentAsMembers = [&](const ExtensionDecl *ED) { return AllExts.count(ED) == 1 && isExtensionApplied(*ND->getDeclContext(), Ty, ED); }; ND->print(OS, Options); return true; } return false; } bool ASTPrinter::printTypeInterface(Type Ty, DeclContext *DC, std::string &Buffer) { llvm::raw_string_ostream OS(Buffer); auto Result = printTypeInterface(Ty, DC, OS); OS.str(); return Result; } void ASTPrinter::anchor() {} void ASTPrinter::printIndent() { llvm::SmallString<16> Str; for (unsigned i = 0; i != CurrentIndentation; ++i) Str += ' '; printText(Str); } void ASTPrinter::printTextImpl(StringRef Text) { forceNewlines(); printText(Text); } void ASTPrinter::printTypeRef(const TypeDecl *TD, Identifier Name) { PrintNameContext Context = PrintNameContext::Normal; if (auto GP = dyn_cast(TD)) { if (GP->isProtocolSelf()) Context = PrintNameContext::GenericParameter; } printName(Name, Context); } void ASTPrinter::printModuleRef(ModuleEntity Mod, Identifier Name) { printName(Name); } void ASTPrinter::callPrintDeclPre(const Decl *D) { forceNewlines(); if (SynthesizeTarget && D->getKind() == DeclKind::Extension) printSynthesizedExtensionPre(cast(D), SynthesizeTarget); else printDeclPre(D); } ASTPrinter &ASTPrinter::operator<<(unsigned long long N) { llvm::SmallString<32> Str; llvm::raw_svector_ostream OS(Str); OS << N; printTextImpl(OS.str()); return *this; } ASTPrinter &ASTPrinter::operator<<(UUID UU) { llvm::SmallString Str; UU.toString(Str); printTextImpl(Str); return *this; } ASTPrinter &ASTPrinter::operator<<(DeclName name) { llvm::SmallString<32> str; llvm::raw_svector_ostream os(str); name.print(os); printTextImpl(os.str()); return *this; } // FIXME: We need to undef 'defer' when including Tokens.def. It is restored // below. #undef defer ASTPrinter &operator<<(ASTPrinter &printer, tok keyword) { StringRef name; switch (keyword) { #define KEYWORD(KW) case tok::kw_##KW: name = #KW; break; #define POUND_KEYWORD(KW) case tok::pound_##KW: name = "#"#KW; break; #include "swift/Parse/Tokens.def" default: llvm_unreachable("unexpected keyword kind"); } printer.printKeyword(name); return printer; } /// Determine whether to escape the given keyword in the given context. static bool escapeKeywordInContext(StringRef keyword, PrintNameContext context){ switch (context) { case PrintNameContext::Normal: case PrintNameContext::Attribute: return true; case PrintNameContext::Keyword: return false; case PrintNameContext::GenericParameter: return keyword != "Self"; case PrintNameContext::FunctionParameterExternal: case PrintNameContext::FunctionParameterLocal: case PrintNameContext::TupleElement: return !canBeArgumentLabel(keyword); } } void ASTPrinter::printName(Identifier Name, PrintNameContext Context) { callPrintNamePre(Context); if (Name.empty()) { *this << "_"; printNamePost(Context); return; } bool IsKeyword = llvm::StringSwitch(Name.str()) #define KEYWORD(KW) \ .Case(#KW, true) #include "swift/Parse/Tokens.def" .Default(false); if (IsKeyword) IsKeyword = escapeKeywordInContext(Name.str(), Context); if (IsKeyword) *this << "`"; *this << Name.str(); if (IsKeyword) *this << "`"; printNamePost(Context); } // FIXME: Restore defer after Tokens.def. #define defer defer_impl void StreamPrinter::printText(StringRef Text) { OS << Text; } namespace { /// \brief AST pretty-printer. class PrintAST : public ASTVisitor { ASTPrinter &Printer; PrintOptions Options; unsigned IndentLevel = 0; friend DeclVisitor; /// \brief RAII object that increases the indentation level. class IndentRAII { PrintAST &Self; bool DoIndent; public: IndentRAII(PrintAST &self, bool DoIndent = true) : Self(self), DoIndent(DoIndent) { if (DoIndent) Self.IndentLevel += Self.Options.Indent; } ~IndentRAII() { if (DoIndent) Self.IndentLevel -= Self.Options.Indent; } }; /// \brief Indent the current number of indentation spaces. void indent() { Printer.setIndent(IndentLevel); } /// \brief Record the location of this declaration, which is about to /// be printed, marking the name and signature end locations. template void recordDeclLoc(Decl *decl, const FnTy &NameFn, llvm::function_ref ParamFn = []{}) { Printer.callPrintDeclLoc(decl); NameFn(); Printer.printDeclNameEndLoc(decl); ParamFn(); Printer.printDeclNameOrSignatureEndLoc(decl); } void printSourceRange(CharSourceRange Range, ASTContext &Ctx) { Printer << Ctx.SourceMgr.extractText(Range); } void printClangDocumentationComment(const clang::Decl *D) { const auto &ClangContext = D->getASTContext(); const clang::RawComment *RC = ClangContext.getRawCommentForAnyRedecl(D); if (!RC) return; bool Invalid; unsigned StartLocCol = ClangContext.getSourceManager().getSpellingColumnNumber( RC->getLocStart(), &Invalid); if (Invalid) StartLocCol = 0; unsigned WhitespaceToTrim = StartLocCol ? StartLocCol - 1 : 0; SmallVector Lines; StringRef RawText = RC->getRawText(ClangContext.getSourceManager()).rtrim("\n\r"); trimLeadingWhitespaceFromLines(RawText, WhitespaceToTrim, Lines); for (auto Line : Lines) { Printer << ASTPrinter::sanitizeUtf8(Line); Printer.printNewline(); } } void printSwiftDocumentationComment(const Decl *D) { auto RC = D->getRawComment(); if (RC.isEmpty()) return; indent(); SmallVector Lines; for (const auto &SRC : RC.Comments) { Lines.clear(); StringRef RawText = SRC.RawText.rtrim("\n\r"); unsigned WhitespaceToTrim = SRC.StartColumn - 1; trimLeadingWhitespaceFromLines(RawText, WhitespaceToTrim, Lines); for (auto Line : Lines) { Printer << Line; Printer.printNewline(); } } } void printDocumentationComment(const Decl *D) { if (!Options.PrintDocumentationComments) return; // Try to print a comment from Clang. auto MaybeClangNode = D->getClangNode(); if (MaybeClangNode) { if (auto *CD = MaybeClangNode.getAsDecl()) printClangDocumentationComment(CD); return; } printSwiftDocumentationComment(D); } void printStaticKeyword(StaticSpellingKind StaticSpelling) { switch (StaticSpelling) { case StaticSpellingKind::None: llvm_unreachable("should not be called for non-static decls"); case StaticSpellingKind::KeywordStatic: Printer << tok::kw_static << " "; break; case StaticSpellingKind::KeywordClass: Printer << tok::kw_class << " "; break; } } void printAccessibility(Accessibility access, StringRef suffix = "") { switch (access) { case Accessibility::Private: Printer << tok::kw_private; break; case Accessibility::Internal: if (!Options.PrintInternalAccessibilityKeyword) return; Printer << tok::kw_internal; break; case Accessibility::Public: Printer << tok::kw_public; break; } Printer << suffix << " "; } void printAccessibility(const ValueDecl *D) { if (!Options.PrintAccessibility || !D->hasAccessibility() || D->getAttrs().hasAttribute()) return; printAccessibility(D->getFormalAccess()); if (auto storageDecl = dyn_cast(D)) { if (auto setter = storageDecl->getSetter()) { Accessibility setterAccess = setter->getFormalAccess(); if (setterAccess != D->getFormalAccess()) printAccessibility(setterAccess, "(set)"); } } } void printTypeLoc(const TypeLoc &TL) { if (Options.TransformContext && TL.getType()) { if (auto RT = Options.TransformContext->transform(TL.getType())) { PrintOptions FreshOptions; RT.print(Printer, FreshOptions); return; } } // Print a TypeRepr if instructed to do so by options, or if the type // is null. if ((Options.PreferTypeRepr && TL.hasLocation()) || TL.getType().isNull()) { if (auto repr = TL.getTypeRepr()) repr->print(Printer, Options); return; } TL.getType().print(Printer, Options); } void printAttributes(const Decl *D); void printTypedPattern(const TypedPattern *TP); public: void printPattern(const Pattern *pattern); void printGenericParams(GenericParamList *params); void printWhereClause(ArrayRef requirements); private: bool shouldPrint(const Decl *D, bool Notify = false); bool shouldPrintPattern(const Pattern *P); void printPatternType(const Pattern *P); void printAccessors(AbstractStorageDecl *ASD); void printMembersOfDecl(Decl * NTD, bool needComma = false); void printMembers(ArrayRef members, bool needComma = false); void printNominalDeclGenericParams(NominalTypeDecl *decl); void printInherited(const Decl *decl, ArrayRef inherited, ArrayRef protos, Type superclass = {}, bool explicitClass = false, bool PrintAsProtocolComposition = false); void printInherited(const NominalTypeDecl *decl, bool explicitClass = false); void printInherited(const EnumDecl *D); void printInherited(const ExtensionDecl *decl); void printInherited(const GenericTypeParamDecl *D); void printEnumElement(EnumElementDecl *elt); /// \returns true if anything was printed. bool printASTNodes(const ArrayRef &Elements, bool NeedIndent = true); void printOneParameter(const ParamDecl *param, bool Curried, bool ArgNameIsAPIByDefault); void printParameterList(ParameterList *PL, bool isCurried, std::function isAPINameByDefault); /// \brief Print the function parameters in curried or selector style, /// to match the original function declaration. void printFunctionParameters(AbstractFunctionDecl *AFD); #define DECL(Name,Parent) void visit##Name##Decl(Name##Decl *decl); #define ABSTRACT_DECL(Name, Parent) #define DECL_RANGE(Name,Start,End) #include "swift/AST/DeclNodes.def" #define STMT(Name, Parent) void visit##Name##Stmt(Name##Stmt *stmt); #include "swift/AST/StmtNodes.def" void printSynthesizedExtension(NominalTypeDecl* Decl, ExtensionDecl* ExtDecl); void printExtension(ExtensionDecl* ExtDecl); public: PrintAST(ASTPrinter &Printer, const PrintOptions &Options) : Printer(Printer), Options(Options) {} using ASTVisitor::visit; bool visit(Decl *D) { if (!shouldPrint(D, true)) return false; bool Synthesize = Options.TransformContext && Options.TransformContext->isPrintingSynthesizedExtension() && D->getKind() == DeclKind::Extension; if (Synthesize) Printer.setSynthesizedTarget(Options.TransformContext->getNominal()); // We want to print a newline before doc comments. Swift code already // handles this, but we need to insert it for clang doc comments when not // printing other clang comments. Do it now so the printDeclPre callback // happens after the newline. if (Options.PrintDocumentationComments && !Options.PrintRegularClangComments && D->hasClangNode()) { auto clangNode = D->getClangNode(); auto clangDecl = clangNode.getAsDecl(); if (clangDecl && clangDecl->getASTContext().getRawCommentForAnyRedecl(clangDecl)) { Printer.printNewline(); indent(); } } Printer.callPrintDeclPre(D); ASTVisitor::visit(D); if (Synthesize) { Printer.setSynthesizedTarget(nullptr); Printer.printSynthesizedExtensionPost( cast(D), Options.TransformContext->getNominal()); } else { Printer.callPrintDeclPost(D); } return true; } }; } // unnamed namespace static StaticSpellingKind getCorrectStaticSpelling(const Decl *D) { if (auto *VD = dyn_cast(D)) { return VD->getCorrectStaticSpelling(); } else if (auto *PBD = dyn_cast(D)) { return PBD->getCorrectStaticSpelling(); } else if (auto *FD = dyn_cast(D)) { return FD->getCorrectStaticSpelling(); } else { return StaticSpellingKind::None; } } void PrintAST::printAttributes(const Decl *D) { if (Options.SkipAttributes) return; // Don't print a redundant 'final' if we are printing a 'static' decl. unsigned originalExcludeAttrCount = Options.ExcludeAttrList.size(); if (Options.PrintImplicitAttrs && D->getDeclContext()->getAsClassOrClassExtensionContext() && getCorrectStaticSpelling(D) == StaticSpellingKind::KeywordStatic) { Options.ExcludeAttrList.push_back(DAK_Final); } D->getAttrs().print(Printer, Options); Options.ExcludeAttrList.resize(originalExcludeAttrCount); } void PrintAST::printTypedPattern(const TypedPattern *TP) { printPattern(TP->getSubPattern()); Printer << ": "; printTypeLoc(TP->getTypeLoc()); } void PrintAST::printPattern(const Pattern *pattern) { switch (pattern->getKind()) { case PatternKind::Any: Printer << "_"; break; case PatternKind::Named: { auto named = cast(pattern); recordDeclLoc(named->getDecl(), [&]{ Printer.printName(named->getBoundName()); }); break; } case PatternKind::Paren: Printer << "("; printPattern(cast(pattern)->getSubPattern()); Printer << ")"; break; case PatternKind::Tuple: { Printer << "("; auto TP = cast(pattern); auto Fields = TP->getElements(); for (unsigned i = 0, e = Fields.size(); i != e; ++i) { const auto &Elt = Fields[i]; if (i != 0) Printer << ", "; printPattern(Elt.getPattern()); } Printer << ")"; break; } case PatternKind::Typed: printTypedPattern(cast(pattern)); break; case PatternKind::Is: { auto isa = cast(pattern); Printer << tok::kw_is << " "; isa->getCastTypeLoc().getType().print(Printer, Options); break; } case PatternKind::NominalType: { auto type = cast(pattern); type->getCastTypeLoc().getType().print(Printer, Options); Printer << "("; interleave(type->getElements().begin(), type->getElements().end(), [&](const NominalTypePattern::Element &elt) { Printer << elt.getPropertyName().str() << ":"; printPattern(elt.getSubPattern()); }, [&] { Printer << ", "; }); break; } case PatternKind::EnumElement: { auto elt = cast(pattern); // FIXME: Print element expr. if (elt->hasSubPattern()) printPattern(elt->getSubPattern()); break; } case PatternKind::OptionalSome: printPattern(cast(pattern)->getSubPattern()); Printer << '?'; break; case PatternKind::Bool: Printer << (cast(pattern)->getValue() ? tok::kw_true : tok::kw_false); break; case PatternKind::Expr: // FIXME: Print expr. break; case PatternKind::Var: if (!Options.SkipIntroducerKeywords) Printer << (cast(pattern)->isLet() ? tok::kw_let : tok::kw_var) << " "; printPattern(cast(pattern)->getSubPattern()); } } void PrintAST::printGenericParams(GenericParamList *Params) { if (!Params) return; Printer << "<"; bool IsFirst = true; SmallVector Scrach; if (Options.TransformContext && Options.TransformContext->isPrintingTypeInterface()) { auto ArgArr = Options.TransformContext->getTypeBase()-> getAllGenericArgs(Scrach); for (auto Arg : ArgArr) { if (IsFirst) { IsFirst = false; } else { Printer << ", "; } auto NM = Arg->getAnyGeneric(); assert(NM && "Cannot get generic type."); Printer.callPrintStructurePre(PrintStructureKind::GenericParameter, NM); Printer << NM->getNameStr(); // FIXME: PrintNameContext::GenericParameter Printer.printStructurePost(PrintStructureKind::GenericParameter, NM); } } else { for (auto GP : Params->getParams()) { if (IsFirst) { IsFirst = false; } else { Printer << ", "; } Printer.callPrintStructurePre(PrintStructureKind::GenericParameter, GP); Printer.printName(GP->getName(), PrintNameContext::GenericParameter); printInherited(GP); Printer.printStructurePost(PrintStructureKind::GenericParameter, GP); } printWhereClause(Params->getRequirements()); } Printer << ">"; } void PrintAST::printWhereClause(ArrayRef requirements) { if (requirements.empty()) return; std::vector> Elements; llvm::SmallString<64> Output; bool Handled = true; for (auto &req : requirements) { if (req.isInvalid()) continue; auto TupleOp = req.getAsAnalyzedWrittenString(); if (TupleOp.hasValue()) { auto Tuple = TupleOp.getValue(); auto FirstType = std::get<0>(Tuple); auto SecondType = std::get<1>(Tuple); auto Kind = std::get<2>(Tuple); if (Options.TransformContext) { FirstType = Options.TransformContext->transform(FirstType); SecondType = Options.TransformContext->transform(SecondType); } if (FirstType == SecondType) continue; Elements.push_back(std::make_tuple(FirstType, SecondType, Kind)); } else { Handled = false; break; } } if (Handled) { bool First = true; for (auto &E : Elements) { if (First) { Printer << " " << tok::kw_where << " "; First = false; } else { Printer << ", "; } Printer.callPrintStructurePre(PrintStructureKind::GenericRequirement); Printer << std::get<0>(E); Printer << (RequirementReprKind::SameType == std::get<2>(E) ? " == " : " : "); Printer << std::get<1>(E); Printer.printStructurePost(PrintStructureKind::GenericRequirement); } return; } bool isFirst = true; for (auto &req : requirements) { if (req.isInvalid()) continue; if (isFirst) { Printer << " " << tok::kw_where << " "; isFirst = false; } else { Printer << ", "; } Printer.callPrintStructurePre(PrintStructureKind::GenericRequirement); defer { Printer.printStructurePost(PrintStructureKind::GenericRequirement); }; switch (req.getKind()) { case RequirementReprKind::TypeConstraint: printTypeLoc(req.getSubjectLoc()); Printer << " : "; printTypeLoc(req.getConstraintLoc()); break; case RequirementReprKind::SameType: printTypeLoc(req.getFirstTypeLoc()); Printer << " == "; printTypeLoc(req.getSecondTypeLoc()); break; } } } bool swift::shouldPrintPattern(const Pattern *P, PrintOptions &Options) { bool ShouldPrint = false; P->forEachVariable([&](VarDecl *VD) { ShouldPrint |= shouldPrint(VD, Options); }); return ShouldPrint; } bool PrintAST::shouldPrintPattern(const Pattern *P) { return swift::shouldPrintPattern(P, Options); } void PrintAST::printPatternType(const Pattern *P) { if (P->hasType()) { Type T = P->getType(); if (Options.TransformContext) { T = Options.TransformContext->transform(T); } Printer << ": "; T.print(Printer, Options); } } bool swift::shouldPrint(const Decl *D, PrintOptions &Options) { if (auto *ED= dyn_cast(D)) { if (Options.printExtensionContentAsMembers(ED)) return false; } if (Options.SkipDeinit && isa(D)) { return false; } if (Options.SkipImports && isa(D)) { return false; } if (Options.SkipImplicit && D->isImplicit()) return false; if (Options.SkipUnavailable && D->getAttrs().isUnavailable(D->getASTContext())) return false; if (Options.ExplodeEnumCaseDecls) { if (isa(D)) return true; if (isa(D)) return false; } else if (auto *EED = dyn_cast(D)) { // Enum elements are printed as part of the EnumCaseDecl, unless they were // imported without source info. return !EED->getSourceRange().isValid(); } // Skip declarations that are not accessible. if (auto *VD = dyn_cast(D)) { if (Options.AccessibilityFilter > Accessibility::Private && VD->hasAccessibility() && VD->getFormalAccess() < Options.AccessibilityFilter) return false; } if (Options.SkipPrivateStdlibDecls && D->isPrivateStdlibDecl( /*whitelistProtocols=*/!Options.SkipUnderscoredStdlibProtocols)) return false; if (Options.SkipEmptyExtensionDecls && isa(D)) { auto Ext = cast(D); // If the extension doesn't add protocols or has no members that we should // print then skip printing it. if (Ext->getLocalProtocols().empty()) { bool HasMemberToPrint = false; for (auto Member : Ext->getMembers()) { if (shouldPrint(Member, Options)) { HasMemberToPrint = true; break; } } if (!HasMemberToPrint) return false; } } // If asked to skip overrides and witnesses, do so. if (Options.SkipOverrides) { if (auto *VD = dyn_cast(D)) { if (VD->getOverriddenDecl()) return false; if (!VD->getSatisfiedProtocolRequirements().empty()) return false; } } // We need to handle PatternBindingDecl as a special case here because its // attributes can only be retrieved from the inside VarDecls. if (auto *PD = dyn_cast(D)) { auto ShouldPrint = false; for (auto entry : PD->getPatternList()) { ShouldPrint |= shouldPrintPattern(entry.getPattern(), Options); if (ShouldPrint) return true; } return false; } return true; } bool PrintAST::shouldPrint(const Decl *D, bool Notify) { auto Result = swift::shouldPrint(D, Options); if (!Result && Notify) Printer.callAvoidPrintDeclPost(D); return Result; } static bool isAccessorAssumedNonMutating(FuncDecl *accessor) { switch (accessor->getAccessorKind()) { case AccessorKind::IsGetter: case AccessorKind::IsAddressor: return true; case AccessorKind::IsSetter: case AccessorKind::IsWillSet: case AccessorKind::IsDidSet: case AccessorKind::IsMaterializeForSet: case AccessorKind::IsMutableAddressor: return false; case AccessorKind::NotAccessor: llvm_unreachable("not an addressor!"); } llvm_unreachable("bad addressor kind"); } static StringRef getAddressorLabel(FuncDecl *addressor) { switch (addressor->getAddressorKind()) { case AddressorKind::NotAddressor: llvm_unreachable("addressor claims not to be an addressor"); case AddressorKind::Unsafe: return "unsafeAddress"; case AddressorKind::Owning: return "addressWithOwner"; case AddressorKind::NativeOwning: return "addressWithNativeOwner"; case AddressorKind::NativePinning: return "addressWithPinnedNativeOwner"; } llvm_unreachable("bad addressor kind"); } static StringRef getMutableAddressorLabel(FuncDecl *addressor) { switch (addressor->getAddressorKind()) { case AddressorKind::NotAddressor: llvm_unreachable("addressor claims not to be an addressor"); case AddressorKind::Unsafe: return "unsafeMutableAddress"; case AddressorKind::Owning: return "mutableAddressWithOwner"; case AddressorKind::NativeOwning: return "mutableAddressWithNativeOwner"; case AddressorKind::NativePinning: return "mutableAddressWithPinnedNativeOwner"; } llvm_unreachable("bad addressor kind"); } void PrintAST::printAccessors(AbstractStorageDecl *ASD) { if (isa(ASD) && !Options.PrintPropertyAccessors) return; auto storageKind = ASD->getStorageKind(); // Never print anything for stored properties. if (storageKind == AbstractStorageDecl::Stored) return; // Treat StoredWithTrivialAccessors the same as Stored unless // we're printing for SIL, in which case we want to distinguish it // from a pure stored property. if (storageKind == AbstractStorageDecl::StoredWithTrivialAccessors) { if (!Options.PrintForSIL) return; // Don't print an accessor for a let; the parser can't handle it. if (isa(ASD) && cast(ASD)->isLet()) return; } // We sometimes want to print the accessors abstractly // instead of listing out how they're actually implemented. bool inProtocol = isa(ASD->getDeclContext()); if (inProtocol || (Options.AbstractAccessors && !Options.FunctionDefinitions)) { bool mutatingGetter = ASD->getGetter() && ASD->isGetterMutating(); bool settable = ASD->isSettable(nullptr); bool nonmutatingSetter = false; if (settable && ASD->isSetterNonMutating() && ASD->isInstanceMember() && !ASD->getDeclContext()->getDeclaredTypeInContext() ->hasReferenceSemantics()) nonmutatingSetter = true; // We're about to print something like this: // { mutating? get (nonmutating? set)? } // But don't print "{ get set }" if we don't have to. if (!inProtocol && !Options.PrintGetSetOnRWProperties && settable && !mutatingGetter && !nonmutatingSetter) { return; } Printer << " {"; if (mutatingGetter) { Printer << " "; Printer.printKeyword("mutating"); } Printer << " "; Printer.printKeyword("get"); if (settable) { if (nonmutatingSetter) { Printer << " "; Printer.printKeyword("nonmutating"); } Printer << " "; Printer.printKeyword("set"); } Printer << " }"; return; } // Honor !Options.PrintGetSetOnRWProperties in the only remaining // case where we could end up printing { get set }. if (storageKind == AbstractStorageDecl::StoredWithTrivialAccessors || storageKind == AbstractStorageDecl::Computed) { if (!Options.PrintGetSetOnRWProperties && !Options.FunctionDefinitions && ASD->getSetter() && !ASD->getGetter()->isMutating() && !ASD->getSetter()->isExplicitNonMutating()) { return; } } // Otherwise, print all the concrete defining accessors. bool PrintAccessorBody = Options.FunctionDefinitions; auto PrintAccessor = [&](FuncDecl *Accessor, StringRef Label) { if (!Accessor) return; if (!PrintAccessorBody) { if (isAccessorAssumedNonMutating(Accessor)) { if (Accessor->isMutating()) { Printer << " "; Printer.printKeyword("mutating"); } } else { if (Accessor->isExplicitNonMutating()) { Printer << " "; Printer.printKeyword("nonmutating"); } } Printer << " "; Printer.printKeyword(Label); // Contextual keyword get, set, ... } else { Printer.printNewline(); IndentRAII IndentMore(*this); indent(); visit(Accessor); } }; auto PrintAddressor = [&](FuncDecl *accessor) { if (!accessor) return; PrintAccessor(accessor, getAddressorLabel(accessor)); }; auto PrintMutableAddressor = [&](FuncDecl *accessor) { if (!accessor) return; PrintAccessor(accessor, getMutableAddressorLabel(accessor)); }; Printer << " {"; switch (storageKind) { case AbstractStorageDecl::Stored: llvm_unreachable("filtered out above!"); case AbstractStorageDecl::StoredWithTrivialAccessors: case AbstractStorageDecl::Computed: PrintAccessor(ASD->getGetter(), "get"); PrintAccessor(ASD->getSetter(), "set"); break; case AbstractStorageDecl::StoredWithObservers: case AbstractStorageDecl::InheritedWithObservers: PrintAccessor(ASD->getWillSetFunc(), "willSet"); PrintAccessor(ASD->getDidSetFunc(), "didSet"); break; case AbstractStorageDecl::Addressed: case AbstractStorageDecl::AddressedWithTrivialAccessors: case AbstractStorageDecl::AddressedWithObservers: PrintAddressor(ASD->getAddressor()); PrintMutableAddressor(ASD->getMutableAddressor()); if (ASD->hasObservers()) { PrintAccessor(ASD->getWillSetFunc(), "willSet"); PrintAccessor(ASD->getDidSetFunc(), "didSet"); } break; case AbstractStorageDecl::ComputedWithMutableAddress: PrintAccessor(ASD->getGetter(), "get"); PrintMutableAddressor(ASD->getMutableAddressor()); break; } if (PrintAccessorBody) { Printer.printNewline(); indent(); } else Printer << " "; Printer << "}"; } void PrintAST::printMembersOfDecl(Decl *D, bool needComma) { llvm::SmallVector Members; auto AddDeclFunc = [&](DeclRange Range) { for (auto RD : Range) Members.push_back(RD); }; if (auto Ext = dyn_cast(D)) { AddDeclFunc(Ext->getMembers()); } else if (auto NTD = dyn_cast(D)) { AddDeclFunc(NTD->getMembers()); for (auto Ext : NTD->getExtensions()) { if (Options.printExtensionContentAsMembers(Ext)) AddDeclFunc(Ext->getMembers()); } } printMembers(Members, needComma); } void PrintAST::printMembers(ArrayRef members, bool needComma) { Printer << " {"; Printer.printNewline(); { IndentRAII indentMore(*this); for (auto i = members.begin(), iEnd = members.end(); i != iEnd; ++i) { auto member = *i; if (!shouldPrint(member, true)) continue; if (!member->shouldPrintInContext(Options)) continue; if (Options.EmptyLineBetweenMembers) Printer.printNewline(); indent(); visit(member); if (needComma && std::next(i) != iEnd) Printer << ","; Printer.printNewline(); } } indent(); Printer << "}"; } void PrintAST::printNominalDeclGenericParams(NominalTypeDecl *decl) { if (auto gp = decl->getGenericParams()) { if (!isa(decl)) { // For a protocol extension, print only the where clause; the // generic parameter list is implicit. For other nominal types, // print the generic parameters. if (decl->getAsProtocolOrProtocolExtensionContext()) printWhereClause(gp->getRequirements()); else printGenericParams(gp); } } } void PrintAST::printInherited(const Decl *decl, ArrayRef inherited, ArrayRef protos, Type superclass, bool explicitClass, bool PrintAsProtocolComposition) { if (inherited.empty() && superclass.isNull() && !explicitClass) { if (protos.empty()) return; // If only conforms to AnyObject protocol, nothing to print. if (protos.size() == 1) { if (protos.front()->isSpecificProtocol(KnownProtocolKind::AnyObject)) return; } } if (inherited.empty()) { bool PrintedColon = false; bool PrintedInherited = false; if (explicitClass) { Printer << " : " << tok::kw_class; PrintedInherited = true; } else if (superclass) { bool ShouldPrintSuper = true; if (auto NTD = superclass->getAnyNominal()) { ShouldPrintSuper = shouldPrint(NTD); } if (ShouldPrintSuper) { Printer << " : "; superclass.print(Printer, Options); PrintedInherited = true; } } bool UseProtocolCompositionSyntax = PrintAsProtocolComposition && protos.size() > 1; if (UseProtocolCompositionSyntax) { Printer << " : " << tok::kw_protocol << "<"; PrintedColon = true; } for (auto Proto : protos) { if (!shouldPrint(Proto)) continue; if (Proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) continue; if (auto Enum = dyn_cast(decl)) { // Conformance to RawRepresentable is implied by having a raw type. if (Enum->hasRawType() && Proto->isSpecificProtocol(KnownProtocolKind::RawRepresentable)) continue; // Conformance to Equatable and Hashable is implied by being a "simple" // no-payload enum. if (Enum->hasOnlyCasesWithoutAssociatedValues() && (Proto->isSpecificProtocol(KnownProtocolKind::Equatable) || Proto->isSpecificProtocol(KnownProtocolKind::Hashable))) continue; } if (PrintedInherited) Printer << ", "; else if (!PrintedColon) Printer << " : "; Proto->getDeclaredType()->print(Printer, Options); PrintedInherited = true; PrintedColon = true; } if (UseProtocolCompositionSyntax) Printer << ">"; } else { SmallVector TypesToPrint; for (auto TL : inherited) { if (auto Ty = TL.getType()) { if (auto NTD = Ty->getAnyNominal()) if (!shouldPrint(NTD)) continue; } TypesToPrint.push_back(TL); } if (TypesToPrint.empty()) return; Printer << " : "; if (explicitClass) Printer << " " << tok::kw_class << ", "; interleave(TypesToPrint, [&](TypeLoc TL) { printTypeLoc(TL); }, [&]() { Printer << ", "; }); } } void PrintAST::printInherited(const NominalTypeDecl *decl, bool explicitClass) { printInherited(decl, decl->getInherited(), { }, nullptr, explicitClass); } void PrintAST::printInherited(const EnumDecl *decl) { printInherited(decl, decl->getInherited(), { }); } void PrintAST::printInherited(const ExtensionDecl *decl) { printInherited(decl, decl->getInherited(), { }); } void PrintAST::printInherited(const GenericTypeParamDecl *D) { printInherited(D, D->getInherited(), { }); } static void getModuleEntities(const clang::Module *ClangMod, SmallVectorImpl &ModuleEnts) { if (!ClangMod) return; getModuleEntities(ClangMod->Parent, ModuleEnts); ModuleEnts.push_back(ClangMod); } static void getModuleEntities(ImportDecl *Import, SmallVectorImpl &ModuleEnts) { if (auto *ClangMod = Import->getClangModule()) { getModuleEntities(ClangMod, ModuleEnts); return; } auto Mod = Import->getModule(); if (!Mod) return; if (auto *ClangMod = Mod->findUnderlyingClangModule()) { getModuleEntities(ClangMod, ModuleEnts); } else { ModuleEnts.push_back(Mod); } } void PrintAST::visitImportDecl(ImportDecl *decl) { printAttributes(decl); Printer << tok::kw_import << " "; switch (decl->getImportKind()) { case ImportKind::Module: break; case ImportKind::Type: Printer << tok::kw_typealias << " "; break; case ImportKind::Struct: Printer << tok::kw_struct << " "; break; case ImportKind::Class: Printer << tok::kw_class << " "; break; case ImportKind::Enum: Printer << tok::kw_enum << " "; break; case ImportKind::Protocol: Printer << tok::kw_protocol << " "; break; case ImportKind::Var: Printer << tok::kw_var << " "; break; case ImportKind::Func: Printer << tok::kw_func << " "; break; } SmallVector ModuleEnts; getModuleEntities(decl, ModuleEnts); ArrayRef Mods = ModuleEnts; interleave(decl->getFullAccessPath(), [&](const ImportDecl::AccessPathElement &Elem) { if (!Mods.empty()) { Printer.printModuleRef(Mods.front(), Elem.first); Mods = Mods.slice(1); } else { Printer << Elem.first.str(); } }, [&] { Printer << "."; }); } static void printExtendedTypeName(Type ExtendedType, ASTPrinter &Printer, PrintOptions Options) { auto Nominal = ExtendedType->getAnyNominal(); assert(Nominal && "extension of non-nominal type"); if (auto ct = ExtendedType->getAs()) { if (auto ParentType = ct->getParent()) { ParentType.print(Printer, Options); Printer << "."; } } if (auto st = ExtendedType->getAs()) { if (auto ParentType = st->getParent()) { ParentType.print(Printer, Options); Printer << "."; } } // Respect alias type. if (ExtendedType->getKind() == TypeKind::NameAlias) { ExtendedType.print(Printer, Options); return; } Printer.printTypeRef(Nominal, Nominal->getName()); } void PrintAST:: printSynthesizedExtension(NominalTypeDecl* Decl, ExtensionDecl *ExtDecl) { Printer << "/// Synthesized extension from " << ExtDecl->getExtendedType()->getAnyNominal()->getName().str() << "\n"; printDocumentationComment(ExtDecl); printAttributes(ExtDecl); Printer << tok::kw_extension << " "; printExtendedTypeName(Decl->getDeclaredType(), Printer, Options); printInherited(ExtDecl); if (auto *GPs = ExtDecl->getGenericParams()) { std::vector ReqsToPrint; for (auto Req : GPs->getRequirements()) { if (Options.TransformContext->shouldPrintRequirement(ExtDecl, Req.getAsWrittenString())) ReqsToPrint.push_back(Req); } printWhereClause(ReqsToPrint); } if (Options.TypeDefinitions) { printMembersOfDecl(ExtDecl); } } void PrintAST::printExtension(ExtensionDecl* decl) { printDocumentationComment(decl); printAttributes(decl); Printer << "extension "; recordDeclLoc(decl, [&]{ // We cannot extend sugared types. Type extendedType = decl->getExtendedType(); NominalTypeDecl *nominal = extendedType ? extendedType->getAnyNominal() : nullptr; if (!nominal) { // Fallback to TypeRepr. printTypeLoc(decl->getExtendedTypeLoc()); return; } printExtendedTypeName(extendedType, Printer, Options); }); printInherited(decl); if (auto *GPs = decl->getGenericParams()) { printWhereClause(GPs->getRequirements()); } if (Options.TypeDefinitions) { printMembersOfDecl(decl); } } void PrintAST::visitExtensionDecl(ExtensionDecl *decl) { if (Options.TransformContext && Options.TransformContext->isPrintingSynthesizedExtension()) printSynthesizedExtension(Options.TransformContext->getNominal(), decl); else printExtension(decl); } void PrintAST::visitPatternBindingDecl(PatternBindingDecl *decl) { // FIXME: We're not printing proper "{ get set }" annotations in pattern // binding decls. As a hack, scan the decl to find out if any of the // variables are immutable, and if so, we print as 'let'. This allows us to // handle the 'let x = 4' case properly at least. const VarDecl *anyVar = nullptr; for (auto entry : decl->getPatternList()) { entry.getPattern()->forEachVariable([&](VarDecl *V) { anyVar = V; }); if (anyVar) break; } if (anyVar) printDocumentationComment(anyVar); if (decl->isStatic()) printStaticKeyword(decl->getCorrectStaticSpelling()); // FIXME: PatternBindingDecls don't have attributes themselves, so just assume // the variables all have the same attributes. This isn't exactly true // after type-checking, but it's close enough for now. if (anyVar) { printAttributes(anyVar); printAccessibility(anyVar); Printer << (anyVar->isSettable(anyVar->getDeclContext()) ? "var " : "let "); } else { Printer << "let "; } bool isFirst = true; for (auto entry : decl->getPatternList()) { if (!shouldPrintPattern(entry.getPattern())) continue; if (isFirst) isFirst = false; else Printer << ", "; printPattern(entry.getPattern()); // We also try to print type for named patterns, e.g. var Field = 10; // and tuple patterns, e.g. var (T1, T2) = (10, 10) if (isa(entry.getPattern()) || isa(entry.getPattern())) { printPatternType(entry.getPattern()); } if (Options.VarInitializers) { // FIXME: Implement once we can pretty-print expressions. } } } void PrintAST::visitTopLevelCodeDecl(TopLevelCodeDecl *decl) { printASTNodes(decl->getBody()->getElements(), /*NeedIndent=*/false); } void PrintAST::visitIfConfigDecl(IfConfigDecl *ICD) { // FIXME: Pretty print #if decls } void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccessibility(decl); if (!Options.SkipIntroducerKeywords) Printer << tok::kw_typealias << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }, [&]{ // Signature printGenericParams(decl->getGenericParams()); }); bool ShouldPrint = true; Type Ty; if (decl->hasUnderlyingType()) Ty = decl->getUnderlyingType(); // If the underlying type is private, don't print it. if (Options.SkipPrivateStdlibDecls && Ty && Ty.isPrivateStdlibType()) ShouldPrint = false; if (ShouldPrint) { Printer << " = "; printTypeLoc(decl->getUnderlyingTypeLoc()); } } void PrintAST::visitGenericTypeParamDecl(GenericTypeParamDecl *decl) { recordDeclLoc(decl, [&] { Printer.printName(decl->getName(), PrintNameContext::GenericParameter); }); printInherited(decl, decl->getInherited(), { }); } void PrintAST::visitAssociatedTypeDecl(AssociatedTypeDecl *decl) { printDocumentationComment(decl); printAttributes(decl); if (!Options.SkipIntroducerKeywords) Printer << tok::kw_associatedtype << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }); printInherited(decl, decl->getInherited(), { }); if (!decl->getDefaultDefinitionLoc().isNull()) { Printer << " = "; decl->getDefaultDefinitionLoc().getType().print(Printer, Options); } } void PrintAST::visitEnumDecl(EnumDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccessibility(decl); if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) { ASTContext &Ctx = decl->getASTContext(); printSourceRange(CharSourceRange(Ctx.SourceMgr, decl->getStartLoc(), decl->getBraces().Start.getAdvancedLoc(-1)), Ctx); } else { if (!Options.SkipIntroducerKeywords) Printer << tok::kw_enum << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }, [&]{ // Signature printNominalDeclGenericParams(decl); }); printInherited(decl); } if (Options.TypeDefinitions) { printMembersOfDecl(decl); } } void PrintAST::visitStructDecl(StructDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccessibility(decl); if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) { ASTContext &Ctx = decl->getASTContext(); printSourceRange(CharSourceRange(Ctx.SourceMgr, decl->getStartLoc(), decl->getBraces().Start.getAdvancedLoc(-1)), Ctx); } else { if (!Options.SkipIntroducerKeywords) Printer << tok::kw_struct << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }, [&]{ // Signature printNominalDeclGenericParams(decl); }); printInherited(decl); } if (Options.TypeDefinitions) { printMembersOfDecl(decl); } } void PrintAST::visitClassDecl(ClassDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccessibility(decl); if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) { ASTContext &Ctx = decl->getASTContext(); printSourceRange(CharSourceRange(Ctx.SourceMgr, decl->getStartLoc(), decl->getBraces().Start.getAdvancedLoc(-1)), Ctx); } else { if (!Options.SkipIntroducerKeywords) Printer << tok::kw_class << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }, [&]{ // Signature printNominalDeclGenericParams(decl); }); printInherited(decl); } if (Options.TypeDefinitions) { printMembersOfDecl(decl); } } void PrintAST::visitProtocolDecl(ProtocolDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccessibility(decl); if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) { ASTContext &Ctx = decl->getASTContext(); printSourceRange(CharSourceRange(Ctx.SourceMgr, decl->getStartLoc(), decl->getBraces().Start.getAdvancedLoc(-1)), Ctx); } else { if (!Options.SkipIntroducerKeywords) Printer << tok::kw_protocol << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }, [&]{ // Signature printNominalDeclGenericParams(decl); }); // Figure out whether we need an explicit 'class' in the inheritance. bool explicitClass = false; if (decl->requiresClass() && !decl->isObjC()) { bool inheritsRequiresClass = false; for (auto proto : decl->getLocalProtocols( ConformanceLookupKind::OnlyExplicit)) { if (proto->requiresClass()) { inheritsRequiresClass = true; break; } } if (!inheritsRequiresClass) explicitClass = true; } printInherited(decl, explicitClass); } if (Options.TypeDefinitions) { printMembersOfDecl(decl); } } static bool isStructOrClassContext(DeclContext *dc) { if (auto ctx = dc->getDeclaredTypeInContext()) return ctx->getClassOrBoundGenericClass() || ctx->getStructOrBoundGenericStruct(); return false; } void PrintAST::visitVarDecl(VarDecl *decl) { printDocumentationComment(decl); // Print @sil_stored when the attribute is not already // on, decl has storage and it is on a class. if (Options.PrintForSIL && decl->hasStorage() && isStructOrClassContext(decl->getDeclContext()) && !decl->getAttrs().hasAttribute()) Printer << "@sil_stored "; printAttributes(decl); printAccessibility(decl); if (!Options.SkipIntroducerKeywords) { if (decl->isStatic()) printStaticKeyword(decl->getCorrectStaticSpelling()); Printer << (decl->isLet() ? tok::kw_let : tok::kw_var) << " "; } recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }); if (decl->hasType()) { Printer << ": "; // Use the non-repr external type, but reuse the TypeLoc printing code. printTypeLoc(TypeLoc::withoutLoc(decl->getType())); } printAccessors(decl); } void PrintAST::visitParamDecl(ParamDecl *decl) { return visitVarDecl(decl); } void PrintAST::printOneParameter(const ParamDecl *param, bool Curried, bool ArgNameIsAPIByDefault) { Printer.callPrintStructurePre(PrintStructureKind::FunctionParameter, param); defer { Printer.printStructurePost(PrintStructureKind::FunctionParameter, param); }; auto printArgName = [&]() { // Print argument name. auto ArgName = param->getArgumentName(); auto BodyName = param->getName(); switch (Options.ArgAndParamPrinting) { case PrintOptions::ArgAndParamPrintingMode::ArgumentOnly: Printer.printName(ArgName, PrintNameContext::FunctionParameterExternal); if (!ArgNameIsAPIByDefault && !ArgName.empty()) Printer << " _"; break; case PrintOptions::ArgAndParamPrintingMode::MatchSource: if (ArgName == BodyName && ArgNameIsAPIByDefault) { Printer.printName(ArgName, PrintNameContext::FunctionParameterExternal); break; } if (ArgName.empty() && !ArgNameIsAPIByDefault) { Printer.printName(BodyName, PrintNameContext::FunctionParameterLocal); break; } SWIFT_FALLTHROUGH; case PrintOptions::ArgAndParamPrintingMode::BothAlways: Printer.printName(ArgName, PrintNameContext::FunctionParameterExternal); Printer << " "; Printer.printName(BodyName, PrintNameContext::FunctionParameterLocal); break; } Printer << ": "; }; auto TheTypeLoc = param->getTypeLoc(); // If the parameter is autoclosure, or noescape, print it. This is stored // on the type of the decl, not on the typerepr. if (param->hasType()) { auto bodyCanType = param->getType()->getCanonicalType(); if (auto patternType = dyn_cast(bodyCanType)) { switch (patternType->isAutoClosure()*2 + patternType->isNoEscape()) { case 0: break; // neither. case 1: Printer << "@noescape "; break; case 2: Printer << "@autoclosure(escaping) "; break; case 3: Printer << "@autoclosure "; break; } } } printArgName(); if (!TheTypeLoc.getTypeRepr() && param->hasType()) TheTypeLoc = TypeLoc::withoutLoc(param->getType()); auto ContainsFunc = [&] (DeclAttrKind Kind) { return Options.ExcludeAttrList.end() != std::find(Options.ExcludeAttrList. begin(), Options.ExcludeAttrList.end(), Kind); }; auto RemoveFunc = [&] (DeclAttrKind Kind) { Options.ExcludeAttrList.erase(std::find(Options.ExcludeAttrList.begin(), Options.ExcludeAttrList.end(), Kind)); }; // Since we have already printed @noescape and @autoclosure, we exclude them // when printing the type. auto hasNoEscape = ContainsFunc(DAK_NoEscape); auto hasAutoClosure = ContainsFunc(DAK_AutoClosure); if (!hasNoEscape) Options.ExcludeAttrList.push_back(DAK_NoEscape); if (!hasAutoClosure) Options.ExcludeAttrList.push_back(DAK_AutoClosure); // If the parameter is variadic, we will print the "..." after it, but we have // to strip off the added array type. if (param->isVariadic() && TheTypeLoc.getType()) { if (auto *BGT = TheTypeLoc.getType()->getAs()) TheTypeLoc.setType(BGT->getGenericArgs()[0]); } printTypeLoc(TheTypeLoc); if (param->isVariadic()) Printer << "..."; // After printing the type, we need to restore what the option used to be. if (!hasNoEscape) RemoveFunc(DAK_NoEscape); if (!hasAutoClosure) RemoveFunc(DAK_AutoClosure); if (Options.PrintDefaultParameterPlaceholder && param->isDefaultArgument()) { Printer << " = "; auto defaultArgStr = getDefaultArgumentSpelling(param->getDefaultArgumentKind()); if (defaultArgStr.empty()) Printer << tok::kw_default; else Printer << defaultArgStr; } } void PrintAST::printParameterList(ParameterList *PL, bool isCurried, std::function isAPINameByDefault) { Printer << "("; for (unsigned i = 0, e = PL->size(); i != e; ++i) { if (i > 0) Printer << ", "; printOneParameter(PL->get(i), isCurried, isAPINameByDefault(i)); } Printer << ")"; } void PrintAST::printFunctionParameters(AbstractFunctionDecl *AFD) { auto BodyParams = AFD->getParameterLists(); // Skip over the implicit 'self'. if (AFD->getImplicitSelfDecl()) BodyParams = BodyParams.slice(1); for (unsigned CurrPattern = 0, NumPatterns = BodyParams.size(); CurrPattern != NumPatterns; ++CurrPattern) { printParameterList(BodyParams[CurrPattern], /*Curried=*/CurrPattern > 0, [&](unsigned argNo)->bool { return CurrPattern > 0 || AFD->argumentNameIsAPIByDefault(argNo); }); } if (AFD->isBodyThrowing()) { if (AFD->getAttrs().hasAttribute()) Printer << " " << tok::kw_rethrows; else Printer << " " << tok::kw_throws; } } bool PrintAST::printASTNodes(const ArrayRef &Elements, bool NeedIndent) { IndentRAII IndentMore(*this, NeedIndent); bool PrintedSomething = false; for (auto element : Elements) { PrintedSomething = true; Printer.printNewline(); indent(); if (auto decl = element.dyn_cast()) { if (decl->shouldPrintInContext(Options)) visit(decl); } else if (auto stmt = element.dyn_cast()) { visit(stmt); } else { // FIXME: print expression // visit(element.get()); } } return PrintedSomething; } void PrintAST::visitFuncDecl(FuncDecl *decl) { if (decl->isAccessor()) { printDocumentationComment(decl); printAttributes(decl); switch (auto kind = decl->getAccessorKind()) { case AccessorKind::NotAccessor: break; case AccessorKind::IsGetter: case AccessorKind::IsAddressor: recordDeclLoc(decl, [&]{ if (decl->isMutating()) Printer << "mutating "; Printer << (kind == AccessorKind::IsGetter ? "get" : getAddressorLabel(decl)); }); Printer << " {"; break; case AccessorKind::IsDidSet: case AccessorKind::IsMaterializeForSet: case AccessorKind::IsMutableAddressor: recordDeclLoc(decl, [&]{ if (decl->isExplicitNonMutating()) Printer << "nonmutating "; Printer << (kind == AccessorKind::IsDidSet ? "didSet" : kind == AccessorKind::IsMaterializeForSet ? "materializeForSet" : getMutableAddressorLabel(decl)); }); Printer << " {"; break; case AccessorKind::IsSetter: case AccessorKind::IsWillSet: recordDeclLoc(decl, [&]{ if (decl->isExplicitNonMutating()) Printer << "nonmutating "; Printer << (decl->isSetter() ? "set" : "willSet"); auto params = decl->getParameterLists().back(); if (params->size() != 0 && !params->get(0)->isImplicit()) { auto Name = params->get(0)->getName(); if (!Name.empty()) { Printer << "("; Printer.printName(Name); Printer << ")"; } } }); Printer << " {"; } if (Options.FunctionDefinitions && decl->getBody()) { if (printASTNodes(decl->getBody()->getElements())) { Printer.printNewline(); indent(); } } Printer << "}"; } else { printDocumentationComment(decl); printAttributes(decl); printAccessibility(decl); if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) { ASTContext &Ctx = decl->getASTContext(); SourceLoc StartLoc = decl->getStartLoc(); SourceLoc EndLoc; if (!decl->getBodyResultTypeLoc().isNull()) { EndLoc = decl->getBodyResultTypeLoc().getSourceRange().End; } else { EndLoc = decl->getSignatureSourceRange().End; } CharSourceRange Range = Lexer::getCharSourceRangeFromSourceRange(Ctx.SourceMgr, SourceRange(StartLoc, EndLoc)); printSourceRange(Range, Ctx); } else { if (!Options.SkipIntroducerKeywords) { if (decl->isStatic() && !decl->isOperator()) printStaticKeyword(decl->getCorrectStaticSpelling()); if (decl->isMutating() && !decl->getAttrs().hasAttribute()) { Printer.printKeyword("mutating"); Printer << " "; } Printer << tok::kw_func << " "; } recordDeclLoc(decl, [&]{ // Name if (!decl->hasName()) Printer << ""; else Printer.printName(decl->getName()); }, [&] { // Parameters if (decl->isGeneric()) { printGenericParams(decl->getGenericParams()); } printFunctionParameters(decl); }); auto &Context = decl->getASTContext(); Type ResultTy = decl->getResultType(); if (ResultTy && !ResultTy->isEqual(TupleType::getEmpty(Context))) { Printer << " -> "; // Use the non-repr external type, but reuse the TypeLoc printing code. Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); printTypeLoc(TypeLoc::withoutLoc(ResultTy)); Printer.printStructurePost(PrintStructureKind::FunctionReturnType); } } if (!Options.FunctionDefinitions || !decl->getBody()) { return; } Printer << " "; visit(decl->getBody()); } } void PrintAST::printEnumElement(EnumElementDecl *elt) { recordDeclLoc(elt, [&]{ Printer.printName(elt->getName()); }); if (elt->hasArgumentType()) { Type Ty = elt->getArgumentType(); if (!Options.SkipPrivateStdlibDecls || !Ty.isPrivateStdlibType()) Ty.print(Printer, Options); } auto *raw = elt->getRawValueExpr(); if (!Options.EnumRawValues || !raw || raw->isImplicit()) return; // Print the explicit raw value expression. Printer << " = "; switch (raw->getKind()) { case ExprKind::IntegerLiteral: case ExprKind::FloatLiteral: { auto *numLiteral = cast(raw); Printer.callPrintStructurePre(PrintStructureKind::NumberLiteral); if (numLiteral->isNegative()) Printer << "-"; Printer << numLiteral->getDigitsText(); Printer.printStructurePost(PrintStructureKind::NumberLiteral); break; } case ExprKind::StringLiteral: Printer.callPrintStructurePre(PrintStructureKind::StringLiteral); Printer << "\"" << cast(raw)->getValue() << "\""; Printer.printStructurePost(PrintStructureKind::StringLiteral); break; default: break; // Incorrect raw value; skip it for error recovery. } } void PrintAST::visitEnumCaseDecl(EnumCaseDecl *decl) { auto elems = decl->getElements(); if (!elems.empty()) { // Documentation comments over the case are attached to the enum elements. printDocumentationComment(elems[0]); } printAttributes(decl); Printer << tok::kw_case << " "; interleave(elems.begin(), elems.end(), [&](EnumElementDecl *elt) { printEnumElement(elt); }, [&] { Printer << ", "; }); } void PrintAST::visitEnumElementDecl(EnumElementDecl *decl) { printDocumentationComment(decl); // In cases where there is no parent EnumCaseDecl (such as imported or // deserialized elements), print the element independently. printAttributes(decl); Printer << tok::kw_case << " "; printEnumElement(decl); } void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccessibility(decl); recordDeclLoc(decl, [&]{ Printer << "subscript"; }, [&] { // Parameters printParameterList(decl->getIndices(), /*Curried=*/false, /*isAPINameByDefault*/[](unsigned)->bool{return false;}); }); Printer << " -> "; Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); printTypeLoc(decl->getElementTypeLoc()); Printer.printStructurePost(PrintStructureKind::FunctionReturnType); printAccessors(decl); } void PrintAST::visitConstructorDecl(ConstructorDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccessibility(decl); if ((decl->getInitKind() == CtorInitializerKind::Convenience || decl->getInitKind() == CtorInitializerKind::ConvenienceFactory) && !decl->getAttrs().hasAttribute()) { Printer.printKeyword("convenience"); Printer << " "; } else if (decl->getInitKind() == CtorInitializerKind::Factory) { Printer << "/*not inherited*/ "; } recordDeclLoc(decl, [&]{ Printer << "init"; }, [&] { // Signature switch (decl->getFailability()) { case OTK_None: break; case OTK_Optional: Printer << "?"; break; case OTK_ImplicitlyUnwrappedOptional: Printer << "!"; break; } if (decl->isGeneric()) printGenericParams(decl->getGenericParams()); printFunctionParameters(decl); }); if (!Options.FunctionDefinitions || !decl->getBody()) { return; } Printer << " "; visit(decl->getBody()); } void PrintAST::visitDestructorDecl(DestructorDecl *decl) { printDocumentationComment(decl); printAttributes(decl); recordDeclLoc(decl, [&]{ Printer << "deinit"; }); if (!Options.FunctionDefinitions || !decl->getBody()) { return; } Printer << " "; visit(decl->getBody()); } void PrintAST::visitInfixOperatorDecl(InfixOperatorDecl *decl) { Printer.printKeyword("infix"); Printer << " " << tok::kw_operator << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }); Printer << " {"; Printer.printNewline(); { IndentRAII indentMore(*this); if (!decl->isAssociativityImplicit()) { indent(); Printer.printKeyword("associativity"); Printer << " "; switch (decl->getAssociativity()) { case Associativity::None: Printer.printKeyword("none"); break; case Associativity::Left: Printer.printKeyword("left"); break; case Associativity::Right: Printer.printKeyword("right"); break; } Printer.printNewline(); } if (!decl->isPrecedenceImplicit()) { indent(); Printer.printKeyword("precedence"); Printer << " " << decl->getPrecedence(); Printer.printNewline(); } if (!decl->isAssignmentImplicit()) { indent(); if (decl->isAssignment()) Printer.printKeyword("assignment"); else Printer << "/* not assignment */"; Printer.printNewline(); } } indent(); Printer << "}"; } void PrintAST::visitPrefixOperatorDecl(PrefixOperatorDecl *decl) { Printer.printKeyword("prefix"); Printer << " " << tok::kw_operator << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }); Printer << " {"; Printer.printNewline(); Printer << "}"; } void PrintAST::visitPostfixOperatorDecl(PostfixOperatorDecl *decl) { Printer.printKeyword("postfix"); Printer << " " << tok::kw_operator << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }); Printer << " {"; Printer.printNewline(); Printer << "}"; } void PrintAST::visitModuleDecl(ModuleDecl *decl) { } void PrintAST::visitBraceStmt(BraceStmt *stmt) { Printer << "{"; printASTNodes(stmt->getElements()); Printer.printNewline(); indent(); Printer << "}"; } void PrintAST::visitReturnStmt(ReturnStmt *stmt) { Printer << tok::kw_return; if (stmt->hasResult()) { Printer << " "; // FIXME: print expression. } } void PrintAST::visitThrowStmt(ThrowStmt *stmt) { Printer << tok::kw_throw << " "; // FIXME: print expression. } void PrintAST::visitDeferStmt(DeferStmt *stmt) { Printer << tok::kw_defer << " "; visit(stmt->getBodyAsWritten()); } void PrintAST::visitIfStmt(IfStmt *stmt) { Printer << tok::kw_if << " "; // FIXME: print condition Printer << " "; visit(stmt->getThenStmt()); if (auto elseStmt = stmt->getElseStmt()) { Printer << " " << tok::kw_else << " "; visit(elseStmt); } } void PrintAST::visitGuardStmt(GuardStmt *stmt) { Printer << tok::kw_guard << " "; // FIXME: print condition Printer << " "; visit(stmt->getBody()); } void PrintAST::visitIfConfigStmt(IfConfigStmt *stmt) { if (!Options.PrintIfConfig) return; for (auto &Clause : stmt->getClauses()) { if (&Clause == &*stmt->getClauses().begin()) Printer << tok::pound_if << " "; // FIXME: print condition else if (Clause.Cond) Printer << tok::pound_elseif << ""; // FIXME: print condition else Printer << tok::pound_else; Printer.printNewline(); if (printASTNodes(Clause.Elements)) { Printer.printNewline(); indent(); } } Printer.printNewline(); Printer << tok::pound_endif; } void PrintAST::visitWhileStmt(WhileStmt *stmt) { Printer << tok::kw_while << " "; // FIXME: print condition Printer << " "; visit(stmt->getBody()); } void PrintAST::visitRepeatWhileStmt(RepeatWhileStmt *stmt) { Printer << tok::kw_do << " "; visit(stmt->getBody()); Printer << " " << tok::kw_while << " "; // FIXME: print condition } void PrintAST::visitDoStmt(DoStmt *stmt) { Printer << tok::kw_do << " "; visit(stmt->getBody()); } void PrintAST::visitDoCatchStmt(DoCatchStmt *stmt) { Printer << tok::kw_do << " "; visit(stmt->getBody()); for (auto clause : stmt->getCatches()) { visitCatchStmt(clause); } } void PrintAST::visitCatchStmt(CatchStmt *stmt) { Printer << tok::kw_catch << " "; printPattern(stmt->getErrorPattern()); if (auto guard = stmt->getGuardExpr()) { Printer << " " << tok::kw_where << " "; // FIXME: print guard expression (void) guard; } Printer << ' '; visit(stmt->getBody()); } void PrintAST::visitForStmt(ForStmt *stmt) { Printer << tok::kw_for << " ("; // FIXME: print initializer Printer << "; "; if (stmt->getCond().isNonNull()) { // FIXME: print cond } Printer << "; "; // FIXME: print increment Printer << ") "; visit(stmt->getBody()); } void PrintAST::visitForEachStmt(ForEachStmt *stmt) { Printer << tok::kw_for << " "; printPattern(stmt->getPattern()); Printer << " " << tok::kw_in << " "; // FIXME: print container Printer << " "; visit(stmt->getBody()); } void PrintAST::visitBreakStmt(BreakStmt *stmt) { Printer << tok::kw_break; } void PrintAST::visitContinueStmt(ContinueStmt *stmt) { Printer << tok::kw_continue; } void PrintAST::visitFallthroughStmt(FallthroughStmt *stmt) { Printer << tok::kw_fallthrough; } void PrintAST::visitSwitchStmt(SwitchStmt *stmt) { Printer << tok::kw_switch << " "; // FIXME: print subject Printer << "{"; Printer.printNewline(); for (CaseStmt *C : stmt->getCases()) { visit(C); } Printer.printNewline(); indent(); Printer << "}"; } void PrintAST::visitCaseStmt(CaseStmt *CS) { if (CS->isDefault()) { Printer << tok::kw_default; } else { auto PrintCaseLabelItem = [&](const CaseLabelItem &CLI) { if (auto *P = CLI.getPattern()) printPattern(P); if (CLI.getGuardExpr()) { Printer << " " << tok::kw_where << " "; // FIXME: print guard expr } }; Printer << tok::kw_case << " "; interleave(CS->getCaseLabelItems(), PrintCaseLabelItem, [&] { Printer << ", "; }); } Printer << ":"; Printer.printNewline(); printASTNodes((cast(CS->getBody())->getElements())); } void PrintAST::visitFailStmt(FailStmt *stmt) { Printer << tok::kw_return << " " << tok::kw_nil; } void Decl::print(raw_ostream &os) const { PrintOptions options; options.FunctionDefinitions = true; options.TypeDefinitions = true; options.VarInitializers = true; print(os, options); } void Decl::print(raw_ostream &OS, const PrintOptions &Opts) const { StreamPrinter Printer(OS); print(Printer, Opts); } bool Decl::print(ASTPrinter &Printer, const PrintOptions &Opts) const { PrintAST printer(Printer, Opts); return printer.visit(const_cast(this)); } bool Decl::shouldPrintInContext(const PrintOptions &PO) const { // Skip getters/setters. They are part of the variable or subscript. if (isa(this) && cast(this)->isAccessor()) return false; if (PO.ExplodePatternBindingDecls) { if (isa(this)) return true; if (isa(this)) return false; } else { // Try to preserve the PatternBindingDecl structure. // Skip stored variables, unless they came from a Clang module. // Stored variables in Swift source will be picked up by the // PatternBindingDecl. if (auto *VD = dyn_cast(this)) { if (!VD->hasClangNode() && VD->hasStorage() && VD->getStorageKind() != VarDecl::StoredWithObservers) return false; } // Skip pattern bindings that consist of just one computed variable. if (auto pbd = dyn_cast(this)) { if (pbd->getPatternList().size() == 1) { auto pattern = pbd->getPatternList()[0].getPattern()->getSemanticsProvidingPattern(); if (auto named = dyn_cast(pattern)) { auto StorageKind = named->getDecl()->getStorageKind(); if (StorageKind == VarDecl::Computed || StorageKind == VarDecl::StoredWithObservers) return false; } } } } if (isa(this)) { return PO.PrintIfConfig; } // Print everything else. return true; } void Pattern::print(llvm::raw_ostream &OS, const PrintOptions &Options) const { StreamPrinter StreamPrinter(OS); PrintAST Printer(StreamPrinter, Options); Printer.printPattern(this); } //===----------------------------------------------------------------------===// // Type Printing //===----------------------------------------------------------------------===// namespace { class TypePrinter : public TypeVisitor { using super = TypeVisitor; ASTPrinter &Printer; const PrintOptions &Options; Optional> UnwrappedGenericParams; void printDeclContext(DeclContext *DC) { switch (DC->getContextKind()) { case DeclContextKind::Module: { Module *M = cast(DC); if (auto Parent = M->getParent()) printDeclContext(Parent); Printer.printModuleRef(M, M->getName()); return; } case DeclContextKind::FileUnit: printDeclContext(DC->getParent()); return; case DeclContextKind::AbstractClosureExpr: // FIXME: print closures somehow. return; case DeclContextKind::GenericTypeDecl: visit(cast(DC)->getType()); return; case DeclContextKind::ExtensionDecl: visit(cast(DC)->getExtendedType()); return; case DeclContextKind::Initializer: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::SerializedLocal: llvm_unreachable("bad decl context"); case DeclContextKind::AbstractFunctionDecl: visit(cast(DC)->getType()); return; case DeclContextKind::SubscriptDecl: visit(cast(DC)->getType()); return; } } void printGenericArgs(ArrayRef Args) { if (Args.empty()) return; Printer << "<"; bool First = true; for (Type Arg : Args) { if (First) First = false; else Printer << ", "; visit(Arg); } Printer << ">"; } static bool isSimple(Type type) { switch (type->getKind()) { case TypeKind::Function: case TypeKind::PolymorphicFunction: case TypeKind::GenericFunction: return false; case TypeKind::Metatype: case TypeKind::ExistentialMetatype: return !cast(type.getPointer())->hasRepresentation(); case TypeKind::Archetype: { auto arch = type->getAs(); return !arch->isOpenedExistential(); } default: return true; } } /// Helper function for printing a type that is embedded within a larger type. /// /// This is necessary whenever the inner type may not normally be represented /// as a 'type-simple' production in the type grammar. void printWithParensIfNotSimple(Type T) { if (T.isNull()) { visit(T); return; } if (!isSimple(T)) { Printer << "("; visit(T); Printer << ")"; } else { visit(T); } } void printGenericParams(GenericParamList *Params) { PrintAST(Printer, Options).printGenericParams(Params); } template void printModuleContext(T *Ty) { Module *Mod = Ty->getDecl()->getModuleContext(); Printer.printModuleRef(Mod, Mod->getName()); Printer << "."; } template void printTypeDeclName(T *Ty) { TypeDecl *TD = Ty->getDecl(); Printer.printTypeRef(TD, TD->getName()); } // FIXME: we should have a callback that would tell us // whether it's kosher to print a module name or not bool isLLDBExpressionModule(Module *M) { if (!M) return false; return M->getName().str().startswith(LLDB_EXPRESSIONS_MODULE_NAME_PREFIX); } bool shouldPrintFullyQualified(TypeBase *T) { if (Options.FullyQualifiedTypes) return true; if (!Options.FullyQualifiedTypesIfAmbiguous) return false; Decl *D = T->getAnyGeneric(); // If we cannot find the declaration, be extra careful and print // the type qualified. if (!D) return true; Module *M = D->getDeclContext()->getParentModule(); // Don't print qualifiers for types from the standard library. if (M->isStdlibModule() || M->getName() == M->getASTContext().Id_ObjectiveC || M->isSystemModule() || isLLDBExpressionModule(M)) return false; // Don't print qualifiers for imported types. for (auto File : M->getFiles()) { if (File->getKind() == FileUnitKind::ClangModule) return false; } return true; } public: TypePrinter(ASTPrinter &Printer, const PrintOptions &PO) : Printer(Printer), Options(PO) {} void visit(Type T) { Printer.printTypePre(TypeLoc::withoutLoc(T)); defer { Printer.printTypePost(TypeLoc::withoutLoc(T)); }; // If we have an alternate name for this type, use it. if (Options.AlternativeTypeNames) { auto found = Options.AlternativeTypeNames->find(T.getCanonicalTypeOrNull()); if (found != Options.AlternativeTypeNames->end()) { Printer << found->second.str(); return; } } super::visit(T); } void visitErrorType(ErrorType *T) { Printer << "<>"; } void visitUnresolvedType(UnresolvedType *T) { if (T->getASTContext().LangOpts.DebugConstraintSolver) Printer << "<>"; else Printer << "_"; } void visitBuiltinRawPointerType(BuiltinRawPointerType *T) { Printer << "Builtin.RawPointer"; } void visitBuiltinNativeObjectType(BuiltinNativeObjectType *T) { Printer << "Builtin.NativeObject"; } void visitBuiltinUnknownObjectType(BuiltinUnknownObjectType *T) { Printer << "Builtin.UnknownObject"; } void visitBuiltinBridgeObjectType(BuiltinBridgeObjectType *T) { Printer << "Builtin.BridgeObject"; } void visitBuiltinUnsafeValueBufferType(BuiltinUnsafeValueBufferType *T) { Printer << "Builtin.UnsafeValueBuffer"; } void visitBuiltinVectorType(BuiltinVectorType *T) { llvm::SmallString<32> UnderlyingStrVec; StringRef UnderlyingStr; { // FIXME: Ugly hack: remove the .Builtin from the element type. { llvm::raw_svector_ostream UnderlyingOS(UnderlyingStrVec); T->getElementType().print(UnderlyingOS); } if (UnderlyingStrVec.startswith("Builtin.")) UnderlyingStr = UnderlyingStrVec.substr(8); else UnderlyingStr = UnderlyingStrVec; } Printer << "Builtin.Vec" << T->getNumElements() << "x" << UnderlyingStr; } void visitBuiltinIntegerType(BuiltinIntegerType *T) { auto width = T->getWidth(); if (width.isFixedWidth()) { Printer << "Builtin.Int" << width.getFixedWidth(); } else if (width.isPointerWidth()) { Printer << "Builtin.Word"; } else { llvm_unreachable("impossible bit width"); } } void visitBuiltinFloatType(BuiltinFloatType *T) { switch (T->getFPKind()) { case BuiltinFloatType::IEEE16: Printer << "Builtin.FPIEEE16"; return; case BuiltinFloatType::IEEE32: Printer << "Builtin.FPIEEE32"; return; case BuiltinFloatType::IEEE64: Printer << "Builtin.FPIEEE64"; return; case BuiltinFloatType::IEEE80: Printer << "Builtin.FPIEEE80"; return; case BuiltinFloatType::IEEE128: Printer << "Builtin.FPIEEE128"; return; case BuiltinFloatType::PPC128: Printer << "Builtin.FPPPC128"; return; } } void visitNameAliasType(NameAliasType *T) { if (Options.PrintForSIL) { visit(T->getSinglyDesugaredType()); return; } if (shouldPrintFullyQualified(T)) { if (auto ParentDC = T->getDecl()->getDeclContext()) { printDeclContext(ParentDC); Printer << "."; } } printTypeDeclName(T); } void visitParenType(ParenType *T) { Printer << "("; visit(T->getUnderlyingType()); Printer << ")"; } void visitTupleType(TupleType *T) { Printer << "("; auto Fields = T->getElements(); for (unsigned i = 0, e = Fields.size(); i != e; ++i) { if (i) Printer << ", "; const TupleTypeElt &TD = Fields[i]; Type EltType = TD.getType(); Printer.callPrintStructurePre(PrintStructureKind::TupleElement); defer { Printer.printStructurePost(PrintStructureKind::TupleElement); }; if (TD.hasName()) { Printer.printName(TD.getName(), PrintNameContext::TupleElement); Printer << ": "; } if (TD.isVararg()) { visit(TD.getVarargBaseTy()); Printer << "..."; } else visit(EltType); } Printer << ")"; } void visitUnboundGenericType(UnboundGenericType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); } void visitBoundGenericType(BoundGenericType *T) { if (Options.SynthesizeSugarOnTypes) { auto *NT = T->getDecl(); auto &Ctx = T->getASTContext(); if (NT == Ctx.getArrayDecl()) { Printer << "["; visit(T->getGenericArgs()[0]); Printer << "]"; return; } if (NT == Ctx.getDictionaryDecl()) { Printer << "["; visit(T->getGenericArgs()[0]); Printer << " : "; visit(T->getGenericArgs()[1]); Printer << "]"; return; } if (NT == Ctx.getOptionalDecl()) { printWithParensIfNotSimple(T->getGenericArgs()[0]); Printer << "?"; return; } if (NT == Ctx.getImplicitlyUnwrappedOptionalDecl()) { printWithParensIfNotSimple(T->getGenericArgs()[0]); Printer << "!"; return; } } if (auto ParentType = T->getParent()) { visit(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); printGenericArgs(T->getGenericArgs()); } void visitEnumType(EnumType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); } void visitStructType(StructType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); } void visitClassType(ClassType *T) { if (auto ParentType = T->getParent()) { visit(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); } void visitAnyMetatypeType(AnyMetatypeType *T) { if (T->hasRepresentation()) { switch (T->getRepresentation()) { case MetatypeRepresentation::Thin: Printer << "@thin "; break; case MetatypeRepresentation::Thick: Printer << "@thick "; break; case MetatypeRepresentation::ObjC: Printer << "@objc_metatype "; break; } } printWithParensIfNotSimple(T->getInstanceType()); // We spell normal metatypes of existential types as .Protocol. if (isa(T) && // Special case AssociatedTypeType's here, since they may not be fully // set up within the type checker (preventing getCanonicalType from // working), and we want type printing to always work even in malformed // programs half way through the type checker. !isa(T->getInstanceType().getPointer()) && T->getInstanceType()->isAnyExistentialType()) { Printer << ".Protocol"; } else { Printer << ".Type"; } } void visitModuleType(ModuleType *T) { Printer << "module<"; Printer.printModuleRef(T->getModule(), T->getModule()->getName()); Printer << ">"; } void visitDynamicSelfType(DynamicSelfType *T) { Printer << "Self"; } void printFunctionExtInfo(AnyFunctionType::ExtInfo info) { if(Options.SkipAttributes) return; auto IsAttrExcluded = [&](DeclAttrKind Kind) { return Options.ExcludeAttrList.end() != std::find(Options.ExcludeAttrList. begin(), Options.ExcludeAttrList.end(), Kind); }; if (info.isAutoClosure() && !IsAttrExcluded(DAK_AutoClosure)) Printer << "@autoclosure "; else if (info.isNoEscape() && !IsAttrExcluded(DAK_NoEscape)) // autoclosure implies noescape. Printer << "@noescape "; if (Options.PrintFunctionRepresentationAttrs) { // TODO: coalesce into a single convention attribute. switch (info.getSILRepresentation()) { case SILFunctionType::Representation::Thick: break; case SILFunctionType::Representation::Thin: Printer << "@convention(thin) "; break; case SILFunctionType::Representation::Block: Printer << "@convention(block) "; break; case SILFunctionType::Representation::CFunctionPointer: Printer << "@convention(c) "; break; case SILFunctionType::Representation::Method: Printer << "@convention(method) "; break; case SILFunctionType::Representation::ObjCMethod: Printer << "@convention(objc_method) "; break; case SILFunctionType::Representation::WitnessMethod: Printer << "@convention(witness_method) "; break; } } if (info.isNoReturn()) Printer << "@noreturn "; } void printFunctionExtInfo(SILFunctionType::ExtInfo info) { if(Options.SkipAttributes) return; if (Options.PrintFunctionRepresentationAttrs) { // TODO: coalesce into a single convention attribute. switch (info.getRepresentation()) { case SILFunctionType::Representation::Thick: break; case SILFunctionType::Representation::Thin: Printer << "@convention(thin) "; break; case SILFunctionType::Representation::Block: Printer << "@convention(block) "; break; case SILFunctionType::Representation::CFunctionPointer: Printer << "@convention(c) "; break; case SILFunctionType::Representation::Method: Printer << "@convention(method) "; break; case SILFunctionType::Representation::ObjCMethod: Printer << "@convention(objc_method) "; break; case SILFunctionType::Representation::WitnessMethod: Printer << "@convention(witness_method) "; break; } } if (info.isNoReturn()) Printer << "@noreturn "; } void visitFunctionType(FunctionType *T) { Printer.callPrintStructurePre(PrintStructureKind::FunctionType); defer { Printer.printStructurePost(PrintStructureKind::FunctionType); }; printFunctionExtInfo(T->getExtInfo()); printWithParensIfNotSimple(T->getInput()); if (T->throws()) Printer << " " << tok::kw_throws; Printer << " -> "; Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); T->getResult().print(Printer, Options); Printer.printStructurePost(PrintStructureKind::FunctionReturnType); } void visitPolymorphicFunctionType(PolymorphicFunctionType *T) { Printer.callPrintStructurePre(PrintStructureKind::FunctionType); defer { Printer.printStructurePost(PrintStructureKind::FunctionType); }; printFunctionExtInfo(T->getExtInfo()); printGenericParams(&T->getGenericParams()); Printer << " "; printWithParensIfNotSimple(T->getInput()); if (T->throws()) Printer << " " << tok::kw_throws; Printer << " -> "; Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); T->getResult().print(Printer, Options); Printer.printStructurePost(PrintStructureKind::FunctionReturnType); } /// If we can't find the depth of a type, return ErrorDepth. const unsigned ErrorDepth = ~0U; /// A helper function to return the depth of a type. unsigned getDepthOfType(Type ty) { if (auto paramTy = ty->getAs()) return paramTy->getDepth(); if (auto depMemTy = dyn_cast(ty->getCanonicalType())) { CanType rootTy; do { rootTy = depMemTy.getBase(); } while ((depMemTy = dyn_cast(rootTy))); if (auto rootParamTy = dyn_cast(rootTy)) return rootParamTy->getDepth(); return ErrorDepth; } return ErrorDepth; } /// A helper function to return the depth of a requirement. unsigned getDepthOfRequirement(const Requirement &req) { switch (req.getKind()) { case RequirementKind::Conformance: case RequirementKind::Superclass: case RequirementKind::WitnessMarker: return getDepthOfType(req.getFirstType()); case RequirementKind::SameType: { // Return the max valid depth of firstType and secondType. unsigned firstDepth = getDepthOfType(req.getFirstType()); unsigned secondDepth = getDepthOfType(req.getSecondType()); unsigned maxDepth; if (firstDepth == ErrorDepth && secondDepth != ErrorDepth) maxDepth = secondDepth; else if (firstDepth != ErrorDepth && secondDepth == ErrorDepth) maxDepth = firstDepth; else maxDepth = std::max(firstDepth, secondDepth); return maxDepth; } } llvm_unreachable("bad RequirementKind"); } void printGenericSignature(ArrayRef genericParams, ArrayRef requirements) { if (!Options.PrintInSILBody) { printSingleDepthOfGenericSignature(genericParams, requirements); return; } // In order to recover the nested GenericParamLists, we divide genericParams // and requirements according to depth. unsigned paramIdx = 0, numParam = genericParams.size(); while (paramIdx < numParam) { unsigned depth = genericParams[paramIdx]->getDepth(); // Move index to genericParams. unsigned lastParamIdx = paramIdx; do { lastParamIdx++; } while (lastParamIdx < numParam && genericParams[lastParamIdx]->getDepth() == depth); // Collect requirements for this level. // Because of same-type requirements, these aren't well-ordered. SmallVector requirementsAtDepth; for (auto reqt : requirements) { unsigned currentDepth = getDepthOfRequirement(reqt); // Collect requirements at the current depth. if (currentDepth == depth) requirementsAtDepth.push_back(reqt); // If we're at the bottom-most level, collect depthless requirements. if (currentDepth == ErrorDepth && lastParamIdx == numParam) requirementsAtDepth.push_back(reqt); } printSingleDepthOfGenericSignature( genericParams.slice(paramIdx, lastParamIdx - paramIdx), requirementsAtDepth); paramIdx = lastParamIdx; } } void printSingleDepthOfGenericSignature( ArrayRef genericParams, ArrayRef requirements) { // Print the generic parameters. Printer << "<"; bool isFirstParam = true; for (auto param : genericParams) { if (isFirstParam) isFirstParam = false; else Printer << ", "; visit(param); } // Print the requirements. bool isFirstReq = true; for (const auto &req : requirements) { if (req.getKind() == RequirementKind::WitnessMarker) continue; if (isFirstReq) { Printer << " " << tok::kw_where << " "; isFirstReq = false; } else { Printer << ", "; } visit(req.getFirstType()); switch (req.getKind()) { case RequirementKind::Conformance: case RequirementKind::Superclass: Printer << " : "; break; case RequirementKind::SameType: Printer << " == "; break; case RequirementKind::WitnessMarker: llvm_unreachable("Handled above"); } visit(req.getSecondType()); } Printer << ">"; } void visitGenericFunctionType(GenericFunctionType *T) { Printer.callPrintStructurePre(PrintStructureKind::FunctionType); defer { Printer.printStructurePost(PrintStructureKind::FunctionType); }; printFunctionExtInfo(T->getExtInfo()); printGenericSignature(T->getGenericParams(), T->getRequirements()); Printer << " "; printWithParensIfNotSimple(T->getInput()); if (T->throws()) Printer << " " << tok::kw_throws; Printer << " -> "; Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); T->getResult().print(Printer, Options); Printer.printStructurePost(PrintStructureKind::FunctionReturnType); } void printCalleeConvention(ParameterConvention conv) { switch (conv) { case ParameterConvention::Direct_Unowned: return; case ParameterConvention::Direct_Owned: Printer << "@callee_owned "; return; case ParameterConvention::Direct_Guaranteed: Printer << "@callee_guaranteed "; return; case ParameterConvention::Direct_Deallocating: // Closures do not have destructors. llvm_unreachable("callee convention cannot be deallocating"); case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: case ParameterConvention::Indirect_In_Guaranteed: llvm_unreachable("callee convention cannot be indirect"); } llvm_unreachable("bad convention"); } void visitSILFunctionType(SILFunctionType *T) { printFunctionExtInfo(T->getExtInfo()); printCalleeConvention(T->getCalleeConvention()); if (auto sig = T->getGenericSignature()) { printGenericSignature(sig->getGenericParams(), sig->getRequirements()); Printer << " "; } Printer << "("; bool first = true; for (auto param : T->getParameters()) { Printer.printSeparator(first, ", "); param.print(Printer, Options); } Printer << ") -> "; unsigned totalResults = T->getNumAllResults() + unsigned(T->hasErrorResult()); if (totalResults != 1) Printer << "("; first = true; for (auto result : T->getAllResults()) { Printer.printSeparator(first, ", "); result.print(Printer, Options); } if (T->hasErrorResult()) { // The error result is implicitly @owned; don't print that. assert(T->getErrorResult().getConvention() == ResultConvention::Owned); Printer.printSeparator(first, ", "); Printer << "@error "; T->getErrorResult().getType().print(Printer, Options); } if (totalResults != 1) Printer << ")"; } void visitSILBlockStorageType(SILBlockStorageType *T) { Printer << "@block_storage "; printWithParensIfNotSimple(T->getCaptureType()); } void visitSILBoxType(SILBoxType *T) { Printer << "@box "; printWithParensIfNotSimple(T->getBoxedType()); } void visitArraySliceType(ArraySliceType *T) { Printer << "["; visit(T->getBaseType()); Printer << "]"; } void visitDictionaryType(DictionaryType *T) { Printer << "["; visit(T->getKeyType()); Printer << " : "; visit(T->getValueType()); Printer << "]"; } void visitOptionalType(OptionalType *T) { printWithParensIfNotSimple(T->getBaseType()); Printer << "?"; } void visitImplicitlyUnwrappedOptionalType(ImplicitlyUnwrappedOptionalType *T) { printWithParensIfNotSimple(T->getBaseType()); Printer << "!"; } void visitProtocolType(ProtocolType *T) { printTypeDeclName(T); } void visitProtocolCompositionType(ProtocolCompositionType *T) { Printer << tok::kw_protocol << "<"; bool First = true; for (auto Proto : T->getProtocols()) { if (First) First = false; else Printer << ", "; visit(Proto); } Printer << ">"; } void visitLValueType(LValueType *T) { Printer << "@lvalue "; visit(T->getObjectType()); } void visitInOutType(InOutType *T) { Printer << tok::kw_inout << " "; visit(T->getObjectType()); } void visitArchetypeType(ArchetypeType *T) { if (auto existentialTy = T->getOpenedExistentialType()) { if (Options.PrintForSIL) Printer << "@opened(\"" << T->getOpenedExistentialID() << "\") "; visit(existentialTy); } else { if (auto parent = T->getParent()) { visit(parent); Printer << "."; } if (T->getName().empty()) Printer << ""; else { PrintNameContext context = PrintNameContext::Normal; if (T->getSelfProtocol()) context = PrintNameContext::GenericParameter; Printer.printName(T->getName(), context); } } } GenericParamList *getGenericParamListAtDepth(unsigned depth) { assert(Options.ContextGenericParams); if (!UnwrappedGenericParams) { std::vector paramLists; for (auto *params = Options.ContextGenericParams; params; params = params->getOuterParameters()) { paramLists.push_back(params); } UnwrappedGenericParams = std::move(paramLists); } return UnwrappedGenericParams->rbegin()[depth]; } void visitGenericTypeParamType(GenericTypeParamType *T) { // Substitute a context archetype if we have context generic params. if (Options.ContextGenericParams) { return visit(getGenericParamListAtDepth(T->getDepth()) ->getPrimaryArchetypes()[T->getIndex()]); } auto Name = T->getName(); if (Name.empty()) Printer << ""; else { PrintNameContext context = PrintNameContext::Normal; if (T->getDecl() && T->getDecl()->isProtocolSelf()) context = PrintNameContext::GenericParameter; Printer.printName(Name, context); } } void visitAssociatedTypeType(AssociatedTypeType *T) { auto Name = T->getDecl()->getName(); if (Name.empty()) Printer << ""; else Printer.printName(Name); } void visitSubstitutedType(SubstitutedType *T) { visit(T->getReplacementType()); } void visitDependentMemberType(DependentMemberType *T) { visit(T->getBase()); Printer << "."; Printer.printName(T->getName()); } void visitUnownedStorageType(UnownedStorageType *T) { if (Options.PrintStorageRepresentationAttrs) Printer << "@sil_unowned "; visit(T->getReferentType()); } void visitUnmanagedStorageType(UnmanagedStorageType *T) { if (Options.PrintStorageRepresentationAttrs) Printer << "@sil_unmanaged "; visit(T->getReferentType()); } void visitWeakStorageType(WeakStorageType *T) { if (Options.PrintStorageRepresentationAttrs) Printer << "@sil_weak "; visit(T->getReferentType()); } void visitTypeVariableType(TypeVariableType *T) { if (T->getASTContext().LangOpts.DebugConstraintSolver) { Printer << "$T" << T->getID(); return; } Printer << "_"; } }; } // unnamed namespace void Type::print(raw_ostream &OS, const PrintOptions &PO) const { StreamPrinter Printer(OS); print(Printer, PO); } void Type::print(ASTPrinter &Printer, const PrintOptions &PO) const { if (isNull()) Printer << ""; else TypePrinter(Printer, PO).visit(*this); } void GenericSignature::print(raw_ostream &OS) const { StreamPrinter Printer(OS); TypePrinter(Printer, PrintOptions()) .printGenericSignature(getGenericParams(), getRequirements()); } void GenericSignature::dump() const { print(llvm::errs()); llvm::errs() << '\n'; } std::string GenericSignature::getAsString() const { std::string result; llvm::raw_string_ostream out(result); print(out); return out.str(); } static StringRef getStringForParameterConvention(ParameterConvention conv) { switch (conv) { case ParameterConvention::Indirect_In: return "@in "; case ParameterConvention::Indirect_In_Guaranteed: return "@in_guaranteed "; case ParameterConvention::Indirect_Inout: return "@inout "; case ParameterConvention::Indirect_InoutAliasable: return "@inout_aliasable "; case ParameterConvention::Direct_Owned: return "@owned "; case ParameterConvention::Direct_Unowned: return ""; case ParameterConvention::Direct_Guaranteed: return "@guaranteed "; case ParameterConvention::Direct_Deallocating: return "@deallocating "; } llvm_unreachable("bad parameter convention"); } StringRef swift::getCheckedCastKindName(CheckedCastKind kind) { switch (kind) { case CheckedCastKind::Unresolved: return "unresolved"; case CheckedCastKind::Coercion: return "coercion"; case CheckedCastKind::ValueCast: return "value_cast"; case CheckedCastKind::ArrayDowncast: return "array_downcast"; case CheckedCastKind::DictionaryDowncast: return "dictionary_downcast"; case CheckedCastKind::DictionaryDowncastBridged: return "dictionary_downcast_bridged"; case CheckedCastKind::SetDowncast: return "set_downcast"; case CheckedCastKind::SetDowncastBridged: return "set_downcast_bridged"; case CheckedCastKind::BridgeFromObjectiveC: return "bridge_from_objc"; } llvm_unreachable("bad checked cast name"); } void SILParameterInfo::dump() const { print(llvm::errs()); llvm::errs() << '\n'; } void SILParameterInfo::print(raw_ostream &OS, const PrintOptions &Opts) const { StreamPrinter Printer(OS); print(Printer, Opts); } void SILParameterInfo::print(ASTPrinter &Printer, const PrintOptions &Opts) const { Printer << getStringForParameterConvention(getConvention()); getType().print(Printer, Opts); } static StringRef getStringForResultConvention(ResultConvention conv) { switch (conv) { case ResultConvention::Indirect: return "@out "; case ResultConvention::Owned: return "@owned "; case ResultConvention::Unowned: return ""; case ResultConvention::UnownedInnerPointer: return "@unowned_inner_pointer "; case ResultConvention::Autoreleased: return "@autoreleased "; } llvm_unreachable("bad result convention"); } void SILResultInfo::dump() const { print(llvm::errs()); llvm::errs() << '\n'; } void SILResultInfo::print(raw_ostream &OS, const PrintOptions &Opts) const { StreamPrinter Printer(OS); print(Printer, Opts); } void SILResultInfo::print(ASTPrinter &Printer, const PrintOptions &Opts) const { Printer << getStringForResultConvention(getConvention()); getType().print(Printer, Opts); } std::string Type::getString(const PrintOptions &PO) const { std::string Result; llvm::raw_string_ostream OS(Result); print(OS, PO); return OS.str(); } std::string TypeBase::getString(const PrintOptions &PO) const { std::string Result; llvm::raw_string_ostream OS(Result); print(OS, PO); return OS.str(); } void TypeBase::dumpPrint() const { print(llvm::errs()); llvm::errs() << '\n'; } void TypeBase::print(raw_ostream &OS, const PrintOptions &PO) const { Type(const_cast(this)).print(OS, PO); } void TypeBase::print(ASTPrinter &Printer, const PrintOptions &PO) const { Type(const_cast(this)).print(Printer, PO); } void ProtocolConformance::printName(llvm::raw_ostream &os, const PrintOptions &PO) const { if (getKind() == ProtocolConformanceKind::Normal) { if (PO.PrintForSIL) { if (auto genericSig = getGenericSignature()) { StreamPrinter sPrinter(os); TypePrinter typePrinter(sPrinter, PO); typePrinter.printGenericSignature(genericSig->getGenericParams(), genericSig->getRequirements()); os << ' '; } } else if (auto gp = getGenericParams()) { StreamPrinter SPrinter(os); PrintAST Printer(SPrinter, PO); Printer.printGenericParams(gp); os << ' '; } } getType()->print(os, PO); os << ": "; switch (getKind()) { case ProtocolConformanceKind::Normal: { auto normal = cast(this); os << normal->getProtocol()->getName() << " module " << normal->getDeclContext()->getParentModule()->getName(); break; } case ProtocolConformanceKind::Specialized: { auto spec = cast(this); os << "specialize <"; interleave(spec->getGenericSubstitutions(), [&](const Substitution &s) { s.print(os, PO); }, [&] { os << ", "; }); os << "> ("; spec->getGenericConformance()->printName(os, PO); os << ")"; break; } case ProtocolConformanceKind::Inherited: { auto inherited = cast(this); os << "inherit ("; inherited->getInheritedConformance()->printName(os, PO); os << ")"; break; } } } void Substitution::print(llvm::raw_ostream &os, const PrintOptions &PO) const { Replacement->print(os, PO); }