Skip to content

Commit 8659022

Browse files
committed
[ASTPrint] For when printing interface from a source file, introduce an option to
pick up the original source text for the declarations.
1 parent 04e3949 commit 8659022

File tree

5 files changed

+159
-70
lines changed

5 files changed

+159
-70
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ struct PrintOptions {
188188
/// \brief Whether to print regular comments from clang module headers.
189189
bool PrintRegularClangComments = false;
190190

191+
/// When true, printing interface from a source file will print the original
192+
/// source text for applicable declarations, in order to preserve the
193+
/// formatting.
194+
bool PrintOriginalSourceText = false;
195+
191196
/// \brief Print dependent types as references into this generic parameter
192197
/// list.
193198
GenericParamList *ContextGenericParams = nullptr;

lib/AST/ASTPrinter.cpp

Lines changed: 117 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "swift/Basic/Fallthrough.h"
3232
#include "swift/Basic/PrimitiveParsing.h"
3333
#include "swift/Basic/STLExtras.h"
34+
#include "swift/Parse/Lexer.h"
3435
#include "swift/Config.h"
3536
#include "swift/Sema/CodeCompletionTypeChecking.h"
3637
#include "swift/Strings.h"
@@ -292,6 +293,10 @@ class PrintAST : public ASTVisitor<PrintAST> {
292293
Printer.printDeclNameEndLoc(decl);
293294
}
294295

296+
void printSourceRange(CharSourceRange Range, ASTContext &Ctx) {
297+
Printer << Ctx.SourceMgr.extractText(Range);
298+
}
299+
295300
void printClangDocumentationComment(const clang::Decl *D) {
296301
const auto &ClangContext = D->getASTContext();
297302
const clang::RawComment *RC = ClangContext.getRawCommentForAnyRedecl(D);
@@ -1411,13 +1416,20 @@ void PrintAST::visitEnumDecl(EnumDecl *decl) {
14111416
printDocumentationComment(decl);
14121417
printAttributes(decl);
14131418
printAccessibility(decl);
1414-
if (!Options.SkipIntroducerKeywords)
1415-
Printer << "enum ";
1416-
recordDeclLoc(decl,
1417-
[&]{
1418-
printNominalDeclName(decl);
1419-
});
1420-
printInherited(decl);
1419+
1420+
if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) {
1421+
ASTContext &Ctx = decl->getASTContext();
1422+
printSourceRange(CharSourceRange(Ctx.SourceMgr, decl->getStartLoc(),
1423+
decl->getBraces().Start.getAdvancedLoc(-1)), Ctx);
1424+
} else {
1425+
if (!Options.SkipIntroducerKeywords)
1426+
Printer << "enum ";
1427+
recordDeclLoc(decl,
1428+
[&]{
1429+
printNominalDeclName(decl);
1430+
});
1431+
printInherited(decl);
1432+
}
14211433
if (Options.TypeDefinitions) {
14221434
printMembersOfDecl(decl);
14231435
}
@@ -1427,13 +1439,20 @@ void PrintAST::visitStructDecl(StructDecl *decl) {
14271439
printDocumentationComment(decl);
14281440
printAttributes(decl);
14291441
printAccessibility(decl);
1430-
if (!Options.SkipIntroducerKeywords)
1431-
Printer << "struct ";
1432-
recordDeclLoc(decl,
1433-
[&]{
1434-
printNominalDeclName(decl);
1435-
});
1436-
printInherited(decl);
1442+
1443+
if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) {
1444+
ASTContext &Ctx = decl->getASTContext();
1445+
printSourceRange(CharSourceRange(Ctx.SourceMgr, decl->getStartLoc(),
1446+
decl->getBraces().Start.getAdvancedLoc(-1)), Ctx);
1447+
} else {
1448+
if (!Options.SkipIntroducerKeywords)
1449+
Printer << "struct ";
1450+
recordDeclLoc(decl,
1451+
[&]{
1452+
printNominalDeclName(decl);
1453+
});
1454+
printInherited(decl);
1455+
}
14371456
if (Options.TypeDefinitions) {
14381457
printMembersOfDecl(decl);
14391458
}
@@ -1443,14 +1462,21 @@ void PrintAST::visitClassDecl(ClassDecl *decl) {
14431462
printDocumentationComment(decl);
14441463
printAttributes(decl);
14451464
printAccessibility(decl);
1446-
if (!Options.SkipIntroducerKeywords)
1447-
Printer << "class ";
1448-
recordDeclLoc(decl,
1449-
[&]{
1450-
printNominalDeclName(decl);
1451-
});
14521465

1453-
printInherited(decl);
1466+
if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) {
1467+
ASTContext &Ctx = decl->getASTContext();
1468+
printSourceRange(CharSourceRange(Ctx.SourceMgr, decl->getStartLoc(),
1469+
decl->getBraces().Start.getAdvancedLoc(-1)), Ctx);
1470+
} else {
1471+
if (!Options.SkipIntroducerKeywords)
1472+
Printer << "class ";
1473+
recordDeclLoc(decl,
1474+
[&]{
1475+
printNominalDeclName(decl);
1476+
});
1477+
1478+
printInherited(decl);
1479+
}
14541480

14551481
if (Options.TypeDefinitions) {
14561482
printMembersOfDecl(decl);
@@ -1461,30 +1487,37 @@ void PrintAST::visitProtocolDecl(ProtocolDecl *decl) {
14611487
printDocumentationComment(decl);
14621488
printAttributes(decl);
14631489
printAccessibility(decl);
1464-
if (!Options.SkipIntroducerKeywords)
1465-
Printer << "protocol ";
1466-
recordDeclLoc(decl,
1467-
[&]{
1468-
printNominalDeclName(decl);
1469-
});
14701490

1471-
// Figure out whether we need an explicit 'class' in the inheritance.
1472-
bool explicitClass = false;
1473-
if (decl->requiresClass() && !decl->isObjC()) {
1474-
bool inheritsRequiresClass = false;
1475-
for (auto proto : decl->getLocalProtocols(
1476-
ConformanceLookupKind::OnlyExplicit)) {
1477-
if (proto->requiresClass()) {
1478-
inheritsRequiresClass = true;
1479-
break;
1491+
if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) {
1492+
ASTContext &Ctx = decl->getASTContext();
1493+
printSourceRange(CharSourceRange(Ctx.SourceMgr, decl->getStartLoc(),
1494+
decl->getBraces().Start.getAdvancedLoc(-1)), Ctx);
1495+
} else {
1496+
if (!Options.SkipIntroducerKeywords)
1497+
Printer << "protocol ";
1498+
recordDeclLoc(decl,
1499+
[&]{
1500+
printNominalDeclName(decl);
1501+
});
1502+
1503+
// Figure out whether we need an explicit 'class' in the inheritance.
1504+
bool explicitClass = false;
1505+
if (decl->requiresClass() && !decl->isObjC()) {
1506+
bool inheritsRequiresClass = false;
1507+
for (auto proto : decl->getLocalProtocols(
1508+
ConformanceLookupKind::OnlyExplicit)) {
1509+
if (proto->requiresClass()) {
1510+
inheritsRequiresClass = true;
1511+
break;
1512+
}
14801513
}
1514+
1515+
if (!inheritsRequiresClass)
1516+
explicitClass = true;
14811517
}
14821518

1483-
if (!inheritsRequiresClass)
1484-
explicitClass = true;
1519+
printInherited(decl, explicitClass);
14851520
}
1486-
1487-
printInherited(decl, explicitClass);
14881521
if (Options.TypeDefinitions) {
14891522
printMembersOfDecl(decl);
14901523
}
@@ -1791,36 +1824,52 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) {
17911824
printDocumentationComment(decl);
17921825
printAttributes(decl);
17931826
printAccessibility(decl);
1794-
if (!Options.SkipIntroducerKeywords) {
1795-
if (decl->isStatic() && !decl->isOperator())
1796-
printStaticKeyword(decl->getCorrectStaticSpelling());
1797-
if (decl->isMutating() && !decl->getAttrs().hasAttribute<MutatingAttr>())
1798-
Printer << "mutating ";
1799-
Printer << "func ";
1800-
}
1801-
recordDeclLoc(decl,
1802-
[&]{
1803-
if (!decl->hasName())
1804-
Printer << "<anonymous>";
1805-
else
1806-
Printer.printName(decl->getName());
1807-
if (decl->isGeneric()) {
1808-
printGenericParams(decl->getGenericParams());
1809-
}
18101827

1811-
printFunctionParameters(decl);
1812-
});
1828+
if (Options.PrintOriginalSourceText && decl->getStartLoc().isValid()) {
1829+
ASTContext &Ctx = decl->getASTContext();
1830+
SourceLoc StartLoc = decl->getStartLoc();
1831+
SourceLoc EndLoc;
1832+
if (!decl->getBodyResultTypeLoc().isNull()) {
1833+
EndLoc = decl->getBodyResultTypeLoc().getSourceRange().End;
1834+
} else {
1835+
EndLoc = decl->getSignatureSourceRange().End;
1836+
}
1837+
CharSourceRange Range =
1838+
Lexer::getCharSourceRangeFromSourceRange(Ctx.SourceMgr,
1839+
SourceRange(StartLoc, EndLoc));
1840+
printSourceRange(Range, Ctx);
1841+
} else {
1842+
if (!Options.SkipIntroducerKeywords) {
1843+
if (decl->isStatic() && !decl->isOperator())
1844+
printStaticKeyword(decl->getCorrectStaticSpelling());
1845+
if (decl->isMutating() && !decl->getAttrs().hasAttribute<MutatingAttr>())
1846+
Printer << "mutating ";
1847+
Printer << "func ";
1848+
}
1849+
recordDeclLoc(decl,
1850+
[&]{
1851+
if (!decl->hasName())
1852+
Printer << "<anonymous>";
1853+
else
1854+
Printer.printName(decl->getName());
1855+
if (decl->isGeneric()) {
1856+
printGenericParams(decl->getGenericParams());
1857+
}
18131858

1814-
auto &Context = decl->getASTContext();
1815-
Type ResultTy = decl->getResultType();
1816-
if (ResultTy && !ResultTy->isEqual(TupleType::getEmpty(Context))) {
1817-
Printer << " -> ";
1818-
if (Options.pTransformer) {
1819-
ResultTy = Options.pTransformer->transformByName(ResultTy);
1820-
PrintOptions FreshOptions;
1821-
ResultTy->print(Printer, FreshOptions);
1822-
} else
1823-
ResultTy->print(Printer, Options);
1859+
printFunctionParameters(decl);
1860+
});
1861+
1862+
auto &Context = decl->getASTContext();
1863+
Type ResultTy = decl->getResultType();
1864+
if (ResultTy && !ResultTy->isEqual(TupleType::getEmpty(Context))) {
1865+
Printer << " -> ";
1866+
if (Options.pTransformer) {
1867+
ResultTy = Options.pTransformer->transformByName(ResultTy);
1868+
PrintOptions FreshOptions;
1869+
ResultTy->print(Printer, FreshOptions);
1870+
} else
1871+
ResultTy->print(Printer, Options);
1872+
}
18241873
}
18251874

18261875
if (!Options.FunctionDefinitions || !decl->getBody()) {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
public protocol Prot {}
2+
3+
public struct Yoda<
4+
Base : GeneratorType
5+
> : Prot {
6+
public func down<U>(
7+
p: Array<U>
8+
) -> Array<U> {
9+
return p
10+
}
11+
}
12+
13+
// RUN: %target-swift-ide-test -print-swift-file-interface -print-original-source -source-filename %s > %t.out
14+
// RUN: diff -u %s.result %t.out
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
public protocol Prot {
3+
}
4+
5+
public struct Yoda<
6+
Base : GeneratorType
7+
> : Prot {
8+
9+
public func down<U>(
10+
p: Array<U>
11+
) -> Array<U>
12+
}

tools/swift-ide-test/swift-ide-test.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,11 @@ PrintRegularComments("print-regular-comments",
461461
llvm::cl::desc("Print regular comments from clang module headers"),
462462
llvm::cl::init(false));
463463

464+
static llvm::cl::opt<bool>
465+
PrintOriginalSourceText("print-original-source",
466+
llvm::cl::desc("print the original source text for applicable declarations"),
467+
llvm::cl::init(false));
468+
464469
static llvm::cl::opt<std::string>
465470
CommentsXMLSchema("comments-xml-schema",
466471
llvm::cl::desc("Filename of the RelaxNG schema for documentation comments"));
@@ -1801,6 +1806,8 @@ static int doPrintSwiftFileInterface(const CompilerInvocation &InitInvok,
18011806
Printer.reset(new StreamPrinter(llvm::outs()));
18021807

18031808
PrintOptions Options = PrintOptions::printSwiftFileInterface();
1809+
if (options::PrintOriginalSourceText)
1810+
Options.PrintOriginalSourceText = true;
18041811
printSwiftSourceInterface(*CI.getPrimarySourceFile(), *Printer, Options);
18051812

18061813
return 0;
@@ -2561,8 +2568,10 @@ int main(int argc, char *argv[]) {
25612568
= PrintOptions::ArgAndParamPrintingMode::ArgumentOnly;
25622569
}
25632570
}
2564-
PrintOpts.SkipUnderscoredStdlibProtocols =
2565-
options::SkipUnderscoredStdlibProtocols;
2571+
if (options::SkipUnderscoredStdlibProtocols)
2572+
PrintOpts.SkipUnderscoredStdlibProtocols = true;
2573+
if (options::PrintOriginalSourceText)
2574+
PrintOpts.PrintOriginalSourceText = true;
25662575

25672576
if (PrintOpts.PrintDocumentationComments) {
25682577
InitInvok.getLangOptions().AttachCommentsToDecls = true;

0 commit comments

Comments
 (0)