Clang默认只分析以 /** 和 ///开头的文档注释,需要通过添加命令行参数-fparse-all-comments分析所有注释。
#include "clang/AST/ASTConsumer.h"#include "clang/AST/RecursiveASTVisitor.h"#include "clang/Frontend/CompilerInstance.h"#include "clang/Frontend/FrontendAction.h"#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"#include "clang/Driver/Options.h"#include "clang/Rewrite/Frontend/FixItRewriter.h"#include "clang/Rewrite/Frontend/FrontendActions.h"#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"#include "clang/Tooling/CommonOptionsParser.h"#include "clang/Tooling/Syntax/BuildTree.h"#include "clang/Tooling/Syntax/Tokens.h"#include "clang/Tooling/Syntax/Tree.h"#include "clang/Tooling/Tooling.h"#include "clang/ASTMatchers/ASTMatchFinder.h"#include "clang/ASTMatchers/ASTMatchers.h"#include "llvm/ADT/STLExtras.h"#include "llvm/Option/OptTable.h"#include "llvm/Support/Path.h"#include "llvm/Support/Signals.h"#include "llvm/Support/TargetSelect.h"using namespace clang;using namespace clang::ast_matchers;using namespace clang::driver;using namespace clang::tooling;using namespace llvm;/// 定义命令行选项static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);static cl::extrahelp MoreHelp( " For example, to run comment
" "
");static cl::OptionCategory ClangCheckCategory("comment options");static const opt::OptTable &Options = getDriverOptTable();static cl::opt VISITORDump("visitor", cl::desc(Options.getOptionHelpText(options::OPT_ast_dump)), cl::cat(ClangCheckCategory));/// 定义Visitorclass CommClassVisitor : public RecursiveASTVisitor {public: explicit CommClassVisitor(ASTContext *context, SourceManager *sm, Rewriter *rw) : context_(context), sm_(sm), rewriter_(rw) {} bool VisitStmt(Stmt *s) { // 当前文件,排除包含文件 if (sm_->isInMainFile(s->getBeginLoc()) && isa(s)) { /// 插入注释 IfStmt *IfStatement = cast(s); Stmt *Then = IfStatement->getThen(); rewriter_->InsertText(Then->getBeginLoc(), "// visitor, the 'if' part
", true, true); Stmt *Else = IfStatement->getElse(); if (Else) { rewriter_->InsertText(Else->getBeginLoc(), "// visitor, the 'else' part
", true, true); } } return true; } bool VisitDecl(Decl *d) { /// 遍历声明相关的注释 ASTContext &ctx = d->getASTContext(); SourceManager &sm = ctx.getSourceManager(); const RawComment *rc = d->getASTContext().getRawCommentForDeclNoCache(d); //const RawComment *rc = d->getASTContext().getRawCommentForAnyRedecl(d); if (rc) { // Found comment! SourceRange range = rc->getSourceRange(); PresumedLoc startPos = sm.getPresumedLoc(range.getBegin()); PresumedLoc endPos = sm.getPresumedLoc(range.getEnd()); llvm::StringRef raw = rc->getRawText(sm); std::string brief = rc->getBriefText(ctx); llvm::outs() << brief << "
"; llvm::outs() << raw << "
"; } return true; }private: ASTContext *context_; SourceManager *sm_; std::string caller_; Rewriter *rewriter_;};class CommClassConsumer : public clang::ASTConsumer {public: explicit CommClassConsumer(ASTContext *context, SourceManager *sm, Rewriter *rw) : visitor_(context, sm, rw), sm_(sm), rewriter_(rw) {} ~CommClassConsumer() { llvm::outs() << "I have finished get comments." << "
"; } virtual void Initialize(ASTContext &Context) override { context_ = &Context; } virtual void HandleTranslationUnit(clang::ASTContext &context) override { /// 遍历所有注释 bool empty = context.Comments.empty(); if (!empty) { SourceManager &sm = context.getSourceManager(); const std::map *commentList = context.Comments.getCommentsInFile(sm.getMainFileID()); for (auto comment : *commentList) { const char *brief = comment.second->getBriefText(context); llvm::outs() << brief << "
"; StringRef raw = comment.second->getRawText(sm); llvm::outs() << raw << "
"; } llvm::outs() << "------------------------------" << "
"; } if (VISITORDump) { // 使用遍历模式 visitor_.TraverseDecl(context.getTranslationUnitDecl()); } }private: CommClassVisitor visitor_; ASTContext *context_; SourceManager *sm_; Rewriter *rewriter_;};class CommClassAction : public clang::ASTFrontendAction {public: void EndSourceFileAction() override { //rewriter_.getEditBuffer(rewriter_.getSourceMgr().getMainFileID()) .write(llvm::outs()); rewriter_.overwriteChangedFiles(); } virtual std::unique_ptr CreateASTConsumer(clang::CompilerInstance &compiler, llvm::StringRef in_file) { // 屏蔽错误信息输出 compiler.getDiagnostics().setClient(new IgnoringDiagConsumer()); // 相当于-w rewriter_.setSourceMgr(compiler.getSourceManager(), compiler.getLangOpts()); return std::make_unique( &compiler.getASTContext(), &compiler.getSourceManager(), &rewriter_); }private: Rewriter rewriter_; };//命令行参数: ast.cpp -- 屏蔽编译数据库找不到int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); // Initialize targets for clang module support. llvm::InitializeAllTargets(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmPrinters(); llvm::InitializeAllAsmParsers(); auto ExpectedParser = CommonOptionsParser::create(argc, argv, ClangCheckCategory); if (!ExpectedParser) { llvm::errs() << ExpectedParser.takeError(); return 1; } CommonOptionsParser &OptionsParser = ExpectedParser.get(); ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); std::unique_ptr FrontendFactory; FrontendFactory = newFrontendActionFactory(); return Tool.run(FrontendFactory.get());}
测试文件:
/// for linux,__cdecl// g++ -g ast.cpp -std=c++11 -I../src -o ast#include#include "stub.h"using namespace std;templatevoid swap(T &a, T &b){ T temp = a; a = b; b = temp;}// Class Aclass A{ int i;public: /// function foo for A int foo(int a){ if(a > 1) cout<<"I am A_foo:"<< a < 1:"<< a <
执行:
./comm_print --extra-arg=-fparse-all-comments --extra-arg=-Wdocumentation -visitor ast.cpp --
结果:
留言与评论(共有 0 条评论) “” |