10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
19 "enum values are from different enum types";
22 "enum type seems like a bitmask (contains mostly "
23 "power-of-2 literals), but this literal is not a "
27 "enum type seems like a bitmask (contains mostly "
28 "power-of-2 literals) but %plural{1:a literal is|:some literals are}0 not "
39 const auto MinMaxVal = std::minmax_element(
40 EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
41 [](
const EnumConstantDecl *E1,
const EnumConstantDecl *E2) {
42 return llvm::APSInt::compareValues(E1->getInitVal(),
43 E2->getInitVal()) < 0;
45 MinVal = MinMaxVal.first->getInitVal();
46 MaxVal = MinMaxVal.second->getInitVal();
52 return std::distance(EnumDec->enumerator_begin(), EnumDec->enumerator_end());
56 const EnumDecl *Enum2) {
58 return llvm::APSInt::compareValues(Range1.MaxVal, Range2.
MinVal) < 0 ||
59 llvm::APSInt::compareValues(Range2.
MaxVal, Range1.MinVal) < 0;
63 const llvm::APSInt &Val = EnumConst->getInitVal();
64 if (Val.isPowerOf2() || !Val.getBoolValue())
66 const Expr *InitExpr = EnumConst->getInitExpr();
69 return isa<IntegerLiteral>(InitExpr->IgnoreImpCasts());
73 auto EnumConst = std::max_element(
74 EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
75 [](
const EnumConstantDecl *E1,
const EnumConstantDecl *E2) {
76 return E1->getInitVal() < E2->getInitVal();
79 if (
const Expr *InitExpr = EnumConst->getInitExpr()) {
80 return EnumConst->getInitVal().countr_one() ==
81 EnumConst->getInitVal().getActiveBits() &&
82 isa<IntegerLiteral>(InitExpr->IgnoreImpCasts());
100 return NonPowOfTwoCounter >= 1 && NonPowOfTwoCounter <= 2 &&
101 NonPowOfTwoCounter < EnumLen / 2 &&
109 StrictMode(Options.getLocalOrGlobal(
"StrictMode", false)) {}
116 const auto EnumExpr = [](StringRef RefName, StringRef DeclName) {
117 return expr(hasType(enumDecl().bind(DeclName))).bind(RefName);
122 hasOperatorName(
"|"), hasLHS(hasType(enumDecl().bind(
"enumDecl"))),
123 hasRHS(hasType(enumDecl(unless(equalsBoundNode(
"enumDecl")))
124 .bind(
"otherEnumDecl"))))
129 binaryOperator(hasAnyOperatorName(
"+",
"|"),
130 hasLHS(EnumExpr(
"lhsExpr",
"enumDecl")),
131 hasRHS(expr(hasType(enumDecl(equalsBoundNode(
"enumDecl"))))
137 hasAnyOperatorName(
"+",
"|"),
138 hasOperands(expr(hasType(isInteger()), unless(hasType(enumDecl()))),
139 EnumExpr(
"enumExpr",
"enumDecl"))),
142 Finder->addMatcher(binaryOperator(hasAnyOperatorName(
"|=",
"+="),
143 hasRHS(EnumExpr(
"enumExpr",
"enumDecl"))),
147void SuspiciousEnumUsageCheck::checkSuspiciousBitmaskUsage(
148 const Expr *NodeExpr,
const EnumDecl *EnumDec) {
149 const auto *EnumExpr = dyn_cast<DeclRefExpr>(NodeExpr);
150 const auto *EnumConst =
151 EnumExpr ? dyn_cast<EnumConstantDecl>(EnumExpr->getDecl()) : nullptr;
166 if (
const auto *DiffEnumOp =
167 Result.Nodes.getNodeAs<BinaryOperator>(
"diffEnumOp")) {
168 const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>(
"enumDecl");
169 const auto *OtherEnumDec =
170 Result.Nodes.getNodeAs<EnumDecl>(
"otherEnumDecl");
174 if (EnumDec->enumerators().empty() || OtherEnumDec->enumerators().empty())
187 const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>(
"enumDecl");
194 if (
const auto *EnumExpr = Result.Nodes.getNodeAs<Expr>(
"enumExpr")) {
195 checkSuspiciousBitmaskUsage(EnumExpr, EnumDec);
201 const auto *LhsExpr = Result.Nodes.getNodeAs<Expr>(
"lhsExpr");
202 checkSuspiciousBitmaskUsage(LhsExpr, EnumDec);
204 const auto *RhsExpr = Result.Nodes.getNodeAs<Expr>(
"rhsExpr");
205 checkSuspiciousBitmaskUsage(RhsExpr, EnumDec);
llvm::SmallString< 256U > Name
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Base class for all clang-tidy checks.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
SuspiciousEnumUsageCheck(StringRef Name, ClangTidyContext *Context)
static bool hasDisjointValueRange(const EnumDecl *Enum1, const EnumDecl *Enum2)
static bool isPossiblyBitMask(const EnumDecl *EnumDec)
Check if there is one or two enumerators that are not a power of 2 and are initialized by a literal i...
static bool isMaxValAllBitSetLiteral(const EnumDecl *EnumDec)
static const char DifferentEnumErrorMessage[]
static const char BitmaskNoteMessage[]
static const char BitmaskVarErrorMessage[]
static int enumLength(const EnumDecl *EnumDec)
Return the number of EnumConstantDecls in an EnumDecl.
static int countNonPowOfTwoLiteralNum(const EnumDecl *EnumDec)
static bool isNonPowerOf2NorNullLiteral(const EnumConstantDecl *EnumConst)
static const char BitmaskErrorMessage[]
llvm::StringMap< ClangTidyValue > OptionMap
Stores a min and a max value which describe an interval.
ValueRange(const EnumDecl *EnumDec)