使用Clang的libtooling匹配#includes(或#defines)的正确方法是什么?

时间:2014-11-19 23:53:26

标签: c++ clang libtooling

我正在编写一个libtooling重构工具。我有一个课程,让我们说Foo,在名为foo.h的标题中定义。我想看看文件中是否包含foo.h。目前,要检查bar.cc是否包含foo.h,我只是使用recordDecl(hasName("Foo"))进行匹配。这是有效的,因为如果class Foo { ... };包含bar.cc,则预处理后bar.cc的AST中会存在foo.h

但是,如果bar.cc包含cat.h包括foo.h,则此功能不起作用。我希望bar.cc明确地包含foo.h

此外,我希望能够匹配#define个宏。

我编写工具的方式使得这两个目标无法实现,因为AST I匹配已​​经过预处理。是我试图做的甚至可能吗?我在Clang的Doxygen页面上挖掘Preprocessor课程参考,但我还没有找到我想要的东西。

2 个答案:

答案 0 :(得分:10)

我在Clang的Doxygen和代码中挖掘后想出了这个。我需要使用PPCallbacks类和Preprocessor类。一个例子如下。请注意,这不保证是功能代码段,但它说明了一般用法。有关详细信息,请参阅Clang的PPCallbacks文档以及addPPCallbacksgetPPCallbacksclang::Preprocessor的文档。

class Find_Includes : public PPCallbacks
{
public:
  bool has_include;

  void InclusionDirective(
    SourceLocation hash_loc,
    const Token &include_token,
    StringRef file_name,
    bool is_angled,
    CharSourceRange filename_range,
    const FileEntry *file,
    StringRef search_path,
    StringRef relative_path,
    const Module *imported)
  {
    // do something with the include
    has_include = true;
  }
};

class Include_Matching_Action : public ASTFrontendAction
{
  bool BeginSourceFileAction(CompilerInstance &ci, StringRef)
  {
    std::unique_ptr<Find_Includes> find_includes_callback(new Find_Includes());

    Preprocessor &pp = ci.getPreprocessor();
    pp.addPPCallbacks(std::move(find_includes_callback));

    return true;
  }

  void EndSourceFileAction()
  {
    CompilerInstance &ci = getCompilerInstance();
    Preprocessor &pp = ci.getPreprocessor();
    Find_Includes *find_includes_callback = static_cast<Find_Includes>(pp.getPPCallbacks());

    // do whatever you want with the callback now
    if (find_includes_callback->has_include)
      std::cout << "Found at least one include" << std::endl;
  }
};

答案 1 :(得分:1)

我成功实施了它。我不认为EndSourceFileAction()方法应该包含与Find_Includes相关的任何内容。

void InclusionDirective( SourceLocation hash_loc, const Token &include_token, StringRef file_name, bool is_angled, CharSourceRange filename_range,
                            const FileEntry *file, StringRef search_path, StringRef relative_path, const Module *imported)
              {
                  // Add your code here.
              }
bool BeginSourceFileAction(CompilerInstance &CI) 
{     std::unique_ptr<Find_Includes> find_includes_callback(new Find_Includes(TheRewriter));
      Preprocessor &pp = CI.getPreprocessor();
      pp.addPPCallbacks(std::move(find_includes_callback));
      return true;
}