程序员的知识教程库

网站首页 > 教程分享 正文

基于Clang库获取源文件所有注释(enhancerbyspringcglib获取原始类)

henian88 2024-08-17 16:08:35 教程分享 8 ℃ 0 评论

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 --

结果:


Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表