Allow resolving headers from a PCH even after headers+PCH were moved to another path.
[clang.git] / lib / AST / StmtPrinter.cpp
blobfa1736f376823cb3e9811ad605530e30ed55f12d
1 //===--- StmtPrinter.cpp - Printing implementation for Stmt ASTs ----------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Stmt::dumpPretty/Stmt::printPretty methods, which
11 // pretty print the AST back out to C code.
13 //===----------------------------------------------------------------------===//
15 #include "clang/AST/StmtVisitor.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/AST/DeclObjC.h"
18 #include "clang/AST/DeclTemplate.h"
19 #include "clang/AST/PrettyPrinter.h"
20 #include "llvm/Support/Format.h"
21 #include "clang/AST/Expr.h"
22 #include "clang/AST/ExprCXX.h"
23 using namespace clang;
25 //===----------------------------------------------------------------------===//
26 // StmtPrinter Visitor
27 //===----------------------------------------------------------------------===//
29 namespace {
30 class StmtPrinter : public StmtVisitor<StmtPrinter> {
31 llvm::raw_ostream &OS;
32 ASTContext &Context;
33 unsigned IndentLevel;
34 clang::PrinterHelper* Helper;
35 PrintingPolicy Policy;
37 public:
38 StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper,
39 const PrintingPolicy &Policy,
40 unsigned Indentation = 0)
41 : OS(os), Context(C), IndentLevel(Indentation), Helper(helper),
42 Policy(Policy) {}
44 void PrintStmt(Stmt *S) {
45 PrintStmt(S, Policy.Indentation);
48 void PrintStmt(Stmt *S, int SubIndent) {
49 IndentLevel += SubIndent;
50 if (S && isa<Expr>(S)) {
51 // If this is an expr used in a stmt context, indent and newline it.
52 Indent();
53 Visit(S);
54 OS << ";\n";
55 } else if (S) {
56 Visit(S);
57 } else {
58 Indent() << "<<<NULL STATEMENT>>>\n";
60 IndentLevel -= SubIndent;
63 void PrintRawCompoundStmt(CompoundStmt *S);
64 void PrintRawDecl(Decl *D);
65 void PrintRawDeclStmt(DeclStmt *S);
66 void PrintRawIfStmt(IfStmt *If);
67 void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
68 void PrintCallArgs(CallExpr *E);
70 void PrintExpr(Expr *E) {
71 if (E)
72 Visit(E);
73 else
74 OS << "<null expr>";
77 llvm::raw_ostream &Indent(int Delta = 0) {
78 for (int i = 0, e = IndentLevel+Delta; i < e; ++i)
79 OS << " ";
80 return OS;
83 void Visit(Stmt* S) {
84 if (Helper && Helper->handledStmt(S,OS))
85 return;
86 else StmtVisitor<StmtPrinter>::Visit(S);
89 void VisitStmt(Stmt *Node) LLVM_ATTRIBUTE_UNUSED {
90 Indent() << "<<unknown stmt type>>\n";
92 void VisitExpr(Expr *Node) LLVM_ATTRIBUTE_UNUSED {
93 OS << "<<unknown expr type>>";
95 void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
97 #define ABSTRACT_STMT(CLASS)
98 #define STMT(CLASS, PARENT) \
99 void Visit##CLASS(CLASS *Node);
100 #include "clang/AST/StmtNodes.inc"
104 //===----------------------------------------------------------------------===//
105 // Stmt printing methods.
106 //===----------------------------------------------------------------------===//
108 /// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and
109 /// with no newline after the }.
110 void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) {
111 OS << "{\n";
112 for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end();
113 I != E; ++I)
114 PrintStmt(*I);
116 Indent() << "}";
119 void StmtPrinter::PrintRawDecl(Decl *D) {
120 D->print(OS, Policy, IndentLevel);
123 void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) {
124 DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end();
125 llvm::SmallVector<Decl*, 2> Decls;
126 for ( ; Begin != End; ++Begin)
127 Decls.push_back(*Begin);
129 Decl::printGroup(Decls.data(), Decls.size(), OS, Policy, IndentLevel);
132 void StmtPrinter::VisitNullStmt(NullStmt *Node) {
133 Indent() << ";\n";
136 void StmtPrinter::VisitDeclStmt(DeclStmt *Node) {
137 Indent();
138 PrintRawDeclStmt(Node);
139 OS << ";\n";
142 void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) {
143 Indent();
144 PrintRawCompoundStmt(Node);
145 OS << "\n";
148 void StmtPrinter::VisitCaseStmt(CaseStmt *Node) {
149 Indent(-1) << "case ";
150 PrintExpr(Node->getLHS());
151 if (Node->getRHS()) {
152 OS << " ... ";
153 PrintExpr(Node->getRHS());
155 OS << ":\n";
157 PrintStmt(Node->getSubStmt(), 0);
160 void StmtPrinter::VisitDefaultStmt(DefaultStmt *Node) {
161 Indent(-1) << "default:\n";
162 PrintStmt(Node->getSubStmt(), 0);
165 void StmtPrinter::VisitLabelStmt(LabelStmt *Node) {
166 Indent(-1) << Node->getName() << ":\n";
167 PrintStmt(Node->getSubStmt(), 0);
170 void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
171 OS << "if (";
172 PrintExpr(If->getCond());
173 OS << ')';
175 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) {
176 OS << ' ';
177 PrintRawCompoundStmt(CS);
178 OS << (If->getElse() ? ' ' : '\n');
179 } else {
180 OS << '\n';
181 PrintStmt(If->getThen());
182 if (If->getElse()) Indent();
185 if (Stmt *Else = If->getElse()) {
186 OS << "else";
188 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Else)) {
189 OS << ' ';
190 PrintRawCompoundStmt(CS);
191 OS << '\n';
192 } else if (IfStmt *ElseIf = dyn_cast<IfStmt>(Else)) {
193 OS << ' ';
194 PrintRawIfStmt(ElseIf);
195 } else {
196 OS << '\n';
197 PrintStmt(If->getElse());
202 void StmtPrinter::VisitIfStmt(IfStmt *If) {
203 Indent();
204 PrintRawIfStmt(If);
207 void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
208 Indent() << "switch (";
209 PrintExpr(Node->getCond());
210 OS << ")";
212 // Pretty print compoundstmt bodies (very common).
213 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
214 OS << " ";
215 PrintRawCompoundStmt(CS);
216 OS << "\n";
217 } else {
218 OS << "\n";
219 PrintStmt(Node->getBody());
223 void StmtPrinter::VisitWhileStmt(WhileStmt *Node) {
224 Indent() << "while (";
225 PrintExpr(Node->getCond());
226 OS << ")\n";
227 PrintStmt(Node->getBody());
230 void StmtPrinter::VisitDoStmt(DoStmt *Node) {
231 Indent() << "do ";
232 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
233 PrintRawCompoundStmt(CS);
234 OS << " ";
235 } else {
236 OS << "\n";
237 PrintStmt(Node->getBody());
238 Indent();
241 OS << "while (";
242 PrintExpr(Node->getCond());
243 OS << ");\n";
246 void StmtPrinter::VisitForStmt(ForStmt *Node) {
247 Indent() << "for (";
248 if (Node->getInit()) {
249 if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getInit()))
250 PrintRawDeclStmt(DS);
251 else
252 PrintExpr(cast<Expr>(Node->getInit()));
254 OS << ";";
255 if (Node->getCond()) {
256 OS << " ";
257 PrintExpr(Node->getCond());
259 OS << ";";
260 if (Node->getInc()) {
261 OS << " ";
262 PrintExpr(Node->getInc());
264 OS << ") ";
266 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
267 PrintRawCompoundStmt(CS);
268 OS << "\n";
269 } else {
270 OS << "\n";
271 PrintStmt(Node->getBody());
275 void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) {
276 Indent() << "for (";
277 if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getElement()))
278 PrintRawDeclStmt(DS);
279 else
280 PrintExpr(cast<Expr>(Node->getElement()));
281 OS << " in ";
282 PrintExpr(Node->getCollection());
283 OS << ") ";
285 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
286 PrintRawCompoundStmt(CS);
287 OS << "\n";
288 } else {
289 OS << "\n";
290 PrintStmt(Node->getBody());
294 void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
295 Indent() << "goto " << Node->getLabel()->getName() << ";\n";
298 void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) {
299 Indent() << "goto *";
300 PrintExpr(Node->getTarget());
301 OS << ";\n";
304 void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) {
305 Indent() << "continue;\n";
308 void StmtPrinter::VisitBreakStmt(BreakStmt *Node) {
309 Indent() << "break;\n";
313 void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) {
314 Indent() << "return";
315 if (Node->getRetValue()) {
316 OS << " ";
317 PrintExpr(Node->getRetValue());
319 OS << ";\n";
323 void StmtPrinter::VisitAsmStmt(AsmStmt *Node) {
324 Indent() << "asm ";
326 if (Node->isVolatile())
327 OS << "volatile ";
329 OS << "(";
330 VisitStringLiteral(Node->getAsmString());
332 // Outputs
333 if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 ||
334 Node->getNumClobbers() != 0)
335 OS << " : ";
337 for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) {
338 if (i != 0)
339 OS << ", ";
341 if (!Node->getOutputName(i).empty()) {
342 OS << '[';
343 OS << Node->getOutputName(i);
344 OS << "] ";
347 VisitStringLiteral(Node->getOutputConstraintLiteral(i));
348 OS << " ";
349 Visit(Node->getOutputExpr(i));
352 // Inputs
353 if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0)
354 OS << " : ";
356 for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) {
357 if (i != 0)
358 OS << ", ";
360 if (!Node->getInputName(i).empty()) {
361 OS << '[';
362 OS << Node->getInputName(i);
363 OS << "] ";
366 VisitStringLiteral(Node->getInputConstraintLiteral(i));
367 OS << " ";
368 Visit(Node->getInputExpr(i));
371 // Clobbers
372 if (Node->getNumClobbers() != 0)
373 OS << " : ";
375 for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) {
376 if (i != 0)
377 OS << ", ";
379 VisitStringLiteral(Node->getClobber(i));
382 OS << ");\n";
385 void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
386 Indent() << "@try";
387 if (CompoundStmt *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) {
388 PrintRawCompoundStmt(TS);
389 OS << "\n";
392 for (unsigned I = 0, N = Node->getNumCatchStmts(); I != N; ++I) {
393 ObjCAtCatchStmt *catchStmt = Node->getCatchStmt(I);
394 Indent() << "@catch(";
395 if (catchStmt->getCatchParamDecl()) {
396 if (Decl *DS = catchStmt->getCatchParamDecl())
397 PrintRawDecl(DS);
399 OS << ")";
400 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody())) {
401 PrintRawCompoundStmt(CS);
402 OS << "\n";
406 if (ObjCAtFinallyStmt *FS = static_cast<ObjCAtFinallyStmt *>(
407 Node->getFinallyStmt())) {
408 Indent() << "@finally";
409 PrintRawCompoundStmt(dyn_cast<CompoundStmt>(FS->getFinallyBody()));
410 OS << "\n";
414 void StmtPrinter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Node) {
417 void StmtPrinter::VisitObjCAtCatchStmt (ObjCAtCatchStmt *Node) {
418 Indent() << "@catch (...) { /* todo */ } \n";
421 void StmtPrinter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *Node) {
422 Indent() << "@throw";
423 if (Node->getThrowExpr()) {
424 OS << " ";
425 PrintExpr(Node->getThrowExpr());
427 OS << ";\n";
430 void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) {
431 Indent() << "@synchronized (";
432 PrintExpr(Node->getSynchExpr());
433 OS << ")";
434 PrintRawCompoundStmt(Node->getSynchBody());
435 OS << "\n";
438 void StmtPrinter::PrintRawCXXCatchStmt(CXXCatchStmt *Node) {
439 OS << "catch (";
440 if (Decl *ExDecl = Node->getExceptionDecl())
441 PrintRawDecl(ExDecl);
442 else
443 OS << "...";
444 OS << ") ";
445 PrintRawCompoundStmt(cast<CompoundStmt>(Node->getHandlerBlock()));
448 void StmtPrinter::VisitCXXCatchStmt(CXXCatchStmt *Node) {
449 Indent();
450 PrintRawCXXCatchStmt(Node);
451 OS << "\n";
454 void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) {
455 Indent() << "try ";
456 PrintRawCompoundStmt(Node->getTryBlock());
457 for (unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) {
458 OS << " ";
459 PrintRawCXXCatchStmt(Node->getHandler(i));
461 OS << "\n";
464 //===----------------------------------------------------------------------===//
465 // Expr printing methods.
466 //===----------------------------------------------------------------------===//
468 void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
469 if (NestedNameSpecifier *Qualifier = Node->getQualifier())
470 Qualifier->print(OS, Policy);
471 OS << Node->getNameInfo();
472 if (Node->hasExplicitTemplateArgs())
473 OS << TemplateSpecializationType::PrintTemplateArgumentList(
474 Node->getTemplateArgs(),
475 Node->getNumTemplateArgs(),
476 Policy);
479 void StmtPrinter::VisitDependentScopeDeclRefExpr(
480 DependentScopeDeclRefExpr *Node) {
481 if (NestedNameSpecifier *Qualifier = Node->getQualifier())
482 Qualifier->print(OS, Policy);
483 OS << Node->getNameInfo();
484 if (Node->hasExplicitTemplateArgs())
485 OS << TemplateSpecializationType::PrintTemplateArgumentList(
486 Node->getTemplateArgs(),
487 Node->getNumTemplateArgs(),
488 Policy);
491 void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
492 if (Node->getQualifier())
493 Node->getQualifier()->print(OS, Policy);
494 OS << Node->getNameInfo();
495 if (Node->hasExplicitTemplateArgs())
496 OS << TemplateSpecializationType::PrintTemplateArgumentList(
497 Node->getTemplateArgs(),
498 Node->getNumTemplateArgs(),
499 Policy);
502 void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
503 if (Node->getBase()) {
504 PrintExpr(Node->getBase());
505 OS << (Node->isArrow() ? "->" : ".");
507 OS << Node->getDecl();
510 void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
511 if (Node->isSuperReceiver())
512 OS << "super.";
513 else if (Node->getBase()) {
514 PrintExpr(Node->getBase());
515 OS << ".";
518 if (Node->isImplicitProperty())
519 OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
520 else
521 OS << Node->getExplicitProperty()->getName();
524 void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
525 switch (Node->getIdentType()) {
526 default:
527 assert(0 && "unknown case");
528 case PredefinedExpr::Func:
529 OS << "__func__";
530 break;
531 case PredefinedExpr::Function:
532 OS << "__FUNCTION__";
533 break;
534 case PredefinedExpr::PrettyFunction:
535 OS << "__PRETTY_FUNCTION__";
536 break;
540 void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
541 unsigned value = Node->getValue();
542 if (Node->isWide())
543 OS << "L";
544 switch (value) {
545 case '\\':
546 OS << "'\\\\'";
547 break;
548 case '\'':
549 OS << "'\\''";
550 break;
551 case '\a':
552 // TODO: K&R: the meaning of '\\a' is different in traditional C
553 OS << "'\\a'";
554 break;
555 case '\b':
556 OS << "'\\b'";
557 break;
558 // Nonstandard escape sequence.
559 /*case '\e':
560 OS << "'\\e'";
561 break;*/
562 case '\f':
563 OS << "'\\f'";
564 break;
565 case '\n':
566 OS << "'\\n'";
567 break;
568 case '\r':
569 OS << "'\\r'";
570 break;
571 case '\t':
572 OS << "'\\t'";
573 break;
574 case '\v':
575 OS << "'\\v'";
576 break;
577 default:
578 if (value < 256 && isprint(value)) {
579 OS << "'" << (char)value << "'";
580 } else if (value < 256) {
581 OS << "'\\x" << llvm::format("%x", value) << "'";
582 } else {
583 // FIXME what to really do here?
584 OS << value;
589 void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
590 bool isSigned = Node->getType()->isSignedIntegerType();
591 OS << Node->getValue().toString(10, isSigned);
593 // Emit suffixes. Integer literals are always a builtin integer type.
594 switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
595 default: assert(0 && "Unexpected type for integer literal!");
596 case BuiltinType::Int: break; // no suffix.
597 case BuiltinType::UInt: OS << 'U'; break;
598 case BuiltinType::Long: OS << 'L'; break;
599 case BuiltinType::ULong: OS << "UL"; break;
600 case BuiltinType::LongLong: OS << "LL"; break;
601 case BuiltinType::ULongLong: OS << "ULL"; break;
604 void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
605 // FIXME: print value more precisely.
606 OS << Node->getValueAsApproximateDouble();
609 void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) {
610 PrintExpr(Node->getSubExpr());
611 OS << "i";
614 void StmtPrinter::VisitStringLiteral(StringLiteral *Str) {
615 if (Str->isWide()) OS << 'L';
616 OS << '"';
618 // FIXME: this doesn't print wstrings right.
619 llvm::StringRef StrData = Str->getString();
620 for (llvm::StringRef::iterator I = StrData.begin(), E = StrData.end();
621 I != E; ++I) {
622 unsigned char Char = *I;
624 switch (Char) {
625 default:
626 if (isprint(Char))
627 OS << (char)Char;
628 else // Output anything hard as an octal escape.
629 OS << '\\'
630 << (char)('0'+ ((Char >> 6) & 7))
631 << (char)('0'+ ((Char >> 3) & 7))
632 << (char)('0'+ ((Char >> 0) & 7));
633 break;
634 // Handle some common non-printable cases to make dumps prettier.
635 case '\\': OS << "\\\\"; break;
636 case '"': OS << "\\\""; break;
637 case '\n': OS << "\\n"; break;
638 case '\t': OS << "\\t"; break;
639 case '\a': OS << "\\a"; break;
640 case '\b': OS << "\\b"; break;
643 OS << '"';
645 void StmtPrinter::VisitParenExpr(ParenExpr *Node) {
646 OS << "(";
647 PrintExpr(Node->getSubExpr());
648 OS << ")";
650 void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) {
651 if (!Node->isPostfix()) {
652 OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
654 // Print a space if this is an "identifier operator" like __real, or if
655 // it might be concatenated incorrectly like '+'.
656 switch (Node->getOpcode()) {
657 default: break;
658 case UO_Real:
659 case UO_Imag:
660 case UO_Extension:
661 OS << ' ';
662 break;
663 case UO_Plus:
664 case UO_Minus:
665 if (isa<UnaryOperator>(Node->getSubExpr()))
666 OS << ' ';
667 break;
670 PrintExpr(Node->getSubExpr());
672 if (Node->isPostfix())
673 OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
676 void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
677 OS << "__builtin_offsetof(";
678 OS << Node->getTypeSourceInfo()->getType().getAsString(Policy) << ", ";
679 bool PrintedSomething = false;
680 for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) {
681 OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i);
682 if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Array) {
683 // Array node
684 OS << "[";
685 PrintExpr(Node->getIndexExpr(ON.getArrayExprIndex()));
686 OS << "]";
687 PrintedSomething = true;
688 continue;
691 // Skip implicit base indirections.
692 if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base)
693 continue;
695 // Field or identifier node.
696 IdentifierInfo *Id = ON.getFieldName();
697 if (!Id)
698 continue;
700 if (PrintedSomething)
701 OS << ".";
702 else
703 PrintedSomething = true;
704 OS << Id->getName();
706 OS << ")";
709 void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
710 OS << (Node->isSizeOf() ? "sizeof" : "__alignof");
711 if (Node->isArgumentType())
712 OS << "(" << Node->getArgumentType().getAsString(Policy) << ")";
713 else {
714 OS << " ";
715 PrintExpr(Node->getArgumentExpr());
718 void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
719 PrintExpr(Node->getLHS());
720 OS << "[";
721 PrintExpr(Node->getRHS());
722 OS << "]";
725 void StmtPrinter::PrintCallArgs(CallExpr *Call) {
726 for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) {
727 if (isa<CXXDefaultArgExpr>(Call->getArg(i))) {
728 // Don't print any defaulted arguments
729 break;
732 if (i) OS << ", ";
733 PrintExpr(Call->getArg(i));
737 void StmtPrinter::VisitCallExpr(CallExpr *Call) {
738 PrintExpr(Call->getCallee());
739 OS << "(";
740 PrintCallArgs(Call);
741 OS << ")";
743 void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
744 // FIXME: Suppress printing implicit bases (like "this")
745 PrintExpr(Node->getBase());
746 if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
747 if (FD->isAnonymousStructOrUnion())
748 return;
749 OS << (Node->isArrow() ? "->" : ".");
750 if (NestedNameSpecifier *Qualifier = Node->getQualifier())
751 Qualifier->print(OS, Policy);
753 OS << Node->getMemberNameInfo();
755 if (Node->hasExplicitTemplateArgs())
756 OS << TemplateSpecializationType::PrintTemplateArgumentList(
757 Node->getTemplateArgs(),
758 Node->getNumTemplateArgs(),
759 Policy);
761 void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) {
762 PrintExpr(Node->getBase());
763 OS << (Node->isArrow() ? "->isa" : ".isa");
766 void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
767 PrintExpr(Node->getBase());
768 OS << ".";
769 OS << Node->getAccessor().getName();
771 void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) {
772 OS << "(" << Node->getType().getAsString(Policy) << ")";
773 PrintExpr(Node->getSubExpr());
775 void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
776 OS << "(" << Node->getType().getAsString(Policy) << ")";
777 PrintExpr(Node->getInitializer());
779 void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
780 // No need to print anything, simply forward to the sub expression.
781 PrintExpr(Node->getSubExpr());
783 void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) {
784 PrintExpr(Node->getLHS());
785 OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
786 PrintExpr(Node->getRHS());
788 void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
789 PrintExpr(Node->getLHS());
790 OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
791 PrintExpr(Node->getRHS());
793 void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) {
794 PrintExpr(Node->getCond());
796 if (Node->getLHS()) {
797 OS << " ? ";
798 PrintExpr(Node->getLHS());
799 OS << " : ";
801 else { // Handle GCC extension where LHS can be NULL.
802 OS << " ?: ";
805 PrintExpr(Node->getRHS());
808 // GNU extensions.
810 void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) {
811 OS << "&&" << Node->getLabel()->getName();
814 void StmtPrinter::VisitStmtExpr(StmtExpr *E) {
815 OS << "(";
816 PrintRawCompoundStmt(E->getSubStmt());
817 OS << ")";
820 void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) {
821 OS << "__builtin_choose_expr(";
822 PrintExpr(Node->getCond());
823 OS << ", ";
824 PrintExpr(Node->getLHS());
825 OS << ", ";
826 PrintExpr(Node->getRHS());
827 OS << ")";
830 void StmtPrinter::VisitGNUNullExpr(GNUNullExpr *) {
831 OS << "__null";
834 void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) {
835 OS << "__builtin_shufflevector(";
836 for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) {
837 if (i) OS << ", ";
838 PrintExpr(Node->getExpr(i));
840 OS << ")";
843 void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
844 if (Node->getSyntacticForm()) {
845 Visit(Node->getSyntacticForm());
846 return;
849 OS << "{ ";
850 for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
851 if (i) OS << ", ";
852 if (Node->getInit(i))
853 PrintExpr(Node->getInit(i));
854 else
855 OS << "0";
857 OS << " }";
860 void StmtPrinter::VisitParenListExpr(ParenListExpr* Node) {
861 OS << "( ";
862 for (unsigned i = 0, e = Node->getNumExprs(); i != e; ++i) {
863 if (i) OS << ", ";
864 PrintExpr(Node->getExpr(i));
866 OS << " )";
869 void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
870 for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(),
871 DEnd = Node->designators_end();
872 D != DEnd; ++D) {
873 if (D->isFieldDesignator()) {
874 if (D->getDotLoc().isInvalid())
875 OS << D->getFieldName()->getName() << ":";
876 else
877 OS << "." << D->getFieldName()->getName();
878 } else {
879 OS << "[";
880 if (D->isArrayDesignator()) {
881 PrintExpr(Node->getArrayIndex(*D));
882 } else {
883 PrintExpr(Node->getArrayRangeStart(*D));
884 OS << " ... ";
885 PrintExpr(Node->getArrayRangeEnd(*D));
887 OS << "]";
891 OS << " = ";
892 PrintExpr(Node->getInit());
895 void StmtPrinter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) {
896 if (Policy.LangOpts.CPlusPlus)
897 OS << "/*implicit*/" << Node->getType().getAsString(Policy) << "()";
898 else {
899 OS << "/*implicit*/(" << Node->getType().getAsString(Policy) << ")";
900 if (Node->getType()->isRecordType())
901 OS << "{}";
902 else
903 OS << 0;
907 void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
908 OS << "__builtin_va_arg(";
909 PrintExpr(Node->getSubExpr());
910 OS << ", ";
911 OS << Node->getType().getAsString(Policy);
912 OS << ")";
915 // C++
916 void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
917 const char *OpStrings[NUM_OVERLOADED_OPERATORS] = {
919 #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
920 Spelling,
921 #include "clang/Basic/OperatorKinds.def"
924 OverloadedOperatorKind Kind = Node->getOperator();
925 if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) {
926 if (Node->getNumArgs() == 1) {
927 OS << OpStrings[Kind] << ' ';
928 PrintExpr(Node->getArg(0));
929 } else {
930 PrintExpr(Node->getArg(0));
931 OS << ' ' << OpStrings[Kind];
933 } else if (Kind == OO_Call) {
934 PrintExpr(Node->getArg(0));
935 OS << '(';
936 for (unsigned ArgIdx = 1; ArgIdx < Node->getNumArgs(); ++ArgIdx) {
937 if (ArgIdx > 1)
938 OS << ", ";
939 if (!isa<CXXDefaultArgExpr>(Node->getArg(ArgIdx)))
940 PrintExpr(Node->getArg(ArgIdx));
942 OS << ')';
943 } else if (Kind == OO_Subscript) {
944 PrintExpr(Node->getArg(0));
945 OS << '[';
946 PrintExpr(Node->getArg(1));
947 OS << ']';
948 } else if (Node->getNumArgs() == 1) {
949 OS << OpStrings[Kind] << ' ';
950 PrintExpr(Node->getArg(0));
951 } else if (Node->getNumArgs() == 2) {
952 PrintExpr(Node->getArg(0));
953 OS << ' ' << OpStrings[Kind] << ' ';
954 PrintExpr(Node->getArg(1));
955 } else {
956 assert(false && "unknown overloaded operator");
960 void StmtPrinter::VisitCXXMemberCallExpr(CXXMemberCallExpr *Node) {
961 VisitCallExpr(cast<CallExpr>(Node));
964 void StmtPrinter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *Node) {
965 PrintExpr(Node->getCallee());
966 OS << "<<<";
967 PrintCallArgs(Node->getConfig());
968 OS << ">>>(";
969 PrintCallArgs(Node);
970 OS << ")";
973 void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
974 OS << Node->getCastName() << '<';
975 OS << Node->getTypeAsWritten().getAsString(Policy) << ">(";
976 PrintExpr(Node->getSubExpr());
977 OS << ")";
980 void StmtPrinter::VisitCXXStaticCastExpr(CXXStaticCastExpr *Node) {
981 VisitCXXNamedCastExpr(Node);
984 void StmtPrinter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *Node) {
985 VisitCXXNamedCastExpr(Node);
988 void StmtPrinter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *Node) {
989 VisitCXXNamedCastExpr(Node);
992 void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) {
993 VisitCXXNamedCastExpr(Node);
996 void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
997 OS << "typeid(";
998 if (Node->isTypeOperand()) {
999 OS << Node->getTypeOperand().getAsString(Policy);
1000 } else {
1001 PrintExpr(Node->getExprOperand());
1003 OS << ")";
1006 void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) {
1007 OS << "__uuidof(";
1008 if (Node->isTypeOperand()) {
1009 OS << Node->getTypeOperand().getAsString(Policy);
1010 } else {
1011 PrintExpr(Node->getExprOperand());
1013 OS << ")";
1016 void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
1017 OS << (Node->getValue() ? "true" : "false");
1020 void StmtPrinter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *Node) {
1021 OS << "nullptr";
1024 void StmtPrinter::VisitCXXThisExpr(CXXThisExpr *Node) {
1025 OS << "this";
1028 void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) {
1029 if (Node->getSubExpr() == 0)
1030 OS << "throw";
1031 else {
1032 OS << "throw ";
1033 PrintExpr(Node->getSubExpr());
1037 void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) {
1038 // Nothing to print: we picked up the default argument
1041 void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
1042 OS << Node->getType().getAsString(Policy);
1043 OS << "(";
1044 PrintExpr(Node->getSubExpr());
1045 OS << ")";
1048 void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
1049 PrintExpr(Node->getSubExpr());
1052 void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
1053 OS << Node->getType().getAsString(Policy);
1054 OS << "(";
1055 for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
1056 ArgEnd = Node->arg_end();
1057 Arg != ArgEnd; ++Arg) {
1058 if (Arg != Node->arg_begin())
1059 OS << ", ";
1060 PrintExpr(*Arg);
1062 OS << ")";
1065 void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
1066 if (TypeSourceInfo *TSInfo = Node->getTypeSourceInfo())
1067 OS << TSInfo->getType().getAsString(Policy) << "()";
1068 else
1069 OS << Node->getType().getAsString(Policy) << "()";
1072 void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
1073 if (E->isGlobalNew())
1074 OS << "::";
1075 OS << "new ";
1076 unsigned NumPlace = E->getNumPlacementArgs();
1077 if (NumPlace > 0) {
1078 OS << "(";
1079 PrintExpr(E->getPlacementArg(0));
1080 for (unsigned i = 1; i < NumPlace; ++i) {
1081 OS << ", ";
1082 PrintExpr(E->getPlacementArg(i));
1084 OS << ") ";
1086 if (E->isParenTypeId())
1087 OS << "(";
1088 std::string TypeS;
1089 if (Expr *Size = E->getArraySize()) {
1090 llvm::raw_string_ostream s(TypeS);
1091 Size->printPretty(s, Context, Helper, Policy);
1092 s.flush();
1093 TypeS = "[" + TypeS + "]";
1095 E->getAllocatedType().getAsStringInternal(TypeS, Policy);
1096 OS << TypeS;
1097 if (E->isParenTypeId())
1098 OS << ")";
1100 if (E->hasInitializer()) {
1101 OS << "(";
1102 unsigned NumCons = E->getNumConstructorArgs();
1103 if (NumCons > 0) {
1104 PrintExpr(E->getConstructorArg(0));
1105 for (unsigned i = 1; i < NumCons; ++i) {
1106 OS << ", ";
1107 PrintExpr(E->getConstructorArg(i));
1110 OS << ")";
1114 void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
1115 if (E->isGlobalDelete())
1116 OS << "::";
1117 OS << "delete ";
1118 if (E->isArrayForm())
1119 OS << "[] ";
1120 PrintExpr(E->getArgument());
1123 void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
1124 PrintExpr(E->getBase());
1125 if (E->isArrow())
1126 OS << "->";
1127 else
1128 OS << '.';
1129 if (E->getQualifier())
1130 E->getQualifier()->print(OS, Policy);
1132 std::string TypeS;
1133 if (IdentifierInfo *II = E->getDestroyedTypeIdentifier())
1134 OS << II->getName();
1135 else
1136 E->getDestroyedType().getAsStringInternal(TypeS, Policy);
1137 OS << TypeS;
1140 void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
1141 for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
1142 if (isa<CXXDefaultArgExpr>(E->getArg(i))) {
1143 // Don't print any defaulted arguments
1144 break;
1147 if (i) OS << ", ";
1148 PrintExpr(E->getArg(i));
1152 void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
1153 // Just forward to the sub expression.
1154 PrintExpr(E->getSubExpr());
1157 void
1158 StmtPrinter::VisitCXXUnresolvedConstructExpr(
1159 CXXUnresolvedConstructExpr *Node) {
1160 OS << Node->getTypeAsWritten().getAsString(Policy);
1161 OS << "(";
1162 for (CXXUnresolvedConstructExpr::arg_iterator Arg = Node->arg_begin(),
1163 ArgEnd = Node->arg_end();
1164 Arg != ArgEnd; ++Arg) {
1165 if (Arg != Node->arg_begin())
1166 OS << ", ";
1167 PrintExpr(*Arg);
1169 OS << ")";
1172 void StmtPrinter::VisitCXXDependentScopeMemberExpr(
1173 CXXDependentScopeMemberExpr *Node) {
1174 if (!Node->isImplicitAccess()) {
1175 PrintExpr(Node->getBase());
1176 OS << (Node->isArrow() ? "->" : ".");
1178 if (NestedNameSpecifier *Qualifier = Node->getQualifier())
1179 Qualifier->print(OS, Policy);
1180 else if (Node->hasExplicitTemplateArgs())
1181 // FIXME: Track use of "template" keyword explicitly?
1182 OS << "template ";
1184 OS << Node->getMemberNameInfo();
1186 if (Node->hasExplicitTemplateArgs()) {
1187 OS << TemplateSpecializationType::PrintTemplateArgumentList(
1188 Node->getTemplateArgs(),
1189 Node->getNumTemplateArgs(),
1190 Policy);
1194 void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
1195 if (!Node->isImplicitAccess()) {
1196 PrintExpr(Node->getBase());
1197 OS << (Node->isArrow() ? "->" : ".");
1199 if (NestedNameSpecifier *Qualifier = Node->getQualifier())
1200 Qualifier->print(OS, Policy);
1202 // FIXME: this might originally have been written with 'template'
1204 OS << Node->getMemberNameInfo();
1206 if (Node->hasExplicitTemplateArgs()) {
1207 OS << TemplateSpecializationType::PrintTemplateArgumentList(
1208 Node->getTemplateArgs(),
1209 Node->getNumTemplateArgs(),
1210 Policy);
1214 static const char *getTypeTraitName(UnaryTypeTrait UTT) {
1215 switch (UTT) {
1216 default: llvm_unreachable("Unknown unary type trait");
1217 case UTT_HasNothrowAssign: return "__has_nothrow_assign";
1218 case UTT_HasNothrowCopy: return "__has_nothrow_copy";
1219 case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
1220 case UTT_HasTrivialAssign: return "__has_trivial_assign";
1221 case UTT_HasTrivialCopy: return "__has_trivial_copy";
1222 case UTT_HasTrivialConstructor: return "__has_trivial_constructor";
1223 case UTT_HasTrivialDestructor: return "__has_trivial_destructor";
1224 case UTT_HasVirtualDestructor: return "__has_virtual_destructor";
1225 case UTT_IsAbstract: return "__is_abstract";
1226 case UTT_IsClass: return "__is_class";
1227 case UTT_IsEmpty: return "__is_empty";
1228 case UTT_IsEnum: return "__is_enum";
1229 case UTT_IsPOD: return "__is_pod";
1230 case UTT_IsPolymorphic: return "__is_polymorphic";
1231 case UTT_IsUnion: return "__is_union";
1233 return "";
1236 static const char *getTypeTraitName(BinaryTypeTrait BTT) {
1237 switch (BTT) {
1238 case BTT_IsBaseOf: return "__is_base_of";
1239 case BTT_TypeCompatible: return "__builtin_types_compatible_p";
1240 case BTT_IsConvertibleTo: return "__is_convertible_to";
1242 return "";
1245 void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
1246 OS << getTypeTraitName(E->getTrait()) << "("
1247 << E->getQueriedType().getAsString(Policy) << ")";
1250 void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
1251 OS << getTypeTraitName(E->getTrait()) << "("
1252 << E->getLhsType().getAsString(Policy) << ","
1253 << E->getRhsType().getAsString(Policy) << ")";
1256 void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
1257 OS << "noexcept(";
1258 PrintExpr(E->getOperand());
1259 OS << ")";
1262 void StmtPrinter::VisitPackExpansionExpr(PackExpansionExpr *E) {
1263 PrintExpr(E->getPattern());
1264 OS << "...";
1267 void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
1268 OS << "sizeof...(" << E->getPack()->getNameAsString() << ")";
1271 void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
1272 SubstNonTypeTemplateParmPackExpr *Node) {
1273 OS << Node->getParameterPack()->getNameAsString();
1276 // Obj-C
1278 void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
1279 OS << "@";
1280 VisitStringLiteral(Node->getString());
1283 void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
1284 OS << "@encode(" << Node->getEncodedType().getAsString(Policy) << ')';
1287 void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
1288 OS << "@selector(" << Node->getSelector().getAsString() << ')';
1291 void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
1292 OS << "@protocol(" << Node->getProtocol() << ')';
1295 void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
1296 OS << "[";
1297 switch (Mess->getReceiverKind()) {
1298 case ObjCMessageExpr::Instance:
1299 PrintExpr(Mess->getInstanceReceiver());
1300 break;
1302 case ObjCMessageExpr::Class:
1303 OS << Mess->getClassReceiver().getAsString(Policy);
1304 break;
1306 case ObjCMessageExpr::SuperInstance:
1307 case ObjCMessageExpr::SuperClass:
1308 OS << "Super";
1309 break;
1312 OS << ' ';
1313 Selector selector = Mess->getSelector();
1314 if (selector.isUnarySelector()) {
1315 OS << selector.getIdentifierInfoForSlot(0)->getName();
1316 } else {
1317 for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) {
1318 if (i < selector.getNumArgs()) {
1319 if (i > 0) OS << ' ';
1320 if (selector.getIdentifierInfoForSlot(i))
1321 OS << selector.getIdentifierInfoForSlot(i)->getName() << ':';
1322 else
1323 OS << ":";
1325 else OS << ", "; // Handle variadic methods.
1327 PrintExpr(Mess->getArg(i));
1330 OS << "]";
1334 void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
1335 BlockDecl *BD = Node->getBlockDecl();
1336 OS << "^";
1338 const FunctionType *AFT = Node->getFunctionType();
1340 if (isa<FunctionNoProtoType>(AFT)) {
1341 OS << "()";
1342 } else if (!BD->param_empty() || cast<FunctionProtoType>(AFT)->isVariadic()) {
1343 OS << '(';
1344 std::string ParamStr;
1345 for (BlockDecl::param_iterator AI = BD->param_begin(),
1346 E = BD->param_end(); AI != E; ++AI) {
1347 if (AI != BD->param_begin()) OS << ", ";
1348 ParamStr = (*AI)->getNameAsString();
1349 (*AI)->getType().getAsStringInternal(ParamStr, Policy);
1350 OS << ParamStr;
1353 const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
1354 if (FT->isVariadic()) {
1355 if (!BD->param_empty()) OS << ", ";
1356 OS << "...";
1358 OS << ')';
1362 void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
1363 OS << Node->getDecl();
1366 void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {}
1368 //===----------------------------------------------------------------------===//
1369 // Stmt method implementations
1370 //===----------------------------------------------------------------------===//
1372 void Stmt::dumpPretty(ASTContext& Context) const {
1373 printPretty(llvm::errs(), Context, 0,
1374 PrintingPolicy(Context.getLangOptions()));
1377 void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context,
1378 PrinterHelper* Helper,
1379 const PrintingPolicy &Policy,
1380 unsigned Indentation) const {
1381 if (this == 0) {
1382 OS << "<NULL>";
1383 return;
1386 if (Policy.Dump && &Context) {
1387 dump(OS, Context.getSourceManager());
1388 return;
1391 StmtPrinter P(OS, Context, Helper, Policy, Indentation);
1392 P.Visit(const_cast<Stmt*>(this));
1395 //===----------------------------------------------------------------------===//
1396 // PrinterHelper
1397 //===----------------------------------------------------------------------===//
1399 // Implement virtual destructor.
1400 PrinterHelper::~PrinterHelper() {}