Ast Matcher для неиспользованного возвращаемого значения - PullRequest
0 голосов
/ 26 мая 2019

Я пытаюсь сопоставить функции, которые имеют возвращаемые значения, но не используются. Примерно так:

int foo(int a) { return 0; }

int main(void) {

foo(5); -->> replace with (void) foo(5);

return 0;
}

Я пытаюсь написать ast-matcher, который соответствует foo (5); и вставляет (void) впереди, когда я использую -fix с clang-tidy.

Я немного потерян. Я знаю, что functionDecl () даст мне все функции, но как я могу проверить, используется ли возвращаемое значение этой функции? Я не смог найти что-то с помощью clang-query.

Любая помощь приветствуется.

1 Ответ

0 голосов
/ 02 июня 2019

Прежде всего, вам нужно сопоставлять не объявления функций, а выражения вызовов.Деконструируя эту проблему, мы получаем следующее: нам нужно сопоставить все выражения вызова, которые вызывают функции, возвращающие что-то и не используемые где-либо в качестве операнда.

Первое условие довольно простое.Тем не менее, второй вариант может иметь много разных вариантов, так как используемое возвращаемое значение может появляться в AST многими разными способами:

  • операнд некоторого другого выражения
  • возвращаемое значение
  • инициализатор для объявления переменных
  • условие в if / while / do while / for / switch операторов

Возможноесть некоторые другие случаи, о которых я не думал.

Собираем все вместе без последнего случая:

callExpr(callee(functionDecl(unless(returns(voidType())))),
         unless(hasParent(anyOf(expr(), returnStmt()))),
         unless(hasParent(varDecl())))

Для условий в различных утверждениях не существует общепринятого способапроверьте, чтобы был реализован новый механизм сопоставления.

#include <clang/ASTMatchers/ASTMatchers.h>

template <class... Other>
bool isCondition(const clang::Expr *Node, const clang::Stmt *Parent);

template <class ConditionalNode, class... Other>
inline bool isConditionImpl(const clang::Expr *Node,
                            const clang::Stmt *Parent) {
  if (const auto *AsConditional = llvm::dyn_cast<ConditionalNode>(Parent)) {
    return AsConditional->getCond() == Node;
  }

  return isCondition<Other...>(Node, Parent);
}

template <class... Other>
inline bool isCondition(const clang::Expr *Node, const clang::Stmt *Parent) {
  return isConditionImpl<Other...>(Node, Parent);
}

template <>
inline bool isCondition(const clang::Expr *,
                        const clang::Stmt *) {
  return false;
}

AST_MATCHER(clang::Expr, isInCondition) {
  auto &Context = Finder->getASTContext();
  auto *Parent = Context.getParents(Node)[0].get<clang::Stmt>();
  if (Parent == nullptr) {
    return false;
  }
  return isCondition<clang::DoStmt, clang::IfStmt, clang::ForStmt,
                     clang::SwitchStmt, clang::WhileStmt>(&Node, Parent);
}

Включая этот новый механизм сопоставления, мы можем использовать следующий механизм сопоставления:

callExpr(callee(functionDecl(unless(returns(voidType())))),
         unless(hasParent(anyOf(expr(), returnStmt()))),
         unless(hasParent(varDecl())),
         unless(isInCondition()))

Скорее всего, это решение может быть грубымпо краям в некоторых случаях, включая неявное приведение, но это может дать вам представление.

Счастливого взлома с помощью clang!

...