1 //===--- NonZeroEnumToBoolConversionCheck.cpp - clang-tidy ----------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "NonZeroEnumToBoolConversionCheck.h"
10 #include "../utils/Matchers.h"
11 #include "../utils/OptionsUtils.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
16 using namespace clang::ast_matchers
;
18 namespace clang::tidy::bugprone
{
22 AST_MATCHER(EnumDecl
, isCompleteAndHasNoZeroValue
) {
23 const EnumDecl
*Definition
= Node
.getDefinition();
24 return Definition
&& Node
.isComplete() &&
25 std::none_of(Definition
->enumerator_begin(),
26 Definition
->enumerator_end(),
27 [](const EnumConstantDecl
*Value
) {
28 return Value
->getInitVal().isZero();
34 NonZeroEnumToBoolConversionCheck::NonZeroEnumToBoolConversionCheck(
35 StringRef Name
, ClangTidyContext
*Context
)
36 : ClangTidyCheck(Name
, Context
),
38 utils::options::parseStringList(Options
.get("EnumIgnoreList", ""))) {}
40 void NonZeroEnumToBoolConversionCheck::storeOptions(
41 ClangTidyOptions::OptionMap
&Opts
) {
42 Options
.store(Opts
, "EnumIgnoreList",
43 utils::options::serializeStringList(EnumIgnoreList
));
46 bool NonZeroEnumToBoolConversionCheck::isLanguageVersionSupported(
47 const LangOptions
&LangOpts
) const {
48 return LangOpts
.CPlusPlus
;
51 void NonZeroEnumToBoolConversionCheck::registerMatchers(MatchFinder
*Finder
) {
52 // Excluding bitwise operators (binary and overload) to avoid false-positives
53 // in code like this 'if (e & SUCCESS) {'.
54 auto ExcludedOperators
= binaryOperation(hasAnyOperatorName(
55 "|", "&", "^", "<<", ">>", "~", "|=", "&=", "^=", "<<=", ">>="));
58 castExpr(hasCastKind(CK_IntegralToBoolean
),
59 unless(isExpansionInSystemHeader()), hasType(booleanType()),
61 expr(hasType(qualType(hasCanonicalType(hasDeclaration(
62 enumDecl(isCompleteAndHasNoZeroValue(),
63 unless(matchers::matchesAnyListedName(
66 unless(declRefExpr(to(enumConstantDecl()))),
67 unless(ignoringImplicit(ExcludedOperators
)))),
68 unless(hasAncestor(staticAssertDecl())))
73 void NonZeroEnumToBoolConversionCheck::check(
74 const MatchFinder::MatchResult
&Result
) {
75 const auto *Cast
= Result
.Nodes
.getNodeAs
<CastExpr
>("cast");
76 const auto *Enum
= Result
.Nodes
.getNodeAs
<EnumDecl
>("enum");
78 diag(Cast
->getExprLoc(), "conversion of %0 into 'bool' will always return "
79 "'true', enum doesn't have a zero-value enumerator")
81 diag(Enum
->getLocation(), "enum is defined here", DiagnosticIDs::Note
);
84 } // namespace clang::tidy::bugprone