Files
swift-mirror/lib/AST/ASTPrinter.cpp
Jordan Rose 5a8cbe4503 [AST] Never print access levels on protocol requirements
We might allow this at some point in the future, but for now we should
stick to the syntax that people write in source.

rdar://problem/26746605
2018-08-16 16:00:49 -07:00

4297 lines
128 KiB
C++

//===--- ASTPrinter.cpp - Swift Language AST Printer ----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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/QuotedString.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 <algorithm>
#include <queue>
using namespace swift;
void PrintOptions::setBaseType(Type T) {
TransformContext = TypeTransformContext(T);
}
void PrintOptions::initForSynthesizedExtension(TypeOrExtensionDecl D) {
TransformContext = TypeTransformContext(D);
}
void PrintOptions::clearSynthesizedExtension() {
TransformContext.reset();
}
PrintOptions PrintOptions::printTextualInterfaceFile() {
PrintOptions result;
result.PrintLongAttrsOnSeparateLines = true;
result.TypeDefinitions = true;
result.PrintIfConfig = false;
result.FullyQualifiedTypes = true;
result.SkipImports = true;
class UsableFromInlineOnly : public ShouldPrintChecker {
bool shouldPrint(const Decl *D, PrintOptions &options) override {
if (auto *VD = dyn_cast<ValueDecl>(D)) {
AccessScope accessScope =
VD->getFormalAccessScope(/*useDC*/nullptr,
/*treatUsableFromInlineAsPublic*/true);
if (!accessScope.isPublic())
return false;
}
return ShouldPrintChecker::shouldPrint(D, options);
}
};
result.CurrentPrintabilityChecker = std::make_shared<UsableFromInlineOnly>();
// FIXME: We don't really need 'public' on everything; we could just change
// the default to 'public' and mark the 'internal' things.
result.PrintAccess = true;
result.ExcludeAttrList.push_back(DAK_AccessControl);
// FIXME: We'll need the actual default parameter expression.
result.PrintDefaultParameterPlaceholder = false;
return result;
}
TypeTransformContext::TypeTransformContext(Type T)
: BaseType(T.getPointer()) {
assert(T->mayHaveMembers());
}
TypeTransformContext::TypeTransformContext(TypeOrExtensionDecl D)
: BaseType(nullptr), Decl(D) {
if (auto NTD = Decl.Decl.dyn_cast<NominalTypeDecl *>())
BaseType = NTD->getDeclaredTypeInContext().getPointer();
else
BaseType = Decl.Decl.get<ExtensionDecl *>()->getExtendedType().getPointer();
}
TypeOrExtensionDecl TypeTransformContext::getDecl() const { return Decl; }
DeclContext *TypeTransformContext::getDeclContext() const {
return Decl.getAsDecl()->getDeclContext();
}
Type TypeTransformContext::getBaseType() const {
return Type(BaseType);
}
bool TypeTransformContext::isPrintingSynthesizedExtension() const {
return !Decl.isNull();
}
std::string ASTPrinter::sanitizeUtf8(StringRef Text) {
llvm::SmallString<256> Builder;
Builder.reserve(Text.size());
const llvm::UTF8* Data = reinterpret_cast<const llvm::UTF8*>(Text.begin());
const llvm::UTF8* End = reinterpret_cast<const llvm::UTF8*>(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<ValueDecl*> 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<GenericTypeParamDecl>(RefTo)) {
Context = PrintNameContext::GenericParameter;
} else if (T && T->is<DynamicSelfType>()) {
assert(T->castTo<DynamicSelfType>()->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<BracketOptions> Bracket) {
forceNewlines();
if (SynthesizeTarget && isa<ExtensionDecl>(D))
printSynthesizedExtensionPre(cast<ExtensionDecl>(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<UUID::StringBufferSize> 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<bool>(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<PrintAST> {
ASTPrinter &Printer;
PrintOptions Options;
unsigned IndentLevel = 0;
Decl *Current = nullptr;
Type CurrentType;
friend DeclVisitor<PrintAST>;
/// \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<typename FnTy>
void recordDeclLoc(Decl *decl, const FnTy &NameFn,
llvm::function_ref<void()> 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<StringRef, 8> 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<StringRef, 8> 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<ValueDecl>(D)) {
if (auto *Req = ASTPrinter::findConformancesWithDocComment(
const_cast<ValueDecl*>(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() ||
isa<ProtocolDecl>(D->getDeclContext()))
return;
if (D->getAttrs().hasAttribute<AccessControlAttr>() &&
!llvm::is_contained(Options.ExcludeAttrList, DAK_AccessControl))
return;
printAccess(D->getFormalAccess());
if (auto storageDecl = dyn_cast<AbstractStorageDecl>(D)) {
if (auto setter = storageDecl->getSetter()) {
AccessLevel setterAccess = setter->getFormalAccess();
if (setterAccess != D->getFormalAccess())
printAccess(setterAccess, "(set)");
}
}
}
void printTypeWithOptions(Type T, PrintOptions options) {
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;
FreshOptions.PrintOptionalAsImplicitlyUnwrapped = options.PrintOptionalAsImplicitlyUnwrapped;
T.print(Printer, FreshOptions);
return;
}
T.print(Printer, options);
}
void printType(Type T) { printTypeWithOptions(T, Options); }
void printTransformedTypeWithOptions(Type T, PrintOptions options) {
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<NominalTypeDecl>(Current))
subMap = CurrentType->getContextSubstitutionMap(M, NTD);
else if (auto *ED = dyn_cast<ExtensionDecl>(Current))
subMap = CurrentType->getContextSubstitutionMap(M, ED);
else {
subMap = CurrentType->getMemberSubstitutionMap(
M, cast<ValueDecl>(Current));
}
T = T.subst(subMap,
SubstFlags::DesugarMemberTypes | SubstFlags::UseErrorType);
}
printTypeWithOptions(T, options);
}
void printTransformedType(Type T) {
printTransformedTypeWithOptions(T, Options);
}
void printTypeLocWithOptions(const TypeLoc &TL, PrintOptions options) {
if (CurrentType && TL.getType()) {
printTransformedTypeWithOptions(TL.getType(), options);
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())
repr->print(Printer, options);
return;
}
TL.getType().print(Printer, options);
}
void printTypeLoc(const TypeLoc &TL) { printTypeLocWithOptions(TL, Options); }
void printTypeLocForImplicitlyUnwrappedOptional(TypeLoc TL) {
PrintOptions options = Options;
options.PrintOptionalAsImplicitlyUnwrapped = true;
printTypeLocWithOptions(TL, options);
}
void printContextIfNeeded(const Decl *decl) {
if (IndentLevel > 0)
return;
switch (Options.ShouldQualifyNestedDeclarations) {
case PrintOptions::QualifyNestedDeclarations::Never:
return;
case PrintOptions::QualifyNestedDeclarations::TypesOnly:
if (!isa<TypeDecl>(decl))
return;
break;
case PrintOptions::QualifyNestedDeclarations::Always:
break;
}
auto *container = dyn_cast<NominalTypeDecl>(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<bool(const Requirement &)> filter);
void printSingleDepthOfGenericSignature(
TypeArrayView<GenericTypeParamType> genericParams,
ArrayRef<Requirement> requirements, unsigned flags,
llvm::function_ref<bool(const Requirement &)> 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<Decl *> members, bool needComma = false,
bool openBracket = true, bool closeBracket = true);
void printGenericDeclGenericParams(GenericContext *decl);
void printGenericDeclGenericRequirements(GenericContext *decl);
void printInherited(const Decl *decl);
void printEnumElement(EnumElementDecl *elt);
/// \returns true if anything was printed.
bool printASTNodes(const ArrayRef<ASTNode> &Elements, bool NeedIndent = true);
void printOneParameter(const ParamDecl *param, ParameterTypeFlags paramFlags,
bool ArgNameIsAPIByDefault);
void printParameterList(ParameterList *PL,
ArrayRef<AnyFunctionType::Param> params,
bool 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(Type ExtendedType, 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<NominalTypeDecl>(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<ExtensionDecl>(D);
if (Synthesize) {
Printer.setSynthesizedTarget(Options.TransformContext->getDecl());
}
// 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({});
Printer.printSynthesizedExtensionPost(cast<ExtensionDecl>(D),
Options.TransformContext->getDecl(),
Options.BracketOptions);
} else {
Printer.callPrintDeclPost(D, Options.BracketOptions);
}
return true;
}
};
} // unnamed namespace
static StaticSpellingKind getCorrectStaticSpelling(const Decl *D) {
if (auto *VD = dyn_cast<VarDecl>(D)) {
return VD->getCorrectStaticSpelling();
} else if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
return PBD->getCorrectStaticSpelling();
} else if (auto *FD = dyn_cast<FuncDecl>(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);
}
// If the declaration is implicitly @objc, print the attribute now.
if (Options.PrintImplicitAttrs) {
if (auto VD = dyn_cast<ValueDecl>(D)) {
if (VD->isObjC() && !VD->getAttrs().hasAttribute<ObjCAttr>()) {
Printer.printAttrName("@objc");
Printer << " ";
}
}
}
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<NamedPattern>(pattern);
recordDeclLoc(named->getDecl(), [&]{
Printer.printName(named->getBoundName());
});
break;
}
case PatternKind::Paren:
Printer << "(";
printPattern(cast<ParenPattern>(pattern)->getSubPattern());
Printer << ")";
break;
case PatternKind::Tuple: {
Printer << "(";
auto TP = cast<TuplePattern>(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<TypedPattern>(pattern));
break;
case PatternKind::Is: {
auto isa = cast<IsPattern>(pattern);
Printer << tok::kw_is << " ";
isa->getCastTypeLoc().getType().print(Printer, Options);
break;
}
case PatternKind::EnumElement: {
auto elt = cast<EnumElementPattern>(pattern);
// FIXME: Print element expr.
if (elt->hasSubPattern())
printPattern(elt->getSubPattern());
break;
}
case PatternKind::OptionalSome:
printPattern(cast<OptionalSomePattern>(pattern)->getSubPattern());
Printer << '?';
break;
case PatternKind::Bool:
Printer << (cast<BoolPattern>(pattern)->getValue() ? tok::kw_true
: tok::kw_false);
break;
case PatternKind::Expr:
// FIXME: Print expr.
break;
case PatternKind::Var:
if (!Options.SkipIntroducerKeywords)
Printer << (cast<VarPattern>(pattern)->isLet() ? tok::kw_let
: tok::kw_var)
<< " ";
printPattern(cast<VarPattern>(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<GenericTypeParamType>())
return combineDepth(paramTy->getDepth());
if (auto depMemTy = dyn_cast<DependentMemberType>(t->getCanonicalType())) {
CanType rootTy;
do {
rootTy = depMemTy.getBase();
} while ((depMemTy = dyn_cast<DependentMemberType>(rootTy)));
if (auto rootParamTy = dyn_cast<GenericTypeParamType>(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<Self.T>. (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<DependentMemberType>()) {
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<AssociatedTypeDecl>(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<Requirement> &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<bool(const Requirement &)> filter) {
if (flags & InnermostOnly) {
auto genericParams = genericSig->getInnermostGenericParams();
unsigned depth = genericParams[0]->getDepth();
SmallVector<Requirement, 2> 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<Requirement, 2> requirementsAtDepth;
getRequirementsAtDepth(genericSig, depth, requirementsAtDepth);
printSingleDepthOfGenericSignature(
genericParams.slice(paramIdx, lastParamIdx - paramIdx),
requirementsAtDepth, flags, filter);
paramIdx = lastParamIdx;
}
}
void PrintAST::printSingleDepthOfGenericSignature(
TypeArrayView<GenericTypeParamType> genericParams,
ArrayRef<Requirement> requirements, unsigned flags,
llvm::function_ref<bool(const Requirement &)> 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<ProtocolDecl>(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<ArchetypeType>() || first->isTypeParameter()) &&
!(second->is<ArchetypeType>() || 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<GenericTypeParamType>() &&
second->is<DependentMemberType>())
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<ExtensionDecl>(D)) {
if (Options.printExtensionContentAsMembers(ED))
return false;
}
if (Options.SkipMissingMemberPlaceholders && isa<MissingMemberDecl>(D))
return false;
if (Options.SkipDeinit && isa<DestructorDecl>(D)) {
return false;
}
if (Options.SkipImports && isa<ImportDecl>(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<EnumElementDecl>(D))
return true;
if (isa<EnumCaseDecl>(D))
return false;
} else if (auto *EED = dyn_cast<EnumElementDecl>(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<ValueDecl>(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<ExtensionDecl>(D)) {
auto Ext = cast<ExtensionDecl>(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<ValueDecl>(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<clang::ObjCProtocolDecl>(clangDecl->getDeclContext()) &&
VD->getDeclContext()->getAsClassOrClassExtensionContext())
return false;
// Check whether Clang considers it an override.
if (auto objcMethod = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
SmallVector<const clang::ObjCMethodDecl *, 4> overriddenMethods;
objcMethod->getOverriddenMethods(overriddenMethods);
if (!overriddenMethods.empty()) return false;
} else if (auto objcProperty
= dyn_cast<clang::ObjCPropertyDecl>(clangDecl)) {
if (auto getter = objcProperty->getGetterMethodDecl()) {
SmallVector<const clang::ObjCMethodDecl *, 4> 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<PatternBindingDecl>(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(AccessorDecl *accessor) {
switch (accessor->getAccessorKind()) {
case AccessorKind::Get:
case AccessorKind::Address:
case AccessorKind::Read:
return true;
case AccessorKind::Set:
case AccessorKind::WillSet:
case AccessorKind::DidSet:
case AccessorKind::MaterializeForSet:
case AccessorKind::MutableAddress:
case AccessorKind::Modify:
return false;
}
llvm_unreachable("bad addressor kind");
}
static StringRef getAccessorLabel(AccessorDecl *accessor) {
switch (accessor->getAccessorKind()) {
#define SINGLETON_ACCESSOR(ID, KEYWORD) \
case AccessorKind::ID: return #KEYWORD;
#define ACCESSOR(ID)
#include "swift/AST/AccessorKinds.def"
case AccessorKind::Address:
switch (accessor->getAddressorKind()) {
case AddressorKind::NotAddressor: llvm_unreachable("bad combination");
#define IMMUTABLE_ADDRESSOR(ID, KEYWORD) \
case AddressorKind::ID: return #KEYWORD;
#define ACCESSOR(ID)
#include "swift/AST/AccessorKinds.def"
}
llvm_unreachable("bad addressor kind");
case AccessorKind::MutableAddress:
switch (accessor->getAddressorKind()) {
case AddressorKind::NotAddressor: llvm_unreachable("bad combination");
#define MUTABLE_ADDRESSOR(ID, KEYWORD) \
case AddressorKind::ID: return #KEYWORD;
#define ACCESSOR(ID)
#include "swift/AST/AccessorKinds.def"
}
llvm_unreachable("bad addressor kind");
}
llvm_unreachable("bad accessor kind");
}
void PrintAST::printAccessors(AbstractStorageDecl *ASD) {
if (isa<VarDecl>(ASD) && !Options.PrintPropertyAccessors)
return;
// Never print anything for stored properties.
if (ASD->getAllAccessors().empty())
return;
auto impl = ASD->getImplInfo();
// 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 (impl.isSimpleStored()) {
if (Options.PrintForSIL) {
Printer << " { get " << (impl.supportsMutation() ? "set }" : "}");
}
return;
}
// We sometimes want to print the accessors abstractly
// instead of listing out how they're actually implemented.
bool inProtocol = isa<ProtocolDecl>(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 ((impl.getReadImpl() == ReadImplKind::Stored ||
impl.getReadImpl() == ReadImplKind::Get) &&
(impl.getWriteImpl() == WriteImplKind::Stored ||
impl.getWriteImpl() == WriteImplKind::Set) &&
(impl.getReadWriteImpl() == ReadWriteImplKind::MaterializeToTemporary) &&
!Options.PrintGetSetOnRWProperties &&
!Options.FunctionDefinitions &&
!ASD->getGetter()->isMutating() &&
!ASD->getSetter()->isExplicitNonMutating()) {
return;
}
// Otherwise, print all the concrete defining accessors.
bool PrintAccessorBody = Options.FunctionDefinitions || Options.FunctionBody;
auto PrintAccessor = [&](AccessorDecl *Accessor) {
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(getAccessorLabel(Accessor));
} else {
Printer.printNewline();
IndentRAII IndentMore(*this);
indent();
visit(Accessor);
}
};
Printer << " {";
if (impl.getReadImpl() == ReadImplKind::Get && ASD->getGetter() &&
!ASD->supportsMutation() &&
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 {
switch (impl.getReadImpl()) {
case ReadImplKind::Stored:
case ReadImplKind::Inherited:
break;
case ReadImplKind::Get:
PrintAccessor(ASD->getGetter());
break;
case ReadImplKind::Address:
PrintAccessor(ASD->getAddressor());
break;
case ReadImplKind::Read:
PrintAccessor(ASD->getReadCoroutine());
break;
}
switch (impl.getWriteImpl()) {
case WriteImplKind::Immutable:
break;
case WriteImplKind::Stored:
llvm_unreachable("simply-stored variable should have been filtered out");
case WriteImplKind::StoredWithObservers:
case WriteImplKind::InheritedWithObservers:
PrintAccessor(ASD->getWillSetFunc());
PrintAccessor(ASD->getDidSetFunc());
break;
case WriteImplKind::Set:
PrintAccessor(ASD->getSetter());
if (impl.getReadWriteImpl() == ReadWriteImplKind::Modify)
PrintAccessor(ASD->getModifyCoroutine());
break;
case WriteImplKind::MutableAddress:
PrintAccessor(ASD->getMutableAddressor());
PrintAccessor(ASD->getWillSetFunc());
PrintAccessor(ASD->getDidSetFunc());
break;
case WriteImplKind::Modify:
PrintAccessor(ASD->getModifyCoroutine());
break;
}
}
if (PrintAccessorBody) {
Printer.printNewline();
indent();
} else
Printer << " ";
Printer << "}";
}
void PrintAST::printMembersOfDecl(Decl *D, bool needComma,
bool openBracket,
bool closeBracket) {
llvm::SmallVector<Decl *, 3> Members;
auto AddDeclFunc = [&](DeclRange Range) {
for (auto RD : Range)
Members.push_back(RD);
};
if (auto Ext = dyn_cast<ExtensionDecl>(D)) {
AddDeclFunc(Ext->getMembers());
} else if (auto NTD = dyn_cast<NominalTypeDecl>(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<Decl *> 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::printGenericDeclGenericParams(GenericContext *decl) {
if (decl->getGenericParams())
if (auto GenericSig = decl->getGenericSignature())
printGenericSignature(GenericSig, PrintParams | InnermostOnly);
}
void PrintAST::printGenericDeclGenericRequirements(GenericContext *decl) {
if (decl->getGenericParams())
if (auto GenericSig = decl->getGenericSignature())
printGenericSignature(GenericSig, PrintRequirements | InnermostOnly);
}
void PrintAST::printInherited(const Decl *decl) {
SmallVector<TypeLoc, 6> TypesToPrint;
getInheritedForPrinting(decl, [this](const Decl* D) { return shouldPrint(D); },
TypesToPrint);
if (TypesToPrint.empty())
return;
Printer << " : ";
interleave(TypesToPrint, [&](TypeLoc TL) {
printTypeLoc(TL);
}, [&]() {
Printer << ", ";
});
}
static void getModuleEntities(const clang::Module *ClangMod,
SmallVectorImpl<ModuleEntity> &ModuleEnts) {
if (!ClangMod)
return;
getModuleEntities(ClangMod->Parent, ModuleEnts);
ModuleEnts.push_back(ClangMod);
}
static void getModuleEntities(ImportDecl *Import,
SmallVectorImpl<ModuleEntity> &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<ModuleEntity, 4> ModuleEnts;
getModuleEntities(decl, ModuleEnts);
ArrayRef<ModuleEntity> 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) {
Options.FullyQualifiedTypes = false;
Options.FullyQualifiedTypesIfAmbiguous = false;
// Strip off generic arguments, if any.
auto Ty = ExtendedType->getAnyNominal()->getDeclaredType();
Ty->print(Printer, Options);
}
void PrintAST::printSynthesizedExtension(Type ExtendedType,
ExtensionDecl *ExtDecl) {
if (Options.BracketOptions.shouldOpenExtension(ExtDecl)) {
printDocumentationComment(ExtDecl);
printAttributes(ExtDecl);
Printer << tok::kw_extension << " ";
printExtendedTypeName(ExtendedType, Printer, Options);
printInherited(ExtDecl);
printGenericDeclGenericRequirements(ExtDecl);
}
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();
if (!extendedType || !extendedType->getAnyNominal()) {
// 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()) {
auto extendedType =
Options.TransformContext->getBaseType()->mapTypeOutOfContext();
printSynthesizedExtension(extendedType, 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<NamedPattern>(entry.getPattern()) ||
isa<TuplePattern>(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::visitPoundDiagnosticDecl(PoundDiagnosticDecl *PDD) {
/// TODO: Should we even print #error/#warning?
if (PDD->isError()) {
Printer << tok::pound_error;
} else {
Printer << tok::pound_warning;
}
Printer << "(\"" << PDD->getMessage()->getValue() << "\")";
}
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
printGenericDeclGenericParams(decl);
});
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());
printGenericDeclGenericRequirements(decl);
}
}
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
printGenericDeclGenericParams(decl);
});
printInherited(decl);
printGenericDeclGenericRequirements(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
printGenericDeclGenericParams(decl);
});
printInherited(decl);
printGenericDeclGenericRequirements(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
printGenericDeclGenericParams(decl);
});
printInherited(decl);
printGenericDeclGenericRequirements(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<ClassDecl>(nominal) || isa<StructDecl>(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 ";
switch (flags.getValueOwnership()) {
case ValueOwnership::Default:
/* nothing */
break;
case ValueOwnership::InOut:
printer << "inout ";
break;
case ValueOwnership::Shared:
printer << "__shared ";
break;
case ValueOwnership::Owned:
printer << "__owned ";
break;
}
}
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<SILStoredAttr>())
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::Let:
Printer << tok::kw_let;
break;
case VarDecl::Specifier::Var:
case VarDecl::Specifier::InOut:
case VarDecl::Specifier::Shared:
case VarDecl::Specifier::Owned:
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());
if (decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
printTypeLocForImplicitlyUnwrappedOptional(tyLoc);
else
printTypeLoc(tyLoc);
}
printAccessors(decl);
}
void PrintAST::visitParamDecl(ParamDecl *decl) {
visitVarDecl(decl);
}
void PrintAST::printOneParameter(const ParamDecl *param,
ParameterTypeFlags paramFlags,
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::EnumElement:
if (ArgName.empty() && BodyName.empty() && !param->getDefaultValue()) {
// Don't print anything, in the style of a tuple element.
return;
}
// Else, print the argument only.
LLVM_FALLTHROUGH;
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<BoundGenericType>())
TheTypeLoc.setType(BGT->getGenericArgs()[0]);
}
// 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)) {
auto type = TheTypeLoc.getType();
printParameterFlags(Printer, Options, paramFlags);
while (auto parenTy = dyn_cast<ParenType>(type.getPointer())) {
++numParens;
type = parenTy->getUnderlyingType();
}
TheTypeLoc = TypeLoc::withoutLoc(type);
}
for (unsigned i = 0; i < numParens; ++i)
Printer << "(";
if (param->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
printTypeLocForImplicitlyUnwrappedOptional(TheTypeLoc);
else
printTypeLoc(TheTypeLoc);
for (unsigned i = 0; i < numParens; ++i)
Printer << ")";
if (param->isVariadic())
Printer << "...";
if (param->isDefaultArgument()) {
StringRef defaultArgStr = param->getDefaultValueStringRepresentation();
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:
case DefaultArgumentKind::NilLiteral:
Printer.printKeyword(defaultArgStr);
break;
default:
Printer << defaultArgStr;
break;
}
}
}
}
void PrintAST::printParameterList(ParameterList *PL,
ArrayRef<AnyFunctionType::Param> params,
bool isAPINameByDefault) {
Printer << "(";
const unsigned paramSize = params.size();
for (unsigned i = 0, e = PL->size(); i != e; ++i) {
if (i > 0)
Printer << ", ";
auto paramFlags = (i < paramSize)
? params[i].getParameterFlags()
: ParameterTypeFlags();
printOneParameter(PL->get(i), paramFlags,
isAPINameByDefault);
}
Printer << ")";
}
void PrintAST::printFunctionParameters(AbstractFunctionDecl *AFD) {
auto BodyParams = AFD->getParameters();
auto curTy = AFD->hasInterfaceType() ? AFD->getInterfaceType() : nullptr;
// Skip over the implicit 'self'.
if (AFD->hasImplicitSelfDecl()) {
if (curTy)
if (auto funTy = curTy->getAs<AnyFunctionType>())
curTy = funTy->getResult();
}
ArrayRef<AnyFunctionType::Param> parameterListTypes;
if (curTy) {
if (auto funTy = curTy->getAs<AnyFunctionType>()) {
parameterListTypes = funTy->getParams();
}
}
printParameterList(BodyParams, parameterListTypes,
AFD->argumentNameIsAPIByDefault());
if (AFD->hasThrows()) {
if (AFD->getAttrs().hasAttribute<RethrowsAttr>())
Printer << " " << tok::kw_rethrows;
else
Printer << " " << tok::kw_throws;
}
}
bool PrintAST::printASTNodes(const ArrayRef<ASTNode> &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<Decl*>()) {
if (decl->shouldPrintInContext(Options))
visit(decl);
} else if (auto stmt = element.dyn_cast<Stmt*>()) {
visit(stmt);
} else {
// FIXME: print expression
// visit(element.get<Expr*>());
}
}
return PrintedSomething;
}
void PrintAST::visitAccessorDecl(AccessorDecl *decl) {
printDocumentationComment(decl);
printAttributes(decl);
switch (auto kind = decl->getAccessorKind()) {
case AccessorKind::Get:
case AccessorKind::Address:
case AccessorKind::Read:
case AccessorKind::Modify:
case AccessorKind::DidSet:
case AccessorKind::MaterializeForSet:
case AccessorKind::MutableAddress:
recordDeclLoc(decl,
[&]{
Printer << getAccessorLabel(decl);
});
Printer << " {";
break;
case AccessorKind::Set:
case AccessorKind::WillSet:
recordDeclLoc(decl,
[&]{
Printer << getAccessorLabel(decl);
auto params = decl->getParameters();
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 << "}";
}
void PrintAST::visitFuncDecl(FuncDecl *decl) {
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<MutatingAttr>()) {
Printer.printKeyword("mutating");
Printer << " ";
} else if (decl->isConsuming() && !decl->getAttrs().hasAttribute<ConsumingAttr>()) {
Printer.printKeyword("__consuming");
Printer << " ";
}
Printer << tok::kw_func << " ";
}
printContextIfNeeded(decl);
recordDeclLoc(decl,
[&]{ // Name
if (!decl->hasName()) {
Printer << "<anonymous>";
} else {
Printer.printName(decl->getName());
if (decl->isOperator())
Printer << " ";
}
}, [&] { // Parameters
printGenericDeclGenericParams(decl);
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<SimpleIdentTypeRepr>(ResultTyLoc.getTypeRepr())) {
if (simId->getIdentifier().str() == "Self")
ResultTyLoc = TypeLoc::withoutLoc(ResultTy);
}
Printer << " -> ";
Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType);
if (decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
printTypeLocForImplicitlyUnwrappedOptional(ResultTyLoc);
else
printTypeLoc(ResultTyLoc);
Printer.printStructurePost(PrintStructureKind::FunctionReturnType);
}
printGenericDeclGenericRequirements(decl);
}
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 *PL = elt->getParameterList()) {
llvm::SaveAndRestore<PrintOptions::ArgAndParamPrintingMode>
mode(Options.ArgAndParamPrinting,
PrintOptions::ArgAndParamPrintingMode::EnumElement);
auto params = ArrayRef<AnyFunctionType::Param>();
if (elt->hasInterfaceType() && !elt->getInterfaceType()->hasError()) {
// Walk to the params of the associated values.
// (EnumMetaType) -> (AssocValues) -> Enum
params = elt->getInterfaceType()->castTo<AnyFunctionType>()
->getResult()
->castTo<AnyFunctionType>()
->getParams();
}
printParameterList(PL, params,
/*isAPINameByDefault*/true);
}
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<NumberLiteralExpr>(raw);
Printer.callPrintStructurePre(PrintStructureKind::NumberLiteral);
if (numLiteral->isNegative())
Printer << "-";
Printer << numLiteral->getDigitsText();
Printer.printStructurePost(PrintStructureKind::NumberLiteral);
break;
}
case ExprKind::StringLiteral: {
Printer.callPrintStructurePre(PrintStructureKind::StringLiteral);
llvm::SmallString<32> str;
llvm::raw_svector_ostream os(str);
os << QuotedString(cast<StringLiteralExpr>(raw)->getValue());
Printer << str;
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
printGenericDeclGenericParams(decl);
auto params = ArrayRef<AnyFunctionType::Param>();
if (decl->hasInterfaceType() && !decl->getInterfaceType()->hasError()) {
// Walk to the params of the subscript's indices.
params = decl->getInterfaceType()->castTo<AnyFunctionType>()->getParams();
}
printParameterList(decl->getIndices(), params,
/*isAPINameByDefault*/false);
});
Printer << " -> ";
Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType);
TypeLoc elementTy = decl->getElementTypeLoc();
if (!elementTy.getTypeRepr())
elementTy = TypeLoc::withoutLoc(decl->getElementInterfaceType());
if (decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
printTypeLocForImplicitlyUnwrappedOptional(elementTy);
else
printTypeLoc(elementTy);
Printer.printStructurePost(PrintStructureKind::FunctionReturnType);
printGenericDeclGenericRequirements(decl);
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<ConvenienceAttr>()) {
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;
}
printGenericDeclGenericParams(decl);
printFunctionParameters(decl);
});
printGenericDeclGenericRequirements(decl);
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::visitYieldStmt(YieldStmt *stmt) {
Printer.printKeyword("yield");
Printer << " ";
bool parens = (stmt->getYields().size() != 1
|| stmt->getLParenLoc().isValid());
if (parens) Printer << "(";
bool first = true;
for (auto yield : stmt->getYields()) {
if (first) {
first = false;
} else {
Printer << ", ";
}
// FIXME: print expression.
(void) yield;
}
if (parens) Printer << ")";
}
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<Stmt*>())
visit(cast<CaseStmt>(N.get<Stmt*>()));
else
visit(cast<IfConfigDecl>(N.get<Decl*>()));
}
Printer.printNewline();
indent();
Printer << "}";
}
void PrintAST::visitCaseStmt(CaseStmt *CS) {
if (CS->hasUnknownAttr())
Printer << "@unknown ";
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<BraceStmt>(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<Decl *>(this));
}
bool Decl::shouldPrintInContext(const PrintOptions &PO) const {
// Skip getters/setters. They are part of the variable or subscript.
if (isa<AccessorDecl>(this))
return false;
if (PO.ExplodePatternBindingDecls) {
if (isa<VarDecl>(this))
return true;
if (isa<PatternBindingDecl>(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<VarDecl>(this)) {
if (!VD->hasClangNode() && VD->getImplInfo().isSimpleStored())
return false;
}
// Skip pattern bindings that consist of just one variable with
// interesting accessors.
if (auto pbd = dyn_cast<PatternBindingDecl>(this)) {
if (pbd->getPatternList().size() == 1) {
auto pattern =
pbd->getPatternList()[0].getPattern()->getSemanticsProvidingPattern();
if (auto named = dyn_cast<NamedPattern>(pattern)) {
if (!named->getDecl()->getImplInfo().isSimpleStored())
return false;
}
}
}
}
if (isa<IfConfigDecl>(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<TypePrinter> {
using super = TypeVisitor;
ASTPrinter &Printer;
const PrintOptions &Options;
void printGenericArgs(ArrayRef<Type> Args) {
if (Args.empty())
return;
Printer << "<";
interleave(Args, [&](Type Arg) { visit(Arg); }, [&] { Printer << ", "; });
Printer << ">";
}
/// 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 (T->hasSimpleTypeRepr()) {
visit(T);
} else {
Printer << "(";
visit(T);
Printer << ")";
}
}
template <typename T>
void printModuleContext(T *Ty) {
ModuleDecl *Mod = Ty->getDecl()->getModuleContext();
Printer.printModuleRef(Mod, Mod->getName());
Printer << ".";
}
template <typename T>
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 << "<<error type>>";
}
void visitUnresolvedType(UnresolvedType *T) {
if (T->getASTContext().LangOpts.DebugConstraintSolver)
Printer << "<<unresolvedtype>>";
else
Printer << "_";
}
void visitBuiltinRawPointerType(BuiltinRawPointerType *T) {
Printer << BUILTIN_TYPE_NAME_RAWPOINTER;
}
void visitBuiltinNativeObjectType(BuiltinNativeObjectType *T) {
Printer << BUILTIN_TYPE_NAME_NATIVEOBJECT;
}
void visitBuiltinUnknownObjectType(BuiltinUnknownObjectType *T) {
Printer << BUILTIN_TYPE_NAME_UNKNOWNOBJECT;
}
void visitBuiltinBridgeObjectType(BuiltinBridgeObjectType *T) {
Printer << BUILTIN_TYPE_NAME_BRIDGEOBJECT;
}
void visitBuiltinUnsafeValueBufferType(BuiltinUnsafeValueBufferType *T) {
Printer << BUILTIN_TYPE_NAME_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_TYPE_NAME_PREFIX))
UnderlyingStr = UnderlyingStrVec.substr(8);
else
UnderlyingStr = UnderlyingStrVec;
}
Printer << BUILTIN_TYPE_NAME_VEC << T->getNumElements() << "x" << UnderlyingStr;
}
void visitBuiltinIntegerType(BuiltinIntegerType *T) {
auto width = T->getWidth();
if (width.isFixedWidth()) {
Printer << BUILTIN_TYPE_NAME_INT << width.getFixedWidth();
} else if (width.isPointerWidth()) {
Printer << BUILTIN_TYPE_NAME_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_TYPE_NAME_SILTOKEN;
}
void visitNameAliasType(NameAliasType *T) {
if (Options.PrintForSIL || Options.PrintNameAliasUnderlyingType) {
visit(T->getSinglyDesugaredType());
return;
}
if (auto parent = T->getParent()) {
visit(parent);
Printer << ".";
}
printTypeDeclName(T);
printGenericArgs(T->getInnermostGenericArgs());
}
void visitParenType(ParenType *T) {
Printer << "(";
printParameterFlags(Printer, Options, T->getParameterFlags());
visit(T->getUnderlyingType()->getInOutObjectType());
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.getRawType();
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 (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<SyntaxSugarType>(T.getPointer()))
T = sugarType->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<MetatypeType>(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<ClassDecl>(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<ProtocolConformanceRef> 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 visitAnyFunctionTypeParams(ArrayRef<AnyFunctionType::Param> Params,
bool printLabels) {
Printer << "(";
for (unsigned i = 0, e = Params.size(); i != e; ++i) {
if (i)
Printer << ", ";
const AnyFunctionType::Param &Param = Params[i];
Printer.callPrintStructurePre(PrintStructureKind::FunctionParameter);
SWIFT_DEFER {
Printer.printStructurePost(PrintStructureKind::FunctionParameter);
};
if (printLabels && Param.hasLabel()) {
Printer.printName(Param.getLabel(),
PrintNameContext::FunctionParameterExternal);
Printer << ": ";
}
printParameterFlags(Printer, Options, Param.getParameterFlags());
visit(Param.getPlainType());
if (Param.isVariadic())
Printer << "...";
}
Printer << ")";
}
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.
visitAnyFunctionTypeParams(T->getParams(), /*printLabels*/false);
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 << " ";
visitAnyFunctionTypeParams(T->getParams(), /*printLabels*/true);
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 (auto subMap = T->getSubstitutions()) {
Printer << " <";
interleave(subMap.getReplacementTypes(),
[&](Type type) {
visit(type);
}, [&]{
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) {
auto printAsIUO = Options.PrintOptionalAsImplicitlyUnwrapped;
// Printing optionals with a trailing '!' applies only to
// top-level optionals, not to any nested within.
const_cast<PrintOptions &>(Options).PrintOptionalAsImplicitlyUnwrapped =
false;
printWithParensIfNotSimple(T->getBaseType());
const_cast<PrintOptions &>(Options).PrintOptionalAsImplicitlyUnwrapped =
printAsIUO;
if (printAsIUO)
Printer << "!";
else
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 << "<anonymous>";
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 << "<anonymous>";
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());
}
#define REF_STORAGE(Name, name, ...) \
void visit##Name##StorageType(Name##StorageType *T) { \
if (Options.PrintStorageRepresentationAttrs) \
Printer << "@sil_" #name " "; \
visit(T->getReferentType()); \
}
#include "swift/AST/ReferenceStorage.def"
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 << "<null>";
else
TypePrinter(Printer, PO).visit(*this);
}
void AnyFunctionType::printParams(raw_ostream &OS, const
PrintOptions &PO) const {
StreamPrinter Printer(OS);
printParams(Printer, PO);
}
void AnyFunctionType::printParams(ASTPrinter &Printer,
const PrintOptions &PO) const {
TypePrinter(Printer, PO).visitAnyFunctionTypeParams(getParams(),
/*printLabels*/true);
}
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, PrintOptions Opts) const {
StreamPrinter Printer(OS);
PrintAST(Printer, Opts)
.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";
}
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();
}
std::string Type::getStringAsComponent(const PrintOptions &PO) const {
std::string Result;
llvm::raw_string_ostream OS(Result);
if (getPointer()->hasSimpleTypeRepr()) {
print(OS, PO);
} else {
OS << "(";
print(OS, PO);
OS << ")";
}
return OS.str();
}
std::string TypeBase::getStringAsComponent(const PrintOptions &PO) const {
std::string Result;
llvm::raw_string_ostream OS(Result);
if (hasSimpleTypeRepr()) {
print(OS, PO);
} else {
OS << "(";
print(OS, PO);
OS << ")";
}
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<TypeBase *>(this)).print(OS, PO);
}
void TypeBase::print(ASTPrinter &Printer, const PrintOptions &PO) const {
Type(const_cast<TypeBase *>(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<NormalProtocolConformance>(this);
os << normal->getProtocol()->getName()
<< " module " << normal->getDeclContext()->getParentModule()->getName();
break;
}
case ProtocolConformanceKind::Specialized: {
auto spec = cast<SpecializedProtocolConformance>(this);
os << "specialize <";
interleave(spec->getSubstitutionMap().getReplacementTypes(),
[&](Type type) { type.print(os, PO); },
[&] { os << ", "; });
os << "> (";
spec->getGenericConformance()->printName(os, PO);
os << ")";
break;
}
case ProtocolConformanceKind::Inherited: {
auto inherited = cast<InheritedProtocolConformance>(this);
os << "inherit (";
inherited->getInheritedConformance()->printName(os, PO);
os << ")";
break;
}
}
}
void swift::printEnumElementsAsCases(
llvm::DenseSet<EnumElementDecl *> &UnhandledElements,
llvm::raw_ostream &OS) {
// Sort the missing elements to a vector because set does not guarantee
// orders.
SmallVector<EnumElementDecl *, 4> 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 = [](ParameterList *PL, llvm::raw_ostream &OS) {
// If the enum element has no payloads, return.
if (!PL)
return;
OS << "(";
// Print each element in the pattern match.
for (auto i = PL->begin(); i != PL->end(); ++i) {
auto *param = *i;
if (param->hasName()) {
OS << tok::kw_let << " " << param->getName().str();
} else {
OS << "_";
}
if (i + 1 != PL->end()) {
OS << ", ";
}
}
OS << ")";
};
// Print each enum element name.
std::for_each(SortedElements.begin(), SortedElements.end(),
[&](EnumElementDecl *EE) {
OS << tok::kw_case << " ." << EE->getNameStr();
printPayloads(EE->getParameterList(), OS);
OS << ": " << getCodePlaceholder() << "\n";
});
}
void
swift::getInheritedForPrinting(const Decl *decl,
llvm::function_ref<bool(const Decl*)> shouldPrint,
llvm::SmallVectorImpl<TypeLoc> &Results) {
ArrayRef<TypeLoc> inherited;
if (auto td = dyn_cast<TypeDecl>(decl)) {
inherited = td->getInherited();
} else if (auto ed = dyn_cast<ExtensionDecl>(decl)) {
inherited = ed->getInherited();
}
// Collect explicit inheritted types.
for (auto TL: inherited) {
if (auto Ty = TL.getType()) {
if (auto NTD = Ty->getAnyNominal())
if (!shouldPrint(NTD))
continue;
}
Results.push_back(TL);
}
// Collect synthesized conformances.
auto &ctx = decl->getASTContext();
for (auto attr : decl->getAttrs().getAttributes<SynthesizedProtocolAttr>()) {
if (auto *proto = ctx.getProtocol(attr->getProtocolKind())) {
if (!shouldPrint(proto))
continue;
if (attr->getProtocolKind() == KnownProtocolKind::RawRepresentable &&
isa<EnumDecl>(decl) &&
cast<EnumDecl>(decl)->hasRawType())
continue;
Results.push_back(TypeLoc::withoutLoc(proto->getDeclaredType()));
}
}
}