10#include "clang/AST/ASTContext.h"
19 Options.store(Opts,
"WarnOnMissingElse", WarnOnMissingElse);
29 anyOf(ignoringImpCasts(memberExpr(hasDeclaration(
30 fieldDecl(isBitField()).bind(
"bitfield")))),
31 ignoringImpCasts(declRefExpr().bind(
"non-enum-condition"))),
35 unless(ignoringImpCasts(
36 declRefExpr(hasType(hasCanonicalType(enumType())))
37 .bind(
"enum-condition"))))))
42 if (WarnOnMissingElse) {
43 Finder->addMatcher(ifStmt(hasParent(ifStmt()), unless(hasElse(anything())))
50 std::size_t CaseCount = 0;
51 bool HasDefault =
false;
53 const SwitchCase *CurrentCase = Switch->getSwitchCaseList();
56 if (isa<DefaultStmt>(CurrentCase))
59 CurrentCase = CurrentCase->getNextSwitchCase();
62 return {CaseCount, HasDefault};
67static std::size_t
twoPow(std::size_t Bits) {
68 return Bits >= std::numeric_limits<std::size_t>::digits
69 ? std::numeric_limits<std::size_t>::max()
70 :
static_cast<size_t>(1) << Bits;
79 const ASTContext &Context) {
82 if (T->isBooleanType())
84 if (T->isIntegralType(Context))
85 return twoPow(Context.getTypeSize(T));
90 if (
const auto *ElseIfWithoutElse =
91 Result.Nodes.getNodeAs<IfStmt>(
"else-if")) {
92 diag(ElseIfWithoutElse->getBeginLoc(),
93 "potentially uncovered codepath; add an ending else statement");
96 const auto *Switch = Result.Nodes.getNodeAs<SwitchStmt>(
"switch");
97 std::size_t SwitchCaseCount = 0;
98 bool SwitchHasDefault =
false;
103 if (SwitchHasDefault) {
104 handleSwitchWithDefault(Switch, SwitchCaseCount);
109 if (!SwitchHasDefault && SwitchCaseCount > 0) {
110 handleSwitchWithoutDefault(Switch, SwitchCaseCount, Result);
117 if (!SwitchHasDefault && SwitchCaseCount == 0) {
118 diag(Switch->getBeginLoc(),
119 "switch statement without labels has no effect");
122 llvm_unreachable(
"matched a case, that was not explicitly handled");
125void UnhandledCodePathsCheck::handleSwitchWithDefault(
const SwitchStmt *Switch,
126 std::size_t CaseCount) {
127 assert(CaseCount > 0 &&
"Switch statement with supposedly one default "
128 "branch did not contain any case labels");
129 if (CaseCount == 1 || CaseCount == 2)
130 diag(Switch->getBeginLoc(),
132 ?
"degenerated switch with default label only"
133 :
"switch could be better written as an if/else statement");
136void UnhandledCodePathsCheck::handleSwitchWithoutDefault(
137 const SwitchStmt *Switch, std::size_t CaseCount,
138 const MatchFinder::MatchResult &Result) {
142 assert(!Result.Nodes.getNodeAs<DeclRefExpr>(
"enum-condition") &&
143 "switch over enum is handled by warnings already, explicitly ignoring "
151 assert(CaseCount > 0 &&
"Switch statement without any case found. This case "
152 "should be excluded by the matcher and is handled "
154 const std::size_t MaxPathsPossible = [&]() {
155 if (
const auto *GeneralCondition =
156 Result.Nodes.getNodeAs<DeclRefExpr>(
"non-enum-condition")) {
160 if (
const auto *BitfieldDecl =
161 Result.Nodes.getNodeAs<FieldDecl>(
"bitfield")) {
162 return twoPow(BitfieldDecl->getBitWidthValue());
165 return static_cast<std::size_t
>(0);
169 if (CaseCount < MaxPathsPossible)
170 diag(Switch->getBeginLoc(),
171 CaseCount == 1 ?
"switch with only one case; use an if statement"
172 :
"potential uncovered code path; add a default label");
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
static std::pair< std::size_t, bool > countCaseLabels(const SwitchStmt *Switch)
static std::size_t twoPow(std::size_t Bits)
This function calculate 2 ** Bits and returns numeric_limits<std::size_t>::max() if an overflow occur...
static std::size_t getNumberOfPossibleValues(QualType T, const ASTContext &Context)
Get the number of possible values that can be switched on for the type T.
llvm::StringMap< ClangTidyValue > OptionMap