diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 60d569b7a..5dfb360fe 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -251,6 +251,15 @@ std::string MathLib::calculate(const std::string &first, const std::string &seco case '%': return MathLib::mod(first, second); + case '&': + return MathLib::toString(MathLib::toLongNumber(first) & MathLib::toLongNumber(second)); + + case '|': + return MathLib::toString(MathLib::toLongNumber(first) | MathLib::toLongNumber(second)); + + case '^': + return MathLib::toString(MathLib::toLongNumber(first) ^ MathLib::toLongNumber(second)); + default: throw InternalError(0, std::string("Unexpected action '") + action + "' in MathLib::calculate(). Please report this to Cppcheck developers."); } diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index a6a1759e4..db7808927 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -897,12 +897,8 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens) const MathLib::bigint rightInt(MathLib::toLongNumber(tok->strAt(2))); std::string result; - if (cop == '&') - result = MathLib::toString(leftInt & rightInt); - else if (cop == '|') - result = MathLib::toString(leftInt | rightInt); - else if (cop == '^') - result = MathLib::toString(leftInt ^ rightInt); + if (cop == '&' || cop == '|' || cop == '^') + result = MathLib::calculate(tok->str(), tok->strAt(2), cop); else if (cop == '<') { if (tok->previous()->str() != "<<") // Ensure that its not a shift operator as used for streams result = MathLib::toString(leftInt << rightInt); diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9137a1f78..0226cfd1a 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -7008,6 +7008,32 @@ void Tokenizer::simplifyEnum() } if (simplify) { + // Simplify calculations.. + while (Token::Match(enumValueStart, "%num% %op% %num% %op%") && + enumValueStart->strAt(1) == enumValueStart->strAt(3)) { + const std::string &op = enumValueStart->strAt(1); + if (op.size() != 1U) + break; + const std::string &val1 = enumValueStart->str(); + const std::string &val2 = enumValueStart->strAt(2); + const std::string result = MathLib::calculate(val1, val2, op[0]); + enumValueStart->str(result); + enumValueStart->deleteNext(2); + } + if (Token::Match(enumValueStart, "%num% %op% %num% [,}]")) { + const std::string &op = enumValueStart->strAt(1); + if (op.size() == 1U) { + const std::string &val1 = enumValueStart->str(); + const std::string &val2 = enumValueStart->strAt(2); + const std::string result = MathLib::calculate(val1, val2, op[0]); + enumValueStart->str(result); + enumValueStart->deleteNext(2); + enumValue = enumValueStart; + enumValueStart = enumValueEnd = 0; + } + } + + if (enumValue) tok2->str(enumValue->str()); else { diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index a4c81d72c..345d25282 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -344,6 +344,7 @@ private: TEST_CASE(enum26); // ticket #2975 (segmentation fault) TEST_CASE(enum27); // ticket #3005 (segmentation fault) TEST_CASE(enum28); + TEST_CASE(enum29); // ticket #3747 (bitwise or value) // remove "std::" on some standard functions TEST_CASE(removestd); @@ -6985,6 +6986,11 @@ private: ASSERT_EQUALS("void f ( ) { char x [ 4 ] ; memset ( x , 0 , 4 ) ; { x } } ; void g ( ) { 0 ; }", checkSimplifyEnum(code)); } + void enum29() { // #3747 - bitwise or value + const char code[] = "enum { x=1, y=x|2 }; i = (3==y);"; + ASSERT_EQUALS("i = 3 == 3 ;", checkSimplifyEnum(code)); + } + void removestd() { ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);")); ASSERT_EQUALS("; strcat ( a , b ) ;", tok("; std::strcat(a,b);"));