diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 0873825ea4e2a92ea5e6f3622e0120fd7d834bbd..7442959201b2af6cd550d3b55816f0a27cb981ee 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/CommentVisitor.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclVisitor.h" @@ -22,6 +23,7 @@ #include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" using namespace clang; +using namespace clang::comments; //===----------------------------------------------------------------------===// // ASTDumper Visitor @@ -29,9 +31,11 @@ using namespace clang; namespace { class ASTDumper - : public DeclVisitor<ASTDumper>, public StmtVisitor<ASTDumper> { - SourceManager *SM; + : public DeclVisitor<ASTDumper>, public StmtVisitor<ASTDumper>, + public ConstCommentVisitor<ASTDumper> { raw_ostream &OS; + const CommandTraits *Traits; + const SourceManager *SM; unsigned IndentLevel; bool IsFirstLine; @@ -40,6 +44,9 @@ namespace { const char *LastLocFilename; unsigned LastLocLine; + /// The \c FullComment parent of the comment being dumped. + const FullComment *FC; + class IndentScope { ASTDumper &Dumper; public: @@ -52,9 +59,10 @@ namespace { }; public: - ASTDumper(SourceManager *SM, raw_ostream &OS) - : SM(SM), OS(OS), IndentLevel(0), IsFirstLine(true), - LastLocFilename(""), LastLocLine(~0U) { } + ASTDumper(raw_ostream &OS, const CommandTraits *Traits, + const SourceManager *SM) + : OS(OS), Traits(Traits), SM(SM), IndentLevel(0), IsFirstLine(true), + LastLocFilename(""), LastLocLine(~0U), FC(0) { } ~ASTDumper() { OS << "\n"; @@ -62,6 +70,7 @@ namespace { void dumpDecl(Decl *D); void dumpStmt(Stmt *S); + void dumpFullComment(const FullComment *C); // Utilities void indent(); @@ -188,6 +197,24 @@ namespace { void VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); void VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node); + + // Comments. + const char *getCommandName(unsigned CommandID); + void dumpComment(const Comment *C); + + // Inline comments. + void visitTextComment(const TextComment *C); + void visitInlineCommandComment(const InlineCommandComment *C); + void visitHTMLStartTagComment(const HTMLStartTagComment *C); + void visitHTMLEndTagComment(const HTMLEndTagComment *C); + + // Block comments. + void visitBlockCommandComment(const BlockCommandComment *C); + void visitParamCommandComment(const ParamCommandComment *C); + void visitTParamCommandComment(const TParamCommandComment *C); + void visitVerbatimBlockComment(const VerbatimBlockComment *C); + void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); + void visitVerbatimLineComment(const VerbatimLineComment *C); }; } @@ -446,6 +473,7 @@ void ASTDumper::dumpDecl(Decl *D) { E = D->getAttrs().end(); I != E; ++I) dumpAttr(*I); } + dumpFullComment(D->getASTContext().getCommentForDecl(D, 0)); // Decls within functions are visited by the body if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D)) dumpDeclContext(dyn_cast<DeclContext>(D)); @@ -1375,6 +1403,145 @@ void ASTDumper::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node) { OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no"); } +//===----------------------------------------------------------------------===// +// Comments +//===----------------------------------------------------------------------===// + +const char *ASTDumper::getCommandName(unsigned CommandID) { + if (Traits) + return Traits->getCommandInfo(CommandID)->Name; + const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID); + if (Info) + return Info->Name; + return "<not a builtin command>"; +} + +void ASTDumper::dumpFullComment(const FullComment *C) { + if (!C) + return; + + FC = C; + dumpComment(C); + FC = 0; +} + +void ASTDumper::dumpComment(const Comment *C) { + IndentScope Indent(*this); + + if (!C) { + OS << "<<<NULL>>>"; + return; + } + + OS << C->getCommentKindName(); + dumpPointer(C); + dumpSourceRange(C->getSourceRange()); + ConstCommentVisitor<ASTDumper>::visit(C); + for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); + I != E; ++I) + dumpComment(*I); +} + +void ASTDumper::visitTextComment(const TextComment *C) { + OS << " Text=\"" << C->getText() << "\""; +} + +void ASTDumper::visitInlineCommandComment(const InlineCommandComment *C) { + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; + switch (C->getRenderKind()) { + case InlineCommandComment::RenderNormal: + OS << " RenderNormal"; + break; + case InlineCommandComment::RenderBold: + OS << " RenderBold"; + break; + case InlineCommandComment::RenderMonospaced: + OS << " RenderMonospaced"; + break; + case InlineCommandComment::RenderEmphasized: + OS << " RenderEmphasized"; + break; + } + + for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) + OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; +} + +void ASTDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) { + OS << " Name=\"" << C->getTagName() << "\""; + if (C->getNumAttrs() != 0) { + OS << " Attrs: "; + for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) { + const HTMLStartTagComment::Attribute &Attr = C->getAttr(i); + OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\""; + } + } + if (C->isSelfClosing()) + OS << " SelfClosing"; +} + +void ASTDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) { + OS << " Name=\"" << C->getTagName() << "\""; +} + +void ASTDumper::visitBlockCommandComment(const BlockCommandComment *C) { + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; + for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) + OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; +} + +void ASTDumper::visitParamCommandComment(const ParamCommandComment *C) { + OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection()); + + if (C->isDirectionExplicit()) + OS << " explicitly"; + else + OS << " implicitly"; + + if (C->hasParamName()) { + if (C->isParamIndexValid()) + OS << " Param=\"" << C->getParamName(FC) << "\""; + else + OS << " Param=\"" << C->getParamNameAsWritten() << "\""; + } + + if (C->isParamIndexValid()) + OS << " ParamIndex=" << C->getParamIndex(); +} + +void ASTDumper::visitTParamCommandComment(const TParamCommandComment *C) { + if (C->hasParamName()) { + if (C->isPositionValid()) + OS << " Param=\"" << C->getParamName(FC) << "\""; + else + OS << " Param=\"" << C->getParamNameAsWritten() << "\""; + } + + if (C->isPositionValid()) { + OS << " Position=<"; + for (unsigned i = 0, e = C->getDepth(); i != e; ++i) { + OS << C->getIndex(i); + if (i != e - 1) + OS << ", "; + } + OS << ">"; + } +} + +void ASTDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) { + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"" + " CloseName=\"" << C->getCloseName() << "\""; +} + +void ASTDumper::visitVerbatimBlockLineComment( + const VerbatimBlockLineComment *C) { + OS << " Text=\"" << C->getText() << "\""; +} + +void ASTDumper::visitVerbatimLineComment(const VerbatimLineComment *C) { + OS << " Text=\"" << C->getText() << "\""; +} + //===----------------------------------------------------------------------===// // Decl method implementations //===----------------------------------------------------------------------===// @@ -1384,7 +1551,8 @@ void Decl::dump() const { } void Decl::dump(raw_ostream &OS) const { - ASTDumper P(&getASTContext().getSourceManager(), OS); + ASTDumper P(OS, &getASTContext().getCommentCommandTraits(), + &getASTContext().getSourceManager()); P.dumpDecl(const_cast<Decl*>(this)); } @@ -1397,11 +1565,31 @@ void Stmt::dump(SourceManager &SM) const { } void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { - ASTDumper P(&SM, OS); + ASTDumper P(OS, 0, &SM); P.dumpStmt(const_cast<Stmt*>(this)); } void Stmt::dump() const { - ASTDumper P(0, llvm::errs()); + ASTDumper P(llvm::errs(), 0, 0); P.dumpStmt(const_cast<Stmt*>(this)); } + +//===----------------------------------------------------------------------===// +// Comment method implementations +//===----------------------------------------------------------------------===// + +void Comment::dump() const { + dump(llvm::errs(), 0, 0); +} + +void Comment::dump(const ASTContext &Context) const { + dump(llvm::errs(), &Context.getCommentCommandTraits(), + &Context.getSourceManager()); +} + +void Comment::dump(llvm::raw_ostream &OS, const CommandTraits *Traits, + const SourceManager *SM) const { + const FullComment *FC = dyn_cast<FullComment>(this); + ASTDumper D(OS, Traits, SM); + D.dumpFullComment(FC); +} diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index f5e6c9605fce7052dcc3c50e636b993f16ed7a46..923c519d4918de8dc3eb5017d58eb33aab8f66d8 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -12,7 +12,6 @@ add_clang_library(clangAST Comment.cpp CommentBriefParser.cpp CommentCommandTraits.cpp - CommentDumper.cpp CommentLexer.cpp CommentParser.cpp CommentSema.cpp diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index 361f8ac61c2a4bc06d398d0c8eac60783af4e295..ea1a3f737af2edb84f65eb7495ddde624ddacf23 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -32,20 +32,6 @@ const char *Comment::getCommentKindName() const { llvm_unreachable("Unknown comment kind!"); } -void Comment::dump() const { - // It is important that Comment::dump() is defined in a different TU than - // Comment::dump(raw_ostream, SourceManager). If both functions were defined - // in CommentDumper.cpp, that object file would be removed by linker because - // none of its functions are referenced by other object files, despite the - // LLVM_ATTRIBUTE_USED. - dump(llvm::errs(), NULL, NULL); -} - -void Comment::dump(const ASTContext &Context) const { - dump(llvm::errs(), &Context.getCommentCommandTraits(), - &Context.getSourceManager()); -} - namespace { struct good {}; struct bad {}; diff --git a/lib/AST/CommentDumper.cpp b/lib/AST/CommentDumper.cpp deleted file mode 100644 index bd8987203fd508e6897ef2a82ab6cb0d44df119f..0000000000000000000000000000000000000000 --- a/lib/AST/CommentDumper.cpp +++ /dev/null @@ -1,257 +0,0 @@ -//===--- CommentDumper.cpp - Dumping implementation for Comment ASTs ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/CommentVisitor.h" -#include "llvm/Support/raw_ostream.h" - -namespace clang { -namespace comments { - -namespace { -class CommentDumper: public comments::ConstCommentVisitor<CommentDumper> { - raw_ostream &OS; - const CommandTraits *Traits; - const SourceManager *SM; - - /// The \c FullComment parent of the comment being dumped. - const FullComment *FC; - - unsigned IndentLevel; - -public: - CommentDumper(raw_ostream &OS, - const CommandTraits *Traits, - const SourceManager *SM, - const FullComment *FC) : - OS(OS), Traits(Traits), SM(SM), FC(FC), IndentLevel(0) - { } - - void dumpIndent() const { - for (unsigned i = 1, e = IndentLevel; i < e; ++i) - OS << " "; - } - - void dumpLocation(SourceLocation Loc) { - if (SM) - Loc.print(OS, *SM); - } - - void dumpSourceRange(const Comment *C); - - void dumpComment(const Comment *C); - - void dumpSubtree(const Comment *C); - - // Inline content. - void visitTextComment(const TextComment *C); - void visitInlineCommandComment(const InlineCommandComment *C); - void visitHTMLStartTagComment(const HTMLStartTagComment *C); - void visitHTMLEndTagComment(const HTMLEndTagComment *C); - - // Block content. - void visitParagraphComment(const ParagraphComment *C); - void visitBlockCommandComment(const BlockCommandComment *C); - void visitParamCommandComment(const ParamCommandComment *C); - void visitTParamCommandComment(const TParamCommandComment *C); - void visitVerbatimBlockComment(const VerbatimBlockComment *C); - void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); - void visitVerbatimLineComment(const VerbatimLineComment *C); - - void visitFullComment(const FullComment *C); - - const char *getCommandName(unsigned CommandID) { - if (Traits) - return Traits->getCommandInfo(CommandID)->Name; - const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID); - if (Info) - return Info->Name; - return "<not a builtin command>"; - } -}; - -void CommentDumper::dumpSourceRange(const Comment *C) { - if (!SM) - return; - - SourceRange SR = C->getSourceRange(); - - OS << " <"; - dumpLocation(SR.getBegin()); - if (SR.getBegin() != SR.getEnd()) { - OS << ", "; - dumpLocation(SR.getEnd()); - } - OS << ">"; -} - -void CommentDumper::dumpComment(const Comment *C) { - dumpIndent(); - OS << "(" << C->getCommentKindName() - << " " << (const void *) C; - dumpSourceRange(C); -} - -void CommentDumper::dumpSubtree(const Comment *C) { - ++IndentLevel; - if (C) { - visit(C); - for (Comment::child_iterator I = C->child_begin(), - E = C->child_end(); - I != E; ++I) { - OS << '\n'; - dumpSubtree(*I); - } - OS << ')'; - } else { - dumpIndent(); - OS << "<<<NULL>>>"; - } - --IndentLevel; -} - -void CommentDumper::visitTextComment(const TextComment *C) { - dumpComment(C); - - OS << " Text=\"" << C->getText() << "\""; -} - -void CommentDumper::visitInlineCommandComment(const InlineCommandComment *C) { - dumpComment(C); - - OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; - switch (C->getRenderKind()) { - case InlineCommandComment::RenderNormal: - OS << " RenderNormal"; - break; - case InlineCommandComment::RenderBold: - OS << " RenderBold"; - break; - case InlineCommandComment::RenderMonospaced: - OS << " RenderMonospaced"; - break; - case InlineCommandComment::RenderEmphasized: - OS << " RenderEmphasized"; - break; - } - - for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) - OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; -} - -void CommentDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) { - dumpComment(C); - - OS << " Name=\"" << C->getTagName() << "\""; - if (C->getNumAttrs() != 0) { - OS << " Attrs: "; - for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) { - const HTMLStartTagComment::Attribute &Attr = C->getAttr(i); - OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\""; - } - } - if (C->isSelfClosing()) - OS << " SelfClosing"; -} - -void CommentDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) { - dumpComment(C); - - OS << " Name=\"" << C->getTagName() << "\""; -} - -void CommentDumper::visitParagraphComment(const ParagraphComment *C) { - dumpComment(C); -} - -void CommentDumper::visitBlockCommandComment(const BlockCommandComment *C) { - dumpComment(C); - - OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; - for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) - OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; -} - -void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) { - dumpComment(C); - - OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection()); - - if (C->isDirectionExplicit()) - OS << " explicitly"; - else - OS << " implicitly"; - - if (C->hasParamName()) { - if (C->isParamIndexValid()) - OS << " Param=\"" << C->getParamName(FC) << "\""; - else - OS << " Param=\"" << C->getParamNameAsWritten() << "\""; - } - - if (C->isParamIndexValid()) - OS << " ParamIndex=" << C->getParamIndex(); -} - -void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) { - dumpComment(C); - - if (C->hasParamName()) { - if (C->isPositionValid()) - OS << " Param=\"" << C->getParamName(FC) << "\""; - else - OS << " Param=\"" << C->getParamNameAsWritten() << "\""; - } - - if (C->isPositionValid()) { - OS << " Position=<"; - for (unsigned i = 0, e = C->getDepth(); i != e; ++i) { - OS << C->getIndex(i); - if (i != e - 1) - OS << ", "; - } - OS << ">"; - } -} - -void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) { - dumpComment(C); - - OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"" - " CloseName=\"" << C->getCloseName() << "\""; -} - -void CommentDumper::visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C) { - dumpComment(C); - - OS << " Text=\"" << C->getText() << "\""; -} - -void CommentDumper::visitVerbatimLineComment(const VerbatimLineComment *C) { - dumpComment(C); - - OS << " Text=\"" << C->getText() << "\""; -} - -void CommentDumper::visitFullComment(const FullComment *C) { - dumpComment(C); -} - -} // unnamed namespace - -void Comment::dump(raw_ostream &OS, const CommandTraits *Traits, - const SourceManager *SM) const { - const FullComment *FC = dyn_cast<FullComment>(this); - CommentDumper D(llvm::errs(), Traits, SM, FC); - D.dumpSubtree(this); - llvm::errs() << '\n'; -} - -} // end namespace comments -} // end namespace clang - diff --git a/test/Misc/ast-dump-comment.cpp b/test/Misc/ast-dump-comment.cpp new file mode 100644 index 0000000000000000000000000000000000000000..072348ca84ad5e13db464ae7e2bd4a906259b394 --- /dev/null +++ b/test/Misc/ast-dump-comment.cpp @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -Wdocumentation -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s + +/// Aaa +int TestLocation; +// CHECK: VarDecl{{.*}}TestLocation +// CHECK-NEXT: FullComment 0x{{[^ ]*}} <line:[[@LINE-3]]:4, col:7> + +/// +int TestIndent; +// CHECK: {{^\(VarDecl.*TestIndent[^()]*$}} +// CHECK-NEXT: {{^ \(FullComment.*>\)\)$}} + +/// Aaa +int Test_TextComment; +// CHECK: VarDecl{{.*}}Test_TextComment +// CHECK-NEXT: FullComment +// CHECK-NEXT: ParagraphComment +// CHECK-NEXT: TextComment{{.*}} Text=" Aaa" + +/// \brief Aaa +int Test_BlockCommandComment; +// CHECK: VarDecl{{.*}}Test_BlockCommandComment +// CHECK: BlockCommandComment{{.*}} Name="brief" +// CHECK-NEXT: ParagraphComment +// CHECK-NEXT: TextComment{{.*}} Text=" Aaa" + +/// \param Aaa xxx +/// \param [in,out] Bbb yyy +void Test_ParamCommandComment(int Aaa, int Bbb); +// CHECK: FunctionDecl{{.*}}Test_ParamCommandComment +// CHECK: ParamCommandComment{{.*}} [in] implicitly Param="Aaa" ParamIndex=0 +// CHECK-NEXT: ParagraphComment +// CHECK-NEXT: TextComment{{.*}} Text=" xxx" +// CHECK: ParamCommandComment{{.*}} [in,out] explicitly Param="Bbb" ParamIndex=1 +// CHECK-NEXT: ParagraphComment +// CHECK-NEXT: TextComment{{.*}} Text=" yyy" + +/// \tparam Aaa xxx +template <typename Aaa> class Test_TParamCommandComment; +// CHECK: ClassTemplateDecl{{.*}}Test_TParamCommandComment +// CHECK: TParamCommandComment{{.*}} Param="Aaa" Position=<0> +// CHECK-NEXT: ParagraphComment +// CHECK-NEXT: TextComment{{.*}} Text=" xxx" + +/// \c Aaa +int Test_InlineCommandComment; +// CHECK: VarDecl{{.*}}Test_InlineCommandComment +// CHECK: InlineCommandComment{{.*}} Name="c" RenderMonospaced Arg[0]="Aaa" + +/// <a>Aaa</a> +/// <br/> +int Test_HTMLTagComment; +// CHECK: VarDecl{{.*}}Test_HTMLTagComment +// CHECK-NEXT: FullComment +// CHECK-NEXT: ParagraphComment +// CHECK-NEXT: TextComment{{.*}} Text=" " +// CHECK-NEXT: HTMLStartTagComment{{.*}} Name="a" +// CHECK-NEXT: TextComment{{.*}} Text="Aaa" +// CHECK-NEXT: HTMLEndTagComment{{.*}} Name="a" +// CHECK-NEXT: TextComment{{.*}} Text=" " +// CHECK-NEXT: HTMLStartTagComment{{.*}} Name="br" SelfClosing + +/// \verbatim +/// Aaa +/// \endverbatim +int Test_VerbatimBlockComment; +// CHECK: VarDecl{{.*}}Test_VerbatimBlockComment +// CHECK: VerbatimBlockComment{{.*}} Name="verbatim" CloseName="endverbatim" +// CHECK-NEXT: VerbatimBlockLineComment{{.*}} Text=" Aaa"