Skip to content

Commit 5c29920

Browse files
committed
[ASTPrinter] Simplify callbacks by dropping the notion of 'pending' callbacks
The three varieties of 'pending callbacks' made it hard to reason about how callbacks would be presented to subclasses of ASTPrinter. I recently added new callbacks that would have made this even more complex to deal with. Luckily, it turns out they weren't buying us much, and simply forcing any pending newlines and indentation to be printed ahead of making callbacks was almost identical to the old behaviour. One complication is that we now need to check for clang doc comments up front so we will emit a newline in the right place. This also incidentally fixed a bug in Loc vs Decl callback order.
1 parent 9e62009 commit 5c29920

File tree

3 files changed

+52
-75
lines changed

3 files changed

+52
-75
lines changed

include/swift/AST/ASTPrinter.h

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,6 @@ enum class PrintStructureKind {
6767
class ASTPrinter {
6868
unsigned CurrentIndentation = 0;
6969
unsigned PendingNewlines = 0;
70-
/// The queue of pending printDeclPre callbacks that will be run when we print
71-
/// a non-whitespace character.
72-
SmallVector<const Decl *, 4> PendingDeclPreCallbacks;
73-
const Decl *PendingDeclLocCallback = nullptr;
74-
Optional<PrintNameContext> PendingNamePreCallback;
7570
const NominalTypeDecl *SynthesizeTarget = nullptr;
7671

7772
void printTextImpl(StringRef Text);
@@ -192,60 +187,51 @@ class ASTPrinter {
192187
PendingNewlines++;
193188
}
194189

190+
void forceNewlines() {
191+
if (PendingNewlines > 0) {
192+
llvm::SmallString<16> Str;
193+
for (unsigned i = 0; i != PendingNewlines; ++i)
194+
Str += '\n';
195+
PendingNewlines = 0;
196+
printText(Str);
197+
printIndent();
198+
}
199+
}
200+
195201
virtual void printIndent();
196202

197203
// MARK: Callback interface wrappers that perform ASTPrinter bookkeeping.
198204

199-
/// Schedule a \c printDeclPre callback to be called as soon as a
200-
/// non-whitespace character is printed.
201-
void callPrintDeclPre(const Decl *D) {
202-
PendingDeclPreCallbacks.emplace_back(D);
203-
}
205+
/// Make a callback to printDeclPre(), performing any necessary bookeeping.
206+
void callPrintDeclPre(const Decl *D);
204207

205208
/// Make a callback to printDeclPost(), performing any necessary bookeeping.
206209
void callPrintDeclPost(const Decl *D) {
207-
if (!PendingDeclPreCallbacks.empty() &&
208-
PendingDeclPreCallbacks.back() == D) {
209-
// Nothing printed for D; skip both pre and post callbacks.
210-
// Ideally we wouldn't get as far as setting up the callback if we aren't
211-
// going to print anything, but currently that would mean walking the
212-
// children of top-level code decls to determine.
213-
PendingDeclPreCallbacks.pop_back();
214-
return;
215-
}
216210
printDeclPost(D);
217211
}
218212

219213
/// Make a callback to avoidPrintDeclPost(), performing any necessary
220214
/// bookkeeping.
221215
void callAvoidPrintDeclPost(const Decl *D) {
222-
assert((PendingDeclPreCallbacks.empty() ||
223-
PendingDeclPreCallbacks.back() != D) &&
224-
"printDeclPre should not be called on avoided decl");
225216
avoidPrintDeclPost(D);
226217
}
227218

228-
/// Schedule a \c printDeclLoc callback to be called as soon as a
229-
/// non-whitespace character is printed.
219+
/// Make a callback to printDeclLoc(), performing any necessary bookeeping.
230220
void callPrintDeclLoc(const Decl *D) {
231-
assert(!PendingDeclLocCallback && "unexpected nested callPrintDeclLoc");
232-
PendingDeclLocCallback = D;
221+
forceNewlines();
222+
printDeclLoc(D);
233223
}
234224

235-
/// Schedule a \c printNamePre callback to be called as soon as a
236-
/// non-whitespace character is printed.
225+
/// Make a callback to printNamePre(), performing any necessary bookeeping.
237226
void callPrintNamePre(PrintNameContext Context) {
238-
assert(!PendingNamePreCallback && "unexpected nested callPrintNamePre");
239-
PendingNamePreCallback = Context;
227+
forceNewlines();
228+
printNamePre(Context);
240229
}
241230

242231
/// Make a callback to printStructurePre(), performing any necessary
243232
/// bookkeeping.
244233
void callPrintStructurePre(PrintStructureKind Kind, const Decl *D = nullptr) {
245-
// FIXME: As a hack, print an empty string to force the pending callbacks.
246-
// The real fix is to incorporate the structure kinds into the pending
247-
// callbacks, interleaved with the decls.
248-
printTextImpl("");
234+
forceNewlines();
249235
printStructurePre(Kind, D);
250236
}
251237

lib/AST/ASTPrinter.cpp

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -481,37 +481,7 @@ void ASTPrinter::printIndent() {
481481
}
482482

483483
void ASTPrinter::printTextImpl(StringRef Text) {
484-
if (PendingNewlines != 0) {
485-
llvm::SmallString<16> Str;
486-
for (unsigned i = 0; i != PendingNewlines; ++i)
487-
Str += '\n';
488-
PendingNewlines = 0;
489-
490-
printText(Str);
491-
printIndent();
492-
}
493-
494-
// Get the pending callbacks and remove them from the printer. They must all
495-
// be removed before calling any of them to ensure correct ordering.
496-
auto pendingDeclPre = PendingDeclPreCallbacks;
497-
PendingDeclPreCallbacks.clear();
498-
auto *LocD = PendingDeclLocCallback;
499-
PendingDeclLocCallback = nullptr;
500-
auto NameContext = PendingNamePreCallback;
501-
PendingNamePreCallback.reset();
502-
503-
// Perform pending callbacks.
504-
for (const Decl *PreD : pendingDeclPre) {
505-
if (SynthesizeTarget && PreD->getKind() == DeclKind::Extension)
506-
printSynthesizedExtensionPre(cast<ExtensionDecl>(PreD), SynthesizeTarget);
507-
else
508-
printDeclPre(PreD);
509-
}
510-
if (LocD)
511-
printDeclLoc(LocD);
512-
if (NameContext)
513-
printNamePre(*NameContext);
514-
484+
forceNewlines();
515485
printText(Text);
516486
}
517487

@@ -529,6 +499,15 @@ void ASTPrinter::printModuleRef(ModuleEntity Mod, Identifier Name) {
529499
printName(Name);
530500
}
531501

502+
void ASTPrinter::callPrintDeclPre(const Decl *D) {
503+
forceNewlines();
504+
505+
if (SynthesizeTarget && D->getKind() == DeclKind::Extension)
506+
printSynthesizedExtensionPre(cast<ExtensionDecl>(D), SynthesizeTarget);
507+
else
508+
printDeclPre(D);
509+
}
510+
532511
ASTPrinter &ASTPrinter::operator<<(unsigned long long N) {
533512
llvm::SmallString<32> Str;
534513
llvm::raw_svector_ostream OS(Str);
@@ -675,11 +654,6 @@ class PrintAST : public ASTVisitor<PrintAST> {
675654
if (!RC)
676655
return;
677656

678-
if (!Options.PrintRegularClangComments) {
679-
Printer.printNewline();
680-
indent();
681-
}
682-
683657
bool Invalid;
684658
unsigned StartLocCol =
685659
ClangContext.getSourceManager().getSpellingColumnNumber(
@@ -882,6 +856,23 @@ class PrintAST : public ASTVisitor<PrintAST> {
882856
D->getKind() == DeclKind::Extension;
883857
if (Synthesize)
884858
Printer.setSynthesizedTarget(Options.TransformContext->getNominal());
859+
860+
// We want to print a newline before doc comments. Swift code already
861+
// handles this, but we need to insert it for clang doc comments when not
862+
// printing other clang comments. Do it now so the printDeclPre callback
863+
// happens after the newline.
864+
if (Options.PrintDocumentationComments &&
865+
!Options.PrintRegularClangComments &&
866+
D->hasClangNode()) {
867+
auto clangNode = D->getClangNode();
868+
auto clangDecl = clangNode.getAsDecl();
869+
if (clangDecl &&
870+
clangDecl->getASTContext().getRawCommentForAnyRedecl(clangDecl)) {
871+
Printer.printNewline();
872+
indent();
873+
}
874+
}
875+
885876
Printer.callPrintDeclPre(D);
886877
ASTVisitor::visit(D);
887878
if (Synthesize) {

test/IDE/Inputs/mock-sdk/Foo.annotated.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,17 +195,17 @@ class <loc>FooClassDerived</loc> : <ref:Class>FooClassBase</ref>, <ref:Protocol>
195195
<decl:Constructor><loc>init()</loc></decl>
196196
<decl:Constructor><loc>init(<decl:Param>x: <ref:Struct>Int32</ref></decl>)</loc></decl>
197197
}</decl>
198-
<decl:Extension>extension <ref:Class><loc>FooClassBase</ref></loc> {
198+
<decl:Extension>extension <loc><ref:Class>FooClassBase</ref></loc> {
199199
<decl:Func>class func <loc>_internalMeth1()</loc> -> <ref:Protocol>AnyObject</ref>!</decl>
200200
<decl:Func>func <loc>_internalMeth1()</loc> -> <ref:Protocol>AnyObject</ref>!</decl>
201201
}</decl>
202-
<decl:Extension>extension <ref:Class><loc>FooClassBase</ref></loc> {
202+
<decl:Extension>extension <loc><ref:Class>FooClassBase</ref></loc> {
203203
<decl:Func>class func <loc>_internalMeth2()</loc> -> <ref:Protocol>AnyObject</ref>!</decl>
204204
<decl:Func>func <loc>_internalMeth2()</loc> -> <ref:Protocol>AnyObject</ref>!</decl>
205205
<decl:Func>class func <loc>nonInternalMeth()</loc> -> <ref:Protocol>AnyObject</ref>!</decl>
206206
<decl:Func>func <loc>nonInternalMeth()</loc> -> <ref:Protocol>AnyObject</ref>!</decl>
207207
}</decl>
208-
<decl:Extension>extension <ref:Class><loc>FooClassBase</ref></loc> {
208+
<decl:Extension>extension <loc><ref:Class>FooClassBase</ref></loc> {
209209
<decl:Func>class func <loc>_internalMeth3()</loc> -> <ref:Protocol>AnyObject</ref>!</decl>
210210
<decl:Func>func <loc>_internalMeth3()</loc> -> <ref:Protocol>AnyObject</ref>!</decl>
211211
}</decl>
@@ -265,11 +265,11 @@ func <loc>FooCFTypeRelease(<decl:Param>_: <ref:Class>FooCFType</ref>!</decl>)</l
265265
<decl:Constructor><loc>init!()</loc></decl>
266266
<decl:Constructor>convenience <loc>init!(<decl:Param>float f: <ref:Struct>Float</ref></decl>)</loc></decl>
267267
}</decl>
268-
<decl:Extension>extension <ref:Class><loc>FooRepeatedMembers</ref></loc> {
268+
<decl:Extension>extension <loc><ref:Class>FooRepeatedMembers</ref></loc> {
269269
<decl:Var>var <loc>repeatedPropertyInCategory</loc>: <ref:Struct>Int32</ref></decl>
270270
<decl:Func>func <loc>repeatedMethodInCategory()</loc></decl>
271271
}</decl>
272-
<decl:Extension>extension <ref:Class><loc>FooRepeatedMembers</ref></loc> {
272+
<decl:Extension>extension <loc><ref:Class>FooRepeatedMembers</ref></loc> {
273273
<decl:Var>var <loc>repeatedPropertyFromCategory</loc>: <ref:Struct>Int32</ref></decl>
274274
<decl:Func>func <loc>repeatedMethodFromCategory()</loc></decl>
275275
}</decl>

0 commit comments

Comments
 (0)