clang-tools 22.0.0git
NonZeroEnumToBoolConversionCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
10#include "../utils/Matchers.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14
15using namespace clang::ast_matchers;
16
17namespace clang::tidy::bugprone {
18
19namespace {
20
21AST_MATCHER(EnumDecl, isCompleteAndHasNoZeroValue) {
22 const EnumDecl *Definition = Node.getDefinition();
23 return Definition && Node.isComplete() &&
24 llvm::none_of(Definition->enumerators(),
25 [](const EnumConstantDecl *Value) {
26 return Value->getInitVal().isZero();
27 });
28}
29
30} // namespace
31
33 StringRef Name, ClangTidyContext *Context)
34 : ClangTidyCheck(Name, Context),
35 EnumIgnoreList(
36 utils::options::parseStringList(Options.get("EnumIgnoreList", ""))) {}
37
40 Options.store(Opts, "EnumIgnoreList",
42}
43
45 const LangOptions &LangOpts) const {
46 return LangOpts.CPlusPlus;
47}
48
50 // Excluding bitwise operators (binary and overload) to avoid false-positives
51 // in code like this 'if (e & SUCCESS) {'.
52 auto ExcludedOperators = binaryOperation(hasAnyOperatorName(
53 "|", "&", "^", "<<", ">>", "~", "|=", "&=", "^=", "<<=", ">>="));
54
55 Finder->addMatcher(
56 castExpr(hasCastKind(CK_IntegralToBoolean),
57 unless(isExpansionInSystemHeader()), hasType(booleanType()),
58 hasSourceExpression(
59 expr(hasType(qualType(hasCanonicalType(hasDeclaration(
60 enumDecl(isCompleteAndHasNoZeroValue(),
62 EnumIgnoreList)))
63 .bind("enum"))))),
64 unless(declRefExpr(to(enumConstantDecl()))),
65 unless(ignoringParenImpCasts(ExcludedOperators)))),
66 unless(hasAncestor(staticAssertDecl())))
67 .bind("cast"),
68 this);
69}
70
72 const MatchFinder::MatchResult &Result) {
73 const auto *Cast = Result.Nodes.getNodeAs<CastExpr>("cast");
74 const auto *Enum = Result.Nodes.getNodeAs<EnumDecl>("enum");
75
76 diag(Cast->getExprLoc(), "conversion of %0 into 'bool' will always return "
77 "'true', enum doesn't have a zero-value enumerator")
78 << Enum;
79 diag(Enum->getLocation(), "enum is defined here", DiagnosticIDs::Note);
80}
81
82} // namespace clang::tidy::bugprone
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
NonZeroEnumToBoolConversionCheck(StringRef Name, ClangTidyContext *Context)
AST_MATCHER(BinaryOperator, isRelationalOperator)
inline ::clang::ast_matchers::internal::Matcher< NamedDecl > matchesAnyListedName(llvm::ArrayRef< StringRef > NameList)
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
llvm::StringMap< ClangTidyValue > OptionMap