aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWaqar Ahmed <waqar.ahmed@kdab.com>2021-07-28 19:05:19 +0500
committerWaqar Ahmed <waqar.17a@gmail.com>2021-07-28 19:05:33 +0500
commitd7e3ffa43b7fa41c8a36a02bd4ab2b89808d436a (patch)
tree7140e65eaeaa4af8a7e32445fed470a8d6f0137a
parenta20570c6757cbbc71900394c7667086555825701 (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.cpp48
-rw-r--r--tests/unexpected-flag-enumerator-value/main.cpp51
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
+};