Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangTidyMiscModule ArgumentCommentCheck.cpp BoolPointerImplicitConversion.cpp + IncompleteSwitchCheck.cpp MiscTidyModule.cpp RedundantSmartptrGet.cpp SwappedArgumentsCheck.cpp Index: clang-tidy/misc/IncompleteSwitchCheck.h =================================================================== --- /dev/null +++ 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 */ Index: clang-tidy/misc/IncompleteSwitchCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/misc/IncompleteSwitchCheck.cpp @@ -0,0 +1,27 @@ +#include "IncompleteSwitchCheck.h" +#include + +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("cast"); + if (c->getCastKind() == CK_IntegralCast) + return; + + const auto s = Result.Nodes.getNodeAs("switch"); + diag(s->getCond()->getLocStart(), "switching on non-enum value without " + "default case may not cover all cases"); +} +} // tidy +} // clang Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ 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 @@ "misc-redundant-smartptr-get", new ClangTidyCheckFactory()); CheckFactories.addCheckFactory( + "misc-incomplete-switch", + new ClangTidyCheckFactory()); + CheckFactories.addCheckFactory( "misc-swapped-arguments", new ClangTidyCheckFactory()); CheckFactories.addCheckFactory( Index: test/clang-tidy/incomplete-switch.cpp =================================================================== --- /dev/null +++ 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; + } +}