В 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); }
Комментариев нет:
Отправить комментарий