blob: 3273d3ec4d7f4ae642a223c466f8d849f62cb16f [file] [log] [blame]
//===--- ASTPrinter.h - Class for printing the AST --------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_ASTPRINTER_H
#define SWIFT_AST_ASTPRINTER_H
#include "swift/Basic/LLVM.h"
#include "swift/Basic/QuotedString.h"
#include "swift/Basic/UUID.h"
#include "swift/AST/Identifier.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/raw_ostream.h"
#include "swift/AST/PrintOptions.h"
namespace swift {
class Decl;
class DeclContext;
class DynamicSelfType;
class ModuleEntity;
class TypeDecl;
class EnumElementDecl;
class Type;
class TypeLoc;
class Pattern;
class ExtensionDecl;
class NominalTypeDecl;
class ValueDecl;
class SourceLoc;
enum class tok;
enum class AccessorKind;
/// Describes the context in which a name is being printed, which
/// affects the keywords that need to be escaped.
enum class PrintNameContext {
/// Normal context
Normal,
/// Keyword context, where no keywords are escaped.
Keyword,
/// Type member context, e.g. properties or enum cases.
TypeMember,
/// Generic parameter context, where 'Self' is not escaped.
GenericParameter,
/// Class method return type, where 'Self' is not escaped.
ClassDynamicSelf,
/// Function parameter context, where keywords other than let/var/inout are
/// not escaped.
FunctionParameterExternal,
FunctionParameterLocal,
/// Tuple element context, similar to \c FunctionParameterExternal.
TupleElement,
/// Attributes, which are escaped as 'Normal', but differentiated for
/// the purposes of printName* callbacks.
Attribute,
};
/// Describes the kind of structured entity being printed.
///
/// This includes printables with sub-structure that cannot be completely
/// handled by the printDeclPre/printDeclPost callbacks.
/// E.g.
/// \code
/// func foo(<FunctionParameter>x: Int = 2</FunctionParameter>, ...)
/// \endcode
enum class PrintStructureKind {
GenericParameter,
GenericRequirement,
FunctionParameter,
FunctionType,
FunctionReturnType,
BuiltinAttribute,
TupleType,
TupleElement,
NumberLiteral,
StringLiteral,
};
/// An abstract class used to print an AST.
class ASTPrinter {
unsigned CurrentIndentation = 0;
unsigned PendingNewlines = 0;
TypeOrExtensionDecl SynthesizeTarget;
void printTextImpl(StringRef Text);
public:
virtual ~ASTPrinter() {}
virtual void printText(StringRef Text) = 0;
// MARK: Callback interface.
/// Called after the printer decides not to print D.
///
/// Callers should use callAvoidPrintDeclPost().
virtual void avoidPrintDeclPost(const Decl *D) {};
/// Called before printing of a declaration.
///
/// Callers should use callPrintDeclPre().
virtual void printDeclPre(const Decl *D, Optional<BracketOptions> Bracket) {}
/// Called before printing at the point which would be considered the location
/// of the declaration (normally the name of the declaration).
///
/// Callers should use callPrintDeclLoc().
virtual void printDeclLoc(const Decl *D) {}
/// Called after printing the name of the declaration.
virtual void printDeclNameEndLoc(const Decl *D) {}
/// Called after printing the name of a declaration, or in the case of
/// functions its signature.
virtual void printDeclNameOrSignatureEndLoc(const Decl *D) {}
/// Called after finishing printing of a declaration.
///
/// Callers should use callPrintDeclPost().
virtual void printDeclPost(const Decl *D, Optional<BracketOptions> Bracket) {}
/// Called before printing the result type of the declaration. Printer can
/// replace \p TL to customize the input.
virtual void printDeclResultTypePre(ValueDecl *VD, TypeLoc &TL) {}
/// Called before printing a type.
virtual void printTypePre(const TypeLoc &TL) {}
/// Called after printing a type.
virtual void printTypePost(const TypeLoc &TL) {}
/// Called when printing the referenced name of a type declaration, possibly
/// from deep inside another type.
///
/// \param T the original \c Type being referenced. May be null.
/// \param RefTo the \c TypeDecl this is considered a reference to.
/// \param Name the name to be printed.
/// \param NameContext the \c PrintNameContext which this type is being
/// printed in, used to determine how to escape type names.
virtual void printTypeRef(
Type T, const TypeDecl *RefTo, Identifier Name,
PrintNameContext NameContext = PrintNameContext::Normal);
/// Called when printing the referenced name of a module.
virtual void printModuleRef(ModuleEntity Mod, Identifier Name);
/// Called before printing a synthesized extension.
virtual void printSynthesizedExtensionPre(const ExtensionDecl *ED,
TypeOrExtensionDecl NTD,
Optional<BracketOptions> Bracket) {}
/// Called after printing a synthesized extension.
virtual void printSynthesizedExtensionPost(const ExtensionDecl *ED,
TypeOrExtensionDecl TargetDecl,
Optional<BracketOptions> Bracket) {
}
/// Called before printing a structured entity.
///
/// Callers should use callPrintStructurePre().
virtual void printStructurePre(PrintStructureKind Kind,
const Decl *D = nullptr) {}
/// Called after printing a structured entity.
virtual void printStructurePost(PrintStructureKind Kind,
const Decl *D = nullptr) {}
/// Called before printing a name in the given context.
virtual void printNamePre(PrintNameContext Context) {}
/// Called after printing a name in the given context.
virtual void printNamePost(PrintNameContext Context) {}
// Helper functions.
void printSeparator(bool &first, StringRef separator) {
if (first) {
first = false;
} else {
printTextImpl(separator);
}
}
ASTPrinter &operator<<(StringRef Text) {
printTextImpl(Text);
return *this;
}
ASTPrinter &operator<<(QuotedString s);
ASTPrinter &operator<<(unsigned long long N);
ASTPrinter &operator<<(UUID UU);
ASTPrinter &operator<<(Identifier name);
ASTPrinter &operator<<(DeclBaseName name);
ASTPrinter &operator<<(DeclName name);
ASTPrinter &operator<<(DeclNameRef name);
// Special case for 'char', but not arbitrary things that convert to 'char'.
template <typename T>
typename std::enable_if<std::is_same<T, char>::value, ASTPrinter &>::type
operator<<(T c) {
return *this << StringRef(&c, 1);
}
void printKeyword(StringRef name,
const PrintOptions &Opts,
StringRef Suffix = "") {
if (Opts.SkipUnderscoredKeywords && name.startswith("_"))
return;
assert(!name.empty() && "Tried to print empty keyword");
callPrintNamePre(PrintNameContext::Keyword);
*this << name;
printNamePost(PrintNameContext::Keyword);
*this << Suffix;
}
void printAttrName(StringRef name, bool needAt = false) {
callPrintNamePre(PrintNameContext::Attribute);
if (needAt)
*this << "@";
*this << name;
printNamePost(PrintNameContext::Attribute);
}
ASTPrinter &printSimpleAttr(StringRef name, bool needAt = false) {
callPrintStructurePre(PrintStructureKind::BuiltinAttribute);
printAttrName(name, needAt);
printStructurePost(PrintStructureKind::BuiltinAttribute);
return *this;
}
void printEscapedStringLiteral(StringRef str);
void printName(Identifier Name,
PrintNameContext Context = PrintNameContext::Normal);
void setIndent(unsigned NumSpaces) {
CurrentIndentation = NumSpaces;
}
void setSynthesizedTarget(TypeOrExtensionDecl Target) {
assert((!SynthesizeTarget || !Target || Target == SynthesizeTarget) &&
"unexpected change of setSynthesizedTarget");
// FIXME: this can overwrite the original target with nullptr.
SynthesizeTarget = Target;
}
void printNewline() {
PendingNewlines++;
}
void forceNewlines() {
if (PendingNewlines > 0) {
llvm::SmallString<16> Str;
for (unsigned i = 0; i != PendingNewlines; ++i)
Str += '\n';
PendingNewlines = 0;
printText(Str);
printIndent();
}
}
virtual void printIndent();
// MARK: Callback interface wrappers that perform ASTPrinter bookkeeping.
/// Make a callback to printDeclPre(), performing any necessary bookeeping.
void callPrintDeclPre(const Decl *D, Optional<BracketOptions> Bracket);
/// Make a callback to printDeclPost(), performing any necessary bookeeping.
void callPrintDeclPost(const Decl *D, Optional<BracketOptions> Bracket) {
printDeclPost(D, Bracket);
}
/// Make a callback to avoidPrintDeclPost(), performing any necessary
/// bookkeeping.
void callAvoidPrintDeclPost(const Decl *D) {
avoidPrintDeclPost(D);
}
/// Make a callback to printDeclLoc(), performing any necessary bookeeping.
void callPrintDeclLoc(const Decl *D) {
forceNewlines();
printDeclLoc(D);
}
/// Make a callback to printNamePre(), performing any necessary bookeeping.
void callPrintNamePre(PrintNameContext Context) {
forceNewlines();
printNamePre(Context);
}
/// Make a callback to printStructurePre(), performing any necessary
/// bookkeeping.
void callPrintStructurePre(PrintStructureKind Kind, const Decl *D = nullptr) {
forceNewlines();
printStructurePre(Kind, D);
}
/// To sanitize a malformed utf8 string to a well-formed one.
static std::string sanitizeUtf8(StringRef Text);
private:
virtual void anchor();
};
/// An AST printer for a raw_ostream.
class StreamPrinter : public ASTPrinter {
protected:
raw_ostream &OS;
public:
explicit StreamPrinter(raw_ostream &OS) : OS(OS) {}
void printText(StringRef Text) override;
};
/// AST stream printer that adds extra indentation to each line.
class ExtraIndentStreamPrinter : public StreamPrinter {
StringRef ExtraIndent;
public:
ExtraIndentStreamPrinter(raw_ostream &out, StringRef extraIndent)
: StreamPrinter(out), ExtraIndent(extraIndent) { }
virtual void printIndent() override {
printText(ExtraIndent);
StreamPrinter::printIndent();
}
};
void printContext(raw_ostream &os, DeclContext *dc);
bool printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
Type AdopterTy, SourceLoc TypeLoc, raw_ostream &OS);
/// Print a keyword or punctuator directly by its kind.
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, tok keyword);
/// Get the length of a keyword or punctuator by its kind.
uint8_t getKeywordLen(tok keyword);
/// Get <#code#>;
StringRef getCodePlaceholder();
/// Given an array of enum element decls, print them as case statements with
/// placeholders as contents.
void printEnumElementsAsCases(
llvm::DenseSet<EnumElementDecl *> &UnhandledElements,
llvm::raw_ostream &OS);
void getInheritedForPrinting(const Decl *decl, const PrintOptions &options,
llvm::SmallVectorImpl<TypeLoc> &Results);
StringRef getAccessorKindString(AccessorKind value);
} // namespace swift
#endif // LLVM_SWIFT_AST_ASTPRINTER_H