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(
"\tFor example, to run comment\n"
"\n");
static cl::OptionCategory ClangCheckCategory("comment options");
static const opt::OptTable &Options = getDriverOptTable();
static cl::opt<bool>
VISITORDump("visitor",
cl::desc(Options.getOptionHelpText(options::OPT_ast_dump)),
cl::cat(ClangCheckCategory));
/// 定义Visitor
class CommClassVisitor : public RecursiveASTVisitor<CommClassVisitor> {
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<IfStmt>(s)) {
/// 插入注释
IfStmt *IfStatement = cast<IfStmt>(s);
Stmt *Then = IfStatement->getThen();
rewriter_->InsertText(Then->getBeginLoc(), "// visitor, the 'if' part\n", true, true);
Stmt *Else = IfStatement->getElse();
if (Else) {
rewriter_->InsertText(Else->getBeginLoc(), "// visitor, the 'else' part\n", 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 << "\n";
llvm::outs() << raw << "\n";
}
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." << "\n";
}
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<unsigned, RawComment *> *commentList =
context.Comments.getCommentsInFile(sm.getMainFileID());
for (auto comment : *commentList) {
const char *brief = comment.second->getBriefText(context);
llvm::outs() << brief << "\n";
StringRef raw = comment.second->getRawText(sm);
llvm::outs() << raw << "\n";
}
llvm::outs() << "------------------------------" << "\n";
}
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<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance &compiler, llvm::StringRef in_file) {
// 屏蔽错误信息输出
compiler.getDiagnostics().setClient(new IgnoringDiagConsumer()); // 相当于-w
rewriter_.setSourceMgr(compiler.getSourceManager(), compiler.getLangOpts());
return std::make_unique<CommClassConsumer>(
&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<FrontendActionFactory> FrontendFactory;
FrontendFactory = newFrontendActionFactory<CommClassAction>();
return Tool.run(FrontendFactory.get());
}
验证
测试文件:
/// for linux,__cdecl
// g++ -g ast.cpp -std=c++11 -I../src -o ast
#include<iostream>
#include "stub.h"
using namespace std;
template<typename T>
void swap(T &a, T &b){
T temp = a;
a = b;
b = temp;
}
// Class A
class A{
int i;
public:
/// function foo for A
int foo(int a){
if(a > 1)
cout<<"I am A_foo:"<< a <<endl;
else
cout<<"I am A_foo > 1:"<< a <<endl;
return 0;
}
static int bar(int b){
cout<<"I am A_bar:"<< b <<endl;
return 0;
}
};
// foo_stub function
int foo_stub(void* obj, int a)
{
A* o= (A*)obj;
cout<<"I am foo_stub"<<endl;
return 0;
}
int main()
{
/// stub var
Stub stub;
stub.set(ADDR(A,foo), foo_stub);
A a;
a.foo(1);
int aa = 1, bb=2;
swap(aa, bb);
cout<<aa<<bb<<endl;
return 0;
}
执行:
./comm_print --extra-arg=-fparse-all-comments --extra-arg=-Wdocumentation -visitor ast.cpp --
结果:
本文暂时没有评论,来添加一个吧(●'◡'●)