Finds cases where integer division in a floating point context is likely to
cause unintended loss of precision.
No reports are made if divisions are part of the following expressions:
- operands of operators expecting integral or bool types,
- call expressions of integral or bool types, and
- explicit cast expressions to integral or bool types,
as these are interpreted as signs of deliberateness from the programmer.
Examples:
float floatFunc(float); int intFunc(int); double d; int i = 42; // Warn, floating-point values expected. d = 32 * 8 / (2 + i); d = 8 * floatFunc(1 + 7 / 2); d = i / (1 << 4); // OK, no integer division. d = 32 * 8.0 / (2 + i); d = 8 * floatFunc(1 + 7.0 / 2); d = (double)i / (1 << 4); // OK, there are signs of deliberateness. d = 1 << (i / 2); d = 9 + intFunc(6 * i / 32); d = (int)(i / 32) - 8;
The way hasAncestor is used in this code makes me uneasy. Each nested ancestor traversal can potentially slow down matching by a factor of the depth of the AST tree, which may lead to poor performance on certain types of code (nested descendant traversal is much worse though). Some of the overhead may be compensated by memoization, but it's hard to predict where it will actually work.
It's usually better to avoid nested ancestor traversals, if there are good alternatives. Here I don't see a better possibility with matchers, but it's to go one level lower and use RecursiveASTVisitor directly. Without constructing / discovering a problematic case it's hard to tell whether the performance win of switching to RAV is worth the added complexity, so I'm not suggesting to do that yet. Just mentioning a possible issue to be aware of.