From f3b2acf585b609795e203f85a6bb074be1f60b47 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Thu, 3 Mar 2011 20:32:10 -0500 Subject: [PATCH 01/54] really fix #2620 reference of typedef of array not simplified properly --- lib/tokenize.cpp | 11 +++++++++++ test/testsimplifytokens.cpp | 13 +++++++++++++ 2 files changed, 24 insertions(+) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index cd1baa565..76374f498 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1791,6 +1791,17 @@ void Tokenizer::simplifyTypedef() if (!inCast && !inSizeof) tok2 = tok2->next(); + // reference to array? + if (tok2->str() == "&") + { + tok2 = tok2->previous(); + tok2->insertToken("("); + tok2 = tok2->tokAt(3); + tok2->insertToken(")"); + tok2 = tok2->next(); + Token::createMutualLinks(tok2, tok2->tokAt(-3)); + } + tok2 = copyTokens(tok2, arrayStart, arrayEnd); tok2 = tok2->next(); diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index a546b3654..e1a17d748 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -243,6 +243,7 @@ private: TEST_CASE(simplifyTypedef80); // ticket #2587 TEST_CASE(simplifyTypedef81); // ticket #2603 TEST_CASE(simplifyTypedef82); // ticket #2403 + TEST_CASE(simplifyTypedef83); // ticket #2620 TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -4961,6 +4962,18 @@ private: ASSERT_EQUALS("", errout.str()); } + void simplifyTypedef83() // ticket #2620 + { + const char code[] = "typedef char Str[10];\n" + "void f(Str &cl) { }\n"; + + // The expected result.. + const std::string expected("; " + "void f ( char ( & cl ) [ 10 ] ) { }"); + + ASSERT_EQUALS(expected, sizeof_(code)); + } + void simplifyTypedefFunction1() { { From 93ea774484498d4fd2b00634873ec1f190438d83 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sat, 19 Feb 2011 21:33:29 +1300 Subject: [PATCH 02/54] initial simplistic implementation of switchCaseFallThrough --- lib/checkother.cpp | 46 +++++++++++++++++++ lib/checkother.h | 6 +++ lib/preprocessor.cpp | 7 ++- test/testother.cpp | 106 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 8588e3666..b7e3e6e19 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -306,6 +306,46 @@ void CheckOther::checkRedundantAssignmentInSwitch() } +void CheckOther::checkSwitchCaseFallThrough() +{ + const char switchPattern[] = "switch ( %any% ) { case"; + //const char breakPattern[] = "break|continue|return|exit|goto"; + //const char functionPattern[] = "%var% ("; + // nested switch + + // Find the beginning of a switch. E.g.: + // switch (var) { ... + const Token *tok = Token::findmatch(_tokenizer->tokens(), switchPattern); + while (tok) + { + + // Check the contents of the switch statement + for (const Token *tok2 = tok->tokAt(6); tok2; tok2 = tok2->next()) + { + if (Token::Match(tok2, switchPattern)) + { + tok2 = tok2->tokAt(4)->link()->previous(); + } + else if (tok2->str() == "case") + { + if (!Token::Match(tok2->previous()->previous(), "break")) + { + switchCaseFallThrough(tok2); + } + } + else if (tok2->str() == "}") + { + // End of the switch block + break; + } + + } + + tok = Token::findmatch(tok->next(), switchPattern); + } +} + + //--------------------------------------------------------------------------- // int x = 1; // x = x; // <- redundant assignment to self @@ -2998,6 +3038,12 @@ void CheckOther::redundantAssignmentInSwitchError(const Token *tok, const std::s "redundantAssignInSwitch", "Redundant assignment of \"" + varname + "\" in switch"); } +void CheckOther::switchCaseFallThrough(const Token *tok) +{ + reportError(tok, Severity::warning, + "switchCaseFallThrough", "Switch falls through case without comment"); +} + void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname) { reportError(tok, Severity::warning, diff --git a/lib/checkother.h b/lib/checkother.h index d43c4c413..63c7ebed7 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -61,6 +61,7 @@ public: checkOther.sizeofsizeof(); checkOther.sizeofCalculation(); checkOther.checkRedundantAssignmentInSwitch(); + checkOther.checkSwitchCaseFallThrough(); checkOther.checkAssignmentInAssert(); checkOther.checkSizeofForArrayParameter(); checkOther.checkSelfAssignment(); @@ -162,6 +163,9 @@ public: /** @brief %Check for assigning to the same variable twice in a switch statement*/ void checkRedundantAssignmentInSwitch(); + /** @brief %Check for switch case fall through without comment */ + void checkSwitchCaseFallThrough(); + /** @brief %Check for assigning a variable to itself*/ void checkSelfAssignment(); @@ -209,6 +213,7 @@ public: void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1); void fflushOnInputStreamError(const Token *tok, const std::string &varname); void redundantAssignmentInSwitchError(const Token *tok, const std::string &varname); + void switchCaseFallThrough(const Token *tok); void selfAssignmentError(const Token *tok, const std::string &varname); void assignmentInAssertError(const Token *tok, const std::string &varname); void incorrectLogicOperatorError(const Token *tok); @@ -247,6 +252,7 @@ public: c.sizeofsizeofError(0); c.sizeofCalculationError(0); c.redundantAssignmentInSwitchError(0, "varname"); + c.switchCaseFallThrough(0); c.selfAssignmentError(0, "varname"); c.assignmentInAssertError(0, "varname"); c.invalidScanfError(0); diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 45ed8a425..9f4bb0384 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -377,10 +377,10 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri i = str.find('\n', i); if (i == std::string::npos) break; + std::string comment(str, commentStart, i - commentStart); if (settings && settings->_inlineSuppressions) { - std::string comment(str, commentStart, i - commentStart); std::istringstream iss(comment); std::string word; iss >> word; @@ -392,6 +392,11 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } } + if (comment.find("fall through") != std::string::npos) + { + suppressionIDs.push_back("switchCaseFallThrough"); + } + code << "\n"; previous = '\n'; ++lineno; diff --git a/test/testother.cpp b/test/testother.cpp index 5707fc264..43d07ee8b 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include "preprocessor.h" #include "tokenize.h" #include "checkother.h" #include "testsuite.h" @@ -74,6 +75,7 @@ private: TEST_CASE(sizeofCalculation); TEST_CASE(switchRedundantAssignmentTest); + TEST_CASE(switchFallThroughCase); TEST_CASE(selfAssignment); TEST_CASE(testScanf1); @@ -148,6 +150,60 @@ private: checkOther.checkComparisonOfBoolWithInt(); } + class SimpleSuppressor: public ErrorLogger + { + public: + SimpleSuppressor(Settings &settings, ErrorLogger *next) + : _settings(settings), _next(next) + { } + virtual void reportOut(const std::string &outmsg) + { + _next->reportOut(outmsg); + } + virtual void reportErr(const ErrorLogger::ErrorMessage &msg) + { + if (!msg._callStack.empty() && !_settings.nomsg.isSuppressed(msg._id, msg._callStack.begin()->getfile(), msg._callStack.begin()->line)) + _next->reportErr(msg); + } + virtual void reportStatus(unsigned int index, unsigned int max) + { + _next->reportStatus(index, max); + } + private: + Settings &_settings; + ErrorLogger *_next; + }; + + void check_preprocess_suppress(const char precode[], const char *filename = NULL) + { + // Clear the error buffer.. + errout.str(""); + + if (filename == NULL) + filename = "test.cpp"; + + Settings settings; + settings._checkCodingStyle = true; + + // Preprocess file.. + Preprocessor preprocessor(&settings, this); + std::list configurations; + std::string filedata = ""; + std::istringstream fin(precode); + preprocessor.preprocess(fin, filedata, configurations, filename, settings._includePaths); + SimpleSuppressor logger(settings, this); + const std::string code = Preprocessor::getcode(filedata, "", filename, &settings, &logger); + + // Tokenize.. + Tokenizer tokenizer(&settings, &logger); + std::istringstream istr(code); + tokenizer.tokenize(istr, filename); + + // Check.. + CheckOther checkOther(&tokenizer, &settings, &logger); + checkOther.checkSwitchCaseFallThrough(); + } + void zeroDiv1() { @@ -1146,6 +1202,56 @@ private: ASSERT_EQUALS("", errout.str()); } + void switchFallThroughCase() + { + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " break;\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " g();\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " g();\n" + " // fall through\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " g();\n" + " break;\n" + " // fall through\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + void selfAssignment() { check("void foo()\n" From a532a9690e4bf9dd8bba42c23d856fb3b96c369b Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 20 Feb 2011 08:02:28 +1300 Subject: [PATCH 03/54] full implementation of switch case fall through --- lib/checkother.cpp | 97 +++++++++++++++++++++++++++++++----- lib/checkother.h | 2 +- test/testother.cpp | 121 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+), 12 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index b7e3e6e19..02688ce81 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -24,6 +24,7 @@ #include // std::isupper #include // fabs() +#include //--------------------------------------------------------------------------- // Register this check class (by creating a static instance of it) @@ -308,10 +309,8 @@ void CheckOther::checkRedundantAssignmentInSwitch() void CheckOther::checkSwitchCaseFallThrough() { - const char switchPattern[] = "switch ( %any% ) { case"; - //const char breakPattern[] = "break|continue|return|exit|goto"; - //const char functionPattern[] = "%var% ("; - // nested switch + const char switchPattern[] = "switch ("; + const char breakPattern[] = "break|continue|return|exit|goto"; // Find the beginning of a switch. E.g.: // switch (var) { ... @@ -320,23 +319,99 @@ void CheckOther::checkSwitchCaseFallThrough() { // Check the contents of the switch statement - for (const Token *tok2 = tok->tokAt(6); tok2; tok2 = tok2->next()) + std::stack > ifnest; + std::stack loopnest; + std::stack scopenest; + bool justbreak = true; + for (const Token *tok2 = tok->tokAt(1)->link()->tokAt(2); tok2; tok2 = tok2->next()) { - if (Token::Match(tok2, switchPattern)) + if (Token::Match(tok2, "if (")) { - tok2 = tok2->tokAt(4)->link()->previous(); + tok2 = tok2->tokAt(1)->link()->next(); + ifnest.push(std::make_pair(tok2->link(), false)); + justbreak = false; } - else if (tok2->str() == "case") + else if (Token::Match(tok2, "while (")) { - if (!Token::Match(tok2->previous()->previous(), "break")) + tok2 = tok2->tokAt(1)->link()->next(); + loopnest.push(tok2->link()); + justbreak = false; + } + else if (Token::Match(tok2, "do {")) + { + tok2 = tok2->tokAt(1); + loopnest.push(tok2->link()); + justbreak = false; + } + else if (Token::Match(tok2, "for (")) + { + tok2 = tok2->tokAt(1)->link()->next(); + loopnest.push(tok2->link()); + justbreak = false; + } + else if (Token::Match(tok2, switchPattern)) + { + // skip over nested switch, we'll come to that soon + tok2 = tok2->tokAt(1)->link()->next()->link(); + } + else if (Token::Match(tok2, breakPattern)) + { + if (loopnest.empty()) + { + justbreak = true; + } + tok2 = Token::findmatch(tok2, ";"); + } + else if (Token::Match(tok2, "case|default")) + { + if (!justbreak) { switchCaseFallThrough(tok2); } + tok2 = Token::findmatch(tok2, ":"); + justbreak = true; + } + else if (tok2->str() == "{") + { + scopenest.push(tok2->link()); } else if (tok2->str() == "}") { - // End of the switch block - break; + if (!ifnest.empty() && tok2 == ifnest.top().first) + { + if (tok2->next()->str() == "else") + { + tok2 = tok2->tokAt(2); + ifnest.pop(); + ifnest.push(std::make_pair(tok2->link(), justbreak)); + justbreak = false; + } + else + { + justbreak &= ifnest.top().second; + ifnest.pop(); + } + } + else if (!loopnest.empty() && tok2 == loopnest.top()) + { + loopnest.pop(); + } + else if (!scopenest.empty() && tok2 == scopenest.top()) + { + scopenest.pop(); + } + else + { + assert(ifnest.empty()); + assert(loopnest.empty()); + assert(scopenest.empty()); + // end of switch block + break; + } + } + else if (tok2->str() != ";") + { + justbreak = false; } } diff --git a/lib/checkother.h b/lib/checkother.h index 63c7ebed7..80605333b 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -61,7 +61,6 @@ public: checkOther.sizeofsizeof(); checkOther.sizeofCalculation(); checkOther.checkRedundantAssignmentInSwitch(); - checkOther.checkSwitchCaseFallThrough(); checkOther.checkAssignmentInAssert(); checkOther.checkSizeofForArrayParameter(); checkOther.checkSelfAssignment(); @@ -91,6 +90,7 @@ public: checkOther.checkIncorrectStringCompare(); checkOther.checkIncrementBoolean(); checkOther.checkComparisonOfBoolWithInt(); + checkOther.checkSwitchCaseFallThrough(); } /** @brief Clarify calculation for ".. a * b ? .." */ diff --git a/test/testother.cpp b/test/testother.cpp index 43d07ee8b..c699b78fd 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -202,6 +202,8 @@ private: // Check.. CheckOther checkOther(&tokenizer, &settings, &logger); checkOther.checkSwitchCaseFallThrough(); + + logger.reportUnmatchedSuppressions(settings.nomsg.getUnmatchedLocalSuppressions(filename)); } @@ -1215,6 +1217,18 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 0:\n" + " case 1:\n" + " break;\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + check_preprocess_suppress( "void foo() {\n" " switch (a) {\n" @@ -1226,6 +1240,17 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str()); + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " g();\n" + " default:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str()); + check_preprocess_suppress( "void foo() {\n" " switch (a) {\n" @@ -1249,7 +1274,103 @@ private: " break;\n" " }\n" "}\n"); + ASSERT_EQUALS("[test.cpp:7]: (information) Unmatched suppression: switchCaseFallThrough\n", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " {\n" + " break;\n" + " }\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); ASSERT_EQUALS("", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " for (;;) {\n" + " break;\n" + " }\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7]: (warning) Switch falls through case without comment\n", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " if (b) {\n" + " break;\n" + " } else {\n" + " break;\n" + " }\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " if (b) {\n" + " break;\n" + " } else {\n" + " }\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:8]: (warning) Switch falls through case without comment\n", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " if (b) {\n" + " break;\n" + " }\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7]: (warning) Switch falls through case without comment\n", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " if (b) {\n" + " } else {\n" + " break;\n" + " }\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:8]: (warning) Switch falls through case without comment\n", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " if (b) {\n" + " case 2:\n" + " } else {\n" + " break;\n" + " }\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str()); } void selfAssignment() From ad457378050ef908d09cd4fc312244723b41c0c2 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 20 Feb 2011 09:43:24 +1300 Subject: [PATCH 04/54] more gracefully handle unexpected blocks inside switch --- lib/checkother.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 02688ce81..e3135dd71 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -328,24 +328,56 @@ void CheckOther::checkSwitchCaseFallThrough() if (Token::Match(tok2, "if (")) { tok2 = tok2->tokAt(1)->link()->next(); + if (tok2->link() == NULL) + { + std::ostringstream errmsg; + errmsg << "unmatched if in switch: " << tok2->linenr(); + reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); + break; + } ifnest.push(std::make_pair(tok2->link(), false)); justbreak = false; } else if (Token::Match(tok2, "while (")) { tok2 = tok2->tokAt(1)->link()->next(); - loopnest.push(tok2->link()); + // skip over "do { } while ( ) ;" case + if (tok2->str() == "{") + { + if (tok2->link() == NULL) + { + std::ostringstream errmsg; + errmsg << "unmatched while in switch: " << tok2->linenr(); + reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); + break; + } + loopnest.push(tok2->link()); + } justbreak = false; } else if (Token::Match(tok2, "do {")) { tok2 = tok2->tokAt(1); + if (tok2->link() == NULL) + { + std::ostringstream errmsg; + errmsg << "unmatched do in switch: " << tok2->linenr(); + reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); + break; + } loopnest.push(tok2->link()); justbreak = false; } else if (Token::Match(tok2, "for (")) { tok2 = tok2->tokAt(1)->link()->next(); + if (tok2->link() == NULL) + { + std::ostringstream errmsg; + errmsg << "unmatched for in switch: " << tok2->linenr(); + reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); + break; + } loopnest.push(tok2->link()); justbreak = false; } @@ -402,9 +434,21 @@ void CheckOther::checkSwitchCaseFallThrough() } else { - assert(ifnest.empty()); - assert(loopnest.empty()); - assert(scopenest.empty()); + if (!ifnest.empty() || !loopnest.empty() || !scopenest.empty()) + { + std::ostringstream errmsg; + errmsg << "unexpected end of switch: "; + errmsg << "ifnest=" << ifnest.size(); + if (!ifnest.empty()) + errmsg << "," << ifnest.top().first->linenr(); + errmsg << ", loopnest=" << loopnest.size(); + if (!loopnest.empty()) + errmsg << "," << loopnest.top()->linenr(); + errmsg << ", scopenest=" << scopenest.size(); + if (!scopenest.empty()) + errmsg << "," << scopenest.top()->linenr(); + reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); + } // end of switch block break; } From 610d2efaeac12586916cd9c0aec1acd05d7f6e64 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 20 Feb 2011 09:54:01 +1300 Subject: [PATCH 05/54] recognise fall through in c style comments --- lib/preprocessor.cpp | 11 +++++++++-- test/testother.cpp | 12 ++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 9f4bb0384..c9d125d83 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -392,7 +392,8 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } } - if (comment.find("fall through") != std::string::npos) + std::transform(comment.begin(), comment.end(), comment.begin(), ::tolower); + if (comment.find("fall") != std::string::npos && comment.find("thr") != std::string::npos) { suppressionIDs.push_back("switchCaseFallThrough"); } @@ -417,10 +418,16 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri ++lineno; } } + std::string comment(str, commentStart, i - commentStart); + + std::transform(comment.begin(), comment.end(), comment.begin(), ::tolower); + if (comment.find("fall") != std::string::npos && comment.find("thr") != std::string::npos) + { + suppressionIDs.push_back("switchCaseFallThrough"); + } if (settings && settings->_inlineSuppressions) { - std::string comment(str, commentStart, i - commentStart); std::istringstream iss(comment); std::string word; iss >> word; diff --git a/test/testother.cpp b/test/testother.cpp index c699b78fd..b65bd7663 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1263,6 +1263,18 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " g();\n" + " /* FALLTHRU */\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + check_preprocess_suppress( "void foo() {\n" " switch (a) {\n" From 8c1d7ef3161806294181c530c889f4d0f5d61b0a Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 20 Feb 2011 23:44:18 +1300 Subject: [PATCH 06/54] avoid crash when else condition doesn't have braces to link --- lib/checkother.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index e3135dd71..93480de5e 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -415,6 +415,13 @@ void CheckOther::checkSwitchCaseFallThrough() { tok2 = tok2->tokAt(2); ifnest.pop(); + if (tok2->link() == NULL) + { + std::ostringstream errmsg; + errmsg << "unmatched if in switch: " << tok2->linenr(); + reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); + break; + } ifnest.push(std::make_pair(tok2->link(), justbreak)); justbreak = false; } From 1a606a57fd0deeb768fe5fa87f44b33a49a8e898 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 20 Feb 2011 23:56:52 +1300 Subject: [PATCH 07/54] slightly more flexible detection of 'fall through' comment --- lib/preprocessor.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index c9d125d83..2e8cd86c5 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -303,6 +303,18 @@ static bool hasbom(const std::string &str) } +static bool isFallThroughComment(std::string comment) +{ + // convert comment to lower case without whitespace + std::transform(comment.begin(), comment.end(), comment.begin(), ::tolower); + comment.erase(std::remove_if(comment.begin(), comment.end(), ::isspace), comment.end()); + + return comment.find("fallthr") != std::string::npos || + comment.find("dropthr") != std::string::npos || + comment.find("passthr") != std::string::npos || + comment.find("nobreak") != std::string::npos; +} + std::string Preprocessor::removeComments(const std::string &str, const std::string &filename, Settings *settings) { // For the error report @@ -392,8 +404,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } } - std::transform(comment.begin(), comment.end(), comment.begin(), ::tolower); - if (comment.find("fall") != std::string::npos && comment.find("thr") != std::string::npos) + if (isFallThroughComment(comment)) { suppressionIDs.push_back("switchCaseFallThrough"); } @@ -420,8 +431,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } std::string comment(str, commentStart, i - commentStart); - std::transform(comment.begin(), comment.end(), comment.begin(), ::tolower); - if (comment.find("fall") != std::string::npos && comment.find("thr") != std::string::npos) + if (isFallThroughComment(comment)) { suppressionIDs.push_back("switchCaseFallThrough"); } From 70fcbe94f49d81438d5ab7276e8e4e6726d11db9 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Wed, 23 Feb 2011 22:45:21 +1300 Subject: [PATCH 08/54] avoid warning on first case (in case there are declarations before first case) --- lib/checkother.cpp | 4 +++- test/testother.cpp | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 93480de5e..8324808c5 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -323,6 +323,7 @@ void CheckOther::checkSwitchCaseFallThrough() std::stack loopnest; std::stack scopenest; bool justbreak = true; + bool firstcase = true; for (const Token *tok2 = tok->tokAt(1)->link()->tokAt(2); tok2; tok2 = tok2->next()) { if (Token::Match(tok2, "if (")) @@ -396,12 +397,13 @@ void CheckOther::checkSwitchCaseFallThrough() } else if (Token::Match(tok2, "case|default")) { - if (!justbreak) + if (!justbreak && !firstcase) { switchCaseFallThrough(tok2); } tok2 = Token::findmatch(tok2, ":"); justbreak = true; + firstcase = false; } else if (tok2->str() == "{") { diff --git a/test/testother.cpp b/test/testother.cpp index b65bd7663..e939f0d61 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1383,6 +1383,16 @@ private: " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " int x;\n" + " case 1:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void selfAssignment() From 8e839a46e8f5d55eb287b26027e45ef6c21a6f08 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Fri, 4 Mar 2011 19:22:17 +1300 Subject: [PATCH 09/54] add TODO for pathological case --- test/testother.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/testother.cpp b/test/testother.cpp index e939f0d61..a95d8f391 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1393,6 +1393,27 @@ private: " }\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " g();\n" + " switch (b) {\n" + " case 1:\n" + " return;\n" + " default:\n" + " return;\n" + " }\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + // This fails because the switch parsing code currently doesn't understand + // that all paths after g() actually return. It's a pretty unusual case + // (no pun intended). + TODO_ASSERT_EQUALS("", + "[test.cpp:11]: (warning) Switch falls through case without comment\n", errout.str()); } void selfAssignment() From cc7e05a5b0ff92021f49331e6e50ed98e12c0883 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Fri, 4 Mar 2011 19:26:48 +1300 Subject: [PATCH 10/54] fix case where fall through comment precedes preprocessor line --- lib/preprocessor.cpp | 33 +++++++++++++++++++++++---------- test/testother.cpp | 14 ++++++++++++++ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 2e8cd86c5..d93ddd6ab 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -326,6 +326,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri unsigned int newlines = 0; std::ostringstream code; unsigned char previous = 0; + bool inPreprocessorLine = false; std::vector suppressionIDs; for (std::string::size_type i = hasbom(str) ? 3U : 0U; i < str.length(); ++i) @@ -370,6 +371,8 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri // if there has been sequences, add extra newlines.. if (ch == '\n') { + if (previous != '\\') + inPreprocessorLine = false; ++lineno; if (newlines > 0) { @@ -449,25 +452,35 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } } } + else if (ch == '#' && previous == '\n') + { + code << ch; + previous = ch; + inPreprocessorLine = true; + } else { - // Not whitespace and not a comment. Must be code here! - // Add any pending inline suppressions that have accumulated. - if (!suppressionIDs.empty()) + if (!inPreprocessorLine) { - if (settings != NULL) + // Not whitespace, not a comment, and not preprocessor. + // Must be code here! + // Add any pending inline suppressions that have accumulated. + if (!suppressionIDs.empty()) { - // Add the suppressions. - for (size_t j(0); j < suppressionIDs.size(); ++j) + if (settings != NULL) { - const std::string errmsg(settings->nomsg.addSuppression(suppressionIDs[j], filename, lineno)); - if (!errmsg.empty()) + // Add the suppressions. + for (size_t j(0); j < suppressionIDs.size(); ++j) { - writeError(filename, lineno, _errorLogger, "cppcheckError", errmsg); + const std::string errmsg(settings->nomsg.addSuppression(suppressionIDs[j], filename, lineno)); + if (!errmsg.empty()) + { + writeError(filename, lineno, _errorLogger, "cppcheckError", errmsg); + } } } + suppressionIDs.clear(); } - suppressionIDs.clear(); } // String or char constants.. diff --git a/test/testother.cpp b/test/testother.cpp index a95d8f391..16aa5afc1 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1414,6 +1414,20 @@ private: // (no pun intended). TODO_ASSERT_EQUALS("", "[test.cpp:11]: (warning) Switch falls through case without comment\n", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + "#ifndef A\n" + " g();\n" + " // fall through\n" + "#endif\n" + " case 2:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void selfAssignment() From c5f8a06a97df57a47a2061e48b55e6fa15f19641 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Fri, 4 Mar 2011 20:26:14 +1300 Subject: [PATCH 11/54] add TODO for case where simplifyGoto() does the wrong thing --- test/testother.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/testother.cpp b/test/testother.cpp index 16aa5afc1..7aab2c4da 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -198,6 +198,7 @@ private: Tokenizer tokenizer(&settings, &logger); std::istringstream istr(code); tokenizer.tokenize(istr, filename); + tokenizer.simplifyGoto(); // Check.. CheckOther checkOther(&tokenizer, &settings, &logger); @@ -1428,6 +1429,26 @@ private: " }\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " goto leave;\n" + " case 2:\n" + " break;\n" + " }\n" + "leave:\n" + " if (x) {\n" + " g();\n" + " return;\n" + " }\n" + "}\n"); + // This fails because Tokenizer::simplifyGoto() copies the "leave:" block + // into where the goto is, but because it contains a "return", it omits + // copying a final return after the block. + TODO_ASSERT_EQUALS("", + "[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str()); } void selfAssignment() From 957bb5c0f25222d4d56362cb35c5aa43f0110ad1 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sat, 5 Mar 2011 11:27:29 +1300 Subject: [PATCH 12/54] Normalise threading support checking into a single #define --- cli/threadexecutor.cpp | 8 ++++---- cli/threadexecutor.h | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cli/threadexecutor.cpp b/cli/threadexecutor.cpp index 7c33d2adb..bce5fd1d0 100644 --- a/cli/threadexecutor.cpp +++ b/cli/threadexecutor.cpp @@ -20,7 +20,7 @@ #include "cppcheck.h" #include #include -#if (defined(__GNUC__) || defined(__sun)) && !defined(__MINGW32__) +#ifdef THREADING_MODEL_FORK #include #include #include @@ -34,7 +34,7 @@ ThreadExecutor::ThreadExecutor(const std::vector &filenames, Settings &settings, ErrorLogger &errorLogger) : _filenames(filenames), _settings(settings), _errorLogger(errorLogger), _fileCount(0) { -#if (defined(__GNUC__) || defined(__sun)) && !defined(__MINGW32__) +#ifdef THREADING_MODEL_FORK _pipe[0] = _pipe[1] = 0; #endif } @@ -50,10 +50,10 @@ void ThreadExecutor::addFileContent(const std::string &path, const std::string & } /////////////////////////////////////////////////////////////////////////////// -////// This code is for __GNUC__ and __sun only /////////////////////////////// +////// This code is for platforms that support fork() only //////////////////// /////////////////////////////////////////////////////////////////////////////// -#if (defined(__GNUC__) || defined(__sun)) && !defined(__MINGW32__) +#ifdef THREADING_MODEL_FORK int ThreadExecutor::handleRead(unsigned int &result) { diff --git a/cli/threadexecutor.h b/cli/threadexecutor.h index 309e110ee..78cb9a5fe 100644 --- a/cli/threadexecutor.h +++ b/cli/threadexecutor.h @@ -25,6 +25,10 @@ #include "settings.h" #include "errorlogger.h" +#if (defined(__GNUC__) || defined(__sun)) && !defined(__MINGW32__) +#define THREADING_MODEL_FORK +#endif + /// @addtogroup CLI /// @{ @@ -59,7 +63,7 @@ private: /** @brief Key is file name, and value is the content of the file */ std::map _fileContents; -#if (defined(__GNUC__) || defined(__sun)) && !defined(__MINGW32__) +#ifdef THREADING_MODEL_FORK private: /** * Read from the pipe, parse and handle what ever is in there. From 5bbf39d094efccadfd9a927c5f7052cde541e730 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sat, 5 Mar 2011 16:43:22 +1300 Subject: [PATCH 13/54] Refactor ThreadExecutor::check() to handle child failures more gracefully --- Makefile | 2 +- cli/threadexecutor.cpp | 127 ++++++++++++++++++++++++++++------------- cli/threadexecutor.h | 8 ++- 3 files changed, 93 insertions(+), 44 deletions(-) diff --git a/Makefile b/Makefile index ca835744d..c0e5675cc 100644 --- a/Makefile +++ b/Makefile @@ -330,7 +330,7 @@ test/teststl.o: test/teststl.cpp lib/tokenize.h lib/checkstl.h lib/check.h lib/t test/testsuite.o: test/testsuite.cpp test/testsuite.h lib/errorlogger.h lib/settings.h test/redirect.h test/options.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testsuite.o test/testsuite.cpp -test/testsuppressions.o: test/testsuppressions.cpp lib/cppcheck.h lib/settings.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h test/testsuite.h test/redirect.h +test/testsuppressions.o: test/testsuppressions.cpp lib/cppcheck.h lib/settings.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h cli/threadexecutor.h lib/token.h lib/tokenize.h test/testsuite.h test/redirect.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testsuppressions.o test/testsuppressions.cpp test/testsymboldatabase.o: test/testsymboldatabase.cpp test/testsuite.h lib/errorlogger.h lib/settings.h test/redirect.h test/testutils.h lib/tokenize.h lib/token.h lib/symboldatabase.h diff --git a/cli/threadexecutor.cpp b/cli/threadexecutor.cpp index bce5fd1d0..f9ae2459e 100644 --- a/cli/threadexecutor.cpp +++ b/cli/threadexecutor.cpp @@ -35,7 +35,7 @@ ThreadExecutor::ThreadExecutor(const std::vector &filenames, Settin : _filenames(filenames), _settings(settings), _errorLogger(errorLogger), _fileCount(0) { #ifdef THREADING_MODEL_FORK - _pipe[0] = _pipe[1] = 0; + _wpipe = 0; #endif } @@ -55,10 +55,10 @@ void ThreadExecutor::addFileContent(const std::string &path, const std::string & #ifdef THREADING_MODEL_FORK -int ThreadExecutor::handleRead(unsigned int &result) +int ThreadExecutor::handleRead(int rpipe, unsigned int &result) { char type = 0; - if (read(_pipe[0], &type, 1) <= 0) + if (read(rpipe, &type, 1) <= 0) { if (errno == EAGAIN) return 0; @@ -73,14 +73,14 @@ int ThreadExecutor::handleRead(unsigned int &result) } unsigned int len = 0; - if (read(_pipe[0], &len, sizeof(len)) <= 0) + if (read(rpipe, &len, sizeof(len)) <= 0) { std::cerr << "#### You found a bug from cppcheck.\nThreadExecutor::handleRead error, type was:" << type << std::endl; exit(0); } char *buf = new char[len]; - if (read(_pipe[0], buf, len) <= 0) + if (read(rpipe, buf, len) <= 0) { std::cerr << "#### You found a bug from cppcheck.\nThreadExecutor::handleRead error, type was:" << type << std::endl; exit(0); @@ -134,32 +134,35 @@ unsigned int ThreadExecutor::check() { _fileCount = 0; unsigned int result = 0; - if (pipe(_pipe) == -1) - { - perror("pipe"); - exit(1); - } - int flags = 0; - if ((flags = fcntl(_pipe[0], F_GETFL, 0)) < 0) - { - perror("fcntl"); - exit(1); - } - - if (fcntl(_pipe[0], F_SETFL, flags | O_NONBLOCK) < 0) - { - perror("fcntl"); - exit(1); - } - - unsigned int childCount = 0; + std::list rpipes; + std::map childFile; unsigned int i = 0; while (true) { // Start a new child - if (i < _filenames.size() && childCount < _settings._jobs) + if (i < _filenames.size() && rpipes.size() < _settings._jobs) { + int pipes[2]; + if (pipe(pipes) == -1) + { + perror("pipe"); + exit(1); + } + + int flags = 0; + if ((flags = fcntl(pipes[0], F_GETFL, 0)) < 0) + { + perror("fcntl"); + exit(1); + } + + if (fcntl(pipes[0], F_SETFL, flags | O_NONBLOCK) < 0) + { + perror("fcntl"); + exit(1); + } + pid_t pid = fork(); if (pid < 0) { @@ -169,6 +172,9 @@ unsigned int ThreadExecutor::check() } else if (pid == 0) { + close(pipes[0]); + _wpipe = pipes[1]; + CppCheck fileChecker(*this, false); fileChecker.settings(_settings); @@ -190,31 +196,70 @@ unsigned int ThreadExecutor::check() exit(0); } - ++childCount; + close(pipes[1]); + rpipes.push_back(pipes[0]); + childFile[pid] = _filenames[i]; + ++i; } - else if (childCount > 0) + else if (!rpipes.empty()) { - // Wait for child to quit before stating new processes - while (true) + fd_set rfds; + FD_ZERO(&rfds); + for (std::list::const_iterator rp = rpipes.begin(); rp != rpipes.end(); ++rp) + FD_SET(*rp, &rfds); + + int r = select(*std::max_element(rpipes.begin(), rpipes.end()) + 1, &rfds, NULL, NULL, NULL); + + if (r > 0) { - int readRes = handleRead(result); - if (readRes == -1) - break; - else if (readRes == 0) + std::list::iterator rp = rpipes.begin(); + while (rp != rpipes.end()) { - struct timespec duration; - duration.tv_sec = 0; - duration.tv_nsec = 5 * 1000 * 1000; // 5 ms - nanosleep(&duration, NULL); + if (FD_ISSET(*rp, &rfds)) + { + int readRes = handleRead(*rp, result); + if (readRes == -1) + { + close(*rp); + rp = rpipes.erase(rp); + } + else + ++rp; + } + else + ++rp; } } int stat = 0; - waitpid(0, &stat, 0); - --childCount; + pid_t child = waitpid(0, &stat, WNOHANG); + if (child > 0) + { + std::string childname; + std::map::iterator c = childFile.find(child); + if (c != childFile.end()) + { + childname = c->second; + childFile.erase(c); + } + + if (WIFSIGNALED(stat)) + { + std::ostringstream oss; + oss << "Internal error: Child process crashed with signal " << WTERMSIG(stat); + + std::list locations; + locations.push_back(ErrorLogger::ErrorMessage::FileLocation(childname, 0)); + const ErrorLogger::ErrorMessage errmsg(locations, + Severity::error, + oss.str(), + "cppcheckError"); + _errorLogger.reportErr(errmsg); + } + } } - else if (childCount == 0) + else { // All done break; @@ -232,7 +277,7 @@ void ThreadExecutor::writeToPipe(char type, const std::string &data) out[0] = type; std::memcpy(&(out[1]), &len, sizeof(len)); std::memcpy(&(out[1+sizeof(len)]), data.c_str(), len); - if (write(_pipe[1], out, len + 1 + sizeof(len)) <= 0) + if (write(_wpipe, out, len + 1 + sizeof(len)) <= 0) { delete [] out; out = 0; diff --git a/cli/threadexecutor.h b/cli/threadexecutor.h index 78cb9a5fe..bbbabe076 100644 --- a/cli/threadexecutor.h +++ b/cli/threadexecutor.h @@ -71,9 +71,13 @@ private: * 0 if there is nothing in the pipe to be read * 1 if we did read something */ - int handleRead(unsigned int &result); + int handleRead(int rpipe, unsigned int &result); void writeToPipe(char type, const std::string &data); - int _pipe[2]; + /** + * Write end of status pipe, different for each child. + * Not used in master process. + */ + int _wpipe; std::list _errorList; public: /** From e12ae654a8bd160fd5eef87b219229d759a40caf Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sat, 5 Mar 2011 18:02:38 +1300 Subject: [PATCH 14/54] Support a few more common styles of "fall through" comment --- lib/preprocessor.cpp | 7 +++++-- test/testother.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index d93ddd6ab..0b2e0478f 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -310,9 +310,12 @@ static bool isFallThroughComment(std::string comment) comment.erase(std::remove_if(comment.begin(), comment.end(), ::isspace), comment.end()); return comment.find("fallthr") != std::string::npos || + comment.find("fallsthr") != std::string::npos || + comment.find("fall-thr") != std::string::npos || comment.find("dropthr") != std::string::npos || comment.find("passthr") != std::string::npos || - comment.find("nobreak") != std::string::npos; + comment.find("nobreak") != std::string::npos || + comment == "fall"; } std::string Preprocessor::removeComments(const std::string &str, const std::string &filename, Settings *settings) @@ -432,7 +435,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri ++lineno; } } - std::string comment(str, commentStart, i - commentStart); + std::string comment(str, commentStart, i - commentStart - 1); if (isFallThroughComment(comment)) { diff --git a/test/testother.cpp b/test/testother.cpp index 7aab2c4da..8bd040908 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1449,6 +1449,39 @@ private: // copying a final return after the block. TODO_ASSERT_EQUALS("", "[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " switch (a) {\n" + " case 1:\n" + " g();\n" + " // fall through\n" + " case 2:\n" + " g();\n" + " // falls through\n" + " case 3:\n" + " g();\n" + " // fall-through\n" + " case 4:\n" + " g();\n" + " // drop through\n" + " case 5:\n" + " g();\n" + " // pass through\n" + " case 5:\n" + " g();\n" + " // no break\n" + " case 5:\n" + " g();\n" + " // fallthru\n" + " case 6:\n" + " g();\n" + " /* fall */\n" + " default:\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void selfAssignment() From 1deb4e890fe30f663a308163a76790970ef32e24 Mon Sep 17 00:00:00 2001 From: Kimmo Varis Date: Sat, 5 Mar 2011 13:18:08 +0200 Subject: [PATCH 15/54] Skip checking gui/temp when using project file. gui/temp directory contains code files generated by qmake so those files are not interesting to check. --- cppcheck.cppcheck | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cppcheck.cppcheck b/cppcheck.cppcheck index 188043b4f..f6a808996 100644 --- a/cppcheck.cppcheck +++ b/cppcheck.cppcheck @@ -13,4 +13,7 @@ + + + From 8c245cfd2f66f424382ce090d5b8e170c2ecbd43 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 6 Mar 2011 09:42:15 +1300 Subject: [PATCH 16/54] switchCaseFallThrough is now a coding style check (ticket #2623) --- lib/checkother.cpp | 5 ++++- lib/preprocessor.cpp | 4 ++-- test/testother.cpp | 18 +++++++++--------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 8324808c5..97ab6ad20 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -309,6 +309,9 @@ void CheckOther::checkRedundantAssignmentInSwitch() void CheckOther::checkSwitchCaseFallThrough() { + if (!_settings->_checkCodingStyle) + return; + const char switchPattern[] = "switch ("; const char breakPattern[] = "break|continue|return|exit|goto"; @@ -3168,7 +3171,7 @@ void CheckOther::redundantAssignmentInSwitchError(const Token *tok, const std::s void CheckOther::switchCaseFallThrough(const Token *tok) { - reportError(tok, Severity::warning, + reportError(tok, Severity::style, "switchCaseFallThrough", "Switch falls through case without comment"); } diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 0b2e0478f..f98578a8c 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -410,7 +410,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } } - if (isFallThroughComment(comment)) + if (_settings->_checkCodingStyle && isFallThroughComment(comment)) { suppressionIDs.push_back("switchCaseFallThrough"); } @@ -437,7 +437,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } std::string comment(str, commentStart, i - commentStart - 1); - if (isFallThroughComment(comment)) + if (_settings->_checkCodingStyle && isFallThroughComment(comment)) { suppressionIDs.push_back("switchCaseFallThrough"); } diff --git a/test/testother.cpp b/test/testother.cpp index 8bd040908..e5dd1481b 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1239,7 +1239,7 @@ private: " break;\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str()); + ASSERT_EQUALS("[test.cpp:5]: (style) Switch falls through case without comment\n", errout.str()); check_preprocess_suppress( "void foo() {\n" @@ -1250,7 +1250,7 @@ private: " break;\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str()); + ASSERT_EQUALS("[test.cpp:5]: (style) Switch falls through case without comment\n", errout.str()); check_preprocess_suppress( "void foo() {\n" @@ -1313,7 +1313,7 @@ private: " break;\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:7]: (warning) Switch falls through case without comment\n", errout.str()); + ASSERT_EQUALS("[test.cpp:7]: (style) Switch falls through case without comment\n", errout.str()); check_preprocess_suppress( "void foo() {\n" @@ -1342,7 +1342,7 @@ private: " break;\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:8]: (warning) Switch falls through case without comment\n", errout.str()); + ASSERT_EQUALS("[test.cpp:8]: (style) Switch falls through case without comment\n", errout.str()); check_preprocess_suppress( "void foo() {\n" @@ -1355,7 +1355,7 @@ private: " break;\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:7]: (warning) Switch falls through case without comment\n", errout.str()); + ASSERT_EQUALS("[test.cpp:7]: (style) Switch falls through case without comment\n", errout.str()); check_preprocess_suppress( "void foo() {\n" @@ -1369,7 +1369,7 @@ private: " break;\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:8]: (warning) Switch falls through case without comment\n", errout.str()); + ASSERT_EQUALS("[test.cpp:8]: (style) Switch falls through case without comment\n", errout.str()); check_preprocess_suppress( "void foo() {\n" @@ -1383,7 +1383,7 @@ private: " break;\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str()); + ASSERT_EQUALS("[test.cpp:5]: (style) Switch falls through case without comment\n", errout.str()); check_preprocess_suppress( "void foo() {\n" @@ -1414,7 +1414,7 @@ private: // that all paths after g() actually return. It's a pretty unusual case // (no pun intended). TODO_ASSERT_EQUALS("", - "[test.cpp:11]: (warning) Switch falls through case without comment\n", errout.str()); + "[test.cpp:11]: (style) Switch falls through case without comment\n", errout.str()); check_preprocess_suppress( "void foo() {\n" @@ -1448,7 +1448,7 @@ private: // into where the goto is, but because it contains a "return", it omits // copying a final return after the block. TODO_ASSERT_EQUALS("", - "[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str()); + "[test.cpp:5]: (style) Switch falls through case without comment\n", errout.str()); check_preprocess_suppress( "void foo() {\n" From c8394909c007addadf7605f975f8789307736b33 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 6 Mar 2011 12:14:10 +1300 Subject: [PATCH 17/54] Relax detection of 'fall through' comment so it only adds a suppression if it immediately precedes 'case' or 'default' --- lib/preprocessor.cpp | 17 +++++++++++++++-- test/testother.cpp | 6 ++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index f98578a8c..25a43d806 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -331,6 +331,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri unsigned char previous = 0; bool inPreprocessorLine = false; std::vector suppressionIDs; + bool fallThroughComment = false; for (std::string::size_type i = hasbom(str) ? 3U : 0U; i < str.length(); ++i) { @@ -412,7 +413,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri if (_settings->_checkCodingStyle && isFallThroughComment(comment)) { - suppressionIDs.push_back("switchCaseFallThrough"); + fallThroughComment = true; } code << "\n"; @@ -439,7 +440,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri if (_settings->_checkCodingStyle && isFallThroughComment(comment)) { - suppressionIDs.push_back("switchCaseFallThrough"); + fallThroughComment = true; } if (settings && settings->_inlineSuppressions) @@ -467,6 +468,18 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri { // Not whitespace, not a comment, and not preprocessor. // Must be code here! + + // First check for a "fall through" comment match, but only + // add a suppression if the next token is 'case' or 'default' + if (fallThroughComment) + { + std::string::size_type j = str.find_first_not_of("abcdefghijklmnopqrstuvwxyz", i); + std::string tok = str.substr(i, j - i); + if (tok == "case" || tok == "default") + suppressionIDs.push_back("switchCaseFallThrough"); + fallThroughComment = false; + } + // Add any pending inline suppressions that have accumulated. if (!suppressionIDs.empty()) { diff --git a/test/testother.cpp b/test/testother.cpp index e5dd1481b..00759ffac 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1482,6 +1482,12 @@ private: " }\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + check_preprocess_suppress( + "void foo() {\n" + " // unrelated comment saying 'fall through'\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void selfAssignment() From b9df7735c5f5e6efde13a01433d7a11f6addf6d2 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 6 Mar 2011 13:06:30 +1300 Subject: [PATCH 18/54] switchCaseFallThrough is now an inconclusive check --- lib/checkother.cpp | 2 +- lib/preprocessor.cpp | 6 +++--- test/testother.cpp | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 97ab6ad20..633020473 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -309,7 +309,7 @@ void CheckOther::checkRedundantAssignmentInSwitch() void CheckOther::checkSwitchCaseFallThrough() { - if (!_settings->_checkCodingStyle) + if (!(_settings->_checkCodingStyle && _settings->inconclusive)) return; const char switchPattern[] = "switch ("; diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 25a43d806..fd072e33f 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -411,7 +411,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } } - if (_settings->_checkCodingStyle && isFallThroughComment(comment)) + if (isFallThroughComment(comment)) { fallThroughComment = true; } @@ -438,7 +438,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } std::string comment(str, commentStart, i - commentStart - 1); - if (_settings->_checkCodingStyle && isFallThroughComment(comment)) + if (isFallThroughComment(comment)) { fallThroughComment = true; } @@ -471,7 +471,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri // First check for a "fall through" comment match, but only // add a suppression if the next token is 'case' or 'default' - if (fallThroughComment) + if (_settings->_checkCodingStyle && _settings->inconclusive && fallThroughComment) { std::string::size_type j = str.find_first_not_of("abcdefghijklmnopqrstuvwxyz", i); std::string tok = str.substr(i, j - i); diff --git a/test/testother.cpp b/test/testother.cpp index 00759ffac..89f32a4ba 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -184,6 +184,7 @@ private: Settings settings; settings._checkCodingStyle = true; + settings.inconclusive = true; // Preprocess file.. Preprocessor preprocessor(&settings, this); From 7d2fb2ecde84c5cab0355eac0fbe8502a18e5b21 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sat, 5 Mar 2011 20:48:28 -0500 Subject: [PATCH 19/54] partial fix for #2624 (better function pointer support needed) --- lib/tokenize.cpp | 10 ++++++---- test/testsimplifytokens.cpp | 28 ++++++---------------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 76374f498..4dc6a9a9a 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5385,7 +5385,7 @@ void Tokenizer:: simplifyFunctionPointers() { for (Token *tok = _tokens; tok; tok = tok->next()) { - if (tok->previous() && !Token::Match(tok->previous(), "[{};]")) + if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|(|public:|protected:|private:")) continue; if (Token::Match(tok, "%type% *| *| ( * %var% ) (")) @@ -5398,8 +5398,8 @@ void Tokenizer:: simplifyFunctionPointers() while (tok->next()->str() == "*") tok = tok->next(); - // check that the declaration ends with ; - if (!Token::simpleMatch(tok->tokAt(5)->link(), ") ;")) + // check that the declaration ends + if (!Token::Match(tok->tokAt(5)->link(), ") ;|,|)|=")) continue; // ok simplify this function pointer to an ordinary pointer @@ -7063,6 +7063,7 @@ bool Tokenizer::simplifyCalculations() // keep parentheses here: int ( * * ( * compilerHookVector ) (void) ) ( ) ; // keep parentheses here: operator new [] (size_t); // keep parentheses here: Functor()(a ... ) + // keep parentheses here: ) ( var ) ; if (Token::Match(tok->next(), "( %var% ) [;),+-*/><]]") && !tok->isName() && tok->str() != ">" && @@ -7071,7 +7072,8 @@ bool Tokenizer::simplifyCalculations() !Token::simpleMatch(tok->previous(), "* )") && !Token::simpleMatch(tok->previous(), ") )") && !Token::Match(tok->tokAt(-2), "* %var% )") && - !Token::Match(tok->tokAt(-2), "%type% ( ) ( %var%") + !Token::Match(tok->tokAt(-2), "%type% ( ) ( %var%") && + !Token::Match(tok, ") ( %var% ) ;") ) { tok->deleteNext(); diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index e1a17d748..72e508bd2 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -3557,8 +3557,8 @@ private: const char expected[] = "; " - "void addCallback ( bool ( * callback ) ( int i ) ) { } " - "void addCallback1 ( bool ( * callback ) ( int i ) , int j ) { }"; + "void addCallback ( bool * callback ) { } " + "void addCallback1 ( bool * callback , int j ) { }"; ASSERT_EQUALS(expected, tok(code, false)); } @@ -3574,28 +3574,12 @@ private: const char expected[] = "; " - "void g ( int ( * f ) ( ) ) " + "void g ( int * f ) " "{ " - "int ( * f2 ) ( ) = ( int ( * ) ( ) ) f ; " + "int * f2 ; f2 = ( int ( * ) ( ) ) f ; " "}"; ASSERT_EQUALS(expected, tok(code, false)); - - // TODO: the definition and assignment should be split up - const char wanted[] = - "; " - "void g ( fp f ) " - "{ " - "int ( * f2 ) ( ) ; f2 = ( int ( * ) ( ) ) f ; " - "}"; - const char current[] = - "; " - "void g ( int ( * f ) ( ) ) " - "{ " - "int ( * f2 ) ( ) = ( int ( * ) ( ) ) f ; " - "}"; - - TODO_ASSERT_EQUALS(wanted, current, tok(code, false)); } { @@ -3607,9 +3591,9 @@ private: const char expected[] = "; " - "void g ( int ( * f ) ( ) ) " + "void g ( int * f ) " "{ " - "int ( * f2 ) ( ) = static_cast < int ( * ) ( ) > ( f ) ; " + "int * f2 ; f2 = static_cast < int ( * ) ( ) > ( f ) ; " "}"; ASSERT_EQUALS(expected, tok(code, false)); From 0debba440966295b3a2d3f89313435c4325caaaf Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sat, 5 Mar 2011 21:41:58 -0500 Subject: [PATCH 20/54] finish fixing #2624 (better function pointer support needed) --- lib/tokenize.cpp | 34 +++++++++++++++++++++++++++++++++- test/testsimplifytokens.cpp | 4 ++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 4dc6a9a9a..2005f60f2 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5385,7 +5385,39 @@ void Tokenizer:: simplifyFunctionPointers() { for (Token *tok = _tokens; tok; tok = tok->next()) { - if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|(|public:|protected:|private:")) + // check for function pointer cast + if (Token::Match(tok, "( %type% *| *| ( * ) (") || + Token::Match(tok, "( %type% %type% *| *| ( * ) (") || + Token::Match(tok, "static_cast < %type% *| *| ( * ) (") || + Token::Match(tok, "static_cast < %type% %type% *| *| ( * ) (")) + { + Token *tok1 = tok; + + if (tok1->str() == "static_cast") + tok1 = tok1->next(); + + tok1 = tok1->next(); + + if (Token::Match(tok1->next(), "%type%")) + tok1 = tok1->next(); + + while (tok1->next()->str() == "*") + tok1 = tok1->next(); + + // check that the cast ends + if (!Token::Match(tok1->tokAt(4)->link(), ") )|>")) + continue; + + // ok simplify this function pointer cast to an ordinary pointer cast + tok1->deleteNext(); + tok1->next()->deleteNext(); + const Token *tok2 = tok1->tokAt(2)->link(); + Token::eraseTokens(tok1->next(), tok2 ? tok2->next() : 0); + continue; + } + + // check for start of statement + else if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|(|public:|protected:|private:")) continue; if (Token::Match(tok, "%type% *| *| ( * %var% ) (")) diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 72e508bd2..96ec83945 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -3576,7 +3576,7 @@ private: "; " "void g ( int * f ) " "{ " - "int * f2 ; f2 = ( int ( * ) ( ) ) f ; " + "int * f2 ; f2 = ( int * ) f ; " "}"; ASSERT_EQUALS(expected, tok(code, false)); @@ -3593,7 +3593,7 @@ private: "; " "void g ( int * f ) " "{ " - "int * f2 ; f2 = static_cast < int ( * ) ( ) > ( f ) ; " + "int * f2 ; f2 = static_cast < int * > ( f ) ; " "}"; ASSERT_EQUALS(expected, tok(code, false)); From 779dba916055ea393df2fcc0df14de6d0c0081e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 6 Mar 2011 09:33:46 +0100 Subject: [PATCH 21/54] Fixed #2612 (segmentation fault of cppcheck ( <><< )) --- lib/tokenize.cpp | 2 +- test/testtokenize.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 2005f60f2..82e0d05a5 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2057,7 +2057,7 @@ bool Tokenizer::tokenize(std::istream &code, { tok->str(tok->str() + c2); tok->deleteNext(); - if (c1 == '<' && tok->next()->str() == "=") + if (c1 == '<' && Token::simpleMatch(tok->next(), "=")) { tok->str("<<="); tok->deleteNext(); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 04697796f..4fea2b224 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -49,6 +49,7 @@ private: TEST_CASE(tokenize13); // bailout if the code contains "@" - that is not handled well. TEST_CASE(tokenize14); // tokenize "0X10" => 16 TEST_CASE(tokenize15); // tokenize ".123" + TEST_CASE(tokenize16); // #2612 - segfault for "<><<" // don't freak out when the syntax is wrong TEST_CASE(wrong_syntax); @@ -516,6 +517,12 @@ private: ASSERT_EQUALS("0.125", tokenizeAndStringify(".125")); } + // #2612 - segfault for "<><<" + void tokenize16() + { + tokenizeAndStringify("<><<"); + } + void wrong_syntax() { { From ca4015f905148ba0f796c8ebcc41af2bf1566133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 6 Mar 2011 09:42:16 +0100 Subject: [PATCH 22/54] CheckMemoryLeak: Refactoring the code --- lib/checkmemoryleak.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 4dd122d1a..cbb7bd954 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -1588,17 +1588,19 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::listlink(),") (")) { - int tokIdx = matchFirst ? 2 : 3; + const Token *tok2 = tok->next(); + if (tok2->str() == "*") + tok2 = tok2->next(); + tok2 = tok2->next(); - while (Token::Match(tok->tokAt(tokIdx), ". %var%")) - tokIdx += 2; + while (Token::Match(tok2, ". %var%")) + tok2 = tok2->tokAt(2); - if (Token::simpleMatch(tok->tokAt(tokIdx), ") (")) + if (Token::simpleMatch(tok2, ") (")) { - for (const Token *tok2 = tok->tokAt(tokIdx + 2); tok2; tok2 = tok2->next()) + for (; tok2; tok2 = tok2->next()) { if (Token::Match(tok2, "[;{]")) break; From c56c90bfe10349f57c2fca58749f7e1966194b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 6 Mar 2011 10:18:50 +0100 Subject: [PATCH 23/54] readme: better build instructions --- readme.txt | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/readme.txt b/readme.txt index 0b0a0ab15..b85442449 100644 --- a/readme.txt +++ b/readme.txt @@ -23,7 +23,8 @@ Compiling There are multiple compilation choices: * qmake - cross platform build tool - * Visual Studio - Windows + * Windows: Visual Studio + * Windows: Qt Creator + mingw * gnu make * g++ @@ -36,11 +37,21 @@ Compiling Visual Studio ============= - Use the cppcheck.sln file. + Use the cppcheck.sln file. The pcre dll is needed, it can be downloaded from: + http://cppcheck.sf.net/pcre-8.10-vs.zip + + Qt Creator + mingw + ================== + The PCRE dll is needed to build the CLI. It can be downloaded here: + http://software-download.name/pcre-library-windows/ gnu make ======== - make + To build Cppcheck with rules (pcre dependency): + make + + To build Cppcheck without rules (no dependencies): + make CXXFLAGS="-O2" g++ (for experts) ================= From 080603148cbb37d396aa655e6cd986698b7e6f0f Mon Sep 17 00:00:00 2001 From: Kimmo Varis Date: Sun, 6 Mar 2011 14:29:12 +0200 Subject: [PATCH 24/54] Document error message severities. --- lib/errorlogger.h | 51 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/errorlogger.h b/lib/errorlogger.h index 384562b54..b50cf5d72 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -35,7 +35,56 @@ class Tokenizer; class Severity { public: - enum SeverityType { none, error, warning, style, performance, portability, information, debug }; + /** + * Message severities. + */ + enum SeverityType + { + /** + * No severity (default value). + */ + none, + /** + * Programming error. + * This indicates severe error like memory leak etc. + */ + error, + /** + * Warning. + */ + warning, + /** + * Style warning. + */ + style, + /** + * Performance warning. + * Not an error as is but suboptimal code and fixing it probably leads + * to faster performance of the compiled code. + */ + performance, + /** + * Portability warning. + * This warning indicates the code is not properly portable for + * different platforms and bitnesses (32/64 bit). If the code is meant + * to compile in different platforms and bitnesses these warnings + * should be fixed. + */ + portability, + /** + * Checking information. + * Information message about the checking (process) itself. These + * messages inform about header files not found etc issues that are + * not errors in the code but something user needs to know. + */ + information, + /** + * Debug message. + * Debug-mode message useful for the developers. + */ + debug + }; + static std::string toString(SeverityType severity) { switch (severity) From 10db7c4a48aeeb75efad4721a073e4a963f983ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 6 Mar 2011 14:26:02 +0100 Subject: [PATCH 25/54] error logger: explain the severities better --- lib/errorlogger.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/errorlogger.h b/lib/errorlogger.h index b50cf5d72..055e551e0 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -47,14 +47,20 @@ public: /** * Programming error. * This indicates severe error like memory leak etc. + * The error is certain. */ error, /** * Warning. + * Used for dangerous coding style that can cause severe runtime errors. + * For example: forgetting to initialize a member variable in a constructor. */ warning, /** * Style warning. + * Used for general code cleanup recommendations. Fixing these + * will not fix any bugs but will make the code easier to maintain. + * For example: redundant code, unreachable code, etc. */ style, /** From de31ec1e4441eab3c065d3208f0be01bbf2c2bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 6 Mar 2011 10:28:51 -0800 Subject: [PATCH 26/54] Tokenizer::simplifyTemplates: better handling of '(foo())'. Ticket: #2631 --- lib/tokenize.cpp | 6432 +---------------------------------- test/testsimplifytokens.cpp | 3789 +-------------------- 2 files changed, 21 insertions(+), 10200 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 82e0d05a5..3e529bb97 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2714,7 +2714,7 @@ std::list Tokenizer::simplifyTemplatesGetTemplateInstantiations() if (!tok) break; } - else if (Token::Match(tok->previous(), "[{};=] %var% <") || + else if (Token::Match(tok->previous(), "[({};=] %type% <") || Token::Match(tok->tokAt(-2), "[,:] private|protected|public %var% <")) { if (templateParameters(tok->next())) @@ -3087,6432 +3087,4 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, } // link() newly tokens manually - if (tok3->str() == "{") - { - braces.push(_tokensBack); - } - else if (tok3->str() == "}") - { - assert(braces.empty() == false); - Token::createMutualLinks(braces.top(), _tokensBack); - braces.pop(); - } - else if (tok3->str() == "(") - { - brackets.push(_tokensBack); - } - else if (tok3->str() == "[") - { - brackets2.push(_tokensBack); - } - else if (tok3->str() == ")") - { - assert(brackets.empty() == false); - Token::createMutualLinks(brackets.top(), _tokensBack); - brackets.pop(); - } - else if (tok3->str() == "]") - { - assert(brackets2.empty() == false); - Token::createMutualLinks(brackets2.top(), _tokensBack); - brackets2.pop(); - } - - } - - assert(braces.empty()); - assert(brackets.empty()); - } - } - - // Replace all these template usages.. - for (Token *tok4 = tok2; tok4; tok4 = tok4->next()) - { - if (Token::simpleMatch(tok4, s1.c_str())) - { - bool match = true; - Token * tok5 = tok4->tokAt(2); - unsigned int count = 0; - const Token *typetok = (!types2.empty()) ? types2[0] : 0; - while (tok5->str() != ">") - { - if (tok5->str() != ",") - { - if (!typetok || - tok5->isUnsigned() != typetok->isUnsigned() || - tok5->isSigned() != typetok->isSigned() || - tok5->isLong() != typetok->isLong()) - { - match = false; - break; - } - - typetok = typetok ? typetok->next() : 0; - } - else - { - ++count; - typetok = (count < types2.size()) ? types2[count] : 0; - } - tok5 = tok5->next(); - } - - if (match) - { - tok4->str(name2); - while (tok4->next()->str() != ">") - { - used.remove(tok4->next()); - tok4->deleteNext(); - } - used.remove(tok4->next()); - tok4->deleteNext(); - } - } - } - } -} - -void Tokenizer::simplifyTemplates() -{ - std::set expandedtemplates(simplifyTemplatesExpandSpecialized()); - - // Locate templates.. - std::list templates(simplifyTemplatesGetTemplateDeclarations()); - - if (templates.empty()) - { - removeTemplates(_tokens); - return; - } - - // There are templates.. - // Remove "typename" unless used in template arguments.. - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "typename") - tok->deleteThis(); - - if (Token::simpleMatch(tok, "template <")) - { - while (tok && tok->str() != ">") - tok = tok->next(); - if (!tok) - break; - } - } - - // Locate possible instantiations of templates.. - std::list used(simplifyTemplatesGetTemplateInstantiations()); - - // No template instantiations? Then remove all templates. - if (used.empty()) - { - removeTemplates(_tokens); - return; - } - - // Template arguments with default values - simplifyTemplatesUseDefaultArgumentValues(templates, used); - - // expand templates - bool done = false; - //while (!done) - { - done = true; - for (std::list::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) - { - simplifyTemplatesInstantiate(*iter1, used, expandedtemplates); - } - } - - removeTemplates(_tokens); -} -//--------------------------------------------------------------------------- - -void Tokenizer::simplifyTemplates2() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "(") - tok = tok->link(); - - else if (Token::Match(tok, "; %type% <")) - { - const Token *tok2 = tok->tokAt(3); - std::string type; - while (Token::Match(tok2, "%type% ,") || Token::Match(tok2, "%num% ,")) - { - type += tok2->str() + ","; - tok2 = tok2->tokAt(2); - } - if (Token::Match(tok2, "%type% > (") || Token::Match(tok2, "%num% > (")) - { - type += tok2->str(); - tok = tok->next(); - tok->str(tok->str() + "<" + type + ">"); - Token::eraseTokens(tok, tok2->tokAt(2)); - } - } - } -} -//--------------------------------------------------------------------------- - -std::string Tokenizer::getNameForFunctionParams(const Token *start) -{ - if (start->next() == start->link()) - return ""; - - std::string result; - bool findNextComma = false; - for (const Token *tok = start->next(); tok && tok != start->link(); tok = tok->next()) - { - if (findNextComma) - { - if (tok->str() == ",") - findNextComma = false; - - continue; - } - - result.append(tok->str() + ","); - findNextComma = true; - } - - return result; -} - -void Tokenizer::setVarId() -{ - // Clear all variable ids - for (Token *tok = _tokens; tok; tok = tok->next()) - tok->varId(0); - - // Set variable ids.. - _varId = 0; - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok != _tokens && !Token::Match(tok, "[;{}(,] %type%")) - continue; - - if (_errorLogger) - _errorLogger->reportProgress(_files[0], "Tokenize (set variable id)", tok->progressValue()); - - // If pattern is "( %type% *|& %var% )" then check if it's a - // variable declaration or a multiplication / mask - if (Token::Match(tok, "( %type% *|& %var% [),]") && !tok->next()->isStandardType()) - { - if (!Token::Match(tok->previous(), "%type%")) - continue; - if (tok->strAt(-1) == "return") - continue; - if (!Token::Match(tok->tokAt(5), "const|{")) - continue; - } - - if (Token::Match(tok, "[,;{}(] %type%")) - { - // not function declaration? - // TODO: Better checking - if (Token::Match(tok->tokAt(-2), "= %var% (")) - { - continue; - } - if (tok->str() == "(" && - tok->previous() && - !tok->previous()->isName() && - tok->strAt(-2) != "operator") - continue; - tok = tok->next(); - } - - if (tok->str() == "new") - continue; - - if (tok->str() == "throw") - continue; - - if (tok->str() == "unsigned") - tok = tok->next(); - - if (Token::Match(tok, "class|struct %type% :|{|;")) - continue; - - if (Token::Match(tok, "using namespace %type% ;")) - { - tok = tok->next(); - continue; - } - - if (Token::Match(tok, "else|return|typedef|delete|sizeof")) - continue; - - while (Token::Match(tok, "const|static|extern|public:|private:|protected:|;|mutable")) - tok = tok->next(); - - while (Token::Match(tok, "%var% ::")) - tok = tok->tokAt(2); - - // Skip template arguments.. - if (Token::Match(tok, "%type% <")) - { - int level = 1; - bool again; - Token *tok2 = tok->tokAt(2); - - do // Look for start of templates or template arguments - { - again = false; - - if (tok2->str() == "const") - tok2 = tok2->next(); - - while (Token::Match(tok2, "%var% ::")) - tok2 = tok2->tokAt(2); - - if (Token::Match(tok2, "%type% <")) - { - level++; - tok2 = tok2->tokAt(2); - again = true; - } - else if (Token::Match(tok2, "%type% *|&| ,")) - { - tok2 = tok2->tokAt(2); - if (tok2->str() == ",") - tok2 = tok2->next(); - again = true; - } - else if (level > 1 && Token::Match(tok2, "%type% *|&| >")) - { - --level; - while (tok2->str() != ">") - tok2 = tok2->next(); - tok2 = tok2->next(); - if (tok2->str() == ",") - tok2 = tok2->next(); - if (level == 1 && tok2->str() == ">") - break; - again = true; - } - else - { - while (tok2 && (tok2->isName() || tok2->isNumber() || tok2->str() == "*" || tok2->str() == "&" || tok2->str() == ",")) - tok2 = tok2->next(); - if (tok2->str() == "(") - { - tok2 = tok2->link()->next(); - if (tok2->str() == "(") - tok2 = tok2->link()->next(); - again = true; - } - } - } - while (again); - - do // Look for end of templates - { - again = false; - - if (level == 1 && Token::Match(tok2, "> %var%")) - tok = tok2; - else if (level > 1 && tok2->str() == ">") - { - level--; - if (level == 0) - tok = tok2; - else - { - tok2 = tok2->tokAt(1); - again = true; - } - } - else if (level == 1 && Token::Match(tok2, "> ::|*|& %var%")) - tok = tok2->next(); - else - continue; // Not code that I understand / not a variable declaration - } - while (again); - } - - // Determine name of declared variable.. - std::string varname; - Token *tok2 = tok->tokAt(1); - while (tok2) - { - if (tok2->isName()) - varname = tok2->str(); - else if (tok2->str() != "*" && tok2->str() != "&") - break; - tok2 = tok2->next(); - } - - // End of tokens reached.. - if (!tok2) - break; - - if (varname == "operator" && Token::Match(tok2, "=|+|-|*|/|[| ]| (")) - continue; - - if (varname == "new" && Token::Match(tok2->tokAt(-2), "operator new (|[")) - continue; - - // Is it a function? - if (tok2->str() == "(") - { - // Search for function declaration, e.g. void f(); - if (Token::simpleMatch(tok2->next(), ") ;")) - continue; - - // Search for function declaration, e.g. void f( int c ); - if (Token::Match(tok2->next(), "%num%") || - Token::Match(tok2->next(), "%bool%") || - tok2->next()->str()[0] == '"' || - tok2->next()->str()[0] == '\'' || - tok2->next()->varId() != 0) - { - // This is not a function - } - else - { - continue; - } - } - - // Variable declaration found => Set variable ids - if (Token::Match(tok2, "[,();[=]") && !varname.empty()) - { - ++_varId; - int indentlevel = 0; - int parlevel = 0; - bool funcDeclaration = false; - for (tok2 = tok->next(); tok2; tok2 = tok2->next()) - { - const char c = tok2->str()[0]; - if (c == varname[0]) - { - const std::string &prev = tok2->strAt(-1); - if (tok2->str() == varname && prev != "struct" && prev != "union" && prev != "::" && prev != "." && tok2->strAt(1) != "::") - tok2->varId(_varId); - } - else if (c == '{') - ++indentlevel; - else if (c == '}') - { - --indentlevel; - if (indentlevel < 0) - break; - - // We have reached the end of a loop: "for( int i;;) { }" - if (funcDeclaration && indentlevel <= 0) - break; - } - else if (c == '(') - ++parlevel; - else if (c == ')') - { - // Is this a function parameter or a variable declared in for example a for loop? - if (parlevel == 0 && indentlevel == 0 && Token::Match(tok2, ") const| {")) - funcDeclaration = true; - else - --parlevel; - } - else if (parlevel < 0 && c == ';') - break; - } - } - } - - // Struct/Class members - for (Token *tok = _tokens; tok; tok = tok->next()) - { - // str.clear is a variable - // str.clear() is a member function - if (tok->varId() != 0 && - Token::Match(tok->next(), ". %var% !!(") && - tok->tokAt(2)->varId() == 0) - { - ++_varId; - - const std::string pattern(std::string(". ") + tok->strAt(2)); - for (Token *tok2 = tok; tok2; tok2 = tok2->next()) - { - if (tok2->varId() == tok->varId()) - { - if (Token::Match(tok2->next(), pattern.c_str())) - tok2->tokAt(2)->varId(_varId); - } - } - } - } - - // Member functions and variables in this source - std::list allMemberFunctions; - std::list allMemberVars; - { - for (Token *tok2 = _tokens; tok2; tok2 = tok2->next()) - { - if (Token::Match(tok2, "%var% :: %var%")) - { - if (Token::simpleMatch(tok2->tokAt(3), "(")) - allMemberFunctions.push_back(tok2); - else if (tok2->tokAt(2)->varId() != 0) - allMemberVars.push_back(tok2); - } - } - } - - // class members.. - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "class|struct %var% {|:")) - { - const std::string &classname(tok->next()->str()); - - // What member variables are there in this class? - std::map varlist; - { - unsigned int indentlevel = 0; - for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) - { - // Indentation.. - if (tok2->str() == "{") - ++indentlevel; - else if (tok2->str() == "}") - { - if (indentlevel <= 1) - break; - --indentlevel; - } - - // Found a member variable.. - else if (indentlevel == 1 && tok2->varId() > 0) - varlist[tok2->str()] = tok2->varId(); - } - } - - // Are there any member variables in this class? - if (varlist.empty()) - continue; - - // Member variables - for (std::list::iterator func = allMemberVars.begin(); func != allMemberVars.end(); ++func) - { - if (!Token::simpleMatch(*func, classname.c_str())) - continue; - - Token *tok2 = *func; - tok2 = tok2->tokAt(2); - tok2->varId(varlist[tok2->str()]); - } - - // Member functions for this class.. - std::list funclist; - { - const std::string funcpattern(classname + " :: %var% ("); - for (std::list::iterator func = allMemberFunctions.begin(); func != allMemberFunctions.end(); ++func) - { - Token *tok2 = *func; - - // Found a class function.. - if (Token::Match(tok2, funcpattern.c_str())) - { - // Goto the end parenthesis.. - tok2 = tok2->tokAt(3)->link(); - if (!tok2) - break; - - // If this is a function implementation.. add it to funclist - if (Token::Match(tok2, ") const|volatile| {")) - funclist.push_back(tok2); - } - } - } - - // Update the variable ids.. - // Parse each function.. - for (std::list::iterator func = funclist.begin(); func != funclist.end(); ++func) - { - unsigned int indentlevel = 0; - for (Token *tok2 = *func; tok2; tok2 = tok2->next()) - { - if (tok2->str() == "{") - ++indentlevel; - else if (tok2->str() == "}") - { - if (indentlevel <= 1) - break; - --indentlevel; - } - else if (indentlevel > 0 && - tok2->varId() == 0 && - !Token::simpleMatch(tok2->previous(), ".") && - varlist.find(tok2->str()) != varlist.end()) - { - tok2->varId(varlist[tok2->str()]); - } - } - } - - } - } -} - -bool Tokenizer::createLinks() -{ - std::list type; - std::list links; - std::list links2; - std::list links3; - for (Token *token = _tokens; token; token = token->next()) - { - if (token->link()) - { - token->link(0); - } - - if (token->str() == "{") - { - links.push_back(token); - type.push_back(token); - } - else if (token->str() == "}") - { - if (links.empty()) - { - // Error, { and } don't match. - syntaxError(token, '{'); - return false; - } - if (type.back()->str() != "{") - { - syntaxError(type.back(), type.back()->str()[0]); - return false; - } - type.pop_back(); - - Token::createMutualLinks(links.back(), token); - links.pop_back(); - } - else if (token->str() == "(") - { - links2.push_back(token); - type.push_back(token); - } - else if (token->str() == ")") - { - if (links2.empty()) - { - // Error, ( and ) don't match. - syntaxError(token, '('); - return false; - } - if (type.back()->str() != "(") - { - syntaxError(type.back(), type.back()->str()[0]); - return false; - } - type.pop_back(); - - Token::createMutualLinks(links2.back(), token); - links2.pop_back(); - } - else if (token->str() == "[") - { - links3.push_back(token); - type.push_back(token); - } - else if (token->str() == "]") - { - if (links3.empty()) - { - // Error, [ and ] don't match. - syntaxError(token, '['); - return false; - } - if (type.back()->str() != "[") - { - syntaxError(type.back(), type.back()->str()[0]); - return false; - } - type.pop_back(); - - Token::createMutualLinks(links3.back(), token); - links3.pop_back(); - } - } - - if (!links.empty()) - { - // Error, { and } don't match. - syntaxError(links.back(), '{'); - return false; - } - - if (!links2.empty()) - { - // Error, ( and ) don't match. - syntaxError(links2.back(), '('); - return false; - } - - if (!links3.empty()) - { - // Error, [ and ] don't match. - syntaxError(links3.back(), '['); - return false; - } - - return true; -} - -void Tokenizer::simplifySizeof() -{ - // Fill the map _typeSize.. - _typeSize.clear(); - _typeSize["char"] = sizeof(char); - _typeSize["short"] = sizeof(short); - _typeSize["int"] = sizeof(int); - _typeSize["long"] = sizeof(long); - _typeSize["float"] = sizeof(float); - _typeSize["double"] = sizeof(double); - _typeSize["size_t"] = sizeof(size_t); - _typeSize["*"] = sizeof(void *); - - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "class|struct %var%")) - { - // we assume that the size of structs and classes are always - // 100 bytes. - _typeSize[tok->strAt(1)] = 100; - } - } - - // Locate variable declarations and calculate the size - std::map sizeOfVar; - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->varId() != 0 && sizeOfVar.find(tok->varId()) == sizeOfVar.end()) - { - const unsigned int varId = tok->varId(); - if (Token::Match(tok->tokAt(-3), "[;{}(,] %type% * %var% [;,)]") || - Token::Match(tok->tokAt(-4), "[;{}(,] const %type% * %var% [;),]") || - Token::Match(tok->tokAt(-2), "[;{}(,] %type% %var% [;),]") || - Token::Match(tok->tokAt(-3), "[;{}(,] const %type% %var% [;),]")) - { - const unsigned int size = sizeOfType(tok->previous()); - if (size == 0) - { - continue; - } - - sizeOfVar[varId] = MathLib::toString(size); - } - - else if (Token::Match(tok->tokAt(-1), "%type% %var% [ %num% ] [;=]") || - Token::Match(tok->tokAt(-2), "%type% * %var% [ %num% ] [;=]")) - { - const unsigned int size = sizeOfType(tok->tokAt(-1)); - if (size == 0) - continue; - - sizeOfVar[varId] = MathLib::toString(size * static_cast(MathLib::toLongNumber(tok->strAt(2)))); - } - - else if (Token::Match(tok->tokAt(-1), "%type% %var% [ %num% ] [,)]") || - Token::Match(tok->tokAt(-2), "%type% * %var% [ %num% ] [,)]")) - { - Token tempTok(0); - tempTok.str("*"); - sizeOfVar[varId] = MathLib::toString(sizeOfType(&tempTok)); - } - - else if (Token::Match(tok->tokAt(-1), "%type% %var% [ ] = %str% ;")) - { - const unsigned int size = sizeOfType(tok->tokAt(4)); - if (size == 0) - continue; - - sizeOfVar[varId] = MathLib::toString(size); - } - } - } - - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() != "sizeof") - continue; - - if (!tok->next()) - break; - - if (Token::simpleMatch(tok->next(), "sizeof")) - continue; - - if (Token::simpleMatch(tok->next(), ". . .")) - { - Token::eraseTokens(tok, tok->tokAt(4)); - } - - // sizeof 'x' - if (tok->strAt(1)[0] == '\'') - { - tok->deleteThis(); - std::ostringstream sz; - sz << sizeof 'x'; - tok->str(sz.str()); - continue; - } - - // sizeof('x') - if (Token::Match(tok, "sizeof ( %any% )") && tok->strAt(2)[0] == '\'') - { - tok->deleteThis(); - tok->deleteThis(); - tok->deleteNext(); - std::ostringstream sz; - sz << sizeof 'x'; - tok->str(sz.str()); - continue; - } - - // sizeof "text" - if (Token::Match(tok->next(), "%str%")) - { - tok->deleteThis(); - std::ostringstream ostr; - ostr << (Token::getStrLength(tok) + 1); - tok->str(ostr.str()); - continue; - } - - // sizeof ("text") - if (Token::Match(tok->next(), "( %str% )")) - { - tok->deleteThis(); - tok->deleteThis(); - tok->deleteNext(); - std::ostringstream ostr; - ostr << (Token::getStrLength(tok) + 1); - tok->str(ostr.str()); - continue; - } - - // sizeof * (...) -> sizeof(*...) - if (Token::simpleMatch(tok->next(), "* (") && !Token::simpleMatch(tok->tokAt(2)->link(), ") .")) - { - tok->deleteNext(); - tok->next()->insertToken("*"); - } - - // sizeof a++ -> sizeof(a++) - if (Token::Match(tok->next(), "++|-- %var% !!.") || Token::Match(tok->next(), "%var% ++|--")) - { - tok->insertToken("("); - tok->tokAt(3)->insertToken(")"); - Token::createMutualLinks(tok->next(), tok->tokAt(4)); - } - - // sizeof 1 => sizeof ( 1 ) - if (tok->next()->isNumber()) - { - Token *tok2 = tok->next(); - tok->insertToken("("); - tok2->insertToken(")"); - Token::createMutualLinks(tok->next(), tok2->next()); - } - - // sizeof int -> sizeof( int ) - else if (tok->next()->str() != "(") - { - // Add parenthesis around the sizeof - int parlevel = 0; - for (Token *tempToken = tok->next(); tempToken; tempToken = tempToken->next()) - { - if (tempToken->str() == "(") - ++parlevel; - else if (tempToken->str() == ")") - --parlevel; - if (Token::Match(tempToken, "%var%")) - { - while (tempToken && tempToken->next() && tempToken->next()->str() == "[") - { - tempToken = tempToken->next()->link(); - } - if (!tempToken || !tempToken->next()) - { - break; - } - - if (tempToken->next()->str() == ".") - { - // We are checking a class or struct, search next varname - tempToken = tempToken->tokAt(1); - continue; - } - else if (Token::simpleMatch(tempToken->next(), "- >")) - { - // We are checking a class or struct, search next varname - tempToken = tempToken->tokAt(2); - continue; - } - else if (Token::Match(tempToken->next(), "++|--")) - { - // We have variable++ or variable--, there should be - // nothing after this - tempToken = tempToken->tokAt(2); - } - else if (parlevel > 0 && Token::simpleMatch(tempToken->next(), ") .")) - { - --parlevel; - tempToken = tempToken->tokAt(2); - continue; - } - - // Ok, we should be clean. Add ) after tempToken - tok->insertToken("("); - tempToken->insertToken(")"); - Token::createMutualLinks(tok->next(), tempToken->next()); - break; - } - } - } - - // sizeof(type *) => sizeof(*) - if (Token::Match(tok->next(), "( %type% * )")) - { - tok->next()->deleteNext(); - } - - if (Token::simpleMatch(tok->next(), "( * )")) - { - tok->str(MathLib::toString(sizeOfType(tok->tokAt(2)))); - Token::eraseTokens(tok, tok->tokAt(4)); - } - - // sizeof( a ) - else if (Token::Match(tok->next(), "( %var% )") && tok->tokAt(2)->varId() != 0) - { - if (sizeOfVar.find(tok->tokAt(2)->varId()) != sizeOfVar.end()) - { - tok->deleteThis(); - tok->deleteThis(); - tok->deleteNext(); - tok->str(sizeOfVar[tok->varId()]); - } - else - { - // don't try to replace size of variable if variable has - // similar name with type (#329) - } - } - - else if (Token::Match(tok, "sizeof ( %type% )")) - { - unsigned int size = sizeOfType(tok->tokAt(2)); - if (size > 0) - { - tok->str(MathLib::toString(size)); - Token::eraseTokens(tok, tok->tokAt(4)); - } - } - - else if (Token::Match(tok, "sizeof ( * %var% )") || Token::Match(tok, "sizeof ( %var% [ %num% ] )")) - { - // Some default value.. - unsigned int sz = 0; - - unsigned int varid = tok->tokAt((tok->tokAt(2)->str() == "*") ? 3 : 2)->varId(); - if (varid != 0) - { - // Try to locate variable declaration.. - const Token *decltok = Token::findmatch(_tokens, "%varid%", varid); - if (Token::Match(decltok->previous(), "%type% %var% [")) - { - sz = sizeOfType(decltok->previous()); - } - else if (Token::Match(decltok->previous(), "* %var% [")) - { - sz = sizeOfType(decltok->previous()); - } - else if (Token::Match(decltok->tokAt(-2), "%type% * %var%")) - { - sz = sizeOfType(decltok->tokAt(-2)); - } - } - else if (tok->strAt(3) == "[" && tok->tokAt(2)->isStandardType()) - { - sz = sizeOfType(tok->tokAt(2)); - if (sz == 0) - continue; - sz = sz * static_cast(MathLib::toLongNumber(tok->strAt(4))); - } - - if (sz > 0) - { - tok->str(MathLib::toString(sz)); - Token::eraseTokens(tok, tok->next()->link()->next()); - } - } - } - -} - -bool Tokenizer::simplifyTokenList() -{ - // clear the _functionList so it can't contain dead pointers - delete _symbolDatabase; - _symbolDatabase = NULL; - - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::simpleMatch(tok, "* const")) - tok->deleteNext(); - } - - // simplify references - simplifyReference(); - - simplifyStd(); - - simplifyGoto(); - - // Combine wide strings - for (Token *tok = _tokens; tok; tok = tok->next()) - { - while (tok->str() == "L" && tok->next() && tok->next()->str()[0] == '"') - { - // Combine 'L "string"' - tok->str(tok->next()->str()); - tok->deleteNext(); - } - } - - // Combine strings - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str()[0] != '"') - continue; - - tok->str(simplifyString(tok->str())); - while (tok->next() && tok->next()->str()[0] == '"') - { - tok->next()->str(simplifyString(tok->next()->str())); - - // Two strings after each other, combine them - tok->concatStr(tok->next()->str()); - tok->deleteNext(); - } - } - - // Convert e.g. atol("0") into 0 - simplifyMathFunctions(); - - // Convert + + into + and + - into - - for (Token *tok = _tokens; tok; tok = tok->next()) - { - while (tok->next()) - { - if (tok->str() == "+") - { - if (tok->next()->str() == "+") - { - tok->deleteNext(); - continue; - } - else if (tok->next()->str() == "-") - { - tok->str("-"); - tok->deleteNext(); - continue; - } - } - else if (tok->str() == "-") - { - if (tok->next()->str() == "-") - { - tok->str("+"); - tok->deleteNext(); - continue; - } - else if (tok->next()->str() == "+") - { - tok->deleteNext(); - continue; - } - } - - break; - } - } - - // 0[a] -> a[0] - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "%num% [ %var% ]")) - { - const std::string temp = tok->str(); - tok->str(tok->tokAt(2)->str()); - tok->tokAt(2)->str(temp); - } - } - - simplifySizeof(); - - // replace strlen(str) - simplifyKnownVariables(); - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "strlen ( %str% )")) - { - std::ostringstream ostr; - ostr << Token::getStrLength(tok->tokAt(2)); - tok->str(ostr.str()); - tok->deleteNext(); - tok->deleteNext(); - tok->deleteNext(); - } - } - - // change array to pointer.. - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "%type% %var% [ ] [,;=]")) - { - Token::eraseTokens(tok->next(), tok->tokAt(4)); - tok->insertToken("*"); - } - } - - // Replace constants.. - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "const %type% %var% = %num% ;")) - { - unsigned int varId = tok->tokAt(2)->varId(); - if (varId == 0) - { - tok = tok->tokAt(5); - continue; - } - - const std::string num = tok->strAt(4); - int indent = 1; - for (Token *tok2 = tok->tokAt(6); tok2; tok2 = tok2->next()) - { - if (tok2->str() == "{") - { - ++indent; - } - else if (tok2->str() == "}") - { - --indent; - if (indent == 0) - break; - } - - // Compare constants, but don't touch members of other structures - else if (tok2->varId() == varId) - { - tok2->str(num); - } - } - } - } - - simplifyCasts(); - - // Simplify simple calculations.. - simplifyCalculations(); - - // Replace "*(str + num)" => "str[num]" - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (! strchr(";{}(=<>", tok->str()[0])) - continue; - - Token *next = tok->next(); - if (! next) - break; - - if (Token::Match(next, "* ( %var% + %num% )") || - Token::Match(next, "* ( %var% + %var% )")) - { - // var - tok = tok->next(); - tok->str(tok->strAt(2)); - - // [ - tok = tok->next(); - tok->str("["); - - // num - tok = tok->next(); - tok->str(tok->strAt(2)); - - // ] - tok = tok->next(); - tok->str("]"); - - tok->deleteNext(); - tok->deleteNext(); - - Token::createMutualLinks(next->tokAt(1), next->tokAt(3)); - } - } - - // simplify "x=realloc(y,0);" => "free(y); x=0;".. - // and "x = realloc (0, n);" => "x = malloc(n);" - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "; %var% = realloc ( %var% , 0 ) ;")) - { - const std::string varname(tok->next()->str()); - const unsigned int varid(tok->next()->varId()); - - // Delete the "%var% =" - tok->deleteNext(); - tok->deleteNext(); - - // Change function name "realloc" to "free" - tok->next()->str("free"); - - // delete the ", 0" - Token::eraseTokens(tok->tokAt(3), tok->tokAt(6)); - - // goto the ";" - tok = tok->tokAt(5); - - // insert "var=0;" - tok->insertToken(";"); - tok->insertToken("0"); - tok->insertToken("="); - tok->insertToken(varname); - tok->next()->varId(varid); - } - else if (Token::Match(tok, "; %var% = realloc ( 0 , %num% ) ;")) - { - const std::string varname(tok->next()->str()); - - tok = tok->tokAt(3); - // Change function name "realloc" to "malloc" - tok->str("malloc"); - - // delete "0 ," - tok->next()->deleteNext(); - tok->next()->deleteNext(); - } - } - - // Change initialisation of variable to assignment - simplifyInitVar(); - - // Simplify variable declarations - simplifyVarDecl(); - - simplifyFunctionParameters(); - elseif(); - simplifyErrNoInWhile(); - simplifyIfAssign(); - simplifyRedundantParanthesis(); - simplifyIfNot(); - simplifyIfNotNull(); - simplifyIfSameInnerCondition(); - simplifyComparisonOrder(); - simplifyNestedStrcat(); - simplifyWhile0(); - simplifyFuncInWhile(); - - simplifyIfAssign(); // could be affected by simplifyIfNot - - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "case %any% : %var%")) - tok->tokAt(2)->insertToken(";"); - if (Token::Match(tok, "default : %var%")) - tok->next()->insertToken(";"); - } - - // In case variable declarations have been updated... - setVarId(); - - bool modified = true; - while (modified) - { - modified = false; - modified |= simplifyConditions(); - modified |= simplifyFunctionReturn(); - modified |= simplifyKnownVariables(); - modified |= removeReduntantConditions(); - modified |= simplifyRedundantParanthesis(); - modified |= simplifyQuestionMark(); - modified |= simplifyCalculations(); - } - - // Remove redundant parentheses in return.. - for (Token *tok = _tokens; tok; tok = tok->next()) - { - while (Token::simpleMatch(tok, "return (")) - { - Token *tok2 = tok->next()->link(); - if (Token::simpleMatch(tok2, ") ;")) - { - tok->deleteNext(); - tok2->deleteThis(); - } - else - { - break; - } - } - } - - removeRedundantAssignment(); - - simplifyComma(); - if (_settings->debug) - { - _tokens->printOut(0, _files); - } - - _tokens->assignProgressValues(); - - removeRedundantSemicolons(); - - return validate(); -} -//--------------------------------------------------------------------------- - -void Tokenizer::removeMacrosInGlobalScope() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "(") - { - tok = tok->link(); - if (Token::Match(tok, ") %type% {") && tok->strAt(1) != "const") - tok->deleteNext(); - } - - if (tok->str() == "{") - tok = tok->link(); - } -} -//--------------------------------------------------------------------------- - -void Tokenizer::removeRedundantAssignment() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "{") - tok = tok->link(); - - if (Token::Match(tok, ") const| {")) - { - // parse in this function.. - std::set localvars; - if (tok->next()->str() == "const") - tok = tok->next(); - const Token * const end = tok->next()->link(); - for (Token *tok2 = tok->next(); tok2 && tok2 != end; tok2 = tok2->next()) - { - if (Token::Match(tok2, "[;{}] %type% * %var% ;") && tok2->strAt(1) != "return") - { - tok2 = tok2->tokAt(3); - localvars.insert(tok2->varId()); - } - else if (Token::Match(tok2, "[;{}] %type% %var% ;") && tok2->next()->isStandardType()) - { - tok2 = tok2->tokAt(2); - localvars.insert(tok2->varId()); - } - else if (tok2->varId() && - !Token::Match(tok2->previous(), "[;{}] %var% = %var% ;") && - !Token::Match(tok2->previous(), "[;{}] %var% = %num% ;") && - !(Token::Match(tok2->previous(), "[;{}] %var% = %any% ;") && tok2->strAt(2)[0] == '\'')) - { - localvars.erase(tok2->varId()); - } - } - localvars.erase(0); - if (!localvars.empty()) - { - for (Token *tok2 = tok->next(); tok2 && tok2 != end; tok2 = tok2->next()) - { - if (Token::Match(tok2, "[;{}] %type% %var% ;") && localvars.find(tok2->tokAt(2)->varId()) != localvars.end()) - { - Token::eraseTokens(tok2, tok2->tokAt(3)); - } - else if (Token::Match(tok2, "[;{}] %type% * %var% ;") && localvars.find(tok2->tokAt(3)->varId()) != localvars.end()) - { - Token::eraseTokens(tok2, tok2->tokAt(4)); - } - else if (Token::Match(tok2, "[;{}] %var% = %any% ;") && localvars.find(tok2->next()->varId()) != localvars.end()) - { - Token::eraseTokens(tok2, tok2->tokAt(4)); - } - } - } - } - } -} - -bool Tokenizer::removeReduntantConditions() -{ - // Return value for function. Set to true if there are any simplifications - bool ret = false; - - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() != "if") - continue; - - if (!Token::Match(tok->tokAt(1), "( %bool% ) {")) - continue; - - // Find matching else - const Token *elseTag = 0; - - // Find the closing "}" - elseTag = tok->tokAt(4)->link()->next(); - - bool boolValue = false; - if (tok->tokAt(2)->str() == "true") - boolValue = true; - - // Handle if with else - if (elseTag && elseTag->str() == "else") - { - if (Token::simpleMatch(elseTag->next(), "if (")) - { - // Handle "else if" - if (boolValue == false) - { - // Convert "if( false ) {aaa;} else if() {bbb;}" => "if() {bbb;}" - Token::eraseTokens(tok, elseTag->tokAt(2)); - ret = true; - } - else - { - // Keep first if, remove every else if and else after it - const Token *lastTagInIf = elseTag->tokAt(2); - while (lastTagInIf) - { - if (lastTagInIf->str() == "(") - { - lastTagInIf = lastTagInIf->link()->next(); - } - - lastTagInIf = lastTagInIf->link()->next(); - if (!Token::simpleMatch(lastTagInIf, "else")) - break; - - lastTagInIf = lastTagInIf->next(); - if (lastTagInIf->str() == "if") - lastTagInIf = lastTagInIf->next(); - } - - Token::eraseTokens(elseTag->previous(), lastTagInIf); - ret = true; - } - } - else - { - // Handle else - if (boolValue == false) - { - // Convert "if( false ) {aaa;} else {bbb;}" => "{bbb;}" or ";{bbb;}" - if (tok->previous()) - tok = tok->previous(); - else - tok->str(";"); - - Token::eraseTokens(tok, elseTag->tokAt(1)); - } - else - { - if (elseTag->tokAt(1)->str() == "{") - { - // Convert "if( true ) {aaa;} else {bbb;}" => "{aaa;}" - const Token *end = elseTag->tokAt(1)->link(); - - // Remove the "else { aaa; }" - Token::eraseTokens(elseTag->previous(), end->tokAt(1)); - } - - // Remove "if( true )" - if (tok->previous()) - tok = tok->previous(); - else - tok->str(";"); - - Token::eraseTokens(tok, tok->tokAt(5)); - } - - ret = true; - } - } - - // Handle if without else - else - { - if (boolValue == false) - { - // Remove if and its content - if (tok->previous()) - tok = tok->previous(); - else - tok->str(";"); - - Token::eraseTokens(tok, elseTag); - } - else - { - // convert "if( true ) {aaa;}" => "{aaa;}" - if (tok->previous()) - tok = tok->previous(); - else - tok->str(";"); - - Token::eraseTokens(tok, tok->tokAt(5)); - } - - ret = true; - } - } - - return ret; -} - - -void Tokenizer::removeRedundantSemicolons() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "(") - { - tok = tok->link(); - } - while (Token::simpleMatch(tok, "; ;")) - { - tok->deleteNext(); - } - } -} - - -void Tokenizer::simplifyIfAddBraces() -{ - for (Token *tok = _tokens; tok; tok = tok ? tok->next() : NULL) - { - if (tok->str() == "(") - { - tok = tok->link(); - continue; - } - - if (Token::Match(tok, "if|for|while (")) - { - // don't add "{}" around ";" in "do {} while();" (#609) - const Token *prev = tok->previous(); - if (Token::simpleMatch(prev, "} while") && - prev->link() && - prev->link()->previous() && - prev->link()->previous()->str() == "do") - { - continue; - } - - // Goto the ending ')' - tok = tok->next()->link(); - - // ')' should be followed by '{' - if (!tok || Token::simpleMatch(tok, ") {")) - continue; - } - - else if (tok->str() == "else") - { - // An else followed by an if or brace don't need to be processed further - if (Token::Match(tok, "else if|{")) - continue; - } - - else - { - continue; - } - - // If there is no code after he if(), abort - if (!tok->next()) - return; - - - // insert open brace.. - tok->insertToken("{"); - tok = tok->next(); - Token *tempToken = tok; - - bool innerIf = Token::simpleMatch(tempToken->next(), "if"); - - if (Token::simpleMatch(tempToken->next(), "do {")) - tempToken = tempToken->tokAt(2)->link(); - - // insert close brace.. - // In most cases it would work to just search for the next ';' and insert a closing brace after it. - // But here are special cases.. - // * if (cond) for (;;) break; - // * if (cond1) if (cond2) { } - // * if (cond1) if (cond2) ; else ; - while ((tempToken = tempToken->next()) != NULL) - { - if (tempToken->str() == "{") - { - if (Token::simpleMatch(tempToken->previous(),"else {")) - { - if (innerIf) - tempToken = tempToken->link(); - else - tempToken = tempToken->tokAt(-2); - break; - } - tempToken = tempToken->link(); - if (!tempToken || !tempToken->next()) - break; - if (tempToken->next()->isName() && tempToken->next()->str() != "else") - break; - continue; - } - - if (tempToken->str() == "(") - { - tempToken = tempToken->link(); - continue; - } - - if (tempToken->str() == "}") - { - // insert closing brace before this token - tempToken = tempToken->previous(); - break; - } - - if (tempToken->str() == ";") - { - if (!innerIf) - break; - - if (Token::simpleMatch(tempToken, "; else if")) - ; - else if (Token::simpleMatch(tempToken, "; else")) - innerIf = false; - else - break; - } - } - - if (tempToken) - { - tempToken->insertToken("}"); - Token::createMutualLinks(tok, tempToken->next()); - } - } -} - -bool Tokenizer::simplifyDoWhileAddBracesHelper(Token *tok) -{ - if (Token::Match(tok->next(), "[),]")) - { - // fix for #988 - return false; - } - - Token *tok1 = tok; // token with "do" - Token *tok2 = NULL; // token with "while" - Token *tok3 = tok->next(); - - // skip loop body - bool result = false; - while (tok3) - { - if (tok3->str() == "{") - { - // skip all tokens until "}" - tok3 = tok3->link(); - } - else if (tok3->str() == "while") - { - tok2 = tok3; - break; - } - else if (Token::simpleMatch(tok3, "do {")) - { - // Skip do{}while inside the current "do" - tok3 = tok3->next()->link(); - if (Token::simpleMatch(tok3->next(), "while")) - tok3 = tok3->next(); - } - else if (Token::Match(tok3, "do !!{") && - !Token::Match(tok3->next(), "[),]")) - { - // Handle do-while inside the current "do" - // first and return true to get the outer - // "do" to be handled later. - tok1 = tok3; - result = true; - } - - tok3 = tok3->next(); - } - - if (tok2) - { - // insert "{" after "do" - tok1->insertToken("{"); - - // insert "}" before "while" - tok2->previous()->insertToken("}"); - - Token::createMutualLinks(tok1->next(), tok2->previous()); - } - else - result = false; - - return result; -} - -void Tokenizer::simplifyDoWhileAddBraces() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "do !!{")) - { - while (simplifyDoWhileAddBracesHelper(tok)) - { - // Call until the function returns false to - // handle do-while inside do-while - - } - } - } -} - -void Tokenizer::simplifyCompoundAssignment() -{ - // Simplify compound assignments: - // "a+=b" => "a = a + b" - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "[;{}] (") || Token::Match(tok, "[;{}:] *| (| %var%")) - { - if (tok->str() == ":") - { - if (tok->strAt(-2) != "case") - continue; - } - - // backup current token.. - Token * const tok1 = tok; - - if (tok->strAt(1) == "*") - tok = tok->next(); - - if (tok->strAt(1) == "(") - { - tok = tok->next()->link()->next(); - } - else - { - // variable.. - tok = tok->tokAt(2); - while (Token::Match(tok, ". %var%") || - (tok && tok->str() == "[") || - Token::simpleMatch(tok, "( )")) - { - if (tok->str() != "[") - tok = tok->tokAt(2); - else if (tok->str() == "(") - tok = tok->tokAt(2); - else - { - // goto "]" - tok = tok->next(); - while (tok && !Token::Match(tok, "++|--|(|[|]")) - tok = tok->next(); - if (!tok) - break; - else if (tok->str() == "]") - tok = tok->next(); - else - break; - } - } - } - if (!tok) - break; - - // Is current token at a compound assignment: +=|-=|.. ? - const std::string &str = tok->str(); - std::string op; // operator used in assignment - if (str.size() == 2 && str[1] == '=' && str.find_first_of("+-*/%&|^")==0) - op = str.substr(0, 1); - else if (str=="<<=" || str==">>=") - op = str.substr(0, 2); - else - { - tok = tok1; - continue; - } - - // Remove the whole statement if it says: "+=0;", "-=0;", "*=1;" or "/=1;" - if (Token::Match(tok, "+=|-= 0 ;") || - Token::Match(tok, "+=|-= '\\0' ;") || - Token::simpleMatch(tok, "|= 0 ;") || - Token::Match(tok, "*=|/= 1 ;")) - { - tok = tok1; - while (tok->next()->str() != ";") - tok->deleteNext(); - } - else - { - // simplify the compound assignment.. - tok->str("="); - tok->insertToken(op); - std::stack tokend; - for (const Token *tok2 = tok->previous(); tok2 && tok2 != tok1; tok2 = tok2->previous()) - { - tok->insertToken(tok2->str()); - tok->next()->varId(tok2->varId()); - if (Token::Match(tok->next(), "]|)")) - tokend.push(tok->next()); - else if (Token::Match(tok->next(), "(|[")) - { - Token::createMutualLinks(tok->next(), tokend.top()); - tokend.pop(); - } - } - } - } - } -} - -void Tokenizer::simplifyConditionOperator() -{ - int parlevel = 0; - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "(") - ++parlevel; - else if (tok->str() == ")") - --parlevel; - else if (parlevel == 0 && Token::Match(tok, "; %var% = %var% ? %var% : %var% ;")) - { - const std::string var(tok->strAt(1)); - const std::string condition(tok->strAt(3)); - const std::string value1(tok->strAt(5)); - const std::string value2(tok->strAt(7)); - - Token::eraseTokens(tok, tok->tokAt(9)); - - std::string str("if ( " + condition + " ) { " + var + " = " + value1 + " ; } else { " + var + " = " + value2 + " ; }"); - std::string::size_type pos1 = 0; - while (pos1 != std::string::npos) - { - std::string::size_type pos2 = str.find(" ", pos1); - if (pos2 == std::string::npos) - { - tok->insertToken(str.substr(pos1).c_str()); - pos1 = pos2; - } - else - { - tok->insertToken(str.substr(pos1, pos2 - pos1).c_str()); - pos1 = pos2 + 1; - } - tok = tok->next(); - } - - Token::createMutualLinks(tok->tokAt(-15), tok->tokAt(-13)); - Token::createMutualLinks(tok->tokAt(-12), tok->tokAt(-7)); - Token::createMutualLinks(tok->tokAt(-5), tok); - } - } -} - -bool Tokenizer::simplifyConditions() -{ - bool ret = false; - - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "! %num%") || Token::Match(tok, "! %bool%")) - { - if (tok->next()->str() == "0" || tok->next()->str() == "false") - tok->str("true"); - else - tok->str("false"); - - tok->deleteNext(); - ret = true; - } - - if (Token::simpleMatch(tok, "( true &&") || - Token::simpleMatch(tok, "&& true &&") || - Token::simpleMatch(tok->next(), "&& true )")) - { - Token::eraseTokens(tok, tok->tokAt(3)); - ret = true; - } - - else if (Token::simpleMatch(tok, "( false ||") || - Token::simpleMatch(tok, "|| false ||") || - Token::simpleMatch(tok->next(), "|| false )")) - { - Token::eraseTokens(tok, tok->tokAt(3)); - ret = true; - } - - else if (Token::simpleMatch(tok, "( true ||") || - Token::simpleMatch(tok, "( false &&")) - { - Token::eraseTokens(tok->next(), tok->link()); - ret = true; - } - - else if (Token::simpleMatch(tok, "|| true )") || - Token::simpleMatch(tok, "&& false )")) - { - tok = tok->next(); - Token::eraseTokens(tok->next()->link(), tok); - ret = true; - } - - // Change numeric constant in condition to "true" or "false" - if (Token::Match(tok, "if|while ( %num%") && - (tok->tokAt(3)->str() == ")" || tok->tokAt(3)->str() == "||" || tok->tokAt(3)->str() == "&&")) - { - tok->tokAt(2)->str((tok->tokAt(2)->str() != "0") ? "true" : "false"); - ret = true; - } - Token *tok2 = tok->tokAt(2); - if (tok2 && - (tok->str() == "&&" || tok->str() == "||") && - Token::Match(tok->next(), "%num%") && - (tok2->str() == ")" || tok2->str() == "&&" || tok2->str() == "||")) - { - tok->next()->str((tok->next()->str() != "0") ? "true" : "false"); - ret = true; - } - - // Reduce "(%num% == %num%)" => "(true)"/"(false)" - const Token *tok4 = tok->tokAt(4); - if (! tok4) - break; - if ((tok->str() == "&&" || tok->str() == "||" || tok->str() == "(") && - (Token::Match(tok->tokAt(1), "%num% %any% %num%") || - Token::Match(tok->tokAt(1), "%bool% %any% %bool%")) && - (tok4->str() == "&&" || tok4->str() == "||" || tok4->str() == ")" || tok4->str() == "?")) - { - std::string cmp = tok->strAt(2); - bool result = false; - if (Token::Match(tok->tokAt(1), "%num%")) - { - // Compare numbers - - if (cmp == "==" || cmp == "!=") - { - const std::string op1(tok->strAt(1)); - const std::string op2(tok->strAt(3)); - - bool eq = false; - if (MathLib::isInt(op1) && MathLib::isInt(op2)) - eq = (MathLib::toLongNumber(op1) == MathLib::toLongNumber(op2)); - else - eq = (op1 == op2); - - if (cmp == "==") - result = eq; - else - result = !eq; - } - else - { - double op1 = MathLib::toDoubleNumber(tok->strAt(1)); - double op2 = MathLib::toDoubleNumber(tok->strAt(3)); - if (cmp == ">=") - result = (op1 >= op2); - else if (cmp == ">") - result = (op1 > op2); - else if (cmp == "<=") - result = (op1 <= op2); - else if (cmp == "<") - result = (op1 < op2); - else - cmp = ""; - } - } - else - { - // Compare boolean - bool op1 = (tok->strAt(1) == std::string("true")); - bool op2 = (tok->strAt(3) == std::string("true")); - - if (cmp == "==") - result = (op1 == op2); - else if (cmp == "!=") - result = (op1 != op2); - else if (cmp == ">=") - result = (op1 >= op2); - else if (cmp == ">") - result = (op1 > op2); - else if (cmp == "<=") - result = (op1 <= op2); - else if (cmp == "<") - result = (op1 < op2); - else - cmp = ""; - } - - if (! cmp.empty()) - { - tok = tok->next(); - tok->deleteNext(); - tok->deleteNext(); - - tok->str(result ? "true" : "false"); - ret = true; - } - } - } - - return ret; -} - -bool Tokenizer::simplifyQuestionMark() -{ - bool ret = false; - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() != "?") - continue; - - if (!tok->tokAt(-2)) - continue; - - if (!Token::Match(tok->tokAt(-2), "[=,(]")) - continue; - - if (!Token::Match(tok->previous(), "%bool%") && - !Token::Match(tok->previous(), "%num%")) - continue; - - // Find the ":" token.. - Token *semicolon = 0; - { - unsigned int parlevel = 0; - for (Token *tok2 = tok; tok2; tok2 = tok2->next()) - { - if (tok2->str() == "(") - ++parlevel; - else if (tok2->str() == ")") - { - if (parlevel == 0) - break; - --parlevel; - } - else if (parlevel == 0 && tok2->str() == ":") - { - semicolon = tok2; - break; - } - } - } - if (!semicolon || !semicolon->next()) - continue; - - if (tok->previous()->str() == "false" || - tok->previous()->str() == "0") - { - // Use code after semicolon, remove code before it. - semicolon = semicolon->next(); - tok = tok->tokAt(-2); - Token::eraseTokens(tok, semicolon); - - tok = tok->next(); - ret = true; - } - - // The condition is true. Delete the operator after the ":".. - else - { - const Token *end = 0; - - // check the operator after the : - if (Token::simpleMatch(semicolon, ": (")) - { - end = semicolon->next()->link(); - if (!Token::Match(end, ") !!.")) - continue; - } - - // delete the condition token and the "?" - tok = tok->tokAt(-2); - Token::eraseTokens(tok, tok->tokAt(3)); - - // delete operator after the : - if (end) - { - Token::eraseTokens(semicolon->previous(), end->next()); - continue; - } - - int ind = 0; - for (const Token *endTok = semicolon; endTok; endTok = endTok->next()) - { - if (endTok->str() == ";") - { - Token::eraseTokens(semicolon->previous(), endTok); - ret = true; - break; - } - - else if (Token::Match(endTok, "[({[]")) - { - ++ind; - } - - else if (Token::Match(endTok, "[)}]]")) - { - --ind; - if (ind < 0) - { - Token::eraseTokens(semicolon->previous(), endTok); - ret = true; - break; - } - } - } - } - } - - return ret; -} - -void Tokenizer::simplifyCasts() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - while (Token::Match(tok->next(), "( %type% *| ) *|&| %var%") || - Token::Match(tok->next(), "( %type% %type% *| ) *|&| %var%") || - (!tok->isName() && (Token::Match(tok->next(), "( %type% * ) (") || - Token::Match(tok->next(), "( %type% %type% * ) (")))) - { - if (tok->isName() && tok->str() != "return") - break; - - if (Token::simpleMatch(tok->previous(), "operator")) - break; - - // Remove cast.. - Token::eraseTokens(tok, tok->next()->link()->next()); - - if (tok->str() == ")" && tok->link()->previous()) - { - // If there was another cast before this, go back - // there to check it also. e.g. "(int)(char)x" - tok = tok->link()->previous(); - } - } - - // Replace pointer casts of 0.. "(char *)0" => "0" - while (Token::Match(tok->next(), "( %type% * ) 0") || - Token::Match(tok->next(), "( %type% %type% * ) 0")) - { - Token::eraseTokens(tok, tok->next()->link()->next()); - if (tok->str() == ")" && tok->link()->previous()) - { - // If there was another cast before this, go back - // there to check it also. e.g. "(char*)(char*)0" - tok = tok->link()->previous(); - } - } - - while (Token::Match(tok->next(), "dynamic_cast|reinterpret_cast|const_cast|static_cast <")) - { - Token *tok2 = tok->next(); - unsigned int level = 0; - while (tok2) - { - if (tok2->str() == "<") - ++level; - else if (tok2->str() == ">") - { - --level; - if (level == 0) - break; - } - tok2 = tok2->next(); - } - - if (Token::simpleMatch(tok2, "> (")) - { - Token *closeBracket = tok2->next()->link(); - if (closeBracket) - { - Token::eraseTokens(tok, tok2->tokAt(2)); - closeBracket->deleteThis(); - } - else - { - break; - } - } - else - { - break; - } - } - } -} - - -void Tokenizer::simplifyFunctionParameters() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "{" || tok->str() == "[" || tok->str() == "(") - { - tok = tok->link(); - if (!tok) - break; - continue; - } - - // Find the function e.g. foo( x ) or foo( x, y ) - if (Token::Match(tok, "%var% ( %var% [,)]")) - { - // We have found old style function, now we need to change it - - // backup pointer to the '(' token - Token * const tok1 = tok->next(); - - // Get list of argument names - std::map argumentNames; - bool bailOut = false; - for (tok = tok->tokAt(2); tok; tok = tok->tokAt(2)) - { - if (!Token::Match(tok, "%var% [,)]")) - { - bailOut = true; - break; - } - - if (argumentNames.find(tok->str()) != argumentNames.end()) - { - // Invalid code, two arguments with the same name. - // TODO, print error perhaps? - bailOut = true; - break; - } - - argumentNames[tok->str()] = tok; - if (tok->next()->str() == ")") - { - tok = tok->tokAt(2); - break; - } - } - - if (bailOut) - { - tok = tok1->link(); - if (!tok) - return; - continue; - } - - Token *start = tok; - while (tok && tok->str() != "{") - { - if (tok->str() == ";") - { - tok = tok->previous(); - // Move tokens from start to tok into the place of - // argumentNames[tok->str()] and remove the ";" - - if (argumentNames.find(tok->str()) == argumentNames.end()) - { - bailOut = true; - break; - } - - // Remove the following ";" - Token *temp = tok->tokAt(2); - tok->deleteNext(); - - // Replace "x" with "int x" or similar - Token::replace(argumentNames[tok->str()], start, tok); - argumentNames.erase(tok->str()); - tok = temp; - start = tok; - } - else - { - tok = tok->next(); - } - } - - if (Token::simpleMatch(tok, "{")) - tok = tok->link(); - - if (tok == NULL) - { - break; - } - - if (bailOut) - { - continue; - } - } - } -} - - -void Tokenizer:: simplifyFunctionPointers() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - // check for function pointer cast - if (Token::Match(tok, "( %type% *| *| ( * ) (") || - Token::Match(tok, "( %type% %type% *| *| ( * ) (") || - Token::Match(tok, "static_cast < %type% *| *| ( * ) (") || - Token::Match(tok, "static_cast < %type% %type% *| *| ( * ) (")) - { - Token *tok1 = tok; - - if (tok1->str() == "static_cast") - tok1 = tok1->next(); - - tok1 = tok1->next(); - - if (Token::Match(tok1->next(), "%type%")) - tok1 = tok1->next(); - - while (tok1->next()->str() == "*") - tok1 = tok1->next(); - - // check that the cast ends - if (!Token::Match(tok1->tokAt(4)->link(), ") )|>")) - continue; - - // ok simplify this function pointer cast to an ordinary pointer cast - tok1->deleteNext(); - tok1->next()->deleteNext(); - const Token *tok2 = tok1->tokAt(2)->link(); - Token::eraseTokens(tok1->next(), tok2 ? tok2->next() : 0); - continue; - } - - // check for start of statement - else if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|(|public:|protected:|private:")) - continue; - - if (Token::Match(tok, "%type% *| *| ( * %var% ) (")) - ; - else if (Token::Match(tok, "%type% %type% *| *| ( * %var% ) (")) - tok = tok->next(); - else - continue; - - while (tok->next()->str() == "*") - tok = tok->next(); - - // check that the declaration ends - if (!Token::Match(tok->tokAt(5)->link(), ") ;|,|)|=")) - continue; - - // ok simplify this function pointer to an ordinary pointer - tok->deleteNext(); - tok->tokAt(2)->deleteNext(); - const Token *tok2 = tok->tokAt(3)->link(); - Token::eraseTokens(tok->tokAt(2), tok2 ? tok2->next() : 0); - } -} - - -bool Tokenizer::simplifyFunctionReturn() -{ - bool ret = false; - int indentlevel = 0; - for (const Token *tok = tokens(); tok; tok = tok->next()) - { - if (tok->str() == "{") - ++indentlevel; - - else if (tok->str() == "}") - --indentlevel; - - else if (indentlevel == 0 && Token::Match(tok, "%var% ( ) { return %num% ; }") && tok->str() != ")") - { - std::ostringstream pattern; - pattern << "[(=+-*/] " << tok->str() << " ( ) [;)+-*/]"; - for (Token *tok2 = _tokens; tok2; tok2 = tok2->next()) - { - if (Token::Match(tok2, pattern.str().c_str())) - { - tok2 = tok2->next(); - tok2->str(tok->strAt(5)); - tok2->deleteNext(); - tok2->deleteNext(); - ret = true; - } - } - } - } - - return ret; -} - - -static void incdec(std::string &value, const std::string &op) -{ - int ivalue = 0; - std::istringstream istr(value.c_str()); - istr >> ivalue; - if (op == "++") - ++ivalue; - else if (op == "--") - --ivalue; - std::ostringstream ostr; - ostr << ivalue; - value = ostr.str(); -} - - - -void Tokenizer::simplifyVarDecl() -{ - // Split up variable declarations.. - // "int a=4;" => "int a; a=4;" - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::simpleMatch(tok, "= {")) - { - tok = tok->next()->link(); - if (!tok) - break; - } - - if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|)|public:|protected:|private:")) - continue; - - Token *type0 = tok; - if (!Token::Match(type0, "%type%")) - continue; - if (Token::Match(type0, "else|return|public:|protected:|private:")) - continue; - - bool isconst = false; - bool isstatic = false; - Token *tok2 = type0; - unsigned int typelen = 1; - - while (Token::Match(tok2, "%type% %type% *| *| %var%")) - { - if (tok2->str() == "const") - isconst = true; - - else if (tok2->str() == "static") - isstatic = true; - - tok2 = tok2->next(); - ++typelen; - } - - // Don't split up const declaration.. - if (isconst && Token::Match(tok2, "%type% %var% =")) - continue; - - // strange looking variable declaration => don't split up. - if (Token::Match(tok2, "%type% *| %var% , %type% *| %var%")) - continue; - - if (Token::Match(tok2, "%type% *| %var% ,|=")) - { - const bool isPointer = (tok2->next()->str() == "*"); - const Token *varName = tok2->tokAt((isPointer ? 2 : 1)); - Token *endDeclaration = varName->next(); - - if (varName->str() != "operator") - { - tok2 = endDeclaration; // The ',' or '=' token - - if (isstatic && tok2->str() == "=") - { - if (Token::Match(tok2->next(), "%num% ,")) - tok2 = tok2->tokAt(2); - else - tok2 = NULL; - } - } - else - tok2 = NULL; - } - - else if (Token::Match(tok2, "%type% * * %var% ,|=")) - { - if (tok2->tokAt(3)->str() != "operator") - tok2 = tok2->tokAt(4); // The ',' token - else - tok2 = NULL; - } - - else if (Token::Match(tok2, "%type% * const %var% ,|=")) - { - if (tok2->tokAt(3)->str() != "operator") - { - tok2 = tok2->tokAt(4); // The ',' token - } - else - { - tok2 = NULL; - } - } - - else if (Token::Match(tok2, "%type% %var% [ %num% ] ,|=|[") || - Token::Match(tok2, "%type% %var% [ %var% ] ,|=|[")) - { - tok2 = tok2->tokAt(5); // The ',' token - while (Token::Match(tok2, "[ %num% ]") || Token::Match(tok2, "[ %var% ]")) - tok2 = tok2->tokAt(3); - if (!Token::Match(tok2, "=|,")) - { - tok2 = NULL; - } - - if (tok2 && tok2->str() == "=") - { - while (tok2 && tok2->str() != ",") - { - if (tok2->str() == "{") - tok2 = tok2->link(); - - tok2 = tok2->next(); - - if (tok2->str() == ";") - tok2 = NULL; - } - } - } - - else if (Token::Match(tok2, "%type% * %var% [ %num% ] ,") || - Token::Match(tok2, "%type% * %var% [ %var% ] ,")) - { - tok2 = tok2->tokAt(6); // The ',' token - } - - else if (Token::Match(tok2, "std :: %type% <") || Token::Match(tok2, "%type% <")) - { - // - // Deal with templates and standart types - // - if (Token::simpleMatch(tok2, "std ::")) - { - typelen += 2; - tok2 = tok2->tokAt(2); - } - - typelen += 2; - tok2 = tok2->tokAt(2); - size_t indentlevel = 1; - - for (Token *tok3 = tok2; tok3; tok3 = tok3->next()) - { - ++typelen; - - if (tok3->str() == "<") - { - ++indentlevel; - } - else if (tok3->str() == ">") - { - --indentlevel; - if (indentlevel == 0) - { - tok2 = tok3->next(); - break; - } - } - else if (tok3->str() == ";") - { - break; - } - } - - if (!tok2) - break; - - if (Token::Match(tok2, ":: %type%")) - { - typelen += 2; - tok2 = tok2->tokAt(2); - } - - if (tok2->str() == "*" || tok2->str() == "&") - { - tok2 = tok2->next(); - } - - if (Token::Match(tok2, "%var% ,")) - { - tok2 = tok2->next(); // The ',' token - typelen--; - } - else - { - tok2 = NULL; - typelen = 0; - } - } - else - { - tok2 = NULL; - typelen = 0; - } - - - if (tok2) - { - if (tok2->str() == ",") - { - tok2->str(";"); - insertTokens(tok2, type0, typelen); - std::stack link1; - std::stack link2; - while (((typelen--) > 0) && (0 != (tok2 = tok2->next()))) - { - if (tok2->str() == "(") - link1.push(tok2); - else if (tok2->str() == ")" && !link1.empty()) - { - Token::createMutualLinks(tok2, link1.top()); - link1.pop(); - } - - else if (tok2->str() == "[") - link2.push(tok2); - else if (tok2->str() == "]" && !link2.empty()) - { - Token::createMutualLinks(tok2, link2.top()); - link2.pop(); - } - } - } - - else - { - Token *eq = tok2; - - unsigned int level = 0; - while (tok2) - { - if (Token::Match(tok2, "[{(]")) - tok2 = tok2->link(); - - else if (tok2->str() == "<") - { - if (tok2->previous()->isName() && !tok2->previous()->varId()) - ++level; - } - - else if (level > 0 && tok2->str() == ">") - --level; - - else if (level == 0 && strchr(";,", tok2->str()[0])) - { - // "type var =" => "type var; var =" - Token *VarTok = type0->tokAt((int)typelen); - while (Token::Match(VarTok, "*|const")) - VarTok = VarTok->next(); - insertTokens(eq, VarTok, 2); - eq->str(";"); - - // "= x, " => "= x; type " - if (tok2->str() == ",") - { - tok2->str(";"); - insertTokens(tok2, type0, typelen); - } - break; - } - - tok2 = tok2->next(); - } - } - } - } -} - -void Tokenizer::simplifyStdType() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - // long unsigned => unsigned long - if (Token::Match(tok, "char|short|int|long|__int8|__int16|__int32|__int64 unsigned|signed")) - { - std::string temp = tok->str(); - tok->str(tok->next()->str()); - tok->next()->str(temp); - } - - if (!Token::Match(tok, "unsigned|signed|char|short|int|long|__int8|__int16|__int32|__int64")) - continue; - - // check if signed or unsigned specified - if (Token::Match(tok, "unsigned|signed")) - { - bool isUnsigned = tok->str() == "unsigned"; - - // unsigned i => unsigned int i - if (!Token::Match(tok->next(), "char|short|int|long|__int8|__int16|__int32|__int64")) - tok->str("int"); - else - tok->deleteThis(); - tok->isUnsigned(isUnsigned); - tok->isSigned(!isUnsigned); - } - - if (Token::simpleMatch(tok, "__int8")) - tok->str("char"); - else if (Token::simpleMatch(tok, "__int16")) - tok->str("short"); - else if (Token::simpleMatch(tok, "__int32")) - tok->str("int"); - else if (Token::simpleMatch(tok, "__int64")) - { - tok->str("long"); - tok->isLong(true); - } - else if (Token::simpleMatch(tok, "long")) - { - if (Token::simpleMatch(tok->next(), "long")) - { - tok->isLong(true); - tok->deleteNext(); - } - - if (Token::simpleMatch(tok->next(), "int")) - tok->deleteNext(); - else if (Token::simpleMatch(tok->next(), "double")) - { - tok->str("double"); - tok->isLong(true); - tok->deleteNext(); - } - } - else if (Token::simpleMatch(tok, "short")) - { - if (Token::simpleMatch(tok->next(), "int")) - tok->deleteNext(); - } - } -} - -void Tokenizer::simplifyIfAssign() -{ - // See also simplifyFunctionAssign - - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (!Token::Match(tok->next(), "if|while ( !| (| %var% =") && - !Token::Match(tok->next(), "if|while ( !| (| %var% . %var% =")) - continue; - - // simplifying a "while" condition ? - const bool iswhile(tok->next()->str() == "while"); - - // delete the "if" - tok->deleteNext(); - - // Remember if there is a "!" or not. And delete it if there are. - const bool isNot(tok->tokAt(2)->str() == "!"); - if (isNot) - tok->next()->deleteNext(); - - // Delete parenthesis.. and remember how many there are with - // their links. - std::stack braces; - while (tok->next()->str() == "(") - { - braces.push(tok->next()->link()); - tok->deleteNext(); - } - - // Skip the "%var% = ..." - Token *tok2; - unsigned int indentlevel = 0; - for (tok2 = tok->next(); tok2; tok2 = tok2->next()) - { - if (tok2->str() == "(") - ++indentlevel; - else if (tok2->str() == ")") - { - if (indentlevel <= 0) - break; - --indentlevel; - } - } - - // Insert "; if|while ( .." - tok2 = tok2->previous(); - if (Token::simpleMatch(tok->tokAt(2), ".")) - { - tok2->insertToken(tok->strAt(3)); - tok2->insertToken(tok->strAt(2)); - } - tok2->insertToken(tok->strAt(1)); - tok2->next()->varId(tok->tokAt(1)->varId()); - - while (! braces.empty()) - { - tok2->insertToken("("); - Token::createMutualLinks(tok2->next(), braces.top()); - braces.pop(); - } - - if (isNot) - tok2->next()->insertToken("!"); - tok2->insertToken(iswhile ? "while" : "if"); - tok2->insertToken(";"); - - // If it's a while loop.. insert the assignment in the loop - if (iswhile) - { - indentlevel = 0; - Token *tok3 = tok2; - for (tok3 = tok2; tok3; tok3 = tok3->next()) - { - if (tok3->str() == "{") - ++indentlevel; - else if (tok3->str() == "}") - { - if (indentlevel <= 1) - break; - --indentlevel; - } - } - - if (tok3 && indentlevel == 1) - { - tok3 = tok3->previous(); - std::stack braces2; - - for (tok2 = tok2->next(); tok2 && tok2 != tok; tok2 = tok2->previous()) - { - tok3->insertToken(tok2->str()); - - Token *newTok = tok3->next(); - newTok->fileIndex(tok2->fileIndex()); - newTok->linenr(tok2->linenr()); - - // link() newly tokens manually - if (Token::Match(newTok, "}|)|]")) - { - braces2.push(newTok); - } - else if (Token::Match(newTok, "{|(|[")) - { - Token::createMutualLinks(newTok, braces2.top()); - braces2.pop(); - } - } - } - } - } -} - - -void Tokenizer::simplifyVariableMultipleAssign() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "%var% = %var% = %num% ;") || - Token::Match(tok, "%var% = %var% = %var% ;")) - { - - // skip intermediate assignments - Token *tok2 = tok->previous(); - while (tok2 && - tok2->str() == "=" && - Token::Match(tok2->previous(), "%var%")) - { - tok2 = tok2->tokAt(-2); - } - - if (tok2->str() != ";") - { - continue; - } - - Token *stopAt = tok->tokAt(2); - const Token *valueTok = tok->tokAt(4); - const std::string value(valueTok->str()); - tok2 = tok2->next(); - - while (tok2 != stopAt) - { - tok2->next()->insertToken(";"); - tok2->next()->insertToken(value); - tok2 = tok2->tokAt(4); - } - } - } -} - - -void Tokenizer::simplifyIfNot() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "(" || tok->str() == "||" || tok->str() == "&&") - { - tok = tok->next(); - while (tok && tok->str() == "(") - tok = tok->next(); - - if (!tok) - break; - - if (Token::Match(tok, "0|false == (") || - Token::Match(tok, "0|false == %var%")) - { - tok->deleteNext(); - tok->str("!"); - } - - else if (Token::Match(tok, "%var% == 0|false")) - { - tok->deleteNext(); - tok->next()->str(tok->str()); - tok->str("!"); - } - - else if (Token::Match(tok, "%var% .|:: %var% == 0|false")) - { - tok = tok->previous(); - tok->insertToken("!"); - tok = tok->tokAt(4); - Token::eraseTokens(tok, tok->tokAt(3)); - } - - else if (Token::Match(tok, "* %var% == 0|false")) - { - tok = tok->previous(); - tok->insertToken("!"); - tok = tok->tokAt(3); - Token::eraseTokens(tok, tok->tokAt(3)); - } - } - - else if (tok->link() && Token::Match(tok, ") == 0|false")) - { - Token::eraseTokens(tok, tok->tokAt(3)); - if (Token::Match(tok->link()->previous(), "%var%")) - { - // if( foo(x) == 0 ) - tok->link()->previous()->insertToken(tok->link()->previous()->str().c_str()); - tok->link()->previous()->previous()->str("!"); - } - else - { - // if( (x) == 0 ) - tok->link()->insertToken("("); - tok->link()->str("!"); - Token *temp = tok->link(); - Token::createMutualLinks(tok->link()->next(), tok); - temp->link(0); - } - } - } -} - - -void Tokenizer::simplifyIfNotNull() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - Token *deleteFrom = NULL; - - if (tok->str() == "(" || tok->str() == "||" || tok->str() == "&&") - { - tok = tok->next(); - - if (!tok) - break; - - if (Token::simpleMatch(tok, "0 != (") || - Token::Match(tok, "0 != %var%")) - { - deleteFrom = tok->previous(); - } - - else if (Token::Match(tok, "%var% != 0")) - { - deleteFrom = tok; - } - - else if (Token::Match(tok, "%var% .|:: %var% != 0")) - { - tok = tok->tokAt(2); - deleteFrom = tok; - } - } - - else if (tok->link() && Token::simpleMatch(tok, ") != 0")) - { - deleteFrom = tok; - } - - if (deleteFrom) - { - Token::eraseTokens(deleteFrom, deleteFrom->tokAt(3)); - tok = deleteFrom; - } - } -} - - -void Tokenizer::simplifyIfSameInnerCondition() -{ - // same inner condition - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "if ( %var% ) {")) - { - const unsigned int varid(tok->tokAt(2)->varId()); - if (!varid) - continue; - - for (Token *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next()) - { - if (tok2->str() == "{" || tok2->str() == "}") - break; - if (Token::simpleMatch(tok2, "if (")) - { - tok2 = tok2->tokAt(2); - if (Token::Match(tok2, "%varid% )", varid)) - tok2->str("true"); - else if (Token::Match(tok2, "! %varid% )", varid)) - tok2->next()->varId(varid); - break; - } - } - } - } -} - - -bool Tokenizer::simplifyLogicalOperators() -{ - bool ret = false; - - // "if (not p)" => "if (!p)" - // "if (p and q)" => "if (p && q)" - // "if (p or q)" => "if (p || q)" - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "if|while ( not|compl %var%")) - { - tok->tokAt(2)->str(tok->strAt(2) == "not" ? "!" : "~"); - ret = true; - } - else if (Token::Match(tok, "&& not|compl %var%")) - { - tok->next()->str(tok->strAt(1) == "not" ? "!" : "~"); - ret = true; - } - else if (Token::Match(tok, "|| not|compl %var%")) - { - tok->next()->str(tok->strAt(1) == "not" ? "!" : "~"); - ret = true; - } - // "%var%|) and %var%|(" - else if (Token::Match(tok->previous(), "%any% %var% %any%")) - { - if (!Token::Match(tok, "and|or|bitand|bitor|xor|not_eq")) - continue; - - const Token *tok2 = tok; - while (0 != (tok2 = tok2->previous())) - { - if (tok2->str() == ")") - tok2 = tok2->link(); - else if (Token::Match(tok2, "(|;|{|}")) - break; - } - if (tok2 && Token::Match(tok2->previous(), "if|while (")) - { - if (tok->str() == "and") - tok->str("&&"); - else if (tok->str() == "or") - tok->str("||"); - else if (tok->str() == "bitand") - tok->str("&"); - else if (tok->str() == "bitor") - tok->str("|"); - else if (tok->str() == "xor") - tok->str("^"); - else if (tok->str() == "not_eq") - tok->str("!="); - ret = true; - } - } - } - return ret; -} - -// int i(0); => int i; i = 0; -// int i(0), j; => int i; i = 0; int j; -void Tokenizer::simplifyInitVar() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (!tok->isName() || (tok->previous() && !Token::Match(tok->previous(), "[;{}]"))) - continue; - - if (Token::Match(tok, "class|struct|union| %type% *| %var% ( &| %any% ) ;") || - Token::Match(tok, "%type% *| %var% ( %type% (")) - { - tok = initVar(tok); - } - else if (Token::Match(tok, "class|struct|union| %type% *| %var% ( &| %any% ) ,")) - { - Token *tok1 = tok; - while (tok1->str() != ",") - tok1 = tok1->next(); - tok1->str(";"); - Token *tok2 = tok; - if (Token::Match(tok2, "class|struct|union")) - { - tok1->insertToken(tok2->str()); - tok1 = tok1->next(); - tok2 = tok2->next(); - } - tok1->insertToken(tok2->str()); - tok1 = tok1->next(); - tok2 = tok2->next(); - if (tok2->str() == "*") - { - tok1->insertToken("*"); - } - tok = initVar(tok); - } - } -} - -static bool isOp(const Token *tok) -{ - return bool(tok && - (tok->str() == "&&" || - tok->str() == "||" || - tok->str() == "==" || - tok->str() == "!=" || - tok->str() == "<" || - tok->str() == "<=" || - tok->str() == ">" || - tok->str() == ">=" || - tok->str() == "<<" || - tok->str() == ">>" || - Token::Match(tok, "[;+-*/%&|^]"))); -} - -Token * Tokenizer::initVar(Token * tok) -{ - // call constructor of class => no simplification - if (Token::Match(tok, "class|struct|union")) - { - if (tok->tokAt(2)->str() != "*") - return tok; - - tok = tok->next(); - } - else if (!tok->isStandardType() && tok->tokAt(1)->str() != "*") - return tok; - - // goto variable name.. - tok = tok->next(); - if (tok->str() == "*") - tok = tok->next(); - - // sizeof is not a variable name.. - if (tok->str() == "sizeof") - return tok; - - // check initializer.. - if (tok->tokAt(2)->isStandardType() || tok->tokAt(2)->str() == "void") - return tok; - else if (!tok->tokAt(2)->isNumber() && !Token::Match(tok->tokAt(2), "%type% (") && tok->tokAt(2)->str() != "&" && tok->tokAt(2)->varId() == 0) - return tok; - - // insert '; var =' - tok->insertToken(";"); - tok->next()->insertToken(tok->str()); - tok->tokAt(2)->varId(tok->varId()); - tok = tok->tokAt(2); - tok->insertToken("="); - - // goto '('.. - tok = tok->tokAt(2); - - // delete ')' - tok->link()->deleteThis(); - - // delete this - tok->deleteThis(); - - return tok; -} - - -bool Tokenizer::simplifyKnownVariables() -{ - // return value for function. Set to true if any simplifications are made - bool ret = false; - - // constants.. - { - std::map constantValues; - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "static| const static| %type% %var% = %any% ;")) - { - Token *tok1 = tok; - - // start of statement - if (tok != _tokens && !Token::Match(tok->previous(),"[;{}]")) - continue; - // skip "const" and "static" - while (tok->str() == "const" || tok->str() == "static") - tok = tok->next(); - // pod type - if (!tok->isStandardType()) - continue; - - const Token * const vartok = tok->next(); - const Token * const valuetok = tok->tokAt(3); - if (valuetok->isNumber() || Token::Match(valuetok, "%str% ;")) - { - constantValues[vartok->varId()] = valuetok->str(); - - // remove statement - while (tok1->str() != ";") - tok1->deleteThis(); - tok = tok1; - } - } - - else if (tok->varId() && constantValues.find(tok->varId()) != constantValues.end()) - { - tok->str(constantValues[tok->varId()]); - } - } - } - - // variable id for float/double variables - std::set floatvars; - - // auto variables.. - for (Token *tok = _tokens; tok; tok = tok->next()) - { - // Search for a block of code - if (! Token::Match(tok, ") const| {")) - continue; - - // parse the block of code.. - int indentlevel = 0; - Token *tok2 = tok; - for (; tok2; tok2 = tok2->next()) - { - if (Token::Match(tok2, "[;{}] float|double %var% ;")) - { - floatvars.insert(tok2->tokAt(2)->varId()); - } - - if (tok2->str() == "{") - ++indentlevel; - - else if (tok2->str() == "}") - { - --indentlevel; - if (indentlevel <= 0) - break; - } - - else if (tok2->previous()->str() != "*" && - (Token::Match(tok2, "%var% = %num% ;") || - Token::Match(tok2, "%var% = %str% ;") || - (Token::Match(tok2, "%var% = %any% ;") && tok2->strAt(2)[0] == '\'') || - Token::Match(tok2, "%var% [ ] = %str% ;") || - Token::Match(tok2, "%var% [ %num% ] = %str% ;") || - Token::Match(tok2, "%var% = %bool% ;") || - Token::Match(tok2, "%var% = %var% ;") || - Token::Match(tok2, "%var% = & %var% ;") || - Token::Match(tok2, "%var% = & %var% [ 0 ] ;"))) - { - const unsigned int varid = tok2->varId(); - if (varid == 0) - continue; - - // skip loop variable - if (Token::Match(tok2->tokAt(-2), "(|:: %type%")) - { - const Token *tok3 = tok2->previous(); - while (Token::Match(tok3->previous(), ":: %type%")) - tok3 = tok3->tokAt(-2); - if (Token::Match(tok3->tokAt(-2), "for ( %type%")) - continue; - } - - // struct name.. - const std::string structname = Token::Match(tok2->tokAt(-3), "[;{}] %var% .") ? - std::string(tok2->strAt(-2) + " .") : - std::string(""); - - if (tok2->str() == tok2->strAt(2)) - continue; - - const Token * const valueToken = tok2->tokAt(2); - - std::string value; - unsigned int valueVarId = 0; - - Token *tok3 = NULL; - bool valueIsPointer = false; - - if (!simplifyKnownVariablesGetData(varid, &tok2, &tok3, value, valueVarId, valueIsPointer, floatvars.find(tok2->varId()) != floatvars.end())) - continue; - - ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel); - } - - else if (Token::Match(tok2, "strcpy ( %var% , %str% ) ;")) - { - const unsigned int varid(tok2->tokAt(2)->varId()); - if (varid == 0) - continue; - const std::string structname(""); - const Token * const valueToken = tok2->tokAt(4); - std::string value(valueToken->str()); - const unsigned int valueVarId(0); - const bool valueIsPointer(false); - Token *tok3 = tok2; - for (int i = 0; i < 6; ++i) - tok3 = tok3->next(); - ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel); - } - } - - if (tok2) - tok = tok2->previous(); - } - - return ret; -} - -bool Tokenizer::simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2, Token **_tok3, std::string &value, unsigned int &valueVarId, bool &valueIsPointer, bool floatvar) -{ - Token *tok2 = *_tok2; - Token *tok3 = *_tok3; - - if (Token::Match(tok2->tokAt(-2), "for ( %varid% = %num% ; %varid% <|<= %num% ; ++| %varid% ++| ) {", varid)) - { - // is there a "break" in the for loop? - bool hasbreak = false; - unsigned int indentlevel4 = 0; // indentlevel for tok4 - for (const Token *tok4 = tok2->previous()->link(); tok4; tok4 = tok4->next()) - { - if (tok4->str() == "{") - ++indentlevel4; - else if (tok4->str() == "}") - { - if (indentlevel4 <= 1) - break; - --indentlevel4; - } - else if (tok4->str() == "break") - { - hasbreak = true; - break; - } - } - if (hasbreak) - return false; - - // no break => the value of the counter value is known after the for loop.. - const std::string compareop = tok2->strAt(5); - if (compareop == "<") - { - value = tok2->strAt(6); - valueVarId = tok2->tokAt(6)->varId(); - } - else - value = MathLib::toString(MathLib::toLongNumber(tok2->strAt(6)) + 1); - - // Skip for-body.. - tok3 = tok2->previous()->link()->next()->link()->next(); - } - else - { - value = tok2->strAt(2); - valueVarId = tok2->tokAt(2)->varId(); - if (Token::simpleMatch(tok2->next(), "[")) - { - value = tok2->next()->link()->strAt(2); - valueVarId = 0; - } - else if (value == "&") - { - value = tok2->strAt(3); - valueVarId = tok2->tokAt(3)->varId(); - - // *ptr = &var; *ptr = 5; - // equals - // var = 5; not *var = 5; - if (tok2->strAt(4) == ";") - valueIsPointer = true; - } - - // float value should contain a "." - else if (tok2->tokAt(2)->isNumber() && - floatvar && - value.find(".") == std::string::npos) - { - value += ".0"; - } - - if (Token::simpleMatch(tok2->next(), "= &")) - tok2 = tok2->tokAt(3); - - tok3 = tok2->next(); - } - *_tok2 = tok2; - *_tok3 = tok3; - return true; -} - -bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel) -{ - const bool pointeralias(valueToken->isName() || Token::Match(valueToken, "& %var% [")); - - bool ret = false; - - Token* bailOutFromLoop = 0; - int indentlevel3 = indentlevel; - bool ret3 = false; - for (; tok3; tok3 = tok3->next()) - { - if (tok3->str() == "{") - { - ++indentlevel3; - } - else if (tok3->str() == "}") - { - --indentlevel3; - if (indentlevel3 < indentlevel) - { - if (Token::Match((*tok2)->tokAt(-7), "%type% * %var% ; %var% = & %var% ;") && - (*tok2)->tokAt(-5)->str() == (*tok2)->tokAt(-3)->str()) - { - (*tok2) = (*tok2)->tokAt(-4); - Token::eraseTokens((*tok2), (*tok2)->tokAt(5)); - } - break; - } - } - - // Stop if label is found - if (Token::Match(tok3, "; %type% : ;")) - break; - - // Stop if return or break is found .. - if (tok3->str() == "break") - break; - if ((indentlevel3 > 1 || !Token::simpleMatch(Token::findmatch(tok3,";"), "; }")) && tok3->str() == "return") - ret3 = true; - if (ret3 && tok3->str() == ";") - break; - - if (pointeralias && Token::Match(tok3, ("!!= " + value).c_str())) - break; - - // Stop if do is found - if (tok3->str() == "do") - break; - - // Stop if something like 'while (--var)' is found - if (tok3->str() == "for" || tok3->str() == "while" || tok3->str() == "do") - { - const Token *endpar = tok3->next()->link(); - if (Token::simpleMatch(endpar, ") {")) - endpar = endpar->next()->link(); - bool bailout = false; - for (const Token *tok4 = tok3; tok4 && tok4 != endpar; tok4 = tok4->next()) - { - if (Token::Match(tok4, "++|-- %varid%", varid) || - Token::Match(tok4, "%varid% ++|--|=", varid)) - { - bailout = true; - break; - } - } - if (bailout) - break; - } - - if (bailOutFromLoop) - { - // This could be a loop, skip it, but only if it doesn't contain - // the variable we are checking for. If it contains the variable - // we will bail out. - if (tok3->varId() == varid) - { - // Continue - //tok2 = bailOutFromLoop; - break; - } - else if (tok3 == bailOutFromLoop) - { - // We have skipped the loop - bailOutFromLoop = 0; - continue; - } - - continue; - } - else if (tok3->str() == "{" && tok3->previous()->str() == ")") - { - // There is a possible loop after the assignment. Try to skip it. - if (tok3->previous()->link() && - !Token::simpleMatch(tok3->previous()->link()->previous(), "if")) - bailOutFromLoop = tok3->link(); - continue; - } - - // Variable used in realloc (see Ticket #1649) - if (Token::Match(tok3, "%var% = realloc ( %var% ,") && - tok3->varId() == varid && - tok3->tokAt(4)->varId() == varid) - { - tok3->tokAt(4)->str(value); - ret = true; - } - - // condition "(|&&|%OROR% %varid% )|&&|%OROR% - if (!Token::Match(tok3->previous(), "( %var% )") && - (Token::Match(tok3->previous(), "&&|(") || tok3->strAt(-1) == "||") && - tok3->varId() == varid && - (Token::Match(tok3->next(), "&&|)") || tok3->strAt(1) == "||")) - { - tok3->str(value); - ret = true; - } - - // Variable is used somehow in a non-defined pattern => bail out - if (tok3->varId() == varid) - { - // This is a really generic bailout so let's try to avoid this. - // There might be lots of false negatives. - if (_settings->debugwarnings) - { - // FIXME: Fix all the debug warnings for values and then - // remove this bailout - if (pointeralias) - break; - - // suppress debug-warning when calling member function - if (Token::Match(tok3->next(), ". %var% (")) - break; - - // suppress debug-warning when assignment - if (Token::simpleMatch(tok3->next(), "=")) - break; - - // taking address of variable.. - if (Token::Match(tok3->tokAt(-2), "return|= & %var% ;")) - break; - - // parameter in function call.. - if (Token::Match(tok3->tokAt(-2), "%var% ( %var% ,|)") || - Token::Match(tok3->previous(), ", %var% ,|)")) - break; - - // conditional increment - if (Token::Match(tok3->tokAt(-3), ") { ++|--") || - Token::Match(tok3->tokAt(-2), ") { %var% ++|--")) - break; - - std::list locationList; - ErrorLogger::ErrorMessage::FileLocation loc; - loc.line = tok3->linenr(); - loc.setfile(file(tok3)); - locationList.push_back(loc); - - const ErrorLogger::ErrorMessage errmsg(locationList, - Severity::debug, - "simplifyKnownVariables: bailing out (variable="+tok3->str()+", value="+value+")", - "debug"); - - if (_errorLogger) - _errorLogger->reportErr(errmsg); - else - Check::reportError(errmsg); - } - - break; - } - - // Using the variable in condition.. - if (Token::Match(tok3->previous(), ("if ( " + structname + " %varid% ==|!=|<|<=|>|>=|)").c_str(), varid) || - Token::Match(tok3, ("( " + structname + " %varid% ==|!=|<|<=|>|>=").c_str(), varid) || - Token::Match(tok3, ("!|==|!=|<|<=|>|>= " + structname + " %varid% ==|!=|<|<=|>|>=|)|;").c_str(), varid) || - Token::Match(tok3->previous(), "strlen|free ( %varid% )", varid)) - { - if (value[0] == '\"' && tok3->strAt(-1) != "strlen") - { - // bail out if value is a string unless if it's just given - // as parameter to strlen - break; - } - if (!structname.empty()) - { - tok3->deleteNext(); - tok3->deleteNext(); - } - if (Token::Match(valueToken, "& %var% ;")) - { - tok3->insertToken("&"); - tok3 = tok3->next(); - } - tok3 = tok3->next(); - tok3->str(value); - tok3->varId(valueVarId); - ret = true; - } - - // Delete pointer alias - if (pointeralias && tok3->str() == "delete" && - (Token::Match(tok3, "delete %varid% ;", varid) || - Token::Match(tok3, "delete [ ] %varid%", varid))) - { - tok3 = (tok3->strAt(1) == "[") ? tok3->tokAt(3) : tok3->next(); - tok3->str(value); - tok3->varId(valueVarId); - ret = true; - } - - // Variable is used in function call.. - if (Token::Match(tok3, ("%var% ( " + structname + " %varid% ,").c_str(), varid)) - { - const char * const functionName[] = - { - "memcmp","memcpy","memmove","memset", - "strcmp","strcpy","strncpy","strdup" - }; - for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) - { - if (tok3->str() == functionName[i]) - { - Token *par1 = tok3->next()->next(); - if (!structname.empty()) - { - par1->deleteThis(); - par1->deleteThis(); - } - par1->str(value); - par1->varId(valueVarId); - break; - } - } - } - - // Variable is used as 2nd parameter in function call.. - if (Token::Match(tok3, ("%var% ( %any% , " + structname + " %varid% ,|)").c_str(), varid)) - { - const char * const functionName[] = - { - "memcmp","memcpy","memmove", - "strcmp","strcpy","strncmp","strncpy" - }; - for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) - { - if (tok3->str() == functionName[i]) - { - Token *par = tok3->tokAt(4); - if (!structname.empty()) - { - par->deleteThis(); - par->deleteThis(); - } - par->str(value); - par->varId(valueVarId); - break; - } - } - } - - // array usage - if (Token::Match(tok3, ("[(,] " + structname + " %varid% [+-*/[]").c_str(), varid)) - { - if (!structname.empty()) - { - tok3->deleteNext(); - tok3->deleteNext(); - } - tok3 = tok3->next(); - tok3->str(value); - tok3->varId(valueVarId); - ret = true; - } - - // Variable is used in calculation.. - if (((tok3->previous()->varId() > 0) && Token::Match(tok3, ("& " + structname + " %varid%").c_str(), varid)) || - Token::Match(tok3, ("[=+-*/%^|[] " + structname + " %varid% [=?+-*/%^|;])]").c_str(), varid) || - Token::Match(tok3, ("[(=+-*/%^|[] " + structname + " %varid% <<|>>").c_str(), varid) || - Token::Match(tok3, ("<<|>> " + structname + " %varid% [+-*/%^|;])]").c_str(), varid) || - Token::Match(tok3->previous(), ("[=+-*/%^|[] ( " + structname + " %varid%").c_str(), varid)) - { - if (value[0] == '\"') - break; - if (!structname.empty()) - { - tok3->deleteNext(); - tok3->deleteNext(); - } - tok3 = tok3->next(); - tok3->str(value); - tok3->varId(valueVarId); - if (tok3->previous()->str() == "*" && valueIsPointer) - { - tok3 = tok3->previous(); - tok3->deleteThis(); - } - ret = true; - } - - if (Token::simpleMatch(tok3, "= {")) - { - unsigned int indentlevel4 = 0; - for (const Token *tok4 = tok3; tok4; tok4 = tok4->next()) - { - if (tok4->str() == "{") - ++indentlevel4; - else if (tok4->str() == "}") - { - if (indentlevel4 <= 1) - break; - --indentlevel4; - } - if (Token::Match(tok4, "{|, %varid% ,|}", varid)) - { - tok4->next()->str(value); - tok4->next()->varId(valueVarId); - ret = true; - } - } - } - - // Using the variable in for-condition.. - if (Token::simpleMatch(tok3, "for (")) - { - for (Token *tok4 = tok3->tokAt(2); tok4; tok4 = tok4->next()) - { - if (tok4->str() == "(" || tok4->str() == ")") - break; - - // Replace variable used in condition.. - if (Token::Match(tok4, "; %var% <|<=|!= %var% ; ++| %var% ++| )")) - { - const Token *inctok = tok4->tokAt(5); - if (inctok->str() == "++") - inctok = inctok->next(); - if (inctok->varId() == varid) - break; - - if (tok4->next()->varId() == varid) - { - tok4->next()->str(value); - tok4->next()->varId(valueVarId); - ret = true; - } - if (tok4->tokAt(3)->varId() == varid) - { - tok4->tokAt(3)->str(value); - tok4->tokAt(3)->varId(valueVarId); - ret = true; - } - } - } - } - - if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "%varid% ++|--", varid) && MathLib::isInt(value)) - { - const std::string op(tok3->strAt(2)); - if (Token::Match(tok3, "[{};] %any% %any% ;")) - { - Token::eraseTokens(tok3, tok3->tokAt(3)); - } - else - { - tok3 = tok3->next(); - tok3->str(value); - tok3->varId(valueVarId); - tok3->deleteNext(); - } - incdec(value, op); - if (!Token::simpleMatch((*tok2)->tokAt(-2), "for (")) - { - (*tok2)->tokAt(2)->str(value); - (*tok2)->tokAt(2)->varId(valueVarId); - } - ret = true; - } - - if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "++|-- %varid%", varid) && MathLib::isInt(value) && - !Token::Match(tok3->tokAt(3), "[.[]")) - { - incdec(value, tok3->strAt(1)); - (*tok2)->tokAt(2)->str(value); - (*tok2)->tokAt(2)->varId(valueVarId); - if (Token::Match(tok3, "[;{}] %any% %any% ;")) - { - Token::eraseTokens(tok3, tok3->tokAt(3)); - } - else - { - tok3->deleteNext(); - tok3->next()->str(value); - tok3->next()->varId(valueVarId); - } - tok3 = tok3->next(); - ret = true; - } - - // return variable.. - if (Token::Match(tok3, "return %varid% %any%", varid) && - isOp(tok3->tokAt(2)) && - value[0] != '\"') - { - tok3->next()->str(value); - tok3->next()->varId(valueVarId); - } - - else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid) && value[0] != '\"') - { - tok3->deleteNext(); - tok3->next()->str(value); - tok3->next()->varId(valueVarId); - } - } - return ret; -} - - -void Tokenizer::elseif() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (!Token::simpleMatch(tok, "else if")) - continue; - int indent = 0; - for (Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next()) - { - if (Token::Match(tok2, "(|{")) - ++indent; - else if (Token::Match(tok2, ")|}")) - --indent; - - if (indent == 0 && Token::Match(tok2, "}|;")) - { - if (tok2->next() && tok2->next()->str() != "else") - { - tok->insertToken("{"); - tok2->insertToken("}"); - Token::createMutualLinks(tok->next(), tok2->next()); - break; - } - } - } - } -} - - -bool Tokenizer::simplifyRedundantParanthesis() -{ - bool ret = false; - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() != "(") - continue; - - // !!operator = ( x ) ; - if (tok->strAt(-2) != "operator" && - tok->strAt(-1) == "=" && - tok->strAt(1) != "{" && - Token::simpleMatch(tok->link(), ") ;")) - { - tok->link()->deleteThis(); - tok->deleteThis(); - continue; - } - - while (Token::simpleMatch(tok, "( (") && - tok->link()->previous() == tok->next()->link()) - { - // We have "(( *something* ))", remove the inner - // parenthesis - tok->deleteNext(); - tok->link()->tokAt(-2)->deleteNext(); - ret = true; - } - - while (Token::Match(tok->previous(), "[,;{}(] ( %var% (") && - tok->link()->previous() == tok->tokAt(2)->link()) - { - // We have "( func ( *something* ))", remove the outer - // parenthesis - tok->link()->deleteThis(); - tok->deleteThis(); - ret = true; - } - - while (Token::Match(tok->previous(), "[;{] ( delete %var% ) ;")) - { - // We have "( delete var )", remove the outer - // parenthesis - tok->tokAt(3)->deleteThis(); - tok->deleteThis(); - ret = true; - } - - while (Token::Match(tok->previous(), "[;{] ( delete [ ] %var% ) ;")) - { - // We have "( delete [] var )", remove the outer - // parenthesis - tok->tokAt(5)->deleteThis(); - tok->deleteThis(); - ret = true; - } - - if (!Token::simpleMatch(tok->tokAt(-2), "operator delete") && - Token::Match(tok->previous(), "delete|; (") && - (tok->strAt(-1) != "delete" || tok->next()->varId() > 0) && - Token::Match(tok->link(), ") ;|,")) - { - tok->link()->deleteThis(); - tok->deleteThis(); - ret = true; - } - - if (Token::Match(tok->previous(), "[(!*;{}] ( %var% )") && tok->next()->varId() != 0) - { - // We have "( var )", remove the parenthesis - tok->deleteThis(); - tok->deleteNext(); - ret = true; - continue; - } - - if (Token::Match(tok->previous(), "[(!] ( %var% . %var% )")) - { - // We have "( var . var )", remove the parenthesis - tok->deleteThis(); - tok = tok->tokAt(2); - tok->deleteNext(); - ret = true; - continue; - } - - if (Token::Match(tok, "( ( %bool% )") || - Token::Match(tok, "( ( %num% )")) - { - tok->tokAt(2)->deleteNext(); - tok->deleteNext(); - ret = true; - } - } - return ret; -} - -void Tokenizer::simplifyReference() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - // starting executable scope.. - if (Token::Match(tok, ") const| {")) - { - // replace references in this scope.. - if (tok->next()->str() != "{") - tok = tok->next(); - Token * const end = tok->next()->link(); - for (Token *tok2 = tok; tok2 && tok2 != end; tok2 = tok2->next()) - { - // found a reference.. - if (Token::Match(tok2, "[;{}] %type% & %var% (|= %var% )| ;")) - { - const unsigned int ref_id = tok2->tokAt(3)->varId(); - if (!ref_id) - continue; - - // replace reference in the code.. - for (Token *tok3 = tok2->tokAt(7); tok3 && tok3 != end; tok3 = tok3->next()) - { - if (tok3->varId() == ref_id) - { - tok3->str(tok2->strAt(5)); - tok3->varId(tok2->tokAt(5)->varId()); - } - } - - Token::eraseTokens(tok2, tok2->tokAt(7)); - } - } - } - } -} - -bool Tokenizer::simplifyCalculations() -{ - bool ret = false; - for (Token *tok = _tokens; tok; tok = tok->next()) - { - // Remove parentheses around variable.. - // keep parentheses here: dynamic_cast(p); - // keep parentheses here: A operator * (int); - // keep parentheses here: int ( * ( * f ) ( ... ) ) (int) ; - // keep parentheses here: int ( * * ( * compilerHookVector ) (void) ) ( ) ; - // keep parentheses here: operator new [] (size_t); - // keep parentheses here: Functor()(a ... ) - // keep parentheses here: ) ( var ) ; - if (Token::Match(tok->next(), "( %var% ) [;),+-*/><]]") && - !tok->isName() && - tok->str() != ">" && - tok->str() != "]" && - !Token::simpleMatch(tok->previous(), "operator") && - !Token::simpleMatch(tok->previous(), "* )") && - !Token::simpleMatch(tok->previous(), ") )") && - !Token::Match(tok->tokAt(-2), "* %var% )") && - !Token::Match(tok->tokAt(-2), "%type% ( ) ( %var%") && - !Token::Match(tok, ") ( %var% ) ;") - ) - { - tok->deleteNext(); - tok = tok->next(); - tok->deleteNext(); - ret = true; - } - - if (tok->isNumber()) - { - if (tok->str() == "0") - { - if (Token::Match(tok->previous(), "[+-] 0")) - { - tok = tok->previous(); - if (Token::Match(tok->tokAt(-4), "[;{}] %var% = %var% [+-] 0 ;") && - tok->strAt(-3) == tok->strAt(-1)) - { - tok = tok->previous()->previous()->previous(); - tok->deleteThis(); - tok->deleteThis(); - tok->deleteThis(); - } - tok->deleteThis(); - tok->deleteThis(); - ret = true; - } - else if (Token::Match(tok->previous(), "[=([,] 0 +")) - { - tok->deleteThis(); - tok->deleteThis(); - ret = true; - } - else if (Token::Match(tok->previous(), "[=[(,] 0 * %any% [+-*/,]);]")) - { - tok->deleteNext(); - if (tok->next()->str() == "(") - Token::eraseTokens(tok, tok->next()->link()); - tok->deleteNext(); - ret = true; - } - } - - if (Token::simpleMatch(tok->previous(), "* 1") || Token::simpleMatch(tok, "1 *")) - { - if (Token::simpleMatch(tok->previous(), "*")) - tok = tok->previous(); - tok->deleteThis(); - tok->deleteThis(); - ret = true; - } - - // Remove parentheses around number.. - if (Token::Match(tok->tokAt(-2), "%any% ( %num% )") && !tok->tokAt(-2)->isName() && tok->strAt(-2) != ">") - { - tok = tok->previous(); - tok->deleteThis(); - tok->deleteNext(); - ret = true; - } - - if (Token::simpleMatch(tok->previous(), "( 0 ||") || - Token::simpleMatch(tok->previous(), "|| 0 )") || - Token::simpleMatch(tok->previous(), "( 1 &&") || - Token::simpleMatch(tok->previous(), "&& 1 )")) - { - if (!Token::simpleMatch(tok->previous(), "(")) - tok = tok->previous(); - tok->deleteThis(); - tok->deleteThis(); - } - - if (Token::Match(tok, "%num% ==|!=|<=|>=|<|> %num%") && - MathLib::isInt(tok->str()) && - MathLib::isInt(tok->tokAt(2)->str())) - { - const std::string prev(tok->previous() ? tok->strAt(-1).c_str() : ""); - const std::string after(tok->tokAt(3) ? tok->strAt(3).c_str() : ""); - if ((prev == "(" || prev == "&&" || prev == "||") && (after == ")" || after == "&&" || after == "||")) - { - const MathLib::bigint op1(MathLib::toLongNumber(tok->str())); - const std::string &cmp(tok->next()->str()); - const MathLib::bigint op2(MathLib::toLongNumber(tok->tokAt(2)->str())); - - std::string result; - - if (cmp == "==") - result = (op1 == op2) ? "1" : "0"; - else if (cmp == "!=") - result = (op1 != op2) ? "1" : "0"; - else if (cmp == "<=") - result = (op1 <= op2) ? "1" : "0"; - else if (cmp == ">=") - result = (op1 >= op2) ? "1" : "0"; - else if (cmp == "<") - result = (op1 < op2) ? "1" : "0"; - else if (cmp == ">") - result = (op1 > op2) ? "1" : "0"; - - tok->str(result); - tok->deleteNext(); - tok->deleteNext(); - } - } - - if (Token::Match(tok->previous(), "[([,=] %num% <<|>> %num%")) - { - const MathLib::bigint op1(MathLib::toLongNumber(tok->str())); - const MathLib::bigint op2(MathLib::toLongNumber(tok->tokAt(2)->str())); - MathLib::bigint result; - - if (tok->next()->str() == "<<") - result = op1 << op2; - else - result = op1 >> op2; - - std::ostringstream ss; - ss << result; - - tok->str(ss.str()); - tok->deleteNext(); - tok->deleteNext(); - } - } - - else if (tok->next() && tok->next()->isNumber()) - { - - // (1-2) - while (Token::Match(tok, "[[,(=<>+-*|&^] %num% [+-*/] %num% [],);=<>+-*/|&^]") || - Token::Match(tok, "<< %num% [+-*/] %num% [],);=<>+-*/|&^]") || - Token::Match(tok, "[[,(=<>+-*|&^] %num% [+-*/] %num% <<|>>") || - Token::Match(tok, "<< %num% [+-*/] %num% <<") || - Token::Match(tok, "[(,[] %num% [|&^] %num% [];,);]")) - { - tok = tok->next(); - - // Don't simplify "%num% / 0" - if (Token::simpleMatch(tok->next(), "/ 0")) - continue; - - // & | ^ - if (Token::Match(tok->next(), "[&|^]")) - { - std::string result; - const std::string first(tok->str()); - const std::string second(tok->strAt(2)); - const char op = tok->next()->str()[0]; - if (op == '&') - result = MathLib::toString(MathLib::toLongNumber(first) & MathLib::toLongNumber(second)); - else if (op == '|') - result = MathLib::toString(MathLib::toLongNumber(first) | MathLib::toLongNumber(second)); - else if (op == '^') - result = MathLib::toString(MathLib::toLongNumber(first) ^ MathLib::toLongNumber(second)); - - if (!result.empty()) - { - ret = true; - tok->str(result); - Token::eraseTokens(tok, tok->tokAt(3)); - continue; - } - } - - // + and - are calculated after * and / - if (Token::Match(tok->next(), "[+-/]")) - { - if (tok->previous()->str() == "*") - continue; - if (Token::Match(tok->tokAt(3), "[*/]")) - continue; - } - - if (Token::Match(tok->previous(), "- %num% - %num%")) - tok->str(MathLib::add(tok->str(), tok->tokAt(2)->str())); - else if (Token::Match(tok->previous(), "- %num% + %num%")) - tok->str(MathLib::subtract(tok->str(), tok->tokAt(2)->str())); - else - tok->str(MathLib::calculate(tok->str(), tok->tokAt(2)->str(), tok->strAt(1)[0], this)); - - Token::eraseTokens(tok, tok->tokAt(3)); - - // evaluate "2 + 2 - 2 - 2" - // as (((2 + 2) - 2) - 2) = 0 - // instead of ((2 + 2) - (2 - 2)) = 4 - if (Token::Match(tok->next(), "[+-*/]")) - { - tok = tok->previous(); - continue; - } - - ret = true; - } - } - } - return ret; -} - - - - -void Tokenizer::simplifyGoto() -{ - std::list gotos; - unsigned int indentlevel = 0; - Token *beginfunction = 0; - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "{") - { - if (beginfunction == 0 && indentlevel == 0 && tok->link()) - tok = tok->link(); - else - ++indentlevel; - } - - else if (tok->str() == "}") - { - if (indentlevel == 0) - break; // break out - it seems the code is wrong - --indentlevel; - if (indentlevel == 0) - { - gotos.clear(); - beginfunction = 0; - } - } - - else if (indentlevel > 0 && tok->str() == "(") - { - tok = tok->link(); - } - - else if (indentlevel == 0 && Token::Match(tok, ") const| {")) - { - gotos.clear(); - beginfunction = tok; - } - - else if (Token::Match(tok, "goto %var% ;")) - gotos.push_back(tok); - - else if (indentlevel == 1 && Token::Match(tok->previous(), "[};] %var% :")) - { - // Is this label at the end.. - bool end = false; - int level = 0; - for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) - { - if (tok2->str() == "}") - { - --level; - if (level < 0) - { - end = true; - break; - } - } - else if (tok2->str() == "{") - { - ++level; - } - - if (Token::Match(tok2, "%var% :") || tok2->str() == "goto") - { - break; - } - } - if (!end) - continue; - - const std::string name(tok->str()); - - tok->deleteThis(); - tok->deleteThis(); - if (Token::Match(tok, "; %any%")) - tok->deleteThis(); - - // This label is at the end of the function.. replace all matching goto statements.. - for (std::list::iterator it = gotos.begin(); it != gotos.end(); ++it) - { - Token *token = *it; - if (token->next()->str() == name) - { - // Delete the "goto name;" - token = token->previous(); - token->deleteNext(); - token->deleteNext(); - token->deleteNext(); - - // Insert the statements.. - bool ret = false; // is there return - bool ret2 = false; // is there return in indentlevel 0 - std::list links; - std::list links2; - std::list links3; - int lev = 0; - for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) - { - if (tok2->str() == "}") - { - --lev; - if (lev < 0) - break; - } - if (tok2->str() == "{") - { - ++lev; - } - else if (tok2->str() == "return") - { - ret = true; - if (indentlevel == 1 && lev == 0) - ret2 = true; - } - token->insertToken(tok2->str().c_str()); - token = token->next(); - token->linenr(tok2->linenr()); - token->varId(tok2->varId()); - if (ret2 && tok2->str() == ";") - { - break; - } - if (token->str() == "(") - { - links.push_back(token); - } - else if (token->str() == ")") - { - if (links.empty()) - { - // This should never happen at this point - syntaxError(token, ')'); - return; - } - - Token::createMutualLinks(links.back(), token); - links.pop_back(); - } - else if (token->str() == "{") - { - links2.push_back(token); - } - else if (token->str() == "}") - { - if (links2.empty()) - { - // This should never happen at this point - syntaxError(token, '}'); - return; - } - - Token::createMutualLinks(links2.back(), token); - links2.pop_back(); - } - else if (token->str() == "[") - { - links3.push_back(token); - } - else if (token->str() == "]") - { - if (links3.empty()) - { - // This should never happen at this point - syntaxError(token, ']'); - return; - } - - Token::createMutualLinks(links3.back(), token); - links3.pop_back(); - } - } - - if (!ret) - { - token->insertToken("return"); - token = token->next(); - token->insertToken(";"); - token = token->next(); - } - } - } - - gotos.clear(); - tok = beginfunction; - indentlevel = 0; - continue; - } - } -} - -void Tokenizer::simplifyNestedStrcat() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (! Token::Match(tok, "[;{}] strcat ( strcat (")) - { - continue; - } - - // find inner strcat call - Token *tok2 = tok->tokAt(3); - while (Token::simpleMatch(tok2, "strcat ( strcat")) - { - tok2 = tok2->tokAt(2); - } - - // If we have this code: - // strcat(strcat(dst, foo), bar); - // We move this part of code before all strcat() calls: strcat(dst, foo) - // And place "dst" token where the code was. - Token *prevTok = tok2->previous(); - - // Move tokens to new place - Token::move(tok2, tok2->next()->link(), tok); - tok = tok2->next()->link(); - - // Insert the "dst" token - prevTok->insertToken(tok2->strAt(2)); - - // Insert semicolon after the moved strcat() - tok->insertToken(";"); - } - -} - -void Tokenizer::duplicateEnumError(const Token * tok1, const Token * tok2, const std::string & type) -{ - if (!(_settings->_checkCodingStyle)) - return; - - std::list locationList; - ErrorLogger::ErrorMessage::FileLocation loc; - loc.line = tok1->linenr(); - loc.setfile(file(tok1)); - locationList.push_back(loc); - loc.line = tok2->linenr(); - loc.setfile(file(tok2)); - locationList.push_back(loc); - - const ErrorLogger::ErrorMessage errmsg(locationList, - Severity::style, - std::string(type + " '" + tok2->str() + - "' hides enumerator with same name"), - "variableHidingEnum"); - - if (_errorLogger) - _errorLogger->reportErr(errmsg); - else - Check::reportError(errmsg); -} - -// Check if this statement is a duplicate definition. A duplicate -// definition will hide the enumerator within it's scope so just -// skip the entire scope of the duplicate. -bool Tokenizer::duplicateDefinition(Token ** tokPtr, const Token * name) -{ - // check for an end of definition - const Token * tok = *tokPtr; - if (tok && Token::Match(tok->next(), ";|,|[|=|)|>")) - { - const Token * end = tok->next(); - - if (end->str() == "[") - { - end = end->link()->next(); - } - else if (end->str() == ",") - { - // check for function argument - if (Token::Match(tok->previous(), "(|,")) - return false; - - // find end of definition - int level = 0; - while (end && end->next() && (!Token::Match(end->next(), ";|)|>") || - (end->next()->str() == ")" && level == 0))) - { - if (end->next()->str() == "(") - level++; - else if (end->next()->str() == ")") - level--; - - end = end->next(); - } - } - else if (end->str() == ")") - { - // check of function argument - if (tok->previous()->str() == ",") - return false; - } - - if (end) - { - if (Token::simpleMatch(end, ") {")) // function parameter ? - { - // look backwards - if (tok->previous()->str() == "enum" || - (Token::Match(tok->previous(), "%type%") && - tok->previous()->str() != "return")) - { - duplicateEnumError(*tokPtr, name, "Function parameter"); - // duplicate definition so skip entire function - *tokPtr = end->next()->link(); - return true; - } - } - else if (end->str() == ">") // template parameter ? - { - // look backwards - if (tok->previous()->str() == "enum" || - (Token::Match(tok->previous(), "%type%") && - tok->previous()->str() != "return")) - { - // duplicate definition so skip entire template - while (end && end->str() != "{") - end = end->next(); - if (end) - { - duplicateEnumError(*tokPtr, name, "Template parameter"); - *tokPtr = end->link(); - return true; - } - } - } - else - { - // look backwards - if (Token::Match(tok->previous(), "enum|,") || - (Token::Match(tok->previous(), "%type%") && - tok->previous()->str() != "return")) - { - duplicateEnumError(*tokPtr, name, "Variable"); - return true; - } - } - } - } - return false; -} - -void Tokenizer::simplifyEnum() -{ - // Don't simplify enums in java files - if (isJavaOrCSharp()) - return; - - std::string className; - int classLevel = 0; - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "class|struct|namespace %any%") && - (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) - { - className = tok->next()->str(); - classLevel = 0; - continue; - } - else if (tok->str() == "}") - { - --classLevel; - if (classLevel < 0) - className = ""; - - continue; - } - else if (tok->str() == "{") - { - ++classLevel; - continue; - } - else if (Token::Match(tok, "enum class|struct| {|:") || - Token::Match(tok, "enum class|struct| %type% {|:|;")) - { - Token *tok1; - Token *start = tok; - Token *end; - Token *enumType = 0; - Token *typeTokenStart = 0; - Token *typeTokenEnd = 0; - - // check for C++0x enum class - if (Token::Match(tok->next(), "class|struct")) - tok->deleteNext(); - - // check for C++0x typed enumeration - if (Token::Match(tok->next(), "%type% :") || tok->next()->str() == ":") - { - int offset = 2; - if (tok->next()->str() != ":") - offset = 3; - - // check for forward declaration - const Token *temp = tok->tokAt(offset); - while (!Token::Match(temp, "{|;")) - temp = temp->next(); - if (temp->str() == ";") - { - /** @todo start substitution check at forward declaration */ - // delete forward declaration - tok->deleteThis(); - tok->deleteThis(); - tok->deleteThis(); - tok->deleteThis(); - continue; - } - - typeTokenStart = tok->tokAt(offset); - typeTokenEnd = typeTokenStart; - while (Token::Match(typeTokenEnd->next(), "signed|unsigned|char|short|int|long")) - typeTokenEnd = typeTokenEnd->next(); - - if (!Token::Match(typeTokenEnd->next(), "{|;")) - { - syntaxError(typeTokenEnd->next()); - return; - } - } - - // check for forward declaration - else if (Token::Match(tok->next(), "%type% ;")) - { - /** @todo start substitution check at forward declaration */ - // delete forward declaration - tok->deleteThis(); - tok->deleteThis(); - continue; - } - - if (tok->tokAt(1)->str() == "{") - tok1 = tok->tokAt(2); - else if (tok->tokAt(1)->str() == ":") - tok1 = typeTokenEnd->tokAt(2); - else if (tok->tokAt(2)->str() == "{") - { - enumType = tok->tokAt(1); - tok1 = tok->tokAt(3); - } - else - { - enumType = tok->tokAt(1); - tok1 = typeTokenEnd->tokAt(2); - } - - end = tok1->tokAt(-1)->link(); - - MathLib::bigint lastValue = -1; - Token * lastEnumValueStart = 0; - Token * lastEnumValueEnd = 0; - - // iterate over all enumerators between { and } - // Give each enumerator the const value specified or if not specified, 1 + the - // previous value or 0 if it is the first one. - for (; tok1 && tok1 != end; tok1 = tok1->next()) - { - Token * enumName = 0; - Token * enumValue = 0; - Token * enumValueStart = 0; - Token * enumValueEnd = 0; - - if (tok1->str() == "(") - { - tok1 = tok1->link(); - continue; - } - - if (Token::Match(tok1->previous(), ",|{ %type% ,|}")) - { - // no value specified - enumName = tok1; - lastValue++; - tok1->insertToken("="); - tok1 = tok1->next(); - - if (lastEnumValueStart && lastEnumValueEnd) - { - // previous value was an expression - Token *valueStart = tok1; - tok1 = copyTokens(tok1, lastEnumValueStart, lastEnumValueEnd); - - // value is previous expression + 1 - tok1->insertToken("+"); - tok1 = tok1->next(); - tok1->insertToken(MathLib::toString(lastValue)); - enumValue = 0; - enumValueStart = valueStart->next(); - enumValueEnd = tok1->next(); - } - else - { - // value is previous numeric value + 1 - tok1->insertToken(MathLib::toString(lastValue)); - enumValue = tok1->next(); - } - } - else if (Token::Match(tok1->previous(), ",|{ %type% = %num% ,|}")) - { - // value is specified numeric value - enumName = tok1; - lastValue = MathLib::toLongNumber(tok1->strAt(2)); - enumValue = tok1->tokAt(2); - lastEnumValueStart = 0; - lastEnumValueEnd = 0; - } - else if (Token::Match(tok1->previous(), ",|{ %type% =")) - { - // value is specified expression - enumName = tok1; - lastValue = 0; - tok1 = tok1->tokAt(2); - enumValueStart = tok1; - enumValueEnd = tok1; - int level = 0; - if (enumValueEnd->str() == "(" || - enumValueEnd->str() == "[" || - enumValueEnd->str() == "{") - level++; - while (enumValueEnd->next() && - (!Token::Match(enumValueEnd->next(), "}|,") || level)) - { - if (enumValueEnd->next()->str() == "(" || - enumValueEnd->next()->str() == "[" || - enumValueEnd->next()->str() == "{") - level++; - else if (enumValueEnd->next()->str() == ")" || - enumValueEnd->next()->str() == "]" || - enumValueEnd->next()->str() == "}") - level--; - - enumValueEnd = enumValueEnd->next(); - } - // remember this expression in case it needs to be incremented - lastEnumValueStart = enumValueStart; - lastEnumValueEnd = enumValueEnd; - // skip over expression - tok1 = enumValueEnd; - } - - // find all uses of this enumerator and substitute it's value for it's name - if (enumName && (enumValue || (enumValueStart && enumValueEnd))) - { - const std::string pattern = className.empty() ? - std::string("") : - std::string(className + " :: " + enumName->str()); - int level = 1; - bool inScope = true; - - bool exitThisScope = false; - int exitScope = 0; - bool simplify = false; - bool hasClass = false; - for (Token *tok2 = tok1->next(); tok2; tok2 = tok2->next()) - { - if (tok2->str() == "}") - { - --level; - if (level < 0) - inScope = false; - - if (exitThisScope) - { - if (level < exitScope) - exitThisScope = false; - } - } - else if (tok2->str() == "{") - { - // Is the same enum redefined? - const Token *begin = end->link(); - if (tok2->fileIndex() == begin->fileIndex() && - tok2->linenr() == begin->linenr() && - Token::Match(begin->tokAt(-2), "enum %type% {") && - Token::Match(tok2->tokAt(-2), "enum %type% {") && - begin->strAt(-1) == tok2->strAt(-1)) - { - // remove duplicate enum - Token * startToken = tok2->tokAt(-3); - tok2 = tok2->link()->next(); - Token::eraseTokens(startToken, tok2); - if (!tok2) - break; - } - else - { - // Not a duplicate enum.. - ++level; - } - } - else if (!pattern.empty() && Token::Match(tok2, pattern.c_str())) - { - simplify = true; - hasClass = true; - } - else if (inScope && !exitThisScope && tok2->str() == enumName->str()) - { - if (Token::simpleMatch(tok2->previous(), "::") || - Token::Match(tok2->next(), "::|[")) - { - // Don't replace this enum if: - // * it's preceded or followed by "::" - // * it's followed by "[" - } - else if (!duplicateDefinition(&tok2, enumName)) - { - simplify = true; - hasClass = false; - } - else - { - // something with the same name. - exitScope = level; - } - } - - if (simplify) - { - if (enumValue) - tok2->str(enumValue->str()); - else - { - tok2 = tok2->previous(); - tok2->deleteNext(); - tok2 = copyTokens(tok2, enumValueStart, enumValueEnd); - } - - if (hasClass) - { - tok2->deleteNext(); - tok2->deleteNext(); - } - - simplify = false; - } - } - } - } - - // check for a variable definition: enum {} x; - if (end->next() && end->next()->str() != ";") - { - Token *tempTok = end; - - tempTok->insertToken(";"); - tempTok = tempTok->next(); - if (typeTokenStart == 0) - tempTok->insertToken("int"); - else - { - Token *tempTok1 = typeTokenStart; - - tempTok->insertToken(tempTok1->str()); - - while (tempTok1 != typeTokenEnd) - { - tempTok1 = tempTok1->next(); - - tempTok->insertToken(tempTok1->str()); - tempTok = tempTok->next(); - } - } - } - - if (enumType) - { - const std::string pattern(className.empty() ? "" : (className + " :: " + enumType->str()).c_str()); - - // count { and } for tok2 - int level = 0; - bool inScope = true; - - bool exitThisScope = false; - int exitScope = 0; - bool simplify = false; - bool hasClass = false; - for (Token *tok2 = end->next(); tok2; tok2 = tok2->next()) - { - if (tok2->str() == "}") - { - --level; - if (level < 0) - inScope = false; - - if (exitThisScope) - { - if (level < exitScope) - exitThisScope = false; - } - } - else if (tok2->str() == "{") - ++level; - else if (!pattern.empty() && ((Token::simpleMatch(tok2, "enum") && Token::Match(tok2->next(), pattern.c_str())) || Token::Match(tok2, pattern.c_str()))) - { - simplify = true; - hasClass = true; - } - else if (inScope && !exitThisScope && (tok2->str() == enumType->str() || (tok2->str() == "enum" && tok2->next()->str() == enumType->str()))) - { - if (Token::simpleMatch(tok2->previous(), "::")) - { - // Don't replace this enum if it's preceded by "::" - } - else if (tok2->next() && - (tok2->next()->isName() || tok2->next()->str() == "(")) - { - simplify = true; - hasClass = false; - } - } - - if (simplify) - { - if (tok2->str() == "enum") - tok2->deleteNext(); - if (typeTokenStart == 0) - tok2->str("int"); - else - { - Token *tok3 = typeTokenStart; - - tok2->str(tok3->str()); - - while (tok3 != typeTokenEnd) - { - tok3 = tok3->next(); - - tok2->insertToken(tok3->str()); - tok2 = tok2->next(); - } - } - - if (hasClass) - { - tok2->deleteNext(); - tok2->deleteNext(); - } - - simplify = false; - } - } - } - - tok1 = start; - while (tok1->next() && tok1->next() != end) - tok1->deleteNext(); - tok1->deleteNext(); - if (start != _tokens) - { - tok1 = start->previous(); - tok1->deleteNext(); - tok = tok1; - } - else - _tokens->deleteThis(); - } - } -} - - -void Tokenizer::simplifyStd() -{ - std::set f; - f.insert("strcat"); - f.insert("strcpy"); - f.insert("strncat"); - f.insert("strncpy"); - f.insert("free"); - f.insert("malloc"); - f.insert("strdup"); - - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() != "std") - continue; - - if (Token::Match(tok->previous(), "[(,{};] std :: %var% (") && - f.find(tok->strAt(2)) != f.end()) - { - tok->deleteNext(); - tok->deleteThis(); - } - } -} - -//--------------------------------------------------------------------------- -// Helper functions for handling the tokens list -//--------------------------------------------------------------------------- - - - -//--------------------------------------------------------------------------- - -const Token *Tokenizer::getFunctionTokenByName(const char funcname[]) const -{ - getSymbolDatabase(); - - std::list::const_iterator i; - - for (i = _symbolDatabase->scopeList.begin(); i != _symbolDatabase->scopeList.end(); ++i) - { - const Scope *scope = *i; - - if (scope->type == Scope::eFunction) - { - if (scope->classDef->str() == funcname) - return scope->classDef; - } - } - return NULL; -} - - -void Tokenizer::fillFunctionList() -{ - getSymbolDatabase(); -} - -//--------------------------------------------------------------------------- - -// Deallocate lists.. -void Tokenizer::deallocateTokens() -{ - deleteTokens(_tokens); - _tokens = 0; - _tokensBack = 0; - _files.clear(); -} - -void Tokenizer::deleteTokens(Token *tok) -{ - while (tok) - { - Token *next = tok->next(); - delete tok; - tok = next; - } -} - -//--------------------------------------------------------------------------- - -const char *Tokenizer::getParameterName(const Token *ftok, unsigned int par) -{ - unsigned int _par = 1; - for (; ftok; ftok = ftok->next()) - { - if (ftok->str() == ")") - break; - if (ftok->str() == ",") - ++_par; - if (par == _par && Token::Match(ftok, "%var% [,)]")) - return ftok->str().c_str(); - } - return NULL; -} - -//--------------------------------------------------------------------------- - -std::string Tokenizer::fileLine(const Token *tok) const -{ - std::ostringstream ostr; - ostr << "[" << _files.at(tok->fileIndex()) << ":" << tok->linenr() << "]"; - return ostr.str(); -} - -std::string Tokenizer::file(const Token *tok) const -{ - return _files.at(tok->fileIndex()); -} - -//--------------------------------------------------------------------------- - -void Tokenizer::syntaxError(const Token *tok) -{ - std::list locationList; - if (tok) - { - ErrorLogger::ErrorMessage::FileLocation loc; - loc.line = tok->linenr(); - loc.setfile(file(tok)); - locationList.push_back(loc); - } - - const ErrorLogger::ErrorMessage errmsg(locationList, - Severity::error, - "syntax error", - "syntaxError"); - - if (_errorLogger) - _errorLogger->reportErr(errmsg); - else - Check::reportError(errmsg); -} - -void Tokenizer::syntaxError(const Token *tok, char c) -{ - std::list locationList; - if (tok) - { - ErrorLogger::ErrorMessage::FileLocation loc; - loc.line = tok->linenr(); - loc.setfile(file(tok)); - locationList.push_back(loc); - } - - const ErrorLogger::ErrorMessage errmsg(locationList, - Severity::error, - std::string("Invalid number of character (") + - c + - ") " + - "when these macros are defined: '" + - _configuration + - "'.", - "syntaxError"); - - if (_errorLogger) - _errorLogger->reportErr(errmsg); - else - Check::reportError(errmsg); -} - -void Tokenizer::cppcheckError(const Token *tok) const -{ - std::list locationList; - if (tok) - { - ErrorLogger::ErrorMessage::FileLocation loc; - loc.line = tok->linenr(); - loc.setfile(file(tok)); - locationList.push_back(loc); - } - - const ErrorLogger::ErrorMessage errmsg(locationList, - Severity::error, - "Analysis failed. If the code is valid then please report this failure.", - "cppcheckError"); - - if (_errorLogger) - _errorLogger->reportErr(errmsg); - else - Check::reportError(errmsg); -} - - -void Tokenizer::simplifyMathFunctions() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "atol ( %str% )")) - { - if (!MathLib::isInt(tok->tokAt(2)->strValue())) - { - // Ignore strings which we can't convert - continue; - } - - if (tok->previous() && - Token::simpleMatch(tok->previous()->previous(), "std ::")) - { - // Delete "std ::" - tok = tok->previous()->previous(); - tok->deleteNext(); - tok->deleteThis(); - } - - // Delete atol( - tok->deleteNext(); - tok->deleteThis(); - - // Convert string into a number - tok->str(MathLib::toString(MathLib::toLongNumber(tok->strValue()))); - - // Delete remaining ) - tok->deleteNext(); - } - } -} - -void Tokenizer::simplifyComma() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::simpleMatch(tok, "for (") || - Token::Match(tok, "=|enum {")) - { - tok = tok->next()->link(); - if (!tok) - break; - - continue; - } - - if (tok->str() == "(") - { - tok = tok->link(); - continue; - } - - // Skip unhandled template specifiers.. - if (Token::Match(tok, "%var% <")) - { - // Todo.. use the link instead. - unsigned int comparelevel = 0; - for (Token *tok2 = tok; tok2; tok2 = tok2->next()) - { - if (tok2->str() == "<") - ++comparelevel; - else if (tok2->str() == ">") - { - if (comparelevel <= 1) - { - tok = tok2; - break; - } - ++comparelevel; - } - else if (Token::Match(tok2, "[;{}]")) - break; - } - } - - // If token after the comma is a constant number, simplification is not required. - if (tok->str() != "," || Token::Match(tok->next(), "%num%")) - continue; - - // We must not accept just any keyword, e.g. accepting int - // would cause function parameters to corrupt. - if (Token::simpleMatch(tok->next(), "delete")) - { - // Handle "delete a, delete b;" - tok->str(";"); - } - - if (tok->previous() && tok->previous()->previous()) - { - if (Token::simpleMatch(tok->previous()->previous(), "delete") && - tok->next()->varId() != 0) - { - // Handle "delete a, b;" - tok->str(";"); - tok->insertToken("delete"); - } - else - { - for (Token *tok2 = tok->previous(); tok2; tok2 = tok2->previous()) - { - if (tok2->str() == "=") - { - // Handle "a = 0, b = 0;" - tok->str(";"); - break; - } - else if (Token::Match(tok2, "delete %var%") || - Token::Match(tok2, "delete [ ] %var%")) - { - // Handle "delete a, a = 0;" - tok->str(";"); - break; - } - else if (Token::Match(tok2, "[;,{}()]")) - { - break; - } - } - } - } - - bool inReturn = false; - Token *startFrom = NULL; // next tokean after "; return" - Token *endAt = NULL; // first ";" token after "; return" - - // find "; return" pattern before comma - for (Token *tok2 = tok; tok2; tok2 = tok2->previous()) - { - if (Token::Match(tok2, "[;{}]")) - { - break; - - } - else if (tok2->str() == "return" && Token::Match(tok2->previous(), "[;{}]")) - { - inReturn = true; - startFrom = tok2->next(); - break; - } - } - - // find token where return ends and also count commas - if (inReturn) - { - size_t commaCounter = 0; - size_t indentlevel = 0; - - for (Token *tok2 = startFrom; tok2; tok2 = tok2->next()) - { - if (tok2->str() == ";") - { - endAt = tok2; - break; - - } - else if (tok2->str() == "(") - { - ++indentlevel; - - } - else if (tok2->str() == ")") - { - --indentlevel; - - } - else if (tok2->str() == "," && indentlevel == 0) - { - ++commaCounter; - } - } - - if (commaCounter) - { - indentlevel = 0; - - // change tokens: - // "; return a ( ) , b ( ) , c ;" - // to - // "; return a ( ) ; b ( ) ; c ;" - for (Token *tok2 = startFrom; tok2 != endAt; tok2 = tok2->next()) - { - if (tok2->str() == "(") - { - ++indentlevel; - - } - else if (tok2->str() == ")") - { - --indentlevel; - - } - else if (tok2->str() == "," && indentlevel == 0) - { - tok2->str(";"); - --commaCounter; - if (commaCounter == 0) - { - tok2->insertToken("return"); - } - } - } - - // delete old "return" - startFrom->previous()->deleteThis(); - startFrom = 0; // give dead pointer a value - - tok = endAt; - if (!tok) - return; - } - } - - } -} - - -void Tokenizer::removeExceptionSpecifications(Token *tok) const -{ - while (tok) - { - if (tok->str() == "{") - tok = tok->link(); - - else if (tok->str() == "}") - break; - - else if (Token::simpleMatch(tok, ") throw (")) - { - Token::eraseTokens(tok, tok->tokAt(2)->link()); - tok->deleteNext(); - } - - else if (Token::Match(tok, "class|namespace|struct %type%")) - { - while (tok && !Token::Match(tok, "[;{]")) - tok = tok->next(); - if (tok && tok->str() == "{") - { - removeExceptionSpecifications(tok->next()); - tok = tok->link(); - } - } - - tok = tok ? tok->next() : 0; - } -} - - - -bool Tokenizer::validate() const -{ - std::stack linktok; - const Token *lastTok = 0; - for (const Token *tok = tokens(); tok; tok = tok->next()) - { - lastTok = tok; - if (Token::Match(tok, "[{([]")) - { - if (tok->link() == 0) - { - cppcheckError(tok); - return false; - } - - linktok.push(tok); - continue; - } - - else if (Token::Match(tok, "[})]]")) - { - if (tok->link() == 0) - { - cppcheckError(tok); - return false; - } - - if (linktok.empty() == true) - { - cppcheckError(tok); - return false; - } - - if (tok->link() != linktok.top()) - { - cppcheckError(tok); - return false; - } - - if (tok != tok->link()->link()) - { - cppcheckError(tok); - return false; - } - - linktok.pop(); - continue; - } - - if (tok->link() != 0) - { - cppcheckError(tok); - return false; - } - } - - if (!linktok.empty()) - { - cppcheckError(linktok.top()); - return false; - } - - // Validate that the Tokenizer::_tokensBack is updated correctly during simplifications - if (lastTok != _tokensBack) - { - cppcheckError(lastTok); - return false; - } - - return true; -} - -std::string Tokenizer::simplifyString(const std::string &source) -{ - std::string str = source; - - // true when previous char is a \ . - bool escaped = false; - for (std::string::size_type i = 0; i + 2 < str.size(); i++) - { - if (!escaped) - { - if (str[i] == '\\') - escaped = true; - - continue; - } - - if (str[i] == 'x') - { - // Hex value - if (str[i+1] == '0' && str[i+2] == '0') - str.replace(i, 3, "0"); - else if (i > 0) - { - // We will replace all other character as 'a' - // If that causes problems in the future, this can - // be improved. But for now, this should be OK. - unsigned int n = 1; - while (n < 2 && std::isxdigit(str[i+1+n])) - ++n; - --i; - n += 2; - str.replace(i, n, "a"); - } - } - else if (MathLib::isOctalDigit(str[i])) - { - if (MathLib::isOctalDigit(str[i+1]) && - MathLib::isOctalDigit(str[i+2])) - { - if (str[i+1] == '0' && str[i+2] == '0') - str.replace(i, 3, "0"); - else - { - // We will replace all other character as 'a' - // If that causes problems in the future, this can - // be improved. But for now, this should be OK. - --i; - str.replace(i, 4, "a"); - } - } - } - - escaped = false; - } - - return str; -} - - -void Tokenizer::simplifyStructInit() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "[;{}] struct| %type% %var% = { . %type% =")) - { - // Goto "." and check if the initializations have an expected format - const Token *tok2 = tok; - while (tok2->str() != ".") - tok2 = tok2->next(); - while (tok2 && tok2->str() == ".") - { - if (Token::Match(tok2, ". %type% = %num% [,}]")) - tok2 = tok2->tokAt(4); - else if (Token::Match(tok2, ". %type% = %var% [,}]")) - tok2 = tok2->tokAt(4); - else if (Token::Match(tok2, ". %type% = & %var% [,}]")) - tok2 = tok2->tokAt(5); - else - break; - - if (Token::simpleMatch(tok2, ", .")) - tok2 = tok2->next(); - } - if (!Token::simpleMatch(tok2, "} ;")) - continue; - - // Known expression format => Perform simplification - Token *vartok = tok->tokAt(3); - if (vartok->str() == "=") - vartok = vartok->previous(); - vartok->next()->str(";"); - - Token *tok3 = vartok->tokAt(2); - tok3->link(0); - while (Token::Match(tok3, "[{,] . %type% =")) - { - tok3->str(vartok->str()); - tok3->varId(vartok->varId()); - tok3 = tok3->tokAt(5); - while (!Token::Match(tok3, "[,}]")) - tok3 = tok3->next(); - if (tok3->str() == "}") - { - tok3->deleteThis(); - break; - } - tok3->previous()->insertToken(";"); - } - } - } -} - - -void Tokenizer::simplifyComparisonOrder() -{ - // Use "<" comparison instead of ">" - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "[;(] %any% >|>= %any% [);]")) - { - if (!tok->next()->isName() && !tok->next()->isNumber()) - continue; - const std::string op1(tok->strAt(1)); - tok->next()->str(tok->strAt(3)); - tok->tokAt(3)->str(op1); - if (tok->tokAt(2)->str() == ">") - tok->tokAt(2)->str("<"); - else - tok->tokAt(2)->str("<="); - } - else if (Token::Match(tok, "( %num% ==|!= %var% )")) - { - if (!tok->next()->isName() && !tok->next()->isNumber()) - continue; - const std::string op1(tok->strAt(1)); - tok->next()->str(tok->strAt(3)); - tok->tokAt(3)->str(op1); - } - } -} - -void Tokenizer::simplifyConst() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "[;{}(,] %type% const") && - tok->next()->str().find(":") == std::string::npos && - tok->next()->str() != "operator") - { - tok->tokAt(2)->str(tok->tokAt(1)->str()); - tok->tokAt(1)->str("const"); - } - } -} - -void Tokenizer::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) -{ - Tokenizer t(settings, errorLogger); - t.syntaxError(0, ' '); - t.cppcheckError(0); -} - -/** find pattern */ -static bool findmatch(const Token *tok1, const Token *tok2, const char pattern[]) -{ - for (const Token *tok = tok1; tok && tok != tok2; tok = tok->next()) - { - if (Token::Match(tok, pattern)) - return true; - } - return false; -} - -void Tokenizer::simplifyWhile0() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - // while (0) - const bool while0(Token::Match(tok, "while ( 0|false )")); - - // for (0) - const bool for0(Token::Match(tok, "for ( %var% = %num% ; %var% < %num% ;") && - tok->strAt(2) == tok->strAt(6) && - tok->strAt(4) == tok->strAt(8)); - - if (!while0 && !for0) - continue; - - if (while0 && Token::simpleMatch(tok->previous(), "}")) - { - // find "do" - Token *tok2 = tok->previous()->link(); - tok2 = tok2 ? tok2->previous() : 0; - if (tok2 && tok2->str() == "do" && !findmatch(tok2, tok, "continue|break")) - { - // delete "do {" - tok2->deleteThis(); - tok2->deleteThis(); - - // delete "} while ( 0 )" - tok = tok->previous(); - tok->deleteNext(); // while - tok->deleteNext(); // ( - tok->deleteNext(); // 0 - tok->deleteNext(); // ) - tok->deleteThis(); // } - - continue; - } - } - - // remove "while (0) { .. }" - if (Token::simpleMatch(tok->next()->link(), ") {")) - { - const Token *end = tok->next()->link()->next()->link(); - if (!findmatch(tok, end, "continue|break")) - { - Token::eraseTokens(tok, end ? end->next() : 0); - tok->deleteThis(); // delete "while" - } - } - - } -} - -void Tokenizer::simplifyErrNoInWhile() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() != "errno") - continue; - - Token *endpar = 0; - if (Token::Match(tok->previous(), "&& errno == EINTR ) { ;| }")) - endpar = tok->tokAt(3); - else if (Token::Match(tok->tokAt(-2), "&& ( errno == EINTR ) ) { ;| }")) - endpar = tok->tokAt(4); - else - continue; - - if (Token::simpleMatch(endpar->link()->previous(), "while (")) - { - Token *tok1 = tok->previous(); - if (tok1->str() == "(") - tok1 = tok1->previous(); - - // erase "&& errno == EINTR" - Token::eraseTokens(tok1->previous(), endpar); - - // tok is invalid.. move to endpar - tok = endpar; - - } - } -} - - -void Tokenizer::simplifyFuncInWhile() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (!Token::Match(tok, "while ( %var% ( %var% ) ) {")) - continue; - - Token *func = tok->tokAt(2); - Token *var = tok->tokAt(4); - Token *end = tok->tokAt(7)->link(); - if (!end) - break; - - tok->str("int"); - tok->insertToken("cppcheck:r"); - tok->tokAt(1)->insertToken("="); - tok->tokAt(2)->insertToken(func->str()); - tok->tokAt(3)->insertToken("("); - tok->tokAt(4)->insertToken(var->str()); - tok->tokAt(5)->varId(var->varId()); - tok->tokAt(5)->insertToken(")"); - tok->tokAt(6)->insertToken(";"); - tok->tokAt(7)->insertToken("while"); - tok->tokAt(9)->insertToken("cppcheck:r"); - Token::createMutualLinks(tok->tokAt(4), tok->tokAt(6)); - end->previous()->insertToken("cppcheck:r"); - end->previous()->insertToken("="); - Token::move(func, func->tokAt(3), end->previous()); - end->previous()->insertToken(";"); - - tok = end; - } -} - -void Tokenizer::simplifyStructDecl() -{ - // A counter that is used when giving unique names for anonymous structs. - unsigned int count = 0; - - // Skip simplification of unions in class definition - std::list skip; - skip.push_back(false); - - for (Token *tok = _tokens; tok; tok = tok->next()) - { - Token *restart; - - if (tok->str() == "{") - skip.push_back(!Token::Match(tok->previous(), "const|)")); - else if (tok->str() == "}" && !skip.empty()) - skip.pop_back(); - else if (!skip.empty() && skip.back() && tok->str() == "union") - continue; - - // check for named struct/union - if (Token::Match(tok, "struct|union %type% :|{")) - { - Token *isStatic = tok->previous() && tok->previous()->str() == "static" ? tok->previous() : NULL; - Token *type = tok->next(); - Token *next = tok->tokAt(2); - - while (next && next->str() != "{") - next = next->next(); - if (!next) - continue; - - tok = next->link(); - restart = next; - - // check for named type - if (Token::Match(tok->next(), "*|&| %type% ,|;|[")) - { - tok->insertToken(";"); - tok = tok->next(); - if (isStatic) - { - isStatic->deleteThis(); - tok->insertToken("static"); - tok = tok->next(); - } - tok->insertToken(type->str().c_str()); - } - - tok = restart; - } - - // check for anonymous struct/union - else if (Token::Match(tok, "struct|union {")) - { - Token *tok1 = tok; - - restart = tok->next(); - tok = tok->next()->link(); - - // check for named type - if (Token::Match(tok->next(), "*|&| %type% ,|;|[")) - { - std::string name; - - name = "Anonymous" + MathLib::toString(count++); - - tok1->insertToken(name.c_str()); - - tok->insertToken(";"); - tok = tok->next(); - tok->insertToken(name.c_str()); - } - - // unnamed anonymous struct/union so remove it - else if (tok->next() && tok->next()->str() == ";") - { - if (tok1->str() == "union") - { - // Try to create references in the union.. - Token *tok2 = tok1->tokAt(2); - while (tok2) - { - if (Token::Match(tok2, "%type% %var% ;")) - tok2 = tok2->tokAt(3); - else - break; - } - if (!Token::simpleMatch(tok2, "} ;")) - continue; - Token *vartok = 0; - tok2 = tok1->tokAt(2); - while (Token::Match(tok2, "%type% %var% ;")) - { - if (!vartok) - { - vartok = tok2->next(); - tok2 = tok2->tokAt(3); - } - else - { - tok2->insertToken("&"); - tok2 = tok2->tokAt(2); - tok2->insertToken(vartok->str()); - tok2->next()->varId(vartok->varId()); - tok2->insertToken("="); - tok2 = tok2->tokAt(4); - } - } - } - - tok1->deleteThis(); - if (tok1->next() == tok) - { - tok1->deleteThis(); - tok = tok1; - } - else - tok1->deleteThis(); - restart = tok1->previous(); - tok->deleteThis(); - if (tok->next()) - tok->deleteThis(); - } - - if (!restart) - { - simplifyStructDecl(); - return; - } - else if (!restart->next()) - return; - - tok = restart; - } - } -} - -void Tokenizer::simplifyCallingConvention() -{ - const char * pattern = "__cdecl|__stdcall|__fastcall|__thiscall|__clrcall|__syscall|__pascal|__fortran|__far|__near|WINAPI|APIENTRY|CALLBACK"; - while (Token::Match(_tokens, pattern)) - { - _tokens->deleteThis(); - } - for (Token *tok = _tokens; tok; tok = tok->next()) - { - while (Token::Match(tok->next(), pattern)) - { - tok->deleteNext(); - } - } -} - -void Tokenizer::simplifyDeclspec() -{ - while (Token::simpleMatch(_tokens, "__declspec (") && _tokens->next()->link() && _tokens->next()->link()->next()) - { - Token::eraseTokens(_tokens, _tokens->next()->link()->next()); - _tokens->deleteThis(); - } - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::simpleMatch(tok, "__declspec (") && tok->next()->link() && tok->next()->link()->next()) - { - Token::eraseTokens(tok, tok->next()->link()->next()); - tok->deleteThis(); - } - } -} - -void Tokenizer::simplifyAttribute() -{ - while (Token::simpleMatch(_tokens, "__attribute__ (") && _tokens->next()->link() && _tokens->next()->link()->next()) - { - Token::eraseTokens(_tokens, _tokens->next()->link()->next()); - _tokens->deleteThis(); - } - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::simpleMatch(tok, "__attribute__ (") && tok->next()->link() && tok->next()->link()->next()) - { - if (Token::simpleMatch(tok->tokAt(2), "( unused )")) - { - // check if after variable name - if (Token::Match(tok->next()->link()->next(), ";|=")) - { - if (Token::Match(tok->previous(), "%type%")) - tok->previous()->isUnused(true); - } - - // check if before variable name - else if (Token::Match(tok->next()->link()->next(), "%type%")) - tok->next()->link()->next()->isUnused(true); - } - - Token::eraseTokens(tok, tok->next()->link()->next()); - tok->deleteThis(); - } - } -} - -// Remove "volatile", "inline", "register", and "restrict" -void Tokenizer::simplifyKeyword() -{ - const char pattern[] = "volatile|inline|__inline|__forceinline|register|restrict|__restrict|__restrict__"; - while (Token::Match(_tokens, pattern)) - { - _tokens->deleteThis(); - } - for (Token *tok = _tokens; tok; tok = tok->next()) - { - while (Token::Match(tok->next(), pattern)) - { - tok->deleteNext(); - } - } -} - -void Tokenizer::simplifyAssignmentInFunctionCall() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "(") - tok = tok->link(); - - // Find 'foo(var='. Exclude 'assert(var=' to allow tests to check that assert(...) does not contain side-effects - else if (Token::Match(tok, "[;{}] %var% ( %var% =") && - Token::simpleMatch(tok->tokAt(2)->link(), ") ;") && - tok->strAt(1) != "assert") - { - const std::string funcname(tok->strAt(1)); - const Token * const vartok = tok->tokAt(3); - - // Goto ',' or ')'.. - for (Token *tok2 = tok->tokAt(4); tok2; tok2 = tok2->next()) - { - if (tok2->str() == "(") - tok2 = tok2->link(); - else if (tok2->str() == ";") - break; - else if (tok2->str() == ")" || tok2->str() == ",") - { - tok2 = tok2->previous(); - - tok2->insertToken(vartok->str()); - tok2->next()->varId(vartok->varId()); - - tok2->insertToken("("); - Token::createMutualLinks(tok2->next(), tok->tokAt(2)->link()); - - tok2->insertToken(funcname); - tok2->insertToken(";"); - - Token::eraseTokens(tok, vartok); - break; - } - } - } - } -} - -// Remove __asm.. -void Tokenizer::simplifyAsm() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok->next(), "__asm|_asm|asm {") && - tok->tokAt(2)->link() && - tok->tokAt(2)->link()->next()) - { - Token::eraseTokens(tok, tok->tokAt(2)->link()->next()); - } - - else if (Token::Match(tok->next(), "asm|__asm|__asm__ volatile|__volatile__| (")) - { - // Goto "(" - Token *partok = tok->tokAt(2); - if (partok->str() != "(") - partok = partok->next(); - Token::eraseTokens(tok, partok->link() ? partok->link()->next() : NULL); - } - - else if (Token::simpleMatch(tok->next(), "__asm")) - { - const Token *tok2 = tok->next(); - while (tok2 && (tok2->isNumber() || tok2->isName() || tok2->str() == ",")) - tok2 = tok2->next(); - if (tok2 && tok2->str() == ";") - Token::eraseTokens(tok, tok2); - else - continue; - } - - else - continue; - - // insert "asm ( )" - tok->insertToken(")"); - tok->insertToken("("); - tok->insertToken("asm"); - - Token::createMutualLinks(tok->tokAt(2), tok->tokAt(3)); - } -} - -// Simplify bitfields -void Tokenizer::simplifyBitfields() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - Token *last = 0; - - if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %any% ;|,") && - tok->next()->str() != "case") - { - int offset = 0; - if (tok->next()->str() == "const") - offset = 1; - - last = tok->tokAt(5 + offset); - Token::eraseTokens(tok->tokAt(2 + offset), tok->tokAt(5 + offset)); - } - else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %any% ;") && - tok->next()->str() != "default") - { - int offset = 0; - if (tok->next()->str() == "const") - offset = 1; - - Token::eraseTokens(tok->tokAt(0), tok->tokAt(5 + offset)); - tok = tok->previous(); - } - - if (last && last->str() == ",") - { - Token *tok1 = last; - tok1->str(";"); - - Token *tok2 = tok->next(); - tok1->insertToken(tok2->str()); - tok1 = tok1->next(); - tok1->isSigned(tok2->isSigned()); - tok1->isUnsigned(tok2->isUnsigned()); - tok1->isLong(tok2->isLong()); - } - } -} - - -// Remove __builtin_expect(...), likely(...), and unlikely(...) -void Tokenizer::simplifyBuiltinExpect() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::simpleMatch(tok->next(), "__builtin_expect (")) - { - // Count parantheses for tok2 - unsigned int parlevel = 0; - for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) - { - if (tok2->str() == "(") - ++parlevel; - else if (tok2->str() == ")") - { - if (parlevel <= 1) - break; - --parlevel; - } - if (parlevel == 1 && tok2->str() == ",") - { - if (Token::Match(tok2, ", %num% )")) - { - tok->deleteNext(); - Token::eraseTokens(tok2->previous(), tok2->tokAt(2)); - } - break; - } - } - } - else if (Token::Match(tok->next(), "likely|unlikely (")) - { - // remove closing ')' - tok->tokAt(2)->link()->previous()->deleteNext(); - - // remove "likely|unlikely (" - tok->deleteNext(); - tok->deleteNext(); - } - } -} - - -// Remove Microsoft MFC 'DECLARE_MESSAGE_MAP()' -void Tokenizer::simplifyMicrosoftMFC() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::simpleMatch(tok->next(), "DECLARE_MESSAGE_MAP ( )")) - { - tok->deleteNext(); - tok->deleteNext(); - tok->deleteNext(); - } - else if (Token::Match(tok->next(), "DECLARE_DYNAMIC|DECLARE_DYNAMIC_CLASS|DECLARE_DYNCREATE ( %any% )")) - { - tok->deleteNext(); - tok->deleteNext(); - tok->deleteNext(); - tok->deleteNext(); - } - } -} - - -// Remove Borland code -void Tokenizer::simplifyBorland() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "( __closure * %var% )")) - { - tok->deleteNext(); - } - } - - // I think that these classes are always declared at the outer scope - // I save some time by ignoring inner classes. - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "{") - { - tok = tok->link(); - if (!tok) - break; - } - - if (Token::Match(tok, "class %var% :|{")) - { - // count { and } for tok2 - unsigned int indentlevel = 0; - for (Token *tok2 = tok; tok2; tok2 = tok2->next()) - { - if (tok2->str() == "{") - { - if (indentlevel == 0) - indentlevel = 1; - else - tok2 = tok2->link(); - } - else if (tok2->str() == "}") - { - break; - } - else if (tok2->str() == "__property" && - Token::Match(tok2->previous(), ";|{|}|protected:|public:|__published:")) - { - while (tok2->next() && !Token::Match(tok2, "{|;")) - tok2->deleteThis(); - if (Token::simpleMatch(tok2, "{")) - { - Token::eraseTokens(tok2, tok2->link()); - tok2->deleteThis(); - tok2->deleteThis(); - - // insert "; __property ;" - tok2->previous()->insertToken(";"); - tok2->previous()->insertToken("__property"); - tok2->previous()->insertToken(";"); - } - } - } - } - } -} - -// Remove Qt signals and slots -void Tokenizer::simplifyQtSignalsSlots() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (!Token::Match(tok, "class %var% :")) - continue; - - if (tok->previous() && tok->previous()->str() == "enum") - { - tok = tok->tokAt(2); - continue; - } - - // count { and } for tok2 - unsigned int indentlevel = 0; - for (Token *tok2 = tok; tok2; tok2 = tok2->next()) - { - if (tok2->str() == "{") - { - indentlevel++; - if (indentlevel == 1) - tok = tok2; - else - tok2 = tok2->link(); - } - else if (tok2->str() == "}") - { - indentlevel--; - if (indentlevel == 0) - break; - } - - if (Token::simpleMatch(tok2->next(), "Q_OBJECT")) - { - tok2->deleteNext(); - } - else if (Token::Match(tok2->next(), "public|protected|private slots|Q_SLOTS :")) - { - tok2 = tok2->next(); - tok2->str(tok2->str() + ":"); - tok2->deleteNext(); - tok2->deleteNext(); - } - else if (Token::Match(tok2->next(), "signals|Q_SIGNALS :")) - { - tok2 = tok2->next(); - tok2->str("protected:"); - tok2->deleteNext(); - } - } - } -} - -const SymbolDatabase *Tokenizer::getSymbolDatabase() const -{ - if (!_symbolDatabase) - _symbolDatabase = new SymbolDatabase(this, _settings, _errorLogger); - - return _symbolDatabase; -} - -void Tokenizer::simplifyOperatorName() -{ - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "operator") - { - // operator op - std::string op; - Token *par = tok->next(); - bool done = false; - while (!done && par) - { - done = true; - if (par && par->isName()) - { - op += par->str(); - par = par->next(); - done = false; - } - if (Token::Match(par, "[<>+-*&/=.]") || Token::Match(par, "==|!=|<=|>=")) - { - op += par->str(); - par = par->next(); - done = false; - } - if (Token::simpleMatch(par, "[ ]")) - { - op += "[]"; - par = par->next()->next(); - done = false; - } - if (Token::Match(par, "( *| )")) - { - // break out and simplify.. - if (Token::Match(par, "( ) const| [=;{),]")) - break; - - while (par->str() != ")") - { - op += par->str(); - par = par->next(); - } - op += ")"; - par = par->next(); - done = false; - } - } - - if (par && Token::Match(par->link(), ") const| [=;{),]")) - { - tok->str("operator" + op); - Token::eraseTokens(tok,par); - } - } - } -} - -// remove unnecessary member qualification.. -struct ClassInfo -{ - std::string className; - Token *end; -}; - -void Tokenizer::removeUnnecessaryQualification() -{ - std::stack classInfo; - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (Token::Match(tok, "class|struct %type% :|{") && - (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) - { - tok = tok->next(); - ClassInfo info; - info.className = tok->str(); - tok = tok->next(); - while (tok && tok->str() != "{") - tok = tok->next(); - if (!tok) - return; - info.end = tok->link(); - classInfo.push(info); - } - else if (!classInfo.empty()) - { - if (tok == classInfo.top().end) - classInfo.pop(); - else if (tok->str() == classInfo.top().className && - Token::Match(tok, "%type% :: %type% (") && - Token::Match(tok->tokAt(3)->link(), ") const| {|;") && - tok->previous()->str() != ":") - { - std::list locationList; - ErrorLogger::ErrorMessage::FileLocation loc; - loc.line = tok->linenr(); - loc.setfile(file(tok)); - locationList.push_back(loc); - - const ErrorLogger::ErrorMessage errmsg(locationList, - Severity::portability, - "Extra qualification \'" + tok->str() + "::\' unnecessary and considered an error by many compilers.", - "portability"); - - if (_errorLogger) - _errorLogger->reportErr(errmsg); - else - Check::reportError(errmsg); - - tok->deleteThis(); - tok->deleteThis(); - } - } - } -} - + \ No newline at end of file diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 96ec83945..def7e688e 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -113,6 +113,7 @@ private: TEST_CASE(template20); TEST_CASE(template21); TEST_CASE(template22); + TEST_CASE(template23); TEST_CASE(template_unhandled); TEST_CASE(template_default_parameter); TEST_CASE(template_default_type); @@ -2025,6 +2026,23 @@ private: ASSERT_EQUALS(expected, sizeof_(code)); } + void template23() + { + const char code[] = "template void foo(double &ac) {}\n" + "\n" + "void bar() {\n" + " std::cout << (foo(r));\n" + "}\n"; + + const char expected[] = "; " + "void bar ( ) {" + " std :: cout << ( foo ( r ) ) ; " + "} " + "void foo ( double & ac ) { }"; + + ASSERT_EQUALS(expected, sizeof_(code)); + } + void template_unhandled() { @@ -2805,3773 +2823,4 @@ private: { const char code[] = "void foo(int x)\n" - "{\n" - " goto A;\n" - "A:\n" - " fooA();\n" - " goto B;\n" - " fooNever();\n" - "B:\n" - " fooB();\n" - " return 3;\n" - "}"; - - const char expect[] = "void foo ( int x ) " - "{ " - "fooA ( ) ; " - "fooB ( ) ; " - "return 3 ; " - "fooA ( ) ; " - "fooB ( ) ; " - "return 3 ; " - "fooNever ( ) ; " - "fooB ( ) ; " - "return 3 ; " - "}"; - - ASSERT_EQUALS(expect, tok(code)); - } - - { - const char code[] = "void foo(int x)\n" - "{\n" - " goto A;\n" - "A:\n" - " fooA();\n" - " if( x ) { goto B; }\n" - " fooNever();\n" - "B:\n" - " fooB();\n" - " return 3;\n" - "}"; - - const char expect[] = "void foo ( int x ) " - "{ " - "fooA ( ) ; " - "if ( x ) { " - "fooB ( ) ; " - "return 3 ; } " - "fooNever ( ) ; " - "fooB ( ) ; " - "return 3 ; " - "fooA ( ) ; " - "if ( x ) { " - "fooB ( ) ; " - "return 3 ; } " - "fooNever ( ) ; " - "fooB ( ) ; " - "return 3 ; " - "}"; - - ASSERT_EQUALS(expect, tok(code)); - } - } - - void goto2() - { - // Don't simplify goto inside function call (macro) - const char code[] = "void f ( ) { slist_iter ( if ( a ) { goto dont_write ; } dont_write : ; x ( ) ; ) ; }"; - ASSERT_EQUALS(code, tok(code)); - } - - void strcat1() - { - const char code[] = "; strcat(strcat(strcat(strcat(strcat(strcat(dst, \"this \"), \"\"), \"is \"), \"a \"), \"test\"), \".\");"; - const char expect[] = "; " - "strcat ( dst , \"this \" ) ; " - "strcat ( dst , \"\" ) ; " - "strcat ( dst , \"is \" ) ; " - "strcat ( dst , \"a \" ) ; " - "strcat ( dst , \"test\" ) ; " - "strcat ( dst , \".\" ) ;"; - - ASSERT_EQUALS(expect, tok(code)); - } - void strcat2() - { - const char code[] = "; strcat(strcat(dst, foo[0]), \" \");"; - const char expect[] = "; " - "strcat ( dst , foo [ 0 ] ) ; " - "strcat ( dst , \" \" ) ;"; - - ASSERT_EQUALS(expect, tok(code)); - } - - void argumentsWithSameName() - { - // This code has syntax error, two variables can not have the same name - { - const char code[] = "void foo(x, x)\n" - " int x;\n" - " int x;\n" - "{}\n"; - ASSERT_EQUALS("void foo ( x , x ) int x ; int x ; { }", tok(code)); - } - - { - const char code[] = "void foo(x, y)\n" - " int x;\n" - " int x;\n" - "{}\n"; - ASSERT_EQUALS("void foo ( int x , y ) int x ; { }", tok(code)); - } - } - - void simplifyAtol() - { - ASSERT_EQUALS("a = std :: atol ( x ) ;", tok("a = std::atol(x);")); - ASSERT_EQUALS("a = atol ( \"text\" ) ;", tok("a = atol(\"text\");")); - ASSERT_EQUALS("a = 0 ;", tok("a = std::atol(\"0\");")); - ASSERT_EQUALS("a = 10 ;", tok("a = atol(\"0xa\");")); - } - - void simplifyHexInString() - { - ASSERT_EQUALS("\"a\"", tok("\"\\x61\"")); - ASSERT_EQUALS("\"a\"", tok("\"\\141\"")); - - ASSERT_EQUALS("\"\\0\"", tok("\"\\x00\"")); - ASSERT_EQUALS("\"\\0\"", tok("\"\\000\"")); - - ASSERT_EQUALS("\"\\nhello\"", tok("\"\\nhello\"")); - - ASSERT_EQUALS("\"aaa\"", tok("\"\\x61\\x61\\x61\"")); - ASSERT_EQUALS("\"aaa\"", tok("\"\\141\\141\\141\"")); - - ASSERT_EQUALS("\"\\\\x61\"", tok("\"\\\\x61\"")); - - // These tests can fail, if other characters are handled - // more correctly. But for now all non null characters should - // become 'a' - ASSERT_EQUALS("\"a\"", tok("\"\\x62\"")); - ASSERT_EQUALS("\"a\"", tok("\"\\177\"")); - } - - - std::string simplifyTypedef(const char code[]) - { - errout.str(""); - - Settings settings; - Tokenizer tokenizer(&settings, this); - - std::istringstream istr(code); - tokenizer.createTokens(istr); - tokenizer.createLinks(); - tokenizer.simplifyTypedef(); - - std::string ret; - for (const Token *tok1 = tokenizer.tokens(); tok1; tok1 = tok1->next()) - { - if (tok1 != tokenizer.tokens()) - ret += " "; - ret += tok1->str(); - } - - return ret; - } - - - - void simplifyTypedef1() - { - const char code[] = "class A\n" - "{\n" - "public:\n" - " typedef wchar_t duplicate;\n" - " void foo() {}\n" - "};\n" - "typedef A duplicate;\n" - "int main()\n" - "{\n" - " duplicate a;\n" - " a.foo();\n" - " A::duplicate c = 0;\n" - "}\n"; - - const std::string expected = - "class A " - "{ " - "public: " - "; " - "void foo ( ) { } " - "} ; " - "int main ( ) " - "{ " - "A a ; " - "a . foo ( ) ; " - "wchar_t c ; c = 0 ; " - "}"; - ASSERT_EQUALS(expected, tok(code)); - } - - void simplifyTypedef2() - { - const char code[] = "class A;\n" - "typedef A duplicate;\n" - "class A\n" - "{\n" - "public:\n" - "typedef wchar_t duplicate;\n" - "duplicate foo() { wchar_t b; return b; }\n" - "};\n"; - - const std::string expected = - "class A ; " - "class A " - "{ " - "public: " - "; " - "wchar_t foo ( ) { wchar_t b ; return b ; } " - "} ;"; - ASSERT_EQUALS(expected, tok(code)); - } - - void simplifyTypedef3() - { - const char code[] = "class A {};\n" - "typedef A duplicate;\n" - "wchar_t foo()\n" - "{\n" - "typedef wchar_t duplicate;\n" - "duplicate b;\n" - "return b;\n" - "}\n" - "int main()\n" - "{\n" - "duplicate b;\n" - "}\n"; - - const std::string expected = - "class A { } ; " - "wchar_t foo ( ) " - "{ " - "; " - "wchar_t b ; " - "return b ; " - "} " - "int main ( ) " - "{ " - "A b ; " - "}"; - ASSERT_EQUALS(expected, tok(code)); - } - - void simplifyTypedef4() - { - const char code[] = "typedef int s32;\n" - "typedef unsigned int u32;\n" - "void f()\n" - "{\n" - " s32 ivar = -2;\n" - " u32 uvar = 2;\n" - " return uvar / ivar;\n" - "}\n"; - - const std::string expected = - "; " - "void f ( ) " - "{ " - "int ivar ; ivar = -2 ; " - "unsigned int uvar ; uvar = 2 ; " - "return uvar / ivar ; " - "}"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef5() - { - // ticket #780 - const char code[] = - "typedef struct yy_buffer_state *YY_BUFFER_STATE;\n" - "void f()\n" - "{\n" - " YY_BUFFER_STATE state;\n" - "}\n"; - - const char expected[] = - "; " - "void f ( ) " - "{ " - "struct yy_buffer_state * state ; " - "}"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef6() - { - // ticket #983 - const char code[] = - "namespace VL {\n" - " typedef float float_t ;\n" - " inline VL::float_t fast_atan2(VL::float_t y, VL::float_t x){}\n" - "}\n"; - - const char expected[] = - "namespace VL { " - "; " - "float fast_atan2 ( float y , float x ) { } " - "}"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef7() - { - const char code[] = "typedef int abc ; " - "Fred :: abc f ;"; - const char expected[] = - "; " - "Fred :: abc f ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef8() - { - const char code[] = "typedef int INT;\n" - "typedef unsigned int UINT;\n" - "typedef int * PINT;\n" - "typedef unsigned int * PUINT;\n" - "typedef int & RINT;\n" - "typedef unsigned int & RUINT;\n" - "typedef const int & RCINT;\n" - "typedef const unsigned int & RCUINT;\n" - "INT ti;\n" - "UINT tui;\n" - "PINT tpi;\n" - "PUINT tpui;\n" - "RINT tri;\n" - "RUINT trui;\n" - "RCINT trci;\n" - "RCUINT trcui;"; - - const char expected[] = - "; " - "int ti ; " - "unsigned int tui ; " - "int * tpi ; " - "unsigned int * tpui ; " - "int & tri ; " - "unsigned int & trui ; " - "const int & trci ; " - "const unsigned int & trcui ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef9() - { - const char code[] = "typedef struct s S, * PS;\n" - "typedef struct t { int a; } T, *TP;\n" - "typedef struct { int a; } U;\n" - "typedef struct { int a; } * V;\n" - "S s;\n" - "PS ps;\n" - "T t;\n" - "TP tp;\n" - "U u;\n" - "V v;"; - - const char expected[] = - "; " - "struct t { int a ; } ; " - "struct U { int a ; } ; " - "struct Unnamed0 { int a ; } ; " - "struct s s ; " - "struct s * ps ; " - "struct t t ; " - "struct t * tp ; " - "struct U u ; " - "struct Unnamed0 * v ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef10() - { - const char code[] = "typedef union s S, * PS;\n" - "typedef union t { int a; float b ; } T, *TP;\n" - "typedef union { int a; float b; } U;\n" - "typedef union { int a; float b; } * V;\n" - "S s;\n" - "PS ps;\n" - "T t;\n" - "TP tp;\n" - "U u;\n" - "V v;"; - - const char expected[] = - "; " - "union t { int a ; float b ; } ; " - "union U { int a ; float b ; } ; " - "union Unnamed1 { int a ; float b ; } ; " - "union s s ; " - "union s * ps ; " - "union t t ; " - "union t * tp ; " - "union U u ; " - "union Unnamed1 * v ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef11() - { - const char code[] = "typedef enum { a = 0 , b = 1 , c = 2 } abc;\n" - "typedef enum xyz { x = 0 , y = 1 , z = 2 } XYZ;\n" - "abc e1;\n" - "XYZ e2;"; - - const char expected[] = - "; " - "int e1 ; " - "int e2 ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef12() - { - const char code[] = "typedef vector V1;\n" - "typedef std::vector V2;\n" - "typedef std::vector > V3;\n" - "typedef std::list::iterator IntListIterator;\n" - "V1 v1;\n" - "V2 v2;\n" - "V3 v3;\n" - "IntListIterator iter;"; - - const char expected[] = - "; " - "vector < int > v1 ; " - "std :: vector < int > v2 ; " - "std :: vector < std :: vector < int > > v3 ; " - "std :: list < int > :: iterator iter ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef13() - { - // ticket # 1167 - const char code[] = "typedef std::pair Func;" - "typedef std::vector CallQueue;" - "int main() {}"; - - // Clear the error buffer.. - errout.str(""); - - Settings settings; - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); - - tokenizer.simplifyTokenList(); - - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef14() - { - // ticket # 1232 - const char code[] = "template struct E" - "{" - " typedef E0)?(N-1):0> v;" - " typedef typename add::val val;" - " FP_M(val);" - "};" - "template struct E " - "{" - " typedef typename D<1>::val val;" - " FP_M(val);" - "};"; - - // Clear the error buffer.. - errout.str(""); - - Settings settings; - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); - - tokenizer.simplifyTokenList(); - - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef15() - { - { - const char code[] = "typedef char frame[10];\n" - "frame f;"; - - const char expected[] = - "; " - "char f [ 10 ] ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "typedef unsigned char frame[10];\n" - "frame f;"; - - const char expected[] = - "; " - "unsigned char f [ 10 ] ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - } - - void simplifyTypedef16() - { - // ticket # 1252 - const char code[] = "typedef char MOT8;\n" - "typedef MOT8 CHFOO[4096];\n" - "typedef struct {\n" - " CHFOO freem;\n" - "} STRFOO;"; - - // Clear the error buffer.. - errout.str(""); - - Settings settings; - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); - - tokenizer.simplifyTokenList(); - - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef17() - { - const char code[] = "typedef char * PCHAR, CHAR;\n" - "PCHAR pc;\n" - "CHAR c;"; - - const char expected[] = - "; " - "char * pc ; " - "char c ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef18() - { - const char code[] = "typedef vector a;\n" - "a b;\n"; - - // Clear the error buffer.. - errout.str(""); - - Settings settings; - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); - - tokenizer.simplifyTokenList(); - - ASSERT_EQUALS(true, tokenizer.validate()); - } - - void simplifyTypedef19() - { - { - // ticket #1275 - const char code[] = "typedef struct {} A, *B, **C;\n" - "A a;\n" - "B b;\n" - "C c;"; - - const char expected[] = - "struct A { } ; " - "struct A a ; " - "struct A * b ; " - "struct A * * c ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "typedef struct {} A, *********B;\n" - "A a;\n" - "B b;"; - - const char expected[] = - "struct A { } ; " - "struct A a ; " - "struct A * * * * * * * * * b ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "typedef struct {} **********A, *B, C;\n" - "A a;\n" - "B b;\n" - "C c;"; - - const char expected[] = - "struct Unnamed2 { } ; " - "struct Unnamed2 * * * * * * * * * * a ; " - "struct Unnamed2 * b ; " - "struct Unnamed2 c ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - } - - void simplifyTypedef20() - { - // ticket #1284 - const char code[] = "typedef jobject invoke_t (jobject, Proxy *, Method *, JArray< jobject > *);"; - - // Clear the error buffer.. - errout.str(""); - - Settings settings; - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); - - tokenizer.simplifyTokenList(); - - ASSERT_EQUALS(true, tokenizer.validate()); - } - - void simplifyTypedef21() - { - const char code[] = "typedef void (* PF)();\n" - "typedef void * (* PFV)(void *);\n" - "PF pf;\n" - "PFV pfv;"; - - const char expected[] = - "; " - "; " - "void ( * pf ) ( ) ; " - "void * ( * pfv ) ( void * ) ;"; - - ASSERT_EQUALS(expected, simplifyTypedef(code)); - } - - void simplifyTypedef22() - { - { - const char code[] = "class Fred {\n" - " typedef void (*testfp)();\n" - " testfp get() { return test; }\n" - " static void test() { }\n" - "};"; - - const char expected[] = - "class Fred { " - "; " - "void ( * get ( ) ) ( ) { return test ; } " - "static void test ( ) { } " - "} ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "class Fred {\n" - " typedef void * (*testfp)(void *);\n" - " testfp get() { return test; }\n" - " static void * test(void * p) { return p; }\n" - "};\n"; - - const char expected[] = - "class Fred { " - "; " - "void * ( * get ( ) ) ( void * ) { return test ; } " - "static void * test ( void * p ) { return p ; } " - "} ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "class Fred {\n" - " typedef unsigned int * (*testfp)(unsigned int *);\n" - " testfp get() { return test; }\n" - " static unsigned int * test(unsigned int * p) { return p; }\n" - "};\n"; - - const char expected[] = - "class Fred { " - "; " - "unsigned int * ( * get ( ) ) ( unsigned int * ) { return test ; } " - "static unsigned int * test ( unsigned int * p ) { return p ; } " - "} ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "class Fred {\n" - " typedef const unsigned int * (*testfp)(const unsigned int *);\n" - " testfp get() { return test; }\n" - " static const unsigned int * test(const unsigned int * p) { return p; }\n" - "};\n"; - - // static const gets changed to const static - const char expected[] = - "class Fred { " - "; " - "const unsigned int * ( * get ( ) ) ( const unsigned int * ) { return test ; } " - "const static unsigned int * test ( const unsigned int * p ) { return p ; } " - "} ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "class Fred {\n" - " typedef void * (*testfp)(void *);\n" - " testfp get(int i) { return test; }\n" - " static void * test(void * p) { return p; }\n" - "};\n"; - - const char expected[] = - "class Fred { " - "; " - "void * ( * get ( int i ) ) ( void * ) { return test ; } " - "static void * test ( void * p ) { return p ; } " - "} ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - } - - void simplifyTypedef23() - { - const char code[] = "typedef bool (*Callback) (int i);\n" - "void addCallback(Callback callback) { }\n" - "void addCallback1(Callback callback, int j) { }"; - - const char expected[] = - "; " - "void addCallback ( bool * callback ) { } " - "void addCallback1 ( bool * callback , int j ) { }"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef24() - { - { - const char code[] = "typedef int (*fp)();\n" - "void g( fp f )\n" - "{\n" - " fp f2 = (fp)f;\n" - "}"; - - const char expected[] = - "; " - "void g ( int * f ) " - "{ " - "int * f2 ; f2 = ( int * ) f ; " - "}"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "typedef int (*fp)();\n" - "void g( fp f )\n" - "{\n" - " fp f2 = static_cast(f);\n" - "}"; - - const char expected[] = - "; " - "void g ( int * f ) " - "{ " - "int * f2 ; f2 = static_cast < int * > ( f ) ; " - "}"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - } - - void simplifyTypedef25() - { - { - // ticket #1298 - const char code[] = "typedef void (*fill_names_f) (const char *);\n" - "struct vfs_class {\n" - " void (*fill_names) (struct vfs_class *me, fill_names_f);\n" - "}"; - - const char expected[] = - "; " - "struct vfs_class { " - "void ( * fill_names ) ( struct vfs_class * me , void ( * ) ( const char * ) ) ; " - "}"; - - ASSERT_EQUALS(expected, simplifyTypedef(code)); - } - - { - const char code[] = "typedef void (*fill_names_f) (const char *);\n" - "struct vfs_class {\n" - " void (*fill_names) (fill_names_f, struct vfs_class *me);\n" - "}"; - - const char expected[] = - "; " - "struct vfs_class { " - "void ( * fill_names ) ( void ( * ) ( const char * ) , struct vfs_class * me ) ; " - "}"; - - ASSERT_EQUALS(expected, simplifyTypedef(code)); - } - } - - void simplifyTypedef26() - { - { - const char code[] = "typedef void (*Callback) ();\n" - "void addCallback(Callback (*callback)());"; - - const char expected[] = - "; " - "void addCallback ( void ( * ( * callback ) ( ) ) ( ) ) ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - // ticket # 1307 - const char code[] = "typedef void (*pc_video_update_proc)(bitmap_t *bitmap,\n" - "struct mscrtc6845 *crtc);\n" - "\n" - "struct mscrtc6845 *pc_video_start(pc_video_update_proc (*choosevideomode)(running_machine *machine, int *width, int *height, struct mscrtc6845 *crtc));"; - - const char expected[] = - "; " - "struct mscrtc6845 * pc_video_start ( void ( * ( * choosevideomode ) ( running_machine * machine , int * width , int * height , struct mscrtc6845 * crtc ) ) ( bitmap_t * bitmap , struct mscrtc6845 * crtc ) ) ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - } - - void simplifyTypedef27() - { - // ticket #1316 - const char code[] = "int main()\n" - "{\n" - " typedef int (*func_ptr)(float, double);\n" - " VERIFY((is_same::type, int>::value));\n" - "}"; - - const char expected[] = - "int main ( ) " - "{ " - "; " - "VERIFY ( is_same < result_of < int ( * ( char , float ) ) ( float , double ) > :: type , int > :: value ) ; " - "}"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef28() - { - const char code[] = "typedef std::pair (*F)(double);\n" - "F f;"; - - const char expected[] = - "; " - "std :: pair < double , double > ( * f ) ( double ) ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef29() - { - const char code[] = "typedef int array [ice_or::value, is_int::value>::value ? 1 : -1];\n" - "typedef int array1 [N];\n" - "typedef int array2 [N][M];\n" - "typedef int int_t, int_array[N];\n" - "array a;\n" - "array1 a1;\n" - "array2 a2;\n" - "int_t t;\n" - "int_array ia;"; - - const char expected[] = - "; " - "int a [ ice_or < is_int < int > :: value , is_int < UDT > :: value > :: value ? 1 : - 1 ] ; " - "int a1 [ N ] ; " - "int a2 [ N ] [ M ] ; " - "int t ; " - "int ia [ N ] ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef30() - { - const char code[] = "typedef ::std::list int_list;\n" - "typedef ::std::list::iterator int_list_iterator;\n" - "typedef ::std::list int_list_array[10];\n" - "int_list il;\n" - "int_list_iterator ili;\n" - "int_list_array ila;"; - - const char expected[] = - "; " - ":: std :: list < int > il ; " - ":: std :: list < int > :: iterator ili ; " - ":: std :: list < int > ila [ 10 ] ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef31() - { - { - const char code[] = "class A {\n" - "public:\n" - " typedef int INT;\n" - " INT get() const;\n" - " void put(INT x) { a = x; }\n" - " INT a;\n" - "};\n" - "A::INT A::get() const { return a; }\n" - "A::INT i = A::a;"; - - const char expected[] = "class A { " - "public: " - "; " - "int get ( ) const ; " - "void put ( int x ) { a = x ; } " - "int a ; " - "} ; " - "int A :: get ( ) const { return a ; } " - "int i ; i = A :: a ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct A {\n" - " typedef int INT;\n" - " INT get() const;\n" - " void put(INT x) { a = x; }\n" - " INT a;\n" - "};\n" - "A::INT A::get() const { return a; }\n" - "A::INT i = A::a;"; - - const char expected[] = "struct A { " - "; " - "int get ( ) const ; " - "void put ( int x ) { a = x ; } " - "int a ; " - "} ; " - "int A :: get ( ) const { return a ; } " - "int i ; i = A :: a ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - } - - void simplifyTypedef32() - { - const char code[] = "typedef char CHAR;\n" - "typedef CHAR * LPSTR;\n" - "typedef const CHAR * LPCSTR;\n" - "CHAR c;\n" - "LPSTR cp;\n" - "LPCSTR ccp;"; - - const char expected[] = - "; " - "char c ; " - "char * cp ; " - "const char * ccp ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef33() - { - const char code[] = "class A {\n" - "public:\n" - " typedef char CHAR_A;\n" - " CHAR_A funA();\n" - " class B {\n" - " public:\n" - " typedef short SHRT_B;\n" - " SHRT_B funB();\n" - " class C {\n" - " public:\n" - " typedef int INT_C;\n" - " INT_C funC();\n" - " struct D {\n" - " typedef long LONG_D;\n" - " LONG_D funD();\n" - " LONG_D d;\n" - " };\n" - " INT_C c;\n" - " };\n" - " SHRT_B b;\n" - " };\n" - " CHAR_A a;\n" - "};\n" - "A::CHAR_A A::funA() { return a; }\n" - "A::B::SHRT_B A::B::funB() { return b; }\n" - "A::B::C::INT_C A::B::C::funC() { return c; }" - "A::B::C::D::LONG_D A::B::C::D::funD() { return d; }"; - - const char expected[] = - "class A { " - "public: " - "; " - "char funA ( ) ; " - "class B { " - "public: " - "; " - "short funB ( ) ; " - "class C { " - "public: " - "; " - "int funC ( ) ; " - "struct D { " - "; " - "long funD ( ) ; " - "long d ; " - "} ; " - "int c ; " - "} ; " - "short b ; " - "} ; " - "char a ; " - "} ; " - "char A :: funA ( ) { return a ; } " - "short A :: B :: funB ( ) { return b ; } " - "int A :: B :: C :: funC ( ) { return c ; } " - "long A :: B :: C :: D :: funD ( ) { return d ; }"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef34() - { - // ticket #1411 - const char code[] = "class X { };\n" - "typedef X (*foofunc)(const X&);\n" - "int main()\n" - "{\n" - " foofunc *Foo = new foofunc[2];\n" - "}"; - const char expected[] = - "class X { } ; " - "int main ( ) " - "{ " - "X ( * * Foo ) ( const X & ) = new X ( * ) ( const X & ) [ 2 ] ; " - "}"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - // Check simplifyTypedef - void checkSimplifyTypedef(const char code[]) - { - errout.str(""); - // Tokenize.. - Settings settings; - settings.inconclusive = true; - settings._checkCodingStyle = true; - settings.debugwarnings = true; // show warnings about unhandled typedef - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); - } - - void simplifyTypedef35() - { - const char code[] = "typedef int A;\n" - "class S\n" - "{\n" - "public:\n" - " typedef float A;\n" - " A a;\n" - " virtual void fun(A x);\n" - "};\n" - "void S::fun(S::A) { };\n" - "class S1 : public S\n" - "{\n" - "public:\n" - " void fun(S::A) { }\n" - "};\n" - "struct T\n" - "{\n" - " typedef A B;\n" - " B b;\n" - "};\n" - "float fun1(float A) { return A; }\n" - "float fun2(float a) { float A = a++; return A; }\n" - "float fun3(int a)\n" - "{\n" - " typedef struct { int a; } A;\n" - " A s; s.a = a;\n" - " return s.a;\n" - "}\n" - "int main()\n" - "{\n" - " A a = 0;\n" - " S::A s = fun1(a) + fun2(a) - fun3(a);\n" - " return a + s;\n" - "}"; - - const char expected[] = "; " - "class S " - "{ " - "public: " - "; " - "float a ; " - "virtual void fun ( float x ) ; " - "} ; " - "void S :: fun ( float ) { } ; " - "class S1 : public S " - "{ " - "public: " - "void fun ( float ) { } " - "} ; " - "struct T " - "{ " - "; " - "int b ; " - "} ; " - "float fun1 ( float A ) { return A ; } " - "float fun2 ( float a ) { float A ; A = a ++ ; return A ; } " - "float fun3 ( int a ) " - "{ " - "struct A { int a ; } ; " - "struct A s ; s . a = a ; " - "return s . a ; " - "} " - "int main ( ) " - "{ " - "int a ; a = 0 ; " - "float s ; s = fun1 ( a ) + fun2 ( a ) - fun3 ( a ) ; " - "return a + s ; " - "}"; - - ASSERT_EQUALS(expected, tok(code, false)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n" - "[test.cpp:20] -> [test.cpp:1]: (style) Function parameter 'A' hides typedef with same name\n" - "[test.cpp:21] -> [test.cpp:1]: (style) Variable 'A' hides typedef with same name\n" - "[test.cpp:24] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n", errout.str()); - } - - void simplifyTypedef36() - { - // ticket #1434 - const char code[] = "typedef void (*TIFFFaxFillFunc)();\n" - "void f(va_list ap)\n" - "{\n" - " *va_arg(ap, TIFFFaxFillFunc*) = 0;\n" - "}"; - const char expected[] = "; " - "void f ( va_list ap ) " - "{ " - "* va_arg ( ap , void ( * * ) ( ) ) = 0 ; " - "}"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - void simplifyTypedef37() - { - { - // ticket #1449 - const char code[] = "template class V {};\n" - "typedef V A;\n" - "typedef int B;\n" - "typedef V A;\n" - "typedef int B;"; - - checkSimplifyTypedef(code); - ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:2]: (style) Typedef 'A' hides typedef with same name\n" - "[test.cpp:5] -> [test.cpp:3]: (style) Typedef 'B' hides typedef with same name\n", errout.str()); - } - - { - const char code[] = "typedef int INT;\n" - "void f()\n" - "{\n" - " INT i; { }\n" - "}"; - const char expected[] = "; " - "void f ( ) " - "{ " - "int i ; { } " - "}"; - ASSERT_EQUALS(expected, tok(code, false)); - } - } - - void simplifyTypedef38() - { - const char code[] = "typedef C A;\n" - "struct AB : public A, public B { };"; - const char expected[] = "; struct AB : public C , public B { } ;"; - ASSERT_EQUALS(expected, tok(code, false)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef39() - { - const char code[] = "typedef int A;\n" - "template ::value;"; - const char expected[] = ";"; - ASSERT_EQUALS(expected, tok(code, false)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef40() - { - const char code[] = "typedef int A;\n" - "typedef int B;\n" - "template class C { };"; - const char expected[] = ";"; - ASSERT_EQUALS(expected, tok(code, false)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:1]: (style) Template parameter 'A' hides typedef with same name\n" - "[test.cpp:3] -> [test.cpp:2]: (style) Template parameter 'B' hides typedef with same name\n", errout.str()); - - checkSimplifyTypedef("typedef tuple t2;\n" - "void ordering_test()\n" - "{\n" - " tuple t2(5, 3.3f);\n" - " BOOST_CHECK(t3 > t2);\n" - "}"); - ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:1]: (style) Template instantiation 't2' hides typedef with same name\n", errout.str()); - - checkSimplifyTypedef("class MyOverflowingUnsigned\n" - "{\n" - "public:\n" - " typedef unsigned self_type::* bool_type;\n" - " operator bool_type() const { return this->v_ ? &self_type::v_ : 0; }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - checkSimplifyTypedef("typedef int (*fptr_type)(int, int);\n" - "struct which_one {\n" - " typedef fptr_type (*result_type)(bool x);\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - checkSimplifyTypedef("class my_configuration\n" - "{\n" - "public:\n" - " template < typename T >\n" - " class hook\n" - " {\n" - " public:\n" - " typedef ::boost::rational rational_type;\n" - " public:\n" - " rational_type ( &r_ )[ 9 ];\n" - " };\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - checkSimplifyTypedef("class A\n" - "{\n" - " typedef B b;\n" - " friend b;\n" - "};"); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef41() - { - // ticket #1488 - checkSimplifyTypedef("class Y;\n" - "class X\n" - "{\n" - " typedef Y type;\n" - " friend class type;\n" - "};"); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef42() - { - // ticket #1506 - checkSimplifyTypedef("typedef struct A { } A;\n" - "struct A;"); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Struct 'A' forward declaration unnecessary, already declared\n", errout.str()); - - checkSimplifyTypedef("typedef union A { int i; float f; } A;\n" - "union A;"); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Union 'A' forward declaration unnecessary, already declared\n", errout.str()); - - checkSimplifyTypedef("typedef std::map A;\n" - "class A;"); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Class 'A' forward declaration unnecessary, already declared\n", errout.str()); - } - - void simplifyTypedef43() - { - // ticket #1588 - { - const char code[] = "typedef struct foo A;\n" - "struct A\n" - "{\n" - " int alloclen;\n" - "};\n"; - - // The expected result.. - const std::string expected("; " - "struct A " - "{ " - "int alloclen ; " - "} ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Struct 'A' hides typedef with same name\n", errout.str()); - } - - { - const char code[] = "typedef union foo A;\n" - "union A\n" - "{\n" - " int alloclen;\n" - "};\n"; - - // The expected result.. - const std::string expected("; " - "union A " - "{ " - "int alloclen ; " - "} ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Union 'A' hides typedef with same name\n", errout.str()); - } - - { - const char code[] = "typedef class foo A;\n" - "class A\n" - "{\n" - " int alloclen;\n" - "};\n"; - - // The expected result.. - const std::string expected("; " - "class A " - "{ " - "int alloclen ; " - "} ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Class 'A' hides typedef with same name\n", errout.str()); - } - } - - void simplifyTypedef44() - { - { - const char code[] = "typedef std::map Map;\n" - "class MyMap : public Map\n" - "{\n" - "};\n"; - - // The expected result.. - const std::string expected("; " - "class MyMap : public std :: map < std :: string , int > " - "{ " - "} ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef std::map Map;\n" - "class MyMap : protected Map\n" - "{\n" - "};\n"; - - // The expected result.. - const std::string expected("; " - "class MyMap : protected std :: map < std :: string , int > " - "{ " - "} ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef std::map Map;\n" - "class MyMap : private Map\n" - "{\n" - "};\n"; - - // The expected result.. - const std::string expected("; " - "class MyMap : private std :: map < std :: string , int > " - "{ " - "} ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef struct foo { } A;\n" - "struct MyA : public A\n" - "{\n" - "};\n"; - - // The expected result.. - const std::string expected("struct foo { } ; " - "struct MyA : public foo " - "{ " - "} ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef class foo { } A;\n" - "class MyA : public A\n" - "{\n" - "};\n"; - - // The expected result.. - const std::string expected("class foo { } ; " - "class MyA : public foo " - "{ " - "} ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - } - - void simplifyTypedef45() - { - // ticket # 1613 - const char code[] = "void fn() {\n" - " typedef foo<> bar;\n" - " while (0 > bar(1)) {}\n" - "}"; - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef46() - { - const char code[] = "typedef const struct A { int a; } * AP;\n" - "AP ap;\n"; - - // The expected result.. - const std::string expected("struct A { int a ; } ; " - "const struct A * ap ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - } - - void simplifyTypedef47() - { - { - const char code[] = "typedef std::pair const I;\n" - "I i;"; - - // The expected result.. - const std::string expected("; " - "std :: pair < int , int > const i ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - } - - { - const char code[] = "typedef void (X:: *F)();\n" - "F f;"; - - // The expected result.. - const std::string expected("; " - "void ( X :: * f ) ( ) ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - } - } - - void simplifyTypedef48() // ticket #1673 - { - const char code[] = "typedef struct string { } string;\n" - "void foo (LIST *module_name)\n" - "{\n" - " bar(module_name ? module_name->string : 0);\n" - "}\n"; - - // The expected result.. - const std::string expected("struct string { } ; " - "void foo ( LIST * module_name ) " - "{ " - "bar ( module_name ? module_name . string : 0 ) ; " - "}"); - ASSERT_EQUALS(expected, sizeof_(code)); - } - - void simplifyTypedef49() // ticket #1691 - { - const char code[] = "class Class2 {\n" - "typedef const Class & Const_Reference;\n" - "void some_method (Const_Reference x) const {}\n" - "void another_method (Const_Reference x) const {}\n" - "}"; - - // The expected result.. - const std::string expected("class Class2 { " - "; " - "void some_method ( const Class & x ) const { } " - "void another_method ( const Class & x ) const { } " - "}"); - ASSERT_EQUALS(expected, sizeof_(code)); - } - - void simplifyTypedef50() - { - const char code[] = "typedef char (* type1)[10];\n" - "typedef char (& type2)[10];\n" - "typedef char (& type3)[x];\n" - "typedef char (& type4)[x + 2];\n" - "type1 t1;\n" - "type1 (*tp1)[2];\n" - "type2 t2;\n" - "type3 t3;\n" - "type4 t4;"; - - // The expected result.. - const std::string expected("; " - "char ( * t1 ) [ 10 ] ; " - "char ( * ( * tp1 ) [ 2 ] ) [ 10 ] ; " - "char ( & t2 ) [ 10 ] ; " - "char ( & t3 ) [ x ] ; " - "char ( & t4 ) [ x + 2 ] ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - } - - void simplifyTypedef51() - { - const char code[] = "class A { public: int i; };\n" - "typedef const char (A :: * type1);\n" - "type1 t1 = &A::i;"; - - // The expected result.. - const std::string expected("class A { public: int i ; } ; " - "const char ( A :: * t1 ) = & A :: i ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - } - - void simplifyTypedef52() // ticket #1782 - { - { - const char code[] = "typedef char (* type1)[10];\n" - "type1 foo() { }"; - - // The expected result.. - const std::string expected("; " - "char ( * foo ( ) ) [ 10 ] { }"); - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef char (* type1)[10];\n" - "LOCAL(type1) foo() { }"; - - // this is invalid C so just make sure it doesn't generate an internal error - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - } - - void simplifyTypedef53() // ticket #1801 - { - { - const char code[] = "typedef int ( * int ( * ) ( ) ) ( ) ;"; - - // this is invalid C so just make sure it doesn't crash - checkSimplifyTypedef(code); - ASSERT_EQUALS("[test.cpp:1]: (debug) Failed to parse 'typedef int ( * int ( * ) ( ) ) ( ) ;'. The checking continues anyway.\n", errout.str()); - } - - { - const char code[] = "typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);\n" - "typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);\n"; - - checkSimplifyTypedef(code); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Typedef 'PPDMarkOption' hides typedef with same name\n", errout.str()); - } - - { - const char code[] = "typedef int * A;\n" - "typedef int * A;\n"; - checkSimplifyTypedef(code); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n", errout.str()); - } - } - - void simplifyTypedef54() // ticket #1814 - { - const char code[] = "void foo()\n" - "{\n" - " typedef std::basic_string string_type;\n" - " try\n" - " {\n" - " throw string_type(\"leak\");\n" - " }\n" - " catch (const string_type&)\n" - " {\n" - " pthread_exit (0);\n" - " }\n" - "}"; - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef55() - { - const char code[] = "typedef volatile unsigned long * const hwreg_t ;\n" - "typedef void *const t1[2];\n" - "typedef int*const *_Iterator;\n" - "hwreg_t v1;\n" - "t1 v2;\n" - "_Iterator v3;\n"; - - // The expected result.. - const std::string expected("; " - "long * v1 ; " - "void * v2 [ 2 ] ; " - "int * * v3 ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef56() // ticket #1829 - { - const char code[] = "struct C {\n" - " typedef void (*fptr)();\n" - " const fptr pr;\n" - " operator const fptr& () { return pr; }\n" - "};\n"; - - // The expected result.. - const std::string expected("struct C { " - "; " - "const void * pr ; " // this gets simplified to a regular pointer - "operatorconstvoid(*)()& ( ) { return pr ; } " - "} ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef57() // ticket #1846 - { - const char code[] = "void foo {\n" - " typedef int A;\n" - " A a = A(1) * A(2);\n" - "};\n"; - - // The expected result.. - const std::string expected("void foo { " - "; " - "int a ; a = int ( 1 ) * int ( 2 ) ; " - "} ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef58() // ticket #1963 - { - { - const char code[] = "typedef int vec2_t[2];\n" - "vec2_t coords[4] = {1,2,3,4,5,6,7,8};\n"; - - // The expected result.. - const std::string expected("; " - "int coords [ 4 ] [ 2 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef int vec2_t[2];\n" - "vec2_t coords[4][5][6+1] = {1,2,3,4,5,6,7,8};\n"; - - // The expected result.. - const std::string expected("; " - "int coords [ 4 ] [ 5 ] [ 7 ] [ 2 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - } - - void simplifyTypedef59() // ticket #2011 - { - const char code[] = "template class SomeTemplateClass {\n" - " typedef void (SomeTemplateClass::*MessageDispatcherFunc)(SerialInputMessage&);\n" - "};\n"; - // The expected result.. - const std::string expected(";"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef60() // ticket #2035 - { - const char code[] = "typedef enum {qfalse, qtrue} qboolean;\n" - "typedef qboolean (*localEntitiyAddFunc_t) (struct le_s * le, entity_t * ent);\n" - "void f()\n" - "{\n" - " qboolean b;\n" - " localEntitiyAddFunc_t f;\n" - "}\n"; - // The expected result.. - const std::string expected("; void f ( ) { int b ; int * f ; }"); - ASSERT_EQUALS(expected, sizeof_(code, false)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef61() // ticket #2074 and 2075 - { - const char code1[] = "typedef unsigned char (*Mf_GetIndexByte_Func) (void);\n" - "typedef const unsigned char * (*Mf_GetPointerToCurrentPos_Func)(void);\n"; - - // Check for output.. - checkSimplifyTypedef(code1); - ASSERT_EQUALS("", errout.str()); - - const char code2[] = "typedef unsigned long uint32_t;\n" - "typedef uint32_t (*write_type_t) (uint32_t);\n"; - - // Check for output.. - checkSimplifyTypedef(code2); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef62() // ticket #2082 - { - const char code1[] = "typedef char TString[256];\n" - "void f()\n" - "{\n" - " TString a, b;\n" - "}"; - - // The expected tokens.. - const std::string expected1("; void f ( ) { char a [ 256 ] ; char b [ 256 ] ; }"); - ASSERT_EQUALS(expected1, sizeof_(code1, false)); - - // Check for output.. - checkSimplifyTypedef(code1); - ASSERT_EQUALS("", errout.str()); - - const char code2[] = "typedef char TString[256];\n" - "void f()\n" - "{\n" - " TString a = { 0 }, b = { 0 };\n" - "}"; - - // The expected tokens.. - const std::string expected2("; void f ( ) { char a [ 256 ] = { 0 } ; char b [ 256 ] = { 0 } ; }"); - ASSERT_EQUALS(expected2, tok(code2, false)); - - // Check for output.. - checkSimplifyTypedef(code2); - ASSERT_EQUALS("", errout.str()); - - const char code3[] = "typedef char TString[256];\n" - "void f()\n" - "{\n" - " TString a = \"\", b = \"\";\n" - "}"; - - // The expected tokens.. - const std::string expected3("; void f ( ) { char a [ 256 ] = \"\" ; char b [ 256 ] = \"\" ; }"); - ASSERT_EQUALS(expected3, tok(code3, false)); - - // Check for output.. - checkSimplifyTypedef(code3); - ASSERT_EQUALS("", errout.str()); - - const char code4[] = "typedef char TString[256];\n" - "void f()\n" - "{\n" - " TString a = \"1234\", b = \"5678\";\n" - "}"; - - // The expected tokens.. - const std::string expected4("; void f ( ) { char a [ 256 ] = \"1234\" ; char b [ 256 ] = \"5678\" ; }"); - ASSERT_EQUALS(expected4, tok(code4, false)); - - // Check for output.. - checkSimplifyTypedef(code4); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef63() // ticket #2175 'typedef float x[3];' - { - const char code[] = "typedef float x[3];\n" - "x a,b,c;\n"; - const std::string actual(sizeof_(code)); - ASSERT_EQUALS("; float a [ 3 ] ; float b [ 3 ] ; float c [ 3 ] ;", actual); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef64() - { - const char code[] = "typedef __typeof__(__type1() + __type2()) __type;" - "__type t;\n"; - const std::string actual(sizeof_(code)); - ASSERT_EQUALS("; __typeof__ ( __type1 ( ) + __type2 ( ) ) t ;", actual); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef65() // ticket #2314 - { - const char code[] = "typedef BAR Foo; \n" - "int main() { \n" - " Foo b(0); \n" - " return b > Foo(10); \n" - "}"; - const std::string actual(sizeof_(code)); - ASSERT_EQUALS("; int main ( ) { BAR < int > b ( 0 ) ; return b > BAR < int > ( 10 ) ; }", actual); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef66() // ticket #2341 - { - const char code[] = "typedef long* GEN;\n" - "extern GEN (*foo)(long);"; - const std::string actual(sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef67() // ticket #2354 - { - const char code[] = "typedef int ( * Function ) ( ) ;\n" - "void f ( ) {\n" - " ((Function * (*) (char *, char *, int, int)) global[6]) ( \"assoc\", \"eggdrop\", 106, 0);\n" - "}\n"; - const std::string expected = "; " - "void f ( ) { " - "( ( int ( * * ( * ) ( char * , char * , int , int ) ) ( ) ) global [ 6 ] ) ( \"assoc\" , \"eggdrop\" , 106 , 0 ) ; " - "}"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef68() // ticket #2355 - { - const char code[] = "typedef FMAC1 void (* a) ();\n" - "void *(*b) ();\n"; - const std::string actual(sizeof_(code)); - ASSERT_EQUALS("; void * * b ;", actual); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef69() // ticket #2348 - { - const char code[] = "typedef int (*CompilerHook)();\n" - "typedef struct VirtualMachine \n" - "{\n" - " CompilerHook *(*compilerHookVector)(void);\n" - "}VirtualMachine;\n"; - const std::string expected = "; " - "struct VirtualMachine " - "{ " - "int ( * * ( * compilerHookVector ) ( void ) ) ( ) ; " - "} ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef70() // ticket #2348 - { - const char code[] = "typedef int pread_f ( int ) ;\n" - "pread_f *(*test_func)(char *filename);\n"; - const std::string expected = "; " - "int ( * ( * test_func ) ( char * filename ) ) ( int ) ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef71() // ticket #2348 - { - { - const char code[] = "typedef int RexxFunctionHandler();\n" - "RexxFunctionHandler *(efuncs[1]);\n"; - const std::string expected = "; " - "int ( * ( efuncs [ 1 ] ) ) ( ) ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - { - const char code[] = "typedef int RexxFunctionHandler();\n" - "RexxFunctionHandler *(efuncs[]) = { NULL, NULL };\n"; - const std::string expected = "; " - "int ( * ( efuncs [ ] ) ) ( ) = { 0 , 0 } ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - } - - void simplifyTypedef72() // ticket #2374 - { - // inline operator - { - const char code[] = "class Fred {\n" - " typedef int* (Fred::*F);\n" - " operator F() const { }\n" - "};\n"; - const std::string expected = "class Fred { " - "; " - "operatorint** ( ) const { } " - "} ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - // inline local variable - { - const char code[] = "class Fred {\n" - " typedef int INT;\n" - " void f1() const { INT i; }\n" - "};\n"; - const std::string expected = "class Fred { " - "; " - "void f1 ( ) const { int i ; } " - "} ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - // out of line member variable - { - const char code[] = "class Fred {\n" - " typedef int INT;\n" - " void f1() const;\n" - "};\n" - "void Fred::f1() const { INT i; f(i); }\n"; - const std::string expected = "class Fred { " - "; " - "void f1 ( ) const ; " - "} ; " - "void Fred :: f1 ( ) const { int i ; f ( i ) ; }"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - // out of line operator - { - const char code[] = "class Fred {\n" - " typedef int* (Fred::*F);\n" - " operator F() const;\n" - "};\n" - "Fred::operator F() const { }\n"; - const std::string expected = "class Fred { " - "; " - "operatorint** ( ) const ; " - "} ; " - "Fred :: operatorint** ( ) const { }"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - } - - void simplifyTypedef73() // ticket #2412 - { - const char code[] = "struct B {};\n" - "typedef struct A : public B {\n" - " void f();\n" - "} a, *aPtr;\n"; - const std::string expected = "struct B { } ; " - "struct A : public B { " - "void f ( ) ; " - "} ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef74() // ticket #2414 - { - const char code[] = "typedef long (*state_func_t)(void);\n" - "typedef state_func_t (*state_t)(void);\n" - "state_t current_state = death;\n" - "static char get_runlevel(const state_t);\n"; - const std::string expected = "; " - "long ( * ( * current_state ) ( void ) ) ( void ) = death ; " - "static char get_runlevel ( const long ( * ( * ) ( void ) ) ( void ) ) ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef75() // ticket #2426 - { - const char code[] = "typedef _Packed struct S { long l; }; \n"; - const std::string expected = ";"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef76() // ticket #2453 segmentation fault - { - const char code[] = "void f1(typedef int x) {}\n"; - const std::string expected = "void f1 ( typedef int x ) { }"; - ASSERT_EQUALS(expected, sizeof_(code)); - ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); - } - - void simplifyTypedef77() // ticket #2554 - { - const char code[] = "typedef char Str[10]; int x = sizeof(Str);\n"; - const std::string expected = "; int x ; x = 10 ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - } - - void simplifyTypedef78() // ticket #2568 - { - const char code[] = "typedef struct A A_t;\n" - "A_t a;\n" - "typedef struct A { } A_t;\n" - "A_t a1;\n"; - const std::string expected = "; struct A a ; struct A { } ; struct A a1 ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - } - - void simplifyTypedef79() // ticket #2348 - { - const char code[] = "typedef int (Tcl_ObjCmdProc) (int x);\n" - "typedef struct LangVtab\n" - "{\n" - " Tcl_ObjCmdProc * (*V_LangOptionCommand);\n" - "} LangVtab;\n"; - const std::string expected = "; " - "struct LangVtab " - "{ " - "int ( * ( * V_LangOptionCommand ) ) ( int x ) ; " - "} ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - } - - void simplifyTypedef80() // ticket #2587 - { - const char code[] = "typedef struct s { };\n" - "void f() {\n" - " sizeof(struct s);\n" - "};\n"; - const std::string expected = "struct s { } ; " - "void f ( ) { " - "sizeof ( struct s ) ; " - "} ;"; - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef81() // ticket #2603 segmentation fault - { - checkSimplifyTypedef("typedef\n"); - ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); - - checkSimplifyTypedef("typedef constexpr\n"); - ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); - } - - void simplifyTypedef82() // ticket #2403 - { - checkSimplifyTypedef("class A {\n" - "public:\n" - " typedef int F(int idx);\n" - "};\n" - "class B {\n" - "public:\n" - " A::F ** f;\n" - "};\n" - "int main()\n" - "{\n" - " B * b = new B;\n" - " b->f = new A::F * [ 10 ];\n" - "}\n"); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedef83() // ticket #2620 - { - const char code[] = "typedef char Str[10];\n" - "void f(Str &cl) { }\n"; - - // The expected result.. - const std::string expected("; " - "void f ( char ( & cl ) [ 10 ] ) { }"); - - ASSERT_EQUALS(expected, sizeof_(code)); - } - - void simplifyTypedefFunction1() - { - { - const char code[] = "typedef void (*my_func)();\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void (*my_func)(void);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( void ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void (*my_func)(int);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( int ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void (*my_func)(int*);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( int * ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - // ticket # 1615 - const char code[] = "typedef void (*my_func)(arg_class*);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - - { - const char code[] = "typedef void (my_func)();\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void (my_func)(void);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( void ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void (my_func)(int);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( int ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void (my_func)(int*);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( int * ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void (my_func)(arg_class*);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - - { - const char code[] = "typedef void my_func();\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void my_func(void);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( void ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void my_func(int);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( int ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void my_func(int*);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( int * ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void my_func(arg_class*);\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - - { - const char code[] = "typedef void (my_func());\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void (my_func(void));\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( void ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void (my_func(int));\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( int ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void (my_func(int*));\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( int * ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef void (my_func(arg_class*));\n" - "std::queue func_queue;"; - - // The expected result.. - const std::string expected("; " - "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - - // Check for output.. - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - } - - void simplifyTypedefFunction2() // ticket #1685 - { - const char code[] = "typedef void voidfn (int);\n" - "voidfn xxx;"; - - // The expected result.. - const std::string expected("; " - "void xxx ( int ) ;"); - ASSERT_EQUALS(expected, sizeof_(code)); - } - - void simplifyTypedefFunction3() - { - { - const char code[] = "typedef C func1();\n" - "typedef C (* func2)();\n" - "typedef C (& func3)();\n" - "typedef C (C::* func4)();\n" - "typedef C (C::* func5)() const;\n" - "typedef C (C::* func6)() volatile;\n" - "typedef C (C::* func7)() const volatile;\n" - "func1 f1;\n" - "func2 f2;\n" - "func3 f3;\n" - "func4 f4;\n" - "func5 f5;\n" - "func6 f6;\n" - "func7 f7;"; - - // The expected result.. - const std::string expected("; " - "C f1 ( ) ; " - "C * f2 ; " // this gets simplified to a regular pointer - "C ( & f3 ) ( ) ; " - "C ( C :: * f4 ) ( ) ; " - "C ( C :: * f5 ) ( ) const ; " - "C ( C :: * f6 ) ( ) ; " // volatile is removed - "C ( C :: * f7 ) ( ) const ;"); // volatile is removed - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef C const func1();\n" - "typedef C const (* func2)();\n" - "typedef C const (& func3)();\n" - "typedef C const (C::* func4)();\n" - "typedef C const (C::* func5)() const;\n" - "typedef C const (C::* func6)() volatile;\n" - "typedef C const (C::* func7)() const volatile;\n" - "func1 f1;\n" - "func2 f2;\n" - "func3 f3;\n" - "func4 f4;\n" - "func5 f5;\n" - "func6 f6;\n" - "func7 f7;"; - - // The expected result.. - // C const -> const C - const std::string expected("; " - "const C f1 ( ) ; " - "const C * f2 ; " // this gets simplified to a regular pointer - "const C ( & f3 ) ( ) ; " - "const C ( C :: * f4 ) ( ) ; " - "const C ( C :: * f5 ) ( ) const ; " - "const C ( C :: * f6 ) ( ) ; " // volatile is removed - "const C ( C :: * f7 ) ( ) const ;"); // volatile is removed - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef const C func1();\n" - "typedef const C (* func2)();\n" - "typedef const C (& func3)();\n" - "typedef const C (C::* func4)();\n" - "typedef const C (C::* func5)() const;\n" - "typedef const C (C::* func6)() volatile;\n" - "typedef const C (C::* func7)() const volatile;\n" - "func1 f1;\n" - "func2 f2;\n" - "func3 f3;\n" - "func4 f4;\n" - "func5 f5;\n" - "func6 f6;\n" - "func7 f7;"; - - // The expected result.. - const std::string expected("; " - "const C f1 ( ) ; " - "const C * f2 ; " // this gets simplified to a regular pointer - "const C ( & f3 ) ( ) ; " - "const C ( C :: * f4 ) ( ) ; " - "const C ( C :: * f5 ) ( ) const ; " - "const C ( C :: * f6 ) ( ) ; " // volatile is removed - "const C ( C :: * f7 ) ( ) const ;"); // volatile is removed - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef C * func1();\n" - "typedef C * (* func2)();\n" - "typedef C * (& func3)();\n" - "typedef C * (C::* func4)();\n" - "typedef C * (C::* func5)() const;\n" - "typedef C * (C::* func6)() volatile;\n" - "typedef C * (C::* func7)() const volatile;\n" - "func1 f1;\n" - "func2 f2;\n" - "func3 f3;\n" - "func4 f4;\n" - "func5 f5;\n" - "func6 f6;\n" - "func7 f7;"; - - // The expected result.. - const std::string expected("; " - "C * f1 ( ) ; " - "C * * f2 ; " // this gets simplified to a regular pointer - "C * ( & f3 ) ( ) ; " - "C * ( C :: * f4 ) ( ) ; " - "C * ( C :: * f5 ) ( ) const ; " - "C * ( C :: * f6 ) ( ) ; " // volatile is removed - "C * ( C :: * f7 ) ( ) const ;"); // volatile is removed - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef const C * func1();\n" - "typedef const C * (* func2)();\n" - "typedef const C * (& func3)();\n" - "typedef const C * (C::* func4)();\n" - "typedef const C * (C::* func5)() const;\n" - "typedef const C * (C::* func6)() volatile;\n" - "typedef const C * (C::* func7)() const volatile;\n" - "func1 f1;\n" - "func2 f2;\n" - "func3 f3;\n" - "func4 f4;\n" - "func5 f5;\n" - "func6 f6;\n" - "func7 f7;"; - - // The expected result.. - const std::string expected("; " - "const C * f1 ( ) ; " - "const C * * f2 ; " // this gets simplified to a regular pointer - "const C * ( & f3 ) ( ) ; " - "const C * ( C :: * f4 ) ( ) ; " - "const C * ( C :: * f5 ) ( ) const ; " - "const C * ( C :: * f6 ) ( ) ; " // volatile is removed - "const C * ( C :: * f7 ) ( ) const ;"); // volatile is removed - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - { - const char code[] = "typedef C const * func1();\n" - "typedef C const * (* func2)();\n" - "typedef C const * (& func3)();\n" - "typedef C const * (C::* func4)();\n" - "typedef C const * (C::* func5)() const;\n" - "typedef C const * (C::* func6)() volatile;\n" - "typedef C const * (C::* func7)() const volatile;\n" - "func1 f1;\n" - "func2 f2;\n" - "func3 f3;\n" - "func4 f4;\n" - "func5 f5;\n" - "func6 f6;\n" - "func7 f7;"; - - // The expected result.. - // C const -> const C - const std::string expected("; " - "const C * f1 ( ) ; " - "const C * * f2 ; " // this gets simplified to a regular pointer - "const C * ( & f3 ) ( ) ; " - "const C * ( C :: * f4 ) ( ) ; " - "const C * ( C :: * f5 ) ( ) const ; " - "const C * ( C :: * f6 ) ( ) ; " // volatile is removed - "const C * ( C :: * f7 ) ( ) const ;"); // volatile is removed - ASSERT_EQUALS(expected, sizeof_(code)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - } - - void simplifyTypedefFunction4() - { - const char code[] = "typedef int ( * ( * type1 ) ( bool ) ) ( int , int ) ;\n" - "typedef int ( * ( type2 ) ( bool ) ) ( int , int ) ;\n" - "typedef int ( * type3 ( bool ) ) ( int , int ) ;\n" - "type1 t1;\n" - "type2 t2;\n" - "type3 t3;"; - - // The expected result.. - const std::string expected("; " - "int ( * ( * t1 ) ( bool ) ) ( int , int ) ; " - "int ( * t2 ( bool ) ) ( int , int ) ; " - "int ( * t3 ( bool ) ) ( int , int ) ;"); - ASSERT_EQUALS(expected, tok(code, false)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedefFunction5() - { - const char code[] = "typedef int ( * type1 ) ( float ) ;\n" - "typedef int ( * const type2 ) ( float ) ;\n" - "typedef int ( * volatile type3 ) ( float ) ;\n" - "typedef int ( * const volatile type4 ) ( float ) ;\n" - "typedef int ( C :: * type5 ) ( float ) ;\n" - "typedef int ( C :: * const type6 ) ( float ) ;\n" - "typedef int ( C :: * volatile type7 ) ( float ) ;\n" - "typedef int ( C :: * const volatile type8 ) ( float ) ;\n" - "typedef int ( :: C :: * type9 ) ( float ) ;\n" - "typedef int ( :: C :: * const type10 ) ( float ) ;\n" - "typedef int ( :: C :: * volatile type11 ) ( float ) ;\n" - "typedef int ( :: C :: * const volatile type12 ) ( float ) ;\n" - "type1 t1;\n" - "type2 t2;\n" - "type3 t3;\n" - "type4 t4;\n" - "type5 t5;\n" - "type6 t6;\n" - "type7 t7;\n" - "type8 t8;\n" - "type9 t9;\n" - "type10 t10;\n" - "type11 t11;\n" - "type12 t12;"; - - // The expected result.. - const std::string expected("; " - "int * t1 ; " // simplified to regular pointer - "int ( * const t2 ) ( float ) ; " - "int * t3 ; " // volatile removed, gets simplified to regular pointer - "int ( * const t4 ) ( float ) ; " // volatile removed - "int ( C :: * t5 ) ( float ) ; " - "int ( C :: * const t6 ) ( float ) ; " - "int ( C :: * t7 ) ( float ) ; " // volatile removed - "int ( C :: * const t8 ) ( float ) ; " // volatile removed - "int ( :: C :: * t9 ) ( float ) ; " - "int ( :: C :: * const t10 ) ( float ) ; " - "int ( :: C :: * t11 ) ( float ) ; " // volatile removed - "int ( :: C :: * const t12 ) ( float ) ;"); // volatile removed - ASSERT_EQUALS(expected, tok(code, false)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedefFunction6() - { - const char code[] = "typedef void (*testfp)();\n" - "struct Fred\n" - "{\n" - " testfp get1() { return 0; }\n" - " void ( * get2 ( ) ) ( ) { return 0 ; }\n" - " testfp get3();\n" - " void ( * get4 ( ) ) ( );\n" - "};\n" - "testfp Fred::get3() { return 0; }\n" - "void ( * Fred::get4 ( ) ) ( ) { return 0 ; }\n"; - - // The expected result.. - const std::string expected("; " - "struct Fred " - "{ " - "void ( * get1 ( ) ) ( ) { return 0 ; } " - "void ( * get2 ( ) ) ( ) { return 0 ; } " - "void ( * get3 ( ) ) ( ) ; " - "void ( * get4 ( ) ) ( ) ; " - "} ; " - "void ( * Fred :: get3 ( ) ) ( ) { return 0 ; } " - "void ( * Fred :: get4 ( ) ) ( ) { return 0 ; }"); - - ASSERT_EQUALS(expected, tok(code, false)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedefFunction7() - { - const char code[] = "typedef void ( __gnu_cxx :: _SGIAssignableConcept < _Tp > :: * _func_Tp_SGIAssignableConcept ) () ;" - "_func_Tp_SGIAssignableConcept X;\n"; - - // The expected result.. - const std::string expected("; " - "void ( __gnu_cxx :: _SGIAssignableConcept < _Tp > :: * X ) ( ) ;"); - - ASSERT_EQUALS(expected, tok(code, false)); - - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyTypedefFunction8() - { - // #2376 - internal error - const char code[] = "typedef int f_expand(const nrv_byte *);\n" - "void f(f_expand *(*get_fexp(int))){}\n"; - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); // make sure that there is no internal error - } - - void reverseArraySyntax() - { - ASSERT_EQUALS("a [ 13 ]", tok("13[a]")); - } - - void simplify_numeric_condition() - { - { - const char code[] = - "void f()\n" - "{\n" - "int x = 0;\n" - "if( !x || 0 )\n" - "{ g();\n" - "}\n" - "}"; - - ASSERT_EQUALS("void f ( ) { ; { g ( ) ; } }", tok(code)); - } - - { - const char code[] = - "void f()\n" - "{\n" - "int x = 1;\n" - "if( !x )\n" - "{ g();\n" - "}\n" - "}"; - - ASSERT_EQUALS("void f ( ) { ; }", tok(code)); - } - - { - const char code[] = - "void f()\n" - "{\n" - "bool x = true;\n" - "if( !x )\n" - "{ g();\n" - "}\n" - "}"; - - ASSERT_EQUALS("void f ( ) { ; }", tok(code)); - } - - { - const char code[] = - "void f()\n" - "{\n" - "bool x = false;\n" - "if( !x )\n" - "{ g();\n" - "}\n" - "}"; - - ASSERT_EQUALS("void f ( ) { ; { g ( ) ; } }", tok(code)); - } - - { - const char code[] = "void f()\n" - "{\n" - " if (5==5);\n" - "}\n"; - - ASSERT_EQUALS("void f ( ) { { ; } }", tok(code)); - } - - { - const char code[] = "void f()\n" - "{\n" - " if (4<5);\n" - "}\n"; - - ASSERT_EQUALS("void f ( ) { { ; } }", tok(code)); - } - - { - const char code[] = "void f()\n" - "{\n" - " if (5<5);\n" - "}\n"; - - ASSERT_EQUALS("void f ( ) { }", tok(code)); - } - - { - const char code[] = "void f()\n" - "{\n" - " if (13>12?true:false);\n" - "}\n"; - - ASSERT_EQUALS("void f ( ) { { ; } }", tok(code)); - } - } - - void simplify_condition() - { - { - const char code[] = - "void f(int a)\n" - "{\n" - "if (a && false) g();\n" - "}"; - ASSERT_EQUALS("void f ( int a ) { }", tok(code)); - } - - { - const char code[] = - "void f(int a)\n" - "{\n" - "if (false && a) g();\n" - "}"; - ASSERT_EQUALS("void f ( int a ) { }", tok(code)); - } - - { - const char code[] = - "void f(int a)\n" - "{\n" - "if (true || a) g();\n" - "}"; - ASSERT_EQUALS("void f ( int a ) { { g ( ) ; } }", tok(code)); - } - - { - const char code[] = - "void f(int a)\n" - "{\n" - "if (a || true) g();\n" - "}"; - ASSERT_EQUALS("void f ( int a ) { { g ( ) ; } }", tok(code)); - } - } - - - void pointeralias1() - { - { - const char code[] = "void f()\n" - "{\n" - " char buf[100];\n" - " char *p = buf;\n" - " free(p);\n" - "}\n"; - - const char expected[] = "void f ( ) " - "{ " - "char buf [ 100 ] ; " - "free ( buf ) ; " - "}"; - - ASSERT_EQUALS(expected, tok(code)); - } - - { - const char code[] = "void f(char *p1)\n" - "{\n" - " char *p = p1;\n" - " p1 = 0;" - " x(p);\n" - "}\n"; - - const char expected[] = "void f ( char * p1 ) " - "{ " - "char * p ; p = p1 ; " - "p1 = 0 ; " - "x ( p ) ; " - "}"; - - ASSERT_EQUALS(expected, tok(code)); - } - - { - const char code[] = "void foo(Result* ptr)\n" - "{\n" - " Result* obj = ptr;\n" - " ++obj->total;\n" - "}\n"; - - const char expected[] = "void foo ( Result * ptr ) " - "{ " - "Result * obj ; obj = ptr ; " - "++ obj . total ; " - "}"; - - ASSERT_EQUALS(expected, tok(code)); - } - - { - const char code[] = "int *foo()\n" - "{\n" - " int a[10];\n" - " int *b = a;\n" - " return b;\n" - "}\n"; - - const char expected[] = "int * foo ( ) " - "{ " - "int a [ 10 ] ; " - "return a ; " - "}"; - - ASSERT_EQUALS(expected, tok(code)); - } - - { - const char code[] = "void f() {\n" - " int a[10];\n" - " int *b = a;\n" - " memset(b,0,sizeof(a));\n" - "}"; - - const char expected[] = "void f ( ) {" - " int a [ 10 ] ;" - " memset ( a , 0 , 40 ) ; " - "}"; - - ASSERT_EQUALS(expected, tok(code)); - } - } - - void pointeralias2() - { - const char code[] = "void f()\n" - "{\n" - " int i;\n" - " int *p = &i;\n" - " return *p;\n" - "}\n"; - ASSERT_EQUALS("void f ( ) { int i ; return i ; }", tok(code)); - } - - void pointeralias3() - { - const char code[] = "void f()\n" - "{\n" - " int i, j, *p;\n" - " if (ab) p = &i;\n" - " else p = &j;\n" - " *p = 0;\n" - "}\n"; - const char expected[] = "void f ( ) " - "{" - " int i ; int j ; int * p ;" - " if ( ab ) { p = & i ; }" - " else { p = & j ; }" - " * p = 0 ; " - "}"; - ASSERT_EQUALS(expected, tok(code)); - } - - void pointeralias4() - { - const char code[] = "void f()\n" - "{\n" - " int a[10];\n" - " int *p = &a[0];\n" - " *p = 0;\n" - "}\n"; - const char expected[] = "void f ( ) " - "{" - " int a [ 10 ] ;" - " int * p ; p = & a [ 0 ] ;" - " * a = 0 ; " - "}"; - ASSERT_EQUALS(expected, tok(code)); - } - - void pointeralias5() - { - const char code[] = "int f()\n" - "{\n" - " int i;\n" - " int *p = &i;\n" - " *p = 5;\n" - " return i;\n" - "}\n"; - const char expected[] = "int f ( ) " - "{" - " ; return 5 ; " - "}"; - ASSERT_EQUALS(expected, tok(code)); - } - - void reduceConstness() - { - ASSERT_EQUALS("char * p ;", tok("char * const p;")); - } - - void while0() - { - ASSERT_EQUALS("; x = 1 ;", tok("; do { x = 1 ; } while (0);")); - ASSERT_EQUALS("; do { continue ; } while ( false ) ;", tok("; do { continue ; } while (0);")); - ASSERT_EQUALS("; do { break ; } while ( false ) ;", tok("; do { break; } while (0);")); - ASSERT_EQUALS(";", tok("; while (false) { a; }")); - - // for (condition is always false) - ASSERT_EQUALS("void f ( ) { ; }", tok("void f() { int i; for (i = 0; i < 0; i++) { a; } }")); - } - - void while1() - { - // ticket #1197 - const char code[] = "void do {} while (0) { }"; - const char expected[] = "void { }"; - ASSERT_EQUALS(expected, tok(code)); - } - - void enum1() - { - const char code[] = "enum A { a, b, c }; A c1 = c;"; - const char expected[] = "; int c1 ; c1 = 2 ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void enum2() - { - const char code[] = "enum A { a, }; int array[a];"; - const char expected[] = "; int array [ 0 ] ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void enum3() - { - const char code[] = "enum { a, }; int array[a];"; - const char expected[] = "; int array [ 0 ] ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - void enum4() - { - { - const char code[] = "class A {\n" - "public:\n" - " enum EA { a1, a2, a3 };\n" - " EA get() const;\n" - " void put(EA a) { ea = a; ea = a1; }\n" - "private:\n" - " EA ea;\n" - "};\n" - "A::EA A::get() const { return ea; }\n" - "A::EA e = A::a1;"; - - const char expected[] = "class A { " - "public: " - "; " - "int get ( ) const ; " - "void put ( int a ) { ea = a ; ea = 0 ; } " - "private: " - "int ea ; " - "} ; " - "int A :: get ( ) const { return ea ; } " - "int e ; e = 0 ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct A {\n" - " enum EA { a1, a2, a3 };\n" - " EA get() const;\n" - " void put(EA a) { ea = a; ea = a1; }\n" - " EA ea;\n" - "};\n" - "A::EA A::get() const { return ea; }\n" - "A::EA e = A::a1;"; - - const char expected[] = "struct A { " - "; " - "int get ( ) const ; " - "void put ( int a ) { ea = a ; ea = 0 ; } " - "int ea ; " - "} ; " - "int A :: get ( ) const { return ea ; } " - "int e ; e = 0 ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - } - } - - void enum5() - { - const char code[] = "enum ABC {\n" - " a = sizeof(int),\n" - " b = 1 + a,\n" - " c = b + 100,\n" - " d,\n" - " e,\n" - " f = 90,\n" - " g\n" - "};\n" - "int sum = a + b + c + d + e + f + g;"; - const char expected[] = "; " - "int sum ; sum = " - "sizeof ( int ) + " - "1 + sizeof ( int ) + " - "1 + sizeof ( int ) + 100 + " - "1 + sizeof ( int ) + 100 + 1 + " - "1 + sizeof ( int ) + 100 + 2 + " - "90 + " - "91 ;"; - - ASSERT_EQUALS(expected, tok(code, false)); - ASSERT_EQUALS("; int sum ; sum = 508 ;", tok(code, true)); - } - - void enum6() - { - const char code[] = "enum { a = MAC(A, B, C) }; void f(a) { }"; - const char expected[] = "; void f ( MAC ( A , B , C ) ) { }"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - void enum7() - { - { - // ticket 1388 - const char code[] = "enum FOO {A,B,C};\n" - "int main()\n" - "{\n" - " int A = B;\n" - " { float A = C; }\n" - "}"; - const char expected[] = "; " - "int main ( ) " - "{ " - "int A ; A = 1 ; " - "{ float A ; A = 2 ; } " - "}"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "enum FOO {A,B,C};\n" - "void f(int A, float B, char C) { }"; - const char expected[] = "; " - "void f ( int A , float B , char C ) { }"; - ASSERT_EQUALS(expected, tok(code, false)); - } - } - - // Check simplifyEnum - void checkSimplifyEnum(const char code[]) - { - errout.str(""); - // Tokenize.. - Settings settings; - settings.inconclusive = true; - settings._checkCodingStyle = true; - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); - tokenizer.simplifyTokenList(); - } - - void enum8() - { - // ticket 1388 - checkSimplifyEnum("enum Direction {N=100,E,S,W,ALL};\n" - "template class EF_Vector{\n" - " T v_v[S];\n" - "\n" - "public:\n" - " EF_Vector();\n" - " explicit EF_Vector(const T &);\n" - " explicit EF_Vector(const T arr[S]);\n" - "};\n" - "\n" - "template\n" - "EF_Vector::EF_Vector()\n" - "{\n" - "}\n" - "\n" - "template\n" - "EF_Vector::EF_Vector(const T &t)\n" - "{\n" - " for(int i=0;i\n" - "EF_Vector::EF_Vector(const T arr[S])\n" - "{\n" - " for(int i=0;i d;\n" - "}"); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n" - "[test.cpp:11] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n" - "[test.cpp:16] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n" - "[test.cpp:23] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n", errout.str()); - } - - void enum9() - { - // ticket 1404 - checkSimplifyEnum("class XX {\n" - "public:\n" - "static void Set(const int &p){m_p=p;}\n" - "static int m_p;\n" - "};\n" - "int XX::m_p=0;\n" - "int main() {\n" - " enum { XX };\n" - " XX::Set(std::numeric_limits::digits());\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void enum10() - { - // ticket 1445 - const char code[] = "enum {\n" - "SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1, \n" - "} e = SHELL_SIZE;"; - const char expected[] = "; int e ; e = sizeof ( union { int i ; char * cp ; double d ; } ) - 1 ;"; - ASSERT_EQUALS(expected, tok(code, false)); - - checkSimplifyEnum(code); - ASSERT_EQUALS("", errout.str()); - } - - void enum11() - { - const char code[] = "int main()\n" - "{\n" - " enum { u, v };\n" - " A u = 1, v = 2;\n" - "}"; - const char expected[] = "int main ( ) " - "{ " - "; " - "A u ; u = 1 ; A v ; v = 2 ; " - "}"; - ASSERT_EQUALS(expected, tok(code, false)); - - checkSimplifyEnum(code); - ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (style) Variable 'u' hides enumerator with same name\n" - "[test.cpp:4] -> [test.cpp:3]: (style) Variable 'v' hides enumerator with same name\n", errout.str()); - } - - void enum12() - { - const char code[] = "enum fred { a, b };\n" - "void foo()\n" - "{\n" - " unsigned int fred = 0;\n" - "}"; - const char expected[] = "; void foo ( ) { unsigned int fred ; fred = 0 ; }"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - void enum13() - { - const char code[] = "enum ab { ENTRY(1, a = 0), ENTRY(2, b) };\n" - "void foo()\n" - "{\n" - " unsigned int fred = a;\n" - "}"; - const char expected[] = "; void foo ( ) { unsigned int fred ; fred = a ; }"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - void enum14() - { - const char code[] = "enum ab { a };\n" - "ab"; - const char expected[] = "; ab"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - void enum15() // C++0x features - { - { - const char code[] = "enum : char { a = 99 };\n" - "char c1 = a;"; - const char expected[] = "; char c1 ; c1 = 99 ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "enum class Enum1 { a };\n" - "Enum1 e1 = a;"; - const char expected[] = "; int e1 ; e1 = 0 ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "enum Enum1 : char { a };\n" - "Enum1 e1 = a;"; - const char expected[] = "; char e1 ; e1 = 0 ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "enum class Enum1 : unsigned char { a };\n" - "Enum1 e1 = a;"; - const char expected[] = "; unsigned char e1 ; e1 = 0 ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "enum class Enum1 : unsigned int { a };\n" - "Enum1 e1 = a;"; - const char expected[] = "; unsigned int e1 ; e1 = 0 ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "enum class Enum1 : unsigned long long int { a };\n" - "Enum1 e1 = a;"; - const char expected[] = "; unsigned long long e1 ; e1 = 0 ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - } - - void enum16() // ticket #1988 - { - const char code[] = "enum D : auto * { FF = 0 };"; - checkSimplifyEnum(code); - ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); - } - - void enum17() // ticket #2381 - { - // if header is included twice its enums will be duplicated - const char code[] = "enum ab { a=0, b };" - "enum ab { a=0, b };\n"; - ASSERT_EQUALS(";", tok(code, false)); - ASSERT_EQUALS("", errout.str()); - } - - void enum18() // ticket #2466 - array with same name as enum constant - { - const char code[] = "enum ab { a=0, b };\n" - "void f() { a[0]; }\n"; - ASSERT_EQUALS("; void f ( ) { a [ 0 ] ; }", tok(code, false)); - } - - void enum19() // ticket #2536 - { - const char code[] = "enum class E1;\n" - "enum class E2 : int;\n"; - ASSERT_EQUALS(";", tok(code, false)); - } - - void enum20() // ticket #2600 segmentation fault - { - const char code[] = "enum { const }\n"; - ASSERT_EQUALS(";", tok(code, false)); - } - - void removestd() - { - ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);")); - ASSERT_EQUALS("; strcat ( a , b ) ;", tok("; std::strcat(a,b);")); - ASSERT_EQUALS("; strncpy ( a , b , 10 ) ;", tok("; std::strncpy(a,b,10);")); - ASSERT_EQUALS("; strncat ( a , b , 10 ) ;", tok("; std::strncat(a,b,10);")); - ASSERT_EQUALS("; free ( p ) ;", tok("; std::free(p);")); - ASSERT_EQUALS("; malloc ( 10 ) ;", tok("; std::malloc(10);")); - } - - void simplifyInitVar() - { - // ticket #1005 - int *p(0); => int *p = 0; - { - const char code[] = "void foo() { int *p(0); }"; - ASSERT_EQUALS("void foo ( ) { ; }", tok(code)); - } - - { - const char code[] = "void foo() { int p(0); }"; - ASSERT_EQUALS("void foo ( ) { ; }", tok(code)); - } - - { - const char code[] = "void a() { foo *p(0); }"; - ASSERT_EQUALS("void a ( ) { ; }", tok(code)); - } - } - - void simplifyReference() - { - ASSERT_EQUALS("void f ( ) { int a ; a ++ ; }", - tok("void f() { int a; int &b(a); b++; }")); - ASSERT_EQUALS("void f ( ) { int a ; a ++ ; }", - tok("void f() { int a; int &b = a; b++; }")); - } - - void simplifyRealloc() - { - ASSERT_EQUALS("; free ( p ) ; p = 0 ;", - tok("; p = realloc(p,0);")); - ASSERT_EQUALS("; p = malloc ( 100 ) ;", - tok("; p = realloc(0, 100);")); - ASSERT_EQUALS("; p = malloc ( 0 ) ;", - tok("; p = realloc(0, sizeof(char)*0);")); - } - - void simplifyErrNoInWhile() - { - ASSERT_EQUALS("; while ( f ( ) ) { }", - tok("; while (f() && errno == EINTR) { }")); - ASSERT_EQUALS("; while ( f ( ) ) { }", - tok("; while (f() && (errno == EINTR)) { }")); - } - - void simplifyFuncInWhile() - { - ASSERT_EQUALS("int cppcheck:r = fclose ( f ) ; " - "while ( cppcheck:r ) " - "{ " - "foo ( ) ; " - "cppcheck:r = fclose ( f ) ; " - "}", - tok("while(fclose(f))foo();")); - - ASSERT_EQUALS("int cppcheck:r = fclose ( f ) ; " - "while ( cppcheck:r ) " - "{ " - "; cppcheck:r = fclose ( f ) ; " - "}", - tok("while(fclose(f));")); - - ASSERT_EQUALS("int cppcheck:r = fclose ( f ) ; " - "while ( cppcheck:r ) " - "{ " - "; cppcheck:r = fclose ( f ) ; " - "} " - "int cppcheck:r = fclose ( g ) ; " - "while ( cppcheck:r ) " - "{ " - "; cppcheck:r = fclose ( g ) ; " - "}", - tok("while(fclose(f)); while(fclose(g));")); - } - - void initstruct() - { - ASSERT_EQUALS("; struct A a ; a . buf = 3 ;", tok("; struct A a = { .buf = 3 };")); - ASSERT_EQUALS("; struct A a ; a . buf = x ;", tok("; struct A a = { .buf = x };")); - ASSERT_EQUALS("; struct A a ; a . buf = & key ;", tok("; struct A a = { .buf = &key };")); - ASSERT_EQUALS("; struct ABC abc ; abc . a = 3 ; abc . b = x ; abc . c = & key ;", tok("; struct ABC abc = { .a = 3, .b = x, .c = &key };")); - TODO_ASSERT_EQUALS("; struct A a ; a . buf = { 0 } ;", - "; struct A a ; a = { . buf = { 0 } } ;", - tok("; struct A a = { .buf = {0} };")); - } - - void simplifyStructDecl1() - { - { - const char code[] = "struct ABC { } abc;"; - const char expected[] = "struct ABC { } ; ABC abc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct ABC { } * pabc;"; - const char expected[] = "struct ABC { } ; ABC * pabc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct ABC { } abc[4];"; - const char expected[] = "struct ABC { } ; ABC abc [ 4 ] ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct ABC { } abc, def;"; - const char expected[] = "struct ABC { } ; ABC abc ; ABC def ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct ABC { } abc, * pabc;"; - const char expected[] = "struct ABC { } ; ABC abc ; ABC * pabc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct ABC { struct DEF {} def; } abc;"; - const char expected[] = "struct ABC { struct DEF { } ; DEF def ; } ; ABC abc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct { } abc;"; - const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct { } * pabc;"; - const char expected[] = "struct Anonymous0 { } ; Anonymous0 * pabc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct { } abc[4];"; - const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc [ 4 ] ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct { } abc, def;"; - const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc ; Anonymous0 def ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct { } abc, * pabc;"; - const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc ; Anonymous0 * pabc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct { struct DEF {} def; } abc;"; - const char expected[] = "struct Anonymous0 { struct DEF { } ; DEF def ; } ; Anonymous0 abc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct ABC { struct {} def; } abc;"; - const char expected[] = "struct ABC { struct Anonymous0 { } ; Anonymous0 def ; } ; ABC abc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct { struct {} def; } abc;"; - const char expected[] = "struct Anonymous0 { struct Anonymous1 { } ; Anonymous1 def ; } ; Anonymous0 abc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "union ABC { int i; float f; } abc;"; - const char expected[] = "union ABC { int i ; float f ; } ; ABC abc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct ABC { struct {} def; };"; - const char expected[] = "struct ABC { struct Anonymous0 { } ; Anonymous0 def ; } ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct ABC : public XYZ { struct {} def; };"; - const char expected[] = "struct ABC : public XYZ { struct Anonymous0 { } ; Anonymous0 def ; } ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct { int x; }; int y;"; - const char expected[] = "int x ; int y ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct { int x; };"; - const char expected[] = "int x ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct { };"; - const char expected[] = ";"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - { - const char code[] = "struct { struct { struct { } ; } ; };"; - const char expected[] = ";"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - // ticket 2464 - { - const char code[] = "static struct ABC { } abc ;"; - const char expected[] = "struct ABC { } ; static ABC abc ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - // ticket #980 - { - const char code[] = "void f() { int A(1),B(2),C=3,D,E(5),F=6; }"; - const char expected[] = "void f ( ) { int A ; A = 1 ; int B ; B = 2 ; int C ; C = 3 ; int D ; int E ; E = 5 ; int F ; F = 6 ; }"; - ASSERT_EQUALS(expected, tok(code, false)); - } - } - - void simplifyStructDecl2() // ticket #2479 (segmentation fault) - { - const char code[] = "struct { char c; }"; - const char expected[] = "struct { char c ; }"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - void removeUnwantedKeywords() - { - ASSERT_EQUALS("int var ;", tok("register int var ;", true)); - ASSERT_EQUALS("short var ;", tok("register short int var ;", true)); - ASSERT_EQUALS("int foo ( ) { }", tok("inline int foo ( ) { }", true)); - ASSERT_EQUALS("int foo ( ) { }", tok("__inline int foo ( ) { }", true)); - ASSERT_EQUALS("int foo ( ) { }", tok("__forceinline int foo ( ) { }", true)); - ASSERT_EQUALS("if ( a ) { }", tok("if ( likely ( a ) ) { }", true)); - ASSERT_EQUALS("if ( a ) { }", tok("if ( unlikely ( a ) ) { }", true)); - ASSERT_EQUALS("int * p ;", tok("int * __restrict p;", true)); - ASSERT_EQUALS("int * * p ;", tok("int * __restrict__ * p;", true)); - ASSERT_EQUALS("void foo ( float * a , float * b ) ;", tok("void foo(float * __restrict__ a, float * __restrict__ b);", true)); - ASSERT_EQUALS("int * p ;", tok("int * restrict p;", true)); - ASSERT_EQUALS("int * * p ;", tok("int * restrict * p;", true)); - ASSERT_EQUALS("void foo ( float * a , float * b ) ;", tok("void foo(float * restrict a, float * restrict b);", true)); - ASSERT_EQUALS("; int * p ;", tok("typedef int * __restrict__ rint; rint p;", true)); - } - - void simplifyCallingConvention() - { - ASSERT_EQUALS("int f ( ) ;", tok("int __cdecl f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __stdcall f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __fastcall f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __clrcall f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __thiscall f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __syscall f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __pascal f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __fortran f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __far __cdecl f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __far __stdcall f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __far __fastcall f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __far __clrcall f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __far __thiscall f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __far __syscall f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __far __pascal f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int __far __fortran f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int WINAPI f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int APIENTRY f();", true)); - ASSERT_EQUALS("int f ( ) ;", tok("int CALLBACK f();", true)); - } - - void simplifyFunctorCall() - { - ASSERT_EQUALS("IncrementFunctor ( ) ( a ) ;", tok("IncrementFunctor()(a);", true)); - } - - void redundant_semicolon() - { - ASSERT_EQUALS("void f ( ) { ; }", tok("void f() { ; }", false)); - ASSERT_EQUALS("void f ( ) { ; }", tok("void f() { do { ; } while (0); }", true)); - } - - void simplifyFunctionReturn() - { - const char code[] = "typedef void (*testfp)();\n" - "struct Fred\n" - "{\n" - " testfp get1() { return 0; }\n" - " void ( * get2 ( ) ) ( ) { return 0 ; }\n" - " testfp get3();\n" - " void ( * get4 ( ) ) ( );\n" - "};"; - const char expected[] = "; " - "struct Fred " - "{ " - "void ( * get1 ( ) ) ( ) { return 0 ; } " - "void ( * get2 ( ) ) ( ) { return 0 ; } " - "void ( * get3 ( ) ) ( ) ; " - "void ( * get4 ( ) ) ( ) ; " - "} ;"; - ASSERT_EQUALS(expected, tok(code, false)); - } - - void removeUnnecessaryQualification1() - { - const char code[] = "class Fred { Fred::Fred() {} };"; - const char expected[] = "class Fred { Fred ( ) { } } ;"; - ASSERT_EQUALS(expected, tok(code, false)); - ASSERT_EQUALS("[test.cpp:1]: (portability) Extra qualification 'Fred::' unnecessary and considered an error by many compilers.\n", errout.str()); - } - - void removeUnnecessaryQualification2() - { - const char code[] = "template\n" - "struct grammar : qi::grammar {\n" - " grammar() : grammar::base_type(start) { }\n" - "};\n"; - tok(code, false); - ASSERT_EQUALS("", errout.str()); - } - - void simplifyIfNotNull() // ticket # 2601 segmentation fault - { - const char code[] = "|| #if #define <="; - tok(code, false); - ASSERT_EQUALS("", errout.str()); - } -}; - -REGISTER_TEST(TestSimplifyTokens) + \ No newline at end of file From 7daa6b93704a1b267f204fad456fab1463878664 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Mon, 7 Mar 2011 07:50:48 +1300 Subject: [PATCH 27/54] Always pass unsigned char to ::isspace to prevent runtime error in MSVC --- lib/preprocessor.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index fd072e33f..7650039e9 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -307,7 +307,13 @@ static bool isFallThroughComment(std::string comment) { // convert comment to lower case without whitespace std::transform(comment.begin(), comment.end(), comment.begin(), ::tolower); - comment.erase(std::remove_if(comment.begin(), comment.end(), ::isspace), comment.end()); + for (std::string::iterator i = comment.begin(); i != comment.end(); ) + { + if (::isspace(static_cast(*i))) + comment.erase(i); + else + ++i; + } return comment.find("fallthr") != std::string::npos || comment.find("fallsthr") != std::string::npos || From 6648267ab80c257ddcbb695eb79ebe45ac24f324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 6 Mar 2011 21:07:06 +0100 Subject: [PATCH 28/54] Revert "Tokenizer::simplifyTemplates: better handling of '(foo())'. Ticket: #2631" This reverts commit de31ec1e4441eab3c065d3208f0be01bbf2c2bcf. --- lib/tokenize.cpp | 6432 ++++++++++++++++++++++++++++++++++- test/testsimplifytokens.cpp | 3789 ++++++++++++++++++++- 2 files changed, 10200 insertions(+), 21 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 3e529bb97..82e0d05a5 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2714,7 +2714,7 @@ std::list Tokenizer::simplifyTemplatesGetTemplateInstantiations() if (!tok) break; } - else if (Token::Match(tok->previous(), "[({};=] %type% <") || + else if (Token::Match(tok->previous(), "[{};=] %var% <") || Token::Match(tok->tokAt(-2), "[,:] private|protected|public %var% <")) { if (templateParameters(tok->next())) @@ -3087,4 +3087,6432 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, } // link() newly tokens manually - \ No newline at end of file + if (tok3->str() == "{") + { + braces.push(_tokensBack); + } + else if (tok3->str() == "}") + { + assert(braces.empty() == false); + Token::createMutualLinks(braces.top(), _tokensBack); + braces.pop(); + } + else if (tok3->str() == "(") + { + brackets.push(_tokensBack); + } + else if (tok3->str() == "[") + { + brackets2.push(_tokensBack); + } + else if (tok3->str() == ")") + { + assert(brackets.empty() == false); + Token::createMutualLinks(brackets.top(), _tokensBack); + brackets.pop(); + } + else if (tok3->str() == "]") + { + assert(brackets2.empty() == false); + Token::createMutualLinks(brackets2.top(), _tokensBack); + brackets2.pop(); + } + + } + + assert(braces.empty()); + assert(brackets.empty()); + } + } + + // Replace all these template usages.. + for (Token *tok4 = tok2; tok4; tok4 = tok4->next()) + { + if (Token::simpleMatch(tok4, s1.c_str())) + { + bool match = true; + Token * tok5 = tok4->tokAt(2); + unsigned int count = 0; + const Token *typetok = (!types2.empty()) ? types2[0] : 0; + while (tok5->str() != ">") + { + if (tok5->str() != ",") + { + if (!typetok || + tok5->isUnsigned() != typetok->isUnsigned() || + tok5->isSigned() != typetok->isSigned() || + tok5->isLong() != typetok->isLong()) + { + match = false; + break; + } + + typetok = typetok ? typetok->next() : 0; + } + else + { + ++count; + typetok = (count < types2.size()) ? types2[count] : 0; + } + tok5 = tok5->next(); + } + + if (match) + { + tok4->str(name2); + while (tok4->next()->str() != ">") + { + used.remove(tok4->next()); + tok4->deleteNext(); + } + used.remove(tok4->next()); + tok4->deleteNext(); + } + } + } + } +} + +void Tokenizer::simplifyTemplates() +{ + std::set expandedtemplates(simplifyTemplatesExpandSpecialized()); + + // Locate templates.. + std::list templates(simplifyTemplatesGetTemplateDeclarations()); + + if (templates.empty()) + { + removeTemplates(_tokens); + return; + } + + // There are templates.. + // Remove "typename" unless used in template arguments.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "typename") + tok->deleteThis(); + + if (Token::simpleMatch(tok, "template <")) + { + while (tok && tok->str() != ">") + tok = tok->next(); + if (!tok) + break; + } + } + + // Locate possible instantiations of templates.. + std::list used(simplifyTemplatesGetTemplateInstantiations()); + + // No template instantiations? Then remove all templates. + if (used.empty()) + { + removeTemplates(_tokens); + return; + } + + // Template arguments with default values + simplifyTemplatesUseDefaultArgumentValues(templates, used); + + // expand templates + bool done = false; + //while (!done) + { + done = true; + for (std::list::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) + { + simplifyTemplatesInstantiate(*iter1, used, expandedtemplates); + } + } + + removeTemplates(_tokens); +} +//--------------------------------------------------------------------------- + +void Tokenizer::simplifyTemplates2() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(") + tok = tok->link(); + + else if (Token::Match(tok, "; %type% <")) + { + const Token *tok2 = tok->tokAt(3); + std::string type; + while (Token::Match(tok2, "%type% ,") || Token::Match(tok2, "%num% ,")) + { + type += tok2->str() + ","; + tok2 = tok2->tokAt(2); + } + if (Token::Match(tok2, "%type% > (") || Token::Match(tok2, "%num% > (")) + { + type += tok2->str(); + tok = tok->next(); + tok->str(tok->str() + "<" + type + ">"); + Token::eraseTokens(tok, tok2->tokAt(2)); + } + } + } +} +//--------------------------------------------------------------------------- + +std::string Tokenizer::getNameForFunctionParams(const Token *start) +{ + if (start->next() == start->link()) + return ""; + + std::string result; + bool findNextComma = false; + for (const Token *tok = start->next(); tok && tok != start->link(); tok = tok->next()) + { + if (findNextComma) + { + if (tok->str() == ",") + findNextComma = false; + + continue; + } + + result.append(tok->str() + ","); + findNextComma = true; + } + + return result; +} + +void Tokenizer::setVarId() +{ + // Clear all variable ids + for (Token *tok = _tokens; tok; tok = tok->next()) + tok->varId(0); + + // Set variable ids.. + _varId = 0; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok != _tokens && !Token::Match(tok, "[;{}(,] %type%")) + continue; + + if (_errorLogger) + _errorLogger->reportProgress(_files[0], "Tokenize (set variable id)", tok->progressValue()); + + // If pattern is "( %type% *|& %var% )" then check if it's a + // variable declaration or a multiplication / mask + if (Token::Match(tok, "( %type% *|& %var% [),]") && !tok->next()->isStandardType()) + { + if (!Token::Match(tok->previous(), "%type%")) + continue; + if (tok->strAt(-1) == "return") + continue; + if (!Token::Match(tok->tokAt(5), "const|{")) + continue; + } + + if (Token::Match(tok, "[,;{}(] %type%")) + { + // not function declaration? + // TODO: Better checking + if (Token::Match(tok->tokAt(-2), "= %var% (")) + { + continue; + } + if (tok->str() == "(" && + tok->previous() && + !tok->previous()->isName() && + tok->strAt(-2) != "operator") + continue; + tok = tok->next(); + } + + if (tok->str() == "new") + continue; + + if (tok->str() == "throw") + continue; + + if (tok->str() == "unsigned") + tok = tok->next(); + + if (Token::Match(tok, "class|struct %type% :|{|;")) + continue; + + if (Token::Match(tok, "using namespace %type% ;")) + { + tok = tok->next(); + continue; + } + + if (Token::Match(tok, "else|return|typedef|delete|sizeof")) + continue; + + while (Token::Match(tok, "const|static|extern|public:|private:|protected:|;|mutable")) + tok = tok->next(); + + while (Token::Match(tok, "%var% ::")) + tok = tok->tokAt(2); + + // Skip template arguments.. + if (Token::Match(tok, "%type% <")) + { + int level = 1; + bool again; + Token *tok2 = tok->tokAt(2); + + do // Look for start of templates or template arguments + { + again = false; + + if (tok2->str() == "const") + tok2 = tok2->next(); + + while (Token::Match(tok2, "%var% ::")) + tok2 = tok2->tokAt(2); + + if (Token::Match(tok2, "%type% <")) + { + level++; + tok2 = tok2->tokAt(2); + again = true; + } + else if (Token::Match(tok2, "%type% *|&| ,")) + { + tok2 = tok2->tokAt(2); + if (tok2->str() == ",") + tok2 = tok2->next(); + again = true; + } + else if (level > 1 && Token::Match(tok2, "%type% *|&| >")) + { + --level; + while (tok2->str() != ">") + tok2 = tok2->next(); + tok2 = tok2->next(); + if (tok2->str() == ",") + tok2 = tok2->next(); + if (level == 1 && tok2->str() == ">") + break; + again = true; + } + else + { + while (tok2 && (tok2->isName() || tok2->isNumber() || tok2->str() == "*" || tok2->str() == "&" || tok2->str() == ",")) + tok2 = tok2->next(); + if (tok2->str() == "(") + { + tok2 = tok2->link()->next(); + if (tok2->str() == "(") + tok2 = tok2->link()->next(); + again = true; + } + } + } + while (again); + + do // Look for end of templates + { + again = false; + + if (level == 1 && Token::Match(tok2, "> %var%")) + tok = tok2; + else if (level > 1 && tok2->str() == ">") + { + level--; + if (level == 0) + tok = tok2; + else + { + tok2 = tok2->tokAt(1); + again = true; + } + } + else if (level == 1 && Token::Match(tok2, "> ::|*|& %var%")) + tok = tok2->next(); + else + continue; // Not code that I understand / not a variable declaration + } + while (again); + } + + // Determine name of declared variable.. + std::string varname; + Token *tok2 = tok->tokAt(1); + while (tok2) + { + if (tok2->isName()) + varname = tok2->str(); + else if (tok2->str() != "*" && tok2->str() != "&") + break; + tok2 = tok2->next(); + } + + // End of tokens reached.. + if (!tok2) + break; + + if (varname == "operator" && Token::Match(tok2, "=|+|-|*|/|[| ]| (")) + continue; + + if (varname == "new" && Token::Match(tok2->tokAt(-2), "operator new (|[")) + continue; + + // Is it a function? + if (tok2->str() == "(") + { + // Search for function declaration, e.g. void f(); + if (Token::simpleMatch(tok2->next(), ") ;")) + continue; + + // Search for function declaration, e.g. void f( int c ); + if (Token::Match(tok2->next(), "%num%") || + Token::Match(tok2->next(), "%bool%") || + tok2->next()->str()[0] == '"' || + tok2->next()->str()[0] == '\'' || + tok2->next()->varId() != 0) + { + // This is not a function + } + else + { + continue; + } + } + + // Variable declaration found => Set variable ids + if (Token::Match(tok2, "[,();[=]") && !varname.empty()) + { + ++_varId; + int indentlevel = 0; + int parlevel = 0; + bool funcDeclaration = false; + for (tok2 = tok->next(); tok2; tok2 = tok2->next()) + { + const char c = tok2->str()[0]; + if (c == varname[0]) + { + const std::string &prev = tok2->strAt(-1); + if (tok2->str() == varname && prev != "struct" && prev != "union" && prev != "::" && prev != "." && tok2->strAt(1) != "::") + tok2->varId(_varId); + } + else if (c == '{') + ++indentlevel; + else if (c == '}') + { + --indentlevel; + if (indentlevel < 0) + break; + + // We have reached the end of a loop: "for( int i;;) { }" + if (funcDeclaration && indentlevel <= 0) + break; + } + else if (c == '(') + ++parlevel; + else if (c == ')') + { + // Is this a function parameter or a variable declared in for example a for loop? + if (parlevel == 0 && indentlevel == 0 && Token::Match(tok2, ") const| {")) + funcDeclaration = true; + else + --parlevel; + } + else if (parlevel < 0 && c == ';') + break; + } + } + } + + // Struct/Class members + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // str.clear is a variable + // str.clear() is a member function + if (tok->varId() != 0 && + Token::Match(tok->next(), ". %var% !!(") && + tok->tokAt(2)->varId() == 0) + { + ++_varId; + + const std::string pattern(std::string(". ") + tok->strAt(2)); + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->varId() == tok->varId()) + { + if (Token::Match(tok2->next(), pattern.c_str())) + tok2->tokAt(2)->varId(_varId); + } + } + } + } + + // Member functions and variables in this source + std::list allMemberFunctions; + std::list allMemberVars; + { + for (Token *tok2 = _tokens; tok2; tok2 = tok2->next()) + { + if (Token::Match(tok2, "%var% :: %var%")) + { + if (Token::simpleMatch(tok2->tokAt(3), "(")) + allMemberFunctions.push_back(tok2); + else if (tok2->tokAt(2)->varId() != 0) + allMemberVars.push_back(tok2); + } + } + } + + // class members.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "class|struct %var% {|:")) + { + const std::string &classname(tok->next()->str()); + + // What member variables are there in this class? + std::map varlist; + { + unsigned int indentlevel = 0; + for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + // Indentation.. + if (tok2->str() == "{") + ++indentlevel; + else if (tok2->str() == "}") + { + if (indentlevel <= 1) + break; + --indentlevel; + } + + // Found a member variable.. + else if (indentlevel == 1 && tok2->varId() > 0) + varlist[tok2->str()] = tok2->varId(); + } + } + + // Are there any member variables in this class? + if (varlist.empty()) + continue; + + // Member variables + for (std::list::iterator func = allMemberVars.begin(); func != allMemberVars.end(); ++func) + { + if (!Token::simpleMatch(*func, classname.c_str())) + continue; + + Token *tok2 = *func; + tok2 = tok2->tokAt(2); + tok2->varId(varlist[tok2->str()]); + } + + // Member functions for this class.. + std::list funclist; + { + const std::string funcpattern(classname + " :: %var% ("); + for (std::list::iterator func = allMemberFunctions.begin(); func != allMemberFunctions.end(); ++func) + { + Token *tok2 = *func; + + // Found a class function.. + if (Token::Match(tok2, funcpattern.c_str())) + { + // Goto the end parenthesis.. + tok2 = tok2->tokAt(3)->link(); + if (!tok2) + break; + + // If this is a function implementation.. add it to funclist + if (Token::Match(tok2, ") const|volatile| {")) + funclist.push_back(tok2); + } + } + } + + // Update the variable ids.. + // Parse each function.. + for (std::list::iterator func = funclist.begin(); func != funclist.end(); ++func) + { + unsigned int indentlevel = 0; + for (Token *tok2 = *func; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + ++indentlevel; + else if (tok2->str() == "}") + { + if (indentlevel <= 1) + break; + --indentlevel; + } + else if (indentlevel > 0 && + tok2->varId() == 0 && + !Token::simpleMatch(tok2->previous(), ".") && + varlist.find(tok2->str()) != varlist.end()) + { + tok2->varId(varlist[tok2->str()]); + } + } + } + + } + } +} + +bool Tokenizer::createLinks() +{ + std::list type; + std::list links; + std::list links2; + std::list links3; + for (Token *token = _tokens; token; token = token->next()) + { + if (token->link()) + { + token->link(0); + } + + if (token->str() == "{") + { + links.push_back(token); + type.push_back(token); + } + else if (token->str() == "}") + { + if (links.empty()) + { + // Error, { and } don't match. + syntaxError(token, '{'); + return false; + } + if (type.back()->str() != "{") + { + syntaxError(type.back(), type.back()->str()[0]); + return false; + } + type.pop_back(); + + Token::createMutualLinks(links.back(), token); + links.pop_back(); + } + else if (token->str() == "(") + { + links2.push_back(token); + type.push_back(token); + } + else if (token->str() == ")") + { + if (links2.empty()) + { + // Error, ( and ) don't match. + syntaxError(token, '('); + return false; + } + if (type.back()->str() != "(") + { + syntaxError(type.back(), type.back()->str()[0]); + return false; + } + type.pop_back(); + + Token::createMutualLinks(links2.back(), token); + links2.pop_back(); + } + else if (token->str() == "[") + { + links3.push_back(token); + type.push_back(token); + } + else if (token->str() == "]") + { + if (links3.empty()) + { + // Error, [ and ] don't match. + syntaxError(token, '['); + return false; + } + if (type.back()->str() != "[") + { + syntaxError(type.back(), type.back()->str()[0]); + return false; + } + type.pop_back(); + + Token::createMutualLinks(links3.back(), token); + links3.pop_back(); + } + } + + if (!links.empty()) + { + // Error, { and } don't match. + syntaxError(links.back(), '{'); + return false; + } + + if (!links2.empty()) + { + // Error, ( and ) don't match. + syntaxError(links2.back(), '('); + return false; + } + + if (!links3.empty()) + { + // Error, [ and ] don't match. + syntaxError(links3.back(), '['); + return false; + } + + return true; +} + +void Tokenizer::simplifySizeof() +{ + // Fill the map _typeSize.. + _typeSize.clear(); + _typeSize["char"] = sizeof(char); + _typeSize["short"] = sizeof(short); + _typeSize["int"] = sizeof(int); + _typeSize["long"] = sizeof(long); + _typeSize["float"] = sizeof(float); + _typeSize["double"] = sizeof(double); + _typeSize["size_t"] = sizeof(size_t); + _typeSize["*"] = sizeof(void *); + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "class|struct %var%")) + { + // we assume that the size of structs and classes are always + // 100 bytes. + _typeSize[tok->strAt(1)] = 100; + } + } + + // Locate variable declarations and calculate the size + std::map sizeOfVar; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->varId() != 0 && sizeOfVar.find(tok->varId()) == sizeOfVar.end()) + { + const unsigned int varId = tok->varId(); + if (Token::Match(tok->tokAt(-3), "[;{}(,] %type% * %var% [;,)]") || + Token::Match(tok->tokAt(-4), "[;{}(,] const %type% * %var% [;),]") || + Token::Match(tok->tokAt(-2), "[;{}(,] %type% %var% [;),]") || + Token::Match(tok->tokAt(-3), "[;{}(,] const %type% %var% [;),]")) + { + const unsigned int size = sizeOfType(tok->previous()); + if (size == 0) + { + continue; + } + + sizeOfVar[varId] = MathLib::toString(size); + } + + else if (Token::Match(tok->tokAt(-1), "%type% %var% [ %num% ] [;=]") || + Token::Match(tok->tokAt(-2), "%type% * %var% [ %num% ] [;=]")) + { + const unsigned int size = sizeOfType(tok->tokAt(-1)); + if (size == 0) + continue; + + sizeOfVar[varId] = MathLib::toString(size * static_cast(MathLib::toLongNumber(tok->strAt(2)))); + } + + else if (Token::Match(tok->tokAt(-1), "%type% %var% [ %num% ] [,)]") || + Token::Match(tok->tokAt(-2), "%type% * %var% [ %num% ] [,)]")) + { + Token tempTok(0); + tempTok.str("*"); + sizeOfVar[varId] = MathLib::toString(sizeOfType(&tempTok)); + } + + else if (Token::Match(tok->tokAt(-1), "%type% %var% [ ] = %str% ;")) + { + const unsigned int size = sizeOfType(tok->tokAt(4)); + if (size == 0) + continue; + + sizeOfVar[varId] = MathLib::toString(size); + } + } + } + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "sizeof") + continue; + + if (!tok->next()) + break; + + if (Token::simpleMatch(tok->next(), "sizeof")) + continue; + + if (Token::simpleMatch(tok->next(), ". . .")) + { + Token::eraseTokens(tok, tok->tokAt(4)); + } + + // sizeof 'x' + if (tok->strAt(1)[0] == '\'') + { + tok->deleteThis(); + std::ostringstream sz; + sz << sizeof 'x'; + tok->str(sz.str()); + continue; + } + + // sizeof('x') + if (Token::Match(tok, "sizeof ( %any% )") && tok->strAt(2)[0] == '\'') + { + tok->deleteThis(); + tok->deleteThis(); + tok->deleteNext(); + std::ostringstream sz; + sz << sizeof 'x'; + tok->str(sz.str()); + continue; + } + + // sizeof "text" + if (Token::Match(tok->next(), "%str%")) + { + tok->deleteThis(); + std::ostringstream ostr; + ostr << (Token::getStrLength(tok) + 1); + tok->str(ostr.str()); + continue; + } + + // sizeof ("text") + if (Token::Match(tok->next(), "( %str% )")) + { + tok->deleteThis(); + tok->deleteThis(); + tok->deleteNext(); + std::ostringstream ostr; + ostr << (Token::getStrLength(tok) + 1); + tok->str(ostr.str()); + continue; + } + + // sizeof * (...) -> sizeof(*...) + if (Token::simpleMatch(tok->next(), "* (") && !Token::simpleMatch(tok->tokAt(2)->link(), ") .")) + { + tok->deleteNext(); + tok->next()->insertToken("*"); + } + + // sizeof a++ -> sizeof(a++) + if (Token::Match(tok->next(), "++|-- %var% !!.") || Token::Match(tok->next(), "%var% ++|--")) + { + tok->insertToken("("); + tok->tokAt(3)->insertToken(")"); + Token::createMutualLinks(tok->next(), tok->tokAt(4)); + } + + // sizeof 1 => sizeof ( 1 ) + if (tok->next()->isNumber()) + { + Token *tok2 = tok->next(); + tok->insertToken("("); + tok2->insertToken(")"); + Token::createMutualLinks(tok->next(), tok2->next()); + } + + // sizeof int -> sizeof( int ) + else if (tok->next()->str() != "(") + { + // Add parenthesis around the sizeof + int parlevel = 0; + for (Token *tempToken = tok->next(); tempToken; tempToken = tempToken->next()) + { + if (tempToken->str() == "(") + ++parlevel; + else if (tempToken->str() == ")") + --parlevel; + if (Token::Match(tempToken, "%var%")) + { + while (tempToken && tempToken->next() && tempToken->next()->str() == "[") + { + tempToken = tempToken->next()->link(); + } + if (!tempToken || !tempToken->next()) + { + break; + } + + if (tempToken->next()->str() == ".") + { + // We are checking a class or struct, search next varname + tempToken = tempToken->tokAt(1); + continue; + } + else if (Token::simpleMatch(tempToken->next(), "- >")) + { + // We are checking a class or struct, search next varname + tempToken = tempToken->tokAt(2); + continue; + } + else if (Token::Match(tempToken->next(), "++|--")) + { + // We have variable++ or variable--, there should be + // nothing after this + tempToken = tempToken->tokAt(2); + } + else if (parlevel > 0 && Token::simpleMatch(tempToken->next(), ") .")) + { + --parlevel; + tempToken = tempToken->tokAt(2); + continue; + } + + // Ok, we should be clean. Add ) after tempToken + tok->insertToken("("); + tempToken->insertToken(")"); + Token::createMutualLinks(tok->next(), tempToken->next()); + break; + } + } + } + + // sizeof(type *) => sizeof(*) + if (Token::Match(tok->next(), "( %type% * )")) + { + tok->next()->deleteNext(); + } + + if (Token::simpleMatch(tok->next(), "( * )")) + { + tok->str(MathLib::toString(sizeOfType(tok->tokAt(2)))); + Token::eraseTokens(tok, tok->tokAt(4)); + } + + // sizeof( a ) + else if (Token::Match(tok->next(), "( %var% )") && tok->tokAt(2)->varId() != 0) + { + if (sizeOfVar.find(tok->tokAt(2)->varId()) != sizeOfVar.end()) + { + tok->deleteThis(); + tok->deleteThis(); + tok->deleteNext(); + tok->str(sizeOfVar[tok->varId()]); + } + else + { + // don't try to replace size of variable if variable has + // similar name with type (#329) + } + } + + else if (Token::Match(tok, "sizeof ( %type% )")) + { + unsigned int size = sizeOfType(tok->tokAt(2)); + if (size > 0) + { + tok->str(MathLib::toString(size)); + Token::eraseTokens(tok, tok->tokAt(4)); + } + } + + else if (Token::Match(tok, "sizeof ( * %var% )") || Token::Match(tok, "sizeof ( %var% [ %num% ] )")) + { + // Some default value.. + unsigned int sz = 0; + + unsigned int varid = tok->tokAt((tok->tokAt(2)->str() == "*") ? 3 : 2)->varId(); + if (varid != 0) + { + // Try to locate variable declaration.. + const Token *decltok = Token::findmatch(_tokens, "%varid%", varid); + if (Token::Match(decltok->previous(), "%type% %var% [")) + { + sz = sizeOfType(decltok->previous()); + } + else if (Token::Match(decltok->previous(), "* %var% [")) + { + sz = sizeOfType(decltok->previous()); + } + else if (Token::Match(decltok->tokAt(-2), "%type% * %var%")) + { + sz = sizeOfType(decltok->tokAt(-2)); + } + } + else if (tok->strAt(3) == "[" && tok->tokAt(2)->isStandardType()) + { + sz = sizeOfType(tok->tokAt(2)); + if (sz == 0) + continue; + sz = sz * static_cast(MathLib::toLongNumber(tok->strAt(4))); + } + + if (sz > 0) + { + tok->str(MathLib::toString(sz)); + Token::eraseTokens(tok, tok->next()->link()->next()); + } + } + } + +} + +bool Tokenizer::simplifyTokenList() +{ + // clear the _functionList so it can't contain dead pointers + delete _symbolDatabase; + _symbolDatabase = NULL; + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok, "* const")) + tok->deleteNext(); + } + + // simplify references + simplifyReference(); + + simplifyStd(); + + simplifyGoto(); + + // Combine wide strings + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (tok->str() == "L" && tok->next() && tok->next()->str()[0] == '"') + { + // Combine 'L "string"' + tok->str(tok->next()->str()); + tok->deleteNext(); + } + } + + // Combine strings + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str()[0] != '"') + continue; + + tok->str(simplifyString(tok->str())); + while (tok->next() && tok->next()->str()[0] == '"') + { + tok->next()->str(simplifyString(tok->next()->str())); + + // Two strings after each other, combine them + tok->concatStr(tok->next()->str()); + tok->deleteNext(); + } + } + + // Convert e.g. atol("0") into 0 + simplifyMathFunctions(); + + // Convert + + into + and + - into - + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (tok->next()) + { + if (tok->str() == "+") + { + if (tok->next()->str() == "+") + { + tok->deleteNext(); + continue; + } + else if (tok->next()->str() == "-") + { + tok->str("-"); + tok->deleteNext(); + continue; + } + } + else if (tok->str() == "-") + { + if (tok->next()->str() == "-") + { + tok->str("+"); + tok->deleteNext(); + continue; + } + else if (tok->next()->str() == "+") + { + tok->deleteNext(); + continue; + } + } + + break; + } + } + + // 0[a] -> a[0] + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "%num% [ %var% ]")) + { + const std::string temp = tok->str(); + tok->str(tok->tokAt(2)->str()); + tok->tokAt(2)->str(temp); + } + } + + simplifySizeof(); + + // replace strlen(str) + simplifyKnownVariables(); + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "strlen ( %str% )")) + { + std::ostringstream ostr; + ostr << Token::getStrLength(tok->tokAt(2)); + tok->str(ostr.str()); + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + } + } + + // change array to pointer.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "%type% %var% [ ] [,;=]")) + { + Token::eraseTokens(tok->next(), tok->tokAt(4)); + tok->insertToken("*"); + } + } + + // Replace constants.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "const %type% %var% = %num% ;")) + { + unsigned int varId = tok->tokAt(2)->varId(); + if (varId == 0) + { + tok = tok->tokAt(5); + continue; + } + + const std::string num = tok->strAt(4); + int indent = 1; + for (Token *tok2 = tok->tokAt(6); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + { + ++indent; + } + else if (tok2->str() == "}") + { + --indent; + if (indent == 0) + break; + } + + // Compare constants, but don't touch members of other structures + else if (tok2->varId() == varId) + { + tok2->str(num); + } + } + } + } + + simplifyCasts(); + + // Simplify simple calculations.. + simplifyCalculations(); + + // Replace "*(str + num)" => "str[num]" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (! strchr(";{}(=<>", tok->str()[0])) + continue; + + Token *next = tok->next(); + if (! next) + break; + + if (Token::Match(next, "* ( %var% + %num% )") || + Token::Match(next, "* ( %var% + %var% )")) + { + // var + tok = tok->next(); + tok->str(tok->strAt(2)); + + // [ + tok = tok->next(); + tok->str("["); + + // num + tok = tok->next(); + tok->str(tok->strAt(2)); + + // ] + tok = tok->next(); + tok->str("]"); + + tok->deleteNext(); + tok->deleteNext(); + + Token::createMutualLinks(next->tokAt(1), next->tokAt(3)); + } + } + + // simplify "x=realloc(y,0);" => "free(y); x=0;".. + // and "x = realloc (0, n);" => "x = malloc(n);" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "; %var% = realloc ( %var% , 0 ) ;")) + { + const std::string varname(tok->next()->str()); + const unsigned int varid(tok->next()->varId()); + + // Delete the "%var% =" + tok->deleteNext(); + tok->deleteNext(); + + // Change function name "realloc" to "free" + tok->next()->str("free"); + + // delete the ", 0" + Token::eraseTokens(tok->tokAt(3), tok->tokAt(6)); + + // goto the ";" + tok = tok->tokAt(5); + + // insert "var=0;" + tok->insertToken(";"); + tok->insertToken("0"); + tok->insertToken("="); + tok->insertToken(varname); + tok->next()->varId(varid); + } + else if (Token::Match(tok, "; %var% = realloc ( 0 , %num% ) ;")) + { + const std::string varname(tok->next()->str()); + + tok = tok->tokAt(3); + // Change function name "realloc" to "malloc" + tok->str("malloc"); + + // delete "0 ," + tok->next()->deleteNext(); + tok->next()->deleteNext(); + } + } + + // Change initialisation of variable to assignment + simplifyInitVar(); + + // Simplify variable declarations + simplifyVarDecl(); + + simplifyFunctionParameters(); + elseif(); + simplifyErrNoInWhile(); + simplifyIfAssign(); + simplifyRedundantParanthesis(); + simplifyIfNot(); + simplifyIfNotNull(); + simplifyIfSameInnerCondition(); + simplifyComparisonOrder(); + simplifyNestedStrcat(); + simplifyWhile0(); + simplifyFuncInWhile(); + + simplifyIfAssign(); // could be affected by simplifyIfNot + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "case %any% : %var%")) + tok->tokAt(2)->insertToken(";"); + if (Token::Match(tok, "default : %var%")) + tok->next()->insertToken(";"); + } + + // In case variable declarations have been updated... + setVarId(); + + bool modified = true; + while (modified) + { + modified = false; + modified |= simplifyConditions(); + modified |= simplifyFunctionReturn(); + modified |= simplifyKnownVariables(); + modified |= removeReduntantConditions(); + modified |= simplifyRedundantParanthesis(); + modified |= simplifyQuestionMark(); + modified |= simplifyCalculations(); + } + + // Remove redundant parentheses in return.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (Token::simpleMatch(tok, "return (")) + { + Token *tok2 = tok->next()->link(); + if (Token::simpleMatch(tok2, ") ;")) + { + tok->deleteNext(); + tok2->deleteThis(); + } + else + { + break; + } + } + } + + removeRedundantAssignment(); + + simplifyComma(); + if (_settings->debug) + { + _tokens->printOut(0, _files); + } + + _tokens->assignProgressValues(); + + removeRedundantSemicolons(); + + return validate(); +} +//--------------------------------------------------------------------------- + +void Tokenizer::removeMacrosInGlobalScope() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(") + { + tok = tok->link(); + if (Token::Match(tok, ") %type% {") && tok->strAt(1) != "const") + tok->deleteNext(); + } + + if (tok->str() == "{") + tok = tok->link(); + } +} +//--------------------------------------------------------------------------- + +void Tokenizer::removeRedundantAssignment() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "{") + tok = tok->link(); + + if (Token::Match(tok, ") const| {")) + { + // parse in this function.. + std::set localvars; + if (tok->next()->str() == "const") + tok = tok->next(); + const Token * const end = tok->next()->link(); + for (Token *tok2 = tok->next(); tok2 && tok2 != end; tok2 = tok2->next()) + { + if (Token::Match(tok2, "[;{}] %type% * %var% ;") && tok2->strAt(1) != "return") + { + tok2 = tok2->tokAt(3); + localvars.insert(tok2->varId()); + } + else if (Token::Match(tok2, "[;{}] %type% %var% ;") && tok2->next()->isStandardType()) + { + tok2 = tok2->tokAt(2); + localvars.insert(tok2->varId()); + } + else if (tok2->varId() && + !Token::Match(tok2->previous(), "[;{}] %var% = %var% ;") && + !Token::Match(tok2->previous(), "[;{}] %var% = %num% ;") && + !(Token::Match(tok2->previous(), "[;{}] %var% = %any% ;") && tok2->strAt(2)[0] == '\'')) + { + localvars.erase(tok2->varId()); + } + } + localvars.erase(0); + if (!localvars.empty()) + { + for (Token *tok2 = tok->next(); tok2 && tok2 != end; tok2 = tok2->next()) + { + if (Token::Match(tok2, "[;{}] %type% %var% ;") && localvars.find(tok2->tokAt(2)->varId()) != localvars.end()) + { + Token::eraseTokens(tok2, tok2->tokAt(3)); + } + else if (Token::Match(tok2, "[;{}] %type% * %var% ;") && localvars.find(tok2->tokAt(3)->varId()) != localvars.end()) + { + Token::eraseTokens(tok2, tok2->tokAt(4)); + } + else if (Token::Match(tok2, "[;{}] %var% = %any% ;") && localvars.find(tok2->next()->varId()) != localvars.end()) + { + Token::eraseTokens(tok2, tok2->tokAt(4)); + } + } + } + } + } +} + +bool Tokenizer::removeReduntantConditions() +{ + // Return value for function. Set to true if there are any simplifications + bool ret = false; + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "if") + continue; + + if (!Token::Match(tok->tokAt(1), "( %bool% ) {")) + continue; + + // Find matching else + const Token *elseTag = 0; + + // Find the closing "}" + elseTag = tok->tokAt(4)->link()->next(); + + bool boolValue = false; + if (tok->tokAt(2)->str() == "true") + boolValue = true; + + // Handle if with else + if (elseTag && elseTag->str() == "else") + { + if (Token::simpleMatch(elseTag->next(), "if (")) + { + // Handle "else if" + if (boolValue == false) + { + // Convert "if( false ) {aaa;} else if() {bbb;}" => "if() {bbb;}" + Token::eraseTokens(tok, elseTag->tokAt(2)); + ret = true; + } + else + { + // Keep first if, remove every else if and else after it + const Token *lastTagInIf = elseTag->tokAt(2); + while (lastTagInIf) + { + if (lastTagInIf->str() == "(") + { + lastTagInIf = lastTagInIf->link()->next(); + } + + lastTagInIf = lastTagInIf->link()->next(); + if (!Token::simpleMatch(lastTagInIf, "else")) + break; + + lastTagInIf = lastTagInIf->next(); + if (lastTagInIf->str() == "if") + lastTagInIf = lastTagInIf->next(); + } + + Token::eraseTokens(elseTag->previous(), lastTagInIf); + ret = true; + } + } + else + { + // Handle else + if (boolValue == false) + { + // Convert "if( false ) {aaa;} else {bbb;}" => "{bbb;}" or ";{bbb;}" + if (tok->previous()) + tok = tok->previous(); + else + tok->str(";"); + + Token::eraseTokens(tok, elseTag->tokAt(1)); + } + else + { + if (elseTag->tokAt(1)->str() == "{") + { + // Convert "if( true ) {aaa;} else {bbb;}" => "{aaa;}" + const Token *end = elseTag->tokAt(1)->link(); + + // Remove the "else { aaa; }" + Token::eraseTokens(elseTag->previous(), end->tokAt(1)); + } + + // Remove "if( true )" + if (tok->previous()) + tok = tok->previous(); + else + tok->str(";"); + + Token::eraseTokens(tok, tok->tokAt(5)); + } + + ret = true; + } + } + + // Handle if without else + else + { + if (boolValue == false) + { + // Remove if and its content + if (tok->previous()) + tok = tok->previous(); + else + tok->str(";"); + + Token::eraseTokens(tok, elseTag); + } + else + { + // convert "if( true ) {aaa;}" => "{aaa;}" + if (tok->previous()) + tok = tok->previous(); + else + tok->str(";"); + + Token::eraseTokens(tok, tok->tokAt(5)); + } + + ret = true; + } + } + + return ret; +} + + +void Tokenizer::removeRedundantSemicolons() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(") + { + tok = tok->link(); + } + while (Token::simpleMatch(tok, "; ;")) + { + tok->deleteNext(); + } + } +} + + +void Tokenizer::simplifyIfAddBraces() +{ + for (Token *tok = _tokens; tok; tok = tok ? tok->next() : NULL) + { + if (tok->str() == "(") + { + tok = tok->link(); + continue; + } + + if (Token::Match(tok, "if|for|while (")) + { + // don't add "{}" around ";" in "do {} while();" (#609) + const Token *prev = tok->previous(); + if (Token::simpleMatch(prev, "} while") && + prev->link() && + prev->link()->previous() && + prev->link()->previous()->str() == "do") + { + continue; + } + + // Goto the ending ')' + tok = tok->next()->link(); + + // ')' should be followed by '{' + if (!tok || Token::simpleMatch(tok, ") {")) + continue; + } + + else if (tok->str() == "else") + { + // An else followed by an if or brace don't need to be processed further + if (Token::Match(tok, "else if|{")) + continue; + } + + else + { + continue; + } + + // If there is no code after he if(), abort + if (!tok->next()) + return; + + + // insert open brace.. + tok->insertToken("{"); + tok = tok->next(); + Token *tempToken = tok; + + bool innerIf = Token::simpleMatch(tempToken->next(), "if"); + + if (Token::simpleMatch(tempToken->next(), "do {")) + tempToken = tempToken->tokAt(2)->link(); + + // insert close brace.. + // In most cases it would work to just search for the next ';' and insert a closing brace after it. + // But here are special cases.. + // * if (cond) for (;;) break; + // * if (cond1) if (cond2) { } + // * if (cond1) if (cond2) ; else ; + while ((tempToken = tempToken->next()) != NULL) + { + if (tempToken->str() == "{") + { + if (Token::simpleMatch(tempToken->previous(),"else {")) + { + if (innerIf) + tempToken = tempToken->link(); + else + tempToken = tempToken->tokAt(-2); + break; + } + tempToken = tempToken->link(); + if (!tempToken || !tempToken->next()) + break; + if (tempToken->next()->isName() && tempToken->next()->str() != "else") + break; + continue; + } + + if (tempToken->str() == "(") + { + tempToken = tempToken->link(); + continue; + } + + if (tempToken->str() == "}") + { + // insert closing brace before this token + tempToken = tempToken->previous(); + break; + } + + if (tempToken->str() == ";") + { + if (!innerIf) + break; + + if (Token::simpleMatch(tempToken, "; else if")) + ; + else if (Token::simpleMatch(tempToken, "; else")) + innerIf = false; + else + break; + } + } + + if (tempToken) + { + tempToken->insertToken("}"); + Token::createMutualLinks(tok, tempToken->next()); + } + } +} + +bool Tokenizer::simplifyDoWhileAddBracesHelper(Token *tok) +{ + if (Token::Match(tok->next(), "[),]")) + { + // fix for #988 + return false; + } + + Token *tok1 = tok; // token with "do" + Token *tok2 = NULL; // token with "while" + Token *tok3 = tok->next(); + + // skip loop body + bool result = false; + while (tok3) + { + if (tok3->str() == "{") + { + // skip all tokens until "}" + tok3 = tok3->link(); + } + else if (tok3->str() == "while") + { + tok2 = tok3; + break; + } + else if (Token::simpleMatch(tok3, "do {")) + { + // Skip do{}while inside the current "do" + tok3 = tok3->next()->link(); + if (Token::simpleMatch(tok3->next(), "while")) + tok3 = tok3->next(); + } + else if (Token::Match(tok3, "do !!{") && + !Token::Match(tok3->next(), "[),]")) + { + // Handle do-while inside the current "do" + // first and return true to get the outer + // "do" to be handled later. + tok1 = tok3; + result = true; + } + + tok3 = tok3->next(); + } + + if (tok2) + { + // insert "{" after "do" + tok1->insertToken("{"); + + // insert "}" before "while" + tok2->previous()->insertToken("}"); + + Token::createMutualLinks(tok1->next(), tok2->previous()); + } + else + result = false; + + return result; +} + +void Tokenizer::simplifyDoWhileAddBraces() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "do !!{")) + { + while (simplifyDoWhileAddBracesHelper(tok)) + { + // Call until the function returns false to + // handle do-while inside do-while + + } + } + } +} + +void Tokenizer::simplifyCompoundAssignment() +{ + // Simplify compound assignments: + // "a+=b" => "a = a + b" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "[;{}] (") || Token::Match(tok, "[;{}:] *| (| %var%")) + { + if (tok->str() == ":") + { + if (tok->strAt(-2) != "case") + continue; + } + + // backup current token.. + Token * const tok1 = tok; + + if (tok->strAt(1) == "*") + tok = tok->next(); + + if (tok->strAt(1) == "(") + { + tok = tok->next()->link()->next(); + } + else + { + // variable.. + tok = tok->tokAt(2); + while (Token::Match(tok, ". %var%") || + (tok && tok->str() == "[") || + Token::simpleMatch(tok, "( )")) + { + if (tok->str() != "[") + tok = tok->tokAt(2); + else if (tok->str() == "(") + tok = tok->tokAt(2); + else + { + // goto "]" + tok = tok->next(); + while (tok && !Token::Match(tok, "++|--|(|[|]")) + tok = tok->next(); + if (!tok) + break; + else if (tok->str() == "]") + tok = tok->next(); + else + break; + } + } + } + if (!tok) + break; + + // Is current token at a compound assignment: +=|-=|.. ? + const std::string &str = tok->str(); + std::string op; // operator used in assignment + if (str.size() == 2 && str[1] == '=' && str.find_first_of("+-*/%&|^")==0) + op = str.substr(0, 1); + else if (str=="<<=" || str==">>=") + op = str.substr(0, 2); + else + { + tok = tok1; + continue; + } + + // Remove the whole statement if it says: "+=0;", "-=0;", "*=1;" or "/=1;" + if (Token::Match(tok, "+=|-= 0 ;") || + Token::Match(tok, "+=|-= '\\0' ;") || + Token::simpleMatch(tok, "|= 0 ;") || + Token::Match(tok, "*=|/= 1 ;")) + { + tok = tok1; + while (tok->next()->str() != ";") + tok->deleteNext(); + } + else + { + // simplify the compound assignment.. + tok->str("="); + tok->insertToken(op); + std::stack tokend; + for (const Token *tok2 = tok->previous(); tok2 && tok2 != tok1; tok2 = tok2->previous()) + { + tok->insertToken(tok2->str()); + tok->next()->varId(tok2->varId()); + if (Token::Match(tok->next(), "]|)")) + tokend.push(tok->next()); + else if (Token::Match(tok->next(), "(|[")) + { + Token::createMutualLinks(tok->next(), tokend.top()); + tokend.pop(); + } + } + } + } + } +} + +void Tokenizer::simplifyConditionOperator() +{ + int parlevel = 0; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(") + ++parlevel; + else if (tok->str() == ")") + --parlevel; + else if (parlevel == 0 && Token::Match(tok, "; %var% = %var% ? %var% : %var% ;")) + { + const std::string var(tok->strAt(1)); + const std::string condition(tok->strAt(3)); + const std::string value1(tok->strAt(5)); + const std::string value2(tok->strAt(7)); + + Token::eraseTokens(tok, tok->tokAt(9)); + + std::string str("if ( " + condition + " ) { " + var + " = " + value1 + " ; } else { " + var + " = " + value2 + " ; }"); + std::string::size_type pos1 = 0; + while (pos1 != std::string::npos) + { + std::string::size_type pos2 = str.find(" ", pos1); + if (pos2 == std::string::npos) + { + tok->insertToken(str.substr(pos1).c_str()); + pos1 = pos2; + } + else + { + tok->insertToken(str.substr(pos1, pos2 - pos1).c_str()); + pos1 = pos2 + 1; + } + tok = tok->next(); + } + + Token::createMutualLinks(tok->tokAt(-15), tok->tokAt(-13)); + Token::createMutualLinks(tok->tokAt(-12), tok->tokAt(-7)); + Token::createMutualLinks(tok->tokAt(-5), tok); + } + } +} + +bool Tokenizer::simplifyConditions() +{ + bool ret = false; + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "! %num%") || Token::Match(tok, "! %bool%")) + { + if (tok->next()->str() == "0" || tok->next()->str() == "false") + tok->str("true"); + else + tok->str("false"); + + tok->deleteNext(); + ret = true; + } + + if (Token::simpleMatch(tok, "( true &&") || + Token::simpleMatch(tok, "&& true &&") || + Token::simpleMatch(tok->next(), "&& true )")) + { + Token::eraseTokens(tok, tok->tokAt(3)); + ret = true; + } + + else if (Token::simpleMatch(tok, "( false ||") || + Token::simpleMatch(tok, "|| false ||") || + Token::simpleMatch(tok->next(), "|| false )")) + { + Token::eraseTokens(tok, tok->tokAt(3)); + ret = true; + } + + else if (Token::simpleMatch(tok, "( true ||") || + Token::simpleMatch(tok, "( false &&")) + { + Token::eraseTokens(tok->next(), tok->link()); + ret = true; + } + + else if (Token::simpleMatch(tok, "|| true )") || + Token::simpleMatch(tok, "&& false )")) + { + tok = tok->next(); + Token::eraseTokens(tok->next()->link(), tok); + ret = true; + } + + // Change numeric constant in condition to "true" or "false" + if (Token::Match(tok, "if|while ( %num%") && + (tok->tokAt(3)->str() == ")" || tok->tokAt(3)->str() == "||" || tok->tokAt(3)->str() == "&&")) + { + tok->tokAt(2)->str((tok->tokAt(2)->str() != "0") ? "true" : "false"); + ret = true; + } + Token *tok2 = tok->tokAt(2); + if (tok2 && + (tok->str() == "&&" || tok->str() == "||") && + Token::Match(tok->next(), "%num%") && + (tok2->str() == ")" || tok2->str() == "&&" || tok2->str() == "||")) + { + tok->next()->str((tok->next()->str() != "0") ? "true" : "false"); + ret = true; + } + + // Reduce "(%num% == %num%)" => "(true)"/"(false)" + const Token *tok4 = tok->tokAt(4); + if (! tok4) + break; + if ((tok->str() == "&&" || tok->str() == "||" || tok->str() == "(") && + (Token::Match(tok->tokAt(1), "%num% %any% %num%") || + Token::Match(tok->tokAt(1), "%bool% %any% %bool%")) && + (tok4->str() == "&&" || tok4->str() == "||" || tok4->str() == ")" || tok4->str() == "?")) + { + std::string cmp = tok->strAt(2); + bool result = false; + if (Token::Match(tok->tokAt(1), "%num%")) + { + // Compare numbers + + if (cmp == "==" || cmp == "!=") + { + const std::string op1(tok->strAt(1)); + const std::string op2(tok->strAt(3)); + + bool eq = false; + if (MathLib::isInt(op1) && MathLib::isInt(op2)) + eq = (MathLib::toLongNumber(op1) == MathLib::toLongNumber(op2)); + else + eq = (op1 == op2); + + if (cmp == "==") + result = eq; + else + result = !eq; + } + else + { + double op1 = MathLib::toDoubleNumber(tok->strAt(1)); + double op2 = MathLib::toDoubleNumber(tok->strAt(3)); + if (cmp == ">=") + result = (op1 >= op2); + else if (cmp == ">") + result = (op1 > op2); + else if (cmp == "<=") + result = (op1 <= op2); + else if (cmp == "<") + result = (op1 < op2); + else + cmp = ""; + } + } + else + { + // Compare boolean + bool op1 = (tok->strAt(1) == std::string("true")); + bool op2 = (tok->strAt(3) == std::string("true")); + + if (cmp == "==") + result = (op1 == op2); + else if (cmp == "!=") + result = (op1 != op2); + else if (cmp == ">=") + result = (op1 >= op2); + else if (cmp == ">") + result = (op1 > op2); + else if (cmp == "<=") + result = (op1 <= op2); + else if (cmp == "<") + result = (op1 < op2); + else + cmp = ""; + } + + if (! cmp.empty()) + { + tok = tok->next(); + tok->deleteNext(); + tok->deleteNext(); + + tok->str(result ? "true" : "false"); + ret = true; + } + } + } + + return ret; +} + +bool Tokenizer::simplifyQuestionMark() +{ + bool ret = false; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "?") + continue; + + if (!tok->tokAt(-2)) + continue; + + if (!Token::Match(tok->tokAt(-2), "[=,(]")) + continue; + + if (!Token::Match(tok->previous(), "%bool%") && + !Token::Match(tok->previous(), "%num%")) + continue; + + // Find the ":" token.. + Token *semicolon = 0; + { + unsigned int parlevel = 0; + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "(") + ++parlevel; + else if (tok2->str() == ")") + { + if (parlevel == 0) + break; + --parlevel; + } + else if (parlevel == 0 && tok2->str() == ":") + { + semicolon = tok2; + break; + } + } + } + if (!semicolon || !semicolon->next()) + continue; + + if (tok->previous()->str() == "false" || + tok->previous()->str() == "0") + { + // Use code after semicolon, remove code before it. + semicolon = semicolon->next(); + tok = tok->tokAt(-2); + Token::eraseTokens(tok, semicolon); + + tok = tok->next(); + ret = true; + } + + // The condition is true. Delete the operator after the ":".. + else + { + const Token *end = 0; + + // check the operator after the : + if (Token::simpleMatch(semicolon, ": (")) + { + end = semicolon->next()->link(); + if (!Token::Match(end, ") !!.")) + continue; + } + + // delete the condition token and the "?" + tok = tok->tokAt(-2); + Token::eraseTokens(tok, tok->tokAt(3)); + + // delete operator after the : + if (end) + { + Token::eraseTokens(semicolon->previous(), end->next()); + continue; + } + + int ind = 0; + for (const Token *endTok = semicolon; endTok; endTok = endTok->next()) + { + if (endTok->str() == ";") + { + Token::eraseTokens(semicolon->previous(), endTok); + ret = true; + break; + } + + else if (Token::Match(endTok, "[({[]")) + { + ++ind; + } + + else if (Token::Match(endTok, "[)}]]")) + { + --ind; + if (ind < 0) + { + Token::eraseTokens(semicolon->previous(), endTok); + ret = true; + break; + } + } + } + } + } + + return ret; +} + +void Tokenizer::simplifyCasts() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (Token::Match(tok->next(), "( %type% *| ) *|&| %var%") || + Token::Match(tok->next(), "( %type% %type% *| ) *|&| %var%") || + (!tok->isName() && (Token::Match(tok->next(), "( %type% * ) (") || + Token::Match(tok->next(), "( %type% %type% * ) (")))) + { + if (tok->isName() && tok->str() != "return") + break; + + if (Token::simpleMatch(tok->previous(), "operator")) + break; + + // Remove cast.. + Token::eraseTokens(tok, tok->next()->link()->next()); + + if (tok->str() == ")" && tok->link()->previous()) + { + // If there was another cast before this, go back + // there to check it also. e.g. "(int)(char)x" + tok = tok->link()->previous(); + } + } + + // Replace pointer casts of 0.. "(char *)0" => "0" + while (Token::Match(tok->next(), "( %type% * ) 0") || + Token::Match(tok->next(), "( %type% %type% * ) 0")) + { + Token::eraseTokens(tok, tok->next()->link()->next()); + if (tok->str() == ")" && tok->link()->previous()) + { + // If there was another cast before this, go back + // there to check it also. e.g. "(char*)(char*)0" + tok = tok->link()->previous(); + } + } + + while (Token::Match(tok->next(), "dynamic_cast|reinterpret_cast|const_cast|static_cast <")) + { + Token *tok2 = tok->next(); + unsigned int level = 0; + while (tok2) + { + if (tok2->str() == "<") + ++level; + else if (tok2->str() == ">") + { + --level; + if (level == 0) + break; + } + tok2 = tok2->next(); + } + + if (Token::simpleMatch(tok2, "> (")) + { + Token *closeBracket = tok2->next()->link(); + if (closeBracket) + { + Token::eraseTokens(tok, tok2->tokAt(2)); + closeBracket->deleteThis(); + } + else + { + break; + } + } + else + { + break; + } + } + } +} + + +void Tokenizer::simplifyFunctionParameters() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "{" || tok->str() == "[" || tok->str() == "(") + { + tok = tok->link(); + if (!tok) + break; + continue; + } + + // Find the function e.g. foo( x ) or foo( x, y ) + if (Token::Match(tok, "%var% ( %var% [,)]")) + { + // We have found old style function, now we need to change it + + // backup pointer to the '(' token + Token * const tok1 = tok->next(); + + // Get list of argument names + std::map argumentNames; + bool bailOut = false; + for (tok = tok->tokAt(2); tok; tok = tok->tokAt(2)) + { + if (!Token::Match(tok, "%var% [,)]")) + { + bailOut = true; + break; + } + + if (argumentNames.find(tok->str()) != argumentNames.end()) + { + // Invalid code, two arguments with the same name. + // TODO, print error perhaps? + bailOut = true; + break; + } + + argumentNames[tok->str()] = tok; + if (tok->next()->str() == ")") + { + tok = tok->tokAt(2); + break; + } + } + + if (bailOut) + { + tok = tok1->link(); + if (!tok) + return; + continue; + } + + Token *start = tok; + while (tok && tok->str() != "{") + { + if (tok->str() == ";") + { + tok = tok->previous(); + // Move tokens from start to tok into the place of + // argumentNames[tok->str()] and remove the ";" + + if (argumentNames.find(tok->str()) == argumentNames.end()) + { + bailOut = true; + break; + } + + // Remove the following ";" + Token *temp = tok->tokAt(2); + tok->deleteNext(); + + // Replace "x" with "int x" or similar + Token::replace(argumentNames[tok->str()], start, tok); + argumentNames.erase(tok->str()); + tok = temp; + start = tok; + } + else + { + tok = tok->next(); + } + } + + if (Token::simpleMatch(tok, "{")) + tok = tok->link(); + + if (tok == NULL) + { + break; + } + + if (bailOut) + { + continue; + } + } + } +} + + +void Tokenizer:: simplifyFunctionPointers() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // check for function pointer cast + if (Token::Match(tok, "( %type% *| *| ( * ) (") || + Token::Match(tok, "( %type% %type% *| *| ( * ) (") || + Token::Match(tok, "static_cast < %type% *| *| ( * ) (") || + Token::Match(tok, "static_cast < %type% %type% *| *| ( * ) (")) + { + Token *tok1 = tok; + + if (tok1->str() == "static_cast") + tok1 = tok1->next(); + + tok1 = tok1->next(); + + if (Token::Match(tok1->next(), "%type%")) + tok1 = tok1->next(); + + while (tok1->next()->str() == "*") + tok1 = tok1->next(); + + // check that the cast ends + if (!Token::Match(tok1->tokAt(4)->link(), ") )|>")) + continue; + + // ok simplify this function pointer cast to an ordinary pointer cast + tok1->deleteNext(); + tok1->next()->deleteNext(); + const Token *tok2 = tok1->tokAt(2)->link(); + Token::eraseTokens(tok1->next(), tok2 ? tok2->next() : 0); + continue; + } + + // check for start of statement + else if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|(|public:|protected:|private:")) + continue; + + if (Token::Match(tok, "%type% *| *| ( * %var% ) (")) + ; + else if (Token::Match(tok, "%type% %type% *| *| ( * %var% ) (")) + tok = tok->next(); + else + continue; + + while (tok->next()->str() == "*") + tok = tok->next(); + + // check that the declaration ends + if (!Token::Match(tok->tokAt(5)->link(), ") ;|,|)|=")) + continue; + + // ok simplify this function pointer to an ordinary pointer + tok->deleteNext(); + tok->tokAt(2)->deleteNext(); + const Token *tok2 = tok->tokAt(3)->link(); + Token::eraseTokens(tok->tokAt(2), tok2 ? tok2->next() : 0); + } +} + + +bool Tokenizer::simplifyFunctionReturn() +{ + bool ret = false; + int indentlevel = 0; + for (const Token *tok = tokens(); tok; tok = tok->next()) + { + if (tok->str() == "{") + ++indentlevel; + + else if (tok->str() == "}") + --indentlevel; + + else if (indentlevel == 0 && Token::Match(tok, "%var% ( ) { return %num% ; }") && tok->str() != ")") + { + std::ostringstream pattern; + pattern << "[(=+-*/] " << tok->str() << " ( ) [;)+-*/]"; + for (Token *tok2 = _tokens; tok2; tok2 = tok2->next()) + { + if (Token::Match(tok2, pattern.str().c_str())) + { + tok2 = tok2->next(); + tok2->str(tok->strAt(5)); + tok2->deleteNext(); + tok2->deleteNext(); + ret = true; + } + } + } + } + + return ret; +} + + +static void incdec(std::string &value, const std::string &op) +{ + int ivalue = 0; + std::istringstream istr(value.c_str()); + istr >> ivalue; + if (op == "++") + ++ivalue; + else if (op == "--") + --ivalue; + std::ostringstream ostr; + ostr << ivalue; + value = ostr.str(); +} + + + +void Tokenizer::simplifyVarDecl() +{ + // Split up variable declarations.. + // "int a=4;" => "int a; a=4;" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok, "= {")) + { + tok = tok->next()->link(); + if (!tok) + break; + } + + if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|)|public:|protected:|private:")) + continue; + + Token *type0 = tok; + if (!Token::Match(type0, "%type%")) + continue; + if (Token::Match(type0, "else|return|public:|protected:|private:")) + continue; + + bool isconst = false; + bool isstatic = false; + Token *tok2 = type0; + unsigned int typelen = 1; + + while (Token::Match(tok2, "%type% %type% *| *| %var%")) + { + if (tok2->str() == "const") + isconst = true; + + else if (tok2->str() == "static") + isstatic = true; + + tok2 = tok2->next(); + ++typelen; + } + + // Don't split up const declaration.. + if (isconst && Token::Match(tok2, "%type% %var% =")) + continue; + + // strange looking variable declaration => don't split up. + if (Token::Match(tok2, "%type% *| %var% , %type% *| %var%")) + continue; + + if (Token::Match(tok2, "%type% *| %var% ,|=")) + { + const bool isPointer = (tok2->next()->str() == "*"); + const Token *varName = tok2->tokAt((isPointer ? 2 : 1)); + Token *endDeclaration = varName->next(); + + if (varName->str() != "operator") + { + tok2 = endDeclaration; // The ',' or '=' token + + if (isstatic && tok2->str() == "=") + { + if (Token::Match(tok2->next(), "%num% ,")) + tok2 = tok2->tokAt(2); + else + tok2 = NULL; + } + } + else + tok2 = NULL; + } + + else if (Token::Match(tok2, "%type% * * %var% ,|=")) + { + if (tok2->tokAt(3)->str() != "operator") + tok2 = tok2->tokAt(4); // The ',' token + else + tok2 = NULL; + } + + else if (Token::Match(tok2, "%type% * const %var% ,|=")) + { + if (tok2->tokAt(3)->str() != "operator") + { + tok2 = tok2->tokAt(4); // The ',' token + } + else + { + tok2 = NULL; + } + } + + else if (Token::Match(tok2, "%type% %var% [ %num% ] ,|=|[") || + Token::Match(tok2, "%type% %var% [ %var% ] ,|=|[")) + { + tok2 = tok2->tokAt(5); // The ',' token + while (Token::Match(tok2, "[ %num% ]") || Token::Match(tok2, "[ %var% ]")) + tok2 = tok2->tokAt(3); + if (!Token::Match(tok2, "=|,")) + { + tok2 = NULL; + } + + if (tok2 && tok2->str() == "=") + { + while (tok2 && tok2->str() != ",") + { + if (tok2->str() == "{") + tok2 = tok2->link(); + + tok2 = tok2->next(); + + if (tok2->str() == ";") + tok2 = NULL; + } + } + } + + else if (Token::Match(tok2, "%type% * %var% [ %num% ] ,") || + Token::Match(tok2, "%type% * %var% [ %var% ] ,")) + { + tok2 = tok2->tokAt(6); // The ',' token + } + + else if (Token::Match(tok2, "std :: %type% <") || Token::Match(tok2, "%type% <")) + { + // + // Deal with templates and standart types + // + if (Token::simpleMatch(tok2, "std ::")) + { + typelen += 2; + tok2 = tok2->tokAt(2); + } + + typelen += 2; + tok2 = tok2->tokAt(2); + size_t indentlevel = 1; + + for (Token *tok3 = tok2; tok3; tok3 = tok3->next()) + { + ++typelen; + + if (tok3->str() == "<") + { + ++indentlevel; + } + else if (tok3->str() == ">") + { + --indentlevel; + if (indentlevel == 0) + { + tok2 = tok3->next(); + break; + } + } + else if (tok3->str() == ";") + { + break; + } + } + + if (!tok2) + break; + + if (Token::Match(tok2, ":: %type%")) + { + typelen += 2; + tok2 = tok2->tokAt(2); + } + + if (tok2->str() == "*" || tok2->str() == "&") + { + tok2 = tok2->next(); + } + + if (Token::Match(tok2, "%var% ,")) + { + tok2 = tok2->next(); // The ',' token + typelen--; + } + else + { + tok2 = NULL; + typelen = 0; + } + } + else + { + tok2 = NULL; + typelen = 0; + } + + + if (tok2) + { + if (tok2->str() == ",") + { + tok2->str(";"); + insertTokens(tok2, type0, typelen); + std::stack link1; + std::stack link2; + while (((typelen--) > 0) && (0 != (tok2 = tok2->next()))) + { + if (tok2->str() == "(") + link1.push(tok2); + else if (tok2->str() == ")" && !link1.empty()) + { + Token::createMutualLinks(tok2, link1.top()); + link1.pop(); + } + + else if (tok2->str() == "[") + link2.push(tok2); + else if (tok2->str() == "]" && !link2.empty()) + { + Token::createMutualLinks(tok2, link2.top()); + link2.pop(); + } + } + } + + else + { + Token *eq = tok2; + + unsigned int level = 0; + while (tok2) + { + if (Token::Match(tok2, "[{(]")) + tok2 = tok2->link(); + + else if (tok2->str() == "<") + { + if (tok2->previous()->isName() && !tok2->previous()->varId()) + ++level; + } + + else if (level > 0 && tok2->str() == ">") + --level; + + else if (level == 0 && strchr(";,", tok2->str()[0])) + { + // "type var =" => "type var; var =" + Token *VarTok = type0->tokAt((int)typelen); + while (Token::Match(VarTok, "*|const")) + VarTok = VarTok->next(); + insertTokens(eq, VarTok, 2); + eq->str(";"); + + // "= x, " => "= x; type " + if (tok2->str() == ",") + { + tok2->str(";"); + insertTokens(tok2, type0, typelen); + } + break; + } + + tok2 = tok2->next(); + } + } + } + } +} + +void Tokenizer::simplifyStdType() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // long unsigned => unsigned long + if (Token::Match(tok, "char|short|int|long|__int8|__int16|__int32|__int64 unsigned|signed")) + { + std::string temp = tok->str(); + tok->str(tok->next()->str()); + tok->next()->str(temp); + } + + if (!Token::Match(tok, "unsigned|signed|char|short|int|long|__int8|__int16|__int32|__int64")) + continue; + + // check if signed or unsigned specified + if (Token::Match(tok, "unsigned|signed")) + { + bool isUnsigned = tok->str() == "unsigned"; + + // unsigned i => unsigned int i + if (!Token::Match(tok->next(), "char|short|int|long|__int8|__int16|__int32|__int64")) + tok->str("int"); + else + tok->deleteThis(); + tok->isUnsigned(isUnsigned); + tok->isSigned(!isUnsigned); + } + + if (Token::simpleMatch(tok, "__int8")) + tok->str("char"); + else if (Token::simpleMatch(tok, "__int16")) + tok->str("short"); + else if (Token::simpleMatch(tok, "__int32")) + tok->str("int"); + else if (Token::simpleMatch(tok, "__int64")) + { + tok->str("long"); + tok->isLong(true); + } + else if (Token::simpleMatch(tok, "long")) + { + if (Token::simpleMatch(tok->next(), "long")) + { + tok->isLong(true); + tok->deleteNext(); + } + + if (Token::simpleMatch(tok->next(), "int")) + tok->deleteNext(); + else if (Token::simpleMatch(tok->next(), "double")) + { + tok->str("double"); + tok->isLong(true); + tok->deleteNext(); + } + } + else if (Token::simpleMatch(tok, "short")) + { + if (Token::simpleMatch(tok->next(), "int")) + tok->deleteNext(); + } + } +} + +void Tokenizer::simplifyIfAssign() +{ + // See also simplifyFunctionAssign + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (!Token::Match(tok->next(), "if|while ( !| (| %var% =") && + !Token::Match(tok->next(), "if|while ( !| (| %var% . %var% =")) + continue; + + // simplifying a "while" condition ? + const bool iswhile(tok->next()->str() == "while"); + + // delete the "if" + tok->deleteNext(); + + // Remember if there is a "!" or not. And delete it if there are. + const bool isNot(tok->tokAt(2)->str() == "!"); + if (isNot) + tok->next()->deleteNext(); + + // Delete parenthesis.. and remember how many there are with + // their links. + std::stack braces; + while (tok->next()->str() == "(") + { + braces.push(tok->next()->link()); + tok->deleteNext(); + } + + // Skip the "%var% = ..." + Token *tok2; + unsigned int indentlevel = 0; + for (tok2 = tok->next(); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "(") + ++indentlevel; + else if (tok2->str() == ")") + { + if (indentlevel <= 0) + break; + --indentlevel; + } + } + + // Insert "; if|while ( .." + tok2 = tok2->previous(); + if (Token::simpleMatch(tok->tokAt(2), ".")) + { + tok2->insertToken(tok->strAt(3)); + tok2->insertToken(tok->strAt(2)); + } + tok2->insertToken(tok->strAt(1)); + tok2->next()->varId(tok->tokAt(1)->varId()); + + while (! braces.empty()) + { + tok2->insertToken("("); + Token::createMutualLinks(tok2->next(), braces.top()); + braces.pop(); + } + + if (isNot) + tok2->next()->insertToken("!"); + tok2->insertToken(iswhile ? "while" : "if"); + tok2->insertToken(";"); + + // If it's a while loop.. insert the assignment in the loop + if (iswhile) + { + indentlevel = 0; + Token *tok3 = tok2; + for (tok3 = tok2; tok3; tok3 = tok3->next()) + { + if (tok3->str() == "{") + ++indentlevel; + else if (tok3->str() == "}") + { + if (indentlevel <= 1) + break; + --indentlevel; + } + } + + if (tok3 && indentlevel == 1) + { + tok3 = tok3->previous(); + std::stack braces2; + + for (tok2 = tok2->next(); tok2 && tok2 != tok; tok2 = tok2->previous()) + { + tok3->insertToken(tok2->str()); + + Token *newTok = tok3->next(); + newTok->fileIndex(tok2->fileIndex()); + newTok->linenr(tok2->linenr()); + + // link() newly tokens manually + if (Token::Match(newTok, "}|)|]")) + { + braces2.push(newTok); + } + else if (Token::Match(newTok, "{|(|[")) + { + Token::createMutualLinks(newTok, braces2.top()); + braces2.pop(); + } + } + } + } + } +} + + +void Tokenizer::simplifyVariableMultipleAssign() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "%var% = %var% = %num% ;") || + Token::Match(tok, "%var% = %var% = %var% ;")) + { + + // skip intermediate assignments + Token *tok2 = tok->previous(); + while (tok2 && + tok2->str() == "=" && + Token::Match(tok2->previous(), "%var%")) + { + tok2 = tok2->tokAt(-2); + } + + if (tok2->str() != ";") + { + continue; + } + + Token *stopAt = tok->tokAt(2); + const Token *valueTok = tok->tokAt(4); + const std::string value(valueTok->str()); + tok2 = tok2->next(); + + while (tok2 != stopAt) + { + tok2->next()->insertToken(";"); + tok2->next()->insertToken(value); + tok2 = tok2->tokAt(4); + } + } + } +} + + +void Tokenizer::simplifyIfNot() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(" || tok->str() == "||" || tok->str() == "&&") + { + tok = tok->next(); + while (tok && tok->str() == "(") + tok = tok->next(); + + if (!tok) + break; + + if (Token::Match(tok, "0|false == (") || + Token::Match(tok, "0|false == %var%")) + { + tok->deleteNext(); + tok->str("!"); + } + + else if (Token::Match(tok, "%var% == 0|false")) + { + tok->deleteNext(); + tok->next()->str(tok->str()); + tok->str("!"); + } + + else if (Token::Match(tok, "%var% .|:: %var% == 0|false")) + { + tok = tok->previous(); + tok->insertToken("!"); + tok = tok->tokAt(4); + Token::eraseTokens(tok, tok->tokAt(3)); + } + + else if (Token::Match(tok, "* %var% == 0|false")) + { + tok = tok->previous(); + tok->insertToken("!"); + tok = tok->tokAt(3); + Token::eraseTokens(tok, tok->tokAt(3)); + } + } + + else if (tok->link() && Token::Match(tok, ") == 0|false")) + { + Token::eraseTokens(tok, tok->tokAt(3)); + if (Token::Match(tok->link()->previous(), "%var%")) + { + // if( foo(x) == 0 ) + tok->link()->previous()->insertToken(tok->link()->previous()->str().c_str()); + tok->link()->previous()->previous()->str("!"); + } + else + { + // if( (x) == 0 ) + tok->link()->insertToken("("); + tok->link()->str("!"); + Token *temp = tok->link(); + Token::createMutualLinks(tok->link()->next(), tok); + temp->link(0); + } + } + } +} + + +void Tokenizer::simplifyIfNotNull() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + Token *deleteFrom = NULL; + + if (tok->str() == "(" || tok->str() == "||" || tok->str() == "&&") + { + tok = tok->next(); + + if (!tok) + break; + + if (Token::simpleMatch(tok, "0 != (") || + Token::Match(tok, "0 != %var%")) + { + deleteFrom = tok->previous(); + } + + else if (Token::Match(tok, "%var% != 0")) + { + deleteFrom = tok; + } + + else if (Token::Match(tok, "%var% .|:: %var% != 0")) + { + tok = tok->tokAt(2); + deleteFrom = tok; + } + } + + else if (tok->link() && Token::simpleMatch(tok, ") != 0")) + { + deleteFrom = tok; + } + + if (deleteFrom) + { + Token::eraseTokens(deleteFrom, deleteFrom->tokAt(3)); + tok = deleteFrom; + } + } +} + + +void Tokenizer::simplifyIfSameInnerCondition() +{ + // same inner condition + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "if ( %var% ) {")) + { + const unsigned int varid(tok->tokAt(2)->varId()); + if (!varid) + continue; + + for (Token *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{" || tok2->str() == "}") + break; + if (Token::simpleMatch(tok2, "if (")) + { + tok2 = tok2->tokAt(2); + if (Token::Match(tok2, "%varid% )", varid)) + tok2->str("true"); + else if (Token::Match(tok2, "! %varid% )", varid)) + tok2->next()->varId(varid); + break; + } + } + } + } +} + + +bool Tokenizer::simplifyLogicalOperators() +{ + bool ret = false; + + // "if (not p)" => "if (!p)" + // "if (p and q)" => "if (p && q)" + // "if (p or q)" => "if (p || q)" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "if|while ( not|compl %var%")) + { + tok->tokAt(2)->str(tok->strAt(2) == "not" ? "!" : "~"); + ret = true; + } + else if (Token::Match(tok, "&& not|compl %var%")) + { + tok->next()->str(tok->strAt(1) == "not" ? "!" : "~"); + ret = true; + } + else if (Token::Match(tok, "|| not|compl %var%")) + { + tok->next()->str(tok->strAt(1) == "not" ? "!" : "~"); + ret = true; + } + // "%var%|) and %var%|(" + else if (Token::Match(tok->previous(), "%any% %var% %any%")) + { + if (!Token::Match(tok, "and|or|bitand|bitor|xor|not_eq")) + continue; + + const Token *tok2 = tok; + while (0 != (tok2 = tok2->previous())) + { + if (tok2->str() == ")") + tok2 = tok2->link(); + else if (Token::Match(tok2, "(|;|{|}")) + break; + } + if (tok2 && Token::Match(tok2->previous(), "if|while (")) + { + if (tok->str() == "and") + tok->str("&&"); + else if (tok->str() == "or") + tok->str("||"); + else if (tok->str() == "bitand") + tok->str("&"); + else if (tok->str() == "bitor") + tok->str("|"); + else if (tok->str() == "xor") + tok->str("^"); + else if (tok->str() == "not_eq") + tok->str("!="); + ret = true; + } + } + } + return ret; +} + +// int i(0); => int i; i = 0; +// int i(0), j; => int i; i = 0; int j; +void Tokenizer::simplifyInitVar() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (!tok->isName() || (tok->previous() && !Token::Match(tok->previous(), "[;{}]"))) + continue; + + if (Token::Match(tok, "class|struct|union| %type% *| %var% ( &| %any% ) ;") || + Token::Match(tok, "%type% *| %var% ( %type% (")) + { + tok = initVar(tok); + } + else if (Token::Match(tok, "class|struct|union| %type% *| %var% ( &| %any% ) ,")) + { + Token *tok1 = tok; + while (tok1->str() != ",") + tok1 = tok1->next(); + tok1->str(";"); + Token *tok2 = tok; + if (Token::Match(tok2, "class|struct|union")) + { + tok1->insertToken(tok2->str()); + tok1 = tok1->next(); + tok2 = tok2->next(); + } + tok1->insertToken(tok2->str()); + tok1 = tok1->next(); + tok2 = tok2->next(); + if (tok2->str() == "*") + { + tok1->insertToken("*"); + } + tok = initVar(tok); + } + } +} + +static bool isOp(const Token *tok) +{ + return bool(tok && + (tok->str() == "&&" || + tok->str() == "||" || + tok->str() == "==" || + tok->str() == "!=" || + tok->str() == "<" || + tok->str() == "<=" || + tok->str() == ">" || + tok->str() == ">=" || + tok->str() == "<<" || + tok->str() == ">>" || + Token::Match(tok, "[;+-*/%&|^]"))); +} + +Token * Tokenizer::initVar(Token * tok) +{ + // call constructor of class => no simplification + if (Token::Match(tok, "class|struct|union")) + { + if (tok->tokAt(2)->str() != "*") + return tok; + + tok = tok->next(); + } + else if (!tok->isStandardType() && tok->tokAt(1)->str() != "*") + return tok; + + // goto variable name.. + tok = tok->next(); + if (tok->str() == "*") + tok = tok->next(); + + // sizeof is not a variable name.. + if (tok->str() == "sizeof") + return tok; + + // check initializer.. + if (tok->tokAt(2)->isStandardType() || tok->tokAt(2)->str() == "void") + return tok; + else if (!tok->tokAt(2)->isNumber() && !Token::Match(tok->tokAt(2), "%type% (") && tok->tokAt(2)->str() != "&" && tok->tokAt(2)->varId() == 0) + return tok; + + // insert '; var =' + tok->insertToken(";"); + tok->next()->insertToken(tok->str()); + tok->tokAt(2)->varId(tok->varId()); + tok = tok->tokAt(2); + tok->insertToken("="); + + // goto '('.. + tok = tok->tokAt(2); + + // delete ')' + tok->link()->deleteThis(); + + // delete this + tok->deleteThis(); + + return tok; +} + + +bool Tokenizer::simplifyKnownVariables() +{ + // return value for function. Set to true if any simplifications are made + bool ret = false; + + // constants.. + { + std::map constantValues; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "static| const static| %type% %var% = %any% ;")) + { + Token *tok1 = tok; + + // start of statement + if (tok != _tokens && !Token::Match(tok->previous(),"[;{}]")) + continue; + // skip "const" and "static" + while (tok->str() == "const" || tok->str() == "static") + tok = tok->next(); + // pod type + if (!tok->isStandardType()) + continue; + + const Token * const vartok = tok->next(); + const Token * const valuetok = tok->tokAt(3); + if (valuetok->isNumber() || Token::Match(valuetok, "%str% ;")) + { + constantValues[vartok->varId()] = valuetok->str(); + + // remove statement + while (tok1->str() != ";") + tok1->deleteThis(); + tok = tok1; + } + } + + else if (tok->varId() && constantValues.find(tok->varId()) != constantValues.end()) + { + tok->str(constantValues[tok->varId()]); + } + } + } + + // variable id for float/double variables + std::set floatvars; + + // auto variables.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // Search for a block of code + if (! Token::Match(tok, ") const| {")) + continue; + + // parse the block of code.. + int indentlevel = 0; + Token *tok2 = tok; + for (; tok2; tok2 = tok2->next()) + { + if (Token::Match(tok2, "[;{}] float|double %var% ;")) + { + floatvars.insert(tok2->tokAt(2)->varId()); + } + + if (tok2->str() == "{") + ++indentlevel; + + else if (tok2->str() == "}") + { + --indentlevel; + if (indentlevel <= 0) + break; + } + + else if (tok2->previous()->str() != "*" && + (Token::Match(tok2, "%var% = %num% ;") || + Token::Match(tok2, "%var% = %str% ;") || + (Token::Match(tok2, "%var% = %any% ;") && tok2->strAt(2)[0] == '\'') || + Token::Match(tok2, "%var% [ ] = %str% ;") || + Token::Match(tok2, "%var% [ %num% ] = %str% ;") || + Token::Match(tok2, "%var% = %bool% ;") || + Token::Match(tok2, "%var% = %var% ;") || + Token::Match(tok2, "%var% = & %var% ;") || + Token::Match(tok2, "%var% = & %var% [ 0 ] ;"))) + { + const unsigned int varid = tok2->varId(); + if (varid == 0) + continue; + + // skip loop variable + if (Token::Match(tok2->tokAt(-2), "(|:: %type%")) + { + const Token *tok3 = tok2->previous(); + while (Token::Match(tok3->previous(), ":: %type%")) + tok3 = tok3->tokAt(-2); + if (Token::Match(tok3->tokAt(-2), "for ( %type%")) + continue; + } + + // struct name.. + const std::string structname = Token::Match(tok2->tokAt(-3), "[;{}] %var% .") ? + std::string(tok2->strAt(-2) + " .") : + std::string(""); + + if (tok2->str() == tok2->strAt(2)) + continue; + + const Token * const valueToken = tok2->tokAt(2); + + std::string value; + unsigned int valueVarId = 0; + + Token *tok3 = NULL; + bool valueIsPointer = false; + + if (!simplifyKnownVariablesGetData(varid, &tok2, &tok3, value, valueVarId, valueIsPointer, floatvars.find(tok2->varId()) != floatvars.end())) + continue; + + ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel); + } + + else if (Token::Match(tok2, "strcpy ( %var% , %str% ) ;")) + { + const unsigned int varid(tok2->tokAt(2)->varId()); + if (varid == 0) + continue; + const std::string structname(""); + const Token * const valueToken = tok2->tokAt(4); + std::string value(valueToken->str()); + const unsigned int valueVarId(0); + const bool valueIsPointer(false); + Token *tok3 = tok2; + for (int i = 0; i < 6; ++i) + tok3 = tok3->next(); + ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel); + } + } + + if (tok2) + tok = tok2->previous(); + } + + return ret; +} + +bool Tokenizer::simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2, Token **_tok3, std::string &value, unsigned int &valueVarId, bool &valueIsPointer, bool floatvar) +{ + Token *tok2 = *_tok2; + Token *tok3 = *_tok3; + + if (Token::Match(tok2->tokAt(-2), "for ( %varid% = %num% ; %varid% <|<= %num% ; ++| %varid% ++| ) {", varid)) + { + // is there a "break" in the for loop? + bool hasbreak = false; + unsigned int indentlevel4 = 0; // indentlevel for tok4 + for (const Token *tok4 = tok2->previous()->link(); tok4; tok4 = tok4->next()) + { + if (tok4->str() == "{") + ++indentlevel4; + else if (tok4->str() == "}") + { + if (indentlevel4 <= 1) + break; + --indentlevel4; + } + else if (tok4->str() == "break") + { + hasbreak = true; + break; + } + } + if (hasbreak) + return false; + + // no break => the value of the counter value is known after the for loop.. + const std::string compareop = tok2->strAt(5); + if (compareop == "<") + { + value = tok2->strAt(6); + valueVarId = tok2->tokAt(6)->varId(); + } + else + value = MathLib::toString(MathLib::toLongNumber(tok2->strAt(6)) + 1); + + // Skip for-body.. + tok3 = tok2->previous()->link()->next()->link()->next(); + } + else + { + value = tok2->strAt(2); + valueVarId = tok2->tokAt(2)->varId(); + if (Token::simpleMatch(tok2->next(), "[")) + { + value = tok2->next()->link()->strAt(2); + valueVarId = 0; + } + else if (value == "&") + { + value = tok2->strAt(3); + valueVarId = tok2->tokAt(3)->varId(); + + // *ptr = &var; *ptr = 5; + // equals + // var = 5; not *var = 5; + if (tok2->strAt(4) == ";") + valueIsPointer = true; + } + + // float value should contain a "." + else if (tok2->tokAt(2)->isNumber() && + floatvar && + value.find(".") == std::string::npos) + { + value += ".0"; + } + + if (Token::simpleMatch(tok2->next(), "= &")) + tok2 = tok2->tokAt(3); + + tok3 = tok2->next(); + } + *_tok2 = tok2; + *_tok3 = tok3; + return true; +} + +bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel) +{ + const bool pointeralias(valueToken->isName() || Token::Match(valueToken, "& %var% [")); + + bool ret = false; + + Token* bailOutFromLoop = 0; + int indentlevel3 = indentlevel; + bool ret3 = false; + for (; tok3; tok3 = tok3->next()) + { + if (tok3->str() == "{") + { + ++indentlevel3; + } + else if (tok3->str() == "}") + { + --indentlevel3; + if (indentlevel3 < indentlevel) + { + if (Token::Match((*tok2)->tokAt(-7), "%type% * %var% ; %var% = & %var% ;") && + (*tok2)->tokAt(-5)->str() == (*tok2)->tokAt(-3)->str()) + { + (*tok2) = (*tok2)->tokAt(-4); + Token::eraseTokens((*tok2), (*tok2)->tokAt(5)); + } + break; + } + } + + // Stop if label is found + if (Token::Match(tok3, "; %type% : ;")) + break; + + // Stop if return or break is found .. + if (tok3->str() == "break") + break; + if ((indentlevel3 > 1 || !Token::simpleMatch(Token::findmatch(tok3,";"), "; }")) && tok3->str() == "return") + ret3 = true; + if (ret3 && tok3->str() == ";") + break; + + if (pointeralias && Token::Match(tok3, ("!!= " + value).c_str())) + break; + + // Stop if do is found + if (tok3->str() == "do") + break; + + // Stop if something like 'while (--var)' is found + if (tok3->str() == "for" || tok3->str() == "while" || tok3->str() == "do") + { + const Token *endpar = tok3->next()->link(); + if (Token::simpleMatch(endpar, ") {")) + endpar = endpar->next()->link(); + bool bailout = false; + for (const Token *tok4 = tok3; tok4 && tok4 != endpar; tok4 = tok4->next()) + { + if (Token::Match(tok4, "++|-- %varid%", varid) || + Token::Match(tok4, "%varid% ++|--|=", varid)) + { + bailout = true; + break; + } + } + if (bailout) + break; + } + + if (bailOutFromLoop) + { + // This could be a loop, skip it, but only if it doesn't contain + // the variable we are checking for. If it contains the variable + // we will bail out. + if (tok3->varId() == varid) + { + // Continue + //tok2 = bailOutFromLoop; + break; + } + else if (tok3 == bailOutFromLoop) + { + // We have skipped the loop + bailOutFromLoop = 0; + continue; + } + + continue; + } + else if (tok3->str() == "{" && tok3->previous()->str() == ")") + { + // There is a possible loop after the assignment. Try to skip it. + if (tok3->previous()->link() && + !Token::simpleMatch(tok3->previous()->link()->previous(), "if")) + bailOutFromLoop = tok3->link(); + continue; + } + + // Variable used in realloc (see Ticket #1649) + if (Token::Match(tok3, "%var% = realloc ( %var% ,") && + tok3->varId() == varid && + tok3->tokAt(4)->varId() == varid) + { + tok3->tokAt(4)->str(value); + ret = true; + } + + // condition "(|&&|%OROR% %varid% )|&&|%OROR% + if (!Token::Match(tok3->previous(), "( %var% )") && + (Token::Match(tok3->previous(), "&&|(") || tok3->strAt(-1) == "||") && + tok3->varId() == varid && + (Token::Match(tok3->next(), "&&|)") || tok3->strAt(1) == "||")) + { + tok3->str(value); + ret = true; + } + + // Variable is used somehow in a non-defined pattern => bail out + if (tok3->varId() == varid) + { + // This is a really generic bailout so let's try to avoid this. + // There might be lots of false negatives. + if (_settings->debugwarnings) + { + // FIXME: Fix all the debug warnings for values and then + // remove this bailout + if (pointeralias) + break; + + // suppress debug-warning when calling member function + if (Token::Match(tok3->next(), ". %var% (")) + break; + + // suppress debug-warning when assignment + if (Token::simpleMatch(tok3->next(), "=")) + break; + + // taking address of variable.. + if (Token::Match(tok3->tokAt(-2), "return|= & %var% ;")) + break; + + // parameter in function call.. + if (Token::Match(tok3->tokAt(-2), "%var% ( %var% ,|)") || + Token::Match(tok3->previous(), ", %var% ,|)")) + break; + + // conditional increment + if (Token::Match(tok3->tokAt(-3), ") { ++|--") || + Token::Match(tok3->tokAt(-2), ") { %var% ++|--")) + break; + + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok3->linenr(); + loc.setfile(file(tok3)); + locationList.push_back(loc); + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::debug, + "simplifyKnownVariables: bailing out (variable="+tok3->str()+", value="+value+")", + "debug"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); + } + + break; + } + + // Using the variable in condition.. + if (Token::Match(tok3->previous(), ("if ( " + structname + " %varid% ==|!=|<|<=|>|>=|)").c_str(), varid) || + Token::Match(tok3, ("( " + structname + " %varid% ==|!=|<|<=|>|>=").c_str(), varid) || + Token::Match(tok3, ("!|==|!=|<|<=|>|>= " + structname + " %varid% ==|!=|<|<=|>|>=|)|;").c_str(), varid) || + Token::Match(tok3->previous(), "strlen|free ( %varid% )", varid)) + { + if (value[0] == '\"' && tok3->strAt(-1) != "strlen") + { + // bail out if value is a string unless if it's just given + // as parameter to strlen + break; + } + if (!structname.empty()) + { + tok3->deleteNext(); + tok3->deleteNext(); + } + if (Token::Match(valueToken, "& %var% ;")) + { + tok3->insertToken("&"); + tok3 = tok3->next(); + } + tok3 = tok3->next(); + tok3->str(value); + tok3->varId(valueVarId); + ret = true; + } + + // Delete pointer alias + if (pointeralias && tok3->str() == "delete" && + (Token::Match(tok3, "delete %varid% ;", varid) || + Token::Match(tok3, "delete [ ] %varid%", varid))) + { + tok3 = (tok3->strAt(1) == "[") ? tok3->tokAt(3) : tok3->next(); + tok3->str(value); + tok3->varId(valueVarId); + ret = true; + } + + // Variable is used in function call.. + if (Token::Match(tok3, ("%var% ( " + structname + " %varid% ,").c_str(), varid)) + { + const char * const functionName[] = + { + "memcmp","memcpy","memmove","memset", + "strcmp","strcpy","strncpy","strdup" + }; + for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) + { + if (tok3->str() == functionName[i]) + { + Token *par1 = tok3->next()->next(); + if (!structname.empty()) + { + par1->deleteThis(); + par1->deleteThis(); + } + par1->str(value); + par1->varId(valueVarId); + break; + } + } + } + + // Variable is used as 2nd parameter in function call.. + if (Token::Match(tok3, ("%var% ( %any% , " + structname + " %varid% ,|)").c_str(), varid)) + { + const char * const functionName[] = + { + "memcmp","memcpy","memmove", + "strcmp","strcpy","strncmp","strncpy" + }; + for (unsigned int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) + { + if (tok3->str() == functionName[i]) + { + Token *par = tok3->tokAt(4); + if (!structname.empty()) + { + par->deleteThis(); + par->deleteThis(); + } + par->str(value); + par->varId(valueVarId); + break; + } + } + } + + // array usage + if (Token::Match(tok3, ("[(,] " + structname + " %varid% [+-*/[]").c_str(), varid)) + { + if (!structname.empty()) + { + tok3->deleteNext(); + tok3->deleteNext(); + } + tok3 = tok3->next(); + tok3->str(value); + tok3->varId(valueVarId); + ret = true; + } + + // Variable is used in calculation.. + if (((tok3->previous()->varId() > 0) && Token::Match(tok3, ("& " + structname + " %varid%").c_str(), varid)) || + Token::Match(tok3, ("[=+-*/%^|[] " + structname + " %varid% [=?+-*/%^|;])]").c_str(), varid) || + Token::Match(tok3, ("[(=+-*/%^|[] " + structname + " %varid% <<|>>").c_str(), varid) || + Token::Match(tok3, ("<<|>> " + structname + " %varid% [+-*/%^|;])]").c_str(), varid) || + Token::Match(tok3->previous(), ("[=+-*/%^|[] ( " + structname + " %varid%").c_str(), varid)) + { + if (value[0] == '\"') + break; + if (!structname.empty()) + { + tok3->deleteNext(); + tok3->deleteNext(); + } + tok3 = tok3->next(); + tok3->str(value); + tok3->varId(valueVarId); + if (tok3->previous()->str() == "*" && valueIsPointer) + { + tok3 = tok3->previous(); + tok3->deleteThis(); + } + ret = true; + } + + if (Token::simpleMatch(tok3, "= {")) + { + unsigned int indentlevel4 = 0; + for (const Token *tok4 = tok3; tok4; tok4 = tok4->next()) + { + if (tok4->str() == "{") + ++indentlevel4; + else if (tok4->str() == "}") + { + if (indentlevel4 <= 1) + break; + --indentlevel4; + } + if (Token::Match(tok4, "{|, %varid% ,|}", varid)) + { + tok4->next()->str(value); + tok4->next()->varId(valueVarId); + ret = true; + } + } + } + + // Using the variable in for-condition.. + if (Token::simpleMatch(tok3, "for (")) + { + for (Token *tok4 = tok3->tokAt(2); tok4; tok4 = tok4->next()) + { + if (tok4->str() == "(" || tok4->str() == ")") + break; + + // Replace variable used in condition.. + if (Token::Match(tok4, "; %var% <|<=|!= %var% ; ++| %var% ++| )")) + { + const Token *inctok = tok4->tokAt(5); + if (inctok->str() == "++") + inctok = inctok->next(); + if (inctok->varId() == varid) + break; + + if (tok4->next()->varId() == varid) + { + tok4->next()->str(value); + tok4->next()->varId(valueVarId); + ret = true; + } + if (tok4->tokAt(3)->varId() == varid) + { + tok4->tokAt(3)->str(value); + tok4->tokAt(3)->varId(valueVarId); + ret = true; + } + } + } + } + + if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "%varid% ++|--", varid) && MathLib::isInt(value)) + { + const std::string op(tok3->strAt(2)); + if (Token::Match(tok3, "[{};] %any% %any% ;")) + { + Token::eraseTokens(tok3, tok3->tokAt(3)); + } + else + { + tok3 = tok3->next(); + tok3->str(value); + tok3->varId(valueVarId); + tok3->deleteNext(); + } + incdec(value, op); + if (!Token::simpleMatch((*tok2)->tokAt(-2), "for (")) + { + (*tok2)->tokAt(2)->str(value); + (*tok2)->tokAt(2)->varId(valueVarId); + } + ret = true; + } + + if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "++|-- %varid%", varid) && MathLib::isInt(value) && + !Token::Match(tok3->tokAt(3), "[.[]")) + { + incdec(value, tok3->strAt(1)); + (*tok2)->tokAt(2)->str(value); + (*tok2)->tokAt(2)->varId(valueVarId); + if (Token::Match(tok3, "[;{}] %any% %any% ;")) + { + Token::eraseTokens(tok3, tok3->tokAt(3)); + } + else + { + tok3->deleteNext(); + tok3->next()->str(value); + tok3->next()->varId(valueVarId); + } + tok3 = tok3->next(); + ret = true; + } + + // return variable.. + if (Token::Match(tok3, "return %varid% %any%", varid) && + isOp(tok3->tokAt(2)) && + value[0] != '\"') + { + tok3->next()->str(value); + tok3->next()->varId(valueVarId); + } + + else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid) && value[0] != '\"') + { + tok3->deleteNext(); + tok3->next()->str(value); + tok3->next()->varId(valueVarId); + } + } + return ret; +} + + +void Tokenizer::elseif() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (!Token::simpleMatch(tok, "else if")) + continue; + int indent = 0; + for (Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next()) + { + if (Token::Match(tok2, "(|{")) + ++indent; + else if (Token::Match(tok2, ")|}")) + --indent; + + if (indent == 0 && Token::Match(tok2, "}|;")) + { + if (tok2->next() && tok2->next()->str() != "else") + { + tok->insertToken("{"); + tok2->insertToken("}"); + Token::createMutualLinks(tok->next(), tok2->next()); + break; + } + } + } + } +} + + +bool Tokenizer::simplifyRedundantParanthesis() +{ + bool ret = false; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "(") + continue; + + // !!operator = ( x ) ; + if (tok->strAt(-2) != "operator" && + tok->strAt(-1) == "=" && + tok->strAt(1) != "{" && + Token::simpleMatch(tok->link(), ") ;")) + { + tok->link()->deleteThis(); + tok->deleteThis(); + continue; + } + + while (Token::simpleMatch(tok, "( (") && + tok->link()->previous() == tok->next()->link()) + { + // We have "(( *something* ))", remove the inner + // parenthesis + tok->deleteNext(); + tok->link()->tokAt(-2)->deleteNext(); + ret = true; + } + + while (Token::Match(tok->previous(), "[,;{}(] ( %var% (") && + tok->link()->previous() == tok->tokAt(2)->link()) + { + // We have "( func ( *something* ))", remove the outer + // parenthesis + tok->link()->deleteThis(); + tok->deleteThis(); + ret = true; + } + + while (Token::Match(tok->previous(), "[;{] ( delete %var% ) ;")) + { + // We have "( delete var )", remove the outer + // parenthesis + tok->tokAt(3)->deleteThis(); + tok->deleteThis(); + ret = true; + } + + while (Token::Match(tok->previous(), "[;{] ( delete [ ] %var% ) ;")) + { + // We have "( delete [] var )", remove the outer + // parenthesis + tok->tokAt(5)->deleteThis(); + tok->deleteThis(); + ret = true; + } + + if (!Token::simpleMatch(tok->tokAt(-2), "operator delete") && + Token::Match(tok->previous(), "delete|; (") && + (tok->strAt(-1) != "delete" || tok->next()->varId() > 0) && + Token::Match(tok->link(), ") ;|,")) + { + tok->link()->deleteThis(); + tok->deleteThis(); + ret = true; + } + + if (Token::Match(tok->previous(), "[(!*;{}] ( %var% )") && tok->next()->varId() != 0) + { + // We have "( var )", remove the parenthesis + tok->deleteThis(); + tok->deleteNext(); + ret = true; + continue; + } + + if (Token::Match(tok->previous(), "[(!] ( %var% . %var% )")) + { + // We have "( var . var )", remove the parenthesis + tok->deleteThis(); + tok = tok->tokAt(2); + tok->deleteNext(); + ret = true; + continue; + } + + if (Token::Match(tok, "( ( %bool% )") || + Token::Match(tok, "( ( %num% )")) + { + tok->tokAt(2)->deleteNext(); + tok->deleteNext(); + ret = true; + } + } + return ret; +} + +void Tokenizer::simplifyReference() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // starting executable scope.. + if (Token::Match(tok, ") const| {")) + { + // replace references in this scope.. + if (tok->next()->str() != "{") + tok = tok->next(); + Token * const end = tok->next()->link(); + for (Token *tok2 = tok; tok2 && tok2 != end; tok2 = tok2->next()) + { + // found a reference.. + if (Token::Match(tok2, "[;{}] %type% & %var% (|= %var% )| ;")) + { + const unsigned int ref_id = tok2->tokAt(3)->varId(); + if (!ref_id) + continue; + + // replace reference in the code.. + for (Token *tok3 = tok2->tokAt(7); tok3 && tok3 != end; tok3 = tok3->next()) + { + if (tok3->varId() == ref_id) + { + tok3->str(tok2->strAt(5)); + tok3->varId(tok2->tokAt(5)->varId()); + } + } + + Token::eraseTokens(tok2, tok2->tokAt(7)); + } + } + } + } +} + +bool Tokenizer::simplifyCalculations() +{ + bool ret = false; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // Remove parentheses around variable.. + // keep parentheses here: dynamic_cast(p); + // keep parentheses here: A operator * (int); + // keep parentheses here: int ( * ( * f ) ( ... ) ) (int) ; + // keep parentheses here: int ( * * ( * compilerHookVector ) (void) ) ( ) ; + // keep parentheses here: operator new [] (size_t); + // keep parentheses here: Functor()(a ... ) + // keep parentheses here: ) ( var ) ; + if (Token::Match(tok->next(), "( %var% ) [;),+-*/><]]") && + !tok->isName() && + tok->str() != ">" && + tok->str() != "]" && + !Token::simpleMatch(tok->previous(), "operator") && + !Token::simpleMatch(tok->previous(), "* )") && + !Token::simpleMatch(tok->previous(), ") )") && + !Token::Match(tok->tokAt(-2), "* %var% )") && + !Token::Match(tok->tokAt(-2), "%type% ( ) ( %var%") && + !Token::Match(tok, ") ( %var% ) ;") + ) + { + tok->deleteNext(); + tok = tok->next(); + tok->deleteNext(); + ret = true; + } + + if (tok->isNumber()) + { + if (tok->str() == "0") + { + if (Token::Match(tok->previous(), "[+-] 0")) + { + tok = tok->previous(); + if (Token::Match(tok->tokAt(-4), "[;{}] %var% = %var% [+-] 0 ;") && + tok->strAt(-3) == tok->strAt(-1)) + { + tok = tok->previous()->previous()->previous(); + tok->deleteThis(); + tok->deleteThis(); + tok->deleteThis(); + } + tok->deleteThis(); + tok->deleteThis(); + ret = true; + } + else if (Token::Match(tok->previous(), "[=([,] 0 +")) + { + tok->deleteThis(); + tok->deleteThis(); + ret = true; + } + else if (Token::Match(tok->previous(), "[=[(,] 0 * %any% [+-*/,]);]")) + { + tok->deleteNext(); + if (tok->next()->str() == "(") + Token::eraseTokens(tok, tok->next()->link()); + tok->deleteNext(); + ret = true; + } + } + + if (Token::simpleMatch(tok->previous(), "* 1") || Token::simpleMatch(tok, "1 *")) + { + if (Token::simpleMatch(tok->previous(), "*")) + tok = tok->previous(); + tok->deleteThis(); + tok->deleteThis(); + ret = true; + } + + // Remove parentheses around number.. + if (Token::Match(tok->tokAt(-2), "%any% ( %num% )") && !tok->tokAt(-2)->isName() && tok->strAt(-2) != ">") + { + tok = tok->previous(); + tok->deleteThis(); + tok->deleteNext(); + ret = true; + } + + if (Token::simpleMatch(tok->previous(), "( 0 ||") || + Token::simpleMatch(tok->previous(), "|| 0 )") || + Token::simpleMatch(tok->previous(), "( 1 &&") || + Token::simpleMatch(tok->previous(), "&& 1 )")) + { + if (!Token::simpleMatch(tok->previous(), "(")) + tok = tok->previous(); + tok->deleteThis(); + tok->deleteThis(); + } + + if (Token::Match(tok, "%num% ==|!=|<=|>=|<|> %num%") && + MathLib::isInt(tok->str()) && + MathLib::isInt(tok->tokAt(2)->str())) + { + const std::string prev(tok->previous() ? tok->strAt(-1).c_str() : ""); + const std::string after(tok->tokAt(3) ? tok->strAt(3).c_str() : ""); + if ((prev == "(" || prev == "&&" || prev == "||") && (after == ")" || after == "&&" || after == "||")) + { + const MathLib::bigint op1(MathLib::toLongNumber(tok->str())); + const std::string &cmp(tok->next()->str()); + const MathLib::bigint op2(MathLib::toLongNumber(tok->tokAt(2)->str())); + + std::string result; + + if (cmp == "==") + result = (op1 == op2) ? "1" : "0"; + else if (cmp == "!=") + result = (op1 != op2) ? "1" : "0"; + else if (cmp == "<=") + result = (op1 <= op2) ? "1" : "0"; + else if (cmp == ">=") + result = (op1 >= op2) ? "1" : "0"; + else if (cmp == "<") + result = (op1 < op2) ? "1" : "0"; + else if (cmp == ">") + result = (op1 > op2) ? "1" : "0"; + + tok->str(result); + tok->deleteNext(); + tok->deleteNext(); + } + } + + if (Token::Match(tok->previous(), "[([,=] %num% <<|>> %num%")) + { + const MathLib::bigint op1(MathLib::toLongNumber(tok->str())); + const MathLib::bigint op2(MathLib::toLongNumber(tok->tokAt(2)->str())); + MathLib::bigint result; + + if (tok->next()->str() == "<<") + result = op1 << op2; + else + result = op1 >> op2; + + std::ostringstream ss; + ss << result; + + tok->str(ss.str()); + tok->deleteNext(); + tok->deleteNext(); + } + } + + else if (tok->next() && tok->next()->isNumber()) + { + + // (1-2) + while (Token::Match(tok, "[[,(=<>+-*|&^] %num% [+-*/] %num% [],);=<>+-*/|&^]") || + Token::Match(tok, "<< %num% [+-*/] %num% [],);=<>+-*/|&^]") || + Token::Match(tok, "[[,(=<>+-*|&^] %num% [+-*/] %num% <<|>>") || + Token::Match(tok, "<< %num% [+-*/] %num% <<") || + Token::Match(tok, "[(,[] %num% [|&^] %num% [];,);]")) + { + tok = tok->next(); + + // Don't simplify "%num% / 0" + if (Token::simpleMatch(tok->next(), "/ 0")) + continue; + + // & | ^ + if (Token::Match(tok->next(), "[&|^]")) + { + std::string result; + const std::string first(tok->str()); + const std::string second(tok->strAt(2)); + const char op = tok->next()->str()[0]; + if (op == '&') + result = MathLib::toString(MathLib::toLongNumber(first) & MathLib::toLongNumber(second)); + else if (op == '|') + result = MathLib::toString(MathLib::toLongNumber(first) | MathLib::toLongNumber(second)); + else if (op == '^') + result = MathLib::toString(MathLib::toLongNumber(first) ^ MathLib::toLongNumber(second)); + + if (!result.empty()) + { + ret = true; + tok->str(result); + Token::eraseTokens(tok, tok->tokAt(3)); + continue; + } + } + + // + and - are calculated after * and / + if (Token::Match(tok->next(), "[+-/]")) + { + if (tok->previous()->str() == "*") + continue; + if (Token::Match(tok->tokAt(3), "[*/]")) + continue; + } + + if (Token::Match(tok->previous(), "- %num% - %num%")) + tok->str(MathLib::add(tok->str(), tok->tokAt(2)->str())); + else if (Token::Match(tok->previous(), "- %num% + %num%")) + tok->str(MathLib::subtract(tok->str(), tok->tokAt(2)->str())); + else + tok->str(MathLib::calculate(tok->str(), tok->tokAt(2)->str(), tok->strAt(1)[0], this)); + + Token::eraseTokens(tok, tok->tokAt(3)); + + // evaluate "2 + 2 - 2 - 2" + // as (((2 + 2) - 2) - 2) = 0 + // instead of ((2 + 2) - (2 - 2)) = 4 + if (Token::Match(tok->next(), "[+-*/]")) + { + tok = tok->previous(); + continue; + } + + ret = true; + } + } + } + return ret; +} + + + + +void Tokenizer::simplifyGoto() +{ + std::list gotos; + unsigned int indentlevel = 0; + Token *beginfunction = 0; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "{") + { + if (beginfunction == 0 && indentlevel == 0 && tok->link()) + tok = tok->link(); + else + ++indentlevel; + } + + else if (tok->str() == "}") + { + if (indentlevel == 0) + break; // break out - it seems the code is wrong + --indentlevel; + if (indentlevel == 0) + { + gotos.clear(); + beginfunction = 0; + } + } + + else if (indentlevel > 0 && tok->str() == "(") + { + tok = tok->link(); + } + + else if (indentlevel == 0 && Token::Match(tok, ") const| {")) + { + gotos.clear(); + beginfunction = tok; + } + + else if (Token::Match(tok, "goto %var% ;")) + gotos.push_back(tok); + + else if (indentlevel == 1 && Token::Match(tok->previous(), "[};] %var% :")) + { + // Is this label at the end.. + bool end = false; + int level = 0; + for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "}") + { + --level; + if (level < 0) + { + end = true; + break; + } + } + else if (tok2->str() == "{") + { + ++level; + } + + if (Token::Match(tok2, "%var% :") || tok2->str() == "goto") + { + break; + } + } + if (!end) + continue; + + const std::string name(tok->str()); + + tok->deleteThis(); + tok->deleteThis(); + if (Token::Match(tok, "; %any%")) + tok->deleteThis(); + + // This label is at the end of the function.. replace all matching goto statements.. + for (std::list::iterator it = gotos.begin(); it != gotos.end(); ++it) + { + Token *token = *it; + if (token->next()->str() == name) + { + // Delete the "goto name;" + token = token->previous(); + token->deleteNext(); + token->deleteNext(); + token->deleteNext(); + + // Insert the statements.. + bool ret = false; // is there return + bool ret2 = false; // is there return in indentlevel 0 + std::list links; + std::list links2; + std::list links3; + int lev = 0; + for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "}") + { + --lev; + if (lev < 0) + break; + } + if (tok2->str() == "{") + { + ++lev; + } + else if (tok2->str() == "return") + { + ret = true; + if (indentlevel == 1 && lev == 0) + ret2 = true; + } + token->insertToken(tok2->str().c_str()); + token = token->next(); + token->linenr(tok2->linenr()); + token->varId(tok2->varId()); + if (ret2 && tok2->str() == ";") + { + break; + } + if (token->str() == "(") + { + links.push_back(token); + } + else if (token->str() == ")") + { + if (links.empty()) + { + // This should never happen at this point + syntaxError(token, ')'); + return; + } + + Token::createMutualLinks(links.back(), token); + links.pop_back(); + } + else if (token->str() == "{") + { + links2.push_back(token); + } + else if (token->str() == "}") + { + if (links2.empty()) + { + // This should never happen at this point + syntaxError(token, '}'); + return; + } + + Token::createMutualLinks(links2.back(), token); + links2.pop_back(); + } + else if (token->str() == "[") + { + links3.push_back(token); + } + else if (token->str() == "]") + { + if (links3.empty()) + { + // This should never happen at this point + syntaxError(token, ']'); + return; + } + + Token::createMutualLinks(links3.back(), token); + links3.pop_back(); + } + } + + if (!ret) + { + token->insertToken("return"); + token = token->next(); + token->insertToken(";"); + token = token->next(); + } + } + } + + gotos.clear(); + tok = beginfunction; + indentlevel = 0; + continue; + } + } +} + +void Tokenizer::simplifyNestedStrcat() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (! Token::Match(tok, "[;{}] strcat ( strcat (")) + { + continue; + } + + // find inner strcat call + Token *tok2 = tok->tokAt(3); + while (Token::simpleMatch(tok2, "strcat ( strcat")) + { + tok2 = tok2->tokAt(2); + } + + // If we have this code: + // strcat(strcat(dst, foo), bar); + // We move this part of code before all strcat() calls: strcat(dst, foo) + // And place "dst" token where the code was. + Token *prevTok = tok2->previous(); + + // Move tokens to new place + Token::move(tok2, tok2->next()->link(), tok); + tok = tok2->next()->link(); + + // Insert the "dst" token + prevTok->insertToken(tok2->strAt(2)); + + // Insert semicolon after the moved strcat() + tok->insertToken(";"); + } + +} + +void Tokenizer::duplicateEnumError(const Token * tok1, const Token * tok2, const std::string & type) +{ + if (!(_settings->_checkCodingStyle)) + return; + + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok1->linenr(); + loc.setfile(file(tok1)); + locationList.push_back(loc); + loc.line = tok2->linenr(); + loc.setfile(file(tok2)); + locationList.push_back(loc); + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::style, + std::string(type + " '" + tok2->str() + + "' hides enumerator with same name"), + "variableHidingEnum"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); +} + +// Check if this statement is a duplicate definition. A duplicate +// definition will hide the enumerator within it's scope so just +// skip the entire scope of the duplicate. +bool Tokenizer::duplicateDefinition(Token ** tokPtr, const Token * name) +{ + // check for an end of definition + const Token * tok = *tokPtr; + if (tok && Token::Match(tok->next(), ";|,|[|=|)|>")) + { + const Token * end = tok->next(); + + if (end->str() == "[") + { + end = end->link()->next(); + } + else if (end->str() == ",") + { + // check for function argument + if (Token::Match(tok->previous(), "(|,")) + return false; + + // find end of definition + int level = 0; + while (end && end->next() && (!Token::Match(end->next(), ";|)|>") || + (end->next()->str() == ")" && level == 0))) + { + if (end->next()->str() == "(") + level++; + else if (end->next()->str() == ")") + level--; + + end = end->next(); + } + } + else if (end->str() == ")") + { + // check of function argument + if (tok->previous()->str() == ",") + return false; + } + + if (end) + { + if (Token::simpleMatch(end, ") {")) // function parameter ? + { + // look backwards + if (tok->previous()->str() == "enum" || + (Token::Match(tok->previous(), "%type%") && + tok->previous()->str() != "return")) + { + duplicateEnumError(*tokPtr, name, "Function parameter"); + // duplicate definition so skip entire function + *tokPtr = end->next()->link(); + return true; + } + } + else if (end->str() == ">") // template parameter ? + { + // look backwards + if (tok->previous()->str() == "enum" || + (Token::Match(tok->previous(), "%type%") && + tok->previous()->str() != "return")) + { + // duplicate definition so skip entire template + while (end && end->str() != "{") + end = end->next(); + if (end) + { + duplicateEnumError(*tokPtr, name, "Template parameter"); + *tokPtr = end->link(); + return true; + } + } + } + else + { + // look backwards + if (Token::Match(tok->previous(), "enum|,") || + (Token::Match(tok->previous(), "%type%") && + tok->previous()->str() != "return")) + { + duplicateEnumError(*tokPtr, name, "Variable"); + return true; + } + } + } + } + return false; +} + +void Tokenizer::simplifyEnum() +{ + // Don't simplify enums in java files + if (isJavaOrCSharp()) + return; + + std::string className; + int classLevel = 0; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "class|struct|namespace %any%") && + (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) + { + className = tok->next()->str(); + classLevel = 0; + continue; + } + else if (tok->str() == "}") + { + --classLevel; + if (classLevel < 0) + className = ""; + + continue; + } + else if (tok->str() == "{") + { + ++classLevel; + continue; + } + else if (Token::Match(tok, "enum class|struct| {|:") || + Token::Match(tok, "enum class|struct| %type% {|:|;")) + { + Token *tok1; + Token *start = tok; + Token *end; + Token *enumType = 0; + Token *typeTokenStart = 0; + Token *typeTokenEnd = 0; + + // check for C++0x enum class + if (Token::Match(tok->next(), "class|struct")) + tok->deleteNext(); + + // check for C++0x typed enumeration + if (Token::Match(tok->next(), "%type% :") || tok->next()->str() == ":") + { + int offset = 2; + if (tok->next()->str() != ":") + offset = 3; + + // check for forward declaration + const Token *temp = tok->tokAt(offset); + while (!Token::Match(temp, "{|;")) + temp = temp->next(); + if (temp->str() == ";") + { + /** @todo start substitution check at forward declaration */ + // delete forward declaration + tok->deleteThis(); + tok->deleteThis(); + tok->deleteThis(); + tok->deleteThis(); + continue; + } + + typeTokenStart = tok->tokAt(offset); + typeTokenEnd = typeTokenStart; + while (Token::Match(typeTokenEnd->next(), "signed|unsigned|char|short|int|long")) + typeTokenEnd = typeTokenEnd->next(); + + if (!Token::Match(typeTokenEnd->next(), "{|;")) + { + syntaxError(typeTokenEnd->next()); + return; + } + } + + // check for forward declaration + else if (Token::Match(tok->next(), "%type% ;")) + { + /** @todo start substitution check at forward declaration */ + // delete forward declaration + tok->deleteThis(); + tok->deleteThis(); + continue; + } + + if (tok->tokAt(1)->str() == "{") + tok1 = tok->tokAt(2); + else if (tok->tokAt(1)->str() == ":") + tok1 = typeTokenEnd->tokAt(2); + else if (tok->tokAt(2)->str() == "{") + { + enumType = tok->tokAt(1); + tok1 = tok->tokAt(3); + } + else + { + enumType = tok->tokAt(1); + tok1 = typeTokenEnd->tokAt(2); + } + + end = tok1->tokAt(-1)->link(); + + MathLib::bigint lastValue = -1; + Token * lastEnumValueStart = 0; + Token * lastEnumValueEnd = 0; + + // iterate over all enumerators between { and } + // Give each enumerator the const value specified or if not specified, 1 + the + // previous value or 0 if it is the first one. + for (; tok1 && tok1 != end; tok1 = tok1->next()) + { + Token * enumName = 0; + Token * enumValue = 0; + Token * enumValueStart = 0; + Token * enumValueEnd = 0; + + if (tok1->str() == "(") + { + tok1 = tok1->link(); + continue; + } + + if (Token::Match(tok1->previous(), ",|{ %type% ,|}")) + { + // no value specified + enumName = tok1; + lastValue++; + tok1->insertToken("="); + tok1 = tok1->next(); + + if (lastEnumValueStart && lastEnumValueEnd) + { + // previous value was an expression + Token *valueStart = tok1; + tok1 = copyTokens(tok1, lastEnumValueStart, lastEnumValueEnd); + + // value is previous expression + 1 + tok1->insertToken("+"); + tok1 = tok1->next(); + tok1->insertToken(MathLib::toString(lastValue)); + enumValue = 0; + enumValueStart = valueStart->next(); + enumValueEnd = tok1->next(); + } + else + { + // value is previous numeric value + 1 + tok1->insertToken(MathLib::toString(lastValue)); + enumValue = tok1->next(); + } + } + else if (Token::Match(tok1->previous(), ",|{ %type% = %num% ,|}")) + { + // value is specified numeric value + enumName = tok1; + lastValue = MathLib::toLongNumber(tok1->strAt(2)); + enumValue = tok1->tokAt(2); + lastEnumValueStart = 0; + lastEnumValueEnd = 0; + } + else if (Token::Match(tok1->previous(), ",|{ %type% =")) + { + // value is specified expression + enumName = tok1; + lastValue = 0; + tok1 = tok1->tokAt(2); + enumValueStart = tok1; + enumValueEnd = tok1; + int level = 0; + if (enumValueEnd->str() == "(" || + enumValueEnd->str() == "[" || + enumValueEnd->str() == "{") + level++; + while (enumValueEnd->next() && + (!Token::Match(enumValueEnd->next(), "}|,") || level)) + { + if (enumValueEnd->next()->str() == "(" || + enumValueEnd->next()->str() == "[" || + enumValueEnd->next()->str() == "{") + level++; + else if (enumValueEnd->next()->str() == ")" || + enumValueEnd->next()->str() == "]" || + enumValueEnd->next()->str() == "}") + level--; + + enumValueEnd = enumValueEnd->next(); + } + // remember this expression in case it needs to be incremented + lastEnumValueStart = enumValueStart; + lastEnumValueEnd = enumValueEnd; + // skip over expression + tok1 = enumValueEnd; + } + + // find all uses of this enumerator and substitute it's value for it's name + if (enumName && (enumValue || (enumValueStart && enumValueEnd))) + { + const std::string pattern = className.empty() ? + std::string("") : + std::string(className + " :: " + enumName->str()); + int level = 1; + bool inScope = true; + + bool exitThisScope = false; + int exitScope = 0; + bool simplify = false; + bool hasClass = false; + for (Token *tok2 = tok1->next(); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "}") + { + --level; + if (level < 0) + inScope = false; + + if (exitThisScope) + { + if (level < exitScope) + exitThisScope = false; + } + } + else if (tok2->str() == "{") + { + // Is the same enum redefined? + const Token *begin = end->link(); + if (tok2->fileIndex() == begin->fileIndex() && + tok2->linenr() == begin->linenr() && + Token::Match(begin->tokAt(-2), "enum %type% {") && + Token::Match(tok2->tokAt(-2), "enum %type% {") && + begin->strAt(-1) == tok2->strAt(-1)) + { + // remove duplicate enum + Token * startToken = tok2->tokAt(-3); + tok2 = tok2->link()->next(); + Token::eraseTokens(startToken, tok2); + if (!tok2) + break; + } + else + { + // Not a duplicate enum.. + ++level; + } + } + else if (!pattern.empty() && Token::Match(tok2, pattern.c_str())) + { + simplify = true; + hasClass = true; + } + else if (inScope && !exitThisScope && tok2->str() == enumName->str()) + { + if (Token::simpleMatch(tok2->previous(), "::") || + Token::Match(tok2->next(), "::|[")) + { + // Don't replace this enum if: + // * it's preceded or followed by "::" + // * it's followed by "[" + } + else if (!duplicateDefinition(&tok2, enumName)) + { + simplify = true; + hasClass = false; + } + else + { + // something with the same name. + exitScope = level; + } + } + + if (simplify) + { + if (enumValue) + tok2->str(enumValue->str()); + else + { + tok2 = tok2->previous(); + tok2->deleteNext(); + tok2 = copyTokens(tok2, enumValueStart, enumValueEnd); + } + + if (hasClass) + { + tok2->deleteNext(); + tok2->deleteNext(); + } + + simplify = false; + } + } + } + } + + // check for a variable definition: enum {} x; + if (end->next() && end->next()->str() != ";") + { + Token *tempTok = end; + + tempTok->insertToken(";"); + tempTok = tempTok->next(); + if (typeTokenStart == 0) + tempTok->insertToken("int"); + else + { + Token *tempTok1 = typeTokenStart; + + tempTok->insertToken(tempTok1->str()); + + while (tempTok1 != typeTokenEnd) + { + tempTok1 = tempTok1->next(); + + tempTok->insertToken(tempTok1->str()); + tempTok = tempTok->next(); + } + } + } + + if (enumType) + { + const std::string pattern(className.empty() ? "" : (className + " :: " + enumType->str()).c_str()); + + // count { and } for tok2 + int level = 0; + bool inScope = true; + + bool exitThisScope = false; + int exitScope = 0; + bool simplify = false; + bool hasClass = false; + for (Token *tok2 = end->next(); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "}") + { + --level; + if (level < 0) + inScope = false; + + if (exitThisScope) + { + if (level < exitScope) + exitThisScope = false; + } + } + else if (tok2->str() == "{") + ++level; + else if (!pattern.empty() && ((Token::simpleMatch(tok2, "enum") && Token::Match(tok2->next(), pattern.c_str())) || Token::Match(tok2, pattern.c_str()))) + { + simplify = true; + hasClass = true; + } + else if (inScope && !exitThisScope && (tok2->str() == enumType->str() || (tok2->str() == "enum" && tok2->next()->str() == enumType->str()))) + { + if (Token::simpleMatch(tok2->previous(), "::")) + { + // Don't replace this enum if it's preceded by "::" + } + else if (tok2->next() && + (tok2->next()->isName() || tok2->next()->str() == "(")) + { + simplify = true; + hasClass = false; + } + } + + if (simplify) + { + if (tok2->str() == "enum") + tok2->deleteNext(); + if (typeTokenStart == 0) + tok2->str("int"); + else + { + Token *tok3 = typeTokenStart; + + tok2->str(tok3->str()); + + while (tok3 != typeTokenEnd) + { + tok3 = tok3->next(); + + tok2->insertToken(tok3->str()); + tok2 = tok2->next(); + } + } + + if (hasClass) + { + tok2->deleteNext(); + tok2->deleteNext(); + } + + simplify = false; + } + } + } + + tok1 = start; + while (tok1->next() && tok1->next() != end) + tok1->deleteNext(); + tok1->deleteNext(); + if (start != _tokens) + { + tok1 = start->previous(); + tok1->deleteNext(); + tok = tok1; + } + else + _tokens->deleteThis(); + } + } +} + + +void Tokenizer::simplifyStd() +{ + std::set f; + f.insert("strcat"); + f.insert("strcpy"); + f.insert("strncat"); + f.insert("strncpy"); + f.insert("free"); + f.insert("malloc"); + f.insert("strdup"); + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "std") + continue; + + if (Token::Match(tok->previous(), "[(,{};] std :: %var% (") && + f.find(tok->strAt(2)) != f.end()) + { + tok->deleteNext(); + tok->deleteThis(); + } + } +} + +//--------------------------------------------------------------------------- +// Helper functions for handling the tokens list +//--------------------------------------------------------------------------- + + + +//--------------------------------------------------------------------------- + +const Token *Tokenizer::getFunctionTokenByName(const char funcname[]) const +{ + getSymbolDatabase(); + + std::list::const_iterator i; + + for (i = _symbolDatabase->scopeList.begin(); i != _symbolDatabase->scopeList.end(); ++i) + { + const Scope *scope = *i; + + if (scope->type == Scope::eFunction) + { + if (scope->classDef->str() == funcname) + return scope->classDef; + } + } + return NULL; +} + + +void Tokenizer::fillFunctionList() +{ + getSymbolDatabase(); +} + +//--------------------------------------------------------------------------- + +// Deallocate lists.. +void Tokenizer::deallocateTokens() +{ + deleteTokens(_tokens); + _tokens = 0; + _tokensBack = 0; + _files.clear(); +} + +void Tokenizer::deleteTokens(Token *tok) +{ + while (tok) + { + Token *next = tok->next(); + delete tok; + tok = next; + } +} + +//--------------------------------------------------------------------------- + +const char *Tokenizer::getParameterName(const Token *ftok, unsigned int par) +{ + unsigned int _par = 1; + for (; ftok; ftok = ftok->next()) + { + if (ftok->str() == ")") + break; + if (ftok->str() == ",") + ++_par; + if (par == _par && Token::Match(ftok, "%var% [,)]")) + return ftok->str().c_str(); + } + return NULL; +} + +//--------------------------------------------------------------------------- + +std::string Tokenizer::fileLine(const Token *tok) const +{ + std::ostringstream ostr; + ostr << "[" << _files.at(tok->fileIndex()) << ":" << tok->linenr() << "]"; + return ostr.str(); +} + +std::string Tokenizer::file(const Token *tok) const +{ + return _files.at(tok->fileIndex()); +} + +//--------------------------------------------------------------------------- + +void Tokenizer::syntaxError(const Token *tok) +{ + std::list locationList; + if (tok) + { + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok->linenr(); + loc.setfile(file(tok)); + locationList.push_back(loc); + } + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::error, + "syntax error", + "syntaxError"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); +} + +void Tokenizer::syntaxError(const Token *tok, char c) +{ + std::list locationList; + if (tok) + { + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok->linenr(); + loc.setfile(file(tok)); + locationList.push_back(loc); + } + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::error, + std::string("Invalid number of character (") + + c + + ") " + + "when these macros are defined: '" + + _configuration + + "'.", + "syntaxError"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); +} + +void Tokenizer::cppcheckError(const Token *tok) const +{ + std::list locationList; + if (tok) + { + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok->linenr(); + loc.setfile(file(tok)); + locationList.push_back(loc); + } + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::error, + "Analysis failed. If the code is valid then please report this failure.", + "cppcheckError"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); +} + + +void Tokenizer::simplifyMathFunctions() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "atol ( %str% )")) + { + if (!MathLib::isInt(tok->tokAt(2)->strValue())) + { + // Ignore strings which we can't convert + continue; + } + + if (tok->previous() && + Token::simpleMatch(tok->previous()->previous(), "std ::")) + { + // Delete "std ::" + tok = tok->previous()->previous(); + tok->deleteNext(); + tok->deleteThis(); + } + + // Delete atol( + tok->deleteNext(); + tok->deleteThis(); + + // Convert string into a number + tok->str(MathLib::toString(MathLib::toLongNumber(tok->strValue()))); + + // Delete remaining ) + tok->deleteNext(); + } + } +} + +void Tokenizer::simplifyComma() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok, "for (") || + Token::Match(tok, "=|enum {")) + { + tok = tok->next()->link(); + if (!tok) + break; + + continue; + } + + if (tok->str() == "(") + { + tok = tok->link(); + continue; + } + + // Skip unhandled template specifiers.. + if (Token::Match(tok, "%var% <")) + { + // Todo.. use the link instead. + unsigned int comparelevel = 0; + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "<") + ++comparelevel; + else if (tok2->str() == ">") + { + if (comparelevel <= 1) + { + tok = tok2; + break; + } + ++comparelevel; + } + else if (Token::Match(tok2, "[;{}]")) + break; + } + } + + // If token after the comma is a constant number, simplification is not required. + if (tok->str() != "," || Token::Match(tok->next(), "%num%")) + continue; + + // We must not accept just any keyword, e.g. accepting int + // would cause function parameters to corrupt. + if (Token::simpleMatch(tok->next(), "delete")) + { + // Handle "delete a, delete b;" + tok->str(";"); + } + + if (tok->previous() && tok->previous()->previous()) + { + if (Token::simpleMatch(tok->previous()->previous(), "delete") && + tok->next()->varId() != 0) + { + // Handle "delete a, b;" + tok->str(";"); + tok->insertToken("delete"); + } + else + { + for (Token *tok2 = tok->previous(); tok2; tok2 = tok2->previous()) + { + if (tok2->str() == "=") + { + // Handle "a = 0, b = 0;" + tok->str(";"); + break; + } + else if (Token::Match(tok2, "delete %var%") || + Token::Match(tok2, "delete [ ] %var%")) + { + // Handle "delete a, a = 0;" + tok->str(";"); + break; + } + else if (Token::Match(tok2, "[;,{}()]")) + { + break; + } + } + } + } + + bool inReturn = false; + Token *startFrom = NULL; // next tokean after "; return" + Token *endAt = NULL; // first ";" token after "; return" + + // find "; return" pattern before comma + for (Token *tok2 = tok; tok2; tok2 = tok2->previous()) + { + if (Token::Match(tok2, "[;{}]")) + { + break; + + } + else if (tok2->str() == "return" && Token::Match(tok2->previous(), "[;{}]")) + { + inReturn = true; + startFrom = tok2->next(); + break; + } + } + + // find token where return ends and also count commas + if (inReturn) + { + size_t commaCounter = 0; + size_t indentlevel = 0; + + for (Token *tok2 = startFrom; tok2; tok2 = tok2->next()) + { + if (tok2->str() == ";") + { + endAt = tok2; + break; + + } + else if (tok2->str() == "(") + { + ++indentlevel; + + } + else if (tok2->str() == ")") + { + --indentlevel; + + } + else if (tok2->str() == "," && indentlevel == 0) + { + ++commaCounter; + } + } + + if (commaCounter) + { + indentlevel = 0; + + // change tokens: + // "; return a ( ) , b ( ) , c ;" + // to + // "; return a ( ) ; b ( ) ; c ;" + for (Token *tok2 = startFrom; tok2 != endAt; tok2 = tok2->next()) + { + if (tok2->str() == "(") + { + ++indentlevel; + + } + else if (tok2->str() == ")") + { + --indentlevel; + + } + else if (tok2->str() == "," && indentlevel == 0) + { + tok2->str(";"); + --commaCounter; + if (commaCounter == 0) + { + tok2->insertToken("return"); + } + } + } + + // delete old "return" + startFrom->previous()->deleteThis(); + startFrom = 0; // give dead pointer a value + + tok = endAt; + if (!tok) + return; + } + } + + } +} + + +void Tokenizer::removeExceptionSpecifications(Token *tok) const +{ + while (tok) + { + if (tok->str() == "{") + tok = tok->link(); + + else if (tok->str() == "}") + break; + + else if (Token::simpleMatch(tok, ") throw (")) + { + Token::eraseTokens(tok, tok->tokAt(2)->link()); + tok->deleteNext(); + } + + else if (Token::Match(tok, "class|namespace|struct %type%")) + { + while (tok && !Token::Match(tok, "[;{]")) + tok = tok->next(); + if (tok && tok->str() == "{") + { + removeExceptionSpecifications(tok->next()); + tok = tok->link(); + } + } + + tok = tok ? tok->next() : 0; + } +} + + + +bool Tokenizer::validate() const +{ + std::stack linktok; + const Token *lastTok = 0; + for (const Token *tok = tokens(); tok; tok = tok->next()) + { + lastTok = tok; + if (Token::Match(tok, "[{([]")) + { + if (tok->link() == 0) + { + cppcheckError(tok); + return false; + } + + linktok.push(tok); + continue; + } + + else if (Token::Match(tok, "[})]]")) + { + if (tok->link() == 0) + { + cppcheckError(tok); + return false; + } + + if (linktok.empty() == true) + { + cppcheckError(tok); + return false; + } + + if (tok->link() != linktok.top()) + { + cppcheckError(tok); + return false; + } + + if (tok != tok->link()->link()) + { + cppcheckError(tok); + return false; + } + + linktok.pop(); + continue; + } + + if (tok->link() != 0) + { + cppcheckError(tok); + return false; + } + } + + if (!linktok.empty()) + { + cppcheckError(linktok.top()); + return false; + } + + // Validate that the Tokenizer::_tokensBack is updated correctly during simplifications + if (lastTok != _tokensBack) + { + cppcheckError(lastTok); + return false; + } + + return true; +} + +std::string Tokenizer::simplifyString(const std::string &source) +{ + std::string str = source; + + // true when previous char is a \ . + bool escaped = false; + for (std::string::size_type i = 0; i + 2 < str.size(); i++) + { + if (!escaped) + { + if (str[i] == '\\') + escaped = true; + + continue; + } + + if (str[i] == 'x') + { + // Hex value + if (str[i+1] == '0' && str[i+2] == '0') + str.replace(i, 3, "0"); + else if (i > 0) + { + // We will replace all other character as 'a' + // If that causes problems in the future, this can + // be improved. But for now, this should be OK. + unsigned int n = 1; + while (n < 2 && std::isxdigit(str[i+1+n])) + ++n; + --i; + n += 2; + str.replace(i, n, "a"); + } + } + else if (MathLib::isOctalDigit(str[i])) + { + if (MathLib::isOctalDigit(str[i+1]) && + MathLib::isOctalDigit(str[i+2])) + { + if (str[i+1] == '0' && str[i+2] == '0') + str.replace(i, 3, "0"); + else + { + // We will replace all other character as 'a' + // If that causes problems in the future, this can + // be improved. But for now, this should be OK. + --i; + str.replace(i, 4, "a"); + } + } + } + + escaped = false; + } + + return str; +} + + +void Tokenizer::simplifyStructInit() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "[;{}] struct| %type% %var% = { . %type% =")) + { + // Goto "." and check if the initializations have an expected format + const Token *tok2 = tok; + while (tok2->str() != ".") + tok2 = tok2->next(); + while (tok2 && tok2->str() == ".") + { + if (Token::Match(tok2, ". %type% = %num% [,}]")) + tok2 = tok2->tokAt(4); + else if (Token::Match(tok2, ". %type% = %var% [,}]")) + tok2 = tok2->tokAt(4); + else if (Token::Match(tok2, ". %type% = & %var% [,}]")) + tok2 = tok2->tokAt(5); + else + break; + + if (Token::simpleMatch(tok2, ", .")) + tok2 = tok2->next(); + } + if (!Token::simpleMatch(tok2, "} ;")) + continue; + + // Known expression format => Perform simplification + Token *vartok = tok->tokAt(3); + if (vartok->str() == "=") + vartok = vartok->previous(); + vartok->next()->str(";"); + + Token *tok3 = vartok->tokAt(2); + tok3->link(0); + while (Token::Match(tok3, "[{,] . %type% =")) + { + tok3->str(vartok->str()); + tok3->varId(vartok->varId()); + tok3 = tok3->tokAt(5); + while (!Token::Match(tok3, "[,}]")) + tok3 = tok3->next(); + if (tok3->str() == "}") + { + tok3->deleteThis(); + break; + } + tok3->previous()->insertToken(";"); + } + } + } +} + + +void Tokenizer::simplifyComparisonOrder() +{ + // Use "<" comparison instead of ">" + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "[;(] %any% >|>= %any% [);]")) + { + if (!tok->next()->isName() && !tok->next()->isNumber()) + continue; + const std::string op1(tok->strAt(1)); + tok->next()->str(tok->strAt(3)); + tok->tokAt(3)->str(op1); + if (tok->tokAt(2)->str() == ">") + tok->tokAt(2)->str("<"); + else + tok->tokAt(2)->str("<="); + } + else if (Token::Match(tok, "( %num% ==|!= %var% )")) + { + if (!tok->next()->isName() && !tok->next()->isNumber()) + continue; + const std::string op1(tok->strAt(1)); + tok->next()->str(tok->strAt(3)); + tok->tokAt(3)->str(op1); + } + } +} + +void Tokenizer::simplifyConst() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "[;{}(,] %type% const") && + tok->next()->str().find(":") == std::string::npos && + tok->next()->str() != "operator") + { + tok->tokAt(2)->str(tok->tokAt(1)->str()); + tok->tokAt(1)->str("const"); + } + } +} + +void Tokenizer::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) +{ + Tokenizer t(settings, errorLogger); + t.syntaxError(0, ' '); + t.cppcheckError(0); +} + +/** find pattern */ +static bool findmatch(const Token *tok1, const Token *tok2, const char pattern[]) +{ + for (const Token *tok = tok1; tok && tok != tok2; tok = tok->next()) + { + if (Token::Match(tok, pattern)) + return true; + } + return false; +} + +void Tokenizer::simplifyWhile0() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + // while (0) + const bool while0(Token::Match(tok, "while ( 0|false )")); + + // for (0) + const bool for0(Token::Match(tok, "for ( %var% = %num% ; %var% < %num% ;") && + tok->strAt(2) == tok->strAt(6) && + tok->strAt(4) == tok->strAt(8)); + + if (!while0 && !for0) + continue; + + if (while0 && Token::simpleMatch(tok->previous(), "}")) + { + // find "do" + Token *tok2 = tok->previous()->link(); + tok2 = tok2 ? tok2->previous() : 0; + if (tok2 && tok2->str() == "do" && !findmatch(tok2, tok, "continue|break")) + { + // delete "do {" + tok2->deleteThis(); + tok2->deleteThis(); + + // delete "} while ( 0 )" + tok = tok->previous(); + tok->deleteNext(); // while + tok->deleteNext(); // ( + tok->deleteNext(); // 0 + tok->deleteNext(); // ) + tok->deleteThis(); // } + + continue; + } + } + + // remove "while (0) { .. }" + if (Token::simpleMatch(tok->next()->link(), ") {")) + { + const Token *end = tok->next()->link()->next()->link(); + if (!findmatch(tok, end, "continue|break")) + { + Token::eraseTokens(tok, end ? end->next() : 0); + tok->deleteThis(); // delete "while" + } + } + + } +} + +void Tokenizer::simplifyErrNoInWhile() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() != "errno") + continue; + + Token *endpar = 0; + if (Token::Match(tok->previous(), "&& errno == EINTR ) { ;| }")) + endpar = tok->tokAt(3); + else if (Token::Match(tok->tokAt(-2), "&& ( errno == EINTR ) ) { ;| }")) + endpar = tok->tokAt(4); + else + continue; + + if (Token::simpleMatch(endpar->link()->previous(), "while (")) + { + Token *tok1 = tok->previous(); + if (tok1->str() == "(") + tok1 = tok1->previous(); + + // erase "&& errno == EINTR" + Token::eraseTokens(tok1->previous(), endpar); + + // tok is invalid.. move to endpar + tok = endpar; + + } + } +} + + +void Tokenizer::simplifyFuncInWhile() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (!Token::Match(tok, "while ( %var% ( %var% ) ) {")) + continue; + + Token *func = tok->tokAt(2); + Token *var = tok->tokAt(4); + Token *end = tok->tokAt(7)->link(); + if (!end) + break; + + tok->str("int"); + tok->insertToken("cppcheck:r"); + tok->tokAt(1)->insertToken("="); + tok->tokAt(2)->insertToken(func->str()); + tok->tokAt(3)->insertToken("("); + tok->tokAt(4)->insertToken(var->str()); + tok->tokAt(5)->varId(var->varId()); + tok->tokAt(5)->insertToken(")"); + tok->tokAt(6)->insertToken(";"); + tok->tokAt(7)->insertToken("while"); + tok->tokAt(9)->insertToken("cppcheck:r"); + Token::createMutualLinks(tok->tokAt(4), tok->tokAt(6)); + end->previous()->insertToken("cppcheck:r"); + end->previous()->insertToken("="); + Token::move(func, func->tokAt(3), end->previous()); + end->previous()->insertToken(";"); + + tok = end; + } +} + +void Tokenizer::simplifyStructDecl() +{ + // A counter that is used when giving unique names for anonymous structs. + unsigned int count = 0; + + // Skip simplification of unions in class definition + std::list skip; + skip.push_back(false); + + for (Token *tok = _tokens; tok; tok = tok->next()) + { + Token *restart; + + if (tok->str() == "{") + skip.push_back(!Token::Match(tok->previous(), "const|)")); + else if (tok->str() == "}" && !skip.empty()) + skip.pop_back(); + else if (!skip.empty() && skip.back() && tok->str() == "union") + continue; + + // check for named struct/union + if (Token::Match(tok, "struct|union %type% :|{")) + { + Token *isStatic = tok->previous() && tok->previous()->str() == "static" ? tok->previous() : NULL; + Token *type = tok->next(); + Token *next = tok->tokAt(2); + + while (next && next->str() != "{") + next = next->next(); + if (!next) + continue; + + tok = next->link(); + restart = next; + + // check for named type + if (Token::Match(tok->next(), "*|&| %type% ,|;|[")) + { + tok->insertToken(";"); + tok = tok->next(); + if (isStatic) + { + isStatic->deleteThis(); + tok->insertToken("static"); + tok = tok->next(); + } + tok->insertToken(type->str().c_str()); + } + + tok = restart; + } + + // check for anonymous struct/union + else if (Token::Match(tok, "struct|union {")) + { + Token *tok1 = tok; + + restart = tok->next(); + tok = tok->next()->link(); + + // check for named type + if (Token::Match(tok->next(), "*|&| %type% ,|;|[")) + { + std::string name; + + name = "Anonymous" + MathLib::toString(count++); + + tok1->insertToken(name.c_str()); + + tok->insertToken(";"); + tok = tok->next(); + tok->insertToken(name.c_str()); + } + + // unnamed anonymous struct/union so remove it + else if (tok->next() && tok->next()->str() == ";") + { + if (tok1->str() == "union") + { + // Try to create references in the union.. + Token *tok2 = tok1->tokAt(2); + while (tok2) + { + if (Token::Match(tok2, "%type% %var% ;")) + tok2 = tok2->tokAt(3); + else + break; + } + if (!Token::simpleMatch(tok2, "} ;")) + continue; + Token *vartok = 0; + tok2 = tok1->tokAt(2); + while (Token::Match(tok2, "%type% %var% ;")) + { + if (!vartok) + { + vartok = tok2->next(); + tok2 = tok2->tokAt(3); + } + else + { + tok2->insertToken("&"); + tok2 = tok2->tokAt(2); + tok2->insertToken(vartok->str()); + tok2->next()->varId(vartok->varId()); + tok2->insertToken("="); + tok2 = tok2->tokAt(4); + } + } + } + + tok1->deleteThis(); + if (tok1->next() == tok) + { + tok1->deleteThis(); + tok = tok1; + } + else + tok1->deleteThis(); + restart = tok1->previous(); + tok->deleteThis(); + if (tok->next()) + tok->deleteThis(); + } + + if (!restart) + { + simplifyStructDecl(); + return; + } + else if (!restart->next()) + return; + + tok = restart; + } + } +} + +void Tokenizer::simplifyCallingConvention() +{ + const char * pattern = "__cdecl|__stdcall|__fastcall|__thiscall|__clrcall|__syscall|__pascal|__fortran|__far|__near|WINAPI|APIENTRY|CALLBACK"; + while (Token::Match(_tokens, pattern)) + { + _tokens->deleteThis(); + } + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (Token::Match(tok->next(), pattern)) + { + tok->deleteNext(); + } + } +} + +void Tokenizer::simplifyDeclspec() +{ + while (Token::simpleMatch(_tokens, "__declspec (") && _tokens->next()->link() && _tokens->next()->link()->next()) + { + Token::eraseTokens(_tokens, _tokens->next()->link()->next()); + _tokens->deleteThis(); + } + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok, "__declspec (") && tok->next()->link() && tok->next()->link()->next()) + { + Token::eraseTokens(tok, tok->next()->link()->next()); + tok->deleteThis(); + } + } +} + +void Tokenizer::simplifyAttribute() +{ + while (Token::simpleMatch(_tokens, "__attribute__ (") && _tokens->next()->link() && _tokens->next()->link()->next()) + { + Token::eraseTokens(_tokens, _tokens->next()->link()->next()); + _tokens->deleteThis(); + } + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok, "__attribute__ (") && tok->next()->link() && tok->next()->link()->next()) + { + if (Token::simpleMatch(tok->tokAt(2), "( unused )")) + { + // check if after variable name + if (Token::Match(tok->next()->link()->next(), ";|=")) + { + if (Token::Match(tok->previous(), "%type%")) + tok->previous()->isUnused(true); + } + + // check if before variable name + else if (Token::Match(tok->next()->link()->next(), "%type%")) + tok->next()->link()->next()->isUnused(true); + } + + Token::eraseTokens(tok, tok->next()->link()->next()); + tok->deleteThis(); + } + } +} + +// Remove "volatile", "inline", "register", and "restrict" +void Tokenizer::simplifyKeyword() +{ + const char pattern[] = "volatile|inline|__inline|__forceinline|register|restrict|__restrict|__restrict__"; + while (Token::Match(_tokens, pattern)) + { + _tokens->deleteThis(); + } + for (Token *tok = _tokens; tok; tok = tok->next()) + { + while (Token::Match(tok->next(), pattern)) + { + tok->deleteNext(); + } + } +} + +void Tokenizer::simplifyAssignmentInFunctionCall() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "(") + tok = tok->link(); + + // Find 'foo(var='. Exclude 'assert(var=' to allow tests to check that assert(...) does not contain side-effects + else if (Token::Match(tok, "[;{}] %var% ( %var% =") && + Token::simpleMatch(tok->tokAt(2)->link(), ") ;") && + tok->strAt(1) != "assert") + { + const std::string funcname(tok->strAt(1)); + const Token * const vartok = tok->tokAt(3); + + // Goto ',' or ')'.. + for (Token *tok2 = tok->tokAt(4); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "(") + tok2 = tok2->link(); + else if (tok2->str() == ";") + break; + else if (tok2->str() == ")" || tok2->str() == ",") + { + tok2 = tok2->previous(); + + tok2->insertToken(vartok->str()); + tok2->next()->varId(vartok->varId()); + + tok2->insertToken("("); + Token::createMutualLinks(tok2->next(), tok->tokAt(2)->link()); + + tok2->insertToken(funcname); + tok2->insertToken(";"); + + Token::eraseTokens(tok, vartok); + break; + } + } + } + } +} + +// Remove __asm.. +void Tokenizer::simplifyAsm() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok->next(), "__asm|_asm|asm {") && + tok->tokAt(2)->link() && + tok->tokAt(2)->link()->next()) + { + Token::eraseTokens(tok, tok->tokAt(2)->link()->next()); + } + + else if (Token::Match(tok->next(), "asm|__asm|__asm__ volatile|__volatile__| (")) + { + // Goto "(" + Token *partok = tok->tokAt(2); + if (partok->str() != "(") + partok = partok->next(); + Token::eraseTokens(tok, partok->link() ? partok->link()->next() : NULL); + } + + else if (Token::simpleMatch(tok->next(), "__asm")) + { + const Token *tok2 = tok->next(); + while (tok2 && (tok2->isNumber() || tok2->isName() || tok2->str() == ",")) + tok2 = tok2->next(); + if (tok2 && tok2->str() == ";") + Token::eraseTokens(tok, tok2); + else + continue; + } + + else + continue; + + // insert "asm ( )" + tok->insertToken(")"); + tok->insertToken("("); + tok->insertToken("asm"); + + Token::createMutualLinks(tok->tokAt(2), tok->tokAt(3)); + } +} + +// Simplify bitfields +void Tokenizer::simplifyBitfields() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + Token *last = 0; + + if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %any% ;|,") && + tok->next()->str() != "case") + { + int offset = 0; + if (tok->next()->str() == "const") + offset = 1; + + last = tok->tokAt(5 + offset); + Token::eraseTokens(tok->tokAt(2 + offset), tok->tokAt(5 + offset)); + } + else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %any% ;") && + tok->next()->str() != "default") + { + int offset = 0; + if (tok->next()->str() == "const") + offset = 1; + + Token::eraseTokens(tok->tokAt(0), tok->tokAt(5 + offset)); + tok = tok->previous(); + } + + if (last && last->str() == ",") + { + Token *tok1 = last; + tok1->str(";"); + + Token *tok2 = tok->next(); + tok1->insertToken(tok2->str()); + tok1 = tok1->next(); + tok1->isSigned(tok2->isSigned()); + tok1->isUnsigned(tok2->isUnsigned()); + tok1->isLong(tok2->isLong()); + } + } +} + + +// Remove __builtin_expect(...), likely(...), and unlikely(...) +void Tokenizer::simplifyBuiltinExpect() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok->next(), "__builtin_expect (")) + { + // Count parantheses for tok2 + unsigned int parlevel = 0; + for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "(") + ++parlevel; + else if (tok2->str() == ")") + { + if (parlevel <= 1) + break; + --parlevel; + } + if (parlevel == 1 && tok2->str() == ",") + { + if (Token::Match(tok2, ", %num% )")) + { + tok->deleteNext(); + Token::eraseTokens(tok2->previous(), tok2->tokAt(2)); + } + break; + } + } + } + else if (Token::Match(tok->next(), "likely|unlikely (")) + { + // remove closing ')' + tok->tokAt(2)->link()->previous()->deleteNext(); + + // remove "likely|unlikely (" + tok->deleteNext(); + tok->deleteNext(); + } + } +} + + +// Remove Microsoft MFC 'DECLARE_MESSAGE_MAP()' +void Tokenizer::simplifyMicrosoftMFC() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::simpleMatch(tok->next(), "DECLARE_MESSAGE_MAP ( )")) + { + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + } + else if (Token::Match(tok->next(), "DECLARE_DYNAMIC|DECLARE_DYNAMIC_CLASS|DECLARE_DYNCREATE ( %any% )")) + { + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + } + } +} + + +// Remove Borland code +void Tokenizer::simplifyBorland() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "( __closure * %var% )")) + { + tok->deleteNext(); + } + } + + // I think that these classes are always declared at the outer scope + // I save some time by ignoring inner classes. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "{") + { + tok = tok->link(); + if (!tok) + break; + } + + if (Token::Match(tok, "class %var% :|{")) + { + // count { and } for tok2 + unsigned int indentlevel = 0; + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + { + if (indentlevel == 0) + indentlevel = 1; + else + tok2 = tok2->link(); + } + else if (tok2->str() == "}") + { + break; + } + else if (tok2->str() == "__property" && + Token::Match(tok2->previous(), ";|{|}|protected:|public:|__published:")) + { + while (tok2->next() && !Token::Match(tok2, "{|;")) + tok2->deleteThis(); + if (Token::simpleMatch(tok2, "{")) + { + Token::eraseTokens(tok2, tok2->link()); + tok2->deleteThis(); + tok2->deleteThis(); + + // insert "; __property ;" + tok2->previous()->insertToken(";"); + tok2->previous()->insertToken("__property"); + tok2->previous()->insertToken(";"); + } + } + } + } + } +} + +// Remove Qt signals and slots +void Tokenizer::simplifyQtSignalsSlots() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (!Token::Match(tok, "class %var% :")) + continue; + + if (tok->previous() && tok->previous()->str() == "enum") + { + tok = tok->tokAt(2); + continue; + } + + // count { and } for tok2 + unsigned int indentlevel = 0; + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + { + indentlevel++; + if (indentlevel == 1) + tok = tok2; + else + tok2 = tok2->link(); + } + else if (tok2->str() == "}") + { + indentlevel--; + if (indentlevel == 0) + break; + } + + if (Token::simpleMatch(tok2->next(), "Q_OBJECT")) + { + tok2->deleteNext(); + } + else if (Token::Match(tok2->next(), "public|protected|private slots|Q_SLOTS :")) + { + tok2 = tok2->next(); + tok2->str(tok2->str() + ":"); + tok2->deleteNext(); + tok2->deleteNext(); + } + else if (Token::Match(tok2->next(), "signals|Q_SIGNALS :")) + { + tok2 = tok2->next(); + tok2->str("protected:"); + tok2->deleteNext(); + } + } + } +} + +const SymbolDatabase *Tokenizer::getSymbolDatabase() const +{ + if (!_symbolDatabase) + _symbolDatabase = new SymbolDatabase(this, _settings, _errorLogger); + + return _symbolDatabase; +} + +void Tokenizer::simplifyOperatorName() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "operator") + { + // operator op + std::string op; + Token *par = tok->next(); + bool done = false; + while (!done && par) + { + done = true; + if (par && par->isName()) + { + op += par->str(); + par = par->next(); + done = false; + } + if (Token::Match(par, "[<>+-*&/=.]") || Token::Match(par, "==|!=|<=|>=")) + { + op += par->str(); + par = par->next(); + done = false; + } + if (Token::simpleMatch(par, "[ ]")) + { + op += "[]"; + par = par->next()->next(); + done = false; + } + if (Token::Match(par, "( *| )")) + { + // break out and simplify.. + if (Token::Match(par, "( ) const| [=;{),]")) + break; + + while (par->str() != ")") + { + op += par->str(); + par = par->next(); + } + op += ")"; + par = par->next(); + done = false; + } + } + + if (par && Token::Match(par->link(), ") const| [=;{),]")) + { + tok->str("operator" + op); + Token::eraseTokens(tok,par); + } + } + } +} + +// remove unnecessary member qualification.. +struct ClassInfo +{ + std::string className; + Token *end; +}; + +void Tokenizer::removeUnnecessaryQualification() +{ + std::stack classInfo; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "class|struct %type% :|{") && + (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) + { + tok = tok->next(); + ClassInfo info; + info.className = tok->str(); + tok = tok->next(); + while (tok && tok->str() != "{") + tok = tok->next(); + if (!tok) + return; + info.end = tok->link(); + classInfo.push(info); + } + else if (!classInfo.empty()) + { + if (tok == classInfo.top().end) + classInfo.pop(); + else if (tok->str() == classInfo.top().className && + Token::Match(tok, "%type% :: %type% (") && + Token::Match(tok->tokAt(3)->link(), ") const| {|;") && + tok->previous()->str() != ":") + { + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok->linenr(); + loc.setfile(file(tok)); + locationList.push_back(loc); + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::portability, + "Extra qualification \'" + tok->str() + "::\' unnecessary and considered an error by many compilers.", + "portability"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); + + tok->deleteThis(); + tok->deleteThis(); + } + } + } +} + diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index def7e688e..96ec83945 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -113,7 +113,6 @@ private: TEST_CASE(template20); TEST_CASE(template21); TEST_CASE(template22); - TEST_CASE(template23); TEST_CASE(template_unhandled); TEST_CASE(template_default_parameter); TEST_CASE(template_default_type); @@ -2026,23 +2025,6 @@ private: ASSERT_EQUALS(expected, sizeof_(code)); } - void template23() - { - const char code[] = "template void foo(double &ac) {}\n" - "\n" - "void bar() {\n" - " std::cout << (foo(r));\n" - "}\n"; - - const char expected[] = "; " - "void bar ( ) {" - " std :: cout << ( foo ( r ) ) ; " - "} " - "void foo ( double & ac ) { }"; - - ASSERT_EQUALS(expected, sizeof_(code)); - } - void template_unhandled() { @@ -2823,4 +2805,3773 @@ private: { const char code[] = "void foo(int x)\n" - \ No newline at end of file + "{\n" + " goto A;\n" + "A:\n" + " fooA();\n" + " goto B;\n" + " fooNever();\n" + "B:\n" + " fooB();\n" + " return 3;\n" + "}"; + + const char expect[] = "void foo ( int x ) " + "{ " + "fooA ( ) ; " + "fooB ( ) ; " + "return 3 ; " + "fooA ( ) ; " + "fooB ( ) ; " + "return 3 ; " + "fooNever ( ) ; " + "fooB ( ) ; " + "return 3 ; " + "}"; + + ASSERT_EQUALS(expect, tok(code)); + } + + { + const char code[] = "void foo(int x)\n" + "{\n" + " goto A;\n" + "A:\n" + " fooA();\n" + " if( x ) { goto B; }\n" + " fooNever();\n" + "B:\n" + " fooB();\n" + " return 3;\n" + "}"; + + const char expect[] = "void foo ( int x ) " + "{ " + "fooA ( ) ; " + "if ( x ) { " + "fooB ( ) ; " + "return 3 ; } " + "fooNever ( ) ; " + "fooB ( ) ; " + "return 3 ; " + "fooA ( ) ; " + "if ( x ) { " + "fooB ( ) ; " + "return 3 ; } " + "fooNever ( ) ; " + "fooB ( ) ; " + "return 3 ; " + "}"; + + ASSERT_EQUALS(expect, tok(code)); + } + } + + void goto2() + { + // Don't simplify goto inside function call (macro) + const char code[] = "void f ( ) { slist_iter ( if ( a ) { goto dont_write ; } dont_write : ; x ( ) ; ) ; }"; + ASSERT_EQUALS(code, tok(code)); + } + + void strcat1() + { + const char code[] = "; strcat(strcat(strcat(strcat(strcat(strcat(dst, \"this \"), \"\"), \"is \"), \"a \"), \"test\"), \".\");"; + const char expect[] = "; " + "strcat ( dst , \"this \" ) ; " + "strcat ( dst , \"\" ) ; " + "strcat ( dst , \"is \" ) ; " + "strcat ( dst , \"a \" ) ; " + "strcat ( dst , \"test\" ) ; " + "strcat ( dst , \".\" ) ;"; + + ASSERT_EQUALS(expect, tok(code)); + } + void strcat2() + { + const char code[] = "; strcat(strcat(dst, foo[0]), \" \");"; + const char expect[] = "; " + "strcat ( dst , foo [ 0 ] ) ; " + "strcat ( dst , \" \" ) ;"; + + ASSERT_EQUALS(expect, tok(code)); + } + + void argumentsWithSameName() + { + // This code has syntax error, two variables can not have the same name + { + const char code[] = "void foo(x, x)\n" + " int x;\n" + " int x;\n" + "{}\n"; + ASSERT_EQUALS("void foo ( x , x ) int x ; int x ; { }", tok(code)); + } + + { + const char code[] = "void foo(x, y)\n" + " int x;\n" + " int x;\n" + "{}\n"; + ASSERT_EQUALS("void foo ( int x , y ) int x ; { }", tok(code)); + } + } + + void simplifyAtol() + { + ASSERT_EQUALS("a = std :: atol ( x ) ;", tok("a = std::atol(x);")); + ASSERT_EQUALS("a = atol ( \"text\" ) ;", tok("a = atol(\"text\");")); + ASSERT_EQUALS("a = 0 ;", tok("a = std::atol(\"0\");")); + ASSERT_EQUALS("a = 10 ;", tok("a = atol(\"0xa\");")); + } + + void simplifyHexInString() + { + ASSERT_EQUALS("\"a\"", tok("\"\\x61\"")); + ASSERT_EQUALS("\"a\"", tok("\"\\141\"")); + + ASSERT_EQUALS("\"\\0\"", tok("\"\\x00\"")); + ASSERT_EQUALS("\"\\0\"", tok("\"\\000\"")); + + ASSERT_EQUALS("\"\\nhello\"", tok("\"\\nhello\"")); + + ASSERT_EQUALS("\"aaa\"", tok("\"\\x61\\x61\\x61\"")); + ASSERT_EQUALS("\"aaa\"", tok("\"\\141\\141\\141\"")); + + ASSERT_EQUALS("\"\\\\x61\"", tok("\"\\\\x61\"")); + + // These tests can fail, if other characters are handled + // more correctly. But for now all non null characters should + // become 'a' + ASSERT_EQUALS("\"a\"", tok("\"\\x62\"")); + ASSERT_EQUALS("\"a\"", tok("\"\\177\"")); + } + + + std::string simplifyTypedef(const char code[]) + { + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + + std::istringstream istr(code); + tokenizer.createTokens(istr); + tokenizer.createLinks(); + tokenizer.simplifyTypedef(); + + std::string ret; + for (const Token *tok1 = tokenizer.tokens(); tok1; tok1 = tok1->next()) + { + if (tok1 != tokenizer.tokens()) + ret += " "; + ret += tok1->str(); + } + + return ret; + } + + + + void simplifyTypedef1() + { + const char code[] = "class A\n" + "{\n" + "public:\n" + " typedef wchar_t duplicate;\n" + " void foo() {}\n" + "};\n" + "typedef A duplicate;\n" + "int main()\n" + "{\n" + " duplicate a;\n" + " a.foo();\n" + " A::duplicate c = 0;\n" + "}\n"; + + const std::string expected = + "class A " + "{ " + "public: " + "; " + "void foo ( ) { } " + "} ; " + "int main ( ) " + "{ " + "A a ; " + "a . foo ( ) ; " + "wchar_t c ; c = 0 ; " + "}"; + ASSERT_EQUALS(expected, tok(code)); + } + + void simplifyTypedef2() + { + const char code[] = "class A;\n" + "typedef A duplicate;\n" + "class A\n" + "{\n" + "public:\n" + "typedef wchar_t duplicate;\n" + "duplicate foo() { wchar_t b; return b; }\n" + "};\n"; + + const std::string expected = + "class A ; " + "class A " + "{ " + "public: " + "; " + "wchar_t foo ( ) { wchar_t b ; return b ; } " + "} ;"; + ASSERT_EQUALS(expected, tok(code)); + } + + void simplifyTypedef3() + { + const char code[] = "class A {};\n" + "typedef A duplicate;\n" + "wchar_t foo()\n" + "{\n" + "typedef wchar_t duplicate;\n" + "duplicate b;\n" + "return b;\n" + "}\n" + "int main()\n" + "{\n" + "duplicate b;\n" + "}\n"; + + const std::string expected = + "class A { } ; " + "wchar_t foo ( ) " + "{ " + "; " + "wchar_t b ; " + "return b ; " + "} " + "int main ( ) " + "{ " + "A b ; " + "}"; + ASSERT_EQUALS(expected, tok(code)); + } + + void simplifyTypedef4() + { + const char code[] = "typedef int s32;\n" + "typedef unsigned int u32;\n" + "void f()\n" + "{\n" + " s32 ivar = -2;\n" + " u32 uvar = 2;\n" + " return uvar / ivar;\n" + "}\n"; + + const std::string expected = + "; " + "void f ( ) " + "{ " + "int ivar ; ivar = -2 ; " + "unsigned int uvar ; uvar = 2 ; " + "return uvar / ivar ; " + "}"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef5() + { + // ticket #780 + const char code[] = + "typedef struct yy_buffer_state *YY_BUFFER_STATE;\n" + "void f()\n" + "{\n" + " YY_BUFFER_STATE state;\n" + "}\n"; + + const char expected[] = + "; " + "void f ( ) " + "{ " + "struct yy_buffer_state * state ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef6() + { + // ticket #983 + const char code[] = + "namespace VL {\n" + " typedef float float_t ;\n" + " inline VL::float_t fast_atan2(VL::float_t y, VL::float_t x){}\n" + "}\n"; + + const char expected[] = + "namespace VL { " + "; " + "float fast_atan2 ( float y , float x ) { } " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef7() + { + const char code[] = "typedef int abc ; " + "Fred :: abc f ;"; + const char expected[] = + "; " + "Fred :: abc f ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef8() + { + const char code[] = "typedef int INT;\n" + "typedef unsigned int UINT;\n" + "typedef int * PINT;\n" + "typedef unsigned int * PUINT;\n" + "typedef int & RINT;\n" + "typedef unsigned int & RUINT;\n" + "typedef const int & RCINT;\n" + "typedef const unsigned int & RCUINT;\n" + "INT ti;\n" + "UINT tui;\n" + "PINT tpi;\n" + "PUINT tpui;\n" + "RINT tri;\n" + "RUINT trui;\n" + "RCINT trci;\n" + "RCUINT trcui;"; + + const char expected[] = + "; " + "int ti ; " + "unsigned int tui ; " + "int * tpi ; " + "unsigned int * tpui ; " + "int & tri ; " + "unsigned int & trui ; " + "const int & trci ; " + "const unsigned int & trcui ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef9() + { + const char code[] = "typedef struct s S, * PS;\n" + "typedef struct t { int a; } T, *TP;\n" + "typedef struct { int a; } U;\n" + "typedef struct { int a; } * V;\n" + "S s;\n" + "PS ps;\n" + "T t;\n" + "TP tp;\n" + "U u;\n" + "V v;"; + + const char expected[] = + "; " + "struct t { int a ; } ; " + "struct U { int a ; } ; " + "struct Unnamed0 { int a ; } ; " + "struct s s ; " + "struct s * ps ; " + "struct t t ; " + "struct t * tp ; " + "struct U u ; " + "struct Unnamed0 * v ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef10() + { + const char code[] = "typedef union s S, * PS;\n" + "typedef union t { int a; float b ; } T, *TP;\n" + "typedef union { int a; float b; } U;\n" + "typedef union { int a; float b; } * V;\n" + "S s;\n" + "PS ps;\n" + "T t;\n" + "TP tp;\n" + "U u;\n" + "V v;"; + + const char expected[] = + "; " + "union t { int a ; float b ; } ; " + "union U { int a ; float b ; } ; " + "union Unnamed1 { int a ; float b ; } ; " + "union s s ; " + "union s * ps ; " + "union t t ; " + "union t * tp ; " + "union U u ; " + "union Unnamed1 * v ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef11() + { + const char code[] = "typedef enum { a = 0 , b = 1 , c = 2 } abc;\n" + "typedef enum xyz { x = 0 , y = 1 , z = 2 } XYZ;\n" + "abc e1;\n" + "XYZ e2;"; + + const char expected[] = + "; " + "int e1 ; " + "int e2 ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef12() + { + const char code[] = "typedef vector V1;\n" + "typedef std::vector V2;\n" + "typedef std::vector > V3;\n" + "typedef std::list::iterator IntListIterator;\n" + "V1 v1;\n" + "V2 v2;\n" + "V3 v3;\n" + "IntListIterator iter;"; + + const char expected[] = + "; " + "vector < int > v1 ; " + "std :: vector < int > v2 ; " + "std :: vector < std :: vector < int > > v3 ; " + "std :: list < int > :: iterator iter ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef13() + { + // ticket # 1167 + const char code[] = "typedef std::pair Func;" + "typedef std::vector CallQueue;" + "int main() {}"; + + // Clear the error buffer.. + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + tokenizer.simplifyTokenList(); + + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef14() + { + // ticket # 1232 + const char code[] = "template struct E" + "{" + " typedef E0)?(N-1):0> v;" + " typedef typename add::val val;" + " FP_M(val);" + "};" + "template struct E " + "{" + " typedef typename D<1>::val val;" + " FP_M(val);" + "};"; + + // Clear the error buffer.. + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + tokenizer.simplifyTokenList(); + + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef15() + { + { + const char code[] = "typedef char frame[10];\n" + "frame f;"; + + const char expected[] = + "; " + "char f [ 10 ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "typedef unsigned char frame[10];\n" + "frame f;"; + + const char expected[] = + "; " + "unsigned char f [ 10 ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef16() + { + // ticket # 1252 + const char code[] = "typedef char MOT8;\n" + "typedef MOT8 CHFOO[4096];\n" + "typedef struct {\n" + " CHFOO freem;\n" + "} STRFOO;"; + + // Clear the error buffer.. + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + tokenizer.simplifyTokenList(); + + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef17() + { + const char code[] = "typedef char * PCHAR, CHAR;\n" + "PCHAR pc;\n" + "CHAR c;"; + + const char expected[] = + "; " + "char * pc ; " + "char c ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef18() + { + const char code[] = "typedef vector a;\n" + "a b;\n"; + + // Clear the error buffer.. + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + tokenizer.simplifyTokenList(); + + ASSERT_EQUALS(true, tokenizer.validate()); + } + + void simplifyTypedef19() + { + { + // ticket #1275 + const char code[] = "typedef struct {} A, *B, **C;\n" + "A a;\n" + "B b;\n" + "C c;"; + + const char expected[] = + "struct A { } ; " + "struct A a ; " + "struct A * b ; " + "struct A * * c ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "typedef struct {} A, *********B;\n" + "A a;\n" + "B b;"; + + const char expected[] = + "struct A { } ; " + "struct A a ; " + "struct A * * * * * * * * * b ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "typedef struct {} **********A, *B, C;\n" + "A a;\n" + "B b;\n" + "C c;"; + + const char expected[] = + "struct Unnamed2 { } ; " + "struct Unnamed2 * * * * * * * * * * a ; " + "struct Unnamed2 * b ; " + "struct Unnamed2 c ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef20() + { + // ticket #1284 + const char code[] = "typedef jobject invoke_t (jobject, Proxy *, Method *, JArray< jobject > *);"; + + // Clear the error buffer.. + errout.str(""); + + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + tokenizer.simplifyTokenList(); + + ASSERT_EQUALS(true, tokenizer.validate()); + } + + void simplifyTypedef21() + { + const char code[] = "typedef void (* PF)();\n" + "typedef void * (* PFV)(void *);\n" + "PF pf;\n" + "PFV pfv;"; + + const char expected[] = + "; " + "; " + "void ( * pf ) ( ) ; " + "void * ( * pfv ) ( void * ) ;"; + + ASSERT_EQUALS(expected, simplifyTypedef(code)); + } + + void simplifyTypedef22() + { + { + const char code[] = "class Fred {\n" + " typedef void (*testfp)();\n" + " testfp get() { return test; }\n" + " static void test() { }\n" + "};"; + + const char expected[] = + "class Fred { " + "; " + "void ( * get ( ) ) ( ) { return test ; } " + "static void test ( ) { } " + "} ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "class Fred {\n" + " typedef void * (*testfp)(void *);\n" + " testfp get() { return test; }\n" + " static void * test(void * p) { return p; }\n" + "};\n"; + + const char expected[] = + "class Fred { " + "; " + "void * ( * get ( ) ) ( void * ) { return test ; } " + "static void * test ( void * p ) { return p ; } " + "} ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "class Fred {\n" + " typedef unsigned int * (*testfp)(unsigned int *);\n" + " testfp get() { return test; }\n" + " static unsigned int * test(unsigned int * p) { return p; }\n" + "};\n"; + + const char expected[] = + "class Fred { " + "; " + "unsigned int * ( * get ( ) ) ( unsigned int * ) { return test ; } " + "static unsigned int * test ( unsigned int * p ) { return p ; } " + "} ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "class Fred {\n" + " typedef const unsigned int * (*testfp)(const unsigned int *);\n" + " testfp get() { return test; }\n" + " static const unsigned int * test(const unsigned int * p) { return p; }\n" + "};\n"; + + // static const gets changed to const static + const char expected[] = + "class Fred { " + "; " + "const unsigned int * ( * get ( ) ) ( const unsigned int * ) { return test ; } " + "const static unsigned int * test ( const unsigned int * p ) { return p ; } " + "} ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "class Fred {\n" + " typedef void * (*testfp)(void *);\n" + " testfp get(int i) { return test; }\n" + " static void * test(void * p) { return p; }\n" + "};\n"; + + const char expected[] = + "class Fred { " + "; " + "void * ( * get ( int i ) ) ( void * ) { return test ; } " + "static void * test ( void * p ) { return p ; } " + "} ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef23() + { + const char code[] = "typedef bool (*Callback) (int i);\n" + "void addCallback(Callback callback) { }\n" + "void addCallback1(Callback callback, int j) { }"; + + const char expected[] = + "; " + "void addCallback ( bool * callback ) { } " + "void addCallback1 ( bool * callback , int j ) { }"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef24() + { + { + const char code[] = "typedef int (*fp)();\n" + "void g( fp f )\n" + "{\n" + " fp f2 = (fp)f;\n" + "}"; + + const char expected[] = + "; " + "void g ( int * f ) " + "{ " + "int * f2 ; f2 = ( int * ) f ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "typedef int (*fp)();\n" + "void g( fp f )\n" + "{\n" + " fp f2 = static_cast(f);\n" + "}"; + + const char expected[] = + "; " + "void g ( int * f ) " + "{ " + "int * f2 ; f2 = static_cast < int * > ( f ) ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef25() + { + { + // ticket #1298 + const char code[] = "typedef void (*fill_names_f) (const char *);\n" + "struct vfs_class {\n" + " void (*fill_names) (struct vfs_class *me, fill_names_f);\n" + "}"; + + const char expected[] = + "; " + "struct vfs_class { " + "void ( * fill_names ) ( struct vfs_class * me , void ( * ) ( const char * ) ) ; " + "}"; + + ASSERT_EQUALS(expected, simplifyTypedef(code)); + } + + { + const char code[] = "typedef void (*fill_names_f) (const char *);\n" + "struct vfs_class {\n" + " void (*fill_names) (fill_names_f, struct vfs_class *me);\n" + "}"; + + const char expected[] = + "; " + "struct vfs_class { " + "void ( * fill_names ) ( void ( * ) ( const char * ) , struct vfs_class * me ) ; " + "}"; + + ASSERT_EQUALS(expected, simplifyTypedef(code)); + } + } + + void simplifyTypedef26() + { + { + const char code[] = "typedef void (*Callback) ();\n" + "void addCallback(Callback (*callback)());"; + + const char expected[] = + "; " + "void addCallback ( void ( * ( * callback ) ( ) ) ( ) ) ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + // ticket # 1307 + const char code[] = "typedef void (*pc_video_update_proc)(bitmap_t *bitmap,\n" + "struct mscrtc6845 *crtc);\n" + "\n" + "struct mscrtc6845 *pc_video_start(pc_video_update_proc (*choosevideomode)(running_machine *machine, int *width, int *height, struct mscrtc6845 *crtc));"; + + const char expected[] = + "; " + "struct mscrtc6845 * pc_video_start ( void ( * ( * choosevideomode ) ( running_machine * machine , int * width , int * height , struct mscrtc6845 * crtc ) ) ( bitmap_t * bitmap , struct mscrtc6845 * crtc ) ) ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef27() + { + // ticket #1316 + const char code[] = "int main()\n" + "{\n" + " typedef int (*func_ptr)(float, double);\n" + " VERIFY((is_same::type, int>::value));\n" + "}"; + + const char expected[] = + "int main ( ) " + "{ " + "; " + "VERIFY ( is_same < result_of < int ( * ( char , float ) ) ( float , double ) > :: type , int > :: value ) ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef28() + { + const char code[] = "typedef std::pair (*F)(double);\n" + "F f;"; + + const char expected[] = + "; " + "std :: pair < double , double > ( * f ) ( double ) ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef29() + { + const char code[] = "typedef int array [ice_or::value, is_int::value>::value ? 1 : -1];\n" + "typedef int array1 [N];\n" + "typedef int array2 [N][M];\n" + "typedef int int_t, int_array[N];\n" + "array a;\n" + "array1 a1;\n" + "array2 a2;\n" + "int_t t;\n" + "int_array ia;"; + + const char expected[] = + "; " + "int a [ ice_or < is_int < int > :: value , is_int < UDT > :: value > :: value ? 1 : - 1 ] ; " + "int a1 [ N ] ; " + "int a2 [ N ] [ M ] ; " + "int t ; " + "int ia [ N ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef30() + { + const char code[] = "typedef ::std::list int_list;\n" + "typedef ::std::list::iterator int_list_iterator;\n" + "typedef ::std::list int_list_array[10];\n" + "int_list il;\n" + "int_list_iterator ili;\n" + "int_list_array ila;"; + + const char expected[] = + "; " + ":: std :: list < int > il ; " + ":: std :: list < int > :: iterator ili ; " + ":: std :: list < int > ila [ 10 ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef31() + { + { + const char code[] = "class A {\n" + "public:\n" + " typedef int INT;\n" + " INT get() const;\n" + " void put(INT x) { a = x; }\n" + " INT a;\n" + "};\n" + "A::INT A::get() const { return a; }\n" + "A::INT i = A::a;"; + + const char expected[] = "class A { " + "public: " + "; " + "int get ( ) const ; " + "void put ( int x ) { a = x ; } " + "int a ; " + "} ; " + "int A :: get ( ) const { return a ; } " + "int i ; i = A :: a ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct A {\n" + " typedef int INT;\n" + " INT get() const;\n" + " void put(INT x) { a = x; }\n" + " INT a;\n" + "};\n" + "A::INT A::get() const { return a; }\n" + "A::INT i = A::a;"; + + const char expected[] = "struct A { " + "; " + "int get ( ) const ; " + "void put ( int x ) { a = x ; } " + "int a ; " + "} ; " + "int A :: get ( ) const { return a ; } " + "int i ; i = A :: a ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef32() + { + const char code[] = "typedef char CHAR;\n" + "typedef CHAR * LPSTR;\n" + "typedef const CHAR * LPCSTR;\n" + "CHAR c;\n" + "LPSTR cp;\n" + "LPCSTR ccp;"; + + const char expected[] = + "; " + "char c ; " + "char * cp ; " + "const char * ccp ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef33() + { + const char code[] = "class A {\n" + "public:\n" + " typedef char CHAR_A;\n" + " CHAR_A funA();\n" + " class B {\n" + " public:\n" + " typedef short SHRT_B;\n" + " SHRT_B funB();\n" + " class C {\n" + " public:\n" + " typedef int INT_C;\n" + " INT_C funC();\n" + " struct D {\n" + " typedef long LONG_D;\n" + " LONG_D funD();\n" + " LONG_D d;\n" + " };\n" + " INT_C c;\n" + " };\n" + " SHRT_B b;\n" + " };\n" + " CHAR_A a;\n" + "};\n" + "A::CHAR_A A::funA() { return a; }\n" + "A::B::SHRT_B A::B::funB() { return b; }\n" + "A::B::C::INT_C A::B::C::funC() { return c; }" + "A::B::C::D::LONG_D A::B::C::D::funD() { return d; }"; + + const char expected[] = + "class A { " + "public: " + "; " + "char funA ( ) ; " + "class B { " + "public: " + "; " + "short funB ( ) ; " + "class C { " + "public: " + "; " + "int funC ( ) ; " + "struct D { " + "; " + "long funD ( ) ; " + "long d ; " + "} ; " + "int c ; " + "} ; " + "short b ; " + "} ; " + "char a ; " + "} ; " + "char A :: funA ( ) { return a ; } " + "short A :: B :: funB ( ) { return b ; } " + "int A :: B :: C :: funC ( ) { return c ; } " + "long A :: B :: C :: D :: funD ( ) { return d ; }"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef34() + { + // ticket #1411 + const char code[] = "class X { };\n" + "typedef X (*foofunc)(const X&);\n" + "int main()\n" + "{\n" + " foofunc *Foo = new foofunc[2];\n" + "}"; + const char expected[] = + "class X { } ; " + "int main ( ) " + "{ " + "X ( * * Foo ) ( const X & ) = new X ( * ) ( const X & ) [ 2 ] ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + // Check simplifyTypedef + void checkSimplifyTypedef(const char code[]) + { + errout.str(""); + // Tokenize.. + Settings settings; + settings.inconclusive = true; + settings._checkCodingStyle = true; + settings.debugwarnings = true; // show warnings about unhandled typedef + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + } + + void simplifyTypedef35() + { + const char code[] = "typedef int A;\n" + "class S\n" + "{\n" + "public:\n" + " typedef float A;\n" + " A a;\n" + " virtual void fun(A x);\n" + "};\n" + "void S::fun(S::A) { };\n" + "class S1 : public S\n" + "{\n" + "public:\n" + " void fun(S::A) { }\n" + "};\n" + "struct T\n" + "{\n" + " typedef A B;\n" + " B b;\n" + "};\n" + "float fun1(float A) { return A; }\n" + "float fun2(float a) { float A = a++; return A; }\n" + "float fun3(int a)\n" + "{\n" + " typedef struct { int a; } A;\n" + " A s; s.a = a;\n" + " return s.a;\n" + "}\n" + "int main()\n" + "{\n" + " A a = 0;\n" + " S::A s = fun1(a) + fun2(a) - fun3(a);\n" + " return a + s;\n" + "}"; + + const char expected[] = "; " + "class S " + "{ " + "public: " + "; " + "float a ; " + "virtual void fun ( float x ) ; " + "} ; " + "void S :: fun ( float ) { } ; " + "class S1 : public S " + "{ " + "public: " + "void fun ( float ) { } " + "} ; " + "struct T " + "{ " + "; " + "int b ; " + "} ; " + "float fun1 ( float A ) { return A ; } " + "float fun2 ( float a ) { float A ; A = a ++ ; return A ; } " + "float fun3 ( int a ) " + "{ " + "struct A { int a ; } ; " + "struct A s ; s . a = a ; " + "return s . a ; " + "} " + "int main ( ) " + "{ " + "int a ; a = 0 ; " + "float s ; s = fun1 ( a ) + fun2 ( a ) - fun3 ( a ) ; " + "return a + s ; " + "}"; + + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n" + "[test.cpp:20] -> [test.cpp:1]: (style) Function parameter 'A' hides typedef with same name\n" + "[test.cpp:21] -> [test.cpp:1]: (style) Variable 'A' hides typedef with same name\n" + "[test.cpp:24] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n", errout.str()); + } + + void simplifyTypedef36() + { + // ticket #1434 + const char code[] = "typedef void (*TIFFFaxFillFunc)();\n" + "void f(va_list ap)\n" + "{\n" + " *va_arg(ap, TIFFFaxFillFunc*) = 0;\n" + "}"; + const char expected[] = "; " + "void f ( va_list ap ) " + "{ " + "* va_arg ( ap , void ( * * ) ( ) ) = 0 ; " + "}"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void simplifyTypedef37() + { + { + // ticket #1449 + const char code[] = "template class V {};\n" + "typedef V A;\n" + "typedef int B;\n" + "typedef V A;\n" + "typedef int B;"; + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:2]: (style) Typedef 'A' hides typedef with same name\n" + "[test.cpp:5] -> [test.cpp:3]: (style) Typedef 'B' hides typedef with same name\n", errout.str()); + } + + { + const char code[] = "typedef int INT;\n" + "void f()\n" + "{\n" + " INT i; { }\n" + "}"; + const char expected[] = "; " + "void f ( ) " + "{ " + "int i ; { } " + "}"; + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyTypedef38() + { + const char code[] = "typedef C A;\n" + "struct AB : public A, public B { };"; + const char expected[] = "; struct AB : public C , public B { } ;"; + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef39() + { + const char code[] = "typedef int A;\n" + "template ::value;"; + const char expected[] = ";"; + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef40() + { + const char code[] = "typedef int A;\n" + "typedef int B;\n" + "template class C { };"; + const char expected[] = ";"; + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:1]: (style) Template parameter 'A' hides typedef with same name\n" + "[test.cpp:3] -> [test.cpp:2]: (style) Template parameter 'B' hides typedef with same name\n", errout.str()); + + checkSimplifyTypedef("typedef tuple t2;\n" + "void ordering_test()\n" + "{\n" + " tuple t2(5, 3.3f);\n" + " BOOST_CHECK(t3 > t2);\n" + "}"); + ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:1]: (style) Template instantiation 't2' hides typedef with same name\n", errout.str()); + + checkSimplifyTypedef("class MyOverflowingUnsigned\n" + "{\n" + "public:\n" + " typedef unsigned self_type::* bool_type;\n" + " operator bool_type() const { return this->v_ ? &self_type::v_ : 0; }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + checkSimplifyTypedef("typedef int (*fptr_type)(int, int);\n" + "struct which_one {\n" + " typedef fptr_type (*result_type)(bool x);\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + checkSimplifyTypedef("class my_configuration\n" + "{\n" + "public:\n" + " template < typename T >\n" + " class hook\n" + " {\n" + " public:\n" + " typedef ::boost::rational rational_type;\n" + " public:\n" + " rational_type ( &r_ )[ 9 ];\n" + " };\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + checkSimplifyTypedef("class A\n" + "{\n" + " typedef B b;\n" + " friend b;\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef41() + { + // ticket #1488 + checkSimplifyTypedef("class Y;\n" + "class X\n" + "{\n" + " typedef Y type;\n" + " friend class type;\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef42() + { + // ticket #1506 + checkSimplifyTypedef("typedef struct A { } A;\n" + "struct A;"); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Struct 'A' forward declaration unnecessary, already declared\n", errout.str()); + + checkSimplifyTypedef("typedef union A { int i; float f; } A;\n" + "union A;"); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Union 'A' forward declaration unnecessary, already declared\n", errout.str()); + + checkSimplifyTypedef("typedef std::map A;\n" + "class A;"); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Class 'A' forward declaration unnecessary, already declared\n", errout.str()); + } + + void simplifyTypedef43() + { + // ticket #1588 + { + const char code[] = "typedef struct foo A;\n" + "struct A\n" + "{\n" + " int alloclen;\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "struct A " + "{ " + "int alloclen ; " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Struct 'A' hides typedef with same name\n", errout.str()); + } + + { + const char code[] = "typedef union foo A;\n" + "union A\n" + "{\n" + " int alloclen;\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "union A " + "{ " + "int alloclen ; " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Union 'A' hides typedef with same name\n", errout.str()); + } + + { + const char code[] = "typedef class foo A;\n" + "class A\n" + "{\n" + " int alloclen;\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "class A " + "{ " + "int alloclen ; " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Class 'A' hides typedef with same name\n", errout.str()); + } + } + + void simplifyTypedef44() + { + { + const char code[] = "typedef std::map Map;\n" + "class MyMap : public Map\n" + "{\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "class MyMap : public std :: map < std :: string , int > " + "{ " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef std::map Map;\n" + "class MyMap : protected Map\n" + "{\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "class MyMap : protected std :: map < std :: string , int > " + "{ " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef std::map Map;\n" + "class MyMap : private Map\n" + "{\n" + "};\n"; + + // The expected result.. + const std::string expected("; " + "class MyMap : private std :: map < std :: string , int > " + "{ " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef struct foo { } A;\n" + "struct MyA : public A\n" + "{\n" + "};\n"; + + // The expected result.. + const std::string expected("struct foo { } ; " + "struct MyA : public foo " + "{ " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef class foo { } A;\n" + "class MyA : public A\n" + "{\n" + "};\n"; + + // The expected result.. + const std::string expected("class foo { } ; " + "class MyA : public foo " + "{ " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedef45() + { + // ticket # 1613 + const char code[] = "void fn() {\n" + " typedef foo<> bar;\n" + " while (0 > bar(1)) {}\n" + "}"; + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef46() + { + const char code[] = "typedef const struct A { int a; } * AP;\n" + "AP ap;\n"; + + // The expected result.. + const std::string expected("struct A { int a ; } ; " + "const struct A * ap ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef47() + { + { + const char code[] = "typedef std::pair const I;\n" + "I i;"; + + // The expected result.. + const std::string expected("; " + "std :: pair < int , int > const i ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + { + const char code[] = "typedef void (X:: *F)();\n" + "F f;"; + + // The expected result.. + const std::string expected("; " + "void ( X :: * f ) ( ) ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + } + + void simplifyTypedef48() // ticket #1673 + { + const char code[] = "typedef struct string { } string;\n" + "void foo (LIST *module_name)\n" + "{\n" + " bar(module_name ? module_name->string : 0);\n" + "}\n"; + + // The expected result.. + const std::string expected("struct string { } ; " + "void foo ( LIST * module_name ) " + "{ " + "bar ( module_name ? module_name . string : 0 ) ; " + "}"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef49() // ticket #1691 + { + const char code[] = "class Class2 {\n" + "typedef const Class & Const_Reference;\n" + "void some_method (Const_Reference x) const {}\n" + "void another_method (Const_Reference x) const {}\n" + "}"; + + // The expected result.. + const std::string expected("class Class2 { " + "; " + "void some_method ( const Class & x ) const { } " + "void another_method ( const Class & x ) const { } " + "}"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef50() + { + const char code[] = "typedef char (* type1)[10];\n" + "typedef char (& type2)[10];\n" + "typedef char (& type3)[x];\n" + "typedef char (& type4)[x + 2];\n" + "type1 t1;\n" + "type1 (*tp1)[2];\n" + "type2 t2;\n" + "type3 t3;\n" + "type4 t4;"; + + // The expected result.. + const std::string expected("; " + "char ( * t1 ) [ 10 ] ; " + "char ( * ( * tp1 ) [ 2 ] ) [ 10 ] ; " + "char ( & t2 ) [ 10 ] ; " + "char ( & t3 ) [ x ] ; " + "char ( & t4 ) [ x + 2 ] ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef51() + { + const char code[] = "class A { public: int i; };\n" + "typedef const char (A :: * type1);\n" + "type1 t1 = &A::i;"; + + // The expected result.. + const std::string expected("class A { public: int i ; } ; " + "const char ( A :: * t1 ) = & A :: i ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef52() // ticket #1782 + { + { + const char code[] = "typedef char (* type1)[10];\n" + "type1 foo() { }"; + + // The expected result.. + const std::string expected("; " + "char ( * foo ( ) ) [ 10 ] { }"); + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef char (* type1)[10];\n" + "LOCAL(type1) foo() { }"; + + // this is invalid C so just make sure it doesn't generate an internal error + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedef53() // ticket #1801 + { + { + const char code[] = "typedef int ( * int ( * ) ( ) ) ( ) ;"; + + // this is invalid C so just make sure it doesn't crash + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:1]: (debug) Failed to parse 'typedef int ( * int ( * ) ( ) ) ( ) ;'. The checking continues anyway.\n", errout.str()); + } + + { + const char code[] = "typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);\n" + "typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);\n"; + + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Typedef 'PPDMarkOption' hides typedef with same name\n", errout.str()); + } + + { + const char code[] = "typedef int * A;\n" + "typedef int * A;\n"; + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Typedef 'A' hides typedef with same name\n", errout.str()); + } + } + + void simplifyTypedef54() // ticket #1814 + { + const char code[] = "void foo()\n" + "{\n" + " typedef std::basic_string string_type;\n" + " try\n" + " {\n" + " throw string_type(\"leak\");\n" + " }\n" + " catch (const string_type&)\n" + " {\n" + " pthread_exit (0);\n" + " }\n" + "}"; + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef55() + { + const char code[] = "typedef volatile unsigned long * const hwreg_t ;\n" + "typedef void *const t1[2];\n" + "typedef int*const *_Iterator;\n" + "hwreg_t v1;\n" + "t1 v2;\n" + "_Iterator v3;\n"; + + // The expected result.. + const std::string expected("; " + "long * v1 ; " + "void * v2 [ 2 ] ; " + "int * * v3 ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef56() // ticket #1829 + { + const char code[] = "struct C {\n" + " typedef void (*fptr)();\n" + " const fptr pr;\n" + " operator const fptr& () { return pr; }\n" + "};\n"; + + // The expected result.. + const std::string expected("struct C { " + "; " + "const void * pr ; " // this gets simplified to a regular pointer + "operatorconstvoid(*)()& ( ) { return pr ; } " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef57() // ticket #1846 + { + const char code[] = "void foo {\n" + " typedef int A;\n" + " A a = A(1) * A(2);\n" + "};\n"; + + // The expected result.. + const std::string expected("void foo { " + "; " + "int a ; a = int ( 1 ) * int ( 2 ) ; " + "} ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef58() // ticket #1963 + { + { + const char code[] = "typedef int vec2_t[2];\n" + "vec2_t coords[4] = {1,2,3,4,5,6,7,8};\n"; + + // The expected result.. + const std::string expected("; " + "int coords [ 4 ] [ 2 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef int vec2_t[2];\n" + "vec2_t coords[4][5][6+1] = {1,2,3,4,5,6,7,8};\n"; + + // The expected result.. + const std::string expected("; " + "int coords [ 4 ] [ 5 ] [ 7 ] [ 2 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedef59() // ticket #2011 + { + const char code[] = "template class SomeTemplateClass {\n" + " typedef void (SomeTemplateClass::*MessageDispatcherFunc)(SerialInputMessage&);\n" + "};\n"; + // The expected result.. + const std::string expected(";"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef60() // ticket #2035 + { + const char code[] = "typedef enum {qfalse, qtrue} qboolean;\n" + "typedef qboolean (*localEntitiyAddFunc_t) (struct le_s * le, entity_t * ent);\n" + "void f()\n" + "{\n" + " qboolean b;\n" + " localEntitiyAddFunc_t f;\n" + "}\n"; + // The expected result.. + const std::string expected("; void f ( ) { int b ; int * f ; }"); + ASSERT_EQUALS(expected, sizeof_(code, false)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef61() // ticket #2074 and 2075 + { + const char code1[] = "typedef unsigned char (*Mf_GetIndexByte_Func) (void);\n" + "typedef const unsigned char * (*Mf_GetPointerToCurrentPos_Func)(void);\n"; + + // Check for output.. + checkSimplifyTypedef(code1); + ASSERT_EQUALS("", errout.str()); + + const char code2[] = "typedef unsigned long uint32_t;\n" + "typedef uint32_t (*write_type_t) (uint32_t);\n"; + + // Check for output.. + checkSimplifyTypedef(code2); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef62() // ticket #2082 + { + const char code1[] = "typedef char TString[256];\n" + "void f()\n" + "{\n" + " TString a, b;\n" + "}"; + + // The expected tokens.. + const std::string expected1("; void f ( ) { char a [ 256 ] ; char b [ 256 ] ; }"); + ASSERT_EQUALS(expected1, sizeof_(code1, false)); + + // Check for output.. + checkSimplifyTypedef(code1); + ASSERT_EQUALS("", errout.str()); + + const char code2[] = "typedef char TString[256];\n" + "void f()\n" + "{\n" + " TString a = { 0 }, b = { 0 };\n" + "}"; + + // The expected tokens.. + const std::string expected2("; void f ( ) { char a [ 256 ] = { 0 } ; char b [ 256 ] = { 0 } ; }"); + ASSERT_EQUALS(expected2, tok(code2, false)); + + // Check for output.. + checkSimplifyTypedef(code2); + ASSERT_EQUALS("", errout.str()); + + const char code3[] = "typedef char TString[256];\n" + "void f()\n" + "{\n" + " TString a = \"\", b = \"\";\n" + "}"; + + // The expected tokens.. + const std::string expected3("; void f ( ) { char a [ 256 ] = \"\" ; char b [ 256 ] = \"\" ; }"); + ASSERT_EQUALS(expected3, tok(code3, false)); + + // Check for output.. + checkSimplifyTypedef(code3); + ASSERT_EQUALS("", errout.str()); + + const char code4[] = "typedef char TString[256];\n" + "void f()\n" + "{\n" + " TString a = \"1234\", b = \"5678\";\n" + "}"; + + // The expected tokens.. + const std::string expected4("; void f ( ) { char a [ 256 ] = \"1234\" ; char b [ 256 ] = \"5678\" ; }"); + ASSERT_EQUALS(expected4, tok(code4, false)); + + // Check for output.. + checkSimplifyTypedef(code4); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef63() // ticket #2175 'typedef float x[3];' + { + const char code[] = "typedef float x[3];\n" + "x a,b,c;\n"; + const std::string actual(sizeof_(code)); + ASSERT_EQUALS("; float a [ 3 ] ; float b [ 3 ] ; float c [ 3 ] ;", actual); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef64() + { + const char code[] = "typedef __typeof__(__type1() + __type2()) __type;" + "__type t;\n"; + const std::string actual(sizeof_(code)); + ASSERT_EQUALS("; __typeof__ ( __type1 ( ) + __type2 ( ) ) t ;", actual); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef65() // ticket #2314 + { + const char code[] = "typedef BAR Foo; \n" + "int main() { \n" + " Foo b(0); \n" + " return b > Foo(10); \n" + "}"; + const std::string actual(sizeof_(code)); + ASSERT_EQUALS("; int main ( ) { BAR < int > b ( 0 ) ; return b > BAR < int > ( 10 ) ; }", actual); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef66() // ticket #2341 + { + const char code[] = "typedef long* GEN;\n" + "extern GEN (*foo)(long);"; + const std::string actual(sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef67() // ticket #2354 + { + const char code[] = "typedef int ( * Function ) ( ) ;\n" + "void f ( ) {\n" + " ((Function * (*) (char *, char *, int, int)) global[6]) ( \"assoc\", \"eggdrop\", 106, 0);\n" + "}\n"; + const std::string expected = "; " + "void f ( ) { " + "( ( int ( * * ( * ) ( char * , char * , int , int ) ) ( ) ) global [ 6 ] ) ( \"assoc\" , \"eggdrop\" , 106 , 0 ) ; " + "}"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef68() // ticket #2355 + { + const char code[] = "typedef FMAC1 void (* a) ();\n" + "void *(*b) ();\n"; + const std::string actual(sizeof_(code)); + ASSERT_EQUALS("; void * * b ;", actual); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef69() // ticket #2348 + { + const char code[] = "typedef int (*CompilerHook)();\n" + "typedef struct VirtualMachine \n" + "{\n" + " CompilerHook *(*compilerHookVector)(void);\n" + "}VirtualMachine;\n"; + const std::string expected = "; " + "struct VirtualMachine " + "{ " + "int ( * * ( * compilerHookVector ) ( void ) ) ( ) ; " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef70() // ticket #2348 + { + const char code[] = "typedef int pread_f ( int ) ;\n" + "pread_f *(*test_func)(char *filename);\n"; + const std::string expected = "; " + "int ( * ( * test_func ) ( char * filename ) ) ( int ) ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef71() // ticket #2348 + { + { + const char code[] = "typedef int RexxFunctionHandler();\n" + "RexxFunctionHandler *(efuncs[1]);\n"; + const std::string expected = "; " + "int ( * ( efuncs [ 1 ] ) ) ( ) ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + { + const char code[] = "typedef int RexxFunctionHandler();\n" + "RexxFunctionHandler *(efuncs[]) = { NULL, NULL };\n"; + const std::string expected = "; " + "int ( * ( efuncs [ ] ) ) ( ) = { 0 , 0 } ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedef72() // ticket #2374 + { + // inline operator + { + const char code[] = "class Fred {\n" + " typedef int* (Fred::*F);\n" + " operator F() const { }\n" + "};\n"; + const std::string expected = "class Fred { " + "; " + "operatorint** ( ) const { } " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + // inline local variable + { + const char code[] = "class Fred {\n" + " typedef int INT;\n" + " void f1() const { INT i; }\n" + "};\n"; + const std::string expected = "class Fred { " + "; " + "void f1 ( ) const { int i ; } " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + // out of line member variable + { + const char code[] = "class Fred {\n" + " typedef int INT;\n" + " void f1() const;\n" + "};\n" + "void Fred::f1() const { INT i; f(i); }\n"; + const std::string expected = "class Fred { " + "; " + "void f1 ( ) const ; " + "} ; " + "void Fred :: f1 ( ) const { int i ; f ( i ) ; }"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + // out of line operator + { + const char code[] = "class Fred {\n" + " typedef int* (Fred::*F);\n" + " operator F() const;\n" + "};\n" + "Fred::operator F() const { }\n"; + const std::string expected = "class Fred { " + "; " + "operatorint** ( ) const ; " + "} ; " + "Fred :: operatorint** ( ) const { }"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedef73() // ticket #2412 + { + const char code[] = "struct B {};\n" + "typedef struct A : public B {\n" + " void f();\n" + "} a, *aPtr;\n"; + const std::string expected = "struct B { } ; " + "struct A : public B { " + "void f ( ) ; " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef74() // ticket #2414 + { + const char code[] = "typedef long (*state_func_t)(void);\n" + "typedef state_func_t (*state_t)(void);\n" + "state_t current_state = death;\n" + "static char get_runlevel(const state_t);\n"; + const std::string expected = "; " + "long ( * ( * current_state ) ( void ) ) ( void ) = death ; " + "static char get_runlevel ( const long ( * ( * ) ( void ) ) ( void ) ) ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef75() // ticket #2426 + { + const char code[] = "typedef _Packed struct S { long l; }; \n"; + const std::string expected = ";"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef76() // ticket #2453 segmentation fault + { + const char code[] = "void f1(typedef int x) {}\n"; + const std::string expected = "void f1 ( typedef int x ) { }"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); + } + + void simplifyTypedef77() // ticket #2554 + { + const char code[] = "typedef char Str[10]; int x = sizeof(Str);\n"; + const std::string expected = "; int x ; x = 10 ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef78() // ticket #2568 + { + const char code[] = "typedef struct A A_t;\n" + "A_t a;\n" + "typedef struct A { } A_t;\n" + "A_t a1;\n"; + const std::string expected = "; struct A a ; struct A { } ; struct A a1 ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef79() // ticket #2348 + { + const char code[] = "typedef int (Tcl_ObjCmdProc) (int x);\n" + "typedef struct LangVtab\n" + "{\n" + " Tcl_ObjCmdProc * (*V_LangOptionCommand);\n" + "} LangVtab;\n"; + const std::string expected = "; " + "struct LangVtab " + "{ " + "int ( * ( * V_LangOptionCommand ) ) ( int x ) ; " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedef80() // ticket #2587 + { + const char code[] = "typedef struct s { };\n" + "void f() {\n" + " sizeof(struct s);\n" + "};\n"; + const std::string expected = "struct s { } ; " + "void f ( ) { " + "sizeof ( struct s ) ; " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef81() // ticket #2603 segmentation fault + { + checkSimplifyTypedef("typedef\n"); + ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); + + checkSimplifyTypedef("typedef constexpr\n"); + ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); + } + + void simplifyTypedef82() // ticket #2403 + { + checkSimplifyTypedef("class A {\n" + "public:\n" + " typedef int F(int idx);\n" + "};\n" + "class B {\n" + "public:\n" + " A::F ** f;\n" + "};\n" + "int main()\n" + "{\n" + " B * b = new B;\n" + " b->f = new A::F * [ 10 ];\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedef83() // ticket #2620 + { + const char code[] = "typedef char Str[10];\n" + "void f(Str &cl) { }\n"; + + // The expected result.. + const std::string expected("; " + "void f ( char ( & cl ) [ 10 ] ) { }"); + + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedefFunction1() + { + { + const char code[] = "typedef void (*my_func)();\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (*my_func)(void);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( void ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (*my_func)(int);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (*my_func)(int*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + // ticket # 1615 + const char code[] = "typedef void (*my_func)(arg_class*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + + { + const char code[] = "typedef void (my_func)();\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func)(void);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( void ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func)(int);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func)(int*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func)(arg_class*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + + { + const char code[] = "typedef void my_func();\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void my_func(void);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( void ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void my_func(int);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void my_func(int*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void my_func(arg_class*);\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + + { + const char code[] = "typedef void (my_func());\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func(void));\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( void ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func(int));\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func(int*));\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( int * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef void (my_func(arg_class*));\n" + "std::queue func_queue;"; + + // The expected result.. + const std::string expected("; " + "std :: queue < void ( * ) ( arg_class * ) > func_queue ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedefFunction2() // ticket #1685 + { + const char code[] = "typedef void voidfn (int);\n" + "voidfn xxx;"; + + // The expected result.. + const std::string expected("; " + "void xxx ( int ) ;"); + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void simplifyTypedefFunction3() + { + { + const char code[] = "typedef C func1();\n" + "typedef C (* func2)();\n" + "typedef C (& func3)();\n" + "typedef C (C::* func4)();\n" + "typedef C (C::* func5)() const;\n" + "typedef C (C::* func6)() volatile;\n" + "typedef C (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + const std::string expected("; " + "C f1 ( ) ; " + "C * f2 ; " // this gets simplified to a regular pointer + "C ( & f3 ) ( ) ; " + "C ( C :: * f4 ) ( ) ; " + "C ( C :: * f5 ) ( ) const ; " + "C ( C :: * f6 ) ( ) ; " // volatile is removed + "C ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef C const func1();\n" + "typedef C const (* func2)();\n" + "typedef C const (& func3)();\n" + "typedef C const (C::* func4)();\n" + "typedef C const (C::* func5)() const;\n" + "typedef C const (C::* func6)() volatile;\n" + "typedef C const (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + // C const -> const C + const std::string expected("; " + "const C f1 ( ) ; " + "const C * f2 ; " // this gets simplified to a regular pointer + "const C ( & f3 ) ( ) ; " + "const C ( C :: * f4 ) ( ) ; " + "const C ( C :: * f5 ) ( ) const ; " + "const C ( C :: * f6 ) ( ) ; " // volatile is removed + "const C ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef const C func1();\n" + "typedef const C (* func2)();\n" + "typedef const C (& func3)();\n" + "typedef const C (C::* func4)();\n" + "typedef const C (C::* func5)() const;\n" + "typedef const C (C::* func6)() volatile;\n" + "typedef const C (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + const std::string expected("; " + "const C f1 ( ) ; " + "const C * f2 ; " // this gets simplified to a regular pointer + "const C ( & f3 ) ( ) ; " + "const C ( C :: * f4 ) ( ) ; " + "const C ( C :: * f5 ) ( ) const ; " + "const C ( C :: * f6 ) ( ) ; " // volatile is removed + "const C ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef C * func1();\n" + "typedef C * (* func2)();\n" + "typedef C * (& func3)();\n" + "typedef C * (C::* func4)();\n" + "typedef C * (C::* func5)() const;\n" + "typedef C * (C::* func6)() volatile;\n" + "typedef C * (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + const std::string expected("; " + "C * f1 ( ) ; " + "C * * f2 ; " // this gets simplified to a regular pointer + "C * ( & f3 ) ( ) ; " + "C * ( C :: * f4 ) ( ) ; " + "C * ( C :: * f5 ) ( ) const ; " + "C * ( C :: * f6 ) ( ) ; " // volatile is removed + "C * ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef const C * func1();\n" + "typedef const C * (* func2)();\n" + "typedef const C * (& func3)();\n" + "typedef const C * (C::* func4)();\n" + "typedef const C * (C::* func5)() const;\n" + "typedef const C * (C::* func6)() volatile;\n" + "typedef const C * (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + const std::string expected("; " + "const C * f1 ( ) ; " + "const C * * f2 ; " // this gets simplified to a regular pointer + "const C * ( & f3 ) ( ) ; " + "const C * ( C :: * f4 ) ( ) ; " + "const C * ( C :: * f5 ) ( ) const ; " + "const C * ( C :: * f6 ) ( ) ; " // volatile is removed + "const C * ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + { + const char code[] = "typedef C const * func1();\n" + "typedef C const * (* func2)();\n" + "typedef C const * (& func3)();\n" + "typedef C const * (C::* func4)();\n" + "typedef C const * (C::* func5)() const;\n" + "typedef C const * (C::* func6)() volatile;\n" + "typedef C const * (C::* func7)() const volatile;\n" + "func1 f1;\n" + "func2 f2;\n" + "func3 f3;\n" + "func4 f4;\n" + "func5 f5;\n" + "func6 f6;\n" + "func7 f7;"; + + // The expected result.. + // C const -> const C + const std::string expected("; " + "const C * f1 ( ) ; " + "const C * * f2 ; " // this gets simplified to a regular pointer + "const C * ( & f3 ) ( ) ; " + "const C * ( C :: * f4 ) ( ) ; " + "const C * ( C :: * f5 ) ( ) const ; " + "const C * ( C :: * f6 ) ( ) ; " // volatile is removed + "const C * ( C :: * f7 ) ( ) const ;"); // volatile is removed + ASSERT_EQUALS(expected, sizeof_(code)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + } + + void simplifyTypedefFunction4() + { + const char code[] = "typedef int ( * ( * type1 ) ( bool ) ) ( int , int ) ;\n" + "typedef int ( * ( type2 ) ( bool ) ) ( int , int ) ;\n" + "typedef int ( * type3 ( bool ) ) ( int , int ) ;\n" + "type1 t1;\n" + "type2 t2;\n" + "type3 t3;"; + + // The expected result.. + const std::string expected("; " + "int ( * ( * t1 ) ( bool ) ) ( int , int ) ; " + "int ( * t2 ( bool ) ) ( int , int ) ; " + "int ( * t3 ( bool ) ) ( int , int ) ;"); + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedefFunction5() + { + const char code[] = "typedef int ( * type1 ) ( float ) ;\n" + "typedef int ( * const type2 ) ( float ) ;\n" + "typedef int ( * volatile type3 ) ( float ) ;\n" + "typedef int ( * const volatile type4 ) ( float ) ;\n" + "typedef int ( C :: * type5 ) ( float ) ;\n" + "typedef int ( C :: * const type6 ) ( float ) ;\n" + "typedef int ( C :: * volatile type7 ) ( float ) ;\n" + "typedef int ( C :: * const volatile type8 ) ( float ) ;\n" + "typedef int ( :: C :: * type9 ) ( float ) ;\n" + "typedef int ( :: C :: * const type10 ) ( float ) ;\n" + "typedef int ( :: C :: * volatile type11 ) ( float ) ;\n" + "typedef int ( :: C :: * const volatile type12 ) ( float ) ;\n" + "type1 t1;\n" + "type2 t2;\n" + "type3 t3;\n" + "type4 t4;\n" + "type5 t5;\n" + "type6 t6;\n" + "type7 t7;\n" + "type8 t8;\n" + "type9 t9;\n" + "type10 t10;\n" + "type11 t11;\n" + "type12 t12;"; + + // The expected result.. + const std::string expected("; " + "int * t1 ; " // simplified to regular pointer + "int ( * const t2 ) ( float ) ; " + "int * t3 ; " // volatile removed, gets simplified to regular pointer + "int ( * const t4 ) ( float ) ; " // volatile removed + "int ( C :: * t5 ) ( float ) ; " + "int ( C :: * const t6 ) ( float ) ; " + "int ( C :: * t7 ) ( float ) ; " // volatile removed + "int ( C :: * const t8 ) ( float ) ; " // volatile removed + "int ( :: C :: * t9 ) ( float ) ; " + "int ( :: C :: * const t10 ) ( float ) ; " + "int ( :: C :: * t11 ) ( float ) ; " // volatile removed + "int ( :: C :: * const t12 ) ( float ) ;"); // volatile removed + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedefFunction6() + { + const char code[] = "typedef void (*testfp)();\n" + "struct Fred\n" + "{\n" + " testfp get1() { return 0; }\n" + " void ( * get2 ( ) ) ( ) { return 0 ; }\n" + " testfp get3();\n" + " void ( * get4 ( ) ) ( );\n" + "};\n" + "testfp Fred::get3() { return 0; }\n" + "void ( * Fred::get4 ( ) ) ( ) { return 0 ; }\n"; + + // The expected result.. + const std::string expected("; " + "struct Fred " + "{ " + "void ( * get1 ( ) ) ( ) { return 0 ; } " + "void ( * get2 ( ) ) ( ) { return 0 ; } " + "void ( * get3 ( ) ) ( ) ; " + "void ( * get4 ( ) ) ( ) ; " + "} ; " + "void ( * Fred :: get3 ( ) ) ( ) { return 0 ; } " + "void ( * Fred :: get4 ( ) ) ( ) { return 0 ; }"); + + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedefFunction7() + { + const char code[] = "typedef void ( __gnu_cxx :: _SGIAssignableConcept < _Tp > :: * _func_Tp_SGIAssignableConcept ) () ;" + "_func_Tp_SGIAssignableConcept X;\n"; + + // The expected result.. + const std::string expected("; " + "void ( __gnu_cxx :: _SGIAssignableConcept < _Tp > :: * X ) ( ) ;"); + + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyTypedefFunction8() + { + // #2376 - internal error + const char code[] = "typedef int f_expand(const nrv_byte *);\n" + "void f(f_expand *(*get_fexp(int))){}\n"; + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); // make sure that there is no internal error + } + + void reverseArraySyntax() + { + ASSERT_EQUALS("a [ 13 ]", tok("13[a]")); + } + + void simplify_numeric_condition() + { + { + const char code[] = + "void f()\n" + "{\n" + "int x = 0;\n" + "if( !x || 0 )\n" + "{ g();\n" + "}\n" + "}"; + + ASSERT_EQUALS("void f ( ) { ; { g ( ) ; } }", tok(code)); + } + + { + const char code[] = + "void f()\n" + "{\n" + "int x = 1;\n" + "if( !x )\n" + "{ g();\n" + "}\n" + "}"; + + ASSERT_EQUALS("void f ( ) { ; }", tok(code)); + } + + { + const char code[] = + "void f()\n" + "{\n" + "bool x = true;\n" + "if( !x )\n" + "{ g();\n" + "}\n" + "}"; + + ASSERT_EQUALS("void f ( ) { ; }", tok(code)); + } + + { + const char code[] = + "void f()\n" + "{\n" + "bool x = false;\n" + "if( !x )\n" + "{ g();\n" + "}\n" + "}"; + + ASSERT_EQUALS("void f ( ) { ; { g ( ) ; } }", tok(code)); + } + + { + const char code[] = "void f()\n" + "{\n" + " if (5==5);\n" + "}\n"; + + ASSERT_EQUALS("void f ( ) { { ; } }", tok(code)); + } + + { + const char code[] = "void f()\n" + "{\n" + " if (4<5);\n" + "}\n"; + + ASSERT_EQUALS("void f ( ) { { ; } }", tok(code)); + } + + { + const char code[] = "void f()\n" + "{\n" + " if (5<5);\n" + "}\n"; + + ASSERT_EQUALS("void f ( ) { }", tok(code)); + } + + { + const char code[] = "void f()\n" + "{\n" + " if (13>12?true:false);\n" + "}\n"; + + ASSERT_EQUALS("void f ( ) { { ; } }", tok(code)); + } + } + + void simplify_condition() + { + { + const char code[] = + "void f(int a)\n" + "{\n" + "if (a && false) g();\n" + "}"; + ASSERT_EQUALS("void f ( int a ) { }", tok(code)); + } + + { + const char code[] = + "void f(int a)\n" + "{\n" + "if (false && a) g();\n" + "}"; + ASSERT_EQUALS("void f ( int a ) { }", tok(code)); + } + + { + const char code[] = + "void f(int a)\n" + "{\n" + "if (true || a) g();\n" + "}"; + ASSERT_EQUALS("void f ( int a ) { { g ( ) ; } }", tok(code)); + } + + { + const char code[] = + "void f(int a)\n" + "{\n" + "if (a || true) g();\n" + "}"; + ASSERT_EQUALS("void f ( int a ) { { g ( ) ; } }", tok(code)); + } + } + + + void pointeralias1() + { + { + const char code[] = "void f()\n" + "{\n" + " char buf[100];\n" + " char *p = buf;\n" + " free(p);\n" + "}\n"; + + const char expected[] = "void f ( ) " + "{ " + "char buf [ 100 ] ; " + "free ( buf ) ; " + "}"; + + ASSERT_EQUALS(expected, tok(code)); + } + + { + const char code[] = "void f(char *p1)\n" + "{\n" + " char *p = p1;\n" + " p1 = 0;" + " x(p);\n" + "}\n"; + + const char expected[] = "void f ( char * p1 ) " + "{ " + "char * p ; p = p1 ; " + "p1 = 0 ; " + "x ( p ) ; " + "}"; + + ASSERT_EQUALS(expected, tok(code)); + } + + { + const char code[] = "void foo(Result* ptr)\n" + "{\n" + " Result* obj = ptr;\n" + " ++obj->total;\n" + "}\n"; + + const char expected[] = "void foo ( Result * ptr ) " + "{ " + "Result * obj ; obj = ptr ; " + "++ obj . total ; " + "}"; + + ASSERT_EQUALS(expected, tok(code)); + } + + { + const char code[] = "int *foo()\n" + "{\n" + " int a[10];\n" + " int *b = a;\n" + " return b;\n" + "}\n"; + + const char expected[] = "int * foo ( ) " + "{ " + "int a [ 10 ] ; " + "return a ; " + "}"; + + ASSERT_EQUALS(expected, tok(code)); + } + + { + const char code[] = "void f() {\n" + " int a[10];\n" + " int *b = a;\n" + " memset(b,0,sizeof(a));\n" + "}"; + + const char expected[] = "void f ( ) {" + " int a [ 10 ] ;" + " memset ( a , 0 , 40 ) ; " + "}"; + + ASSERT_EQUALS(expected, tok(code)); + } + } + + void pointeralias2() + { + const char code[] = "void f()\n" + "{\n" + " int i;\n" + " int *p = &i;\n" + " return *p;\n" + "}\n"; + ASSERT_EQUALS("void f ( ) { int i ; return i ; }", tok(code)); + } + + void pointeralias3() + { + const char code[] = "void f()\n" + "{\n" + " int i, j, *p;\n" + " if (ab) p = &i;\n" + " else p = &j;\n" + " *p = 0;\n" + "}\n"; + const char expected[] = "void f ( ) " + "{" + " int i ; int j ; int * p ;" + " if ( ab ) { p = & i ; }" + " else { p = & j ; }" + " * p = 0 ; " + "}"; + ASSERT_EQUALS(expected, tok(code)); + } + + void pointeralias4() + { + const char code[] = "void f()\n" + "{\n" + " int a[10];\n" + " int *p = &a[0];\n" + " *p = 0;\n" + "}\n"; + const char expected[] = "void f ( ) " + "{" + " int a [ 10 ] ;" + " int * p ; p = & a [ 0 ] ;" + " * a = 0 ; " + "}"; + ASSERT_EQUALS(expected, tok(code)); + } + + void pointeralias5() + { + const char code[] = "int f()\n" + "{\n" + " int i;\n" + " int *p = &i;\n" + " *p = 5;\n" + " return i;\n" + "}\n"; + const char expected[] = "int f ( ) " + "{" + " ; return 5 ; " + "}"; + ASSERT_EQUALS(expected, tok(code)); + } + + void reduceConstness() + { + ASSERT_EQUALS("char * p ;", tok("char * const p;")); + } + + void while0() + { + ASSERT_EQUALS("; x = 1 ;", tok("; do { x = 1 ; } while (0);")); + ASSERT_EQUALS("; do { continue ; } while ( false ) ;", tok("; do { continue ; } while (0);")); + ASSERT_EQUALS("; do { break ; } while ( false ) ;", tok("; do { break; } while (0);")); + ASSERT_EQUALS(";", tok("; while (false) { a; }")); + + // for (condition is always false) + ASSERT_EQUALS("void f ( ) { ; }", tok("void f() { int i; for (i = 0; i < 0; i++) { a; } }")); + } + + void while1() + { + // ticket #1197 + const char code[] = "void do {} while (0) { }"; + const char expected[] = "void { }"; + ASSERT_EQUALS(expected, tok(code)); + } + + void enum1() + { + const char code[] = "enum A { a, b, c }; A c1 = c;"; + const char expected[] = "; int c1 ; c1 = 2 ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum2() + { + const char code[] = "enum A { a, }; int array[a];"; + const char expected[] = "; int array [ 0 ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum3() + { + const char code[] = "enum { a, }; int array[a];"; + const char expected[] = "; int array [ 0 ] ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum4() + { + { + const char code[] = "class A {\n" + "public:\n" + " enum EA { a1, a2, a3 };\n" + " EA get() const;\n" + " void put(EA a) { ea = a; ea = a1; }\n" + "private:\n" + " EA ea;\n" + "};\n" + "A::EA A::get() const { return ea; }\n" + "A::EA e = A::a1;"; + + const char expected[] = "class A { " + "public: " + "; " + "int get ( ) const ; " + "void put ( int a ) { ea = a ; ea = 0 ; } " + "private: " + "int ea ; " + "} ; " + "int A :: get ( ) const { return ea ; } " + "int e ; e = 0 ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct A {\n" + " enum EA { a1, a2, a3 };\n" + " EA get() const;\n" + " void put(EA a) { ea = a; ea = a1; }\n" + " EA ea;\n" + "};\n" + "A::EA A::get() const { return ea; }\n" + "A::EA e = A::a1;"; + + const char expected[] = "struct A { " + "; " + "int get ( ) const ; " + "void put ( int a ) { ea = a ; ea = 0 ; } " + "int ea ; " + "} ; " + "int A :: get ( ) const { return ea ; } " + "int e ; e = 0 ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void enum5() + { + const char code[] = "enum ABC {\n" + " a = sizeof(int),\n" + " b = 1 + a,\n" + " c = b + 100,\n" + " d,\n" + " e,\n" + " f = 90,\n" + " g\n" + "};\n" + "int sum = a + b + c + d + e + f + g;"; + const char expected[] = "; " + "int sum ; sum = " + "sizeof ( int ) + " + "1 + sizeof ( int ) + " + "1 + sizeof ( int ) + 100 + " + "1 + sizeof ( int ) + 100 + 1 + " + "1 + sizeof ( int ) + 100 + 2 + " + "90 + " + "91 ;"; + + ASSERT_EQUALS(expected, tok(code, false)); + ASSERT_EQUALS("; int sum ; sum = 508 ;", tok(code, true)); + } + + void enum6() + { + const char code[] = "enum { a = MAC(A, B, C) }; void f(a) { }"; + const char expected[] = "; void f ( MAC ( A , B , C ) ) { }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum7() + { + { + // ticket 1388 + const char code[] = "enum FOO {A,B,C};\n" + "int main()\n" + "{\n" + " int A = B;\n" + " { float A = C; }\n" + "}"; + const char expected[] = "; " + "int main ( ) " + "{ " + "int A ; A = 1 ; " + "{ float A ; A = 2 ; } " + "}"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum FOO {A,B,C};\n" + "void f(int A, float B, char C) { }"; + const char expected[] = "; " + "void f ( int A , float B , char C ) { }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + // Check simplifyEnum + void checkSimplifyEnum(const char code[]) + { + errout.str(""); + // Tokenize.. + Settings settings; + settings.inconclusive = true; + settings._checkCodingStyle = true; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + tokenizer.simplifyTokenList(); + } + + void enum8() + { + // ticket 1388 + checkSimplifyEnum("enum Direction {N=100,E,S,W,ALL};\n" + "template class EF_Vector{\n" + " T v_v[S];\n" + "\n" + "public:\n" + " EF_Vector();\n" + " explicit EF_Vector(const T &);\n" + " explicit EF_Vector(const T arr[S]);\n" + "};\n" + "\n" + "template\n" + "EF_Vector::EF_Vector()\n" + "{\n" + "}\n" + "\n" + "template\n" + "EF_Vector::EF_Vector(const T &t)\n" + "{\n" + " for(int i=0;i\n" + "EF_Vector::EF_Vector(const T arr[S])\n" + "{\n" + " for(int i=0;i d;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n" + "[test.cpp:11] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n" + "[test.cpp:16] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n" + "[test.cpp:23] -> [test.cpp:1]: (style) Template parameter 'S' hides enumerator with same name\n", errout.str()); + } + + void enum9() + { + // ticket 1404 + checkSimplifyEnum("class XX {\n" + "public:\n" + "static void Set(const int &p){m_p=p;}\n" + "static int m_p;\n" + "};\n" + "int XX::m_p=0;\n" + "int main() {\n" + " enum { XX };\n" + " XX::Set(std::numeric_limits::digits());\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void enum10() + { + // ticket 1445 + const char code[] = "enum {\n" + "SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1, \n" + "} e = SHELL_SIZE;"; + const char expected[] = "; int e ; e = sizeof ( union { int i ; char * cp ; double d ; } ) - 1 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyEnum(code); + ASSERT_EQUALS("", errout.str()); + } + + void enum11() + { + const char code[] = "int main()\n" + "{\n" + " enum { u, v };\n" + " A u = 1, v = 2;\n" + "}"; + const char expected[] = "int main ( ) " + "{ " + "; " + "A u ; u = 1 ; A v ; v = 2 ; " + "}"; + ASSERT_EQUALS(expected, tok(code, false)); + + checkSimplifyEnum(code); + ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (style) Variable 'u' hides enumerator with same name\n" + "[test.cpp:4] -> [test.cpp:3]: (style) Variable 'v' hides enumerator with same name\n", errout.str()); + } + + void enum12() + { + const char code[] = "enum fred { a, b };\n" + "void foo()\n" + "{\n" + " unsigned int fred = 0;\n" + "}"; + const char expected[] = "; void foo ( ) { unsigned int fred ; fred = 0 ; }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum13() + { + const char code[] = "enum ab { ENTRY(1, a = 0), ENTRY(2, b) };\n" + "void foo()\n" + "{\n" + " unsigned int fred = a;\n" + "}"; + const char expected[] = "; void foo ( ) { unsigned int fred ; fred = a ; }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum14() + { + const char code[] = "enum ab { a };\n" + "ab"; + const char expected[] = "; ab"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void enum15() // C++0x features + { + { + const char code[] = "enum : char { a = 99 };\n" + "char c1 = a;"; + const char expected[] = "; char c1 ; c1 = 99 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum class Enum1 { a };\n" + "Enum1 e1 = a;"; + const char expected[] = "; int e1 ; e1 = 0 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum Enum1 : char { a };\n" + "Enum1 e1 = a;"; + const char expected[] = "; char e1 ; e1 = 0 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum class Enum1 : unsigned char { a };\n" + "Enum1 e1 = a;"; + const char expected[] = "; unsigned char e1 ; e1 = 0 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum class Enum1 : unsigned int { a };\n" + "Enum1 e1 = a;"; + const char expected[] = "; unsigned int e1 ; e1 = 0 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "enum class Enum1 : unsigned long long int { a };\n" + "Enum1 e1 = a;"; + const char expected[] = "; unsigned long long e1 ; e1 = 0 ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void enum16() // ticket #1988 + { + const char code[] = "enum D : auto * { FF = 0 };"; + checkSimplifyEnum(code); + ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); + } + + void enum17() // ticket #2381 + { + // if header is included twice its enums will be duplicated + const char code[] = "enum ab { a=0, b };" + "enum ab { a=0, b };\n"; + ASSERT_EQUALS(";", tok(code, false)); + ASSERT_EQUALS("", errout.str()); + } + + void enum18() // ticket #2466 - array with same name as enum constant + { + const char code[] = "enum ab { a=0, b };\n" + "void f() { a[0]; }\n"; + ASSERT_EQUALS("; void f ( ) { a [ 0 ] ; }", tok(code, false)); + } + + void enum19() // ticket #2536 + { + const char code[] = "enum class E1;\n" + "enum class E2 : int;\n"; + ASSERT_EQUALS(";", tok(code, false)); + } + + void enum20() // ticket #2600 segmentation fault + { + const char code[] = "enum { const }\n"; + ASSERT_EQUALS(";", tok(code, false)); + } + + void removestd() + { + ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);")); + ASSERT_EQUALS("; strcat ( a , b ) ;", tok("; std::strcat(a,b);")); + ASSERT_EQUALS("; strncpy ( a , b , 10 ) ;", tok("; std::strncpy(a,b,10);")); + ASSERT_EQUALS("; strncat ( a , b , 10 ) ;", tok("; std::strncat(a,b,10);")); + ASSERT_EQUALS("; free ( p ) ;", tok("; std::free(p);")); + ASSERT_EQUALS("; malloc ( 10 ) ;", tok("; std::malloc(10);")); + } + + void simplifyInitVar() + { + // ticket #1005 - int *p(0); => int *p = 0; + { + const char code[] = "void foo() { int *p(0); }"; + ASSERT_EQUALS("void foo ( ) { ; }", tok(code)); + } + + { + const char code[] = "void foo() { int p(0); }"; + ASSERT_EQUALS("void foo ( ) { ; }", tok(code)); + } + + { + const char code[] = "void a() { foo *p(0); }"; + ASSERT_EQUALS("void a ( ) { ; }", tok(code)); + } + } + + void simplifyReference() + { + ASSERT_EQUALS("void f ( ) { int a ; a ++ ; }", + tok("void f() { int a; int &b(a); b++; }")); + ASSERT_EQUALS("void f ( ) { int a ; a ++ ; }", + tok("void f() { int a; int &b = a; b++; }")); + } + + void simplifyRealloc() + { + ASSERT_EQUALS("; free ( p ) ; p = 0 ;", + tok("; p = realloc(p,0);")); + ASSERT_EQUALS("; p = malloc ( 100 ) ;", + tok("; p = realloc(0, 100);")); + ASSERT_EQUALS("; p = malloc ( 0 ) ;", + tok("; p = realloc(0, sizeof(char)*0);")); + } + + void simplifyErrNoInWhile() + { + ASSERT_EQUALS("; while ( f ( ) ) { }", + tok("; while (f() && errno == EINTR) { }")); + ASSERT_EQUALS("; while ( f ( ) ) { }", + tok("; while (f() && (errno == EINTR)) { }")); + } + + void simplifyFuncInWhile() + { + ASSERT_EQUALS("int cppcheck:r = fclose ( f ) ; " + "while ( cppcheck:r ) " + "{ " + "foo ( ) ; " + "cppcheck:r = fclose ( f ) ; " + "}", + tok("while(fclose(f))foo();")); + + ASSERT_EQUALS("int cppcheck:r = fclose ( f ) ; " + "while ( cppcheck:r ) " + "{ " + "; cppcheck:r = fclose ( f ) ; " + "}", + tok("while(fclose(f));")); + + ASSERT_EQUALS("int cppcheck:r = fclose ( f ) ; " + "while ( cppcheck:r ) " + "{ " + "; cppcheck:r = fclose ( f ) ; " + "} " + "int cppcheck:r = fclose ( g ) ; " + "while ( cppcheck:r ) " + "{ " + "; cppcheck:r = fclose ( g ) ; " + "}", + tok("while(fclose(f)); while(fclose(g));")); + } + + void initstruct() + { + ASSERT_EQUALS("; struct A a ; a . buf = 3 ;", tok("; struct A a = { .buf = 3 };")); + ASSERT_EQUALS("; struct A a ; a . buf = x ;", tok("; struct A a = { .buf = x };")); + ASSERT_EQUALS("; struct A a ; a . buf = & key ;", tok("; struct A a = { .buf = &key };")); + ASSERT_EQUALS("; struct ABC abc ; abc . a = 3 ; abc . b = x ; abc . c = & key ;", tok("; struct ABC abc = { .a = 3, .b = x, .c = &key };")); + TODO_ASSERT_EQUALS("; struct A a ; a . buf = { 0 } ;", + "; struct A a ; a = { . buf = { 0 } } ;", + tok("; struct A a = { .buf = {0} };")); + } + + void simplifyStructDecl1() + { + { + const char code[] = "struct ABC { } abc;"; + const char expected[] = "struct ABC { } ; ABC abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { } * pabc;"; + const char expected[] = "struct ABC { } ; ABC * pabc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { } abc[4];"; + const char expected[] = "struct ABC { } ; ABC abc [ 4 ] ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { } abc, def;"; + const char expected[] = "struct ABC { } ; ABC abc ; ABC def ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { } abc, * pabc;"; + const char expected[] = "struct ABC { } ; ABC abc ; ABC * pabc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { struct DEF {} def; } abc;"; + const char expected[] = "struct ABC { struct DEF { } ; DEF def ; } ; ABC abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { } abc;"; + const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { } * pabc;"; + const char expected[] = "struct Anonymous0 { } ; Anonymous0 * pabc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { } abc[4];"; + const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc [ 4 ] ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { } abc, def;"; + const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc ; Anonymous0 def ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { } abc, * pabc;"; + const char expected[] = "struct Anonymous0 { } ; Anonymous0 abc ; Anonymous0 * pabc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { struct DEF {} def; } abc;"; + const char expected[] = "struct Anonymous0 { struct DEF { } ; DEF def ; } ; Anonymous0 abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { struct {} def; } abc;"; + const char expected[] = "struct ABC { struct Anonymous0 { } ; Anonymous0 def ; } ; ABC abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { struct {} def; } abc;"; + const char expected[] = "struct Anonymous0 { struct Anonymous1 { } ; Anonymous1 def ; } ; Anonymous0 abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "union ABC { int i; float f; } abc;"; + const char expected[] = "union ABC { int i ; float f ; } ; ABC abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC { struct {} def; };"; + const char expected[] = "struct ABC { struct Anonymous0 { } ; Anonymous0 def ; } ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct ABC : public XYZ { struct {} def; };"; + const char expected[] = "struct ABC : public XYZ { struct Anonymous0 { } ; Anonymous0 def ; } ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { int x; }; int y;"; + const char expected[] = "int x ; int y ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { int x; };"; + const char expected[] = "int x ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { };"; + const char expected[] = ";"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + { + const char code[] = "struct { struct { struct { } ; } ; };"; + const char expected[] = ";"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + // ticket 2464 + { + const char code[] = "static struct ABC { } abc ;"; + const char expected[] = "struct ABC { } ; static ABC abc ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + // ticket #980 + { + const char code[] = "void f() { int A(1),B(2),C=3,D,E(5),F=6; }"; + const char expected[] = "void f ( ) { int A ; A = 1 ; int B ; B = 2 ; int C ; C = 3 ; int D ; int E ; E = 5 ; int F ; F = 6 ; }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + } + + void simplifyStructDecl2() // ticket #2479 (segmentation fault) + { + const char code[] = "struct { char c; }"; + const char expected[] = "struct { char c ; }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void removeUnwantedKeywords() + { + ASSERT_EQUALS("int var ;", tok("register int var ;", true)); + ASSERT_EQUALS("short var ;", tok("register short int var ;", true)); + ASSERT_EQUALS("int foo ( ) { }", tok("inline int foo ( ) { }", true)); + ASSERT_EQUALS("int foo ( ) { }", tok("__inline int foo ( ) { }", true)); + ASSERT_EQUALS("int foo ( ) { }", tok("__forceinline int foo ( ) { }", true)); + ASSERT_EQUALS("if ( a ) { }", tok("if ( likely ( a ) ) { }", true)); + ASSERT_EQUALS("if ( a ) { }", tok("if ( unlikely ( a ) ) { }", true)); + ASSERT_EQUALS("int * p ;", tok("int * __restrict p;", true)); + ASSERT_EQUALS("int * * p ;", tok("int * __restrict__ * p;", true)); + ASSERT_EQUALS("void foo ( float * a , float * b ) ;", tok("void foo(float * __restrict__ a, float * __restrict__ b);", true)); + ASSERT_EQUALS("int * p ;", tok("int * restrict p;", true)); + ASSERT_EQUALS("int * * p ;", tok("int * restrict * p;", true)); + ASSERT_EQUALS("void foo ( float * a , float * b ) ;", tok("void foo(float * restrict a, float * restrict b);", true)); + ASSERT_EQUALS("; int * p ;", tok("typedef int * __restrict__ rint; rint p;", true)); + } + + void simplifyCallingConvention() + { + ASSERT_EQUALS("int f ( ) ;", tok("int __cdecl f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __stdcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __fastcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __clrcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __thiscall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __syscall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __pascal f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __fortran f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __cdecl f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __stdcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __fastcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __clrcall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __thiscall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __syscall f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __pascal f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int __far __fortran f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int WINAPI f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int APIENTRY f();", true)); + ASSERT_EQUALS("int f ( ) ;", tok("int CALLBACK f();", true)); + } + + void simplifyFunctorCall() + { + ASSERT_EQUALS("IncrementFunctor ( ) ( a ) ;", tok("IncrementFunctor()(a);", true)); + } + + void redundant_semicolon() + { + ASSERT_EQUALS("void f ( ) { ; }", tok("void f() { ; }", false)); + ASSERT_EQUALS("void f ( ) { ; }", tok("void f() { do { ; } while (0); }", true)); + } + + void simplifyFunctionReturn() + { + const char code[] = "typedef void (*testfp)();\n" + "struct Fred\n" + "{\n" + " testfp get1() { return 0; }\n" + " void ( * get2 ( ) ) ( ) { return 0 ; }\n" + " testfp get3();\n" + " void ( * get4 ( ) ) ( );\n" + "};"; + const char expected[] = "; " + "struct Fred " + "{ " + "void ( * get1 ( ) ) ( ) { return 0 ; } " + "void ( * get2 ( ) ) ( ) { return 0 ; } " + "void ( * get3 ( ) ) ( ) ; " + "void ( * get4 ( ) ) ( ) ; " + "} ;"; + ASSERT_EQUALS(expected, tok(code, false)); + } + + void removeUnnecessaryQualification1() + { + const char code[] = "class Fred { Fred::Fred() {} };"; + const char expected[] = "class Fred { Fred ( ) { } } ;"; + ASSERT_EQUALS(expected, tok(code, false)); + ASSERT_EQUALS("[test.cpp:1]: (portability) Extra qualification 'Fred::' unnecessary and considered an error by many compilers.\n", errout.str()); + } + + void removeUnnecessaryQualification2() + { + const char code[] = "template\n" + "struct grammar : qi::grammar {\n" + " grammar() : grammar::base_type(start) { }\n" + "};\n"; + tok(code, false); + ASSERT_EQUALS("", errout.str()); + } + + void simplifyIfNotNull() // ticket # 2601 segmentation fault + { + const char code[] = "|| #if #define <="; + tok(code, false); + ASSERT_EQUALS("", errout.str()); + } +}; + +REGISTER_TEST(TestSimplifyTokens) From f53ff27b712ec942c1c36b5b1e116bf024d4d71a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 6 Mar 2011 21:15:42 +0100 Subject: [PATCH 29/54] Tokenizer::simplifyTemplates: better handling of '(foo())'. Ticket: #2631 --- lib/tokenize.cpp | 2 +- test/testsimplifytokens.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 82e0d05a5..c028b3388 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2714,7 +2714,7 @@ std::list Tokenizer::simplifyTemplatesGetTemplateInstantiations() if (!tok) break; } - else if (Token::Match(tok->previous(), "[{};=] %var% <") || + else if (Token::Match(tok->previous(), "[({};=] %var% <") || Token::Match(tok->tokAt(-2), "[,:] private|protected|public %var% <")) { if (templateParameters(tok->next())) diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 96ec83945..37f484c6b 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -113,6 +113,7 @@ private: TEST_CASE(template20); TEST_CASE(template21); TEST_CASE(template22); + TEST_CASE(template23); TEST_CASE(template_unhandled); TEST_CASE(template_default_parameter); TEST_CASE(template_default_type); @@ -2025,6 +2026,22 @@ private: ASSERT_EQUALS(expected, sizeof_(code)); } + void template23() + { + const char code[] = "template void foo() { }\n" + "void bar() {\n" + " std::cout << (foo());\n" + "}"; + + const std::string expected("; " + "void bar ( ) {" + " std :: cout << ( foo ( ) ) ; " + "} " + "void foo ( ) { }"); + + ASSERT_EQUALS(expected, sizeof_(code)); + } + void template_unhandled() { From 80235b0d535109810a8323a5495ca49b74c1638a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 6 Mar 2011 21:15:58 +0100 Subject: [PATCH 30/54] astyle formatting --- lib/preprocessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 7650039e9..0d153a9e3 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -307,7 +307,7 @@ static bool isFallThroughComment(std::string comment) { // convert comment to lower case without whitespace std::transform(comment.begin(), comment.end(), comment.begin(), ::tolower); - for (std::string::iterator i = comment.begin(); i != comment.end(); ) + for (std::string::iterator i = comment.begin(); i != comment.end();) { if (::isspace(static_cast(*i))) comment.erase(i); From e26a7819d3579942ea696798499bd8fb2dcee938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 6 Mar 2011 21:21:42 +0100 Subject: [PATCH 31/54] Symbol database: variable fix. ticket: #2629 --- lib/symboldatabase.cpp | 135 ++++++++++++++++++++++------------------- lib/symboldatabase.h | 8 +++ 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 769f13671..933fad3da 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -424,9 +424,13 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti else if (Token::simpleMatch(tok, "for (") && Token::simpleMatch(tok->next()->link(), ") {")) { + // save location of initialization + const Token *tok1 = tok->tokAt(2); scope = new Scope(this, tok, scope, Scope::eFor, tok->next()->link()->next()); tok = tok->next()->link()->next(); scopeList.push_back(scope); + // check for variable declaration and add it to new scope if found + scope->checkVariable(tok1, Local); } else if (Token::simpleMatch(tok, "while (") && Token::simpleMatch(tok->next()->link(), ") {")) @@ -1401,71 +1405,78 @@ void Scope::getVariableList() else if (Token::Match(tok, ";|{|}")) continue; - // This is the start of a statement - const Token *vartok = NULL; - const Token *typetok = NULL; - const Token *typestart = tok; - - // Is it const..? - bool isConst = false; - if (tok->str() == "const") - { - tok = tok->next(); - isConst = true; - } - - // Is it a static variable? - const bool isStatic(Token::simpleMatch(tok, "static")); - if (isStatic) - { - tok = tok->next(); - } - - // Is it a mutable variable? - const bool isMutable(Token::simpleMatch(tok, "mutable")); - if (isMutable) - { - tok = tok->next(); - } - - // Is it const..? - if (tok->str() == "const") - { - tok = tok->next(); - isConst = true; - } - - bool isClass = false; - - if (Token::Match(tok, "struct|union")) - { - tok = tok->next(); - } - - bool isArray = false; - - if (isVariableDeclaration(tok, vartok, typetok, isArray)) - { - isClass = (!typetok->isStandardType() && vartok->previous()->str() != "*"); - tok = vartok->next(); - } - - // If the vartok was set in the if-blocks above, create a entry for this variable.. - if (vartok && vartok->str() != "operator") - { - if (vartok->varId() == 0 && !vartok->isBoolean()) - check->debugMessage(vartok, "Scope::getVariableList found variable \'" + vartok->str() + "\' with varid 0."); - - const Scope *scope = NULL; - - if (typetok) - scope = check->findVariableType(this, typetok); - - addVariable(vartok, typestart, vartok->previous(), varaccess, isMutable, isStatic, isConst, isClass, scope, this, isArray); - } + tok = checkVariable(tok, varaccess); } } +const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess) +{ + // This is the start of a statement + const Token *vartok = NULL; + const Token *typetok = NULL; + const Token *typestart = tok; + + // Is it const..? + bool isConst = false; + if (tok->str() == "const") + { + tok = tok->next(); + isConst = true; + } + + // Is it a static variable? + const bool isStatic(Token::simpleMatch(tok, "static")); + if (isStatic) + { + tok = tok->next(); + } + + // Is it a mutable variable? + const bool isMutable(Token::simpleMatch(tok, "mutable")); + if (isMutable) + { + tok = tok->next(); + } + + // Is it const..? + if (tok->str() == "const") + { + tok = tok->next(); + isConst = true; + } + + bool isClass = false; + + if (Token::Match(tok, "struct|union")) + { + tok = tok->next(); + } + + bool isArray = false; + + if (isVariableDeclaration(tok, vartok, typetok, isArray)) + { + isClass = (!typetok->isStandardType() && vartok->previous()->str() != "*"); + tok = vartok->next(); + } + + // If the vartok was set in the if-blocks above, create a entry for this variable.. + if (vartok && vartok->str() != "operator") + { + if (vartok->varId() == 0 && !vartok->isBoolean()) + check->debugMessage(vartok, "Scope::checkVariable found variable \'" + vartok->str() + "\' with varid 0."); + + const Scope *scope = NULL; + + if (typetok) + scope = check->findVariableType(this, typetok); + + addVariable(vartok, typestart, vartok->previous(), varaccess, isMutable, isStatic, isConst, isClass, scope, this, isArray); + } + + return tok; +} + const Token* skipScopeIdentifiers(const Token* tok) { const Token* ret = tok; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index e1cb05206..27aa08d4f 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -452,6 +452,14 @@ public: AccessControl defaultAccess() const; + /** + * @brief check if statement is variable declaration and add it if it is + * @param tok pointer to start of statement + * @param varaccess access control of statement + * @return pointer to last token + */ + const Token *checkVariable(const Token *tok, AccessControl varaccess); + private: /** * @brief helper function for getVariableList() From a77993db758bcb88513fe02a248ae3ded9d3c325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 6 Mar 2011 21:23:33 +0100 Subject: [PATCH 32/54] Refactoring of the CheckNullPointer::isPointer. Use the symbol database. Ticket: #2629 --- lib/checknullpointer.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index 6241dceae..4681177d6 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -21,6 +21,7 @@ #include "checknullpointer.h" #include "executionpath.h" #include "mathlib.h" +#include "symboldatabase.h" //--------------------------------------------------------------------------- // Register this check class (by creating a static instance of it) @@ -166,8 +167,12 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown) bool CheckNullPointer::isPointer(const unsigned int varid) { // Check if given variable is a pointer - const Token *tok = Token::findmatch(_tokenizer->tokens(), "%varid%", varid); - tok = tok->tokAt(-2); + const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); + const Variable *variableInfo = symbolDatabase->getVariableFromVarId(varid); + const Token *tok = variableInfo ? variableInfo->typeStartToken() : NULL; + + if (Token::Match(tok, "%type% %type% * %varid% [;)=]", varid)) + return true; // maybe not a pointer if (!Token::Match(tok, "%type% * %varid% [;)=]", varid)) From d678e4424c7dfea1ab87ef3a898dd616317eb1af Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 6 Mar 2011 18:59:56 -0500 Subject: [PATCH 33/54] fix #2630 (segmentation fault of cppcheck ( typedef y x () x )) --- lib/tokenize.cpp | 19 ++++++++----------- test/testsimplifytokens.cpp | 8 ++++++++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index c028b3388..38d948075 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1185,19 +1185,16 @@ void Tokenizer::simplifyTypedef() tok = deleteInvalidTypedef(typeDef); continue; } + else if (!Token::Match(tok->tokAt(offset)->link(), ") ;|,")) + { + syntaxError(tok); + return; + } function = true; - if (tok->tokAt(offset)->link()->next()) - { - argStart = tok->tokAt(offset); - argEnd = tok->tokAt(offset)->link(); - tok = argEnd->next(); - } - else - { - // internal error - continue; - } + argStart = tok->tokAt(offset); + argEnd = tok->tokAt(offset)->link(); + tok = argEnd->next(); } // unhandled typedef, skip it and continue diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 37f484c6b..e0f6d3499 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -245,6 +245,7 @@ private: TEST_CASE(simplifyTypedef81); // ticket #2603 TEST_CASE(simplifyTypedef82); // ticket #2403 TEST_CASE(simplifyTypedef83); // ticket #2620 + TEST_CASE(simplifyTypedef84); // ticket #2630 TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -4975,6 +4976,13 @@ private: ASSERT_EQUALS(expected, sizeof_(code)); } + void simplifyTypedef84() // ticket #2630 (segmentation fault) + { + const char code[] = "typedef y x () x\n"; + checkSimplifyTypedef(code); + ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); + } + void simplifyTypedefFunction1() { { From 7c589384d29c78b7240bfc58a1b6f347a89cb57b Mon Sep 17 00:00:00 2001 From: Kimmo Varis Date: Mon, 7 Mar 2011 21:10:30 +0200 Subject: [PATCH 34/54] GUI: Use severity enum in ErrorItem. Convert from using string to enum values for severity in ErrorItem. Storing and handling severity as string was the easy way earlier but it is not convenient or efficient way to handle severities. This commit is the first step in converting severity handling to use the enum values instead of strings. --- gui/csvreport.cpp | 2 +- gui/erroritem.cpp | 4 +-- gui/erroritem.h | 60 +++++++++++++++++++++++++++++++++++++++++++- gui/resultstree.cpp | 8 +++--- gui/resultsview.cpp | 2 +- gui/threadresult.cpp | 2 +- gui/txtreport.cpp | 2 +- gui/xmlreportv1.cpp | 6 +++-- gui/xmlreportv2.cpp | 6 +++-- 9 files changed, 77 insertions(+), 15 deletions(-) diff --git a/gui/csvreport.cpp b/gui/csvreport.cpp index 0080f1434..1147d01f3 100644 --- a/gui/csvreport.cpp +++ b/gui/csvreport.cpp @@ -65,7 +65,7 @@ void CsvReport::WriteError(const ErrorItem &error) QString line; const QString file = QDir::toNativeSeparators(error.files[error.files.size() - 1]); line += QString("%1,%2,").arg(file).arg(error.lines[error.lines.size() - 1]); - line += QString("%1,%2").arg(error.severity).arg(error.summary); + line += QString("%1,%2").arg(GuiSeverity::toString(error.severity)).arg(error.summary); mTxtWriter << line << endl; } diff --git a/gui/erroritem.cpp b/gui/erroritem.cpp index a7b09c853..dd7fc1aa9 100644 --- a/gui/erroritem.cpp +++ b/gui/erroritem.cpp @@ -35,14 +35,14 @@ ErrorItem::ErrorItem(const ErrorLine &line) files.append(line.file); lines.append(line.line); id = line.id; - severity = line.severity; + severity = GuiSeverity::fromString(line.severity); summary = line.summary; message = line.message; } QString ErrorItem::ToString() const { - QString str = file + " - " + id + " - " + severity +"\n"; + QString str = file + " - " + id + " - " + GuiSeverity::toString(severity) +"\n"; str += summary + "\n"; str += message + "\n"; for (int i = 0; i < files.size(); i++) diff --git a/gui/erroritem.h b/gui/erroritem.h index c6b36b7c3..8092c5f46 100644 --- a/gui/erroritem.h +++ b/gui/erroritem.h @@ -22,12 +22,70 @@ #include #include #include +#include "errorlogger.h" class ErrorLine; /// @addtogroup GUI /// @{ + +/** + * @brief GUI versions of severity conversions. + * GUI needs its own versions of conversions since GUI uses Qt's QString + * instead of the std::string used by lib/cli. + */ +class GuiSeverity : Severity +{ +public: + static QString toString(SeverityType severity) + { + switch (severity) + { + case none: + return ""; + case error: + return "error"; + case warning: + return "warning"; + case style: + return "style"; + case performance: + return "performance"; + case portability: + return "portability"; + case information: + return "information"; + case debug: + return "debug"; + }; + return "???"; + } + + static SeverityType fromString(const QString &severity) + { + if (severity.isEmpty()) + return none; + if (severity == "none") + return none; + if (severity == "error") + return error; + if (severity == "warning") + return warning; + if (severity == "style") + return style; + if (severity == "performance") + return performance; + if (severity == "portability") + return portability; + if (severity == "information") + return information; + if (severity == "debug") + return debug; + return none; + } +}; + /** * @brief A class containing error data for one error. * @@ -54,7 +112,7 @@ public: QStringList files; QList lines; QString id; - QString severity; + Severity::SeverityType severity; QString summary; QString message; }; diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index 5f2630c53..59b6bfc23 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -109,7 +109,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item) realfile = tr("Undefined file"); } - bool hide = !mShowTypes[SeverityToShowType(item.severity)]; + bool hide = !mShowTypes[SeverityToShowType(GuiSeverity::toString(item.severity))]; //if there is at least one error that is not hidden, we have a visible error if (!hide) @@ -123,7 +123,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item) line.line = item.lines[0]; line.summary = item.summary; line.message = item.message; - line.severity = item.severity; + line.severity = GuiSeverity::toString(item.severity); //Create the base item for the error and ensure it has a proper //file item as a parent QStandardItem *stditem = AddBacktraceFiles(EnsureFileItem(line.file, hide), @@ -137,7 +137,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item) //Add user data to that item QMap data; data["hide"] = false; - data["severity"] = SeverityToShowType(item.severity); + data["severity"] = SeverityToShowType(GuiSeverity::toString(item.severity)); data["summary"] = item.summary; data["message"] = item.message; data["file"] = item.files[0]; @@ -794,7 +794,7 @@ void ResultsTree::SaveErrors(Report *report, QStandardItem *item) QVariantMap data = userdata.toMap(); ErrorItem item; - item.severity = ShowTypeToString(VariantToShowType(data["severity"])); + item.severity = GuiSeverity::fromString(ShowTypeToString(VariantToShowType(data["severity"]))); item.summary = data["summary"].toString(); item.message = data["message"].toString(); item.id = data["id"].toString(); diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp index 1d4f90568..13bf85348 100644 --- a/gui/resultsview.cpp +++ b/gui/resultsview.cpp @@ -88,7 +88,7 @@ void ResultsView::Error(const ErrorItem &item) mErrorsFound = true; mUI.mTree->AddErrorItem(item); emit GotResults(); - mStatistics->AddItem(ResultsTree::SeverityToShowType(item.severity)); + mStatistics->AddItem(ResultsTree::SeverityToShowType(GuiSeverity::toString(item.severity))); } void ResultsView::ShowResults(ShowTypes type, bool show) diff --git a/gui/threadresult.cpp b/gui/threadresult.cpp index 7a92481c4..38e990ba1 100644 --- a/gui/threadresult.cpp +++ b/gui/threadresult.cpp @@ -71,7 +71,7 @@ void ThreadResult::reportErr(const ErrorLogger::ErrorMessage &msg) item.lines = lines; item.summary = QString::fromStdString(msg.shortMessage()); item.message = QString::fromStdString(msg.verboseMessage()); - item.severity = QString::fromStdString(Severity::toString(msg._severity)); + item.severity = msg._severity; if (msg._severity != Severity::debug) emit Error(item); diff --git a/gui/txtreport.cpp b/gui/txtreport.cpp index 20c34d7b7..f7c5ceb86 100644 --- a/gui/txtreport.cpp +++ b/gui/txtreport.cpp @@ -76,7 +76,7 @@ void TxtReport::WriteError(const ErrorItem &error) } } - line += QString("(%1) %2").arg(error.severity).arg(error.summary); + line += QString("(%1) %2").arg(GuiSeverity::toString(error.severity)).arg(error.summary); mTxtWriter << line << endl; } diff --git a/gui/xmlreportv1.cpp b/gui/xmlreportv1.cpp index 1062de07f..bab621f81 100644 --- a/gui/xmlreportv1.cpp +++ b/gui/xmlreportv1.cpp @@ -100,7 +100,9 @@ void XmlReportV1::WriteError(const ErrorItem &error) const QString line = QString::number(error.lines[error.lines.size() - 1]); mXmlWriter->writeAttribute(LineAttribute, line); mXmlWriter->writeAttribute(IdAttribute, error.id); - mXmlWriter->writeAttribute(SeverityAttribute, error.severity); + + // Don't localize severity so we can read these files + mXmlWriter->writeAttribute(SeverityAttribute, GuiSeverity::toString(error.severity)); const QString message = XmlReport::quoteMessage(error.message); mXmlWriter->writeAttribute(MsgAttribute, message); mXmlWriter->writeEndElement(); @@ -165,7 +167,7 @@ ErrorItem XmlReportV1::ReadError(QXmlStreamReader *reader) const int line = attribs.value("", LineAttribute).toString().toUInt(); item.lines.push_back(line); item.id = attribs.value("", IdAttribute).toString(); - item.severity = attribs.value("", SeverityAttribute).toString(); + item.severity = GuiSeverity::fromString(attribs.value("", SeverityAttribute).toString()); // NOTE: This dublicates the message to Summary-field. But since // old XML format doesn't have separate summary and verbose messages diff --git a/gui/xmlreportv2.cpp b/gui/xmlreportv2.cpp index 381d7d9c0..2c5665704 100644 --- a/gui/xmlreportv2.cpp +++ b/gui/xmlreportv2.cpp @@ -110,7 +110,9 @@ void XmlReportV2::WriteError(const ErrorItem &error) mXmlWriter->writeStartElement(ErrorElementName); mXmlWriter->writeAttribute(IdAttribute, error.id); - mXmlWriter->writeAttribute(SeverityAttribute, error.severity); + + // Don't localize severity so we can read these files + mXmlWriter->writeAttribute(SeverityAttribute, GuiSeverity::toString(error.severity)); const QString summary = XmlReport::quoteMessage(error.summary); mXmlWriter->writeAttribute(MsgAttribute, summary); const QString message = XmlReport::quoteMessage(error.message); @@ -196,7 +198,7 @@ ErrorItem XmlReportV2::ReadError(QXmlStreamReader *reader) { QXmlStreamAttributes attribs = reader->attributes(); item.id = attribs.value("", IdAttribute).toString(); - item.severity = attribs.value("", SeverityAttribute).toString(); + item.severity = GuiSeverity::fromString(attribs.value("", SeverityAttribute).toString()); const QString summary = attribs.value("", MsgAttribute).toString(); item.summary = XmlReport::unquoteMessage(summary); const QString message = attribs.value("", VerboseAttribute).toString(); From 8e571c04e4dd1e9dcc0acf0ace1c4825a234328c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 7 Mar 2011 20:17:52 +0100 Subject: [PATCH 35/54] Fixed #2633 (False positive: Memory leak for tree node) --- lib/checkmemoryleak.cpp | 16 ++++++++++++---- test/testmemleak.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index cbb7bd954..a53a06d5b 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -75,10 +75,18 @@ bool CheckMemoryLeak::isclass(const Tokenizer *_tokenizer, const Token *tok) con if (tok->isStandardType()) return false; - std::ostringstream pattern; - pattern << "struct " << tok->str(); - if (Token::findmatch(_tokenizer->tokens(), pattern.str().c_str())) - return false; + // return false if the type is a simple struct without member functions + const std::string pattern("struct " + tok->str() + " {"); + const Token *tok2 = Token::findmatch(_tokenizer->tokens(), pattern.c_str()); + if (tok2) + { + while (tok2 && tok2->str() != "}" && tok2->str() != "(") + tok2 = tok2->next(); + + // Simple struct => return false + if (tok2 && tok2->str() == "}") + return false; + } return true; } diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 4fbf3832b..c23d64395 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -285,6 +285,7 @@ private: // detect leak in class member function.. TEST_CASE(class1); + TEST_CASE(class2); TEST_CASE(autoptr1); TEST_CASE(if_with_and); @@ -2518,6 +2519,37 @@ private: ASSERT_EQUALS("[test.cpp:7]: (error) Memory leak: p\n", errout.str()); } + void class2() + { + check("class Fred {\n" + "public:\n" + " Fred() : rootNode(0) {}\n" + "\n" + "private:\n" + " struct Node {\n" + " Node(Node* p) {\n" + " parent = p;\n" + " if (parent) {\n" + " parent->children.append(this);\n" + " }\n" + " }\n" + "\n" + " ~Node() {\n" + " qDeleteAll(children);\n" + " }\n" + "\n" + " QList children;\n" + " };\n" + "\n" + " Node rootNode;\n" + "\n" + " void f() {\n" + " Node* recordNode = new Node(&rootNode);\n" + " }\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + void autoptr1() { From d2c06501d9139d2c31b2db7602423f70616ed94b Mon Sep 17 00:00:00 2001 From: Kimmo Varis Date: Mon, 7 Mar 2011 21:20:09 +0200 Subject: [PATCH 36/54] GUI: Convert severity in ErrorLine to enum value. This commit continues converting severity in GUI to enum. --- gui/erroritem.cpp | 2 +- gui/erroritem.h | 2 +- gui/resultstree.cpp | 9 +++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/gui/erroritem.cpp b/gui/erroritem.cpp index dd7fc1aa9..92055678d 100644 --- a/gui/erroritem.cpp +++ b/gui/erroritem.cpp @@ -35,7 +35,7 @@ ErrorItem::ErrorItem(const ErrorLine &line) files.append(line.file); lines.append(line.line); id = line.id; - severity = GuiSeverity::fromString(line.severity); + severity = line.severity; summary = line.summary; message = line.message; } diff --git a/gui/erroritem.h b/gui/erroritem.h index 8092c5f46..cc0ddc913 100644 --- a/gui/erroritem.h +++ b/gui/erroritem.h @@ -128,7 +128,7 @@ public: QString file; unsigned int line; QString id; - QString severity; + Severity::SeverityType severity; QString summary; QString message; }; diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index 59b6bfc23..968475342 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -123,13 +123,13 @@ void ResultsTree::AddErrorItem(const ErrorItem &item) line.line = item.lines[0]; line.summary = item.summary; line.message = item.message; - line.severity = GuiSeverity::toString(item.severity); + line.severity = item.severity; //Create the base item for the error and ensure it has a proper //file item as a parent QStandardItem *stditem = AddBacktraceFiles(EnsureFileItem(line.file, hide), line, hide, - SeverityToIcon(line.severity)); + SeverityToIcon(GuiSeverity::toString(line.severity))); if (!stditem) return; @@ -158,7 +158,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item) //Add user data to that item QMap child_data; - child_data["severity"] = SeverityToShowType(line.severity); + child_data["severity"] = SeverityToShowType(GuiSeverity::toString(line.severity)); child_data["summary"] = line.summary; child_data["message"] = line.message; child_data["file"] = item.files[i]; @@ -190,7 +190,8 @@ QStandardItem *ResultsTree::AddBacktraceFiles(QStandardItem *parent, // Ensure shown path is with native separators const QString file = QDir::toNativeSeparators(item.file); list << CreateNormalItem(file); - list << CreateNormalItem(tr(item.severity.toLatin1())); + const QString severity = GuiSeverity::toString(item.severity); + list << CreateNormalItem(severity.toLatin1()); list << CreateLineNumberItem(QString("%1").arg(item.line)); //TODO message has parameter names so we'll need changes to the core //cppcheck so we can get proper translations From 7496cd412c1f54ff792db061c7714b558ebd9c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 7 Mar 2011 21:21:06 +0100 Subject: [PATCH 37/54] Fixed #2631 (Tokenizer::simplifyTemplates: template usage 'std::cout << (foo(r));') --- lib/tokenize.cpp | 16 ++++++++++++++-- test/testsimplifytokens.cpp | 19 +++++++------------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 38d948075..b998fc1a5 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2684,11 +2684,23 @@ std::list Tokenizer::simplifyTemplatesGetTemplateInstantiations() // template definition.. skip it if (Token::simpleMatch(tok, "template <")) { + unsigned int level = 0; + // Goto the end of the template definition for (; tok; tok = tok->next()) { + // skip '<' .. '>' + if (tok->str() == "<") + ++level; + else if (tok->str() == ">") + { + if (level <= 1) + break; + --level; + } + // skip inner '(' .. ')' and '{' .. '}' - if (tok->str() == "{" || tok->str() == "(") + else if (tok->str() == "{" || tok->str() == "(") { // skip inner tokens. goto ')' or '}' tok = tok->link(); @@ -3217,7 +3229,7 @@ void Tokenizer::simplifyTemplates() //while (!done) { done = true; - for (std::list::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) + for (std::list::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) { simplifyTemplatesInstantiate(*iter1, used, expandedtemplates); } diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index e0f6d3499..2a3a17b2e 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -1714,7 +1714,7 @@ private: "} ;\n"; // The expected result.. - std::string expected("; void f ( ) { A a ; } ; class A { }"); + std::string expected("; void f ( ) { A a ; } ; class A { } class A { }"); ASSERT_EQUALS(expected, sizeof_(code)); } @@ -1868,18 +1868,13 @@ private: " return 0;\n" "}\n"; - const std::string wanted("; " - "; " - "int main ( ) { b<2> ( ) ; return 0 ; } " - "void b<2> ( ) { a<2> ( ) ; } " - "void a<2> ( ) { }"); + const std::string expected("; " + "int main ( ) { b<2> ( ) ; return 0 ; } " + "void b<2> ( ) { a<2> ( ) ; } " + "void a ( ) { } " + "void a<2> ( ) { }"); - const std::string current("; " - "int main ( ) { b<2> ( ) ; return 0 ; } " - "void b<2> ( ) { a < 2 > ( ) ; }" - ); - - TODO_ASSERT_EQUALS(wanted, current, sizeof_(code)); + ASSERT_EQUALS(expected, sizeof_(code)); } void template17() From 5bf98447c97a5430a409b890087b05e9fff6594a Mon Sep 17 00:00:00 2001 From: Kimmo Varis Date: Mon, 7 Mar 2011 22:36:47 +0200 Subject: [PATCH 38/54] GUI: Make Severity to ShowType use enum values. Continue converting Severity use in GUI from QString to enum values. --- gui/resultstree.cpp | 20 ++++++++++---------- gui/resultstree.h | 5 +++-- gui/resultsview.cpp | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index 968475342..b61f5e1bb 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -109,7 +109,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item) realfile = tr("Undefined file"); } - bool hide = !mShowTypes[SeverityToShowType(GuiSeverity::toString(item.severity))]; + bool hide = !mShowTypes[SeverityToShowType(item.severity)]; //if there is at least one error that is not hidden, we have a visible error if (!hide) @@ -137,7 +137,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item) //Add user data to that item QMap data; data["hide"] = false; - data["severity"] = SeverityToShowType(GuiSeverity::toString(item.severity)); + data["severity"] = SeverityToShowType(item.severity); data["summary"] = item.summary; data["message"] = item.message; data["file"] = item.files[0]; @@ -158,7 +158,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item) //Add user data to that item QMap child_data; - child_data["severity"] = SeverityToShowType(GuiSeverity::toString(line.severity)); + child_data["severity"] = SeverityToShowType(line.severity); child_data["summary"] = line.summary; child_data["message"] = line.message; child_data["file"] = item.files[i]; @@ -252,19 +252,19 @@ ShowTypes ResultsTree::VariantToShowType(const QVariant &data) return (ShowTypes)value; } -ShowTypes ResultsTree::SeverityToShowType(const QString & severity) +ShowTypes ResultsTree::SeverityToShowType(Severity::SeverityType severity) { - if (severity == "error") + if (severity == Severity::error) return SHOW_ERRORS; - if (severity == "style") + if (severity == Severity::style) return SHOW_STYLE; - if (severity == "warning") + if (severity == Severity::warning) return SHOW_WARNINGS; - if (severity == "performance") + if (severity == Severity::performance) return SHOW_PERFORMANCE; - if (severity == "portability") + if (severity == Severity::portability) return SHOW_PORTABILITY; - if (severity == "information") + if (severity == Severity::information) return SHOW_INFORMATION; return SHOW_NONE; diff --git a/gui/resultstree.h b/gui/resultstree.h index 99448261e..652e13435 100644 --- a/gui/resultstree.h +++ b/gui/resultstree.h @@ -28,6 +28,7 @@ #include #include "common.h" #include "applicationlist.h" +#include "errorlogger.h" // Severity class Report; class ErrorItem; @@ -128,10 +129,10 @@ public: /** * @brief Convert severity string to ShowTypes value - * @param severity Error severity string + * @param severity Error severity * @return Severity converted to ShowTypes value */ - static ShowTypes SeverityToShowType(const QString &severity); + static ShowTypes SeverityToShowType(Severity::SeverityType severity); signals: /** diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp index 13bf85348..1d4f90568 100644 --- a/gui/resultsview.cpp +++ b/gui/resultsview.cpp @@ -88,7 +88,7 @@ void ResultsView::Error(const ErrorItem &item) mErrorsFound = true; mUI.mTree->AddErrorItem(item); emit GotResults(); - mStatistics->AddItem(ResultsTree::SeverityToShowType(GuiSeverity::toString(item.severity))); + mStatistics->AddItem(ResultsTree::SeverityToShowType(item.severity)); } void ResultsView::ShowResults(ShowTypes type, bool show) From 06abaf95a5e66f402452e6d2534874a9dbdc9ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 7 Mar 2011 21:37:13 +0100 Subject: [PATCH 39/54] Incorrect string compare: reduce noise when using strncmp on string literal --- lib/checkother.cpp | 9 --------- test/testother.cpp | 10 ---------- 2 files changed, 19 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 633020473..2b9674056 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2982,15 +2982,6 @@ void CheckOther::checkIncorrectStringCompare() incorrectStringCompareError(tok->next(), "substr", tok->str(), tok->tokAt(8)->str()); } } - if (Token::Match(tok, "strncmp ( %any% , %str% , %num% )")) - { - size_t clen = MathLib::toLongNumber(tok->tokAt(6)->str()); - size_t slen = Token::getStrLength(tok->tokAt(4)); - if (clen != slen) - { - incorrectStringCompareError(tok, "strncmp", tok->tokAt(4)->str(), tok->tokAt(6)->str()); - } - } } } diff --git a/test/testother.cpp b/test/testother.cpp index 89f32a4ba..8366b4d68 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -2241,16 +2241,6 @@ private: " return \"Hello\" == test.substr( 0 , 5 ) ? : 0 : 1 ;\n" "}"); ASSERT_EQUALS("", errout.str()); - - check("int f() {\n" - " return strncmp(\"test\" , \"test\" , 2) ; \n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) String literal \"test\" doesn't match length argument for strncmp(2).\n", errout.str()); - - check("int f() {\n" - " return strncmp(\"test\" , \"test\" , 4) ; \n" - "}"); - ASSERT_EQUALS("", errout.str()); } From a177fc4b2469b484720d0b8069019c9ece99b210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 7 Mar 2011 22:00:30 +0100 Subject: [PATCH 40/54] Preprocessor: made sure string::iterator is valid after string::erase --- lib/preprocessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 0d153a9e3..432cd5f8a 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -310,7 +310,7 @@ static bool isFallThroughComment(std::string comment) for (std::string::iterator i = comment.begin(); i != comment.end();) { if (::isspace(static_cast(*i))) - comment.erase(i); + i = comment.erase(i); else ++i; } From 0d27966eb808d491e50ef560ebfeb4db436690a4 Mon Sep 17 00:00:00 2001 From: Kimmo Varis Date: Mon, 7 Mar 2011 23:11:59 +0200 Subject: [PATCH 41/54] GUI: Update more severity conversion methods. --- gui/resultstree.cpp | 96 +++++++++++++++++++++++---------------------- gui/resultstree.h | 8 ++-- 2 files changed, 54 insertions(+), 50 deletions(-) diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index b61f5e1bb..ed15cca69 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -129,7 +129,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item) QStandardItem *stditem = AddBacktraceFiles(EnsureFileItem(line.file, hide), line, hide, - SeverityToIcon(GuiSeverity::toString(line.severity))); + SeverityToIcon(line.severity)); if (!stditem) return; @@ -270,6 +270,42 @@ ShowTypes ResultsTree::SeverityToShowType(Severity::SeverityType severity) return SHOW_NONE; } +Severity::SeverityType ResultsTree::ShowTypeToSeverity(ShowTypes type) +{ + switch (type) + { + case SHOW_STYLE: + return Severity::style; + break; + + case SHOW_ERRORS: + return Severity::error; + break; + + case SHOW_WARNINGS: + return Severity::warning; + break; + + case SHOW_PERFORMANCE: + return Severity::performance; + break; + + case SHOW_PORTABILITY: + return Severity::portability; + break; + + case SHOW_INFORMATION: + return Severity::information; + break; + + case SHOW_NONE: + return Severity::none; + break; + } + + return Severity::none; +} + QStandardItem *ResultsTree::FindFileItem(const QString &name) { QList list = mModel.findItems(name); @@ -736,21 +772,25 @@ void ResultsTree::CopyPath(QStandardItem *target, bool fullPath) } } -QString ResultsTree::SeverityToIcon(const QString &severity) const +QString ResultsTree::SeverityToIcon(Severity::SeverityType severity) const { - if (severity == "error") + switch (severity) + { + case Severity::error: return ":images/dialog-error.png"; - if (severity == "style") + case Severity::style: return ":images/applications-development.png"; - if (severity == "warning") + case Severity::warning: return ":images/dialog-warning.png"; - if (severity == "portability") + case Severity::portability: return ":images/applications-system.png"; - if (severity == "performance") + case Severity::performance: return ":images/utilities-system-monitor.png"; - if (severity == "information") + case Severity::information: return ":images/dialog-information.png"; - + default: + return ""; + } return ""; } @@ -795,7 +835,7 @@ void ResultsTree::SaveErrors(Report *report, QStandardItem *item) QVariantMap data = userdata.toMap(); ErrorItem item; - item.severity = GuiSeverity::fromString(ShowTypeToString(VariantToShowType(data["severity"]))); + item.severity = ShowTypeToSeverity(VariantToShowType(data["severity"])); item.summary = data["summary"].toString(); item.message = data["message"].toString(); item.id = data["id"].toString(); @@ -824,42 +864,6 @@ void ResultsTree::SaveErrors(Report *report, QStandardItem *item) } } -QString ResultsTree::ShowTypeToString(ShowTypes type) -{ - switch (type) - { - case SHOW_STYLE: - return tr("style"); - break; - - case SHOW_ERRORS: - return tr("error"); - break; - - case SHOW_WARNINGS: - return tr("warning"); - break; - - case SHOW_PERFORMANCE: - return tr("performance"); - break; - - case SHOW_PORTABILITY: - return tr("portability"); - break; - - case SHOW_INFORMATION: - return tr("information"); - break; - - case SHOW_NONE: - return ""; - break; - } - - return ""; -} - void ResultsTree::UpdateSettings(bool showFullPath, bool saveFullPath, bool saveAllErrors) diff --git a/gui/resultstree.h b/gui/resultstree.h index 652e13435..3681869c8 100644 --- a/gui/resultstree.h +++ b/gui/resultstree.h @@ -231,9 +231,9 @@ protected: /** * @brief Convert a severity string to a icon filename * - * @param severity Severity string + * @param severity Severity */ - QString SeverityToIcon(const QString &severity) const; + QString SeverityToIcon(Severity::SeverityType severity) const; /** * @brief Helper function to open an error within target with application* @@ -292,9 +292,9 @@ protected: /** * @brief Convert ShowType to severity string * @param type ShowType to convert - * @return ShowType converted to string + * @return ShowType converted to severity */ - QString ShowTypeToString(ShowTypes type); + Severity::SeverityType ShowTypeToSeverity(ShowTypes type); /** * @brief Load all settings From d9efd53033b2b139e3f1040bb441741fbc58b197 Mon Sep 17 00:00:00 2001 From: Kimmo Varis Date: Mon, 7 Mar 2011 23:35:58 +0200 Subject: [PATCH 42/54] GUI: Add back translation of severity texts. Translation of severity texts was temporarily disabled by earlier commits. Now adding new method to ResultsTree for getting translated severity string. --- gui/resultstree.cpp | 59 ++++++++++++++++++++++++++++++++++++++++----- gui/resultstree.h | 7 ++++++ 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index ed15cca69..90e785d04 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -254,18 +254,25 @@ ShowTypes ResultsTree::VariantToShowType(const QVariant &data) ShowTypes ResultsTree::SeverityToShowType(Severity::SeverityType severity) { - if (severity == Severity::error) + switch (severity) + { + case Severity::none: + return SHOW_NONE; + case Severity::error: return SHOW_ERRORS; - if (severity == Severity::style) + case Severity::style: return SHOW_STYLE; - if (severity == Severity::warning) + case Severity::warning: return SHOW_WARNINGS; - if (severity == Severity::performance) + case Severity::performance: return SHOW_PERFORMANCE; - if (severity == Severity::portability) + case Severity::portability: return SHOW_PORTABILITY; - if (severity == Severity::information) + case Severity::information: return SHOW_INFORMATION; + default: + return SHOW_NONE; + } return SHOW_NONE; } @@ -306,6 +313,46 @@ Severity::SeverityType ResultsTree::ShowTypeToSeverity(ShowTypes type) return Severity::none; } +QString ResultsTree::SeverityToTranslatedString(Severity::SeverityType severity) +{ + switch (severity) + { + case Severity::style: + return tr("style"); + break; + + case Severity::error: + return tr("error"); + break; + + case Severity::warning: + return tr("warning"); + break; + + case Severity::performance: + return tr("performance"); + break; + + case Severity::portability: + return tr("portability"); + break; + + case Severity::information: + return tr("information"); + break; + + case Severity::debug: + return tr("debug"); + break; + + case Severity::none: + return ""; + break; + } + + return ""; +} + QStandardItem *ResultsTree::FindFileItem(const QString &name) { QList list = mModel.findItems(name); diff --git a/gui/resultstree.h b/gui/resultstree.h index 3681869c8..cc5f1b03d 100644 --- a/gui/resultstree.h +++ b/gui/resultstree.h @@ -296,6 +296,13 @@ protected: */ Severity::SeverityType ShowTypeToSeverity(ShowTypes type); + /** + * @brief Convert Severity to translated string for GUI. + * @param type Severity to convert + * @return Severity as translated string + */ + QString SeverityToTranslatedString(Severity::SeverityType severity); + /** * @brief Load all settings * Colum widths From d8ced1dbb1e2fa78cbd17c78c468a65b6338581d Mon Sep 17 00:00:00 2001 From: Kimmo Varis Date: Mon, 7 Mar 2011 23:43:59 +0200 Subject: [PATCH 43/54] GUI: Initialize Severity in ErrorItem constructor. --- gui/erroritem.cpp | 5 +++++ gui/erroritem.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/gui/erroritem.cpp b/gui/erroritem.cpp index 92055678d..46ab536a9 100644 --- a/gui/erroritem.cpp +++ b/gui/erroritem.cpp @@ -18,6 +18,11 @@ #include "erroritem.h" +ErrorItem::ErrorItem() + : severity(Severity::none) +{ +} + ErrorItem::ErrorItem(const ErrorItem &item) { file = item.file; diff --git a/gui/erroritem.h b/gui/erroritem.h index cc0ddc913..cb3db71f9 100644 --- a/gui/erroritem.h +++ b/gui/erroritem.h @@ -97,7 +97,7 @@ public: class ErrorItem { public: - ErrorItem() { } + ErrorItem(); ErrorItem(const ErrorItem &item); ErrorItem(const ErrorLine &line); ~ErrorItem() { } From e305a155afd529de70ae129bac70d1b84d342b17 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Mon, 7 Mar 2011 19:49:43 -0500 Subject: [PATCH 44/54] convert CheckStl::size() to use symbol database, fix false positives, and remove inconclusive --- lib/checkstl.cpp | 41 +++++++++++++++---------------------- test/teststl.cpp | 53 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index e52a4b79f..3509386ca 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -17,8 +17,8 @@ */ #include "checkstl.h" -#include "token.h" #include "executionpath.h" +#include "symboldatabase.h" #include // Register this check class (by creating a static instance of it) @@ -799,11 +799,13 @@ bool CheckStl::isStlContainer(const Token *tok) if (tok->varId()) { // find where this token is defined - const Token *type = Token::findmatch(_tokenizer->tokens(), "%varid%", tok->varId()); + const Variable *var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok->varId()); + + if (!var) + return false; // find where this tokens type starts - while (type->previous() && !Token::Match(type->previous(), "[;{,(]")) - type = type->previous(); + const Token *type = var->typeStartToken(); // ignore "const" if (type->str() == "const") @@ -829,38 +831,27 @@ bool CheckStl::isStlContainer(const Token *tok) void CheckStl::size() { - if (!_settings->_checkCodingStyle || !_settings->inconclusive) + if (!_settings->_checkCodingStyle) return; for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (Token::Match(tok, "%var% . size ( )")) { - if (Token::Match(tok->tokAt(5), "==|!=|> 0")) + // check for comparison to zero + if (Token::Match(tok->tokAt(5), "==|!=|> 0") || + Token::Match(tok->tokAt(-2), "0 ==|!=|<")) { if (isStlContainer(tok)) sizeError(tok); } - else if ((tok->tokAt(5)->str() == ")" || - tok->tokAt(5)->str() == "&&" || - tok->tokAt(5)->str() == "||" || - tok->tokAt(5)->str() == "!") && - (tok->tokAt(-1)->str() == "(" || - tok->tokAt(-1)->str() == "&&" || - tok->tokAt(-1)->str() == "||" || - tok->tokAt(-1)->str() == "!")) + + // check for using as boolean expression + else if ((Token::Match(tok->tokAt(-2), "if|while (") || + Token::Match(tok->tokAt(-3), "if|while ( !")) && + tok->strAt(5) == ")") { - if (tok->tokAt(-1)->str() == "(" && - tok->tokAt(5)->str() == ")") - { - // check for passing size to function call - if (Token::Match(tok->tokAt(-2), "if|while")) - { - if (isStlContainer(tok)) - sizeError(tok); - } - } - else if (isStlContainer(tok)) + if (isStlContainer(tok)) sizeError(tok); } } diff --git a/test/teststl.cpp b/test/teststl.cpp index 748c46ac0..15b68fd36 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -113,7 +113,6 @@ private: errout.str(""); Settings settings; - settings.inconclusive = true; settings._checkCodingStyle = true; // Tokenize.. @@ -1064,6 +1063,23 @@ private: void size1() { + check("struct Fred {\n" + " void foo();\n" + " std::list x;\n" + "};\n" + "void Fred::foo()\n" + "{\n" + " if (x.size() == 0) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); + + check("std::list x;\n" + "void f()\n" + "{\n" + " if (x.size() == 0) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); + check("void f()\n" "{\n" " std::list x;\n" @@ -1071,6 +1087,13 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); + check("void f()\n" + "{\n" + " std::list x;\n" + " if (0 == x.size()) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); + check("void f()\n" "{\n" " std::list x;\n" @@ -1078,6 +1101,13 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); + check("void f()\n" + "{\n" + " std::list x;\n" + " if (0 != x.size()) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); + check("void f()\n" "{\n" " std::list x;\n" @@ -1085,6 +1115,13 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); + check("void f()\n" + "{\n" + " std::list x;\n" + " if (0 < x.size()) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); + check("void f()\n" "{\n" " std::list x;\n" @@ -1092,12 +1129,26 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); + check("void f()\n" + "{\n" + " std::list x;\n" + " if (!x.size()) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); + check("void f()\n" "{\n" " std::list x;\n" " fun(x.size());\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + check("void f()\n" + "{\n" + " std::list x;\n" + " fun(!x.size());\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void redundantCondition1() From d74ae3b0f0de84895a10f01010391e1411d63010 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Mon, 7 Mar 2011 20:04:25 -0500 Subject: [PATCH 45/54] copy all flag fields in a Token --- lib/token.cpp | 3 +++ lib/token.h | 12 ++++++++++++ lib/tokenize.cpp | 9 +++++++++ 3 files changed, 24 insertions(+) diff --git a/lib/token.cpp b/lib/token.cpp index f874d1f8e..e40a18fa8 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -107,6 +107,9 @@ void Token::deleteThis() _isName = _next->_isName; _isNumber = _next->_isNumber; _isBoolean = _next->_isBoolean; + _isUnsigned = _next->_isUnsigned; + _isSigned = _next->_isSigned; + _isLong = _next->_isLong; _isUnused = _next->_isUnused; _varId = _next->_varId; _fileIndex = _next->_fileIndex; diff --git a/lib/token.h b/lib/token.h index 769ac4467..f23aba76f 100644 --- a/lib/token.h +++ b/lib/token.h @@ -141,14 +141,26 @@ public: { return _isName; } + void isName(bool name) + { + _isName = name; + } bool isNumber() const { return _isNumber; } + void isNumber(bool number) + { + _isNumber = number; + } bool isBoolean() const { return _isBoolean; } + void isBoolean(bool boolean) + { + _isBoolean = boolean; + } bool isUnsigned() const { return _isUnsigned; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index b998fc1a5..3881aec3b 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -243,13 +243,18 @@ void Tokenizer::insertTokens(Token *dest, const Token *src, unsigned int n) dest->fileIndex(src->fileIndex()); dest->linenr(src->linenr()); dest->varId(src->varId()); + dest->isName(src->isName()); + dest->isNumber(src->isNumber()); + dest->isBoolean(src->isBoolean()); dest->isUnsigned(src->isUnsigned()); dest->isSigned(src->isSigned()); dest->isLong(src->isLong()); + dest->isUnused(src->isUnused()); src = src->next(); --n; } } + //--------------------------------------------------------------------------- Token *Tokenizer::copyTokens(Token *dest, const Token *first, const Token *last) @@ -262,9 +267,13 @@ Token *Tokenizer::copyTokens(Token *dest, const Token *first, const Token *last) tok2 = tok2->next(); tok2->fileIndex(dest->fileIndex()); tok2->linenr(dest->linenr()); + tok2->isName(tok->isName()); + tok2->isNumber(tok->isNumber()); + tok2->isBoolean(tok->isBoolean()); tok2->isUnsigned(tok->isUnsigned()); tok2->isSigned(tok->isSigned()); tok2->isLong(tok->isLong()); + tok2->isUnused(tok->isUnused()); // Check for links and fix them up if (tok2->str() == "(" || tok2->str() == "[" || tok2->str() == "{") From c34a129102ed1692e36c966fe2b037905e69ab46 Mon Sep 17 00:00:00 2001 From: Kimmo Varis Date: Tue, 8 Mar 2011 08:59:52 +0200 Subject: [PATCH 46/54] GUI: Update About-dialog copyright year to 2011. --- gui/about.ui | 330 +++++++++++++++++++++++++-------------------------- 1 file changed, 165 insertions(+), 165 deletions(-) diff --git a/gui/about.ui b/gui/about.ui index 8dd7d231b..63c192f1a 100644 --- a/gui/about.ui +++ b/gui/about.ui @@ -1,165 +1,165 @@ - - - About - - - - 0 - 0 - 478 - 300 - - - - About Cppcheck - - - - - - - - - - - - - :/icon.png - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Version %1 - - - - - - - Cppcheck - A tool for static C/C++ code analysis. - - - true - - - - - - - Copyright © 2007-2010 Daniel Marjamäki and cppcheck team. - - - true - - - - - - - This program is licensed under the terms -of the GNU General Public License version 3 - - - true - - - - - - - Visit Cppcheck homepage at %1 - - - true - - - true - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Ok - - - - - - - - - - - mButtons - accepted() - About - accept() - - - 248 - 254 - - - 157 - 274 - - - - - mButtons - rejected() - About - reject() - - - 316 - 260 - - - 286 - 274 - - - - - + + + About + + + + 0 + 0 + 478 + 300 + + + + About Cppcheck + + + + + + + + + + + + + :/icon.png + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Version %1 + + + + + + + Cppcheck - A tool for static C/C++ code analysis. + + + true + + + + + + + Copyright © 2007-2011 Daniel Marjamäki and cppcheck team. + + + true + + + + + + + This program is licensed under the terms +of the GNU General Public License version 3 + + + true + + + + + + + Visit Cppcheck homepage at %1 + + + true + + + true + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + + mButtons + accepted() + About + accept() + + + 248 + 254 + + + 157 + 274 + + + + + mButtons + rejected() + About + reject() + + + 316 + 260 + + + 286 + 274 + + + + + From bf2362d558c7df72d7f5fb699b7a24f4ca8ee036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 8 Mar 2011 19:49:56 +0100 Subject: [PATCH 47/54] Fixed #2634 (False positive: buffer access out of bounds) --- lib/checkbufferoverrun.cpp | 9 +++++++++ test/testbufferoverrun.cpp | 14 ++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index ecd7aac8c..83d9bb068 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -469,6 +469,15 @@ void CheckBufferOverrun::parse_for_body(const Token *tok2, const ArrayInfo &arra if (tok2->str() == "?") break; + if (Token::simpleMatch(tok2, "for (") && Token::simpleMatch(tok2->next()->link(), ") {")) + { + const Token *endpar = tok2->next()->link(); + const Token *startbody = endpar->next(); + const Token *endbody = startbody->link(); + tok2 = endbody; + continue; + } + if (Token::Match(tok2, "if|switch")) { if (bailoutIfSwitch(tok2, arrayInfo.varid)) diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index f3a74a4b6..59daa3376 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -108,6 +108,7 @@ private: TEST_CASE(array_index_32); TEST_CASE(array_index_multidim); TEST_CASE(array_index_switch_in_for); + TEST_CASE(array_index_for_in_for); // FP: #2634 TEST_CASE(array_index_calculation); TEST_CASE(array_index_negative); TEST_CASE(array_index_for_decr); @@ -1189,6 +1190,19 @@ private: TODO_ASSERT_EQUALS("[test.cpp:12]: (error) Array index out of bounds\n", "", errout.str()); } + void array_index_for_in_for() + { + check("void f() {\n" + " int a[5];\n" + " for (int i = 0; i < 10; ++i) {\n" + " for (int j = i; j < 5; ++j) {\n" + " a[i] = 0;\n" + " }\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + void array_index_calculation() { // #1193 - false negative: array out of bounds in loop when there is calculation From 0b8581e71713f6ba50aeab2d088fbbf93bacb482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 8 Mar 2011 20:41:41 +0100 Subject: [PATCH 48/54] Fixed #2620 (Tokenizer::setVarId : wrong handling of member function parameters) --- lib/tokenize.cpp | 4 ++++ test/testtokenize.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 3881aec3b..e23d9a605 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3603,6 +3603,10 @@ void Tokenizer::setVarId() --indentlevel; } + // skip parantheses.. + else if (tok2->str() == "(") + tok2 = tok2->link(); + // Found a member variable.. else if (indentlevel == 1 && tok2->varId() > 0) varlist[tok2->str()] = tok2->varId(); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 4fea2b224..6b316e3f1 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -190,6 +190,7 @@ private: TEST_CASE(varidclass6); TEST_CASE(varidclass7); TEST_CASE(varidclass8); + TEST_CASE(varidclass9); TEST_CASE(file1); TEST_CASE(file2); @@ -3363,6 +3364,32 @@ private: ASSERT_EQUALS(expected, tokenizeDebugListing(code)); } + void varidclass9() + { + const std::string code("typedef char Str[10];" + "class A {\n" + "public:\n" + " void f(Str &cl);\n" + " void g(Str cl);\n" + "}\n" + "void Fred::f(Str &cl) {\n" + " sizeof(cl);\n" + "}"); + + const std::string expected("\n\n" + "##file 0\n" + "1: ; class A {\n" + "2: public:\n" + "3: void f ( char ( & cl ) [ 10 ] ) ;\n" + "4: void g ( char cl@1 [ 10 ] ) ;\n" + "5: }\n" + "6: void Fred :: f ( char ( & cl ) [ 10 ] ) {\n" + "7: sizeof ( cl ) ;\n" + "8: }\n"); + + ASSERT_EQUALS(expected, tokenizeDebugListing(code)); + } + void file1() { From c457179ce6c753fbc14db9107ed7cf7778ca041b Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Tue, 8 Mar 2011 20:14:46 -0500 Subject: [PATCH 49/54] fix null pointer dereference found by clang++ --analyze --- lib/symboldatabase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 933fad3da..bfa17306f 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -920,7 +920,7 @@ void SymbolDatabase::addFunction(Scope **scope, const Token **tok, const Token * if (func->hasBody) { addNewFunction(scope, tok); - if (scope) + if (*scope) { (*scope)->functionOf = scope1; added = true; From 7a7257f200c8a8d5e40fafe96c331356f64acc9c Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Tue, 8 Mar 2011 20:24:57 -0500 Subject: [PATCH 50/54] fix #2630 (segmentation fault of cppcheck ( typedef ... ) --- lib/tokenize.cpp | 7 +++++++ test/testsimplifytokens.cpp | 12 ++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index e23d9a605..9514dcd12 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1151,6 +1151,13 @@ void Tokenizer::simplifyTypedef() while (Token::Match(tok->tokAt(offset), "*|&|const")) pointers.push_back(tok->tokAt(offset++)->str()); + // check for invalid input + if (!tok->tokAt(offset)) + { + syntaxError(tok); + return; + } + if (Token::Match(tok->tokAt(offset), "%type%")) { // found the type name diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 2a3a17b2e..74adc52af 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -4973,8 +4973,16 @@ private: void simplifyTypedef84() // ticket #2630 (segmentation fault) { - const char code[] = "typedef y x () x\n"; - checkSimplifyTypedef(code); + const char code1[] = "typedef y x () x\n"; + checkSimplifyTypedef(code1); + ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); + + const char code2[] = "typedef struct template <>\n"; + checkSimplifyTypedef(code2); + ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); + + const char code3[] = "typedef ::<>\n"; + checkSimplifyTypedef(code3); ASSERT_EQUALS("[test.cpp:1]: (error) syntax error\n", errout.str()); } From 70b407611124838b3c83e8e920100d4771c71f29 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Wed, 9 Mar 2011 21:29:30 +1300 Subject: [PATCH 51/54] refactor noMemset so it recursively checks parent classes for non-memset-compatible things --- lib/checkclass.cpp | 146 ++++++++++++++++++++++++++------------------- lib/checkclass.h | 1 + test/testclass.cpp | 12 ++++ 3 files changed, 98 insertions(+), 61 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 569f4ed9d..648c562d1 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -693,6 +693,90 @@ void CheckClass::unusedPrivateFunctionError(const Token *tok, const std::string // ClassCheck: Check that memset is not used on classes //--------------------------------------------------------------------------- +void CheckClass::checkMemsetType(const Token *tok, const std::string &type) +{ + // Warn if type is a class or struct that contains any std::* variables + const std::string pattern2(std::string("struct|class ") + type + " :|{"); + const Token *tstruct = Token::findmatch(_tokenizer->tokens(), pattern2.c_str()); + + if (!tstruct) + return; + + const std::string &typeName = tstruct->str(); + + if (tstruct->tokAt(2)->str() == ":") + { + tstruct = tstruct->tokAt(3); + for (; tstruct; tstruct = tstruct->next()) + { + while (Token::Match(tstruct, "public|private|protected|virtual")) + { + tstruct = tstruct->next(); + } + + // recursively check all parent classes + checkMemsetType(tok, tstruct->str()); + + tstruct = tstruct->next(); + if (tstruct->str() != ",") + break; + } + } + + for (; tstruct; tstruct = tstruct->next()) + { + if (tstruct->str() == "}") + break; + + // struct with function? skip function body.. + if (Token::simpleMatch(tstruct, ") {")) + { + tstruct = tstruct->next()->link(); + if (!tstruct) + break; + } + + // before a statement there must be either: + // * private:|protected:|public: + // * { } ; + if (Token::Match(tstruct, "[;{}]") || + tstruct->str().find(":") != std::string::npos) + { + if (Token::Match(tstruct->next(), "std :: %type% %var% ;")) + memsetError(tok, tok->str(), tstruct->strAt(3), typeName); + + else if (Token::Match(tstruct->next(), "std :: %type% <")) + { + // backup the type + const std::string typestr(tstruct->strAt(3)); + + // check if it's a pointer variable.. + unsigned int level = 0; + while (0 != (tstruct = tstruct->next())) + { + if (tstruct->str() == "<") + ++level; + else if (tstruct->str() == ">") + { + if (level <= 1) + break; + --level; + } + else if (tstruct->str() == "(") + tstruct = tstruct->link(); + } + + if (!tstruct) + break; + + // found error => report + if (Token::Match(tstruct, "> %var% ;")) + memsetError(tok, tok->str(), typestr, typeName); + } + } + } +} + void CheckClass::noMemset() { createSymbolDatabase(); @@ -726,67 +810,7 @@ void CheckClass::noMemset() if (type.empty()) continue; - // Warn if type is a class or struct that contains any std::* variables - const std::string pattern2(std::string("struct|class ") + type + " {"); - const Token *tstruct = Token::findmatch(_tokenizer->tokens(), pattern2.c_str()); - - if (!tstruct) - continue; - - const std::string &typeName = tstruct->str(); - - for (; tstruct; tstruct = tstruct->next()) - { - if (tstruct->str() == "}") - break; - - // struct with function? skip function body.. - if (Token::simpleMatch(tstruct, ") {")) - { - tstruct = tstruct->next()->link(); - if (!tstruct) - break; - } - - // before a statement there must be either: - // * private:|protected:|public: - // * { } ; - if (Token::Match(tstruct, "[;{}]") || - tstruct->str().find(":") != std::string::npos) - { - if (Token::Match(tstruct->next(), "std :: %type% %var% ;")) - memsetError(tok, tok->str(), tstruct->strAt(3), typeName); - - else if (Token::Match(tstruct->next(), "std :: %type% <")) - { - // backup the type - const std::string typestr(tstruct->strAt(3)); - - // check if it's a pointer variable.. - unsigned int level = 0; - while (0 != (tstruct = tstruct->next())) - { - if (tstruct->str() == "<") - ++level; - else if (tstruct->str() == ">") - { - if (level <= 1) - break; - --level; - } - else if (tstruct->str() == "(") - tstruct = tstruct->link(); - } - - if (!tstruct) - break; - - // found error => report - if (Token::Match(tstruct, "> %var% ;")) - memsetError(tok, tok->str(), typestr, typeName); - } - } - } + checkMemsetType(tok, type); } } diff --git a/lib/checkclass.h b/lib/checkclass.h index 2dd238f83..1b3b5fa43 100644 --- a/lib/checkclass.h +++ b/lib/checkclass.h @@ -84,6 +84,7 @@ public: * Important: The checking doesn't work on simplified tokens list. */ void noMemset(); + void checkMemsetType(const Token *tok, const std::string &type); /** @brief 'operator=' should return something and it should not be const. */ void operatorEq(); diff --git a/test/testclass.cpp b/test/testclass.cpp index d49d5abe3..a724285df 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -2949,6 +2949,18 @@ private: " memset(&fred, 0, sizeof(fred));\n" "}\n"); ASSERT_EQUALS("[test.cpp:8]: (error) Using 'memset' on class that contains a 'std::string'\n", errout.str()); + + checkNoMemset("class Fred\n" + "{\n" + " std::string s;\n" + "};\n" + "class Pebbles: public Fred {};\n" + "void f()\n" + "{\n" + " Pebbles pebbles;\n" + " memset(&pebbles, 0, sizeof(pebbles));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:9]: (error) Using 'memset' on class that contains a 'std::string'\n", errout.str()); } void memsetOnStruct() From 3883afcbf48044aa3ef1c6ee4c6d3a7768bbeb9f Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Wed, 9 Mar 2011 22:10:39 +1300 Subject: [PATCH 52/54] Check for memset on objects with virtual functions (ticket #607) --- lib/checkclass.cpp | 8 +++++--- test/testclass.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 648c562d1..c01baed55 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -743,7 +743,7 @@ void CheckClass::checkMemsetType(const Token *tok, const std::string &type) tstruct->str().find(":") != std::string::npos) { if (Token::Match(tstruct->next(), "std :: %type% %var% ;")) - memsetError(tok, tok->str(), tstruct->strAt(3), typeName); + memsetError(tok, tok->str(), "'std::" + tstruct->strAt(3) + "'", typeName); else if (Token::Match(tstruct->next(), "std :: %type% <")) { @@ -771,8 +771,10 @@ void CheckClass::checkMemsetType(const Token *tok, const std::string &type) // found error => report if (Token::Match(tstruct, "> %var% ;")) - memsetError(tok, tok->str(), typestr, typeName); + memsetError(tok, tok->str(), "'std::" + typestr + "'", typeName); } + else if (Token::simpleMatch(tstruct->next(), "virtual")) + memsetError(tok, tok->str(), "virtual method", typeName); } } } @@ -816,7 +818,7 @@ void CheckClass::noMemset() void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type) { - reportError(tok, Severity::error, "memsetClass", "Using '" + memfunc + "' on " + type + " that contains a 'std::" + classname + "'"); + reportError(tok, Severity::error, "memsetClass", "Using '" + memfunc + "' on " + type + " that contains a " + classname); } //--------------------------------------------------------------------------- diff --git a/test/testclass.cpp b/test/testclass.cpp index a724285df..ff0da1953 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -2961,6 +2961,32 @@ private: " memset(&pebbles, 0, sizeof(pebbles));\n" "}\n"); ASSERT_EQUALS("[test.cpp:9]: (error) Using 'memset' on class that contains a 'std::string'\n", errout.str()); + + checkNoMemset("class Fred\n" + "{\n" + " virtual ~Fred();\n" + "};\n" + "void f()\n" + "{\n" + " Fred fred;\n" + " memset(&fred, 0, sizeof(fred));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:8]: (error) Using 'memset' on class that contains a virtual method\n", errout.str()); + + checkNoMemset("class Fred\n" + "{\n" + "};\n" + "class Wilma\n" + "{\n" + " virtual ~Wilma();\n" + "};\n" + "class Pebbles: public Fred, Wilma {};\n" + "void f()\n" + "{\n" + " Pebbles pebbles;\n" + " memset(&pebbles, 0, sizeof(pebbles));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:12]: (error) Using 'memset' on class that contains a virtual method\n", errout.str()); } void memsetOnStruct() From a084697410bac0e08324236e78185a0c1a8a92ff Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Wed, 9 Mar 2011 22:49:13 +1300 Subject: [PATCH 53/54] Check for memset on nested structs (ticket #1288) --- lib/checkclass.cpp | 30 ++++++++++++++++++++++++------ lib/checkclass.h | 10 +++++++--- test/testclass.cpp | 12 ++++++++++++ 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index c01baed55..a43c39ea5 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -695,6 +695,14 @@ void CheckClass::unusedPrivateFunctionError(const Token *tok, const std::string void CheckClass::checkMemsetType(const Token *tok, const std::string &type) { + // check for cached message for this type + std::map::const_iterator msg = _memsetClassMessages.find(type); + if (msg != _memsetClassMessages.end()) + { + memsetError(tok, type, msg->second); + return; + } + // Warn if type is a class or struct that contains any std::* variables const std::string pattern2(std::string("struct|class ") + type + " :|{"); const Token *tstruct = Token::findmatch(_tokenizer->tokens(), pattern2.c_str()); @@ -702,7 +710,8 @@ void CheckClass::checkMemsetType(const Token *tok, const std::string &type) if (!tstruct) return; - const std::string &typeName = tstruct->str(); + // typeKind is either 'struct' or 'class' + const std::string &typeKind = tstruct->str(); if (tstruct->tokAt(2)->str() == ":") { @@ -743,7 +752,7 @@ void CheckClass::checkMemsetType(const Token *tok, const std::string &type) tstruct->str().find(":") != std::string::npos) { if (Token::Match(tstruct->next(), "std :: %type% %var% ;")) - memsetError(tok, tok->str(), "'std::" + tstruct->strAt(3) + "'", typeName); + memsetError(tok, type, tok->str(), "'std::" + tstruct->strAt(3) + "'", typeKind); else if (Token::Match(tstruct->next(), "std :: %type% <")) { @@ -771,10 +780,12 @@ void CheckClass::checkMemsetType(const Token *tok, const std::string &type) // found error => report if (Token::Match(tstruct, "> %var% ;")) - memsetError(tok, tok->str(), "'std::" + typestr + "'", typeName); + memsetError(tok, type, tok->str(), "'std::" + typestr + "'", typeKind); } else if (Token::simpleMatch(tstruct->next(), "virtual")) - memsetError(tok, tok->str(), "virtual method", typeName); + memsetError(tok, type, tok->str(), "virtual method", typeKind); + else if (!Token::Match(tstruct->next(), "static|}")) + checkMemsetType(tok, tstruct->next()->str()); } } } @@ -816,9 +827,16 @@ void CheckClass::noMemset() } } -void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type) +void CheckClass::memsetError(const Token *tok, const std::string &type, const std::string &message) { - reportError(tok, Severity::error, "memsetClass", "Using '" + memfunc + "' on " + type + " that contains a " + classname); + reportError(tok, Severity::error, "memsetClass", message); + // cache the message for this type so we don't have to look it up again + _memsetClassMessages[type] = message; +} + +void CheckClass::memsetError(const Token *tok, const std::string &type, const std::string &memfunc, const std::string &classname, const std::string &typekind) +{ + memsetError(tok, type, "Using '" + memfunc + "' on " + typekind + " that contains a " + classname); } //--------------------------------------------------------------------------- diff --git a/lib/checkclass.h b/lib/checkclass.h index 1b3b5fa43..9cd12f499 100644 --- a/lib/checkclass.h +++ b/lib/checkclass.h @@ -84,7 +84,6 @@ public: * Important: The checking doesn't work on simplified tokens list. */ void noMemset(); - void checkMemsetType(const Token *tok, const std::string &type); /** @brief 'operator=' should return something and it should not be const. */ void operatorEq(); @@ -118,7 +117,8 @@ private: void uninitVarError(const Token *tok, const std::string &classname, const std::string &varname); void operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname); void unusedPrivateFunctionError(const Token *tok, const std::string &classname, const std::string &funcname); - void memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type); + void memsetError(const Token *tok, const std::string &type, const std::string &message); + void memsetError(const Token *tok, const std::string &type, const std::string &memfunc, const std::string &classname, const std::string &typekind); void operatorEqReturnError(const Token *tok); void virtualDestructorError(const Token *tok, const std::string &Base, const std::string &Derived); void thisSubtractionError(const Token *tok); @@ -134,7 +134,7 @@ private: c.uninitVarError(0, "classname", "varname"); c.operatorEqVarError(0, "classname", ""); c.unusedPrivateFunctionError(0, "classname", "funcname"); - c.memsetError(0, "memfunc", "classname", "class"); + c.memsetError(0, "type", "memfunc", "classname", "class"); c.operatorEqReturnError(0); //c.virtualDestructorError(0, "Base", "Derived"); c.thisSubtractionError(0); @@ -228,6 +228,10 @@ private: void initializeVarList(const Function &func, std::list &callstack, const Scope *scope, std::vector &usage); bool canNotCopy(const Scope *scope) const; + + // noMemset helpers + void checkMemsetType(const Token *tok, const std::string &type); + std::map _memsetClassMessages; }; /// @} //--------------------------------------------------------------------------- diff --git a/test/testclass.cpp b/test/testclass.cpp index ff0da1953..afa2748a2 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -2962,6 +2962,18 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:9]: (error) Using 'memset' on class that contains a 'std::string'\n", errout.str()); + checkNoMemset("struct Stringy {\n" + " std::string inner;\n" + "};\n" + "struct Foo {\n" + " Stringy s;\n" + "};\n" + "int main() {\n" + " Foo foo;\n" + " memset(&foo, 0, sizeof(Foo));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:9]: (error) Using 'memset' on struct that contains a 'std::string'\n", errout.str()); + checkNoMemset("class Fred\n" "{\n" " virtual ~Fred();\n" From be33f6b94510c02b622063afc995a208ef43b30a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 9 Mar 2011 19:53:59 +0100 Subject: [PATCH 54/54] Fixed #2635 (False positive: resource leak) --- lib/checkmemoryleak.cpp | 4 ++-- test/testmemleak.cpp | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index a53a06d5b..8c96509dc 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -1964,8 +1964,8 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok) } else { - // remove the "if* ;" - Token::eraseTokens(tok2, tok2->tokAt(3)); + // remove the "if*" + Token::eraseTokens(tok2, tok2->tokAt(2)); } done = false; } diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index c23d64395..17cd57147 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -727,6 +727,10 @@ private: // use ; dealloc ; ASSERT_EQUALS("; alloc ; use ; if return ; dealloc ;", simplifycode("; alloc ; use ; if { return ; } dealloc ;")); + + // #2635 - false negative + ASSERT_EQUALS("; alloc ; return use ; }", + simplifycode("; alloc ; if(!var) { loop { ifv { } } alloc ; } return use; }")); }