From c5ee083c82f5758ca21ce505b33a3b99b72f14a0 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Fri, 15 Feb 2013 06:44:07 +0100 Subject: [PATCH] Fixed #4388 (false positive 'noConstructor' in 1.57) --- lib/symboldatabase.cpp | 38 +++++++++++++++++++++++++++------- lib/symboldatabase.h | 4 ++++ lib/tokenize.cpp | 43 --------------------------------------- test/testconstructors.cpp | 11 ++++++++++ test/testtokenize.cpp | 43 --------------------------------------- 5 files changed, 46 insertions(+), 93 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 51f971907..b8b6d330b 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -410,10 +410,6 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti if (end->next()->str() == "const") function.isConst = true; - // pure virtual function - if (Token::Match(end, ") const| = %any%")) - function.isPure = true; - // count the number of constructors if (function.type == Function::eConstructor || function.type == Function::eCopyConstructor) @@ -424,10 +420,35 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti function.arg = function.argDef; // out of line function - if (Token::Match(end, ") const| ;") || - Token::Match(end, ") const| = %any%")) { + if (Token::Match(end, ") const| ;")) { // find the function implementation later tok = end->next(); + if (tok->str() != ";") + tok = tok->next(); + + scope->functionList.push_back(function); + } + + // default or delete + else if (Token::Match(end, ") = default|delete ;")) { + if (end->strAt(2) == "default") + function.isDefault = true; + else + function.isDelete = true; + + tok = end->tokAt(3); + + scope->functionList.push_back(function); + } + + // pure virtual function + else if (Token::Match(end, ") const| = %any% ;")) { + function.isPure = true; + + if (end->next()->str() == "const") + tok = end->tokAt(4); + else + tok = end->tokAt(3); scope->functionList.push_back(function); } @@ -981,7 +1002,8 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const tok->strAt(-1) == "::" || tok->strAt(-1) == "~" || // or a scope qualifier in front of tok outerScope->isClassOrStruct()) && // or a ctor/dtor (Token::Match(tok->next()->link(), ") const| ;|{|=") || - Token::Match(tok->next()->link(), ") : ::| %var% (|::|<|{"))) { + Token::Match(tok->next()->link(), ") : ::| %var% (|::|<|{") || + Token::Match(tok->next()->link(), ") = delete|default ;"))) { *funcStart = tok; *argStart = tok->next(); return true; @@ -1642,6 +1664,8 @@ void SymbolDatabase::printOut(const char *title) const std::cout << " isStatic: " << (func->isStatic ? "true" : "false") << std::endl; std::cout << " isFriend: " << (func->isFriend ? "true" : "false") << std::endl; std::cout << " isExplicit: " << (func->isExplicit ? "true" : "false") << std::endl; + std::cout << " isDefault: " << (func->isDefault ? "true" : "false") << std::endl; + std::cout << " isDelete: " << (func->isDelete ? "true" : "false") << std::endl; std::cout << " isOperator: " << (func->isOperator ? "true" : "false") << std::endl; std::cout << " retFuncPtr: " << (func->retFuncPtr ? "true" : "false") << std::endl; std::cout << " tokenDef: " << _tokenizer->list.fileLine(func->tokenDef) << std::endl; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 8862d27b2..00463c424 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -390,6 +390,8 @@ public: isStatic(false), isFriend(false), isExplicit(false), + isDefault(false), + isDelete(false), isOperator(false), retFuncPtr(false) { } @@ -427,6 +429,8 @@ public: bool isStatic; // is static bool isFriend; // is friend bool isExplicit; // is explicit + bool isDefault; // is default + bool isDelete; // is delete bool isOperator; // is operator bool retFuncPtr; // returns function pointer diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index cc04088cc..8b7d34079 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1745,8 +1745,6 @@ bool Tokenizer::tokenize(std::istream &code, return false; } - simplifyDefaultAndDeleteInsideClass(); - // Remove __declspec() simplifyDeclspec(); @@ -2196,47 +2194,6 @@ bool Tokenizer::hasComplicatedSyntaxErrorsInTemplates() return false; } -void Tokenizer::simplifyDefaultAndDeleteInsideClass() -{ - if (isC()) - return; - - // Remove "= default|delete" inside class|struct definitions - // Todo: Remove it if it is used "externally" too. - for (Token *tok = list.front(); tok; tok = tok->next()) { - if (Token::Match(tok, "struct|class %var% :|{")) { - for (Token *tok2 = tok->tokAt(3); tok2; tok2 = tok2->next()) { - if (tok2->str() == "{") - tok2 = tok2->link(); - else if (tok2->str() == "}") - break; - else if (Token::Match(tok2, ") = delete|default ;")) { - Token * const end = tok2->tokAt(4); - tok2 = tok2->link()->previous(); - - // operator ==|>|<|.. - if (Token::Match(tok2->previous(), "operator %any%")) - tok2 = tok2->previous(); - else if (Token::simpleMatch(tok2->tokAt(-2), "operator [ ]")) - tok2 = tok2->tokAt(-2); - else if (Token::simpleMatch(tok2->tokAt(-2), "operator ( )")) - tok2 = tok2->tokAt(-2); - else if (Token::simpleMatch(tok2->tokAt(-3), "operator delete [ ]")) - tok2 = tok2->tokAt(-3); - - while ((tok2->isName() && tok2->str().find(":") == std::string::npos) || - Token::Match(tok2, "[&*~]")) - tok2 = tok2->previous(); - if (Token::Match(tok2, "[;{}]") || tok2->isName()) - Token::eraseTokens(tok2, end); - else - tok2 = end->previous(); - } - } - } - } -} - bool Tokenizer::hasEnumsWithTypedef() { for (const Token *tok = list.front(); tok; tok = tok->next()) { diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index 52db57b8d..0ce35856e 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -62,6 +62,7 @@ private: TEST_CASE(simple7); // ticket #4531 TEST_CASE(simple8); TEST_CASE(simple9); // ticket #4574 + TEST_CASE(simple10); // ticket #4388 TEST_CASE(initvar_with_this); // BUG 2190300 TEST_CASE(initvar_if); // BUG 2190290 @@ -331,6 +332,16 @@ private: ASSERT_EQUALS("", errout.str()); } + void simple10() { // ticket #4388 + check("class Fred {\n" + "public:\n" + " Fred() = default;\n" + "private:\n" + " int x;\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + void initvar_with_this() { check("struct Fred\n" "{\n" diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 459f22563..44fba5695 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -398,7 +398,6 @@ private: TEST_CASE(cpp0xtemplate1); TEST_CASE(cpp0xtemplate2); TEST_CASE(cpp0xtemplate3); - TEST_CASE(cpp0xdefault); TEST_CASE(arraySize); @@ -6314,48 +6313,6 @@ private: tokenizeAndStringify(code)); } - void cpp0xdefault() { - { - const char *code = "struct foo {" - " foo() = default;" - "}"; - ASSERT_EQUALS("struct foo { }", tokenizeAndStringify(code)); - } - - { - const char *code = "struct A {" - " void operator delete (void *) = delete;" - " void operator delete[] (void *) = delete;" - "}"; - ASSERT_EQUALS("struct A { }", tokenizeAndStringify(code)); - } - - { - const char *code = "struct A {" - " void operator = (void *) = delete;" - "}"; - ASSERT_EQUALS("struct A { }", tokenizeAndStringify(code)); - } - - { - const char *code = "struct foo {" - " foo();" - "}" - "foo::foo() = delete;"; - TODO_ASSERT_EQUALS("struct foo { }", - "struct foo { foo ( ) ; } foo :: foo ( ) = delete ;", tokenizeAndStringify(code)); - } - - //ticket #3448 (segmentation fault) - { - const char *code = "struct A {" - " void bar () = delete;" - "};" - "void baz () = delete;"; - ASSERT_EQUALS("struct A { } ; void baz ( ) = delete ;", tokenizeAndStringify(code)); - } - } - std::string arraySize_(const std::string &code) { errout.str(""); Settings settings;