diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 25f42260e..09f154f2a 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -443,9 +443,18 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti function.arg = function.argDef; // out of line function - if (Token::simpleMatch(end, ") ;")) { + if (Token::Match(end, ") const| &|&&| ;")) { // find the function implementation later tok = end->next(); + if (tok->str() == "const") + tok = tok->next(); + if (tok->str() == "&") { + function.hasLvalRefQualifier(true); + tok = tok->next(); + } else if (tok->str() == "&&") { + function.hasRvalRefQualifier(true); + tok = tok->next(); + } scope->addFunction(function); } @@ -575,6 +584,16 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti function.throwArg = end->tokAt(arg); function.isThrow(true); + } else if (Token::Match(end, ") const| &|&&|")) { + int arg = 1; + + if (end->strAt(arg) == "const") + arg++; + + if (end->strAt(arg) == "&") + function.hasLvalRefQualifier(true); + else if (end->strAt(arg) == "&&") + function.hasRvalRefQualifier(true); } // find start of function '{' @@ -670,7 +689,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti } // has body? - if (Token::Match(scopeBegin, "{|:")) { + if (Token::Match(scopeBegin, "&|&&| {|:")) { tok = funcStart; // class function @@ -1388,6 +1407,7 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const (tok2->isUpperCaseName() && Token::Match(tok2, "%name% ;|{")) || (tok2->isUpperCaseName() && Token::Match(tok2, "%name% (") && tok2->next()->link()->strAt(1) == "{") || Token::Match(tok2, ": ::| %name% (|::|<|{") || + Token::Match(tok2, "const| &|&&| ;|{") || Token::Match(tok2, "= delete|default ;") || Token::Match(tok2, "const| noexcept {|:|;|=") || (Token::Match(tok2, "const| noexcept|throw (") && @@ -1763,6 +1783,9 @@ Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token *tok, void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const Token *argStart) { const bool destructor((*tok)->previous()->str() == "~"); + const bool has_const(argStart->link()->strAt(1) == "const"); + const bool lval(argStart->link()->strAt(has_const ? 2 : 1) == "&"); + const bool rval(argStart->link()->strAt(has_const ? 2 : 1) == "&&"); const Token *tok1; // skip class/struct name if (destructor) @@ -1888,8 +1911,9 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To // normal function? if ((*tok)->next()->link()) { const bool hasConstKeyword = (*tok)->next()->link()->next()->str() == "const"; - if ((func->isConst() && hasConstKeyword) || - (!func->isConst() && !hasConstKeyword)) { + if ((func->isConst() == hasConstKeyword) && + (func->hasLvalRefQualifier() == lval) && + (func->hasRvalRefQualifier() == rval)) { func->hasBody(true); } } @@ -2303,6 +2327,8 @@ void SymbolDatabase::printOut(const char *title) const std::cout << " isNoExcept: " << func->isNoExcept() << std::endl; std::cout << " isThrow: " << func->isThrow() << std::endl; std::cout << " isOperator: " << func->isOperator() << std::endl; + std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl; + std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl; std::cout << " attributes:"; if (func->isAttributeConst()) std::cout << " const "; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 4c75b7133..df56da5ca 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -593,21 +593,23 @@ private: class CPPCHECKLIB Function { /** @brief flags mask used to access specific bit. */ enum { - fHasBody = (1 << 0), /** @brief has implementation */ - fIsInline = (1 << 1), /** @brief implementation in class definition */ - fIsConst = (1 << 2), /** @brief is const */ - fIsVirtual = (1 << 3), /** @brief is virtual */ - fIsPure = (1 << 4), /** @brief is pure virtual */ - fIsStatic = (1 << 5), /** @brief is static */ - fIsStaticLocal = (1 << 6), /** @brief is static local */ - fIsExtern = (1 << 7), /** @brief is extern */ - fIsFriend = (1 << 8), /** @brief is friend */ - fIsExplicit = (1 << 9), /** @brief is explicit */ - fIsDefault = (1 << 10), /** @brief is default */ - fIsDelete = (1 << 11), /** @brief is delete */ - fIsNoExcept = (1 << 12), /** @brief is noexcept */ - fIsThrow = (1 << 13), /** @brief is throw */ - fIsOperator = (1 << 14) /** @brief is operator */ + fHasBody = (1 << 0), /** @brief has implementation */ + fIsInline = (1 << 1), /** @brief implementation in class definition */ + fIsConst = (1 << 2), /** @brief is const */ + fIsVirtual = (1 << 3), /** @brief is virtual */ + fIsPure = (1 << 4), /** @brief is pure virtual */ + fIsStatic = (1 << 5), /** @brief is static */ + fIsStaticLocal = (1 << 6), /** @brief is static local */ + fIsExtern = (1 << 7), /** @brief is extern */ + fIsFriend = (1 << 8), /** @brief is friend */ + fIsExplicit = (1 << 9), /** @brief is explicit */ + fIsDefault = (1 << 10), /** @brief is default */ + fIsDelete = (1 << 11), /** @brief is delete */ + fIsNoExcept = (1 << 12), /** @brief is noexcept */ + fIsThrow = (1 << 13), /** @brief is throw */ + fIsOperator = (1 << 14), /** @brief is operator */ + fHasLvalRefQual = (1 << 15), /** @brief has & lvalue ref-qualifier */ + fHasRvalRefQual = (1 << 16) /** @brief has && rvalue ref-qualifier */ }; /** @@ -739,6 +741,12 @@ public: bool isOperator() const { return getFlag(fIsOperator); } + bool hasLvalRefQualifier() const { + return getFlag(fHasLvalRefQual); + } + bool hasRvalRefQualifier() const { + return getFlag(fHasRvalRefQual); + } void hasBody(bool state) { setFlag(fHasBody, state); @@ -785,6 +793,12 @@ public: void isOperator(bool state) { setFlag(fIsOperator, state); } + void hasLvalRefQualifier(bool state) { + setFlag(fHasLvalRefQual, state); + } + void hasRvalRefQualifier(bool state) { + setFlag(fHasRvalRefQual, state); + } const Token *tokenDef; // function name token in class definition const Token *argDef; // function argument start '(' in class definition diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 48e5b47c1..3f47816ed 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -249,6 +249,7 @@ private: TEST_CASE(findFunction5); // #6230 TEST_CASE(findFunction6); TEST_CASE(findFunction7); // #6700 + TEST_CASE(findFunction8); TEST_CASE(noexceptFunction1); TEST_CASE(noexceptFunction2); @@ -2606,6 +2607,83 @@ private: ASSERT_EQUALS(true, callfunc && callfunc->tokAt(2)->function() && callfunc->tokAt(2)->function()->tokenDef->linenr() == 3); } + void findFunction8() { + GET_SYMBOL_DB("struct S {\n" + " void f() { }\n" + " void f() & { }\n" + " void f() &&{ }\n" + " void f() const { }\n" + " void f() const & { }\n" + " void f() const &&{ }\n" + " void g() ;\n" + " void g() & ;\n" + " void g() &&;\n" + " void g() const ;\n" + " void g() const & ;\n" + " void g() const &&;\n" + "};\n" + "void S::g() { }\n" + "void S::g() & { }\n" + "void S::g() &&{ }\n" + "void S::g() const { }\n" + "void S::g() const & { }\n" + "void S::g() const &&{ }\n"); + ASSERT_EQUALS("", errout.str()); + + const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( ) {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2); + + f = Token::findsimplematch(tokenizer.tokens(), "f ( ) & {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3); + + f = Token::findsimplematch(tokenizer.tokens(), "f ( ) && {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4); + + f = Token::findsimplematch(tokenizer.tokens(), "f ( ) const {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5); + + f = Token::findsimplematch(tokenizer.tokens(), "f ( ) const & {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6); + + f = Token::findsimplematch(tokenizer.tokens(), "f ( ) const && {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7); + + f = Token::findsimplematch(tokenizer.tokens(), "g ( ) {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8 && f->function()->token->linenr() == 15); + + f = Token::findsimplematch(tokenizer.tokens(), "g ( ) & {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 9 && f->function()->token->linenr() == 16); + + f = Token::findsimplematch(tokenizer.tokens(), "g ( ) && {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 10 && f->function()->token->linenr() == 17); + + f = Token::findsimplematch(tokenizer.tokens(), "g ( ) const {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 11 && f->function()->token->linenr() == 18); + + f = Token::findsimplematch(tokenizer.tokens(), "g ( ) const & {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 12 && f->function()->token->linenr() == 19); + + f = Token::findsimplematch(tokenizer.tokens(), "g ( ) const && {"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 13 && f->function()->token->linenr() == 20); + + f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) {"); + ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 8 && f->tokAt(2)->function()->token->linenr() == 15); + + f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) & {"); + ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 9 && f->tokAt(2)->function()->token->linenr() == 16); + + f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) && {"); + ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 10 && f->tokAt(2)->function()->token->linenr() == 17); + + f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) const {"); + ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 11 && f->tokAt(2)->function()->token->linenr() == 18); + + f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) const & {"); + ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 12 && f->tokAt(2)->function()->token->linenr() == 19); + + f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) const && {"); + ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 13 && f->tokAt(2)->function()->token->linenr() == 20); + } #define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \