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.
This commit is contained in:
IOBYTE 2018-05-10 01:40:01 -04:00 committed by Daniel Marjamäki
parent 5452c4dc4a
commit 184537884f
8 changed files with 66 additions and 35 deletions

View File

@ -278,11 +278,11 @@ void CheckOther::warningOldStylePointerCast()
tok = scope->bodyStart; tok = scope->bodyStart;
for (; tok && tok != scope->bodyEnd; tok = tok->next()) { for (; tok && tok != scope->bodyEnd; tok = tok->next()) {
// Old style pointer casting.. // 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; continue;
// skip first "const" in "const Type* const" // skip first "const" in "const Type* const"
if (tok->strAt(1) == "const") while (Token::Match(tok->next(), "const|volatile"))
tok = tok->next(); tok = tok->next();
const Token* typeTok = tok->next(); const Token* typeTok = tok->next();
// skip second "const" in "const Type* const" // skip second "const" in "const Type* const"
@ -326,7 +326,7 @@ void CheckOther::invalidPointerCast()
const Token* toTok = nullptr; const Token* toTok = nullptr;
const Token* fromTok = nullptr; const Token* fromTok = nullptr;
// Find cast // Find cast
if (Token::Match(tok, "( const| %type% %type%| const| * )")) { if (Token::Match(tok, "( const|volatile| const|volatile| %type% %type%| const| * )")) {
toTok = tok; toTok = tok;
fromTok = tok->astOperand1(); fromTok = tok->astOperand1();
} else if (Token::simpleMatch(tok, "reinterpret_cast <") && tok->linkAt(1)) { } else if (Token::simpleMatch(tok, "reinterpret_cast <") && tok->linkAt(1)) {

View File

@ -1406,8 +1406,8 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
tok1 = tok1->link()->tokAt(-2); tok1 = tok1->link()->tokAt(-2);
} }
// skip over const, noexcept, throw and override specifiers // skip over const, noexcept, throw, override, final and volatile specifiers
while (Token::Match(tok2, "const|noexcept|throw|override|final")) { while (Token::Match(tok2, "const|noexcept|throw|override|final|volatile")) {
tok2 = tok2->next(); tok2 = tok2->next();
if (tok2 && tok2->str() == "(") if (tok2 && tok2->str() == "(")
tok2 = tok2->link()->next(); tok2 = tok2->link()->next();
@ -1646,9 +1646,9 @@ void Variable::evaluate(const Library* lib)
tok = tok->next(); tok = tok->next();
} }
while (Token::Match(_start, "static|const %any%")) while (Token::Match(_start, "static|const|volatile %any%"))
_start = _start->next(); _start = _start->next();
while (_end && _end->previous() && _end->str() == "const") while (_end && _end->previous() && Token::Match(_end, "const|volatile"))
_end = _end->previous(); _end = _end->previous();
if (_start) { if (_start) {
@ -1793,6 +1793,8 @@ Function::Function(const Tokenizer *_tokenizer, const Token *tok, const Scope *s
setFlag(fHasOverrideSpecifier, true); setFlag(fHasOverrideSpecifier, true);
else if (tok->str() == "final") else if (tok->str() == "final")
setFlag(fHasFinalSpecifier, true); setFlag(fHasFinalSpecifier, true);
else if (tok->str() == "volatile")
isVolatile(true);
else if (tok->str() == "noexcept") { else if (tok->str() == "noexcept") {
isNoExcept(!Token::simpleMatch(tok->next(), "( false )")); isNoExcept(!Token::simpleMatch(tok->next(), "( false )"));
if (tok->next()->str() == "(") if (tok->next()->str() == "(")
@ -2703,6 +2705,7 @@ void SymbolDatabase::printOut(const char *title) const
std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl; std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl;
std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl; std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl;
std::cout << " isVariadic: " << func->isVariadic() << std::endl; std::cout << " isVariadic: " << func->isVariadic() << std::endl;
std::cout << " isVolatile: " << func->isVolatile() << std::endl;
std::cout << " attributes:"; std::cout << " attributes:";
if (func->isAttributeConst()) if (func->isAttributeConst())
std::cout << " const "; std::cout << " const ";
@ -3057,7 +3060,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
const Token *typeTok = startTok; const Token *typeTok = startTok;
// skip over stuff to get to type // 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(); typeTok = typeTok->next();
if (Token::Match(typeTok, ",|)")) { // #8333 if (Token::Match(typeTok, ",|)")) { // #8333
symbolDatabase->_tokenizer->syntaxError(typeTok); 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 // check for argument with no name or missing varid
if (!endTok) { 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) { if (tok->previous() != typeTok) {
nameTok = tok->previous(); nameTok = tok->previous();
endTok = nameTok->previous(); endTok = nameTok->previous();
@ -3100,7 +3103,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
} }
// skip over stuff before type // skip over stuff before type
while (Token::Match(startTok, "enum|struct|const")) while (Token::Match(startTok, "enum|struct|const|volatile"))
startTok = startTok->next(); startTok = startTok->next();
argumentList.emplace_back(nameTok, startTok, endTok, count++, Argument, argType, functionScope, &symbolDatabase->_settings->library); 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; return next;
} }
// skip const|static|mutable|extern // skip const|volatile|static|mutable|extern
while (Token::Match(tok, "const|static|mutable|extern")) { while (Token::Match(tok, "const|volatile|static|mutable|extern")) {
tok = tok->next(); tok = tok->next();
} }

View File

@ -672,7 +672,8 @@ class CPPCHECKLIB Function {
fIsOperator = (1 << 16), ///< @brief is operator fIsOperator = (1 << 16), ///< @brief is operator
fHasLvalRefQual = (1 << 17), ///< @brief has & lvalue ref-qualifier fHasLvalRefQual = (1 << 17), ///< @brief has & lvalue ref-qualifier
fHasRvalRefQual = (1 << 18), ///< @brief has && rvalue 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 { bool isVariadic() const {
return getFlag(fIsVariadic); return getFlag(fIsVariadic);
} }
bool isVolatile() const {
return getFlag(fIsVolatile);
}
void hasBody(bool state) { void hasBody(bool state) {
setFlag(fHasBody, state); setFlag(fHasBody, state);
@ -893,6 +897,9 @@ private:
void isVariadic(bool state) { void isVariadic(bool state) {
setFlag(fIsVariadic, state); setFlag(fIsVariadic, state);
} }
void isVolatile(bool state) {
setFlag(fIsVolatile, state);
}
}; };
class CPPCHECKLIB Scope { class CPPCHECKLIB Scope {

View File

@ -3635,7 +3635,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
if (_settings->terminated()) if (_settings->terminated())
return false; return false;
// Remove "volatile", "inline", "register", and "restrict" // Remove "inline", "register", and "restrict"
simplifyKeyword(); simplifyKeyword();
// simplify simple calculations inside <..> // simplify simple calculations inside <..>
@ -4169,7 +4169,7 @@ void Tokenizer::removeMacrosInGlobalScope()
if (tok->str() == "(") { if (tok->str() == "(") {
tok = tok->link(); tok = tok->link();
if (Token::Match(tok, ") %type% {") && 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(); tok->deleteNext();
} }
@ -5521,10 +5521,10 @@ void Tokenizer::simplifyFunctionPointers()
Token *endTok = tok->link()->next()->link(); Token *endTok = tok->link()->next()->link();
if (Token::simpleMatch(endTok, ") throw (")) if (Token::simpleMatch(endTok, ") throw ("))
endTok = endTok->linkAt(2); endTok = endTok->linkAt(2);
if (!Token::Match(endTok, ") const| ;|,|)|=|[|{")) if (!Token::Match(endTok, ") const|volatile| const|volatile| ;|,|)|=|[|{"))
continue; continue;
if (endTok->strAt(1) == "const") while (Token::Match(endTok->next(), "const|volatile"))
endTok->deleteNext(); endTok->deleteNext();
// ok simplify this function pointer to an ordinary pointer // ok simplify this function pointer to an ordinary pointer
@ -8960,8 +8960,7 @@ void Tokenizer::simplifyCPPAttribute()
} }
static const std::set<std::string> keywords = { static const std::set<std::string> keywords = {
"volatile" "inline"
, "inline"
, "_inline" , "_inline"
, "__inline" , "__inline"
, "__forceinline" , "__forceinline"
@ -8969,7 +8968,7 @@ static const std::set<std::string> keywords = {
, "__restrict" , "__restrict"
, "__restrict__" , "__restrict__"
}; };
// Remove "volatile", "inline", "register", "restrict", "override", "final", "static" and "constexpr" // Remove "inline", "register", "restrict", "override", "final", "static" and "constexpr"
// "restrict" keyword // "restrict" keyword
// - New to 1999 ANSI/ISO C standard // - New to 1999 ANSI/ISO C standard
// - Not in C++ standard yet // - Not in C++ standard yet

View File

@ -238,8 +238,7 @@ private:
" std::cout << k << std::endl;\n" " std::cout << k << std::endl;\n"
" return 0;\n" " return 0;\n"
"}"); "}");
TODO_ASSERT_EQUALS("", ASSERT_EQUALS("[test.cpp:6]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout.str());
"[test.cpp:6]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout.str());
} }
void testiterator() { void testiterator() {

View File

@ -1187,7 +1187,7 @@ private:
void simplifyTypedef39() { void simplifyTypedef39() {
const char code[] = "typedef int A;\n" const char code[] = "typedef int A;\n"
"template <const A, volatile A> struct S{};"; "template <const A, volatile A> 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(expected, tok(code, false));
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
@ -1478,7 +1478,7 @@ private:
"_Iterator v3;"; "_Iterator v3;";
// The expected result.. // The expected result..
const char expected[] = "long * const v1 ; " const char expected[] = "volatile long * const v1 ; "
"void * const v2 [ 2 ] ; " "void * const v2 [ 2 ] ; "
"int * const * v3 ;"; "int * const * v3 ;";
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
@ -2931,16 +2931,16 @@ private:
// The expected result.. // The expected result..
const char expected[] = "int * t1 ; " // simplified to regular pointer const char expected[] = "int * t1 ; " // simplified to regular pointer
"int * const t2 ; " "int * const t2 ; "
"int * t3 ; " // volatile removed, gets simplified to regular pointer "int * volatile t3 ; "
"int * const t4 ; " // volatile removed "int * const volatile t4 ; "
"int * t5 ; " "int * t5 ; "
"int * const t6 ; " "int * const t6 ; "
"int * t7 ; " // volatile removed "int * volatile t7 ; "
"int * const t8 ; " // volatile removed "int * const volatile t8 ; "
"int ( :: C :: * t9 ) ( float ) ; " "int ( :: C :: * t9 ) ( float ) ; "
"int ( :: C :: * const t10 ) ( float ) ; " "int ( :: C :: * const t10 ) ( float ) ; "
"int ( :: C :: * t11 ) ( float ) ; " // volatile removed "int ( :: C :: * volatile t11 ) ( float ) ; "
"int ( :: C :: * const t12 ) ( float ) ;"; // volatile removed "int ( :: C :: * const volatile t12 ) ( float ) ;";
ASSERT_EQUALS(expected, tok(code, false)); ASSERT_EQUALS(expected, tok(code, false));
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
@ -3005,8 +3005,8 @@ private:
// The expected result.. // The expected result..
const char expected[] = ":: C ( :: C :: * f1 ) ( ) ; " const char expected[] = ":: C ( :: C :: * f1 ) ( ) ; "
":: C ( :: C :: * f2 ) ( ) const ; " ":: C ( :: C :: * f2 ) ( ) const ; "
":: C ( :: C :: * f3 ) ( ) ; " ":: C ( :: C :: * f3 ) ( ) volatile ; "
":: C ( :: C :: * f4 ) ( ) const ;"; ":: C ( :: C :: * f4 ) ( ) const volatile ;";
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
@ -3043,8 +3043,8 @@ private:
// The expected result.. // The expected result..
const char expected[] = ":: B :: C ( :: B :: C :: * f1 ) ( ) ; " const char expected[] = ":: B :: C ( :: B :: C :: * f1 ) ( ) ; "
":: B :: C ( :: B :: C :: * f2 ) ( ) const ; " ":: B :: C ( :: B :: C :: * f2 ) ( ) const ; "
":: B :: C ( :: B :: C :: * f3 ) ( ) ; " ":: B :: C ( :: B :: C :: * f3 ) ( ) volatile ; "
":: B :: C ( :: B :: C :: * f4 ) ( ) const ;"; ":: B :: C ( :: B :: C :: * f4 ) ( ) const volatile ;";
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }

View File

@ -286,6 +286,7 @@ private:
TEST_CASE(symboldatabase66); // #8540 TEST_CASE(symboldatabase66); // #8540
TEST_CASE(symboldatabase67); // #8538 TEST_CASE(symboldatabase67); // #8538
TEST_CASE(symboldatabase68); // #8560 TEST_CASE(symboldatabase68); // #8560
TEST_CASE(symboldatabase69);
TEST_CASE(enum1); TEST_CASE(enum1);
TEST_CASE(enum2); TEST_CASE(enum2);
@ -3864,6 +3865,28 @@ private:
ASSERT(f && f->function() && f->function()->isNoExcept()); 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() { void enum1() {
GET_SYMBOL_DB("enum BOOL { FALSE, TRUE }; enum BOOL b;"); GET_SYMBOL_DB("enum BOOL { FALSE, TRUE }; enum BOOL b;");

View File

@ -4033,7 +4033,7 @@ private:
const std::string actual(tokenizeAndStringify(code)); 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);
} }