Как получить функцию-член, которая содержит конкретный varDeclRef через AST?

Вопрос или проблема

Пример кода:

class DBFetcher {
  public:
    void findByName(std::string name) {}
    void findByNameV2(std::string name) {}
}

DBFetcher getFetcher() {
  return FBFetcher();

void clientFetch() {
  std::string myName = "abc";
  return getFetcher().findByName(std::move(myName));
}

С помощью сопоставителя я могу сопоставить местоположение переменной myName внутри std::move. Однако, как мне сопоставить или пройти к функции findByName? Я хочу заменить функцию findByName на v2, а также изменить имя переменной myName на newName.

Сопоставитель:

auto matcher = declRefExpr(
            isExpansionInMainFile(),
            to(varDecl(hasInitializer(
                           cxxConstructExpr(hasType(cxxRecordDecl(hasName(
                                                "DBFetcher"))))
                               .bind("constructor")))
                   .bind("var")))
            .bind("varRef"));

Ответ или решение

Чтобы добиться замены имени функции findByName на findByNameV2 в AST (Abstract Syntax Tree) и переименовать переменную myName на newName, необходимо правильно использовать механизмы работы с инструментом Clang LibTooling. Давайте детально разберем, как можно найти метод, содержащий DeclRefExpr переменной, и произвести необходимые изменения.

1. Основные шаги

Для начала вам нужно распарсить исходный код и создать AST. После этого используйте matcher для поиска DeclRefExpr, который был сопоставлен с именем переменной myName. Затем, получив ссылку на метод, вы сможете внести изменения в код.

2. Поиск DeclRefExpr

Вы уже имеете часть кода для создания matcher, и следующая цель – сопоставить ссылку на myName. Ваш matcher выглядит корректно, однако для того чтобы проследовать от varDecl к функции findByName, вам понадобится дополнительная логика.

3. Модификация Matcher для поиска функции

Вы можете использовать callExpr для нахождения конкретного вызова функции, что поможет связать переменную с методом класса. Ниже приведен пример, как это сделать:

auto matcher = callExpr(
        callee(hasDeclaration(cxxMethodDecl(hasName("findByName")))),
        hasArgument(0, 
            declRefExpr(to(varDecl(hasName("myName"))))
        )
    ).bind("callExpr");

Это позволит находить нужный вызов метода в AST, используя hasArgument и declRefExpr для получения имени переменной.

4. Применение замены

При использовании ASTConsumer, реализуйте логику для замены findByName на findByNameV2, а myName на newName. Пример класса ASTConsumer, который добивается этого:

class MyASTConsumer : public ASTConsumer {
public:
    void HandleTranslationUnit(ASTContext &context) override {
        MatchFinder finder;
        finder.addMatcher(matcher, this);
        finder.matchAST(context);
    }

    void run(const MatchFinder::MatchResult &result) override {
        if (const auto *callExpr = result.Nodes.getNodeAs<CallExpr>("callExpr")) {
            const auto *methodDecl = callExpr->getDirectCallee();

            // Замена имени метода
            if (methodDecl) {
                SourceLocation loc = methodDecl->getLocation();
                // вставьте здесь код замены на 'findByNameV2'
            }

            // Замена имени переменной
            const auto *declRef = result.Nodes.getNodeAs<DeclRefExpr>("varRef");
            if (declRef) {
                SourceLocation loc = declRef->getLocation();
                // вставьте здесь код замены 'myName' на 'newName'
            }
        }
    }
};

5. Заключение

Использование данного подхода в Clang LibTooling позволит вам эффективно находить и заменять функционал в коде на основе AST. Это не только ускоряет процесс разработки, но и делает код более чистым и понятным. Общая стратегия включает в себя нахождение нужного варианта выражения, а затем выполнение замены непосредственно в AST, чтобы произвести изменения в исходном коде.

Подводя итог, вы получите механизм для трансформации вашего C++ кода, что приведет к внесению желаемых изменений в программное обеспечение без необходимости вручную редактировать каждый вызов функции.

Оцените материал
Добавить комментарий

Капча загружается...