未使用的返回值的ast匹配器

时间:2019-05-26 03:19:18

标签: c function return clang abstract-syntax-tree

我正在尝试匹配具有返回值但未使用的函数。像这样:

int foo(int a) { return 0; }

int main(void) {

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

return 0;
}

我正在尝试编写一个与foo(5)匹配的ast匹配器;并在将-fix与clang-tidy一起使用时,在前面粘贴一个(void)。

我有点迷茫。我知道functionDecl()将为我提供所有功能,但是如何检查该函数的返回值是否使用? 我用clang-query找不到东西。

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

首先,您不需要匹配函数声明,而是调用表达式。解构此问题,我们得到以下信息:我们需要匹配所有调用返回 something 并且不用作某处操作数的函数的调用表达式。

第一个条件非常简单。但是,第二个可以有很多不同的变化,因为使用的返回值可以通过多种方式出现在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进行快乐的黑客入侵!