Basically I am writing a clang-tidy check to detect "bad" divisions where there is a division and the divisor was not checked with an assert() statement.
In the following example good_disvisor should pass the check as there is an assert checking it's equality to zero but bad_divisor should be detected and marked.
#include <cassert>
int main() {
const double good_divisor = 0.3;
assert(good_divisor != 0.0);
double foo = 1.0 / good_divisor;
const double bad_divisor = 0.3;
double bar = 1.0 / bad_divisor;
return 0;
}
So far my machers and check can only detect the divison opeartor but couldn't do much beyond it:
void UnsafeArithmeticCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(binaryOperator(hasOperatorName("/")).bind("div"), this);
}
void UnsafeArithmeticCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Binop = Result.Nodes.getNodeAs<BinaryOperator>("div");
if (!Binop) {
return;
}
diag(Binop->getExprLoc(), "found a division here", DiagnosticIDs::Note);
auto rhs = Binop->getRHS();
// now how do I check if this `rhs` is a variable and not an expression?
}
I think there are 3 steps missing still:
- to check if
rhsfrom division operator is a variable (and not an expression). In my check I get it throughBinop->getRHS()but I can't find an function to examine it's type - to check if there is an
asssert()prior to theDeclStmt(the father node of this divison operator) - if there is such an
assert(), then further check if there is arhs != 0in it (rhswas identified from step 1)
Can someone help me to complete this check?
Answering @Scott's question (what I hope to achieve that core.DivideZero can't not):
core.DivideZero simply couldn't detect code like below:
double foo(double x) {
return x * 3 - 1;
}
int main() {
double divisor = foo(0.3);
double x = 1.0 / divisor;
return 0;
}
And I hope my check can mark an error for:
double divisor = foo(0.3);
double x = 1.0 / divisor;
and wouldn't raise an error when assert() added:
double divisor = foo(0.3);
assert(divisor != 0);
double x = 1.0 / divisor;