diff options
author | Waqar Ahmed <waqar.ahmed@kdab.com> | 2021-07-28 19:05:19 +0500 |
---|---|---|
committer | Waqar Ahmed <waqar.17a@gmail.com> | 2021-07-28 19:05:33 +0500 |
commit | d7e3ffa43b7fa41c8a36a02bd4ab2b89808d436a (patch) | |
tree | 7140e65eaeaa4af8a7e32445fed470a8d6f0137a | |
parent | a20570c6757cbbc71900394c7667086555825701 (diff) |
Unexpected-flag-enumerator-value fixes
Fixes include
- Recognize when a value is mask
- Recognize binary operator behind implict casts
- Recognize when a value is a ref to another value (DeclRefExpr)
-rw-r--r-- | src/checks/manuallevel/unexpected-flag-enumerator-value.cpp | 48 | ||||
-rw-r--r-- | tests/unexpected-flag-enumerator-value/main.cpp | 51 |
2 files changed, 94 insertions, 5 deletions
diff --git a/src/checks/manuallevel/unexpected-flag-enumerator-value.cpp b/src/checks/manuallevel/unexpected-flag-enumerator-value.cpp index 6d1bf226..76c7afa8 100644 --- a/src/checks/manuallevel/unexpected-flag-enumerator-value.cpp +++ b/src/checks/manuallevel/unexpected-flag-enumerator-value.cpp @@ -39,17 +39,55 @@ UnexpectedFlagEnumeratorValue::UnexpectedFlagEnumeratorValue(const std::string & { } +static ConstantExpr* getConstantExpr(EnumConstantDecl *enCD) +{ + auto cexpr = dyn_cast_or_null<ConstantExpr>(enCD->getInitExpr()); + if (cexpr) + return cexpr; + if (auto cast = dyn_cast_or_null<ImplicitCastExpr>(enCD->getInitExpr())) { + return dyn_cast_or_null<ConstantExpr>(cast->getSubExpr()); + } + return nullptr; +} + +static bool isBinaryOperatorExpression(ConstantExpr* cexpr) +{ + auto subExpr = cexpr->getSubExpr(); + if (dyn_cast_or_null<BinaryOperator>(subExpr)) + return true; + + if (auto cast = dyn_cast_or_null<ImplicitCastExpr>(subExpr)) { + return dyn_cast_or_null<BinaryOperator>(cast->getSubExpr()); + } + return false; +} + +static bool isReferenceToEnumerator(ConstantExpr* cexpr) +{ + return dyn_cast_or_null<DeclRefExpr>(cexpr->getSubExpr()); +} + static bool isIntentionallyNotPowerOf2(EnumConstantDecl *en) { + constexpr unsigned MinOnesToQualifyAsMask = 3; + + const auto val = en->getInitVal(); + if (val.isMask() && val.countTrailingOnes() >= MinOnesToQualifyAsMask) + return true; + + if (val.isShiftedMask() && val.countPopulation() >= MinOnesToQualifyAsMask) + return true; - auto cexpr = dyn_cast_or_null<ConstantExpr>(clazy::getFirstChild(en->getInitExpr())); + if (en->getName().contains_lower("mask")) + return true; + + auto *cexpr = getConstantExpr(en); if (!cexpr) return false; - if (auto binaryOp = dyn_cast_or_null<BinaryOperator>(cexpr->getSubExpr())) { + if (isBinaryOperatorExpression(cexpr)) return true; - } - if (en->getName().contains_lower("mask")) + if (isReferenceToEnumerator(cexpr)) return true; return false; @@ -124,7 +162,7 @@ void UnexpectedFlagEnumeratorValue::VisitDecl(clang::Decl *decl) for (EnumConstantDecl* enumerator : enumerators) { const auto &initVal = enumerator->getInitVal(); - if (!initVal.isPowerOf2() && !initVal.isNullValue() && !initVal.isNegative()){ + if (!initVal.isPowerOf2() && !initVal.isNullValue() && !initVal.isNegative()) { if (isIntentionallyNotPowerOf2(enumerator)) continue; const auto value = enumerator->getInitVal().getLimitedValue(); diff --git a/tests/unexpected-flag-enumerator-value/main.cpp b/tests/unexpected-flag-enumerator-value/main.cpp index 40d3e885..91856fc4 100644 --- a/tests/unexpected-flag-enumerator-value/main.cpp +++ b/tests/unexpected-flag-enumerator-value/main.cpp @@ -64,6 +64,13 @@ enum WithMasks Mask = 0x0000FFFF }; +enum RelationFlag { + Label = 0x00000001, + Labelled = 0x00000002, + Controller = 0x00000004, + Controlled = 0x00000008, + AllRelations = 0xffffffff +}; enum class WithZero { Zero = 0, @@ -90,3 +97,47 @@ enum class WithNegative V8 = 8, VFoo = -1 }; + +enum Filter { + Dirs = 0x001, + Files = 0x002, + Drives = 0x004, + NoSymLinks = 0x008, + AllEntries = Dirs | Files | Drives,// Because of this -1, the type of this enum becomes signed and hence BinaryOp | doesn't need any implicit casts + TypeMask = 0x00f, + + NoFilter = -1 +}; + +enum ComponentFormattingOption : unsigned int { + PrettyDecoded = 0x000000, + EncodeSpaces = 0x100000, + EncodeUnicode = 0x200000, + EncodeDelimiters = 0x400000 | 0x800000, + EncodeReserved = 0x1000000, + DecodeReserved = 0x2000000, + // 0x4000000 used to indicate full-decode mode + + FullyEncoded = EncodeSpaces | EncodeUnicode | EncodeDelimiters | EncodeReserved, + FullyDecoded = FullyEncoded | DecodeReserved | 0x4000000 +}; +enum MarkdownFeature { + MarkdownNoHTML = 0x0020 | 0x0040, + MarkdownDialectCommonMark = 0, + MarkdownDialectGitHub = 0x0004 | 0x0008 | 0x0400 | 0x0100 | 0x0200 | 0x0800 | 0x4000 +}; +enum Feature { + FeatureCollapseWhitespace = 0x0001, + FeaturePermissiveATXHeaders = 0x0002, + FeaturePermissiveURLAutoLinks = 0x0004, + FeaturePermissiveMailAutoLinks = 0x0008, + FeatureNoIndentedCodeBlocks = 0x0010, + FeatureNoHTMLBlocks = 0x0020, + FeatureNoHTMLSpans = 0x0040, + FeatureTables = 0x0100, + FeatureStrikeThrough = 0x0200, + FeaturePermissiveWWWAutoLinks = 0x0400, + FeatureTasklists = 0x0800, + FeatureUnderline = 0x4000, + DialectGitHub = MarkdownDialectGitHub +}; |