10 #include "clang/AST/ASTContext.h"
20 void MultiwayPathsCoveredCheck::storeOptions(
22 Options.store(Opts,
"WarnOnMissingElse", WarnOnMissingElse);
25 void MultiwayPathsCoveredCheck::registerMatchers(MatchFinder *Finder) {
32 anyOf(ignoringImpCasts(memberExpr(hasDeclaration(
33 fieldDecl(isBitField()).bind(
"bitfield")))),
34 ignoringImpCasts(declRefExpr().bind(
"non-enum-condition"))),
38 unless(ignoringImpCasts(
39 declRefExpr(hasType(enumType())).bind(
"enum-condition"))))))
44 if (WarnOnMissingElse) {
45 Finder->addMatcher(ifStmt(hasParent(ifStmt()), unless(hasElse(anything())))
52 std::size_t CaseCount = 0;
53 bool HasDefault =
false;
55 const SwitchCase *CurrentCase = Switch->getSwitchCaseList();
58 if (isa<DefaultStmt>(CurrentCase))
61 CurrentCase = CurrentCase->getNextSwitchCase();
64 return std::make_pair(CaseCount, HasDefault);
69 static std::size_t
twoPow(std::size_t Bits) {
70 return Bits >= std::numeric_limits<std::size_t>::digits
71 ? std::numeric_limits<std::size_t>::max()
72 : static_cast<size_t>(1) << Bits;
81 const ASTContext &Context) {
84 if (T->isBooleanType())
86 else if (T->isIntegralType(Context))
87 return twoPow(Context.getTypeSize(T));
92 void MultiwayPathsCoveredCheck::check(
const MatchFinder::MatchResult &Result) {
93 if (
const auto *ElseIfWithoutElse =
94 Result.Nodes.getNodeAs<IfStmt>(
"else-if")) {
95 diag(ElseIfWithoutElse->getBeginLoc(),
96 "potentially uncovered codepath; add an ending else statement");
99 const auto *Switch = Result.Nodes.getNodeAs<SwitchStmt>(
"switch");
100 std::size_t SwitchCaseCount;
101 bool SwitchHasDefault;
106 if (SwitchHasDefault) {
107 handleSwitchWithDefault(Switch, SwitchCaseCount);
112 if (!SwitchHasDefault && SwitchCaseCount > 0) {
113 handleSwitchWithoutDefault(Switch, SwitchCaseCount, Result);
120 if (!SwitchHasDefault && SwitchCaseCount == 0) {
121 diag(Switch->getBeginLoc(),
122 "switch statement without labels has no effect");
125 llvm_unreachable(
"matched a case, that was not explicitly handled");
128 void MultiwayPathsCoveredCheck::handleSwitchWithDefault(
129 const SwitchStmt *Switch, std::size_t CaseCount) {
130 assert(CaseCount > 0 &&
"Switch statement with supposedly one default "
131 "branch did not contain any case labels");
132 if (CaseCount == 1 || CaseCount == 2)
133 diag(Switch->getBeginLoc(),
135 ?
"degenerated switch with default label only"
136 :
"switch could be better written as an if/else statement");
139 void MultiwayPathsCoveredCheck::handleSwitchWithoutDefault(
140 const SwitchStmt *Switch, std::size_t CaseCount,
141 const MatchFinder::MatchResult &Result) {
145 assert(!Result.Nodes.getNodeAs<DeclRefExpr>(
"enum-condition") &&
146 "switch over enum is handled by warnings already, explicitly ignoring "
154 assert(CaseCount > 0 &&
"Switch statement without any case found. This case "
155 "should be excluded by the matcher and is handled "
157 std::size_t MaxPathsPossible = [&]() {
158 if (
const auto *GeneralCondition =
159 Result.Nodes.getNodeAs<DeclRefExpr>(
"non-enum-condition")) {
163 if (
const auto *BitfieldDecl =
164 Result.Nodes.getNodeAs<FieldDecl>(
"bitfield")) {
165 return twoPow(BitfieldDecl->getBitWidthValue(*Result.Context));
168 return static_cast<std::size_t>(0);
172 if (CaseCount < MaxPathsPossible)
173 diag(Switch->getBeginLoc(),
174 CaseCount == 1 ?
"switch with only one case; use an if statement"
175 :
"potential uncovered code path; add a default label");