What is the correct way to map #includes (or #defines) using Clang libtooling?

I am writing a libtooling refactoring tool. I have a class, say Foo , defined in the foo.h header. I want to see if foo.h included in the file. Currently, to check if bar.cc includes foo.h , I just use recordDecl(hasName("Foo")) . This works because class Foo { ... }; will exist inside bar.cc AST after pre-processing if bar.cc includes bar.cc

But this does not work if, for example, bar.cc includes cat.h , which includes foo.h I want bar.cc EXPLICITLY to include bar.cc

In addition, I would like to be able to match #define macros.

The way I wrote my tool made these two goals impossible, because the AST, with which I agree, has already been pre-processed. Is what I'm trying to do even possible? I dug up a link to the Preprocessor class on the Clang Doxygen pages, but I didn’t quite find what I was looking for.

+5
source share
2 answers

I figured this out after digging into Clang Doxygen and the code. I needed to use the PPCallbacks class along with the Preprocessor class. The following is an example. Note that this is not guaranteed to be a functional piece of code, but it illustrates common usage. For more information, see the Clang PPCallbacks Documentation, as well as the documentation for addPPCallbacks and getPPCallbacks in clang :: 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; } }; 
+7
source

I have successfully implemented it. I do not think that the EndSourceFileAction () method should contain everything related to 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; } 
+1
source

Source: https://habr.com/ru/post/1207265/


All Articles