有没有办法重新开始匹配"与libclang匹配后已经匹配的东西?

时间:2016-06-28 04:35:02

标签: c++ libclang

class __attribute__((annotate("some_important_string"))) Foo {
public:
    void do_something();
};

我想在具有特定注释的类中查找所有公共方法。我有一个匹配器来设置带注释的类:

Matcher.addMatcher(cxxRecordDecl(anyOf(isStruct(), isClass()),
                                 hasAttr(attr::Annotate)).bind("class")

但似乎没有任何方法可以匹配注释的确切字符串。

因此,在我的MatchCallback :: run方法中,我通过获取属性dyn_castAnnotateAttr并检查注释字符串ref来检查属性字符串:

auto &attrs = decl->getAttrs();
...
auto attribute_attr = dyn_cast<AnnotateAttr>(attr);
auto string_ref = attribute_attr->getAnnotation();

但现在我真的宁愿做更多匹配,而不是AST树遍历。我的理解是匹配器比树遍历函数更稳定,它们似乎也更直接。

那么在过滤类的注释字符串之后,还有什么办法可以回到使用匹配器吗?

我目前正在根据以下代码进行过滤,它可以正常使用,但我并不喜欢这样做:

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

1 个答案:

答案 0 :(得分:1)

我不确定目前的Clang AST Matchers API(截至3.9)是否支持重新启动匹配过程。据我所知 - MatchFinder包括匹配节点MatchFinder.match的方法,以及匹配整个翻译单元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;
}