特定节点上的 AST 匹配器
AST matcher on a specific node
我写了一个 AST 匹配器来查找特定类型的语句。在匹配的节点中,我计算了该节点的邻居兄弟节点。现在我需要 运行 邻居节点上的匹配器来验证它们是否满足我的条件。
clang AST匹配器一一匹配整个树节点。我想 运行 匹配器针对特定节点,如果节点符合我的要求条件,则 return 为真。
这可能吗?
我建议实现您自己的匹配器,它将封装查找邻居节点并将它们与其他匹配器进行匹配的逻辑。
我将以下匹配器放在一起作为如何完成的示例:
using clang::ast_matchers::internal::Matcher;
constexpr auto AVERAGE_NUMBER_OF_NESTED_MATCHERS = 3;
using Matchers =
llvm::SmallVector<Matcher<clang::Stmt>, AVERAGE_NUMBER_OF_NESTED_MATCHERS>;
clang::Stmt *getNeighbor(const clang::Stmt &Node, clang::ASTContext &Context) {
// It is my naive implementation of this method, you can easily put your own
auto Parents = Context.getParents(Node);
if (Parents.size() != 1) {
return nullptr;
}
// As we deal with statements, let's assume that neighbor - is the next
// statement in the enclosing compound statement.
if (auto *Parent = Parents[0].get<clang::CompoundStmt>()) {
auto Neighbor = std::adjacent_find(
Parent->body_begin(), Parent->body_end(),
[&Node](const auto *Top, const auto *Bottom) { return Top == &Node; });
if (Neighbor != Parent->body_end()) {
return *std::next(Neighbor);
}
}
return nullptr;
}
AST_MATCHER_P(clang::Stmt, neighbors, Matchers, NestedMatchers) {
// Node is the current tested node
const clang::Stmt *CurrentNode = &Node;
// Our goal is to iterate over the given matchers and match the current node
// with the first matcher.
//
// Further on, we plan on checking whether the next
// matcher matches the neighbor/sibling of the previous node.
for (auto NestedMatcher : NestedMatchers) {
// This is how one can call a matcher to test one node.
//
// NOTE: it uses Finder and Builder, so it's better to do it from
// inside of a matcher and get those for free
if (CurrentNode == nullptr or
not NestedMatcher.matches(*CurrentNode, Finder, Builder)) {
return false;
}
// Here you can put your own implementation of finding neighbor/sibling
CurrentNode = getNeighbor(*CurrentNode, Finder->getASTContext());
}
return true;
}
我希望代码段中的评论涵盖了这个匹配器背后的主要思想。
演示
匹配器:
neighbors({declStmt().bind("first"), forStmt().bind("second"),
returnStmt().bind("third")})
代码片段:
int foo() {
int x = 42;
int y = 10;
for (; x > y; --x) {
}
return x;
}
输出:
first:
DeclStmt 0x4c683e0
`-VarDecl 0x4c68360 used y 'int' cinit
`-IntegerLiteral 0x4c683c0 'int' 10
second:
ForStmt 0x4c684d0
|-<<<NULL>>>
|-<<<NULL>>>
|-BinaryOperator 0x4c68468 '_Bool' '>'
| |-ImplicitCastExpr 0x4c68438 'int' <LValueToRValue>
| | `-DeclRefExpr 0x4c683f8 'int' lvalue Var 0x4c682b0 'x' 'int'
| `-ImplicitCastExpr 0x4c68450 'int' <LValueToRValue>
| `-DeclRefExpr 0x4c68418 'int' lvalue Var 0x4c68360 'y' 'int'
|-UnaryOperator 0x4c684a8 'int' lvalue prefix '--'
| `-DeclRefExpr 0x4c68488 'int' lvalue Var 0x4c682b0 'x' 'int'
`-CompoundStmt 0x4c684c0
third:
ReturnStmt 0x4c68540
`-ImplicitCastExpr 0x4c68528 'int' <LValueToRValue>
`-DeclRefExpr 0x4c68508 'int' lvalue Var 0x4c682b0 'x' 'int'
希望这能回答您的问题!
我写了一个 AST 匹配器来查找特定类型的语句。在匹配的节点中,我计算了该节点的邻居兄弟节点。现在我需要 运行 邻居节点上的匹配器来验证它们是否满足我的条件。 clang AST匹配器一一匹配整个树节点。我想 运行 匹配器针对特定节点,如果节点符合我的要求条件,则 return 为真。 这可能吗?
我建议实现您自己的匹配器,它将封装查找邻居节点并将它们与其他匹配器进行匹配的逻辑。
我将以下匹配器放在一起作为如何完成的示例:
using clang::ast_matchers::internal::Matcher;
constexpr auto AVERAGE_NUMBER_OF_NESTED_MATCHERS = 3;
using Matchers =
llvm::SmallVector<Matcher<clang::Stmt>, AVERAGE_NUMBER_OF_NESTED_MATCHERS>;
clang::Stmt *getNeighbor(const clang::Stmt &Node, clang::ASTContext &Context) {
// It is my naive implementation of this method, you can easily put your own
auto Parents = Context.getParents(Node);
if (Parents.size() != 1) {
return nullptr;
}
// As we deal with statements, let's assume that neighbor - is the next
// statement in the enclosing compound statement.
if (auto *Parent = Parents[0].get<clang::CompoundStmt>()) {
auto Neighbor = std::adjacent_find(
Parent->body_begin(), Parent->body_end(),
[&Node](const auto *Top, const auto *Bottom) { return Top == &Node; });
if (Neighbor != Parent->body_end()) {
return *std::next(Neighbor);
}
}
return nullptr;
}
AST_MATCHER_P(clang::Stmt, neighbors, Matchers, NestedMatchers) {
// Node is the current tested node
const clang::Stmt *CurrentNode = &Node;
// Our goal is to iterate over the given matchers and match the current node
// with the first matcher.
//
// Further on, we plan on checking whether the next
// matcher matches the neighbor/sibling of the previous node.
for (auto NestedMatcher : NestedMatchers) {
// This is how one can call a matcher to test one node.
//
// NOTE: it uses Finder and Builder, so it's better to do it from
// inside of a matcher and get those for free
if (CurrentNode == nullptr or
not NestedMatcher.matches(*CurrentNode, Finder, Builder)) {
return false;
}
// Here you can put your own implementation of finding neighbor/sibling
CurrentNode = getNeighbor(*CurrentNode, Finder->getASTContext());
}
return true;
}
我希望代码段中的评论涵盖了这个匹配器背后的主要思想。
演示
匹配器:
neighbors({declStmt().bind("first"), forStmt().bind("second"),
returnStmt().bind("third")})
代码片段:
int foo() {
int x = 42;
int y = 10;
for (; x > y; --x) {
}
return x;
}
输出:
first:
DeclStmt 0x4c683e0
`-VarDecl 0x4c68360 used y 'int' cinit
`-IntegerLiteral 0x4c683c0 'int' 10
second:
ForStmt 0x4c684d0
|-<<<NULL>>>
|-<<<NULL>>>
|-BinaryOperator 0x4c68468 '_Bool' '>'
| |-ImplicitCastExpr 0x4c68438 'int' <LValueToRValue>
| | `-DeclRefExpr 0x4c683f8 'int' lvalue Var 0x4c682b0 'x' 'int'
| `-ImplicitCastExpr 0x4c68450 'int' <LValueToRValue>
| `-DeclRefExpr 0x4c68418 'int' lvalue Var 0x4c68360 'y' 'int'
|-UnaryOperator 0x4c684a8 'int' lvalue prefix '--'
| `-DeclRefExpr 0x4c68488 'int' lvalue Var 0x4c682b0 'x' 'int'
`-CompoundStmt 0x4c684c0
third:
ReturnStmt 0x4c68540
`-ImplicitCastExpr 0x4c68528 'int' <LValueToRValue>
`-DeclRefExpr 0x4c68508 'int' lvalue Var 0x4c682b0 'x' 'int'
希望这能回答您的问题!