AST匹配器


文档摘要

AST匹配器[^1] 为定位特定的AST节点提供了另一种方法。在搜索不适当的模式,使用或识别需要修改的AST节点的检查器和重构工具。 我们将创建一个简单的程序来测试AST匹配。该程序将识别具有名称max的函数定义,使用从前面的示例中稍作修改的CMakeLists.txt文件,以包含支持AST匹配所需的库: 图3.24: AST匹配器测试工具的CMakeLists.txt文件 添加了两个库:LLVMFrontendOpenMP和clangASTMatchers(见图3.24中的第18行和第21行)。工具的主函数看起来像这样: \#include "clang/Tooling/CommonOptionsParser.h" \#include "clang/Tooling/Tooling.

AST匹配器1
为定位特定的AST节点提供了另一种方法。在搜索不适当的模式,使用或识别需要修改的AST节点的检查器和重构工具。

我们将创建一个简单的程序来测试AST匹配。该程序将识别具有名称max的函数定义,使用从前面的示例中稍作修改的CMakeLists.txt文件,以包含支持AST匹配所需的库:

图3.24: AST匹配器测试工具的CMakeLists.txt文件

添加了两个库:LLVMFrontendOpenMP和clangASTMatchers(见图3.24中的第18行和第21行)。工具的主函数看起来像这样:

#include "clang/Tooling/CommonOptionsParser.h" #include
"clang/Tooling/Tooling.h" #include "llvm/Support/CommandLine.h" //
llvm:🆑:extrahelp #include "MatchCallback.hpp"

namespace llvm:🆑:OptionCategory TestCategory("Test project");
llvm:🆑:extrahelp
CommonHelp(clang::tooling::CommonOptionsParser::HelpMessage); //
namespace

int main(int argc, const char **argv)
llvm::Expected<clang::tooling::CommonOptionsParser> OptionsParser =
clang::tooling::CommonOptionsParser::create(argc, argv, TestCategory);
if (!OptionsParser) llvm::errs() << OptionsParser.takeError(); return
1; clang::tooling::ClangTool Tool(OptionsParser->getCompilations(),
OptionsParser->getSourcePathList());
clangbook::matchvisitor::MatchCallback MC;
clang::ast_matchers::MatchFinder Finder;
Finder.addMatcher(clangbook::matchvisitor::M, &MC); return
Tool.run(clang::tooling::newFrontendActionFactory(&Finder).get());

图3.25: AST匹配器测试工具的主函数

第21-23行使用了MatchFinder类,并定义了一个自定义回调(通过第4行的头文件包含),该回调描述了我们打算匹配的特定AST节点。回调的实现如下:

#include "clang/ASTMatchers/ASTMatchFinder.h" #include
"clang/ASTMatchers/ASTMatchers.h"

namespace clangbook

namespace matchvisitor

using namespace clang::ast_matchers; static const char *MatchID =
"match-id"; clang::ast_matchers::DeclarationMatcher M =
functionDecl(decl().bind(MatchID), matchesName("max"));

class MatchCallback : public
clang::ast_matchers::MatchFinder::MatchCallback public: virtual void
run(const clang::ast_matchers::MatchFinder::MatchResult &Result) final
if (const auto *FD =
Result.Nodes.getNodeAs<clang::FunctionDecl>(MatchID)) const auto &SM =
*Result.SourceManager; const auto &Loc = FD->getLocation();
llvm::outs() << "Found ’max’ function at " << SM.getFilename(Loc)
<< ":" << SM.getSpellingLineNumber(Loc) << ":" <<
SM.getSpellingColumnNumber(Loc) << ""; ;

// namespace matchvisitor

// namespace clangbook

图3.26: AST匹配器测试工具的匹配回调

代码中最重要的部分位于第7-9行。每个匹配器都由一个ID标识,在我们的示例中是’match-id’。匹配器本身在第8-9行定义:

clang::ast_matchers::DeclarationMatcher M =
functionDecl(decl().bind(MatchID), matchesName("max"));

这个匹配器寻找具有特定名称的函数声明,使用functionDecl(),正如在matchesName()中看到的那样。使用了一个专门的领域特定语言(DSL)来指定匹配器,DSL使用C++宏实现。还可以创建自己的匹配器,检查实现中展示。值得注意的是,递归AST访问者在匹配器实现中的AST遍历中起着核心作用。

程序可以使用之前使用的相同的命令序列进行编译。见图3.11。

使用图2.5中示例的一个修改版本,添加了一个函数:

int max(int a, int b) if (a > b) return a; return b;

int min(int a, int b) if (a > b) return b; return a;

图3.27: AST匹配器的测试程序minmax.cpp

运行测试工具时,将获得以下输出:

./matchvisitor minmax.cpp – -std=c++17 ... Found the ’max’ function at
minmax.cpp:1:5

图3.28: 在测试文件上运行matchvisitor实用程序的结果

它只找到了与匹配器指定的名称匹配的一个函数声明。

匹配器的DSL通常在自定义Clang工具中使用,也可以作为独立工具使用。一个专门的程序名为clang-query,可以执行不同的匹配查询,用于在分析的C++代码中搜索特定的AST节点。让我们看看这个工具是如何工作的。

  1. LLVM Community. AST Matcher Reference. 2024. URL
    https://clang.llvm.org/docs/LibASTMatchersReference.html


作者与出处
原作者: xiaoweiChen
来源:xiaoweiChen
许可证:Apache-2.0
整理: 灏天文库整理
由灏天文库结构化整理,提供目录导航、全文检索与在线阅读,便于系统化学习
发布者: 作者: xiaoweiChen 转发
评论区 (0)
U