ztamas created this revision.
Herald added subscribers: cfe-commits, jdoerfert, xazax.hun.
Herald added a project: clang.

The bugprone-too-small-loop-variable check often catches loop variables which 
can represent "big enough" values, so we don't actually need to worry about 
that this variable will overflow in a loop when the code iterates through a 
container. For example a 32 bit signed integer type's maximum value is 2 147 
483 647 and a container's size won't reach this maximum value in most of the 
cases.
So the idea of this option to allow the user to specify an upper limit (using 
magnitude bit of the integer type) to filter out those catches which are not 
interesting for the user, so he/she can focus on the more risky integer 
incompatibilities.
Next to the option I replaced the term "positive bits" to "magnitude bits" 
which seems a better naming both in the code and in the name of the new option.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D59870

Files:
  clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp
  clang-tidy/bugprone/TooSmallLoopVariableCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-too-small-loop-variable.rst
  test/clang-tidy/bugprone-too-small-loop-variable-magniute-bits-upper-limit.cpp

Index: test/clang-tidy/bugprone-too-small-loop-variable-magniute-bits-upper-limit.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/bugprone-too-small-loop-variable-magniute-bits-upper-limit.cpp
@@ -0,0 +1,31 @@
+// RUN: %check_clang_tidy %s bugprone-too-small-loop-variable %t -- \
+// RUN:   -config="{CheckOptions: \
+// RUN:             [{key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit, \
+// RUN:               value: 31}]}" \
+// RUN:   -- --target=x86_64-linux
+
+unsigned long size() { return 294967296l; }
+
+void voidFilteredOutForLoop1() {
+  for (long i = 0; i < size(); ++i) {
+    // no warning
+  }
+}
+
+void voidFilteredOutForLoop2() {
+  for (unsigned i = 0; i < size(); ++i) {
+    // no warning
+  }
+}
+
+void voidCaughtForLoop1() {
+  for (int i = 0; i < size(); ++i) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'unsigned long' [bugprone-too-small-loop-variable]
+  }
+}
+
+void voidCaughtForLoop2() {
+  for (short i = 0; i < size(); ++i) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'unsigned long' [bugprone-too-small-loop-variable]
+  }
+}
Index: docs/clang-tidy/checks/bugprone-too-small-loop-variable.rst
===================================================================
--- docs/clang-tidy/checks/bugprone-too-small-loop-variable.rst
+++ docs/clang-tidy/checks/bugprone-too-small-loop-variable.rst
@@ -27,3 +27,20 @@
 
 This algorithm works for small amount of objects, but will lead to freeze for a
 a larger user input.
+
+.. option:: MagnitudeBitsUpperLimit
+
+  Upper limit for the magnitue bits of the loop variable. If it's set the check
+  filters out those catches in which the loop variable's type has more magnitude
+  bit as the specified upper limit.
+  For example, if the user sets this attribute to 31, then a 32-bit ``unsigend int``
+  is ignored by the check, however a 32-bit ``int`` is not (A 32-bit ``signed int``
+  has 31 magnitude bits).
+
+.. code-block:: c++
+
+  int main() {
+    long size = 294967296l;
+    for (unsigned i = 0; i < size; ++i) {} // no warning
+    for (int i = 0; i < size; ++i) {} // warning
+  }
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -119,6 +119,10 @@
   `CommentUserDefiniedLiterals`, `CommentStringLiterals`,
   `CommentCharacterLiterals` & `CommentNullPtrs` options.
 
