10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 21 "enum values are from different enum types";
24 "enum type seems like a bitmask (contains mostly " 25 "power-of-2 literals), but this literal is not a " 29 "enum type seems like a bitmask (contains mostly " 30 "power-of-2 literals) but %plural{1:a literal is|:some literals are}0 not " 41 const auto MinMaxVal = std::minmax_element(
42 EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
43 [](
const EnumConstantDecl *E1,
const EnumConstantDecl *E2) {
44 return llvm::APSInt::compareValues(E1->getInitVal(),
45 E2->getInitVal()) < 0;
47 MinVal = MinMaxVal.first->getInitVal();
48 MaxVal = MinMaxVal.second->getInitVal();
54 return std::distance(EnumDec->enumerator_begin(), EnumDec->enumerator_end());
58 const EnumDecl *Enum2) {
60 return llvm::APSInt::compareValues(Range1.MaxVal, Range2.
MinVal) < 0 ||
61 llvm::APSInt::compareValues(Range2.
MaxVal, Range1.MinVal) < 0;
65 llvm::APSInt Val = EnumConst->getInitVal();
66 if (Val.isPowerOf2() || !Val.getBoolValue())
68 const Expr *InitExpr = EnumConst->getInitExpr();
71 return isa<IntegerLiteral>(InitExpr->IgnoreImpCasts());
75 auto EnumConst = std::max_element(
76 EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
77 [](
const EnumConstantDecl *E1,
const EnumConstantDecl *E2) {
78 return E1->getInitVal() < E2->getInitVal();
81 if (
const Expr *InitExpr = EnumConst->getInitExpr()) {
82 return EnumConst->getInitVal().countTrailingOnes() ==
83 EnumConst->getInitVal().getActiveBits() &&
84 isa<IntegerLiteral>(InitExpr->IgnoreImpCasts());
91 EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
104 return NonPowOfTwoCounter >= 1 && NonPowOfTwoCounter <= 2 &&
105 NonPowOfTwoCounter < EnumLen / 2 &&
110 SuspiciousEnumUsageCheck::SuspiciousEnumUsageCheck(StringRef
Name,
113 StrictMode(Options.getLocalOrGlobal(
"StrictMode", 0)) {}
120 const auto enumExpr = [](StringRef RefName, StringRef DeclName) {
121 return expr(ignoringImpCasts(expr().bind(RefName)),
122 ignoringImpCasts(hasType(enumDecl().bind(DeclName))));
126 binaryOperator(hasOperatorName(
"|"), hasLHS(enumExpr(
"",
"enumDecl")),
127 hasRHS(expr(enumExpr(
"",
"otherEnumDecl"),
128 ignoringImpCasts(hasType(enumDecl(
129 unless(equalsBoundNode(
"enumDecl"))))))))
134 binaryOperator(anyOf(hasOperatorName(
"+"), hasOperatorName(
"|")),
135 hasLHS(enumExpr(
"lhsExpr",
"enumDecl")),
136 hasRHS(expr(enumExpr(
"rhsExpr",
""),
137 ignoringImpCasts(hasType(
138 enumDecl(equalsBoundNode(
"enumDecl"))))))),
142 binaryOperator(anyOf(hasOperatorName(
"+"), hasOperatorName(
"|")),
144 expr(hasType(isInteger()), unless(enumExpr(
"",
"")))),
145 hasEitherOperand(enumExpr(
"enumExpr",
"enumDecl"))),
149 binaryOperator(anyOf(hasOperatorName(
"|="), hasOperatorName(
"+=")),
150 hasRHS(enumExpr(
"enumExpr",
"enumDecl"))),
154 void SuspiciousEnumUsageCheck::checkSuspiciousBitmaskUsage(
155 const Expr *NodeExpr,
const EnumDecl *EnumDec) {
156 const auto *EnumExpr = dyn_cast<DeclRefExpr>(NodeExpr);
157 const auto *EnumConst =
158 EnumExpr ? dyn_cast<EnumConstantDecl>(EnumExpr->getDecl()) :
nullptr;
173 if (
const auto *DiffEnumOp =
174 Result.Nodes.getNodeAs<BinaryOperator>(
"diffEnumOp")) {
175 const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>(
"enumDecl");
176 const auto *OtherEnumDec =
177 Result.Nodes.getNodeAs<EnumDecl>(
"otherEnumDecl");
181 if (EnumDec->enumerator_begin() == EnumDec->enumerator_end() ||
182 OtherEnumDec->enumerator_begin() == OtherEnumDec->enumerator_end())
195 const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>(
"enumDecl");
202 if (
const auto *EnumExpr = Result.Nodes.getNodeAs<Expr>(
"enumExpr")) {
203 checkSuspiciousBitmaskUsage(EnumExpr, EnumDec);
209 const auto *LhsExpr = Result.Nodes.getNodeAs<Expr>(
"lhsExpr");
210 checkSuspiciousBitmaskUsage(LhsExpr, EnumDec);
212 const auto *RhsExpr = Result.Nodes.getNodeAs<Expr>(
"rhsExpr");
213 checkSuspiciousBitmaskUsage(RhsExpr, EnumDec);
static int enumLength(const EnumDecl *EnumDec)
Return the number of EnumConstantDecls in an EnumDecl.
static int countNonPowOfTwoLiteralNum(const EnumDecl *EnumDec)
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...
Base class for all clang-tidy checks.
ValueRange(const EnumDecl *EnumDec)
Stores a min and a max value which describe an interval.
static const char BitmaskErrorMessage[]
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.
static bool isMaxValAllBitSetLiteral(const EnumDecl *EnumDec)
static const char BitmaskVarErrorMessage[]
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
static const char BitmaskNoteMessage[]
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static bool isNonPowerOf2NorNullLiteral(const EnumConstantDecl *EnumConst)
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
static const char DifferentEnumErrorMessage[]
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
static bool hasDisjointValueRange(const EnumDecl *Enum1, const EnumDecl *Enum2)