Skip to content

Commit

Permalink
[ASTPrint] For when printing interface from a source file, introduce …
Browse files Browse the repository at this point in the history
…an option to

pick up the original source text for the declarations.
  • Loading branch information
akyrtzi committed Dec 3, 2015
1 parent 04e3949 commit 8659022
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 70 deletions.
5 changes: 5 additions & 0 deletions include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ struct PrintOptions {
/// \brief Whether to print regular comments from clang module headers.
bool PrintRegularClangComments = false;

/// When true, printing interface from a source file will print the original
/// source text for applicable declarations, in order to preserve the
/// formatting.
bool PrintOriginalSourceText = false;

/// \brief Print dependent types as references into this generic parameter
/// list.
GenericParamList *ContextGenericParams = nullptr;
Expand Down
185 changes: 117 additions & 68 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "swift/Basic/Fallthrough.h"
#include "swift/Basic/PrimitiveParsing.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Parse/Lexer.h"
#include "swift/Config.h"
#include "swift/Sema/CodeCompletionTypeChecking.h"
#include "swift/Strings.h"
Expand Down Expand Up @@ -292,6 +293,10 @@ class PrintAST : public ASTVisitor<PrintAST> {
Printer.printDeclNameEndLoc(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);
Expand Down Expand Up @@ -1411,13 +1416,20 @@ void PrintAST::visitEnumDecl(EnumDecl *decl) {
printDocumentationComment(decl);
printAttributes(decl);
printAccessibility(decl);
if (!Options.SkipIntroducerKeywords)
Printer << "enum ";
recordDeclLoc(decl,
[&]{
printNominalDeclName(decl);
});
printInherited(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 << "enum ";
recordDeclLoc(decl,
[&]{
printNominalDeclName(decl);
});
printInherited(decl);
}
if (Options.TypeDefinitions) {
printMembersOfDecl(decl);
}
Expand All @@ -1427,13 +1439,20 @@ void PrintAST::visitStructDecl(StructDecl *decl) {
printDocumentationComment(decl);
printAttributes(decl);
printAccessibility(decl);
if (!Options.SkipIntroducerKeywords)
Printer << "struct ";
recordDeclLoc(decl,
[&]{
printNominalDeclName(decl);
});
printInherited(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 << "struct ";
recordDeclLoc(decl,
[&]{
printNominalDeclName(decl);
});
printInherited(decl);
}
if (Options.TypeDefinitions) {
printMembersOfDecl(decl);
}
Expand All @@ -1443,14 +1462,21 @@ void PrintAST::visitClassDecl(ClassDecl *decl) {
printDocumentationComment(decl);
printAttributes(decl);
printAccessibility(decl);
if (!Options.SkipIntroducerKeywords)
Printer << "class ";
recordDeclLoc(decl,
[&]{
printNominalDeclName(decl);
});

printInherited(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 << "class ";
recordDeclLoc(decl,
[&]{
printNominalDeclName(decl);
});

printInherited(decl);
}

if (Options.TypeDefinitions) {
printMembersOfDecl(decl);
Expand All @@ -1461,30 +1487,37 @@ void PrintAST::visitProtocolDecl(ProtocolDecl *decl) {
printDocumentationComment(decl);
printAttributes(decl);
printAccessibility(decl);
if (!Options.SkipIntroducerKeywords)
Printer << "protocol ";
recordDeclLoc(decl,
[&]{
printNominalDeclName(decl);
});

// Figure out whether we need an explicit 'class' in the inheritance.
bool explicitClass = false;
if (decl->requiresClass() && !decl->isObjC()) {
bool inheritsRequiresClass = false;
for (auto proto : decl->getLocalProtocols(
ConformanceLookupKind::OnlyExplicit)) {
if (proto->requiresClass()) {
inheritsRequiresClass = true;
break;
if (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 << "protocol ";
recordDeclLoc(decl,
[&]{
printNominalDeclName(decl);
});

// Figure out whether we need an explicit 'class' in the inheritance.
bool explicitClass = false;
if (decl->requiresClass() && !decl->isObjC()) {
bool inheritsRequiresClass = false;
for (auto proto : decl->getLocalProtocols(
ConformanceLookupKind::OnlyExplicit)) {
if (proto->requiresClass()) {
inheritsRequiresClass = true;
break;
}
}

if (!inheritsRequiresClass)
explicitClass = true;
}

if (!inheritsRequiresClass)
explicitClass = true;
printInherited(decl, explicitClass);
}

printInherited(decl, explicitClass);
if (Options.TypeDefinitions) {
printMembersOfDecl(decl);
}
Expand Down Expand Up @@ -1791,36 +1824,52 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) {
printDocumentationComment(decl);
printAttributes(decl);
printAccessibility(decl);
if (!Options.SkipIntroducerKeywords) {
if (decl->isStatic() && !decl->isOperator())
printStaticKeyword(decl->getCorrectStaticSpelling());
if (decl->isMutating() && !decl->getAttrs().hasAttribute<MutatingAttr>())
Printer << "mutating ";
Printer << "func ";
}
recordDeclLoc(decl,
[&]{
if (!decl->hasName())
Printer << "<anonymous>";
else
Printer.printName(decl->getName());
if (decl->isGeneric()) {
printGenericParams(decl->getGenericParams());
}

printFunctionParameters(decl);
});
if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) {
ASTContext &Ctx = decl->getASTContext();
SourceLoc StartLoc = decl->getStartLoc();
SourceLoc EndLoc;
if (!decl->getBodyResultTypeLoc().isNull()) {
EndLoc = decl->getBodyResultTypeLoc().getSourceRange().End;
} else {
EndLoc = decl->getSignatureSourceRange().End;
}
CharSourceRange Range =
Lexer::getCharSourceRangeFromSourceRange(Ctx.SourceMgr,
SourceRange(StartLoc, EndLoc));
printSourceRange(Range, Ctx);
} else {
if (!Options.SkipIntroducerKeywords) {
if (decl->isStatic() && !decl->isOperator())
printStaticKeyword(decl->getCorrectStaticSpelling());
if (decl->isMutating() && !decl->getAttrs().hasAttribute<MutatingAttr>())
Printer << "mutating ";
Printer << "func ";
}
recordDeclLoc(decl,
[&]{
if (!decl->hasName())
Printer << "<anonymous>";
else
Printer.printName(decl->getName());
if (decl->isGeneric()) {
printGenericParams(decl->getGenericParams());
}

auto &Context = decl->getASTContext();
Type ResultTy = decl->getResultType();
if (ResultTy && !ResultTy->isEqual(TupleType::getEmpty(Context))) {
Printer << " -> ";
if (Options.pTransformer) {
ResultTy = Options.pTransformer->transformByName(ResultTy);
PrintOptions FreshOptions;
ResultTy->print(Printer, FreshOptions);
} else
ResultTy->print(Printer, Options);
printFunctionParameters(decl);
});

auto &Context = decl->getASTContext();
Type ResultTy = decl->getResultType();
if (ResultTy && !ResultTy->isEqual(TupleType::getEmpty(Context))) {
Printer << " -> ";
if (Options.pTransformer) {
ResultTy = Options.pTransformer->transformByName(ResultTy);
PrintOptions FreshOptions;
ResultTy->print(Printer, FreshOptions);
} else
ResultTy->print(Printer, Options);
}
}

if (!Options.FunctionDefinitions || !decl->getBody()) {
Expand Down
14 changes: 14 additions & 0 deletions test/IDE/print_source_file_interface_preserve.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
public protocol Prot {}

public struct Yoda<
Base : GeneratorType
> : Prot {
public func down<U>(
p: Array<U>
) -> Array<U> {
return p
}
}

// RUN: %target-swift-ide-test -print-swift-file-interface -print-original-source -source-filename %s > %t.out
// RUN: diff -u %s.result %t.out
12 changes: 12 additions & 0 deletions test/IDE/print_source_file_interface_preserve.swift.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

public protocol Prot {
}

public struct Yoda<
Base : GeneratorType
> : Prot {

public func down<U>(
p: Array<U>
) -> Array<U>
}
13 changes: 11 additions & 2 deletions tools/swift-ide-test/swift-ide-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,11 @@ PrintRegularComments("print-regular-comments",
llvm::cl::desc("Print regular comments from clang module headers"),
llvm::cl::init(false));

static llvm::cl::opt<bool>
PrintOriginalSourceText("print-original-source",
llvm::cl::desc("print the original source text for applicable declarations"),
llvm::cl::init(false));

static llvm::cl::opt<std::string>
CommentsXMLSchema("comments-xml-schema",
llvm::cl::desc("Filename of the RelaxNG schema for documentation comments"));
Expand Down Expand Up @@ -1801,6 +1806,8 @@ static int doPrintSwiftFileInterface(const CompilerInvocation &InitInvok,
Printer.reset(new StreamPrinter(llvm::outs()));

PrintOptions Options = PrintOptions::printSwiftFileInterface();
if (options::PrintOriginalSourceText)
Options.PrintOriginalSourceText = true;
printSwiftSourceInterface(*CI.getPrimarySourceFile(), *Printer, Options);

return 0;
Expand Down Expand Up @@ -2561,8 +2568,10 @@ int main(int argc, char *argv[]) {
= PrintOptions::ArgAndParamPrintingMode::ArgumentOnly;
}
}
PrintOpts.SkipUnderscoredStdlibProtocols =
options::SkipUnderscoredStdlibProtocols;
if (options::SkipUnderscoredStdlibProtocols)
PrintOpts.SkipUnderscoredStdlibProtocols = true;
if (options::PrintOriginalSourceText)
PrintOpts.PrintOriginalSourceText = true;

if (PrintOpts.PrintDocumentationComments) {
InitInvok.getLangOptions().AttachCommentsToDecls = true;
Expand Down

0 comments on commit 8659022

Please sign in to comment.