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(),
92 [](
const EnumConstantDecl *
E) { return isNonPowerOf2NorNullLiteral(E); });
104 return NonPowOfTwoCounter >= 1 && NonPowOfTwoCounter <= 2 &&
105 NonPowOfTwoCounter < EnumLen / 2 &&
110 SuspiciousEnumUsageCheck::SuspiciousEnumUsageCheck(StringRef
Name,
113 StrictMode(Options.getLocalOrGlobal(
"StrictMode", false)) {}
120 const auto EnumExpr = [](StringRef RefName, StringRef DeclName) {
121 return expr(hasType(enumDecl().bind(DeclName))).bind(RefName);
126 hasOperatorName(
"|"), hasLHS(hasType(enumDecl().bind(
"enumDecl"))),
127 hasRHS(hasType(enumDecl(unless(equalsBoundNode(
"enumDecl")))
128 .bind(
"otherEnumDecl"))))
133 binaryOperator(hasAnyOperatorName(
"+",
"|"),
134 hasLHS(EnumExpr(
"lhsExpr",
"enumDecl")),
135 hasRHS(expr(hasType(enumDecl(equalsBoundNode(
"enumDecl"))))
141 hasAnyOperatorName(
"+",
"|"),
142 hasOperands(expr(hasType(isInteger()), unless(hasType(enumDecl()))),
143 EnumExpr(
"enumExpr",
"enumDecl"))),
146 Finder->addMatcher(binaryOperator(hasAnyOperatorName(
"|=",
"+="),
147 hasRHS(EnumExpr(
"enumExpr",
"enumDecl"))),
151 void SuspiciousEnumUsageCheck::checkSuspiciousBitmaskUsage(
152 const Expr *NodeExpr,
const EnumDecl *EnumDec) {
153 const auto *EnumExpr = dyn_cast<DeclRefExpr>(NodeExpr);
154 const auto *EnumConst =
155 EnumExpr ? dyn_cast<EnumConstantDecl>(EnumExpr->getDecl()) : nullptr;
170 if (
const auto *DiffEnumOp =
171 Result.Nodes.getNodeAs<BinaryOperator>(
"diffEnumOp")) {
172 const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>(
"enumDecl");
173 const auto *OtherEnumDec =
174 Result.Nodes.getNodeAs<EnumDecl>(
"otherEnumDecl");
178 if (EnumDec->enumerator_begin() == EnumDec->enumerator_end() ||
179 OtherEnumDec->enumerator_begin() == OtherEnumDec->enumerator_end())
192 const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>(
"enumDecl");
199 if (
const auto *EnumExpr = Result.Nodes.getNodeAs<Expr>(
"enumExpr")) {
200 checkSuspiciousBitmaskUsage(EnumExpr, EnumDec);
206 const auto *LhsExpr = Result.Nodes.getNodeAs<Expr>(
"lhsExpr");
207 checkSuspiciousBitmaskUsage(LhsExpr, EnumDec);
209 const auto *RhsExpr = Result.Nodes.getNodeAs<Expr>(
"rhsExpr");
210 checkSuspiciousBitmaskUsage(RhsExpr, EnumDec);