[PATCH] D37808: [clang-tidy] Add new hicpp-multiway-paths-covered check for missing branches

Aaron Ballman via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 15 10:39:35 PST 2017


aaron.ballman added inline comments.


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:13
+
+#include <iostream>
+#include <limits>
----------------
Including <iostream> is forbidden by our coding standard. However, it doesn't appear to be used in the source file, either.


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:41
+          switchStmt(hasCondition(allOf(
+              // Match on switch statements that have either bitfield or integer
+              // condition.
----------------
either bitfield or integer condition -> either a bit-field or an integer condition


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:43
+              // condition.
+              // The ordering in 'anyOf()' is important, since the last
+              // condition is the most general.
----------------
since -> because

Also, drop the comma.


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:48
+                    hasDescendant(declRefExpr().bind("non-enum-condition"))),
+              // 'unless()' must be the last match here and must be binded,
+              // otherwise the matcher does not work correctly.
----------------
binded -> bound


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:54
+
+  /// This option is noisy, therefore matching is configurable.
+  if (WarnOnMissingElse) {
----------------
Don't use doxygen comments here.


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:63
+
+namespace {
+unsigned countCaseLabels(const SwitchStmt *Switch) {
----------------
Our usual preference is to make these methods static rather than put them in an anonymous namespace (types go into anonymous namespaces, however).


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:80
+
+  return Bits > 0 && DiscreteValues <= 1
+             ? std::numeric_limits<std::size_t>::max()
----------------
This logic does not make sense to me -- the goal is to test for overflow, which can be done solely by looking at the value of `Bits` and the size of `std::size_t`. The current logic appears to return 1 if `Bits == 0` and will only return the max value if the wraparound happens to precisely create the value 0 or 1. I'd replace with:
```
return Bits >= std::numeric_limits<std::size_t>::digits() ? std::numeric_limits<std::size_t>::max() : static_cast<size_t>(1) << Bits;
```


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:84
+}
+/// Get the number of different values for the Type T, that is switched on.
+///
----------------
How about: Get the number of possible values that can be switched on for the type T


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:91-92
+  // Context.getTypeSize(T) returns the number of bits T uses.
+  // Calculates the number of discrete values that are representable by this
+  // type.
+  return T->isIntegralType(Context) ? twoPow(Context.getTypeSize(T))
----------------
I don't think this comment adds value.


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:94
+  return T->isIntegralType(Context) ? twoPow(Context.getTypeSize(T))
+                                    : twoPow(0ul);
+}
----------------
No need for the `ul` suffix -- the type will undergo implicit conversion with or without the suffix.


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:94
+  return T->isIntegralType(Context) ? twoPow(Context.getTypeSize(T))
+                                    : twoPow(0ul);
+}
----------------
aaron.ballman wrote:
> No need for the `ul` suffix -- the type will undergo implicit conversion with or without the suffix.
Why call toPow instead of just returning the value `1` directly?


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:102
+    diag(ElseIfWithoutElse->getLocStart(),
+         "potential uncovered codepath; add an ending else branch");
+    return;
----------------
potential uncovered codepath -> potentially uncovered code path
branch -> statement


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:131
+    const SwitchStmt *Switch) {
+  const unsigned CaseCount = countCaseLabels(Switch);
+  assert(CaseCount > 0 && "Switch statementt with supposedly one default "
----------------
No need to make this `const` (we only do that for reference and pointer types, not other local variable or parameter types). Here and elsewhere.


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:132
+  const unsigned CaseCount = countCaseLabels(Switch);
+  assert(CaseCount > 0 && "Switch statementt with supposedly one default "
+                          "branch did not contain any case labels");
----------------
statementt -> statement


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:138
+             ? "degenerated switch with default label only"
+             : "switch could be better written as if/else statement");
+}
----------------
as if/else -> as an if/else


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:143-145
+  // The matcher only works, because some nodes are explicitly matched and
+  // bound, but ignored. This is necessary, to build the excluding logic for
+  // enums and 'switch' statements without a 'default' branch.
----------------
Remove all commas.


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:161
+                          "should be excluded by the matcher and is handled "
+                          "seperatly");
+  const std::size_t MaxPathsPossible = [&]() {
----------------
seperatly -> separately.

(period also)


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:176
+    diag(Switch->getLocStart(),
+         CaseCount == 1 ? "switch with only one case; use if statement"
+                        : "potential uncovered codepath; add a default case");
----------------
use if -> use an if


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp:177
+         CaseCount == 1 ? "switch with only one case; use if statement"
+                        : "potential uncovered codepath; add a default case");
+}
----------------
potential uncovered codepath -> potentially uncovered code path
default case -> default label


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.h:21
+
+/// Find occasions, where not all codepaths are explicitly covered in code.
+/// This includes 'switch' without a 'default'-branch and 'if'-'else if'-chains
----------------
Drop the comma.


