From 184537884f8a71d9e1c93e9690bd7a5e193352bf Mon Sep 17 00:00:00 2001 From: IOBYTE Date: Thu, 10 May 2018 01:40:01 -0400 Subject: [PATCH] Don't remove the volatile keyword so we can properly overload functions. (#1218) * Don't remove the volatile keyword so we can properly overload functions. I fixed all the checks that had tests that use volatile. There will probably be more changes needed due to lack of test coverage for volatile in some checks. * Fix unused private function warning. --- lib/checkother.cpp | 6 +++--- lib/symboldatabase.cpp | 21 ++++++++++++--------- lib/symboldatabase.h | 9 ++++++++- lib/tokenize.cpp | 13 ++++++------- test/testpostfixoperator.cpp | 3 +-- test/testsimplifytypedef.cpp | 24 ++++++++++++------------ test/testsymboldatabase.cpp | 23 +++++++++++++++++++++++ test/testtokenize.cpp | 2 +- 8 files changed, 66 insertions(+), 35 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 08b39c485..017075336 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -278,11 +278,11 @@ void CheckOther::warningOldStylePointerCast() tok = scope->bodyStart; for (; tok && tok != scope->bodyEnd; tok = tok->next()) { // Old style pointer casting.. - if (!Token::Match(tok, "( const| %type% * const| ) (| %name%|%num%|%bool%|%char%|%str%")) + if (!Token::Match(tok, "( const|volatile| const|volatile| %type% * const| ) (| %name%|%num%|%bool%|%char%|%str%")) continue; // skip first "const" in "const Type* const" - if (tok->strAt(1) == "const") + while (Token::Match(tok->next(), "const|volatile")) tok = tok->next(); const Token* typeTok = tok->next(); // skip second "const" in "const Type* const" @@ -326,7 +326,7 @@ void CheckOther::invalidPointerCast() const Token* toTok = nullptr; const Token* fromTok = nullptr; // Find cast - if (Token::Match(tok, "( const| %type% %type%| const| * )")) { + if (Token::Match(tok, "( const|volatile| const|volatile| %type% %type%| const| * )")) { toTok = tok; fromTok = tok->astOperand1(); } else if (Token::simpleMatch(tok, "reinterpret_cast <") && tok->linkAt(1)) { diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index bceec4c46..7964bb3c8 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1406,8 +1406,8 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const tok1 = tok1->link()->tokAt(-2); } - // skip over const, noexcept, throw and override specifiers - while (Token::Match(tok2, "const|noexcept|throw|override|final")) { + // skip over const, noexcept, throw, override, final and volatile specifiers + while (Token::Match(tok2, "const|noexcept|throw|override|final|volatile")) { tok2 = tok2->next(); if (tok2 && tok2->str() == "(") tok2 = tok2->link()->next(); @@ -1646,9 +1646,9 @@ void Variable::evaluate(const Library* lib) tok = tok->next(); } - while (Token::Match(_start, "static|const %any%")) + while (Token::Match(_start, "static|const|volatile %any%")) _start = _start->next(); - while (_end && _end->previous() && _end->str() == "const") + while (_end && _end->previous() && Token::Match(_end, "const|volatile")) _end = _end->previous(); if (_start) { @@ -1793,6 +1793,8 @@ Function::Function(const Tokenizer *_tokenizer, const Token *tok, const Scope *s setFlag(fHasOverrideSpecifier, true); else if (tok->str() == "final") setFlag(fHasFinalSpecifier, true); + else if (tok->str() == "volatile") + isVolatile(true); else if (tok->str() == "noexcept") { isNoExcept(!Token::simpleMatch(tok->next(), "( false )")); if (tok->next()->str() == "(") @@ -2703,6 +2705,7 @@ void SymbolDatabase::printOut(const char *title) const std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl; std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl; std::cout << " isVariadic: " << func->isVariadic() << std::endl; + std::cout << " isVolatile: " << func->isVolatile() << std::endl; std::cout << " attributes:"; if (func->isAttributeConst()) std::cout << " const "; @@ -3057,7 +3060,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s const Token *typeTok = startTok; // skip over stuff to get to type - while (Token::Match(typeTok, "const|enum|struct|::")) + while (Token::Match(typeTok, "const|volatile|enum|struct|::")) typeTok = typeTok->next(); if (Token::Match(typeTok, ",|)")) { // #8333 symbolDatabase->_tokenizer->syntaxError(typeTok); @@ -3069,7 +3072,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s // check for argument with no name or missing varid if (!endTok) { - if (tok->previous()->isName() && tok->strAt(-1) != "const") { + if (tok->previous()->isName() && !Token::Match(tok->tokAt(-1), "const|volatile")) { if (tok->previous() != typeTok) { nameTok = tok->previous(); endTok = nameTok->previous(); @@ -3100,7 +3103,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s } // skip over stuff before type - while (Token::Match(startTok, "enum|struct|const")) + while (Token::Match(startTok, "enum|struct|const|volatile")) startTok = startTok->next(); argumentList.emplace_back(nameTok, startTok, endTok, count++, Argument, argType, functionScope, &symbolDatabase->_settings->library); @@ -3434,8 +3437,8 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess, con return next; } - // skip const|static|mutable|extern - while (Token::Match(tok, "const|static|mutable|extern")) { + // skip const|volatile|static|mutable|extern + while (Token::Match(tok, "const|volatile|static|mutable|extern")) { tok = tok->next(); } diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index d324a0b8d..5590ba0ab 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -672,7 +672,8 @@ class CPPCHECKLIB Function { fIsOperator = (1 << 16), ///< @brief is operator fHasLvalRefQual = (1 << 17), ///< @brief has & lvalue ref-qualifier fHasRvalRefQual = (1 << 18), ///< @brief has && rvalue ref-qualifier - fIsVariadic = (1 << 19) ///< @brief is variadic + fIsVariadic = (1 << 19), ///< @brief is variadic + fIsVolatile = (1 << 20) ///< @brief is volatile }; /** @@ -808,6 +809,9 @@ public: bool isVariadic() const { return getFlag(fIsVariadic); } + bool isVolatile() const { + return getFlag(fIsVolatile); + } void hasBody(bool state) { setFlag(fHasBody, state); @@ -893,6 +897,9 @@ private: void isVariadic(bool state) { setFlag(fIsVariadic, state); } + void isVolatile(bool state) { + setFlag(fIsVolatile, state); + } }; class CPPCHECKLIB Scope { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index d4ea62283..16de73f25 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3635,7 +3635,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) if (_settings->terminated()) return false; - // Remove "volatile", "inline", "register", and "restrict" + // Remove "inline", "register", and "restrict" simplifyKeyword(); // simplify simple calculations inside <..> @@ -4169,7 +4169,7 @@ void Tokenizer::removeMacrosInGlobalScope() if (tok->str() == "(") { tok = tok->link(); if (Token::Match(tok, ") %type% {") && - !Token::Match(tok->next(), "const|namespace|class|struct|union|noexcept|override|final")) + !Token::Match(tok->next(), "const|namespace|class|struct|union|noexcept|override|final|volatile")) tok->deleteNext(); } @@ -5521,10 +5521,10 @@ void Tokenizer::simplifyFunctionPointers() Token *endTok = tok->link()->next()->link(); if (Token::simpleMatch(endTok, ") throw (")) endTok = endTok->linkAt(2); - if (!Token::Match(endTok, ") const| ;|,|)|=|[|{")) + if (!Token::Match(endTok, ") const|volatile| const|volatile| ;|,|)|=|[|{")) continue; - if (endTok->strAt(1) == "const") + while (Token::Match(endTok->next(), "const|volatile")) endTok->deleteNext(); // ok simplify this function pointer to an ordinary pointer @@ -8960,8 +8960,7 @@ void Tokenizer::simplifyCPPAttribute() } static const std::set keywords = { - "volatile" - , "inline" + "inline" , "_inline" , "__inline" , "__forceinline" @@ -8969,7 +8968,7 @@ static const std::set keywords = { , "__restrict" , "__restrict__" }; -// Remove "volatile", "inline", "register", "restrict", "override", "final", "static" and "constexpr" +// Remove "inline", "register", "restrict", "override", "final", "static" and "constexpr" // "restrict" keyword // - New to 1999 ANSI/ISO C standard // - Not in C++ standard yet diff --git a/test/testpostfixoperator.cpp b/test/testpostfixoperator.cpp index d877c2cbf..ca52a6231 100644 --- a/test/testpostfixoperator.cpp +++ b/test/testpostfixoperator.cpp @@ -238,8 +238,7 @@ private: " std::cout << k << std::endl;\n" " return 0;\n" "}"); - TODO_ASSERT_EQUALS("", - "[test.cpp:6]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:6]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout.str()); } void testiterator() { diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 9c1634d01..70bf6c727 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -1187,7 +1187,7 @@ private: void simplifyTypedef39() { const char code[] = "typedef int A;\n" "template struct S{};"; - const char expected[] = "template < const int , int > struct S { } ;"; + const char expected[] = "template < const int , volatile int > struct S { } ;"; ASSERT_EQUALS(expected, tok(code, false)); ASSERT_EQUALS("", errout.str()); } @@ -1478,7 +1478,7 @@ private: "_Iterator v3;"; // The expected result.. - const char expected[] = "long * const v1 ; " + const char expected[] = "volatile long * const v1 ; " "void * const v2 [ 2 ] ; " "int * const * v3 ;"; ASSERT_EQUALS(expected, tok(code)); @@ -2931,16 +2931,16 @@ private: // The expected result.. const char expected[] = "int * t1 ; " // simplified to regular pointer "int * const t2 ; " - "int * t3 ; " // volatile removed, gets simplified to regular pointer - "int * const t4 ; " // volatile removed + "int * volatile t3 ; " + "int * const volatile t4 ; " "int * t5 ; " "int * const t6 ; " - "int * t7 ; " // volatile removed - "int * const t8 ; " // volatile removed + "int * volatile t7 ; " + "int * const volatile t8 ; " "int ( :: C :: * t9 ) ( float ) ; " "int ( :: C :: * const t10 ) ( float ) ; " - "int ( :: C :: * t11 ) ( float ) ; " // volatile removed - "int ( :: C :: * const t12 ) ( float ) ;"; // volatile removed + "int ( :: C :: * volatile t11 ) ( float ) ; " + "int ( :: C :: * const volatile t12 ) ( float ) ;"; ASSERT_EQUALS(expected, tok(code, false)); ASSERT_EQUALS("", errout.str()); } @@ -3005,8 +3005,8 @@ private: // The expected result.. const char expected[] = ":: C ( :: C :: * f1 ) ( ) ; " ":: C ( :: C :: * f2 ) ( ) const ; " - ":: C ( :: C :: * f3 ) ( ) ; " - ":: C ( :: C :: * f4 ) ( ) const ;"; + ":: C ( :: C :: * f3 ) ( ) volatile ; " + ":: C ( :: C :: * f4 ) ( ) const volatile ;"; ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS("", errout.str()); } @@ -3043,8 +3043,8 @@ private: // The expected result.. const char expected[] = ":: B :: C ( :: B :: C :: * f1 ) ( ) ; " ":: B :: C ( :: B :: C :: * f2 ) ( ) const ; " - ":: B :: C ( :: B :: C :: * f3 ) ( ) ; " - ":: B :: C ( :: B :: C :: * f4 ) ( ) const ;"; + ":: B :: C ( :: B :: C :: * f3 ) ( ) volatile ; " + ":: B :: C ( :: B :: C :: * f4 ) ( ) const volatile ;"; ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS("", errout.str()); } diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 3ddfb66c1..b2ef2656a 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -286,6 +286,7 @@ private: TEST_CASE(symboldatabase66); // #8540 TEST_CASE(symboldatabase67); // #8538 TEST_CASE(symboldatabase68); // #8560 + TEST_CASE(symboldatabase69); TEST_CASE(enum1); TEST_CASE(enum2); @@ -3864,6 +3865,28 @@ private: ASSERT(f && f->function() && f->function()->isNoExcept()); } + void symboldatabase69() { + GET_SYMBOL_DB("struct Fred {\n" + " int x, y;\n" + " void foo() volatile { }\n" + " void foo() const { }\n" + " void foo() { }\n" + "};"); + const Token *f = db ? Token::findsimplematch(tokenizer.tokens(), "foo ( ) volatile {") : nullptr; + ASSERT(f != nullptr); + ASSERT(f && f->function() && f->function()->token->linenr() == 3); + ASSERT(f && f->function() && f->function()->isVolatile()); + f = db ? Token::findsimplematch(tokenizer.tokens(), "foo ( ) const {") : nullptr; + ASSERT(f != nullptr); + ASSERT(f && f->function() && f->function()->token->linenr() == 4); + ASSERT(f && f->function() && f->function()->isConst()); + f = db ? Token::findsimplematch(tokenizer.tokens(), "foo ( ) {") : nullptr; + ASSERT(f != nullptr); + ASSERT(f && f->function() && f->function()->token->linenr() == 5); + ASSERT(f && f->function() && !f->function()->isVolatile()); + ASSERT(f && f->function() && !f->function()->isConst()); + } + void enum1() { GET_SYMBOL_DB("enum BOOL { FALSE, TRUE }; enum BOOL b;"); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 233de4f7a..cb5b762b8 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -4033,7 +4033,7 @@ private: const std::string actual(tokenizeAndStringify(code)); - ASSERT_EQUALS("int a ; a = 0 ;\nint b ; b = 0 ;\nint c ; c = 0 ;", actual); + ASSERT_EQUALS("volatile int a ; a = 0 ;\nvolatile int b ; b = 0 ;\nvolatile int c ; c = 0 ;", actual); }