From 893b84a87cd8dee03aa4dd8d5e915ba01dc95fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 28 Feb 2011 20:29:34 +0100 Subject: [PATCH 01/15] Fixed #2615 (Segmentation fault in cppcheck 1.47) --- lib/tokenize.cpp | 58 ++++++++++++++++++++++++++--------- test/testtokenize.cpp | 71 ++++++++++++++++++++++++++++--------------- 2 files changed, 91 insertions(+), 38 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 7460faf3b..b56ba9e25 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9349,26 +9349,56 @@ const SymbolDatabase *Tokenizer::getSymbolDatabase() const void Tokenizer::simplifyOperatorName() { - for (const Token *tok = _tokens; tok; tok = tok->next()) + for (Token *tok = _tokens; tok; tok = tok->next()) { - if (Token::Match(tok, ") const| {|;|=")) + if (tok->str() == "operator") { - Token *tok1 = tok->link(); - Token *tok2 = tok1; - - tok1 = tok1->previous(); - while (tok1 && !Token::Match(tok1, "operator|{|}|;|public:|private|protected:")) + // operator op + std::string op; + Token *par = tok->next(); + bool done = false; + while (!done && par) { - tok1 = tok1->previous(); + 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 (tok1 && tok1->str() == "operator") + if (par && Token::Match(par->link(), ") const| [=;{),]")) { - while (tok1->next() != tok2) - { - tok1->str(tok1->str() + tok1->next()->str()); - tok1->deleteNext(); - } + tok->str("operator" + op); + Token::eraseTokens(tok,par); } } } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index c25552845..13d86cb28 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -305,7 +305,10 @@ private: // Tokenize JAVA TEST_CASE(java); - TEST_CASE(simplifyOperatorName); + TEST_CASE(simplifyOperatorName1); + TEST_CASE(simplifyOperatorName2); + TEST_CASE(simplifyOperatorName3); + TEST_CASE(simplifyOperatorName4); // Some simple cleanups of unhandled macros in the global scope TEST_CASE(removeMacrosInGlobalScope); @@ -5312,36 +5315,56 @@ private: ASSERT_EQUALS("void f ( ) { }", javatest("void f() throws Exception { }")); } - void simplifyOperatorName() + void simplifyOperatorName1() { // make sure C code doesn't get changed - const char code1[] = "void operator () {}" - "int main()" - "{" - " operator();" - "}"; + const char code[] = "void operator () {}" + "int main()" + "{" + " operator();" + "}"; - const char result1 [] = "void operator ( ) { } " - "int main ( ) " - "{ " - "operator ( ) ; " - "}"; + const char result [] = "void operator ( ) { } " + "int main ( ) " + "{ " + "operator ( ) ; " + "}"; - ASSERT_EQUALS(result1, tokenizeAndStringify(code1,false)); + ASSERT_EQUALS(result, tokenizeAndStringify(code,false)); + } - const char code2[] = "class Fred" - "{" - " Fred(const Fred & f) { operator = (f); }" - " operator = ();" - "}"; + void simplifyOperatorName2() + { + const char code[] = "class Fred" + "{" + " Fred(const Fred & f) { operator = (f); }" + " operator = ();" + "}"; - const char result2 [] = "class Fred " - "{ " - "Fred ( const Fred & f ) { operator= ( f ) ; } " - "operator= ( ) ; " - "}"; + const char result [] = "class Fred " + "{ " + "Fred ( const Fred & f ) { operator= ( f ) ; } " + "operator= ( ) ; " + "}"; - ASSERT_EQUALS(result2, tokenizeAndStringify(code2,false)); + ASSERT_EQUALS(result, tokenizeAndStringify(code,false)); + } + + void simplifyOperatorName3() + { + // #2615 + const char code[] = "void f() {" + "static_cast(xResult.operator->())->GetMatrix();" + "}"; + const char result[] = "void f ( ) { static_cast < ScToken * > ( xResult . operator. ( ) ) . GetMatrix ( ) ; }"; + ASSERT_EQUALS(result, tokenizeAndStringify(code,false)); + } + + void simplifyOperatorName4() + { + const char code[] = "void operator==() { }"; + const char result[] = "void operator== ( ) { }"; + ASSERT_EQUALS(result, tokenizeAndStringify(code,false)); } void removeMacrosInGlobalScope() From 92efbd748ee08a48b451f8b09c8f2a60677f3736 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Mon, 28 Feb 2011 19:35:00 -0500 Subject: [PATCH 02/15] fix #2595 bitfield fix for case x: break; and default: break; --- lib/tokenize.cpp | 6 ++++-- test/testtokenize.cpp | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index b56ba9e25..d31c06fe3 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9124,7 +9124,8 @@ void Tokenizer::simplifyBitfields() { Token *last = 0; - if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %any% ;|,")) + if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %any% ;|,") && + tok->next()->str() != "case") { int offset = 0; if (tok->next()->str() == "const") @@ -9133,7 +9134,8 @@ void Tokenizer::simplifyBitfields() 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% ;")) + else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %any% ;") && + tok->next()->str() != "default") { int offset = 0; if (tok->next()->str() == "const") diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 13d86cb28..02e75604d 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -5121,6 +5121,12 @@ private: const char code3[] = "struct A { bool : true; };"; ASSERT_EQUALS("struct A { } ;", tokenizeAndStringify(code3,false)); + + const char code4[] = "void f(int a) { switch (a) { case b: break; } }"; + ASSERT_EQUALS("void f ( int a ) { switch ( a ) { case b : ; break ; } }", tokenizeAndStringify(code4,true)); + + const char code5[] = "void f(int a) { switch (a) { default: break; } }"; + ASSERT_EQUALS("void f ( int a ) { switch ( a ) { default : ; break ; } }", tokenizeAndStringify(code5,true)); } void microsoftMFC() From 87fd55b155f2bcfbbb2c1de4eb91249bed9d764b Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Tue, 1 Mar 2011 19:30:42 +1300 Subject: [PATCH 03/15] test case for #if 0 exclusion --- test/testpreprocessor.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 37df95c61..a16eccfd8 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -92,6 +92,8 @@ private: TEST_CASE(error3); + TEST_CASE(if0_exclude); + // Don't handle include in a #if 0 block TEST_CASE(if0_include_1); TEST_CASE(if0_include_2); @@ -641,6 +643,18 @@ private: ASSERT_EQUALS("[test.c:1]: (error) #error hello world!\n", errout.str()); } + void if0_exclude() + { + Settings settings; + Preprocessor preprocessor(&settings, this); + + std::istringstream code("#if 0\n" + "A\n" + "#endif\n" + "B\n"); + ASSERT_EQUALS("\n\n\nB\n", preprocessor.read(code,"",NULL)); + } + void if0_include_1() { Settings settings; From 31c56d7353a61faa9302a64f17cae44606ed8118 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Tue, 1 Mar 2011 19:32:47 +1300 Subject: [PATCH 04/15] handle embedded whitespace in #if 0 processing --- lib/preprocessor.cpp | 8 ++++---- test/testpreprocessor.cpp | 13 +++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 17963f673..c41134a09 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -178,15 +178,15 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename, // Remove all comments.. result = removeComments(result, filename, settings); - // Remove '#if 0' blocks - if (result.find("#if 0\n") != std::string::npos) - result = removeIf0(result); - // ------------------------------------------------------------------------------------------ // // Clean up all preprocessor statements result = preprocessCleanupDirectives(result); + // Remove '#if 0' blocks + if (result.find("#if 0\n") != std::string::npos) + result = removeIf0(result); + // ------------------------------------------------------------------------------------------ // // Clean up preprocessor #if statements with Parantheses diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index a16eccfd8..1e6ce5c64 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -93,6 +93,7 @@ private: TEST_CASE(error3); TEST_CASE(if0_exclude); + TEST_CASE(if0_whitespace); // Don't handle include in a #if 0 block TEST_CASE(if0_include_1); @@ -655,6 +656,18 @@ private: ASSERT_EQUALS("\n\n\nB\n", preprocessor.read(code,"",NULL)); } + void if0_whitespace() + { + Settings settings; + Preprocessor preprocessor(&settings, this); + + std::istringstream code(" # if 0 \n" + "A\n" + " # endif \n" + "B\n"); + ASSERT_EQUALS("\n\n\nB\n", preprocessor.read(code,"",NULL)); + } + void if0_include_1() { Settings settings; From a33151673568196251831e3dad933df9d3c12cab Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Tue, 1 Mar 2011 19:50:17 +1300 Subject: [PATCH 05/15] handle #if (0) after removing parentheses --- lib/preprocessor.cpp | 8 ++++---- test/testpreprocessor.cpp | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index c41134a09..f7fdcde6e 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -183,15 +183,15 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename, // Clean up all preprocessor statements result = preprocessCleanupDirectives(result); - // Remove '#if 0' blocks - if (result.find("#if 0\n") != std::string::npos) - result = removeIf0(result); - // ------------------------------------------------------------------------------------------ // // Clean up preprocessor #if statements with Parantheses result = removeParantheses(result); + // Remove '#if 0' blocks + if (result.find("#if 0\n") != std::string::npos) + result = removeIf0(result); + return result; } diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 1e6ce5c64..2e3721914 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -654,6 +654,12 @@ private: "#endif\n" "B\n"); ASSERT_EQUALS("\n\n\nB\n", preprocessor.read(code,"",NULL)); + + std::istringstream code2("#if (0)\n" + "A\n" + "#endif\n" + "B\n"); + ASSERT_EQUALS("\n\n\nB\n", preprocessor.read(code2,"",NULL)); } void if0_whitespace() From 2efb2efaca421f2097f89fbedcd2b2ceaf99c9eb Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Tue, 1 Mar 2011 20:04:11 +1300 Subject: [PATCH 06/15] refactor #if 0 handling to leave preprocessor statements alone --- lib/preprocessor.cpp | 20 +++++++++++++++++--- test/testpreprocessor.cpp | 25 ++++++++++++++++++++----- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index f7fdcde6e..45ed8a425 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -563,19 +563,33 @@ std::string Preprocessor::removeIf0(const std::string &code) else { // replace '#if 0' with empty line - ret << "\n"; + ret << line << "\n"; // goto the end of the '#if 0' block unsigned int level = 1; + bool in = false; while (level > 0 && std::getline(istr,line)) { if (line.compare(0,3,"#if") == 0) ++level; else if (line == "#endif") --level; + else if (line == "#else") + { + if (level == 1) + in = true; + } + else + { + if (in) + ret << line << "\n"; + else + // replace code within '#if 0' block with empty lines + ret << "\n"; + continue; + } - // replace code within '#if 0' block with empty lines - ret << "\n"; + ret << line << "\n"; } } } diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 2e3721914..9b4fcf02f 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -94,6 +94,7 @@ private: TEST_CASE(if0_exclude); TEST_CASE(if0_whitespace); + TEST_CASE(if0_else); // Don't handle include in a #if 0 block TEST_CASE(if0_include_1); @@ -653,13 +654,13 @@ private: "A\n" "#endif\n" "B\n"); - ASSERT_EQUALS("\n\n\nB\n", preprocessor.read(code,"",NULL)); + ASSERT_EQUALS("#if 0\n\n#endif\nB\n", preprocessor.read(code,"",NULL)); std::istringstream code2("#if (0)\n" "A\n" "#endif\n" "B\n"); - ASSERT_EQUALS("\n\n\nB\n", preprocessor.read(code2,"",NULL)); + ASSERT_EQUALS("#if 0\n\n#endif\nB\n", preprocessor.read(code2,"",NULL)); } void if0_whitespace() @@ -671,7 +672,21 @@ private: "A\n" " # endif \n" "B\n"); - ASSERT_EQUALS("\n\n\nB\n", preprocessor.read(code,"",NULL)); + ASSERT_EQUALS("#if 0\n\n#endif\nB\n", preprocessor.read(code,"",NULL)); + } + + void if0_else() + { + Settings settings; + Preprocessor preprocessor(&settings, this); + + std::istringstream code("#if 0\n" + "A\n" + "#else\n" + "B\n" + "#endif\n" + "C\n"); + ASSERT_EQUALS("#if 0\n\n#else\nB\n#endif\nC\n", preprocessor.read(code,"",NULL)); } void if0_include_1() @@ -683,7 +698,7 @@ private: "#include \"a.h\"\n" "#endif\n" "AB\n"); - ASSERT_EQUALS("\n\n\nAB\n", preprocessor.read(code,"",NULL)); + ASSERT_EQUALS("#if 0\n\n#endif\nAB\n", preprocessor.read(code,"",NULL)); } void if0_include_2() @@ -698,7 +713,7 @@ private: "#endif\n" "#endif\n" "AB\n"); - ASSERT_EQUALS("\n\n\n\n\n\nAB\n", preprocessor.read(code,"",NULL)); + ASSERT_EQUALS("#if 0\n\n#ifdef WIN32\n#else\n#endif\n#endif\nAB\n", preprocessor.read(code,"",NULL)); } void includeguard1() From baf50c6db15585cfb5c6ec8ad68d2786b5387ff1 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Tue, 1 Mar 2011 20:17:54 +1300 Subject: [PATCH 07/15] add TODO for #elif inside #if 0 processing, also for #if 1 --- test/testpreprocessor.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 9b4fcf02f..bc1765840 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -95,6 +95,7 @@ private: TEST_CASE(if0_exclude); TEST_CASE(if0_whitespace); TEST_CASE(if0_else); + TEST_CASE(if0_elif); // Don't handle include in a #if 0 block TEST_CASE(if0_include_1); @@ -687,6 +688,30 @@ private: "#endif\n" "C\n"); ASSERT_EQUALS("#if 0\n\n#else\nB\n#endif\nC\n", preprocessor.read(code,"",NULL)); + + std::istringstream code2("#if 1\n" + "A\n" + "#else\n" + "B\n" + "#endif\n" + "C\n"); + TODO_ASSERT_EQUALS("#if 1\nA\n#else\n\n#endif\nC\n", + "#if 1\nA\n#else\nB\n#endif\nC\n", preprocessor.read(code2,"",NULL)); + } + + void if0_elif() + { + Settings settings; + Preprocessor preprocessor(&settings, this); + + std::istringstream code("#if 0\n" + "A\n" + "#elif 1\n" + "B\n" + "#endif\n" + "C\n"); + TODO_ASSERT_EQUALS("#if 0\n\n#elif 1\nB\n#endif\nC\n", + "#if 0\n\n\n\n#endif\nC\n", preprocessor.read(code,"",NULL)); } void if0_include_1() From a2d2d93958e3ecb707fa107f340b7a915143953d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 1 Mar 2011 17:58:15 +0100 Subject: [PATCH 08/15] astyle formatting --- gui/projectfiledialog.cpp | 2 +- test/testpreprocessor.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gui/projectfiledialog.cpp b/gui/projectfiledialog.cpp index 89bfd2b2b..a8917fc41 100644 --- a/gui/projectfiledialog.cpp +++ b/gui/projectfiledialog.cpp @@ -98,7 +98,7 @@ QStringList ProjectFileDialog::GetIncludePaths() const QListWidgetItem *item = mUI.mListIncludeDirs->item(i); includePaths << QDir::fromNativeSeparators(item->text()); } - return includePaths; + return includePaths; } QStringList ProjectFileDialog::GetDefines() const diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index bc1765840..96e1a33cf 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -658,9 +658,9 @@ private: ASSERT_EQUALS("#if 0\n\n#endif\nB\n", preprocessor.read(code,"",NULL)); std::istringstream code2("#if (0)\n" - "A\n" - "#endif\n" - "B\n"); + "A\n" + "#endif\n" + "B\n"); ASSERT_EQUALS("#if 0\n\n#endif\nB\n", preprocessor.read(code2,"",NULL)); } From db04d7b71e534c1541972c93fdefc1a9151fbfda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 1 Mar 2011 18:02:50 +0100 Subject: [PATCH 09/15] Fixed #2616 (Segmentation fault with unknown macro) --- lib/tokenize.cpp | 3 --- test/testtokenize.cpp | 7 +++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index d31c06fe3..f0a8f6318 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4600,9 +4600,6 @@ void Tokenizer::simplifyIfAddBraces() continue; } - if (tok->previous() && !Token::Match(tok->previous(), ";|{|}|else|)|:")) - continue; - if (Token::Match(tok, "if|for|while (")) { // don't add "{}" around ";" in "do {} while();" (#609) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 02e75604d..76ddfc0cb 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -80,6 +80,7 @@ private: TEST_CASE(ifAddBraces12); TEST_CASE(ifAddBraces13); TEST_CASE(ifAddBraces14); // #2610 - segfault: if()<{} + TEST_CASE(ifAddBraces15); // #2616 - unknown macro before if TEST_CASE(whileAddBraces); TEST_CASE(doWhileAddBraces); @@ -861,6 +862,12 @@ private: tokenizeAndStringify("if()<{}", false); } + void ifAddBraces15() + { + // ticket #2616 - unknown macro before if + ASSERT_EQUALS("{ A if ( x ) { y ( ) ; } }", tokenizeAndStringify("{A if(x)y();}", false)); + } + void whileAddBraces() { From 8e9a1c33ad209ef9da297cad0490805f353b1b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 1 Mar 2011 20:20:48 +0100 Subject: [PATCH 10/15] Fixed #2618 (Tokenizer::simplifyKnownVariables: Don't use known string value if address is wanted) --- lib/tokenize.cpp | 6 ++++++ test/testtokenize.cpp | 36 ++++++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f0a8f6318..aa4c00af8 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6636,6 +6636,12 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign 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(); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 76ddfc0cb..72763bc01 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -2053,17 +2053,33 @@ private: void simplifyKnownVariables42() { - const char code[] = "void f() {\n" - " char str1[10], str2[10];\n" - " strcpy(str1, \"abc\");\n" - " strcpy(str2, str1);\n" - "}"; - const char expected[] = "void f ( ) {\n" - "char str1 [ 10 ] ; char str2 [ 10 ] ;\n" - "strcpy ( str1 , \"abc\" ) ;\n" - "strcpy ( str2 , \"abc\" ) ;\n" + { + const char code[] = "void f() {\n" + " char str1[10], str2[10];\n" + " strcpy(str1, \"abc\");\n" + " strcpy(str2, str1);\n" "}"; - ASSERT_EQUALS(expected, tokenizeAndStringify(code, true)); + const char expected[] = "void f ( ) {\n" + "char str1 [ 10 ] ; char str2 [ 10 ] ;\n" + "strcpy ( str1 , \"abc\" ) ;\n" + "strcpy ( str2 , \"abc\" ) ;\n" + "}"; + ASSERT_EQUALS(expected, tokenizeAndStringify(code, true)); + } + + { + const char code[] = "void f() {" + " char *s = malloc(10);" + " strcpy(s, \"\");" + " free(s);" + "}"; + const char expected[] = "void f ( ) {" + " char * s ; s = malloc ( 10 ) ;" + " strcpy ( s , \"\" ) ;" + " free ( s ) ; " + "}"; + ASSERT_EQUALS(expected, tokenizeAndStringify(code, true)); + } } void simplifyKnownVariablesBailOutAssign() From c9b2ab3c260523f726c4d435331b8ddd8a0ffc35 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Wed, 2 Mar 2011 21:08:27 -0500 Subject: [PATCH 11/15] add debug message for function argument missing varid --- lib/symboldatabase.cpp | 81 +++++++++++++++++++++----------------- lib/symboldatabase.h | 5 +++ test/testautovariables.cpp | 2 +- 3 files changed, 51 insertions(+), 37 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 03ccd8b00..769f13671 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -623,22 +623,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti scope = *it; if (scope->isClassOrStruct() && scope->needInitialization == Scope::Unknown) - { - std::list locationList; - ErrorLogger::ErrorMessage::FileLocation loc; - loc.line = scope->classDef->linenr(); - loc.setfile(_tokenizer->file(scope->classDef)); - locationList.push_back(loc); - - const ErrorLogger::ErrorMessage errmsg(locationList, - Severity::debug, - "SymbolDatabase::SymbolDatabase couldn't resolve all user defined types.", - "debug"); - if (_errorLogger) - _errorLogger->reportErr(errmsg); - else - Check::reportError(errmsg); - } + debugMessage(scope->classDef, "SymbolDatabase::SymbolDatabase couldn't resolve all user defined types."); } } @@ -1078,6 +1063,27 @@ const Token *SymbolDatabase::initBaseInfo(Scope *scope, const Token *tok) return tok2; } +void SymbolDatabase::debugMessage(const Token *tok, const std::string &msg) const +{ + if (tok && _settings->debugwarnings) + { + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok->linenr(); + loc.setfile(_tokenizer->file(tok)); + locationList.push_back(loc); + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::debug, + msg, + "debug"); + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); + } +} + //--------------------------------------------------------------------------- unsigned int Function::argCount() const @@ -1124,6 +1130,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s const Token *endTok; const Token *nameTok; bool isConstVar; + bool isArrayVar; const Token *tok = arg->next(); for (;;) { @@ -1131,6 +1138,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s endTok = NULL; nameTok = NULL; isConstVar = bool(tok->str() == "const"); + isArrayVar = false; while (tok->str() != "," && tok->str() != ")") { @@ -1139,12 +1147,28 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s nameTok = tok; endTok = tok->previous(); } + else if (tok->str() == "[") + isArrayVar = true; + tok = tok->next(); } - // check for argument with no name + // check for argument with no name or missing varid if (!endTok) - endTok = tok->previous(); + { + if (tok->previous()->isName()) + { + if (tok->previous() != startTok->tokAt(isConstVar ? 1 : 0)) + { + nameTok = tok->previous(); + endTok = nameTok->previous(); + + symbolDatabase->debugMessage(nameTok, "Function::addArguments found argument \'" + nameTok->str() + "\' with varid 0."); + } + } + else + endTok = tok->previous(); + } const Token *typeTok = startTok; if (isConstVar) @@ -1156,7 +1180,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s bool isClassVar = startTok == endTok && !startTok->isStandardType(); - argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, false, false, isConstVar, isClassVar, argType, scope, false)); + argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, false, false, isConstVar, isClassVar, argType, scope, isArrayVar)); if (tok->str() == ")") break; @@ -1429,23 +1453,8 @@ void Scope::getVariableList() // 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->_settings->debugwarnings) - { - std::list locationList; - ErrorLogger::ErrorMessage::FileLocation loc; - loc.line = vartok->linenr(); - loc.setfile(check->_tokenizer->file(vartok)); - locationList.push_back(loc); - - const ErrorLogger::ErrorMessage errmsg(locationList, - Severity::debug, - "Scope::getVariableList found variable \'" + vartok->str() + "\' with varid 0.", - "debug"); - if (check->_errorLogger) - check->_errorLogger->reportErr(errmsg); - else - Check::reportError(errmsg); - } + if (vartok->varId() == 0 && !vartok->isBoolean()) + check->debugMessage(vartok, "Scope::getVariableList found variable \'" + vartok->str() + "\' with varid 0."); const Scope *scope = NULL; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 3e11805b3..e1cb05206 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -500,6 +500,11 @@ public: return _variableList[varId]; } + /** + * @brief output a debug message + */ + void debugMessage(const Token *tok, const std::string &msg) const; + private: // Needed by Borland C++: diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 5131b86e1..91c8406cc 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -216,7 +216,7 @@ private: " EventPtr event = *eventP;\n" " *actionsP = &event->actions;\n" "}\n"); - ASSERT_EQUALS(std::string(""), errout.str()); + TODO_ASSERT_EQUALS("", "[test.cpp:1]: (debug) Function::addArguments found argument 'eventP' with varid 0.\n", errout.str()); } void returnLocalVariable1() From 4b0edccec4060ea1c50dfa25ec9dae46d5c09682 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Wed, 2 Mar 2011 21:21:46 -0500 Subject: [PATCH 12/15] convert some of the checks in CheckAutoVariables to use the variable symbol table --- lib/checkautovariables.cpp | 73 +++++++------------------------------- 1 file changed, 13 insertions(+), 60 deletions(-) diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index 10b53cd2b..9c8657cc9 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -266,7 +266,6 @@ void CheckAutoVariables::returnPointerToLocalArray() tok2 = tok2->next()->link(); unsigned int indentlevel = 0; - std::set arrayVar; for (; tok2; tok2 = tok2->next()) { // indentlevel.. @@ -279,21 +278,13 @@ void CheckAutoVariables::returnPointerToLocalArray() --indentlevel; } - // Declaring a local array.. - if (Token::Match(tok2, "[;{}] %type% %var% [")) - { - const unsigned int varid = tok2->tokAt(2)->varId(); - if (varid > 0) - { - arrayVar.insert(varid); - } - } - // Return pointer to local array variable.. if (Token::Match(tok2, "return %var% ;")) { const unsigned int varid = tok2->next()->varId(); - if (varid > 0 && arrayVar.find(varid) != arrayVar.end()) + const Variable *var = symbolDatabase->getVariableFromVarId(varid); + + if (var && var->isLocal() && !var->isStatic() && var->isArray()) { errorReturnPointerToLocalArray(tok2); } @@ -361,7 +352,6 @@ void CheckAutoVariables::returnReference() tok2 = tok2->link(); unsigned int indentlevel = 0; - std::set localvar; // local variables in function for (; tok2; tok2 = tok2->next()) { // indentlevel.. @@ -374,33 +364,14 @@ void CheckAutoVariables::returnReference() --indentlevel; } - // declare local variable.. - if (Token::Match(tok2, "[{};] %type%") && tok2->next()->str() != "return") - { - // goto next token.. - tok2 = tok2->next(); - - // skip "const" - if (Token::Match(tok2, "const %type%")) - tok2 = tok2->next(); - - // skip "std::" if it is seen - if (Token::simpleMatch(tok2, "std ::")) - tok2 = tok2->tokAt(2); - - // is it a variable declaration? - if (Token::Match(tok2, "%type% %var% ;")) - localvar.insert(tok2->next()->varId()); - else if (Token::Match(tok2, "%type% < %any% > %var% ;")) - localvar.insert(tok2->tokAt(4)->varId()); - } - // return.. - else if (Token::Match(tok2, "return %var% ;")) + if (Token::Match(tok2, "return %var% ;")) { // is the returned variable a local variable? - if ((tok2->next()->varId() > 0) && - (localvar.find(tok2->next()->varId()) != localvar.end())) + const unsigned int varid = tok2->next()->varId(); + const Variable *var = symbolDatabase->getVariableFromVarId(varid); + + if (var && var->isLocal() && !var->isStatic()) { // report error.. errorReturnReference(tok2); @@ -462,7 +433,6 @@ void CheckAutoVariables::returncstr() tok2 = tok2->next()->link(); unsigned int indentlevel = 0; - std::set localvar; // local variables in function for (; tok2; tok2 = tok2->next()) { // indentlevel.. @@ -475,31 +445,14 @@ void CheckAutoVariables::returncstr() --indentlevel; } - // declare local variable.. - if (Token::Match(tok2, "[{};] %type%") && tok2->next()->str() != "return") - { - // goto next token.. - tok2 = tok2->next(); - - // skip "const" - if (Token::Match(tok2, "const %type%")) - tok2 = tok2->next(); - - // skip "std::" if it is seen - if (Token::simpleMatch(tok2, "std ::")) - tok2 = tok2->tokAt(2); - - // is it a variable declaration? - if (Token::Match(tok2, "%type% %var% [;=]")) - localvar.insert(tok2->next()->varId()); - } - // return.. - else if (Token::Match(tok2, "return %var% . c_str ( ) ;")) + if (Token::Match(tok2, "return %var% . c_str ( ) ;")) { // is the returned variable a local variable? - if ((tok2->next()->varId() > 0) && - (localvar.find(tok2->next()->varId()) != localvar.end())) + const unsigned int varid = tok2->next()->varId(); + const Variable *var = symbolDatabase->getVariableFromVarId(varid); + + if (var && var->isLocal() && !var->isStatic()) { // report error.. errorReturnAutocstr(tok2); From ee4b4f62d83e3cd51053e6c5895119c81278f9ee Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Thu, 3 Mar 2011 07:27:53 -0500 Subject: [PATCH 13/15] fix #2620 reference of typedef of array not simplified properly --- lib/tokenize.cpp | 5 +++++ test/testsimplifytokens.cpp | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index aa4c00af8..1fcb7184b 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1790,6 +1790,11 @@ void Tokenizer::simplifyTypedef() { if (!inCast && !inSizeof) tok2 = tok2->next(); + + // skip over reference + if (tok2->str() == "&") + tok2 = tok2->next(); + tok2 = copyTokens(tok2, arrayStart, arrayEnd); tok2 = tok2->next(); diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index a546b3654..c2b76a51b 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,17 @@ 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 3f0d0446e033eff09d47092c83e4f8b33e286fd0 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Thu, 3 Mar 2011 07:40:43 -0500 Subject: [PATCH 14/15] revert previous commit: simplified code isn't correct --- lib/tokenize.cpp | 4 ---- test/testsimplifytokens.cpp | 12 ------------ 2 files changed, 16 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 1fcb7184b..7bd917d21 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1791,10 +1791,6 @@ void Tokenizer::simplifyTypedef() if (!inCast && !inSizeof) tok2 = tok2->next(); - // skip over reference - if (tok2->str() == "&") - tok2 = tok2->next(); - tok2 = copyTokens(tok2, arrayStart, arrayEnd); tok2 = tok2->next(); diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index c2b76a51b..a546b3654 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -243,7 +243,6 @@ 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 @@ -4962,17 +4961,6 @@ 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 d7a6e729b84a72b3886dedb8fa7b50db3c68de3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 3 Mar 2011 20:07:56 +0100 Subject: [PATCH 15/15] Tokenizer::simplifyKnownVariables: Don't simplify 'strcpy(a,"ab"); b=a;'. Ticket: #2031 --- lib/tokenize.cpp | 7 +++++-- test/testtokenize.cpp | 12 ++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 7bd917d21..cd1baa565 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6741,6 +6741,8 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign 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(); @@ -6857,13 +6859,14 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign // return variable.. if (Token::Match(tok3, "return %varid% %any%", varid) && - isOp(tok3->tokAt(2))) + isOp(tok3->tokAt(2)) && + value[0] != '\"') { tok3->next()->str(value); tok3->next()->varId(valueVarId); } - else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid)) + else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid) && value[0] != '\"') { tok3->deleteNext(); tok3->next()->str(value); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 72763bc01..04697796f 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -2080,6 +2080,18 @@ private: "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code, true)); } + + { + const char code[] = "void f(char *p, char *q) {" + " strcpy(p, \"abc\");" + " q = p;" + "}"; + const char expected[] = "void f ( char * p , char * q ) {" + " strcpy ( p , \"abc\" ) ;" + " q = p ; " + "}"; + ASSERT_EQUALS(expected, tokenizeAndStringify(code, true)); + } } void simplifyKnownVariablesBailOutAssign()