+- The :bugprone-too-small-loop-variable
+  <clang-tidy/checks/bugprone-too-small-loop-variable>` now supports
+  `MagnitudeBitsUpperLimit` option.
+
 - The :doc:`google-runtime-int <clang-tidy/checks/google-runtime-int>`
   check has been disabled in Objective-C++.
 
Index: clang-tidy/bugprone/TooSmallLoopVariableCheck.h
===================================================================
--- clang-tidy/bugprone/TooSmallLoopVariableCheck.h
+++ clang-tidy/bugprone/TooSmallLoopVariableCheck.h
@@ -29,10 +29,14 @@
 /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-too-small-loop-variable.html
 class TooSmallLoopVariableCheck : public ClangTidyCheck {
 public:
-  TooSmallLoopVariableCheck(StringRef Name, ClangTidyContext *Context)
-      : ClangTidyCheck(Name, Context) {}
+  TooSmallLoopVariableCheck(StringRef Name, ClangTidyContext *Context);
+
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  const unsigned MagnitudeBitsUpperLimit;
 };
 
 } // namespace bugprone
Index: clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp
===================================================================
--- clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp
+++ clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp
@@ -27,6 +27,17 @@
 static constexpr llvm::StringLiteral LoopIncrementName =
     llvm::StringLiteral("loopIncrement");
 
+TooSmallLoopVariableCheck::TooSmallLoopVariableCheck(StringRef Name,
+                                                     ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      MagnitudeBitsUpperLimit(Options.get<unsigned>(
+          "MagnitudeBitsUpperLimit", std::numeric_limits<unsigned>::max())) {}
+
+void TooSmallLoopVariableCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "MagnitudeBitsUpperLimit", MagnitudeBitsUpperLimit);
+}
+
 /// \brief The matcher for loops with suspicious integer loop variable.
 ///
 /// In this general example, assuming 'j' and 'k' are of integral type:
@@ -84,9 +95,9 @@
       this);
 }
 
-/// Returns the positive part of the integer width for an integer type.
-static unsigned calcPositiveBits(const ASTContext &Context,
-                                 const QualType &IntExprType) {
+/// Returns the magnitude bits of an integer type.
+static unsigned calcMagnitudeBits(const ASTContext &Context,
+                                  const QualType &IntExprType) {
   assert(IntExprType->isIntegerType());
 
   return IntExprType->isUnsignedIntegerType()
@@ -94,13 +105,13 @@
              : Context.getIntWidth(IntExprType) - 1;
 }
 
-/// \brief Calculate the upper bound expression's positive bits, but ignore
+/// \brief Calculate the upper bound expression's magnitude bits, but ignore
 /// constant like values to reduce false positives.
-static unsigned calcUpperBoundPositiveBits(const ASTContext &Context,
-                                           const Expr *UpperBound,
-                                           const QualType &UpperBoundType) {
+static unsigned calcUpperBoundMagnitudeBits(const ASTContext &Context,
+                                            const Expr *UpperBound,
+                                            const QualType &UpperBoundType) {
   // Ignore casting caused by constant values inside a binary operator.
-  // We are interested in variable values' positive bits.
+  // We are interested in variable values' magnitude bits.
   if (const auto *BinOperator = dyn_cast<BinaryOperator>(UpperBound)) {
     const Expr *RHSE = BinOperator->getRHS()->IgnoreParenImpCasts();
     const Expr *LHSE = BinOperator->getLHS()->IgnoreParenImpCasts();
@@ -122,15 +133,15 @@
     if (RHSEIsConstantValue && LHSEIsConstantValue)
       return 0;
     if (RHSEIsConstantValue)
-      return calcPositiveBits(Context, LHSEType);
+      return calcMagnitudeBits(Context, LHSEType);
     if (LHSEIsConstantValue)
-      return calcPositiveBits(Context, RHSEType);
+      return calcMagnitudeBits(Context, RHSEType);
 
-    return std::max(calcPositiveBits(Context, LHSEType),
-                    calcPositiveBits(Context, RHSEType));
+    return std::max(calcMagnitudeBits(Context, LHSEType),
+                    calcMagnitudeBits(Context, RHSEType));
   }
 
-  return calcPositiveBits(Context, UpperBoundType);
+  return calcMagnitudeBits(Context, UpperBoundType);
 }
 
 void TooSmallLoopVariableCheck::check(const MatchFinder::MatchResult &Result) {
@@ -149,14 +160,17 @@
 
   ASTContext &Context = *Result.Context;
 
-  unsigned LoopVarPosBits = calcPositiveBits(Context, LoopVarType);
-  unsigned UpperBoundPosBits =
-      calcUpperBoundPositiveBits(Context, UpperBound, UpperBoundType);
+  unsigned LoopVarMagnitudeBits = calcMagnitudeBits(Context, LoopVarType);
+  unsigned UpperBoundMagnitudeBits =
+      calcUpperBoundMagnitudeBits(Context, UpperBound, UpperBoundType);
+
+  if (UpperBoundMagnitudeBits == 0)
+    return;
 
-  if (UpperBoundPosBits == 0)
+  if (LoopVarMagnitudeBits > MagnitudeBitsUpperLimit)
     return;
 
-  if (LoopVarPosBits < UpperBoundPosBits)
+  if (LoopVarMagnitudeBits < UpperBoundMagnitudeBits)
     diag(LoopVar->getBeginLoc(), "loop variable has narrower type %0 than "
                                  "iteration's upper bound %1")
         << LoopVarType << UpperBoundType;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to