I generally followed Artem’s suggestions (for my approach) and things worked out okay. Specifically:
void MyChecker::checkPreCall(const CallEvent &Call, CheckerContext &ChCtx) const {
const Stmt *Parent = ChCtx.getStackFrame()->getParentMap().getParent(Call.getOriginExpr());
if (!Parent || !isa(Parent))
return;
// Proceed with my checks.
}
Then I generalized this a bit, but still in a syntactic way (not in the path-sensitive way Artem suggested). The idea is to follow the parent chain to get the first non-Expr statement containing the call, and then check if that statement makes use of the expression value (which is built from the call’s return value).
bool isReturnValueUsed(const CallEvent &Call, CheckerContext &ChCtx) {
const ParentMap &PM = ChCtx.getStackFrame()->getParentMap();
const Expr *TopLevelExpr = Call.getOriginExpr();
const Stmt *Containing Stmt = PM.getParent(TopLevelExpr);
while (ContainingStmt && isa(ContainingStmt)) {
if (is(ContainingStmt) && cast(ContainingStmt)->isAssignmentOp())
return true; // return value is used in an assignment
TopLevelExpr = cast(ContainingStmt);
ContainingStmt = PM.getParent(TopLevelExpr);
}
if (!ContainingStmt)
return false;
if (isa(ContainingStmt))
return true; // return value is used in an initialization
if (isa(ContainingStmt) && TopLevelExpr == cast(ContainingStmt)->getCond())
return true; // return value is used in an if condition
if (isa(ContainingStmt) && TopLevelExpr == cast(ContainingStmt)->getCond())
return true; // return value is used in a switch condition
if (isa(ContainingStmt) && TopLevelExpr == cast(ContainingStmt)->getCond())
return true; // return value is used in a while loop condition
if (isa(ContainingStmt) && TopLevelExpr == cast(ContainingStmt)->getCond())
return true; // return value is used in do loop condition
if (isa(ContainingStmt) && TopLevelExpr == cast(ContainingStmt)->getRetValue())
return true; // return value is used to construct a higher-level return value
return false;
}
void MyChecker::checkPreCall(const CallEvent &Call, CheckerContext &ChCtx) const {
const Stmt *Parent = ChCtx.getStackFrame()->getParentMap().getParent(Call.getOriginExpr());
if (!Parent || !isa(Parent))
return;
// Proceed with my checks.
}