//===--- ASTPrinter.cpp - Swift Language AST Printer ----------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements printing for the Swift ASTs. // //===----------------------------------------------------------------------===// #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PrintOptions.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeVisitor.h" #include "swift/AST/TypeWalker.h" #include "swift/AST/Types.h" #include "swift/Basic/Defer.h" #include "swift/Basic/PrimitiveParsing.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/StringExtras.h" #include "swift/Config.h" #include "swift/Parse/Lexer.h" #include "swift/Strings.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/Module.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" #include #include using namespace swift; void PrintOptions::setBaseType(Type T) { TransformContext = TypeTransformContext(T); } void PrintOptions::initForSynthesizedExtension(NominalTypeDecl *D) { TransformContext = TypeTransformContext(D); } void PrintOptions::clearSynthesizedExtension() { TransformContext.reset(); } TypeTransformContext::TypeTransformContext(Type T) : BaseType(T.getPointer()) { assert(T->mayHaveMembers()); } TypeTransformContext::TypeTransformContext(NominalTypeDecl *NTD) : BaseType(NTD->getDeclaredTypeInContext().getPointer()), Nominal(NTD) {} NominalTypeDecl *TypeTransformContext::getNominal() const { return Nominal; } Type TypeTransformContext::getBaseType() const { return Type(BaseType); } bool TypeTransformContext::isPrintingSynthesizedExtension() const { return Nominal != nullptr; } std::string ASTPrinter::sanitizeUtf8(StringRef Text) { llvm::SmallString<256> Builder; Builder.reserve(Text.size()); const llvm::UTF8* Data = reinterpret_cast(Text.begin()); const llvm::UTF8* End = reinterpret_cast(Text.end()); StringRef Replacement = u8"\ufffd"; while (Data < End) { auto Step = llvm::getNumBytesForUTF8(*Data); if (Data + Step > End) { Builder.append(Replacement); break; } if (llvm::isLegalUTF8Sequence(Data, Data + Step)) { Builder.append(Data, Data + Step); } else { // If malformed, add replacement characters. Builder.append(Replacement); } Data += Step; } return Builder.str(); } ValueDecl* ASTPrinter::findConformancesWithDocComment(ValueDecl *VD) { assert(VD->getRawComment().isEmpty()); std::queue AllConformances; AllConformances.push(VD); while (!AllConformances.empty()) { auto *VD = AllConformances.front(); AllConformances.pop(); if (VD->getRawComment().isEmpty()) { for (auto *Req : VD->getSatisfiedProtocolRequirements()) { AllConformances.push(Req); } } else { return VD; } } return nullptr; } 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(Type T, const TypeDecl *RefTo, Identifier Name) { PrintNameContext Context = PrintNameContext::Normal; if (isa(RefTo)) { Context = PrintNameContext::GenericParameter; } else if (T && T->is()) { assert(T->castTo()->getSelfType()->getAnyNominal() && "protocol Self handled as GenericTypeParamDecl"); Context = PrintNameContext::ClassDynamicSelf; } printName(Name, Context); } void ASTPrinter::printModuleRef(ModuleEntity Mod, Identifier Name) { printName(Name); } void ASTPrinter::callPrintDeclPre(const Decl *D, Optional Bracket) { forceNewlines(); if (SynthesizeTarget && isa(D)) printSynthesizedExtensionPre(cast(D), SynthesizeTarget, Bracket); else printDeclPre(D, Bracket); } 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; } llvm::raw_ostream &swift:: operator<<(llvm::raw_ostream &OS, tok keyword) { switch (keyword) { #define KEYWORD(KW) case tok::kw_##KW: OS << #KW; break; #define POUND_KEYWORD(KW) case tok::pound_##KW: OS << "#"#KW; break; #define PUNCTUATOR(PUN, TEXT) case tok::PUN: OS << TEXT; break; #include "swift/Syntax/TokenKinds.def" default: llvm_unreachable("unexpected keyword or punctuator kind"); } return OS; } uint8_t swift::getKeywordLen(tok keyword) { switch (keyword) { #define KEYWORD(KW) case tok::kw_##KW: return StringRef(#KW).size(); #define POUND_KEYWORD(KW) case tok::pound_##KW: return StringRef("#"#KW).size(); #define PUNCTUATOR(PUN, TEXT) case tok::PUN: return StringRef(TEXT).size(); #include "swift/Syntax/TokenKinds.def" default: llvm_unreachable("unexpected keyword or punctuator kind"); } } StringRef swift::getCodePlaceholder() { return "<#code#>"; } ASTPrinter &operator<<(ASTPrinter &printer, tok keyword) { SmallString<16> Buffer; llvm::raw_svector_ostream OS(Buffer); OS << keyword; printer.printKeyword(Buffer.str()); 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::ClassDynamicSelf: case PrintNameContext::GenericParameter: return keyword != "Self"; case PrintNameContext::FunctionParameterExternal: case PrintNameContext::FunctionParameterLocal: case PrintNameContext::TupleElement: return !canBeArgumentLabel(keyword); } llvm_unreachable("Unhandled PrintNameContext in switch."); } 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/Syntax/TokenKinds.def" .Default(false); if (IsKeyword) IsKeyword = escapeKeywordInContext(Name.str(), Context); if (IsKeyword) *this << "`"; *this << Name.str(); if (IsKeyword) *this << "`"; printNamePost(Context); } void StreamPrinter::printText(StringRef Text) { OS << Text; } /// Whether we will be printing a TypeLoc by using the TypeRepr printer static bool willUseTypeReprPrinting(TypeLoc tyLoc, Type currentType, PrintOptions options) { // Special case for when transforming archetypes if (currentType && tyLoc.getType()) return false; return ((options.PreferTypeRepr && tyLoc.hasLocation()) || (tyLoc.getType().isNull() && tyLoc.getTypeRepr())); } namespace { /// \brief AST pretty-printer. class PrintAST : public ASTVisitor { ASTPrinter &Printer; PrintOptions Options; unsigned IndentLevel = 0; Decl *Current = nullptr; Type CurrentType; 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 printRawComment(RawComment RC) { 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 printSwiftDocumentationComment(const Decl *D) { auto RC = D->getRawComment(); if (RC.isEmpty() && !Options.ElevateDocCommentFromConformance) return; if (RC.isEmpty()) { if (auto *VD = dyn_cast(D)) { if (auto *Req = ASTPrinter::findConformancesWithDocComment( const_cast(VD))) { printRawComment(Req->getRawComment()); } } } else { printRawComment(RC); } } 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 printAccess(AccessLevel access, StringRef suffix = "") { switch (access) { case AccessLevel::Private: Printer << tok::kw_private; break; case AccessLevel::FilePrivate: Printer << tok::kw_fileprivate; break; case AccessLevel::Internal: if (!Options.PrintInternalAccessKeyword) return; Printer << tok::kw_internal; break; case AccessLevel::Public: Printer << tok::kw_public; break; case AccessLevel::Open: Printer.printKeyword("open"); break; } Printer << suffix << " "; } void printAccess(const ValueDecl *D) { if (!Options.PrintAccess || !D->hasAccess() || D->getAttrs().hasAttribute()) return; printAccess(D->getFormalAccess()); if (auto storageDecl = dyn_cast(D)) { if (auto setter = storageDecl->getSetter()) { AccessLevel setterAccess = setter->getFormalAccess(); if (setterAccess != D->getFormalAccess()) printAccess(setterAccess, "(set)"); } } } void printType(Type T) { if (Options.TransformContext) { // FIXME: it's not clear exactly what we want to keep from the existing // options, and what we want to discard. PrintOptions FreshOptions; FreshOptions.ExcludeAttrList = Options.ExcludeAttrList; FreshOptions.ExclusiveAttrList = Options.ExclusiveAttrList; T.print(Printer, FreshOptions); return; } T.print(Printer, Options); } void printTransformedType(Type T) { if (CurrentType) { if (T->hasArchetype()) { // Get the interface type, since TypeLocs still have // contextual types in them. T = T->mapTypeOutOfContext(); } auto *M = Current->getDeclContext()->getParentModule(); SubstitutionMap subMap; if (auto *NTD = dyn_cast(Current)) subMap = CurrentType->getContextSubstitutionMap(M, NTD); else if (auto *ED = dyn_cast(Current)) subMap = CurrentType->getContextSubstitutionMap(M, ED); else { subMap = CurrentType->getMemberSubstitutionMap( M, cast(Current)); } T = T.subst(subMap, SubstFlags::DesugarMemberTypes | SubstFlags::UseErrorType); } printType(T); } void printTypeLoc(const TypeLoc &TL) { if (CurrentType && TL.getType()) { printTransformedType(TL.getType()); return; } // Print a TypeRepr if instructed to do so by options, or if the type // is null. if (willUseTypeReprPrinting(TL, CurrentType, Options)) { if (auto repr = TL.getTypeRepr()) { llvm::SaveAndRestore SPTA(Options.SkipParameterTypeAttributes, true); repr->print(Printer, Options); } return; } TL.getType().print(Printer, Options); } void printContextIfNeeded(const Decl *decl) { if (IndentLevel > 0) return; switch (Options.ShouldQualifyNestedDeclarations) { case PrintOptions::QualifyNestedDeclarations::Never: return; case PrintOptions::QualifyNestedDeclarations::TypesOnly: if (!isa(decl)) return; break; case PrintOptions::QualifyNestedDeclarations::Always: break; } auto *container = dyn_cast(decl->getDeclContext()); if (!container) return; printType(container->getDeclaredInterfaceType()); Printer << "."; } void printAttributes(const Decl *D); void printTypedPattern(const TypedPattern *TP); public: void printPattern(const Pattern *pattern); enum GenericSignatureFlags { PrintParams = 1, PrintRequirements = 2, InnermostOnly = 4, SkipSelfRequirement = 8, SwapSelfAndDependentMemberType = 16, PrintInherited = 32, }; void printInheritedFromRequirementSignature(ProtocolDecl *proto, Decl *attachingTo); void printWhereClauseFromRequirementSignature(ProtocolDecl *proto, Decl *attachingTo); void printTrailingWhereClause(TrailingWhereClause *whereClause); void printGenericSignature(const GenericSignature *genericSig, unsigned flags); void printGenericSignature(const GenericSignature *genericSig, unsigned flags, llvm::function_ref filter); void printSingleDepthOfGenericSignature( ArrayRef genericParams, ArrayRef requirements, unsigned flags, llvm::function_ref filter); void printRequirement(const Requirement &req); 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, bool openBracket = true, bool closeBracket = true); void printMembers(ArrayRef members, bool needComma = false, bool openBracket = true, bool closeBracket = true); void printNominalDeclGenericParams(NominalTypeDecl *decl); void printNominalDeclGenericRequirements(NominalTypeDecl *decl); void printInherited(const Decl *decl, ArrayRef inherited); void printInherited(const NominalTypeDecl *D); void printInherited(const ExtensionDecl *D); void printInherited(const GenericTypeParamDecl *D); void printInherited(const AssociatedTypeDecl *D); void printEnumElement(EnumElementDecl *elt); /// \returns true if anything was printed. bool printASTNodes(const ArrayRef &Elements, bool NeedIndent = true); void printOneParameter(const ParamDecl *param, ParameterTypeFlags paramFlags, bool Curried, bool ArgNameIsAPIByDefault); void printParameterList(ParameterList *PL, Type paramListTy, 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) { if (Options.TransformContext) CurrentType = Options.TransformContext->getBaseType(); } using ASTVisitor::visit; bool visit(Decl *D) { if (!shouldPrint(D, true)) return false; Decl *Old = Current; Current = D; SWIFT_DEFER { Current = Old; }; Type OldType = CurrentType; if (CurrentType && (Old != nullptr || Options.PrintAsMember)) { if (auto *NTD = dyn_cast(D)) { auto Subs = CurrentType->getContextSubstitutionMap( Options.CurrentModule, NTD->getDeclContext()); CurrentType = NTD->getDeclaredInterfaceType().subst(Subs); } } SWIFT_DEFER { CurrentType = OldType; }; bool Synthesize = Options.TransformContext && Options.TransformContext->isPrintingSynthesizedExtension() && isa(D); 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, Options.BracketOptions); ASTVisitor::visit(D); if (Synthesize) { Printer.setSynthesizedTarget(nullptr); Printer.printSynthesizedExtensionPost( cast(D), Options.TransformContext->getNominal(), Options.BracketOptions); } else { Printer.callPrintDeclPost(D, Options.BracketOptions); } 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, D); 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::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()); } } /// If we can't find the depth of a type, return ErrorDepth. static const unsigned ErrorDepth = ~0U; /// A helper function to return the depth of a type. static unsigned getDepthOfType(Type ty) { unsigned depth = ErrorDepth; auto combineDepth = [&depth](unsigned newDepth) -> bool { // If there is no current depth (depth == ErrorDepth), then assign to // newDepth; otherwise, choose the deeper of the current and new depth. // Since ErrorDepth == ~0U, ErrorDepth + 1 == 0, which is smaller than any // valid depth + 1. depth = std::max(depth+1U, newDepth+1U) - 1U; return false; }; ty.findIf([combineDepth](Type t) -> bool { if (auto paramTy = t->getAs()) return combineDepth(paramTy->getDepth()); if (auto depMemTy = dyn_cast(t->getCanonicalType())) { CanType rootTy; do { rootTy = depMemTy.getBase(); } while ((depMemTy = dyn_cast(rootTy))); if (auto rootParamTy = dyn_cast(rootTy)) return combineDepth(rootParamTy->getDepth()); } return false; }); return depth; } namespace { struct RequirementPrintLocation { /// The Decl where the requirement should be attached (whether inherited or in /// a where clause) Decl *AttachedTo; /// Whether the requirement needs to be in a where clause. bool InWhereClause; }; } // end anonymous namespace /// Heuristically work out a good place for \c req to be printed inside \c /// proto. /// /// This depends only on the protocol so that we make the same decisions for all /// requirements in all associated types, guaranteeing that all of them will be /// printed somewhere. That is, taking an AssociatedTypeDecl as an argument and /// asking "should this requirement be printed on this ATD?" seems more likely /// to result in inconsistencies in what is printed where, versus what this /// function does: asking "where should this requirement be printed?" and then /// callers check if the location is the ATD. static RequirementPrintLocation bestRequirementPrintLocation(ProtocolDecl *proto, const Requirement &req) { auto protoSelf = proto->getProtocolSelfType(); // Returns the most relevant decl within proto connected to outerType (or null // if one doesn't exist), and whether the type is an "direct use", // i.e. outerType itself is Self or Self.T, but not, say, Self.T.U, or // Array. (The first's decl will be proto, while the other three will // be Self.T.) auto findRelevantDeclAndDirectUse = [&](Type outerType) { TypeDecl *relevantDecl = nullptr; Type foundType; (void)outerType.findIf([&](Type t) { if (t->isEqual(protoSelf)) { relevantDecl = proto; foundType = t; return true; } else if (auto DMT = t->getAs()) { auto assocType = DMT->getAssocType(); if (assocType && assocType->getProtocol() == proto) { relevantDecl = assocType; foundType = t; return true; } } // not here, so let's keep looking. return false; }); // If we didn't find anything, relevantDecl and foundType will be null, as // desired. auto directUse = foundType && outerType->isEqual(foundType); return std::make_pair(relevantDecl, directUse); }; Decl *bestDecl; bool inWhereClause; switch (req.getKind()) { case RequirementKind::Conformance: case RequirementKind::Superclass: case RequirementKind::Layout: { auto subject = req.getFirstType(); auto result = findRelevantDeclAndDirectUse(subject); bestDecl = result.first; inWhereClause = !bestDecl || !result.second; break; } case RequirementKind::SameType: { auto lhs = req.getFirstType(); auto rhs = req.getSecondType(); auto lhsResult = findRelevantDeclAndDirectUse(lhs); auto rhsResult = findRelevantDeclAndDirectUse(rhs); // Default to using the left type's decl. bestDecl = lhsResult.first; // But maybe the right type's one is "obviously" better! // e.g. Int == Self.T auto lhsDoesntExist = !lhsResult.first; // e.g. Self.T.U == Self.V should go on V (first two conditions), but // Self.T.U == Self should go on T (third condition). auto rhsBetterDirect = !lhsResult.second && rhsResult.second && rhsResult.first != proto; auto rhsOfSelfToAssoc = lhsResult.first == proto && rhsResult.first; // e.g. Self == Self.T.U if (lhsDoesntExist || rhsBetterDirect || rhsOfSelfToAssoc) bestDecl = rhsResult.first; // Same-type requirements can only occur in where clauses inWhereClause = true; break; } } // Didn't find anything that we think is relevant, so let's default to a where // clause on the protocol. if (!bestDecl) { bestDecl = proto; inWhereClause = true; } return {/*AttachedTo=*/bestDecl, inWhereClause}; } void PrintAST::printInheritedFromRequirementSignature(ProtocolDecl *proto, Decl *attachingTo) { assert(proto->isRequirementSignatureComputed()); printGenericSignature( GenericSignature::get({proto->getProtocolSelfType()} , proto->getRequirementSignature()), PrintInherited, [&](const Requirement &req) { auto location = bestRequirementPrintLocation(proto, req); return location.AttachedTo == attachingTo && !location.InWhereClause; }); } void PrintAST::printWhereClauseFromRequirementSignature(ProtocolDecl *proto, Decl *attachingTo) { assert(proto->isRequirementSignatureComputed()); unsigned flags = PrintRequirements; if (isa(attachingTo)) flags |= SwapSelfAndDependentMemberType; printGenericSignature( GenericSignature::get({proto->getProtocolSelfType()} , proto->getRequirementSignature()), flags, [&](const Requirement &req) { auto location = bestRequirementPrintLocation(proto, req); return location.AttachedTo == attachingTo && location.InWhereClause; }); } void PrintAST::printTrailingWhereClause(TrailingWhereClause *whereClause) { Printer << " " << tok::kw_where << " "; interleave( whereClause->getRequirements(), [&](const RequirementRepr &req) { Printer.callPrintStructurePre(PrintStructureKind::GenericRequirement); req.print(Printer); Printer.printStructurePost(PrintStructureKind::GenericRequirement); }, [&] { Printer << ", "; }); } /// A helper function to return the depth of a requirement. static unsigned getDepthOfRequirement(const Requirement &req) { switch (req.getKind()) { case RequirementKind::Conformance: case RequirementKind::Layout: return getDepthOfType(req.getFirstType()); case RequirementKind::Superclass: 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"); } static void getRequirementsAtDepth(const GenericSignature *genericSig, unsigned depth, SmallVectorImpl &result) { for (auto reqt : genericSig->getRequirements()) { unsigned currentDepth = getDepthOfRequirement(reqt); assert(currentDepth != ErrorDepth); if (currentDepth == depth) result.push_back(reqt); } } void PrintAST::printGenericSignature(const GenericSignature *genericSig, unsigned flags) { printGenericSignature(genericSig, flags, // print everything [&](const Requirement &) { return true; }); } void PrintAST::printGenericSignature( const GenericSignature *genericSig, unsigned flags, llvm::function_ref filter) { if (flags & InnermostOnly) { auto genericParams = genericSig->getInnermostGenericParams(); unsigned depth = genericParams[0]->getDepth(); SmallVector requirementsAtDepth; getRequirementsAtDepth(genericSig, depth, requirementsAtDepth); printSingleDepthOfGenericSignature(genericParams, requirementsAtDepth, flags, filter); return; } auto genericParams = genericSig->getGenericParams(); auto requirements = genericSig->getRequirements(); if (!Options.PrintInSILBody) { printSingleDepthOfGenericSignature(genericParams, requirements, flags, filter); 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. SmallVector requirementsAtDepth; getRequirementsAtDepth(genericSig, depth, requirementsAtDepth); printSingleDepthOfGenericSignature( genericParams.slice(paramIdx, lastParamIdx - paramIdx), requirementsAtDepth, flags, filter); paramIdx = lastParamIdx; } } void PrintAST::printSingleDepthOfGenericSignature( ArrayRef genericParams, ArrayRef requirements, unsigned flags, llvm::function_ref filter) { bool printParams = (flags & PrintParams); bool printRequirements = (flags & PrintRequirements); bool printInherited = (flags & PrintInherited); bool swapSelfAndDependentMemberType = (flags & SwapSelfAndDependentMemberType); SubstitutionMap subMap; if (CurrentType) { if (!CurrentType->isExistentialType()) { auto *DC = Current->getInnermostDeclContext()->getInnermostTypeContext(); auto *M = DC->getParentModule(); subMap = CurrentType->getContextSubstitutionMap(M, DC); } } auto substParam = [&](Type param) -> Type { return param.subst(subMap); }; if (printParams) { // Print the generic parameters. Printer << "<"; interleave(genericParams, [&](GenericTypeParamType *param) { if (!subMap.empty()) { if (auto argTy = substParam(param)) printType(argTy); else printType(param); } else if (auto *GP = param->getDecl()) { Printer.callPrintStructurePre( PrintStructureKind::GenericParameter, GP); Printer.printName(GP->getName(), PrintNameContext::GenericParameter); Printer.printStructurePost( PrintStructureKind::GenericParameter, GP); } else { printType(param); } }, [&] { Printer << ", "; }); } if (printRequirements || printInherited) { bool isFirstReq = true; for (const auto &req : requirements) { if (!filter(req)) continue; auto first = req.getFirstType(); Type second; if (req.getKind() != RequirementKind::Layout) second = req.getSecondType(); if ((flags & SkipSelfRequirement) && req.getKind() == RequirementKind::Conformance) { auto proto = cast(second->getAnyNominal()); if (first->isEqual(proto->getSelfInterfaceType())) continue; } if (!subMap.empty()) { if (Type subFirst = substParam(first)) first = subFirst; if (second) { if (Type subSecond = substParam(second)) second = subSecond; if (!(first->is() || first->isTypeParameter()) && !(second->is() || second->isTypeParameter())) continue; } } if (isFirstReq) { if (printRequirements) Printer << " " << tok::kw_where << " "; else Printer << " : "; isFirstReq = false; } else { Printer << ", "; } // Swap the order of Self == Self.A requirements if requested. if (swapSelfAndDependentMemberType && req.getKind() == RequirementKind::SameType && first->is() && second->is()) std::swap(first, second); if (printInherited) { // We only print the second part of a requirement in the "inherited" // clause. switch (req.getKind()) { case RequirementKind::Layout: req.getLayoutConstraint()->print(Printer, Options); break; case RequirementKind::Conformance: case RequirementKind::Superclass: printType(second); break; case RequirementKind::SameType: llvm_unreachable("same-type constraints belong in the where clause"); break; } } else { Printer.callPrintStructurePre(PrintStructureKind::GenericRequirement); if (second) { Requirement substReq(req.getKind(), first, second); printRequirement(substReq); } else { Requirement substReq(req.getKind(), first, req.getLayoutConstraint()); printRequirement(substReq); } Printer.printStructurePost(PrintStructureKind::GenericRequirement); } } } if (printParams) Printer << ">"; } void PrintAST::printRequirement(const Requirement &req) { printType(req.getFirstType()); switch (req.getKind()) { case RequirementKind::Layout: Printer << " : "; req.getLayoutConstraint()->print(Printer, Options); return; case RequirementKind::Conformance: case RequirementKind::Superclass: Printer << " : "; break; case RequirementKind::SameType: Printer << " == "; break; } printType(req.getSecondType()); } bool PrintAST::shouldPrintPattern(const Pattern *P) { return Options.shouldPrint(P); } void PrintAST::printPatternType(const Pattern *P) { if (P->hasType()) { Printer << ": "; printType(P->getType()); } } bool ShouldPrintChecker::shouldPrint(const Pattern *P, PrintOptions &Options) { bool ShouldPrint = false; P->forEachVariable([&](const VarDecl *VD) { ShouldPrint |= shouldPrint(VD, Options); }); return ShouldPrint; } bool ShouldPrintChecker::shouldPrint(const Decl *D, PrintOptions &Options) { if (auto *ED= dyn_cast(D)) { if (Options.printExtensionContentAsMembers(ED)) return false; } if (Options.SkipMissingMemberPlaceholders && isa(D)) 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.AccessFilter > AccessLevel::Private && VD->hasAccess() && VD->getFormalAccess() < Options.AccessFilter) return false; } if (Options.SkipPrivateStdlibDecls && D->isPrivateStdlibDecl(!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; if (auto clangDecl = VD->getClangDecl()) { // If the Clang declaration is from a protocol but was mirrored into // class or extension thereof, treat it as an override. if (isa(clangDecl->getDeclContext()) && VD->getDeclContext()->getAsClassOrClassExtensionContext()) return false; // Check whether Clang considers it an override. if (auto objcMethod = dyn_cast(clangDecl)) { SmallVector overriddenMethods; objcMethod->getOverriddenMethods(overriddenMethods); if (!overriddenMethods.empty()) return false; } else if (auto objcProperty = dyn_cast(clangDecl)) { if (auto getter = objcProperty->getGetterMethodDecl()) { SmallVector overriddenMethods; getter->getOverriddenMethods(overriddenMethods); if (!overriddenMethods.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 |= shouldPrint(entry.getPattern(), Options); if (ShouldPrint) return true; } return false; } return true; } bool PrintAST::shouldPrint(const Decl *D, bool Notify) { auto Result = Options.shouldPrint(D); 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 (!Options.FunctionBody && (inProtocol || (Options.AbstractAccessors && !Options.FunctionDefinitions))) { bool mutatingGetter = ASD->getGetter() && ASD->isGetterMutating(); bool settable = ASD->isSettable(nullptr); bool nonmutatingSetter = false; if (settable && !ASD->isSetterMutating() && ASD->isInstanceMember() && !ASD->getDeclContext()->getDeclaredInterfaceType() ->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 || Options.FunctionBody; 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: if (ASD->getGetter() && !ASD->getSetter() && PrintAccessorBody && !Options.FunctionDefinitions) { // Omit the 'get' keyword. Directly print getter if (auto BodyFunc = Options.FunctionBody) { Printer.printNewline(); IndentRAII IndentBody(*this); indent(); Printer << BodyFunc(ASD->getGetter()); } } else { 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, bool openBracket, bool closeBracket) { 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()); } if (Options.PrintExtensionFromConformingProtocols) { for (auto Conf : NTD->getAllConformances()) { for (auto Ext : Conf->getProtocol()->getExtensions()) { if (Options.printExtensionContentAsMembers(Ext)) AddDeclFunc(Ext->getMembers()); } } } } printMembers(Members, needComma, openBracket, closeBracket); } void PrintAST::printMembers(ArrayRef members, bool needComma, bool openBracket, bool closeBracket) { if (openBracket) { 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(); if (closeBracket) Printer << "}"; } void PrintAST::printNominalDeclGenericParams(NominalTypeDecl *decl) { if (decl->getGenericParams()) if (auto GenericSig = decl->getGenericSignature()) printGenericSignature(GenericSig, PrintParams | InnermostOnly); } void PrintAST::printNominalDeclGenericRequirements(NominalTypeDecl *decl) { if (decl->getGenericParams()) if (auto GenericSig = decl->getGenericSignature()) printGenericSignature(GenericSig, PrintRequirements | InnermostOnly); } void PrintAST::printInherited(const Decl *decl, ArrayRef inherited) { SmallVector TypesToPrint; for (auto TL : inherited) { if (auto Ty = TL.getType()) { if (auto NTD = Ty->getAnyNominal()) if (!shouldPrint(NTD)) continue; } TypesToPrint.push_back(TL); } auto &ctx = decl->getASTContext(); for (auto attr : decl->getAttrs().getAttributes()) { if (auto *proto = ctx.getProtocol(attr->getProtocolKind())) { if (!shouldPrint(proto)) continue; if (attr->getProtocolKind() == KnownProtocolKind::RawRepresentable && isa(decl) && cast(decl)->hasRawType()) continue; TypesToPrint.push_back(TypeLoc::withoutLoc(proto->getDeclaredType())); } } if (TypesToPrint.empty()) return; Printer << " : "; interleave(TypesToPrint, [&](TypeLoc TL) { printTypeLoc(TL); }, [&]() { Printer << ", "; }); } void PrintAST::printInherited(const NominalTypeDecl *D) { printInherited(D, D->getInherited()); } void PrintAST::printInherited(const ExtensionDecl *D) { printInherited(D, D->getInherited()); } void PrintAST::printInherited(const GenericTypeParamDecl *D) { printInherited(D, D->getInherited()); } void PrintAST::printInherited(const AssociatedTypeDecl *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 (isa(ExtendedType.getPointer())) { ExtendedType.print(Printer, Options); return; } Printer.printTypeRef(ExtendedType, Nominal, Nominal->getName()); } void PrintAST:: printSynthesizedExtension(NominalTypeDecl* Decl, ExtensionDecl *ExtDecl) { if (Options.BracketOptions.shouldOpenExtension(ExtDecl)) { printDocumentationComment(ExtDecl); printAttributes(ExtDecl); Printer << tok::kw_extension << " "; printExtendedTypeName(Decl->getDeclaredType(), Printer, Options); printInherited(ExtDecl); if (ExtDecl->getGenericParams()) if (auto *GenericSig = ExtDecl->getGenericSignature()) printGenericSignature(GenericSig, PrintRequirements | InnermostOnly); } if (Options.TypeDefinitions) { printMembersOfDecl(ExtDecl, false, Options.BracketOptions.shouldOpenExtension(ExtDecl), Options.BracketOptions.shouldCloseExtension(ExtDecl)); } } void PrintAST::printExtension(ExtensionDecl *decl) { if (Options.BracketOptions.shouldOpenExtension(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 (decl->getGenericParams()) if (auto *genericSig = decl->getGenericSignature()) { // For protocol extensions, don't print the 'Self : ...' requirement. unsigned flags = PrintRequirements | InnermostOnly; if (decl->getAsProtocolExtensionContext()) flags |= SkipSelfRequirement; printGenericSignature(genericSig, flags); } } if (Options.TypeDefinitions) { printMembersOfDecl(decl, false, Options.BracketOptions.shouldOpenExtension(decl), Options.BracketOptions.shouldCloseExtension(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); // 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); printAccess(anyVar); } if (decl->isStatic()) printStaticKeyword(decl->getCorrectStaticSpelling()); if (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) { if (!Options.PrintIfConfig) return; for (auto &Clause : ICD->getClauses()) { if (&Clause == &*ICD->getClauses().begin()) Printer << tok::pound_if << " /* condition */"; // FIXME: print condition else if (Clause.Cond) Printer << tok::pound_elseif << " /* condition */"; // FIXME: print condition else Printer << tok::pound_else; printASTNodes(Clause.Elements); Printer.printNewline(); indent(); } Printer << tok::pound_endif; } void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccess(decl); if (!Options.SkipIntroducerKeywords) Printer << tok::kw_typealias << " "; printContextIfNeeded(decl); recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }, [&]{ // Signature if (decl->getGenericParams()) if (auto *genericSig = decl->getGenericSignature()) printGenericSignature(genericSig, PrintParams | InnermostOnly); }); bool ShouldPrint = true; Type Ty = decl->getUnderlyingTypeLoc().getType(); // 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); } void PrintAST::visitAssociatedTypeDecl(AssociatedTypeDecl *decl) { printDocumentationComment(decl); printAttributes(decl); if (!Options.SkipIntroducerKeywords) Printer << tok::kw_associatedtype << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }); auto proto = decl->getProtocol(); if (proto->isRequirementSignatureComputed()) { printInheritedFromRequirementSignature(proto, decl); } else { printInherited(decl); } if (!decl->getDefaultDefinitionLoc().isNull()) { Printer << " = "; decl->getDefaultDefinitionLoc().getType().print(Printer, Options); } // As with protocol's trailing where clauses, use the requirement signature // when available. if (proto->isRequirementSignatureComputed()) { printWhereClauseFromRequirementSignature(proto, decl); } else { if (auto trailingWhere = decl->getTrailingWhereClause()) { printTrailingWhereClause(trailingWhere); } } } void PrintAST::visitEnumDecl(EnumDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccess(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 << " "; printContextIfNeeded(decl); recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }, [&]{ // Signature printNominalDeclGenericParams(decl); }); printInherited(decl); printNominalDeclGenericRequirements(decl); } if (Options.TypeDefinitions) { printMembersOfDecl(decl, false, true, Options.BracketOptions.shouldCloseNominal(decl)); } } void PrintAST::visitStructDecl(StructDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccess(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 << " "; printContextIfNeeded(decl); recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }, [&]{ // Signature printNominalDeclGenericParams(decl); }); printInherited(decl); printNominalDeclGenericRequirements(decl); } if (Options.TypeDefinitions) { printMembersOfDecl(decl, false, true, Options.BracketOptions.shouldCloseNominal(decl)); } } void PrintAST::visitClassDecl(ClassDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccess(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 << " "; printContextIfNeeded(decl); recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }, [&]{ // Signature printNominalDeclGenericParams(decl); }); printInherited(decl); printNominalDeclGenericRequirements(decl); } if (Options.TypeDefinitions) { printMembersOfDecl(decl, false, true, Options.BracketOptions.shouldCloseNominal(decl)); } } void PrintAST::visitProtocolDecl(ProtocolDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccess(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 << " "; printContextIfNeeded(decl); recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }); if (decl->isRequirementSignatureComputed()) { printInheritedFromRequirementSignature(decl, decl); } else { printInherited(decl); } // The trailing where clause is a syntactic thing, which isn't serialized // (etc.) and thus isn't available for printing things out of // already-compiled SIL modules. The requirement signature is available in // such cases, so let's go with that when we can. if (decl->isRequirementSignatureComputed()) { printWhereClauseFromRequirementSignature(decl, decl); } else { if (auto trailingWhere = decl->getTrailingWhereClause()) { printTrailingWhereClause(trailingWhere); } } } if (Options.TypeDefinitions) { printMembersOfDecl(decl, false, true, Options.BracketOptions.shouldCloseNominal(decl)); } } static bool isStructOrClassContext(DeclContext *dc) { auto *nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext(); if (nominal == nullptr) return false; return isa(nominal) || isa(nominal); } static void printParameterFlags(ASTPrinter &printer, PrintOptions options, ParameterTypeFlags flags) { if (!options.excludeAttrKind(TAK_autoclosure) && flags.isAutoClosure()) printer << "@autoclosure "; if (!options.excludeAttrKind(TAK_escaping) && flags.isEscaping()) printer << "@escaping "; if (flags.isShared()) printer << "__shared "; } 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); printAccess(decl); if (!Options.SkipIntroducerKeywords) { if (decl->isStatic()) printStaticKeyword(decl->getCorrectStaticSpelling()); if (decl->getKind() == DeclKind::Var || Options.PrintParameterSpecifiers) { // Map all non-let specifiers to 'var'. This is not correct, but // SourceKit relies on this for info about parameter decls. switch (decl->getSpecifier()) { case VarDecl::Specifier::Owned: Printer << tok::kw_let; break; case VarDecl::Specifier::Var: case VarDecl::Specifier::InOut: case VarDecl::Specifier::Shared: Printer << tok::kw_var; break; } Printer << " "; } } printContextIfNeeded(decl); recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }); if (decl->hasInterfaceType()) { Printer << ": "; auto tyLoc = decl->getTypeLoc(); if (!tyLoc.getTypeRepr()) tyLoc = TypeLoc::withoutLoc(decl->getInterfaceType()); printTypeLoc(tyLoc); } printAccessors(decl); } void PrintAST::visitParamDecl(ParamDecl *decl) { visitVarDecl(decl); } void PrintAST::printOneParameter(const ParamDecl *param, ParameterTypeFlags paramFlags, bool Curried, bool ArgNameIsAPIByDefault) { Printer.callPrintStructurePre(PrintStructureKind::FunctionParameter, param); SWIFT_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; } LLVM_FALLTHROUGH; case PrintOptions::ArgAndParamPrintingMode::BothAlways: Printer.printName(ArgName, PrintNameContext::FunctionParameterExternal); Printer << " "; Printer.printName(BodyName, PrintNameContext::FunctionParameterLocal); break; } Printer << ": "; }; auto TheTypeLoc = param->getTypeLoc(); printArgName(); if (!TheTypeLoc.getTypeRepr() && param->hasInterfaceType()) TheTypeLoc = TypeLoc::withoutLoc(param->getInterfaceType()); // 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]); } // FIXME: don't do if will be using type repr printing printParameterFlags(Printer, Options, paramFlags); // Special case, if we're not going to use the type repr printing, peek // through the paren types so that we don't print excessive @escapings. unsigned numParens = 0; if (!willUseTypeReprPrinting(TheTypeLoc, CurrentType, Options)) { while (auto parenTy = dyn_cast(TheTypeLoc.getType().getPointer())) { ++numParens; TheTypeLoc = TypeLoc::withoutLoc(parenTy->getUnderlyingType()); } } for (unsigned i = 0; i < numParens; ++i) Printer << "("; printTypeLoc(TheTypeLoc); for (unsigned i = 0; i < numParens; ++i) Printer << ")"; if (param->isVariadic()) Printer << "..."; if (param->isDefaultArgument()) { auto defaultArgStr = getDefaultArgumentSpelling(param->getDefaultArgumentKind()); if (defaultArgStr.empty()) { if (Options.PrintDefaultParameterPlaceholder) Printer << " = " << tok::kw_default; } else { Printer << " = "; switch (param->getDefaultArgumentKind()) { case DefaultArgumentKind::File: case DefaultArgumentKind::Line: case DefaultArgumentKind::Column: case DefaultArgumentKind::Function: case DefaultArgumentKind::DSOHandle: Printer.printKeyword(defaultArgStr); break; default: Printer << defaultArgStr; break; } } } } void PrintAST::printParameterList(ParameterList *PL, Type paramListTy, bool isCurried, std::function isAPINameByDefault) { SmallVector paramFlags; if (paramListTy && !paramListTy->hasError()) { if (auto parenTy = dyn_cast(paramListTy.getPointer())) { paramFlags.push_back(parenTy->getParameterFlags()); } else if (auto tupleTy = paramListTy->getAs()) { for (auto elt : tupleTy->getElements()) paramFlags.push_back(elt.getParameterFlags()); } else { paramFlags.push_back({}); } } else { // Malformed AST, just use default flags paramFlags.resize(PL->size()); } Printer << "("; for (unsigned i = 0, e = PL->size(); i != e; ++i) { if (i > 0) Printer << ", "; printOneParameter(PL->get(i), paramFlags[i], isCurried, isAPINameByDefault()); } Printer << ")"; } void PrintAST::printFunctionParameters(AbstractFunctionDecl *AFD) { auto BodyParams = AFD->getParameterLists(); auto curTy = AFD->hasInterfaceType() ? AFD->getInterfaceType() : nullptr; // Skip over the implicit 'self'. if (AFD->getImplicitSelfDecl()) { BodyParams = BodyParams.slice(1); if (curTy) if (auto funTy = curTy->getAs()) curTy = funTy->getResult(); } SmallVector parameterListTypes; for (unsigned i = 0; i < BodyParams.size(); ++i) { if (curTy) { if (auto funTy = curTy->getAs()) { parameterListTypes.push_back(funTy->getInput()); if (i < BodyParams.size() - 1) curTy = funTy->getResult(); } else { parameterListTypes.push_back(curTy); } } } for (unsigned CurrPattern = 0, NumPatterns = BodyParams.size(); CurrPattern != NumPatterns; ++CurrPattern) { // Be extra careful in the event of printing mal-formed ASTs auto paramListType = CurrPattern < parameterListTypes.size() ? parameterListTypes[CurrPattern] : nullptr; printParameterList(BodyParams[CurrPattern], paramListType, /*isCurried=*/CurrPattern > 0, [&]()->bool { return CurrPattern > 0 || AFD->argumentNameIsAPIByDefault(); }); } if (AFD->hasThrows()) { 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, [&]{ Printer << (kind == AccessorKind::IsGetter ? "get" : getAddressorLabel(decl)); }); Printer << " {"; break; case AccessorKind::IsDidSet: case AccessorKind::IsMaterializeForSet: case AccessorKind::IsMutableAddressor: recordDeclLoc(decl, [&]{ Printer << (kind == AccessorKind::IsDidSet ? "didSet" : kind == AccessorKind::IsMaterializeForSet ? "materializeForSet" : getMutableAddressorLabel(decl)); }); Printer << " {"; break; case AccessorKind::IsSetter: case AccessorKind::IsWillSet: recordDeclLoc(decl, [&]{ 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 (auto BodyFunc = Options.FunctionBody) { { IndentRAII IndentBody(*this); indent(); Printer.printNewline(); Printer << BodyFunc(decl); } indent(); Printer.printNewline(); } else if (Options.FunctionDefinitions && decl->getBody()) { if (printASTNodes(decl->getBody()->getElements())) { Printer.printNewline(); indent(); } } Printer << "}"; } else { printDocumentationComment(decl); printAttributes(decl); printAccess(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()) printStaticKeyword(decl->getCorrectStaticSpelling()); if (decl->isMutating() && !decl->getAttrs().hasAttribute()) { Printer.printKeyword("mutating"); Printer << " "; } else if (decl->isConsuming() && !decl->getAttrs().hasAttribute()) { Printer.printKeyword("__consuming"); Printer << " "; } Printer << tok::kw_func << " "; } printContextIfNeeded(decl); recordDeclLoc(decl, [&]{ // Name if (!decl->hasName()) { Printer << ""; } else { Printer.printName(decl->getName()); if (decl->isOperator()) Printer << " "; } }, [&] { // Parameters if (decl->isGeneric()) if (auto *genericSig = decl->getGenericSignature()) printGenericSignature(genericSig, PrintParams | InnermostOnly); printFunctionParameters(decl); }); Type ResultTy = decl->getResultInterfaceType(); if (ResultTy && !ResultTy->isVoid()) { TypeLoc ResultTyLoc = decl->getBodyResultTypeLoc(); if (!ResultTyLoc.getTypeRepr()) ResultTyLoc = TypeLoc::withoutLoc(ResultTy); // FIXME: Hacky way to workaround the fact that 'Self' as return // TypeRepr is not getting 'typechecked'. See // \c resolveTopLevelIdentTypeComponent function in TypeCheckType.cpp. if (auto *simId = dyn_cast_or_null(ResultTyLoc.getTypeRepr())) { if (simId->getIdentifier().str() == "Self") ResultTyLoc = TypeLoc::withoutLoc(ResultTy); } Printer << " -> "; Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); printTypeLoc(ResultTyLoc); Printer.printStructurePost(PrintStructureKind::FunctionReturnType); } if (decl->isGeneric()) if (auto *genericSig = decl->getGenericSignature()) printGenericSignature(genericSig, PrintRequirements | InnermostOnly); } if (auto BodyFunc = Options.FunctionBody) { Printer << " {"; Printer.printNewline(); { IndentRAII IndentBody(*this); indent(); Printer << BodyFunc(decl); } indent(); Printer.printNewline(); Printer << "}"; } else if (Options.FunctionDefinitions && decl->getBody()) { Printer << " "; visit(decl->getBody()); } } } void PrintAST::printEnumElement(EnumElementDecl *elt) { recordDeclLoc(elt, [&]{ Printer.printName(elt->getName()); }); if (auto argTy = elt->getArgumentInterfaceType()) { if (!Options.SkipPrivateStdlibDecls || !argTy.isPrivateStdlibType()) argTy.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); printAccess(decl); printContextIfNeeded(decl); recordDeclLoc(decl, [&]{ Printer << "subscript"; }, [&] { // Parameters if (decl->isGeneric()) if (auto *genericSig = decl->getGenericSignature()) printGenericSignature(genericSig, PrintParams | InnermostOnly); printParameterList(decl->getIndices(), decl->hasInterfaceType() ? decl->getIndicesInterfaceType() : nullptr, /*isCurried=*/false, /*isAPINameByDefault*/[]()->bool{return false;}); }); Printer << " -> "; Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); TypeLoc elementTy = decl->getElementTypeLoc(); if (!elementTy.getTypeRepr()) elementTy = TypeLoc::withoutLoc(decl->getElementInterfaceType()); printTypeLoc(elementTy); Printer.printStructurePost(PrintStructureKind::FunctionReturnType); if (decl->isGeneric()) if (auto *genericSig = decl->getGenericSignature()) printGenericSignature(genericSig, PrintRequirements | InnermostOnly); printAccessors(decl); } void PrintAST::visitConstructorDecl(ConstructorDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccess(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*/ "; } printContextIfNeeded(decl); 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()) if (auto *genericSig = decl->getGenericSignature()) printGenericSignature(genericSig, PrintParams | InnermostOnly); printFunctionParameters(decl); }); if (decl->isGeneric()) if (auto *genericSig = decl->getGenericSignature()) printGenericSignature(genericSig, PrintRequirements | InnermostOnly); if (auto BodyFunc = Options.FunctionBody) { Printer << " {"; { Printer.printNewline(); IndentRAII IndentBody(*this); indent(); Printer << BodyFunc(decl); } indent(); Printer.printNewline(); Printer << "}"; } else if (Options.FunctionDefinitions && decl->getBody()) { Printer << " "; visit(decl->getBody()); } } void PrintAST::visitDestructorDecl(DestructorDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printContextIfNeeded(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()); }); if (!decl->getPrecedenceGroupName().empty()) { Printer << " : " << decl->getPrecedenceGroupName(); } } void PrintAST::visitPrecedenceGroupDecl(PrecedenceGroupDecl *decl) { Printer << tok::kw_precedencegroup << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }); Printer << " {"; Printer.printNewline(); { IndentRAII indentMore(*this); if (!decl->isAssociativityImplicit() || !decl->isNonAssociative()) { 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->isAssignmentImplicit() || decl->isAssignment()) { indent(); Printer.printKeyword("assignment"); Printer << ": "; Printer.printKeyword(decl->isAssignment() ? "true" : "false"); Printer.printNewline(); } if (!decl->getHigherThan().empty()) { indent(); Printer.printKeyword("higherThan"); Printer << ": "; if (!decl->getHigherThan().empty()) { Printer << decl->getHigherThan()[0].Name; for (auto &rel : decl->getHigherThan().slice(1)) Printer << ", " << rel.Name; } Printer.printNewline(); } if (!decl->getLowerThan().empty()) { indent(); Printer.printKeyword("lowerThan"); Printer << ": "; if (!decl->getLowerThan().empty()) { Printer << decl->getLowerThan()[0].Name; for (auto &rel : decl->getLowerThan().slice(1)) Printer << ", " << rel.Name; } Printer.printNewline(); } } indent(); Printer << "}"; } void PrintAST::visitPrefixOperatorDecl(PrefixOperatorDecl *decl) { Printer.printKeyword("prefix"); Printer << " " << tok::kw_operator << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }); } void PrintAST::visitPostfixOperatorDecl(PostfixOperatorDecl *decl) { Printer.printKeyword("postfix"); Printer << " " << tok::kw_operator << " "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); }); } void PrintAST::visitModuleDecl(ModuleDecl *decl) { } void PrintAST::visitMissingMemberDecl(MissingMemberDecl *decl) { Printer << "/* placeholder for "; recordDeclLoc(decl, [&]{ Printer << decl->getFullName(); }); Printer << " */"; } 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::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::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 (auto N : stmt->getRawCases()) { if (N.is()) visit(cast(N.get())); else visit(cast(N.get())); } 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; // FIXME: Move all places where SIL printing is happening to explicit options. // For example, see \c ProjectionPath::print. options.PreferTypeRepr = false; 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; void printGenericArgs(ArrayRef Args) { if (Args.empty()) return; Printer << "<"; interleave(Args, [&](Type Arg) { visit(Arg); }, [&] { Printer << ", "; }); Printer << ">"; } static bool isSimple(Type type) { switch (type->getKind()) { case TypeKind::Function: 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(); } case TypeKind::ProtocolComposition: { // 'Any', 'AnyObject' and single protocol compositions are simple auto composition = type->getAs(); auto memberCount = composition->getMembers().size(); if (composition->hasExplicitAnyObject()) return memberCount == 0; return memberCount <= 1; } 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); } } template void printModuleContext(T *Ty) { ModuleDecl *Mod = Ty->getDecl()->getModuleContext(); Printer.printModuleRef(Mod, Mod->getName()); Printer << "."; } template void printTypeDeclName(T *Ty) { TypeDecl *TD = Ty->getDecl(); Printer.printTypeRef(Ty, 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(ModuleDecl *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; ModuleDecl *M = D->getDeclContext()->getParentModule(); if (Options.CurrentModule && M == Options.CurrentModule) { return false; } // 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)); SWIFT_DEFER { Printer.printTypePost(TypeLoc::withoutLoc(T)); }; super::visit(T); } void visitErrorType(ErrorType *T) { if (auto originalType = T->getOriginalType()) visit(originalType); else 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 visitSILTokenType(SILTokenType *T) { Printer << "Builtin.SILToken"; } void visitNameAliasType(NameAliasType *T) { if (Options.PrintForSIL || Options.PrintNameAliasUnderlyingType) { visit(T->getSinglyDesugaredType()); return; } auto ParentDC = T->getDecl()->getDeclContext(); auto ParentNominal = ParentDC ? ParentDC->getAsNominalTypeOrNominalTypeExtensionContext() : nullptr; if (ParentNominal) { visit(ParentNominal->getDeclaredType()); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); } void visitParenType(ParenType *T) { Printer << "("; printParameterFlags(Printer, Options, T->getParameterFlags()); visit(T->getUnderlyingType()); Printer << ")"; } void visitTupleType(TupleType *T) { Printer.callPrintStructurePre(PrintStructureKind::TupleType); SWIFT_DEFER { Printer.printStructurePost(PrintStructureKind::TupleType); }; 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); SWIFT_DEFER { Printer.printStructurePost(PrintStructureKind::TupleElement); }; if (TD.hasName()) { Printer.printName(TD.getName(), PrintNameContext::TupleElement); Printer << ": "; } if (TD.isVararg()) { visit(TD.getVarargBaseTy()); Printer << "..."; } else { printParameterFlags(Printer, Options, TD.getParameterFlags()); 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 visitParentType(Type T) { PrintOptions innerOptions = Options; innerOptions.SynthesizeSugarOnTypes = false; if (auto sugarType = dyn_cast(T.getPointer())) T = sugarType->getImplementationType(); else if (auto dictType = dyn_cast(T.getPointer())) T = dictType->getImplementationType(); TypePrinter(Printer, innerOptions).visit(T); } void visitEnumType(EnumType *T) { if (auto ParentType = T->getParent()) { visitParentType(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); } void visitStructType(StructType *T) { if (auto ParentType = T->getParent()) { visitParentType(ParentType); Printer << "."; } else if (shouldPrintFullyQualified(T)) { printModuleContext(T); } printTypeDeclName(T); } void visitClassType(ClassType *T) { if (auto ParentType = T->getParent()) { visitParentType(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) && 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) { if (Options.PrintInSILBody) { Printer << "@dynamic_self "; visit(T->getSelfType()); return; } // Try to print as a reference to the static type so that we will get a USR, // in cursor info. auto staticSelfT = T->getSelfType(); if (auto *NTD = staticSelfT->getAnyNominal()) { if (isa(NTD)) { auto Name = T->getASTContext().Id_Self; Printer.printTypeRef(T, NTD, Name); return; } } visit(staticSelfT); } void printFunctionExtInfo(AnyFunctionType::ExtInfo info) { if (Options.SkipAttributes) return; if (Options.PrintFunctionRepresentationAttrs && !Options.excludeAttrKind(TAK_convention) && info.getSILRepresentation() != SILFunctionType::Representation::Thick) { Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute); Printer.printAttrName("@convention"); Printer << "("; // TODO: coalesce into a single convention attribute. switch (info.getSILRepresentation()) { case SILFunctionType::Representation::Thick: llvm_unreachable("thick is not printed"); case SILFunctionType::Representation::Thin: Printer << "thin"; break; case SILFunctionType::Representation::Block: Printer << "block"; break; case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; break; case SILFunctionType::Representation::Method: Printer << "method"; break; case SILFunctionType::Representation::ObjCMethod: Printer << "objc_method"; break; case SILFunctionType::Representation::WitnessMethod: Printer << "witness_method"; break; case SILFunctionType::Representation::Closure: Printer << "closure"; break; } Printer << ")"; Printer.printStructurePost(PrintStructureKind::BuiltinAttribute); Printer << " "; } } void printFunctionExtInfo( SILFunctionType::ExtInfo info, Optional witnessMethodConformance) { if (Options.SkipAttributes) return; if (Options.PrintFunctionRepresentationAttrs && !Options.excludeAttrKind(TAK_convention) && info.getRepresentation() != SILFunctionType::Representation::Thick) { Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute); Printer.printAttrName("@convention"); Printer << "("; switch (info.getRepresentation()) { case SILFunctionType::Representation::Thick: llvm_unreachable("thick is not printed"); case SILFunctionType::Representation::Thin: Printer << "thin"; break; case SILFunctionType::Representation::Block: Printer << "block"; break; case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; break; case SILFunctionType::Representation::Method: Printer << "method"; break; case SILFunctionType::Representation::ObjCMethod: Printer << "objc_method"; break; case SILFunctionType::Representation::WitnessMethod: Printer << "witness_method: "; printTypeDeclName( witnessMethodConformance->getRequirement()->getDeclaredType()); break; case SILFunctionType::Representation::Closure: Printer << "closure"; break; } Printer << ")"; Printer.printStructurePost(PrintStructureKind::BuiltinAttribute); Printer << " "; } if (info.isPseudogeneric()) { Printer.printSimpleAttr("@pseudogeneric") << " "; } if (info.isNoEscape()) { Printer.printSimpleAttr("@noescape") << " "; } } void visitFunctionType(FunctionType *T) { Printer.callPrintStructurePre(PrintStructureKind::FunctionType); SWIFT_DEFER { Printer.printStructurePost(PrintStructureKind::FunctionType); }; printFunctionExtInfo(T->getExtInfo()); // If we're stripping argument labels from types, do it when printing. Type inputType = T->getInput(); if (auto tupleTy = dyn_cast(inputType.getPointer())) { SmallVector elements; elements.reserve(tupleTy->getNumElements()); for (const auto &elt : tupleTy->getElements()) elements.push_back(elt.getWithoutName()); inputType = TupleType::get(elements, inputType->getASTContext()); } bool needsParens = !isa(inputType.getPointer()) && !inputType->is(); if (needsParens) Printer << "("; visit(inputType); if (needsParens) Printer << ")"; if (T->throws()) Printer << " " << tok::kw_throws; Printer << " -> "; Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); T->getResult().print(Printer, Options); Printer.printStructurePost(PrintStructureKind::FunctionReturnType); } void printGenericSignature(const GenericSignature *genericSig, unsigned flags) { PrintAST(Printer, Options).printGenericSignature(genericSig, flags); } void visitGenericFunctionType(GenericFunctionType *T) { Printer.callPrintStructurePre(PrintStructureKind::FunctionType); SWIFT_DEFER { Printer.printStructurePost(PrintStructureKind::FunctionType); }; printFunctionExtInfo(T->getExtInfo()); printGenericSignature(T->getGenericSignature(), PrintAST::PrintParams | PrintAST::PrintRequirements); Printer << " "; bool needsParens = !isa(T->getInput().getPointer()) && !T->getInput()->is(); if (needsParens) Printer << "("; visit(T->getInput()); if (needsParens) Printer << ")"; if (T->throws()) Printer << " " << tok::kw_throws; Printer << " -> "; Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); T->getResult().print(Printer, Options); Printer.printStructurePost(PrintStructureKind::FunctionReturnType); } void printSILCoroutineKind(SILCoroutineKind kind) { switch (kind) { case SILCoroutineKind::None: return; case SILCoroutineKind::YieldOnce: Printer << "@yield_once "; return; case SILCoroutineKind::YieldMany: Printer << "@yield_many "; return; } llvm_unreachable("bad convention"); } 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::Indirect_In: case ParameterConvention::Indirect_In_Constant: 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) { printSILCoroutineKind(T->getCoroutineKind()); printFunctionExtInfo(T->getExtInfo(), T->getWitnessMethodConformanceOrNone()); printCalleeConvention(T->getCalleeConvention()); if (auto sig = T->getGenericSignature()) { printGenericSignature(sig, PrintAST::PrintParams | PrintAST::PrintRequirements); Printer << " "; } Printer << "("; bool first = true; for (auto param : T->getParameters()) { Printer.printSeparator(first, ", "); param.print(Printer, Options); } Printer << ") -> "; unsigned totalResults = T->getNumYields() + T->getNumResults() + unsigned(T->hasErrorResult()); if (totalResults != 1) Printer << "("; first = true; for (auto yield : T->getYields()) { Printer.printSeparator(first, ", "); Printer << "@yields "; yield.print(Printer, Options); } for (auto result : T->getResults()) { 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) { { // A box layout has its own independent generic environment. Don't try // to print it with the environment's generic params. PrintOptions subOptions = Options; subOptions.GenericEnv = nullptr; TypePrinter sub(Printer, subOptions); // Capture list used here to ensure we don't print anything using `this` // printer, but only the sub-Printer. [&sub, T]{ if (auto sig = T->getLayout()->getGenericSignature()) { sub.printGenericSignature(sig, PrintAST::PrintParams | PrintAST::PrintRequirements); sub.Printer << " "; } sub.Printer << "{"; interleave(T->getLayout()->getFields(), [&](const SILField &field) { sub.Printer << (field.isMutable() ? " var " : " let "); sub.visit(field.getLoweredType()); }, [&]{ sub.Printer << ","; }); sub.Printer << " }"; }(); } // The arguments to the layout, if any, do come from the outer environment. if (!T->getGenericArgs().empty()) { Printer << " <"; interleave(T->getGenericArgs(), [&](const Substitution &arg) { visit(arg.getReplacement()); }, [&]{ Printer << ", "; }); Printer << ">"; } } 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) { if (T->getMembers().empty()) { if (T->hasExplicitAnyObject()) Printer << "AnyObject"; else Printer << "Any"; } else { interleave(T->getMembers(), [&](Type Ty) { visit(Ty); }, [&] { Printer << " & "; }); if (T->hasExplicitAnyObject()) Printer << " & AnyObject"; } } 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 (Options.AlternativeTypeNames) { auto found = Options.AlternativeTypeNames->find(T->getCanonicalType()); if (found != Options.AlternativeTypeNames->end()) { Printer << found->second.str(); return; } } auto Name = T->getName(); if (Name.empty()) Printer << ""; else { PrintNameContext context = PrintNameContext::Normal; if (Name == T->getASTContext().Id_Self) context = PrintNameContext::GenericParameter; Printer.printName(Name, context); } } } void visitGenericTypeParamType(GenericTypeParamType *T) { if (T->getDecl() == nullptr) { // If we have an alternate name for this type, use it. if (Options.AlternativeTypeNames) { auto found = Options.AlternativeTypeNames->find(T->getCanonicalType()); if (found != Options.AlternativeTypeNames->end()) { Printer << found->second.str(); return; } } // When printing SIL types, use a generic environment to map them from // canonical types to sugared types. if (Options.GenericEnv) T = Options.GenericEnv->getSugaredType(T); } auto Name = T->getName(); if (Name.empty()) Printer << ""; else { if (T->getDecl() && T->getDecl()->getDeclContext()->getAsProtocolOrProtocolExtensionContext()) { Printer.printTypeRef(T, T->getDecl(), Name); return; } PrintNameContext context = PrintNameContext::Normal; if (Name == T->getASTContext().Id_Self) context = PrintNameContext::GenericParameter; Printer.printName(Name, context); } } void visitDependentMemberType(DependentMemberType *T) { visitParentType(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 LayoutConstraintInfo::print(raw_ostream &OS, const PrintOptions &PO) const { StreamPrinter Printer(OS); print(Printer, PO); } void LayoutConstraint::print(raw_ostream &OS, const PrintOptions &PO) const { assert(*this); getPointer()->print(OS, PO); } void LayoutConstraintInfo::print(ASTPrinter &Printer, const PrintOptions &PO) const { Printer << getName(); switch (getKind()) { case LayoutConstraintKind::UnknownLayout: case LayoutConstraintKind::RefCountedObject: case LayoutConstraintKind::NativeRefCountedObject: case LayoutConstraintKind::Class: case LayoutConstraintKind::NativeClass: case LayoutConstraintKind::Trivial: return; case LayoutConstraintKind::TrivialOfAtMostSize: case LayoutConstraintKind::TrivialOfExactSize: Printer << "("; Printer << SizeInBits; if (Alignment) Printer << ", " << Alignment; Printer << ")"; break; } } void GenericSignature::print(raw_ostream &OS) const { StreamPrinter Printer(OS); PrintAST(Printer, PrintOptions()) .printGenericSignature(this, PrintAST::PrintParams | PrintAST::PrintRequirements); } void GenericSignature::dump() const { print(llvm::errs()); llvm::errs() << '\n'; } void Requirement::dump() const { dump(llvm::errs()); llvm::errs() << '\n'; } void Requirement::dump(raw_ostream &out) const { switch (getKind()) { case RequirementKind::Conformance: out << "conforms_to: "; break; case RequirementKind::Layout: out << "layout: "; break; case RequirementKind::Superclass: out << "superclass: "; break; case RequirementKind::SameType: out << "same_type: "; break; } if (getFirstType()) out << getFirstType() << " "; if (getKind() != RequirementKind::Layout && getSecondType()) out << getSecondType(); else if (getLayoutConstraint()) out << getLayoutConstraint(); } void Requirement::print(raw_ostream &os, const PrintOptions &opts) const { StreamPrinter printer(os); PrintAST(printer, opts).printRequirement(*this); } void Requirement::print(ASTPrinter &printer, const PrintOptions &opts) const { PrintAST(printer, opts).printRequirement(*this); } 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_Constant: return "@in_constant "; 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 "; } 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::SetDowncast: return "set_downcast"; case CheckedCastKind::BridgingCoercion: return "bridging_coercion"; case CheckedCastKind::Swift3BridgingDowncast: return "bridging_downcast"; } 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); } std::string LayoutConstraint::getString(const PrintOptions &PO) const { std::string Result; llvm::raw_string_ostream OS(Result); print(OS, PO); return OS.str(); } std::string LayoutConstraintInfo::getString(const PrintOptions &PO) const { std::string Result; llvm::raw_string_ostream OS(Result); print(OS, PO); return OS.str(); } void ProtocolConformance::printName(llvm::raw_ostream &os, const PrintOptions &PO) const { if (getKind() == ProtocolConformanceKind::Normal) { if (auto genericSig = getGenericSignature()) { StreamPrinter sPrinter(os); TypePrinter typePrinter(sPrinter, PO); typePrinter .printGenericSignature(genericSig, PrintAST::PrintParams | PrintAST::PrintRequirements); 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); } void swift::printEnumElementsAsCases( llvm::DenseSet &UnhandledElements, llvm::raw_ostream &OS) { // Sort the missing elements to a vector because set does not guarantee // orders. SmallVector SortedElements; SortedElements.insert(SortedElements.begin(), UnhandledElements.begin(), UnhandledElements.end()); std::sort(SortedElements.begin(), SortedElements.end(), [](EnumElementDecl *LHS, EnumElementDecl *RHS) { return LHS->getNameStr().compare(RHS->getNameStr()) < 0; }); auto printPayloads = [](EnumElementDecl *EE, llvm::raw_ostream &OS) { // If the enum element has no payloads, return. auto TL = EE->getArgumentTypeLoc(); if (TL.isNull()) return; TypeRepr *TR = EE->getArgumentTypeLoc().getTypeRepr(); if (auto *TTR = dyn_cast(TR)) { SmallVector Names; if (TTR->hasElementNames()) { // Get the name from the tuple repr, if exist. TTR->getElementNames(Names); } else { // Create same amount of empty names to the elements. Names.assign(TTR->getNumElements(), Identifier()); } OS << "("; // Print each element in the pattern match. for (unsigned I = 0, N = Names.size(); I < N; I++) { auto Id = Names[I]; if (Id.empty()) OS << "_"; else OS << tok::kw_let << " " << Id.str(); if (I + 1 != N) { OS << ", "; } } OS << ")"; } }; // Print each enum element name. std::for_each(SortedElements.begin(), SortedElements.end(), [&](EnumElementDecl *EE) { OS << tok::kw_case << " ." << EE->getNameStr(); printPayloads(EE, OS); OS << ": " << getCodePlaceholder() << "\n"; }); }