在已经匹配了一些东西之后,有没有办法 "restart matching" 与 libclang 匹配器?
Is there any way to "restart matching" with libclang matchers after already having matched something?
class __attribute__((annotate("some_important_string"))) Foo {
public:
void do_something();
};
我想在带有特定注释的 class 中找到所有 public 方法。我设置了一个匹配器来获取带有注释的 classes:
Matcher.addMatcher(cxxRecordDecl(anyOf(isStruct(), isClass()),
hasAttr(attr::Annotate)).bind("class")
但似乎没有任何方法可以匹配注释的确切字符串。
因此,在我的 MatchCallback::run 方法中,我通过获取属性 dyn_cast
到 AnnotateAttr
并检查注释字符串 ref:[=17= 来检查属性字符串]
auto &attrs = decl->getAttrs();
...
auto attribute_attr = dyn_cast<AnnotateAttr>(attr);
auto string_ref = attribute_attr->getAnnotation();
但现在我真的更愿意做更多的匹配,而不是 AST 树遍历。我的理解是匹配器比树遍历函数更稳定,而且看起来也更直接。
那么,在过滤注释字符串的 class 之后,有什么方法可以返回到使用匹配器吗?
我目前正在根据以下代码进行过滤,它工作正常,但这不是我想要的方式:
if (method->getAccess() != AS_public) {
if (PRINT_SKIPPED_EXPORT_REASONS) printf("%s**%s is not public, skipping\n", indentation.c_str(), method_name.c_str());
return;
}
if (method->isOverloadedOperator()) {
if (PRINT_SKIPPED_EXPORT_REASONS) printf("%s**skipping overloaded operator %s\n", indentation.c_str(), method_name.c_str());
return;
}
if (dyn_cast<CXXConstructorDecl>(method)) {
if (PRINT_SKIPPED_EXPORT_REASONS) printf("%s**skipping constructor %s\n", indentation.c_str(), method_name.c_str());
return;
}
if (dyn_cast<CXXDestructorDecl>(method)) {
if (PRINT_SKIPPED_EXPORT_REASONS) printf("%s**skipping destructor %s\n", indentation.c_str(), method_name.c_str());
return;
}
if (method->isPure()) {
assert(method->isVirtual());
if (PRINT_SKIPPED_EXPORT_REASONS) printf("%s**skipping pure virtual %s\n", indentation.c_str(), method_name.c_str());
return;
}
我不确定 Clang AST 匹配器 API 目前(从 3.9 开始)是否支持重新启动匹配过程。据我所知 - MatchFinder
包括匹配节点 MatchFinder.match, and to match a whole translation unit MatchFinder.matchAST 的方法,但不从提供的节点递归匹配。
解决此问题的一种方法是简单地使您的匹配器更复杂,并将您想要进行的所有匹配嵌入到一个位置(如下)。
#include <string>
#include <iostream>
#include "clang/AST/AST.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::driver;
using namespace clang::tooling;
static llvm::cl::OptionCategory ToolingSampleCategory("Matcher Sample");
class Handler : public MatchFinder::MatchCallback {
public:
Handler()
{}
void run(const MatchFinder::MatchResult &Result) override {
if(const CXXRecordDecl* klass = Result.Nodes.getNodeAs<CXXRecordDecl>("klass"))
{
for(auto it : klass->attrs())
{
Attr& attr = (*it);
auto annotatedAttr = dyn_cast<AnnotateAttr>(&attr);
if((annotatedAttr == nullptr) || (std::string(annotatedAttr->getAnnotation()) != "meh"))
{
return;
}
}
}
if(const CXXMethodDecl* mthd = Result.Nodes.getNodeAs<CXXMethodDecl>("mthd"))
{
std::cout << mthd->getNameInfo().getAsString() << std::endl;
}
}
};
int main(int argc, const char **argv) {
CommonOptionsParser op(argc, argv, ToolingSampleCategory);
RefactoringTool Tool(op.getCompilations(), op.getSourcePathList());
Handler handler;
MatchFinder finder;
finder.addMatcher(
cxxRecordDecl(
hasAttr(attr::Annotate),
forEach(
cxxMethodDecl(
isPublic(),
unless(isPure()),
unless(cxxConstructorDecl()),
unless(cxxDestructorDecl())).bind("mthd")
)).bind("klass"), &handler);
Tool.run(newFrontendActionFactory(&finder).get());
return 0;
}
class __attribute__((annotate("some_important_string"))) Foo {
public:
void do_something();
};
我想在带有特定注释的 class 中找到所有 public 方法。我设置了一个匹配器来获取带有注释的 classes:
Matcher.addMatcher(cxxRecordDecl(anyOf(isStruct(), isClass()),
hasAttr(attr::Annotate)).bind("class")
但似乎没有任何方法可以匹配注释的确切字符串。
因此,在我的 MatchCallback::run 方法中,我通过获取属性 dyn_cast
到 AnnotateAttr
并检查注释字符串 ref:[=17= 来检查属性字符串]
auto &attrs = decl->getAttrs();
...
auto attribute_attr = dyn_cast<AnnotateAttr>(attr);
auto string_ref = attribute_attr->getAnnotation();
但现在我真的更愿意做更多的匹配,而不是 AST 树遍历。我的理解是匹配器比树遍历函数更稳定,而且看起来也更直接。
那么,在过滤注释字符串的 class 之后,有什么方法可以返回到使用匹配器吗?
我目前正在根据以下代码进行过滤,它工作正常,但这不是我想要的方式:
if (method->getAccess() != AS_public) {
if (PRINT_SKIPPED_EXPORT_REASONS) printf("%s**%s is not public, skipping\n", indentation.c_str(), method_name.c_str());
return;
}
if (method->isOverloadedOperator()) {
if (PRINT_SKIPPED_EXPORT_REASONS) printf("%s**skipping overloaded operator %s\n", indentation.c_str(), method_name.c_str());
return;
}
if (dyn_cast<CXXConstructorDecl>(method)) {
if (PRINT_SKIPPED_EXPORT_REASONS) printf("%s**skipping constructor %s\n", indentation.c_str(), method_name.c_str());
return;
}
if (dyn_cast<CXXDestructorDecl>(method)) {
if (PRINT_SKIPPED_EXPORT_REASONS) printf("%s**skipping destructor %s\n", indentation.c_str(), method_name.c_str());
return;
}
if (method->isPure()) {
assert(method->isVirtual());
if (PRINT_SKIPPED_EXPORT_REASONS) printf("%s**skipping pure virtual %s\n", indentation.c_str(), method_name.c_str());
return;
}
我不确定 Clang AST 匹配器 API 目前(从 3.9 开始)是否支持重新启动匹配过程。据我所知 - MatchFinder
包括匹配节点 MatchFinder.match, and to match a whole translation unit MatchFinder.matchAST 的方法,但不从提供的节点递归匹配。
解决此问题的一种方法是简单地使您的匹配器更复杂,并将您想要进行的所有匹配嵌入到一个位置(如下)。
#include <string>
#include <iostream>
#include "clang/AST/AST.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::driver;
using namespace clang::tooling;
static llvm::cl::OptionCategory ToolingSampleCategory("Matcher Sample");
class Handler : public MatchFinder::MatchCallback {
public:
Handler()
{}
void run(const MatchFinder::MatchResult &Result) override {
if(const CXXRecordDecl* klass = Result.Nodes.getNodeAs<CXXRecordDecl>("klass"))
{
for(auto it : klass->attrs())
{
Attr& attr = (*it);
auto annotatedAttr = dyn_cast<AnnotateAttr>(&attr);
if((annotatedAttr == nullptr) || (std::string(annotatedAttr->getAnnotation()) != "meh"))
{
return;
}
}
}
if(const CXXMethodDecl* mthd = Result.Nodes.getNodeAs<CXXMethodDecl>("mthd"))
{
std::cout << mthd->getNameInfo().getAsString() << std::endl;
}
}
};
int main(int argc, const char **argv) {
CommonOptionsParser op(argc, argv, ToolingSampleCategory);
RefactoringTool Tool(op.getCompilations(), op.getSourcePathList());
Handler handler;
MatchFinder finder;
finder.addMatcher(
cxxRecordDecl(
hasAttr(attr::Annotate),
forEach(
cxxMethodDecl(
isPublic(),
unless(isPure()),
unless(cxxConstructorDecl()),
unless(cxxDestructorDecl())).bind("mthd")
)).bind("klass"), &handler);
Tool.run(newFrontendActionFactory(&finder).get());
return 0;
}