我正在尝试匹配具有返回值但未使用的函数。像这样的事情:
int foo(int a) { return 0; }
int main(void) {
foo(5); -->> replace with (void) foo(5);
return 0;
}
我正在尝试编写一个与 foo(5) 匹配的 ast-matcher;当我使用 -fix 和 clang-tidy 时,在前面粘贴 (void)。
我有点迷失了。我知道 functionDecl() 会给我所有的函数,但是我如何检查该函数的返回值是否被使用? 我无法使用 clang-query 找到某些内容。
感谢任何帮助。
最佳答案
首先,您需要匹配的不是函数声明,而是调用表达式。解构这个问题,我们得到以下结论:我们需要匹配所有调用函数返回某物并且不被用作某处操作数的调用表达式。
第一个条件非常简单。然而,第二个可以有许多不同的变体,因为使用的返回值可以以多种方式出现在 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 进行黑客攻击!
关于c - 未使用的返回值的 ast 匹配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56310386/