使用 Clang Tools —— ClangCheck

本文为译文,点击此处查看原文。

ClangCheck 是一个围绕 LibTooling 的小的 wrapper,可以用来进行基本的错误检查和 AST 转储。

$ cat <<EOF > snippet.cc
> void f() {
>   int a = 0
> }
> EOF
$ ~/clang/build/bin/clang-check snippet.cc -ast-dump --
Processing: /Users/danieljasper/clang/llvm/tools/clang/docs/snippet.cc.
/Users/danieljasper/clang/llvm/tools/clang/docs/snippet.cc:2:12: error: expected ';' at end of
      declaration
  int a = 0
           ^
           ;
(TranslationUnitDecl 0x7ff3a3029ed0 <<invalid sloc>>
  (TypedefDecl 0x7ff3a302a410 <<invalid sloc>> __int128_t '__int128')
  (TypedefDecl 0x7ff3a302a470 <<invalid sloc>> __uint128_t 'unsigned __int128')
  (TypedefDecl 0x7ff3a302a830 <<invalid sloc>> __builtin_va_list '__va_list_tag [1]')
  (FunctionDecl 0x7ff3a302a8d0 </Users/danieljasper/clang/llvm/tools/clang/docs/snippet.cc:1:1, line:3:1> f 'void (void)'
    (CompoundStmt 0x7ff3a302aa10 <line:1:10, line:3:1>
      (DeclStmt 0x7ff3a302a9f8 <line:2:3, line:3:1>
        (VarDecl 0x7ff3a302a980 <line:2:3, col:11> a 'int'
          (IntegerLiteral 0x7ff3a302a9d8 <col:11> 'int' 0))))))
1 error generated.
Error while processing snippet.cc.

结尾的“-”很重要,因为它阻止了clang-check搜索一个编译数据库。有关在一个工程中如何设置和使用clang-check的更多信息,请参见如何为LLVM设置Clang工具

要遍历 Clang 的 AST 树,可以使用 clang 提供的 LibTooling 库。下面是一个使用 LibTooling 的完整示例项目,可以遍历 C++ 代码并输出类、函数和变量的信息。 1. 创建一个 C++ 项目,并在项目中包含 clang 的头文件和 LibTooling 库的头文件和库文件。 2. 创建一个名为 `MyASTVisitor` 的类,继承自 `clang::RecursiveASTVisitor`。在该类中实现需要遍历 AST 树时需要的方法,例如 `VisitCXXRecordDecl`,`VisitFunctionDecl`,`VisitVarDecl`,`VisitStmt` 等等。这些方法将用于处理不同类型的 AST 节点。 ```cpp #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include <iostream> #include <string> using namespace clang; using namespace clang::tooling; using namespace llvm; using namespace std; class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> { public: bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) { if (Declaration->isClass()) { cout << "Class name: " << Declaration->getNameAsString() << endl; } else if (Declaration->isStruct()) { cout << "Struct name: " << Declaration->getNameAsString() << endl; } else if (Declaration->isUnion()) { cout << "Union name: " << Declaration->getNameAsString() << endl; } return true; } bool VisitFunctionDecl(FunctionDecl *Declaration) { cout << "Function name: " << Declaration->getNameInfo().getName().getAsString() << endl; return true; } bool VisitVarDecl(VarDecl *Declaration) { cout << "Variable name: " << Declaration->getNameAsString() << endl; return true; } bool VisitStmt(Stmt *Statement) { if (isa<DeclStmt>(Statement)) { DeclStmt *DeclStatement = cast<DeclStmt>(Statement); for (auto it = DeclStatement->decl_begin(); it != DeclStatement->decl_end(); ++it) { VarDecl *VarDeclaration = dyn_cast<VarDecl>(*it); if (VarDeclaration != nullptr) { cout << "Variable name: " << VarDeclaration->getNameAsString() << endl; } } } return true; } }; ``` 3. 创建一个名为 `MyASTConsumer` 的类,继承自 `clang::ASTConsumer`。在该类中实现需要处理 AST 树时需要的方法,例如 `HandleTranslationUnit`。 ```cpp class MyASTConsumer : public ASTConsumer { public: virtual void HandleTranslationUnit(ASTContext &Context) override { MyASTVisitor Visitor; Visitor.TraverseDecl(Context.getTranslationUnitDecl()); } }; ``` 4. 创建一个名为 `MyFrontendAction` 的类,继承自 `clang::ASTFrontendAction`。在该类中实现需要处理 AST 树时需要的方法,例如 `CreateASTConsumer`。 ```cpp class MyFrontendAction : public ASTFrontendAction { public: virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, llvm::StringRef InFile) override { return std::make_unique<MyASTConsumer>(); } }; ``` 5. 在 `main` 函数中,使用 `CommonOptionsParser` 解析命令行参数,并使用 `ClangTool` 运行代码分析。 ```cpp int main(int argc, const char **argv) { CommonOptionsParser OptionsParser(argc, argv); ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); int Result = Tool.run(newFrontendActionFactory<MyFrontendAction>().get()); return Result; } ``` 6. 编译并运行代码,例如: ```bash clang++ -std=c++11 -I /path/to/clang/include -I /path/to/libtooling/include -L /path/to/libtooling/libs main.cpp -lclangTooling -lclangASTMatchers -lclangAST -lclangAnalysis -lclangBasic -lclangDriver -lclangEdit -lclangFrontend -lclangLex -lclangParse -lclangSema -lclangSerialization -lLLVMSupport -lLLVMMC -lLLVMMCParser -lLLVMCore -o tool ./tool my_cpp_file.cpp ``` 以上示例代码只是一个简单的例子,并不能处理所有类型的 AST 节点,也无法处理复杂的代码逻辑,具体的处理方法需要根据实际需要进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值