[PATCH] [clang-tidy] Add check for possibly incomplete switch statements

Benjamin Bannier bbannier at gmail.com
Sun Aug 3 08:04:44 PDT 2014


While clang warns about a possibly incomplete switch statement when
switching over an enum variable and failing to cover all enum values
(either explicitly or with a default case), no such warning is emitted
if a plain integer variable is used as switch variable.

Add a clang-tidy check to diagnose these scenarios.

No fixit hint is provided since there are multiple possible solutions.
---
 clang-tidy/misc/CMakeLists.txt            |    1 +
 clang-tidy/misc/IncompleteSwitchCheck.cpp |   27 +++++++++++++++++++++++++++
 clang-tidy/misc/IncompleteSwitchCheck.h   |   17 +++++++++++++++++
 clang-tidy/misc/MiscTidyModule.cpp        |    4 ++++
 test/clang-tidy/incomplete-switch.cpp     |   27 +++++++++++++++++++++++++++
 5 files changed, 76 insertions(+)
 create mode 100644 clang-tidy/misc/IncompleteSwitchCheck.cpp
 create mode 100644 clang-tidy/misc/IncompleteSwitchCheck.h
 create mode 100644 test/clang-tidy/incomplete-switch.cpp

diff --git a/clang-tidy/misc/CMakeLists.txt b/clang-tidy/misc/CMakeLists.txt
index fbe5bb0..2c7ce33 100644
--- a/clang-tidy/misc/CMakeLists.txt
+++ b/clang-tidy/misc/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS support)
 add_clang_library(clangTidyMiscModule
   ArgumentCommentCheck.cpp
   BoolPointerImplicitConversion.cpp
+  IncompleteSwitchCheck.cpp
   MiscTidyModule.cpp
   RedundantSmartptrGet.cpp
   SwappedArgumentsCheck.cpp
diff --git a/clang-tidy/misc/IncompleteSwitchCheck.cpp b/clang-tidy/misc/IncompleteSwitchCheck.cpp
new file mode 100644
index 0000000..f36414c
--- /dev/null
+++ b/clang-tidy/misc/IncompleteSwitchCheck.cpp
@@ -0,0 +1,27 @@
+#include "IncompleteSwitchCheck.h"
+#include <iostream>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+void
+IncompleteSwitchCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
+  Finder->addMatcher(
+      switchStmt(hasDescendant(implicitCastExpr().bind("cast")),
+                 unless(hasDescendant(defaultStmt()))).bind("switch"),
+      this);
+}
+
+void IncompleteSwitchCheck::check(
+    const ast_matchers::MatchFinder::MatchResult &Result) {
+  const auto c = Result.Nodes.getNodeAs<ImplicitCastExpr>("cast");
+  if (c->getCastKind() == CK_IntegralCast)
+    return;
+
+  const auto s = Result.Nodes.getNodeAs<SwitchStmt>("switch");
+  diag(s->getCond()->getLocStart(), "switching on non-enum value without "
+                                    "default case may not cover all cases");
+}
+} // tidy
+} // clang
diff --git a/clang-tidy/misc/IncompleteSwitchCheck.h b/clang-tidy/misc/IncompleteSwitchCheck.h
new file mode 100644
index 0000000..60fbd90
--- /dev/null
+++ b/clang-tidy/misc/IncompleteSwitchCheck.h
@@ -0,0 +1,17 @@
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_INCOMPLETESWITCHCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_INCOMPLETESWITCHCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+class IncompleteSwitchCheck : public ClangTidyCheck {
+public:
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+} // tidy
+} // clang
+
+#endif /* end of include guard: INCOMPLETESWITCHCHECK_H */
diff --git a/clang-tidy/misc/MiscTidyModule.cpp b/clang-tidy/misc/MiscTidyModule.cpp
index 8cf70d3..7fb7c0b 100644
--- a/clang-tidy/misc/MiscTidyModule.cpp
+++ b/clang-tidy/misc/MiscTidyModule.cpp
@@ -12,6 +12,7 @@
 #include "../ClangTidyModuleRegistry.h"
 #include "ArgumentCommentCheck.h"
 #include "BoolPointerImplicitConversion.h"
+#include "IncompleteSwitchCheck.h"
 #include "RedundantSmartptrGet.h"
 #include "SwappedArgumentsCheck.h"
 #include "UndelegatedConstructor.h"
@@ -34,6 +35,9 @@ public:
         "misc-redundant-smartptr-get",
         new ClangTidyCheckFactory<RedundantSmartptrGet>());
     CheckFactories.addCheckFactory(
+        "misc-incomplete-switch",
+        new ClangTidyCheckFactory<IncompleteSwitchCheck>());
+    CheckFactories.addCheckFactory(
         "misc-swapped-arguments",
         new ClangTidyCheckFactory<SwappedArgumentsCheck>());
     CheckFactories.addCheckFactory(
diff --git a/test/clang-tidy/incomplete-switch.cpp b/test/clang-tidy/incomplete-switch.cpp
new file mode 100644
index 0000000..5cc6a05
--- /dev/null
+++ b/test/clang-tidy/incomplete-switch.cpp
@@ -0,0 +1,27 @@
+// RUN: clang-tidy --checks='-*,misc-incomplete-switch' %s -- | FileCheck %s
+
+void Positive() {
+  int i = 0;
+  // CHECK: [[@LINE+1]]:11: warning: switching on non-enum value without default case may not cover all cases [misc-incomplete-switch]
+  switch (i) {
+  case 0:
+    break;
+  }
+}
+
+void Negative() {
+  enum E { eE1 };
+  E e = eE1;
+  switch (e) { // no-warning
+  case eE1:
+    break;
+  }
+
+  int i = 0;
+  switch (i) { // no-warning
+  case 0:
+    break;
+  default:
+    break;
+  }
+}
-- 
1.7.10.4




More information about the cfe-commits mailing list