[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang-tools-extra / clang-tidy / bugprone / NonZeroEnumToBoolConversionCheck.cpp
blob918b6e3824f0b1be62ae14043344dffb0dad62bb
1 //===--- NonZeroEnumToBoolConversionCheck.cpp - clang-tidy ----------------===//
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 //===----------------------------------------------------------------------===//
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"
14 #include <algorithm>
16 using namespace clang::ast_matchers;
18 namespace clang::tidy::bugprone {
20 namespace {
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();
29 });
32 } // namespace
34 NonZeroEnumToBoolConversionCheck::NonZeroEnumToBoolConversionCheck(
35 StringRef Name, ClangTidyContext *Context)
36 : ClangTidyCheck(Name, Context),
37 EnumIgnoreList(
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 "|", "&", "^", "<<", ">>", "~", "|=", "&=", "^=", "<<=", ">>="));
57 Finder->addMatcher(
58 castExpr(hasCastKind(CK_IntegralToBoolean),
59 unless(isExpansionInSystemHeader()), hasType(booleanType()),
60 hasSourceExpression(
61 expr(hasType(qualType(hasCanonicalType(hasDeclaration(
62 enumDecl(isCompleteAndHasNoZeroValue(),
63 unless(matchers::matchesAnyListedName(
64 EnumIgnoreList)))
65 .bind("enum"))))),
66 unless(declRefExpr(to(enumConstantDecl()))),
67 unless(ignoringImplicit(ExcludedOperators)))),
68 unless(hasAncestor(staticAssertDecl())))
69 .bind("cast"),
70 this);
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")
80 << Enum;
81 diag(Enum->getLocation(), "enum is defined here", DiagnosticIDs::Note);
84 } // namespace clang::tidy::bugprone