================
Comment at: clang-tidy/hicpp/MultiwayPathsCoveredCheck.h:41-43
+  /// This option configures if there is a warning on missing 'else'-branches
+  /// in 'if-else if'-chains. The default is false, since this option might be
+  /// very noisy on particular codebases.
----------------
How about:
```
This option can be configured to warn on missing 'else' branches in an 'if-else if' chain. The default is false because this option might be noisy on some code bases.
```


================
Comment at: docs/ReleaseNotes.rst:139
+
+  Checks on various possible constellations where ``switch`` and ``if-else if`` statements
+  do not cover all possible codepaths.
----------------
Perhaps: Checks on switch and if-else if constructs that do not cover all possible code paths.


================
Comment at: docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst:6
+
+This check catches multiple occasion where not all possible code paths are covered.
+It furthermore suggests using ``if`` instead of ``switch`` if the code gets clearer with it.
----------------
Perhaps: This check discovers situations where code paths are not fully-covered.


================
Comment at: docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst:7
+This check catches multiple occasion where not all possible code paths are covered.
+It furthermore suggests using ``if`` instead of ``switch`` if the code gets clearer with it.
+The `rule 6.1.2 <http://www.codingstandard.com/rule/6-1-2-explicitly-cover-all-paths-through-multi-way-selection-statements/>`_
----------------
gets clearer with it -> will be more clear


================
Comment at: docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst:16
+comment.
+Since this warning might be very noise on many codebases it is configurable and by 
+default deactivated.
----------------
Perhaps: This warning can be noisy on some code bases, so it is disabled by default.


================
Comment at: docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst:32
+
+Similar arguments hold for ``switch`` statements, that do not cover all possible code paths.
+
----------------
, that -> which


================
Comment at: docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst:62
+The `rule 6.1.4 <http://www.codingstandard.com/rule/6-1-4-ensure-that-a-switch-statement-has-at-least-two-case-labels-distinct-from-the-default-label/>`_
+requires every ``switch`` statement to have at least two ``case`` labels, that are not default.
+Otherwise the ``switch`` could be better expressed with a common ``if`` statement.
----------------
, that are not default -> other than a ``default`` label


================
Comment at: docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst:63
+requires every ``switch`` statement to have at least two ``case`` labels, that are not default.
+Otherwise the ``switch`` could be better expressed with a common ``if`` statement.
+Degenerated ``switch`` statements without any labels are catched as well.
----------------
Otherwise should have a comma after it

I'd remove "common" and go with "with an ``if`` statement."


================
Comment at: docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst:64
+Otherwise the ``switch`` could be better expressed with a common ``if`` statement.
+Degenerated ``switch`` statements without any labels are catched as well.
+
----------------
catched -> caught


================
Comment at: docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst:68
+
+  // Degenerated switch that could be better written as if()
+  int i = 42;
----------------
if() -> an ``if`` statement:


================
Comment at: docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst:86
+  
+  // Completly degenerated switch, will be warned.
+  int i = 42;
----------------
Completly -> A completely
warned -> diagnosed

drop the comma.


================
Comment at: test/clang-tidy/hicpp-multiway-paths-covered.cpp:445
+  }
+}
----------------
For fun, can you add a switch over a value of type `bool`?
```
void f(bool b) {
  switch (b) {
  case true:
  }

  switch (b) {
  default:
  }

  switch (b) {
  case true:
  case false:
  }
}
```


https://reviews.llvm.org/D37808





More information about the cfe-commits mailing list