В clang-c есть функция clang_visitChildren, предназначенная для частичного обхода AST. Она начинает с узла, переданного первым параметром, и вызывает функцию (второй параметр) для каждого дочернего узла.
Функция возвращает одно из трёх значений из enum CXChildVisitResult. В зависимости от этого значения clang прерывает обход, преходит к следующему потомку либо обходит ещё и потомков потомка.
Вот такой код выберет самое раннее объявление класса, даже если оно вложено в пространство имён:
А теперь самая мякотка. Превратим вызов функции с тремя параметрами в вызов лямбды без параметров, вместо этого cursor и parent будут ложиться в контекст, а сам класс будет иметь методы pushContext и popContext:
Функция возвращает одно из трёх значений из enum CXChildVisitResult. В зависимости от этого значения clang прерывает обход, преходит к следующему потомку либо обходит ещё и потомков потомка.
Вот такой код выберет самое раннее объявление класса, даже если оно вложено в пространство имён:
static CXChildVisitResult childVisitor(CXCursor cursor,
CXCursor parent,
CXClientData client_data)
{
if (cursor.kind == CXCursor_Namespace)
return CXChildVisit_Recurse;
if (cursor.kind == CXCursor_ClassDecl)
{
CXCursor *placeholder = reinterpret_cast<CXCursor*>(client_data);
*placeholder = self;
return CXChildVisit_Break;
}
return CXChildVisit_Continue;
}
А теперь самая мякотка. Превратим вызов функции с тремя параметрами в вызов лямбды без параметров, вместо этого cursor и parent будут ложиться в контекст, а сам класс будет иметь методы pushContext и popContext:
typedef std::function<CXChildVisitResult()> Visitor;
typedef std::function<CXChildVisitResult(const CXCursor &self, const CXCursor &parent)> VisitorWrapper;
static CXChildVisitResult childVisitor(CXCursor cursor,
CXCursor parent,
CXClientData client_data)
{
VisitorWrapper &callback = *reinterpret_cast<VisitorWrapper *>(client_data);
return callback(cursor, parent);
}
void TUConsumer::visitCursorChildren(CXCursor cursor, Visitor callback)
{
VisitorWrapper wrapper = [&callback, this](const CXCursor &self, const CXCursor &parent)
{
pushContext(self, parent);
auto ret = callback();
popContext();
return ret;
};
CXClientData data = reinterpret_cast<CXClientData>(&wrapper);
clang_visitChildren(cursor, childVisitor, data);
}
Комментариев нет:
Отправить комментарий