11 #include "clang/AST/ASTContext.h" 21 void MultiwayPathsCoveredCheck::storeOptions(
23 Options.store(Opts,
"WarnOnMissingElse", WarnOnMissingElse);
26 void MultiwayPathsCoveredCheck::registerMatchers(MatchFinder *Finder) {
33 anyOf(ignoringImpCasts(memberExpr(hasDeclaration(
34 fieldDecl(isBitField()).bind(
"bitfield")))),
35 ignoringImpCasts(declRefExpr().bind(
"non-enum-condition"))),
39 unless(ignoringImpCasts(
40 declRefExpr(hasType(enumType())).bind(
"enum-condition"))))))
45 if (WarnOnMissingElse) {
46 Finder->addMatcher(ifStmt(hasParent(ifStmt()), unless(hasElse(anything())))
53 std::size_t CaseCount = 0;
54 bool HasDefault =
false;
56 const SwitchCase *CurrentCase = Switch->getSwitchCaseList();
59 if (isa<DefaultStmt>(CurrentCase))
62 CurrentCase = CurrentCase->getNextSwitchCase();
65 return std::make_pair(CaseCount, HasDefault);
70 static std::size_t
twoPow(std::size_t Bits) {
71 return Bits >= std::numeric_limits<std::size_t>::digits
72 ? std::numeric_limits<std::size_t>::max()
73 :
static_cast<size_t>(1) << Bits;
82 const ASTContext &Context) {
85 if (T->isBooleanType())
87 else if (T->isIntegralType(Context))
88 return twoPow(Context.getTypeSize(T));
93 void MultiwayPathsCoveredCheck::check(
const MatchFinder::MatchResult &
Result) {
94 if (
const auto *ElseIfWithoutElse =
95 Result.Nodes.getNodeAs<IfStmt>(
"else-if")) {
96 diag(ElseIfWithoutElse->getBeginLoc(),
97 "potentially uncovered codepath; add an ending else statement");
100 const auto *Switch = Result.Nodes.getNodeAs<SwitchStmt>(
"switch");
101 std::size_t SwitchCaseCount;
102 bool SwitchHasDefault;
107 if (SwitchHasDefault) {
108 handleSwitchWithDefault(Switch, SwitchCaseCount);
113 if (!SwitchHasDefault && SwitchCaseCount > 0) {
114 handleSwitchWithoutDefault(Switch, SwitchCaseCount, Result);
121 if (!SwitchHasDefault && SwitchCaseCount == 0) {
122 diag(Switch->getBeginLoc(),
123 "switch statement without labels has no effect");
126 llvm_unreachable(
"matched a case, that was not explicitly handled");
129 void MultiwayPathsCoveredCheck::handleSwitchWithDefault(
130 const SwitchStmt *Switch, std::size_t CaseCount) {
131 assert(CaseCount > 0 &&
"Switch statement with supposedly one default " 132 "branch did not contain any case labels");
133 if (CaseCount == 1 || CaseCount == 2)
134 diag(Switch->getBeginLoc(),
136 ?
"degenerated switch with default label only" 137 :
"switch could be better written as an if/else statement");
140 void MultiwayPathsCoveredCheck::handleSwitchWithoutDefault(
141 const SwitchStmt *Switch, std::size_t CaseCount,
142 const MatchFinder::MatchResult &
Result) {
146 assert(!Result.Nodes.getNodeAs<DeclRefExpr>(
"enum-condition") &&
147 "switch over enum is handled by warnings already, explicitly ignoring " 155 assert(CaseCount > 0 &&
"Switch statement without any case found. This case " 156 "should be excluded by the matcher and is handled " 158 std::size_t MaxPathsPossible = [&]() {
159 if (
const auto *GeneralCondition =
160 Result.Nodes.getNodeAs<DeclRefExpr>(
"non-enum-condition")) {
164 if (
const auto *BitfieldDecl =
165 Result.Nodes.getNodeAs<FieldDecl>(
"bitfield")) {
166 return twoPow(BitfieldDecl->getBitWidthValue(*Result.Context));
169 return static_cast<std::size_t
>(0);
173 if (CaseCount < MaxPathsPossible)
174 diag(Switch->getBeginLoc(),
175 CaseCount == 1 ?
"switch with only one case; use an if statement" 176 :
"potential uncovered code path; add a default label");
static std::pair< std::size_t, bool > countCaseLabels(const SwitchStmt *Switch)
std::map< std::string, std::string > OptionMap
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
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::size_t twoPow(std::size_t Bits)
This function calculate 2 ** Bits and returns numeric_limits<std::size_t>::max() if an overflow occur...