Я пишу инструмент рефакторинга libtooling. У меня есть класс, скажем Foo
определяется в заголовке foo.h
, Я хочу увидеть, если foo.h
включен в файл. В настоящее время, чтобы проверить, если bar.cc
включает в себя foo.h
Я просто соответствую, используя recordDecl(hasName("Foo"))
, Это работает, потому что class Foo { ... };
будет существовать внутри bar.cc
АСТ после предварительной обработки, если bar.cc
включает в себя foo.h
,
Но это не работает, если, например, bar.cc
включает в себя cat.h
который включает в себя foo.h
, я хочу bar.cc
ТОЧНО включать foo.h
,
Кроме того, я хотел бы иметь возможность соответствовать #define
макросы.
То, как я писал свой инструмент, сделало эти две цели невозможными, потому что AST, с которым я сопоставляюсь, уже был предварительно обработан. Возможно ли то, что я пытаюсь сделать? Я покопался Preprocessor
ссылка на класс на страницах Кланга о Doxygen, но я не совсем нашел то, что искал.
Я понял это после того, как покопался в Doxygen и коде Clang. Мне нужно было использовать PPCallbacks
класс вместе с Preprocessor
учебный класс. Пример ниже. Обратите внимание, что это не обязательно является функциональным фрагментом кода, но он иллюстрирует общее использование. Для получения дополнительной информации см. Clang’s PPCallbacks документация, а также документация для addPPCallbacks а также getPPCallbacks в лязг :: Препроцессор.
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;
}
};
Я успешно реализовал это. Я не думаю, что метод EndSourceFileAction () должен содержать что-либо, связанное с Find_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)
{
// 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;
}