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#include <algorithm>
15
16using namespace clang::ast_matchers;
17
18namespace clang::tidy::bugprone {
19
20namespace {
21
22AST_MATCHER(EnumDecl, isCompleteAndHasNoZeroValue) {
23 const EnumDecl *Definition = Node.getDefinition();
24 return Definition && Node.isComplete() &&
25 llvm::none_of(Definition->enumerators(),
26 [](const EnumConstantDecl *Value) {
27 return Value->getInitVal().isZero();
28 });
29}
30
31} // namespace
32
34 StringRef Name, ClangTidyContext *Context)
35 : ClangTidyCheck(Name, Context),
36 EnumIgnoreList(
37 utils::options::parseStringList(Options.get("EnumIgnoreList", ""))) {}
38
41 Options.store(Opts, "EnumIgnoreList",
43}
44
46 const LangOptions &LangOpts) const {
47 return LangOpts.CPlusPlus;
48}
49
51 // Excluding bitwise operators (binary and overload) to avoid false-positives
52 // in code like this 'if (e & SUCCESS) {'.
53 auto ExcludedOperators = binaryOperation(hasAnyOperatorName(
54 "|", "&", "^", "<<", ">>", "~", "|=", "&=", "^=", "<<=", ">>="));
55
56 Finder->addMatcher(
57 castExpr(hasCastKind(CK_IntegralToBoolean),
58 unless(isExpansionInSystemHeader()), hasType(booleanType()),
59 hasSourceExpression(
60 expr(hasType(qualType(hasCanonicalType(hasDeclaration(
61 enumDecl(isCompleteAndHasNoZeroValue(),
63 EnumIgnoreList)))
64 .bind("enum"))))),
65 unless(declRefExpr(to(enumConstantDecl()))),
66 unless(ignoringParenImpCasts(ExcludedOperators)))),
67 unless(hasAncestor(staticAssertDecl())))
68 .bind("cast"),
69 this);
70}
71
73 const MatchFinder::MatchResult &Result) {
74 const auto *Cast = Result.Nodes.getNodeAs<CastExpr>("cast");
75 const auto *Enum = Result.Nodes.getNodeAs<EnumDecl>("enum");
76
77 diag(Cast->getExprLoc(), "conversion of %0 into 'bool' will always return "
78 "'true', enum doesn't have a zero-value enumerator")
79 << Enum;
80 diag(Enum->getLocation(), "enum is defined here", DiagnosticIDs::Note);
81}
82
83} // 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