diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index f5f2729d6..d23bb5a0e 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -620,6 +620,8 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const break; } } + if (i->isArray() && i->isClass()) // Array of class/struct members. Initialized by ctor. + variables.write(i->varId()); if (i->isArray() && Token::Match(i->nameToken(), "%var% [ %var% ]")) // Array index variable read. variables.read(i->nameToken()->tokAt(2)->varId()); @@ -706,7 +708,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const } } - else if (Token::Match(tok, "return|throw %var%")) { + else if (Token::Match(tok, "return|throw")) { for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) { if (tok2->varId()) variables.readAll(tok2->varId()); @@ -838,7 +840,12 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const } } - else if (Token::Match(tok, ">>|& %var%")) + else if (Token::Match(tok, "& %var%")) { + if (tok->previous()->isName() || tok->previous()->isNumber()) { // bitop + variables.read(tok->next()->varId()); + } else // addressof + variables.use(tok->next()->varId()); // use = read + write + } else if (Token::Match(tok, ">> %var%")) variables.use(tok->next()->varId()); // use = read + write else if (Token::Match(tok, "%var% >>|&") && Token::Match(tok->previous(), "[{};:]")) variables.read(tok->varId()); @@ -865,8 +872,8 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const else if (Token::Match(tok, "%var% .")) variables.use(tok->varId()); // use = read + write - else if ((Token::Match(tok, "[(=&!]") || tok->isExtendedOp()) && - (Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false|new")) && tok->strAt(2) != "=") + else if (tok->isExtendedOp() && + Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false|new") && tok->strAt(2) != "=") variables.readAll(tok->next()->varId()); else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || tok->next()->isExtendedOp())) @@ -994,9 +1001,9 @@ void CheckUnusedVar::checkStructMemberUsage() if (Token::Match(tok, "struct|union %type% {")) { structname.clear(); - if (Token::simpleMatch(tok->previous(), "extern")) + if (tok->strAt(-1) == "extern") continue; - if ((!tok->previous() || Token::simpleMatch(tok->previous(), ";")) && Token::Match(tok->linkAt(2), ("} ; " + tok->strAt(1) + " %var% ;").c_str())) + if ((!tok->previous() || tok->previous()->str() == ";") && Token::Match(tok->linkAt(2), ("} ; " + tok->strAt(1) + " %var% ;").c_str())) continue; structname = tok->strAt(1); diff --git a/lib/checkunusedvar.h b/lib/checkunusedvar.h index 833713590..eabca9e0c 100644 --- a/lib/checkunusedvar.h +++ b/lib/checkunusedvar.h @@ -70,6 +70,7 @@ public: /** @brief %Check that all struct members are used */ void checkStructMemberUsage(); +private: // Error messages.. void unusedStructMemberError(const Token *tok, const std::string &structname, const std::string &varname); void unusedVariableError(const Token *tok, const std::string &varname); diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 92127c2f6..4c44d07f7 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2299,6 +2299,8 @@ bool Tokenizer::tokenize(std::istream &code, if (!preprocessorCondition) { setVarId(); + createLinks2(); + // Change initialisation of variable to assignment simplifyInitVar(); } @@ -2814,7 +2816,7 @@ void Tokenizer::setVarId() if (Token::Match(tok, "( %type% *|& %var% [),]") && !tok->next()->isStandardType()) { if (!Token::Match(tok->previous(), "%type%")) continue; - if (tok->previous() && tok->previous()->str() == "return") + if (Token::Match(tok->previous(), "return|if|while")) continue; if (tok->link() && !Token::Match(tok->link()->next(), "const| {") && (!tok->link()->next() || tok->link()->next()->str() != ":")) @@ -2865,7 +2867,7 @@ void Tokenizer::setVarId() if (tok->str() == "unsigned") tok = tok->next(); - if (Token::Match(tok, "using namespace| %type% ;")) { + if (Token::Match(tok, "using namespace %type% ;")) { tok = tok->next(); continue; } @@ -3296,6 +3298,62 @@ bool Tokenizer::createLinks() return true; } +void Tokenizer::createLinks2() +{ + std::stack type; + std::stack links; + for (Token *token = _tokens; token; token = token->next()) { + if (token->link()) { + if (Token::Match(token, "{|[|(")) + type.push(token); + else if (Token::Match(token, "}|]|)")) { + while (type.top()->str() == "<") + type.pop(); + type.pop(); + } else + token->link(0); + } + + else if (token->str() == ";") + while (!links.empty()) + links.pop(); + else if (token->str() == "<" && token->previous() && token->previous()->isName() && !token->previous()->varId()) { + type.push(token); + links.push(token); + } else if (token->str() == ">" || token->str() == ">>") { + if (links.empty()) // < and > don't match. + continue; + if (token->next() && !token->next()->isName() && !Token::Match(token->next(), ">|&|*|::|,")) + continue; + + // Check type of open link + if (type.empty() || type.top()->str() != "<" || (token->str() == ">>" && type.size() < 2)) { + if (!links.empty()) + links.pop(); + continue; + } + const Token* top = type.top(); + type.pop(); + if (token->str() == ">>" && type.top()->str() != "<") { + type.push(top); + if (!links.empty()) + links.pop(); + continue; + } + + if (token->str() == ">>") { // C++11 right angle bracket + if (links.size() < 2) + continue; + token->str(">"); + token->insertToken(">"); + } + + Token::createMutualLinks(links.top(), token); + links.pop(); + } + } +} + void Tokenizer::simplifySizeof() { for (Token *tok = _tokens; tok; tok = tok->next()) { @@ -8069,17 +8127,16 @@ bool Tokenizer::validate() const const Token *lastTok = 0; for (const Token *tok = tokens(); tok; tok = tok->next()) { lastTok = tok; - if (Token::Match(tok, "[{([]")) { + if (Token::Match(tok, "[{([]") || (tok->str() == "<" && tok->link())) { if (tok->link() == 0) { cppcheckError(tok); return false; } linktok.push(tok); - continue; } - else if (Token::Match(tok, "[})]]")) { + else if (Token::Match(tok, "[})]]") || (tok->str() == ">" && tok->link())) { if (tok->link() == 0) { cppcheckError(tok); return false; @@ -8101,10 +8158,9 @@ bool Tokenizer::validate() const } linktok.pop(); - continue; } - if (tok->link() != 0) { + else if (tok->link() != 0) { cppcheckError(tok); return false; } diff --git a/lib/tokenize.h b/lib/tokenize.h index 8727f8a66..ceeb1355a 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -583,6 +583,11 @@ public: */ bool createLinks(); + /** + * Setup links between < and >. + */ + void createLinks2(); + /** Syntax error */ void syntaxError(const Token *tok); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 09ec7506f..ef70f6a08 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -206,6 +206,7 @@ private: TEST_CASE(varid40); // ticket #3279 TEST_CASE(varid41); // ticket #3340 (varid for union type) TEST_CASE(varid42); // ticket #3316 (varid for array) + TEST_CASE(varid43); TEST_CASE(varid44); TEST_CASE(varidFunctionCall1); TEST_CASE(varidFunctionCall2); @@ -223,7 +224,6 @@ private: TEST_CASE(varid_operator); TEST_CASE(varid_throw); TEST_CASE(varid_unknown_macro); // #2638 - unknown macro is not type - TEST_CASE(varid_using); // ticket #3648 TEST_CASE(varidclass1); TEST_CASE(varidclass2); @@ -3249,6 +3249,13 @@ private: tokenizeDebugListing(code)); } + void varid43() { + const std::string code("int main(int flag) { if(a & flag) { return 1; } }"); + ASSERT_EQUALS("\n\n##file 0\n" + "1: int main ( int flag@1 ) { if ( a & flag@1 ) { return 1 ; } }\n", + tokenizeDebugListing(code)); + } + void varid44() { const std::string code("class A:public B,public C,public D {};"); ASSERT_EQUALS("\n\n##file 0\n" @@ -3628,14 +3635,6 @@ private: ASSERT_EQUALS(expected, tokenizeDebugListing(code)); } - void varid_using() { - // #3648 - const char code[] = "using std::size_t;"; - const char expected[] = "\n\n##file 0\n" - "1: using long ;\n"; - ASSERT_EQUALS(expected, tokenizeDebugListing(code)); - } - void varidclass1() { const std::string actual = tokenizeDebugListing( "class Fred\n" @@ -5053,6 +5052,33 @@ private: ASSERT_EQUALS(true, tok->linkAt(8) == tok->tokAt(9)); ASSERT_EQUALS(true, tok->linkAt(9) == tok->tokAt(8)); } + + { + const char code[] = "bool foo(C a, bar>& f, int b) {\n" + " return(af);\n" + "}"; + errout.str(""); + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + const Token *tok = tokenizer.tokens(); + // template< + ASSERT_EQUALS((long long)tok->tokAt(6), (long long)tok->linkAt(4)); + ASSERT_EQUALS((long long)tok->tokAt(4), (long long)tok->linkAt(6)); + + // bar< + ASSERT_EQUALS((long long)tok->tokAt(17), (long long)tok->linkAt(10)); + ASSERT_EQUALS((long long)tok->tokAt(10), (long long)tok->linkAt(17)); + + // x< + ASSERT_EQUALS((long long)tok->tokAt(16), (long long)tok->linkAt(14)); + ASSERT_EQUALS((long long)tok->tokAt(14), (long long)tok->linkAt(16)); + + // af + ASSERT_EQUALS(0, (long long)tok->linkAt(28)); + ASSERT_EQUALS(0, (long long)tok->linkAt(32)); + } } void removeExceptionSpecification1() { @@ -5318,8 +5344,7 @@ private: void cpp0xtemplate2() { // tokenize ">>" into "> >" const char *code = "list> ints;\n"; - TODO_ASSERT_EQUALS("list < list < int > > ints ;", - "list < list < int >> ints ;", tokenizeAndStringify(code)); + ASSERT_EQUALS("list < list < int > > ints ;", tokenizeAndStringify(code)); } void cpp0xtemplate3() {