diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index af6e677af..f4a80138f 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -60,6 +60,7 @@ CmdLineParser::CmdLineParser(Settings *settings) , _showHelp(false) , _showVersion(false) , _showErrorMessages(false) + , _exitAfterPrint(false) { } @@ -75,6 +76,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) if (strcmp(argv[i], "--version") == 0) { _showVersion = true; + _exitAfterPrint = true; return true; } // Flag used for various purposes during debugging @@ -362,10 +364,9 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) // print all possible error messages.. else if (strcmp(argv[i], "--errorlist") == 0) { - //_cppcheck->getErrorMessages(); _showErrorMessages = true; _settings->_xml = true; - return true; + _exitAfterPrint = true; } // documentation.. @@ -383,6 +384,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) while (doc2.find("\n\n\n") != std::string::npos) doc2.erase(doc2.find("\n\n\n"), 1); std::cout << doc2; + _exitAfterPrint = true; return true; } @@ -459,6 +461,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) { _pathnames.clear(); _showHelp = true; + _exitAfterPrint = true; break; } @@ -486,15 +489,17 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) PrintMessage("--test-2-pass doesn't work with -j option yet."); } - if (argc <= 1) _showHelp = true; if (_showHelp) { PrintHelp(); + return true; } - else if (_pathnames.empty()) + + // Print error only if we have "real" command and expect files + if (!_exitAfterPrint && _pathnames.empty()) { PrintMessage("cppcheck: No C or C++ source files found."); return false; diff --git a/cli/cmdlineparser.h b/cli/cmdlineparser.h index 60fccb93b..7a60e24a6 100644 --- a/cli/cmdlineparser.h +++ b/cli/cmdlineparser.h @@ -84,6 +84,14 @@ public: return _showHelp; } + /** + * Return if we should exit after printing version, help etc. + */ + bool ExitAfterPrinting() const + { + return _exitAfterPrint; + } + protected: /** @@ -101,6 +109,7 @@ private: bool _showHelp; bool _showVersion; bool _showErrorMessages; + bool _exitAfterPrint; std::vector _pathnames; }; diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 4885357e6..fdb886471 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -45,10 +45,9 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c if (success) { - if (parser.GetShowVersion()) + if (parser.GetShowVersion() && !parser.GetShowErrorMessages()) { std::cout << "Cppcheck " << cppcheck->version() << std::endl; - return true; } if (parser.GetShowErrorMessages()) @@ -57,8 +56,10 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c std::cout << ErrorLogger::ErrorMessage::getXMLHeader(_settings._xml_version); cppcheck->getErrorMessages(); std::cout << ErrorLogger::ErrorMessage::getXMLFooter() << std::endl; - std::exit(0); } + + if (parser.ExitAfterPrinting()) + std::exit(0); } // Check that all include paths exist diff --git a/gui/aboutdialog.cpp b/gui/aboutdialog.cpp index f21bc5495..ec79fc6bf 100644 --- a/gui/aboutdialog.cpp +++ b/gui/aboutdialog.cpp @@ -27,7 +27,7 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) mUI.setupUi(this); mUI.mVersion->setText(mUI.mVersion->text().arg(version)); - QString url = "http://cppcheck.wiki.sourceforge.net/"; + QString url = "http://cppcheck.sourceforge.net/"; mUI.mHomepage->setText(mUI.mHomepage->text().arg(url)); connect(mUI.mButtons, SIGNAL(accepted()), this, SLOT(accept())); } diff --git a/gui/erroritem.cpp b/gui/erroritem.cpp index 35506c697..a7b09c853 100644 --- a/gui/erroritem.cpp +++ b/gui/erroritem.cpp @@ -43,9 +43,11 @@ ErrorItem::ErrorItem(const ErrorLine &line) QString ErrorItem::ToString() const { QString str = file + " - " + id + " - " + severity +"\n"; - str += " " + summary; - str += "\n" + message; + str += summary + "\n"; + str += message + "\n"; for (int i = 0; i < files.size(); i++) - str += " " + files[i] + ": " + lines[i] + "\n"; + { + str += " " + files[i] + ": " + QString::number(lines[i]) + "\n"; + } return str; } diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 75a3f54b2..72cd10091 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -358,6 +358,7 @@ Settings MainWindow::GetCppcheckSettings() result.addEnabled("style"); result.addEnabled("information"); + result.addEnabled("missingInclude"); result.debug = false; result.debugwarnings = mSettings->value(SETTINGS_SHOW_DEBUG_WARNINGS, false).toBool(); result._errorsOnly = false; diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 2881d894b..fc96af0cc 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -140,11 +140,7 @@ void CheckClass::constructors() // It's non-static and it's not initialized => error if (func->type == Function::eOperatorEqual) { - const Token *operStart = 0; - if (func->token->str() == "=") - operStart = func->token->tokAt(1); - else - operStart = func->token->tokAt(3); + const Token *operStart = func->token->tokAt(1); bool classNameUsed = false; for (const Token *operTok = operStart; operTok != operStart->link(); operTok = operTok->next()) @@ -376,14 +372,14 @@ void CheckClass::initializeVarList(const Function &func, std::list } // Calling member function? - else if (Token::simpleMatch(ftok, "operator = (") && + else if (Token::simpleMatch(ftok, "operator= (") && ftok->previous()->str() != "::") { // check if member function exists std::list::const_iterator it; for (it = scope->functionList.begin(); it != scope->functionList.end(); ++it) { - if (ftok->next()->str() == it->tokenDef->str() && it->type != Function::eConstructor) + if (ftok->str() == it->tokenDef->str() && it->type != Function::eConstructor) break; } @@ -583,11 +579,6 @@ void CheckClass::privateFunctions() if (Token::findmatch(_tokenizer->tokens(), "; __property ;")) return; - // #2407 calls from operator() is not detected - // TODO: Don't bailout. Detect the call. - if (Token::findmatch(_tokenizer->tokens(), "operator ( )")) - return; - createSymbolDatabase(); std::list::const_iterator i; @@ -872,8 +863,8 @@ void CheckClass::operatorEq() { if (it->type == Function::eOperatorEqual && it->access != Private) { - if (it->token->strAt(-2) == "void") - operatorEqReturnError(it->token->tokAt(-2)); + if (it->token->strAt(-1) == "void") + operatorEqReturnError(it->token->tokAt(-1)); } } } @@ -940,7 +931,7 @@ void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, co // check of *this is returned else if (!(Token::Match(tok->tokAt(1), "(| * this ;|=") || Token::Match(tok->tokAt(1), "(| * this +=") || - Token::Match(tok->tokAt(1), "operator = ("))) + Token::Match(tok->tokAt(1), "operator= ("))) operatorEqRetRefThisError(func->token); } } @@ -971,8 +962,8 @@ void CheckClass::operatorEqRetRefThis() if (func->type == Function::eOperatorEqual && func->hasBody) { // make sure return signature is correct - if (Token::Match(func->tokenDef->tokAt(-4), ";|}|{|public:|protected:|private: %type% &") && - func->tokenDef->strAt(-3) == scope->className) + if (Token::Match(func->tokenDef->tokAt(-3), ";|}|{|public:|protected:|private: %type% &") && + func->tokenDef->strAt(-2) == scope->className) { // find the ')' const Token *tok = func->token->next()->link(); @@ -1027,8 +1018,8 @@ void CheckClass::operatorEqToSelf() if (it->type == Function::eOperatorEqual && it->hasBody) { // make sure return signature is correct - if (Token::Match(it->tokenDef->tokAt(-4), ";|}|{|public:|protected:|private: %type% &") && - it->tokenDef->strAt(-3) == scope->className) + if (Token::Match(it->tokenDef->tokAt(-3), ";|}|{|public:|protected:|private: %type% &") && + it->tokenDef->strAt(-2) == scope->className) { // check for proper function parameter signature if ((Token::Match(it->tokenDef->next(), "( const %var% & )") || diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 08c8d5486..8b7947387 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -137,12 +137,12 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti function.tokenDef = funcStart; // operator function - if (function.tokenDef->previous()->str() == "operator") + if (function.tokenDef->str().find("operator") == 0) { function.isOperator = true; // 'operator =' is special - if (function.tokenDef->str() == "=") + if (function.tokenDef->str() == "operator=") function.type = Function::eOperatorEqual; } @@ -578,38 +578,6 @@ bool SymbolDatabase::isFunction(const Token *tok, const Token **funcStart, const return true; } - // simple operator? - else if (Token::Match(tok, "operator %any% (") && Token::Match(tok->tokAt(2)->link(), ") const| ;|{|=")) - { - *funcStart = tok->next(); - *argStart = tok->tokAt(2); - return true; - } - - // operator[] or operator()? - else if (Token::Match(tok, "operator %any% %any% (") && Token::Match(tok->tokAt(3)->link(), ") const| ;|{|=")) - { - *funcStart = tok->next(); - *argStart = tok->tokAt(3); - return true; - } - - // operator new/delete []? - else if (Token::Match(tok, "operator %any% %any% %any% (") && Token::Match(tok->tokAt(4)->link(), ") const| ;|{|=")) - { - *funcStart = tok->next(); - *argStart = tok->tokAt(4); - return true; - } - - // complex user defined operator? - else if (Token::Match(tok, "operator %any% %any% %any% %any% (") && Token::Match(tok->tokAt(5)->link(), ") const| ;|{|=")) - { - *funcStart = tok->next(); - *argStart = tok->tokAt(5); - return true; - } - return false; } @@ -772,20 +740,9 @@ void SymbolDatabase::addFunction(Scope **scope, const Token **tok, const Token * { if (!func->hasBody) { - if (func->isOperator && - (*tok)->str() == "operator" && - func->tokenDef->str() == (*tok)->strAt(1)) - { - if (argsMatch(scope1, func->tokenDef->tokAt(2), (*tok)->tokAt(3), path, path_length)) - { - func->hasBody = true; - func->token = (*tok)->next(); - func->arg = argStart; - } - } - else if (func->type == Function::eDestructor && - (*tok)->previous()->str() == "~" && - func->tokenDef->str() == (*tok)->str()) + if (func->type == Function::eDestructor && + (*tok)->previous()->str() == "~" && + func->tokenDef->str() == (*tok)->str()) { if (argsMatch(scope1, func->tokenDef->next(), (*tok)->next(), path, path_length)) { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index ee640937a..d21484c52 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -513,7 +513,7 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name) } else if (end->str() == "(") { - if (tok->previous()->str() == "operator") + if (tok->previous()->str().find("operator") == 0) { // conversion operator return false; @@ -2490,6 +2490,10 @@ bool Tokenizer::tokenize(std::istream &code, // remove exception specifications.. removeExceptionSpecifications(_tokens); + // Collapse operator name tokens into single token + // operator = => operator= + simplifyOperatorName(); + // simplify function pointers simplifyFunctionPointers(); @@ -9238,3 +9242,30 @@ const SymbolDatabase *Tokenizer::getSymbolDatabase() const return _symbolDatabase; } + +void Tokenizer::simplifyOperatorName() +{ + for (const Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, ") const| {|;|=")) + { + Token *tok1 = tok->link(); + Token *tok2 = tok1; + + tok1 = tok1->previous(); + while (tok1 && !Token::Match(tok1, "operator|{|}|;|public:|private|protected:")) + { + tok1 = tok1->previous(); + } + + if (tok1 && tok1->str() == "operator") + { + while (tok1->next() != tok2) + { + tok1->str(tok1->str() + tok1->next()->str()); + tok1->deleteNext(); + } + } + } + } +} diff --git a/lib/tokenize.h b/lib/tokenize.h index 318bdf4c4..8dacc345a 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -531,6 +531,12 @@ public: */ void simplifyQtSignalsSlots(); + /** + * Collapse operator name tokens into single token + * operator = => operator= + */ + void simplifyOperatorName(); + /** * This will return a short name describing function parameters * e.g. parameters: (int a, char b) should get name "int,char,". diff --git a/test/testclass.cpp b/test/testclass.cpp index 431c7252e..44ffed8a3 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -3506,7 +3506,7 @@ private: " typedef int* (Fred::*UnspecifiedBoolType);\n" " operator UnspecifiedBoolType() { };\n" "};\n"); - ASSERT_EQUALS("[test.cpp:4]: (information) Technically the member function 'Fred::int' can be const.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (information) Technically the member function 'Fred::operatorint**' can be const.\n", errout.str()); checkConst("struct Fred {\n" " int array[10];\n" diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index a0a29cbd6..78dc5be51 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -77,6 +77,12 @@ private: TEST_CASE(templatesGcc); TEST_CASE(templatesVs); TEST_CASE(xml); + TEST_CASE(xmlver2); + TEST_CASE(xmlver2both); + TEST_CASE(xmlver2both2); + TEST_CASE(errorlist1); + TEST_CASE(errorlistverbose1) + TEST_CASE(errorlistverbose2) TEST_CASE(unknownParam); } @@ -533,6 +539,69 @@ private: CmdLineParser parser(&settings); ASSERT(parser.ParseFromArgs(3, argv)); ASSERT(settings._xml); + ASSERT_EQUALS(1, settings._xml_version); + } + + void xmlver2() + { + REDIRECT; + const char *argv[] = {"cppcheck", "--xml-version=2", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(3, argv)); + ASSERT(settings._xml); + ASSERT_EQUALS(2, settings._xml_version); + } + + void xmlver2both() + { + REDIRECT; + const char *argv[] = {"cppcheck", "--xml", "--xml-version=2", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(4, argv)); + ASSERT(settings._xml); + ASSERT_EQUALS(2, settings._xml_version); + } + + void xmlver2both2() + { + REDIRECT; + const char *argv[] = {"cppcheck", "--xml-version=2", "--xml", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(4, argv)); + ASSERT(settings._xml); + ASSERT_EQUALS(2, settings._xml_version); + } + + void errorlist1() + { + REDIRECT; + const char *argv[] = {"cppcheck", "--errorlist"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(2, argv)); + } + + void errorlistverbose1() + { + REDIRECT; + const char *argv[] = {"cppcheck", "--verbose", "--errorlist"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(3, argv)); + ASSERT(settings._verbose); + } + + void errorlistverbose2() + { + REDIRECT; + const char *argv[] = {"cppcheck", "--errorlist", "--verbose"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(3, argv)); + ASSERT(settings._verbose); } void unknownParam() diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index e0633b261..e7928ae12 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -383,8 +383,8 @@ private: ASSERT_EQUALS("if ( * a )", tok("if ((char)*a)")); ASSERT_EQUALS("if ( & a )", tok("if ((int)&a)")); ASSERT_EQUALS("if ( * a )", tok("if ((unsigned int)(unsigned char)*a)")); - ASSERT_EQUALS("class A { A operator * ( int ) ; } ;", tok("class A { A operator *(int); };")); - ASSERT_EQUALS("class A { A operator * ( int ) const ; } ;", tok("class A { A operator *(int) const; };")); + ASSERT_EQUALS("class A { A operator* ( int ) ; } ;", tok("class A { A operator *(int); };")); + ASSERT_EQUALS("class A { A operator* ( int ) const ; } ;", tok("class A { A operator *(int) const; };")); ASSERT_EQUALS("if ( ! p )", tok("if (p == (char *)(char *)0)")); } @@ -2611,7 +2611,7 @@ private: { // Ticket #1997 const char code[] = "void * operator new[](size_t);"; - ASSERT_EQUALS("void * operator new [ ] ( size_t ) ;", tok(code)); + ASSERT_EQUALS("void * operatornew[] ( size_t ) ;", tok(code)); } ASSERT_EQUALS("; a [ 0 ] ;", tok(";a[0*(*p)];")); @@ -4462,7 +4462,7 @@ private: const std::string expected("struct C { " "; " "const void * pr ; " // this gets simplified to a regular pointer - "operator const void ( * ) ( ) & ( ) { return pr ; } " + "operatorconstvoid(*)()& ( ) { return pr ; } " "} ;"); ASSERT_EQUALS(expected, sizeof_(code)); @@ -4746,7 +4746,7 @@ private: "};\n"; const std::string expected = "class Fred { " "; " - "operator int * * ( ) const { } " + "operatorint** ( ) const { } " "} ;"; ASSERT_EQUALS(expected, sizeof_(code)); ASSERT_EQUALS("", errout.str()); @@ -4788,9 +4788,9 @@ private: "Fred::operator F() const { }\n"; const std::string expected = "class Fred { " "; " - "operator int * * ( ) const ; " + "operatorint** ( ) const ; " "} ; " - "Fred :: operator int * * ( ) const { }"; + "Fred :: operatorint** ( ) const { }"; ASSERT_EQUALS(expected, sizeof_(code)); ASSERT_EQUALS("", errout.str()); } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index dfa87d3bb..561b91a95 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -293,6 +293,8 @@ private: // Tokenize JAVA TEST_CASE(java); + + TEST_CASE(simplifyOperatorName); } @@ -2990,7 +2992,7 @@ private: "1: class Foo\n" "2: {\n" "3: public:\n" - "4: void operator = ( const Foo & ) ;\n" + "4: void operator= ( const Foo & ) ;\n" "5: } ;\n"); ASSERT_EQUALS(expected, actual); @@ -3002,7 +3004,7 @@ private: "};\n"); const std::string expected("\n\n##file 0\n" "1: struct Foo {\n" - "2: void * operator new [ ] ( int ) ;\n" + "2: void * operatornew[] ( int ) ;\n" "3: } ;\n"); ASSERT_EQUALS(expected, actual); @@ -3660,7 +3662,7 @@ private: const std::string actual(tokenizeAndStringify(code)); const char expected[] = "struct foo {\n" - "void operator delete ( void * obj , size_t sz ) ;\n" + "void operatordelete ( void * obj , size_t sz ) ;\n" "}"; ASSERT_EQUALS(expected, actual); @@ -5182,6 +5184,38 @@ private: { ASSERT_EQUALS("void f ( ) { }", javatest("void f() throws Exception { }")); } + + void simplifyOperatorName() + { + // make sure C code doesn't get changed + const char code1[] = "void operator () {}" + "int main()" + "{" + " operator();" + "}"; + + const char result1 [] = "void operator ( ) { } " + "int main ( ) " + "{ " + "operator ( ) ; " + "}"; + + ASSERT_EQUALS(result1, tokenizeAndStringify(code1,false)); + + const char code2[] = "class Fred" + "{" + " Fred(const Fred & f) { operator = (f); }" + " operator = ();" + "}"; + + const char result2 [] = "class Fred " + "{ " + "Fred ( const Fred & f ) { operator= ( f ) ; } " + "operator= ( ) ; " + "}"; + + ASSERT_EQUALS(result2, tokenizeAndStringify(code2,false)); + } }; REGISTER_TEST(TestTokenizer) diff --git a/test/testunusedprivfunc.cpp b/test/testunusedprivfunc.cpp index ff6f84c60..adbbf2b20 100644 --- a/test/testunusedprivfunc.cpp +++ b/test/testunusedprivfunc.cpp @@ -460,8 +460,7 @@ private: " void startListening() {\n" " }\n" "};\n"); - TODO_ASSERT_EQUALS("[test.cpp:8]: (style) Unused private function 'Fred::startListening'\n", errout.str()); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:8]: (style) Unused private function 'Fred::startListening'\n", errout.str()); } void testDoesNotIdentifyMethodAsFirstFunctionArgument()