我正在尝试匹配具有返回值但未使用的函数。像这样:
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找不到东西。
感谢您的帮助。
答案 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进行快乐的黑客入侵!