From 5d50e7e9ae9bac4be69c33d5b5c642f8287b4d27 Mon Sep 17 00:00:00 2001 From: PKEuS Date: Tue, 19 Aug 2014 11:06:52 +0200 Subject: [PATCH] Changed heuristics to detect variable constructor initialization syntax (#6071) --- lib/tokenize.cpp | 75 ++++++++++++++++++++++--------------------- test/testtokenize.cpp | 38 +++++++++++++++------- 2 files changed, 65 insertions(+), 48 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index df35cb0d1..604750efe 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2281,7 +2281,8 @@ static bool setVarIdParseDeclaration(const Token **tok, const std::mapstr() != "::") break; } else { - ++typeCount; + if (tok2->str() != "void" || Token::Match(tok2, "void const| *|(")) // just "void" cannot be a variable type + ++typeCount; ++singleNameCount; } } else if ((TemplateSimplifier::templateParameters(tok2) > 0) || @@ -2545,7 +2546,7 @@ void Tokenizer::setVarId() } if (tok == list.front() || Token::Match(tok, "[;{}]") || - (Token::Match(tok,"[(,]") && (!executableScope.top() || Token::simpleMatch(tok->link(), ") {"))) || + (Token::Match(tok, "[(,]") && (!executableScope.top() || Token::simpleMatch(tok->link(), ") {"))) || (tok->isName() && tok->str().at(tok->str().length()-1U) == ':')) { // No variable declarations in sizeof @@ -2570,45 +2571,45 @@ void Tokenizer::setVarId() if (notstart.find(tok2->str()) != notstart.end()) continue; - const bool decl = setVarIdParseDeclaration(&tok2, variableId, executableScope.top(), isCPP()); + bool decl = setVarIdParseDeclaration(&tok2, variableId, executableScope.top(), isCPP()); + if (decl) { + const Token* prev2 = tok2->previous(); + if (Token::Match(prev2, "%type% [;[=,)]") && tok2->previous()->str() != "const") + ; + else if (Token::Match(prev2, "%type% ( !!)") && Token::simpleMatch(tok2->link(), ") ;")) { + // In C++ , a variable can't be called operator+ or something like that. + if (isCPP() && + prev2->str().size() >= 9 && + prev2->str().compare(0, 8, "operator") == 0 && + prev2->str()[8] != '_' && + !std::isalnum(prev2->str()[8])) + continue; - if (decl && Token::Match(tok2->previous(), "%type% [;[=,)]") && tok2->previous()->str() != "const") { - variableId[tok2->previous()->str()] = ++_varId; - tok = tok2->previous(); - } - - else if (decl && Token::Match(tok2->previous(), "%type% ( !!)") && Token::simpleMatch(tok2->link(), ") ;")) { - // In C++ , a variable can't be called operator+ or something like that. - if (isCPP() && - tok2->previous()->str().size() >= 9 && - tok2->previous()->str().compare(0, 8, "operator") == 0 && - tok2->previous()->str()[8] != '_' && - !std::isalnum(tok2->previous()->str()[8])) - continue; - - const Token *tok3 = tok2->next(); - if (!tok3->isStandardType() && tok3->str() != "void" && !Token::Match(tok3, "struct|union|class %type%") && tok3->str() != "." && !Token::Match(tok2->link()->previous(), "[&*]")) { - bool isDecl = true; - for (; tok3; tok3 = tok3->nextArgument()) { - if (tok3->strAt(-2) == "&" || tok3->strAt(-2) == "*" || (notstart.find(tok3->str()) == notstart.end() && setVarIdParseDeclaration(&tok3, variableId, executableScope.top(), isCPP()))) { - isDecl = false; - break; + const Token *tok3 = tok2->next(); + if (!tok3->isStandardType() && tok3->str() != "void" && !Token::Match(tok3, "struct|union|class %type%") && tok3->str() != "." && !Token::Match(tok2->link()->previous(), "[&*]")) { + if (!executableScope.top()) { + // Detecting initializations with () in non-executable scope is hard and often impossible to be done safely. Thus, only treat code as a variable that definitly is one. + decl = false; + for (; tok3; tok3 = tok3->nextArgument()) { + if (tok3->isLiteral() || (tok3->isName() && (variableId.find(tok3->str()) != variableId.end())) || tok3->isOp() || (tok3->next()->isOp() && !Token::Match(tok3->next(), "*|&")) || notstart.find(tok3->str()) != notstart.end()) { + decl = true; + break; + } + } } - } - if (isDecl) { - variableId[tok2->previous()->str()] = ++_varId; - tok = tok2->previous(); - } + } else + decl = false; + } else if (isCPP() && Token::Match(prev2, "%type% {") && Token::simpleMatch(tok2->link(), "} ;")) { // C++11 initialization style + if (Token::Match(prev2, "do|try|else")) + continue; + } else + decl = false; + + if (decl) { + variableId[prev2->str()] = ++_varId; + tok = tok2->previous(); } } - - else if (decl && isCPP() && Token::Match(tok2->previous(), "%type% {") && Token::simpleMatch(tok2->link(), "} ;")) { // C++11 initialization style - if (Token::Match(tok2->previous(), "do|try|else")) - continue; - - variableId[tok2->previous()->str()] = ++_varId; - tok = tok2->previous(); - } } if (tok->isName()) { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 52b51c628..ef47be692 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -4633,14 +4633,16 @@ private: } void varid_in_class17() { // #6056 - Set no varid for member functions - const char code[] = "class Fred {\n" - " int method_with_internal(X&);\n" - " int method_with_internal(X*);\n" - " int method_with_internal(int&);\n" - " int method_with_internal(A* b, X&);\n" - " int method_with_internal(X&, A* b);\n" - " int method_with_internal(const B &, int);\n" - "};"; + const char code1[] = "class Fred {\n" + " int method_with_internal(X&);\n" + " int method_with_internal(X*);\n" + " int method_with_internal(int&);\n" + " int method_with_internal(A* b, X&);\n" + " int method_with_internal(X&, A* b);\n" + " int method_with_internal(const B &, int);\n" + " void Set(BAR);\n" + " FOO Set(BAR);\n" + "};"; ASSERT_EQUALS("\n\n##file 0\n" "1: class Fred {\n" "2: int method_with_internal ( X & ) ;\n" @@ -4649,7 +4651,21 @@ private: "5: int method_with_internal ( A * b@1 , X & ) ;\n" "6: int method_with_internal ( X & , A * b@2 ) ;\n" "7: int method_with_internal ( const B & , int ) ;\n" - "8: } ;\n", tokenizeDebugListing(code, false, "test.cpp")); + "8: void Set ( BAR ) ;\n" + "9: FOO Set ( BAR ) ;\n" + "10: } ;\n", tokenizeDebugListing(code1, false, "test.cpp")); + + const char code2[] = "int i;\n" + "SomeType someVar1(i, i);\n" + "SomeType someVar2(j, j);\n" + "SomeType someVar3(j, 1);\n" + "SomeType someVar4(new bar);"; + ASSERT_EQUALS("\n\n##file 0\n" + "1: int i@1 ;\n" + "2: SomeType someVar1@2 ( i@1 , i@1 ) ;\n" + "3: SomeType someVar2 ( j , j ) ;\n" // This one could be a function + "4: SomeType someVar3@3 ( j , 1 ) ;\n" + "5: SomeType someVar4@4 ( new bar ) ;\n", tokenizeDebugListing(code2, false, "test.cpp")); } void varid_initList() { @@ -7297,12 +7313,12 @@ private: void functionpointer6() { const char code1[] = ";void (*fp(f))(int);"; const char expected1[] = "\n\n##file 0\n" - "1: ; void * fp@1 ( f ) ;\n"; + "1: ; void * fp ( f ) ;\n"; // No varId - it could be a function ASSERT_EQUALS(expected1, tokenizeDebugListing(code1, false)); const char code2[] = ";std::string (*fp(f))(int);"; const char expected2[] = "\n\n##file 0\n" - "1: ; std :: string * fp@1 ( f ) ;\n"; + "1: ; std :: string * fp ( f ) ;\n"; ASSERT_EQUALS(expected2, tokenizeDebugListing(code2, false)); }