10#include "clang/AST/ASTContext.h"
20 Options.
store(Opts,
"WarnOnMissingElse", WarnOnMissingElse);
30 anyOf(ignoringImpCasts(memberExpr(hasDeclaration(
31 fieldDecl(isBitField()).bind(
"bitfield")))),
32 ignoringImpCasts(declRefExpr().bind(
"non-enum-condition"))),
36 unless(ignoringImpCasts(
37 declRefExpr(hasType(hasCanonicalType(enumType())))
38 .bind(
"enum-condition"))))))
43 if (WarnOnMissingElse) {
44 Finder->addMatcher(ifStmt(hasParent(ifStmt()), unless(hasElse(anything())))
51 std::size_t CaseCount = 0;
52 bool HasDefault =
false;
54 const SwitchCase *CurrentCase = Switch->getSwitchCaseList();
57 if (isa<DefaultStmt>(CurrentCase))
60 CurrentCase = CurrentCase->getNextSwitchCase();
63 return std::make_pair(CaseCount, HasDefault);
68static std::size_t
twoPow(std::size_t Bits) {
69 return Bits >= std::numeric_limits<std::size_t>::digits
70 ? std::numeric_limits<std::size_t>::max()
71 :
static_cast<size_t>(1) << Bits;
80 const ASTContext &Context) {
83 if (T->isBooleanType())
85 if (T->isIntegralType(Context))
86 return twoPow(Context.getTypeSize(T));
91 if (
const auto *ElseIfWithoutElse =
92 Result.Nodes.getNodeAs<IfStmt>(
"else-if")) {
93 diag(ElseIfWithoutElse->getBeginLoc(),
94 "potentially uncovered codepath; add an ending else statement");
97 const auto *Switch = Result.Nodes.getNodeAs<SwitchStmt>(
"switch");
98 std::size_t SwitchCaseCount = 0;
99 bool SwitchHasDefault =
false;
104 if (SwitchHasDefault) {
105 handleSwitchWithDefault(Switch, SwitchCaseCount);
110 if (!SwitchHasDefault && SwitchCaseCount > 0) {
111 handleSwitchWithoutDefault(Switch, SwitchCaseCount, Result);
118 if (!SwitchHasDefault && SwitchCaseCount == 0) {
119 diag(Switch->getBeginLoc(),
120 "switch statement without labels has no effect");
123 llvm_unreachable(
"matched a case, that was not explicitly handled");
126void MultiwayPathsCoveredCheck::handleSwitchWithDefault(
127 const SwitchStmt *Switch, std::size_t CaseCount) {
128 assert(CaseCount > 0 &&
"Switch statement with supposedly one default "
129 "branch did not contain any case labels");
130 if (CaseCount == 1 || CaseCount == 2)
131 diag(Switch->getBeginLoc(),
133 ?
"degenerated switch with default label only"
134 :
"switch could be better written as an if/else statement");
137void MultiwayPathsCoveredCheck::handleSwitchWithoutDefault(
138 const SwitchStmt *Switch, std::size_t CaseCount,
139 const MatchFinder::MatchResult &Result) {
143 assert(!Result.Nodes.getNodeAs<DeclRefExpr>(
"enum-condition") &&
144 "switch over enum is handled by warnings already, explicitly ignoring "
152 assert(CaseCount > 0 &&
"Switch statement without any case found. This case "
153 "should be excluded by the matcher and is handled "
155 std::size_t MaxPathsPossible = [&]() {
156 if (
const auto *GeneralCondition =
157 Result.Nodes.getNodeAs<DeclRefExpr>(
"non-enum-condition")) {
161 if (
const auto *BitfieldDecl =
162 Result.Nodes.getNodeAs<FieldDecl>(
"bitfield")) {
163 return twoPow(BitfieldDecl->getBitWidthValue(*Result.Context));
166 return static_cast<std::size_t
>(0);
170 if (CaseCount < MaxPathsPossible)
171 diag(Switch->getBeginLoc(),
172 CaseCount == 1 ?
"switch with only one case; use an if statement"
173 :
"potential uncovered code path; add a default label");
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
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.
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...
llvm::StringMap< ClangTidyValue > OptionMap