From 467c984cd1e364bd39d4f81ba2ae9ce506a4b9ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 13 Feb 2011 22:03:46 +0100 Subject: [PATCH 01/17] Tokenizer::simplifyKnownVariables: Fixed TODO testcase (better handling of %) --- lib/tokenize.cpp | 10 +++++----- test/testtokenize.cpp | 23 ++++++++--------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 346405b8f..754091c7b 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6357,7 +6357,7 @@ bool Tokenizer::simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2, bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, bool pointeralias, int indentlevel) { - bool ret = false;; + bool ret = false; Token* bailOutFromLoop = 0; int indentlevel3 = indentlevel; @@ -6618,10 +6618,10 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign // 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)) + 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 (!structname.empty()) { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index e07d202b0..a768df9a0 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -1685,21 +1685,14 @@ private: " int i = v;\n" " return h % i;\n" "}\n"; - const char wanted[] = "\n\n##file 0\n" - "1: int foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4:\n" - "5: return u@1 % v@2 ;\n" - "6: }\n"; - const char current[] = "\n\n##file 0\n" - "1: int foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4: int i@4 ; i@4 = v@2 ;\n" - "5: return u@1 % i@4 ;\n" - "6: }\n"; - TODO_ASSERT_EQUALS(wanted, current, tokenizeDebugListing(code, true)); + const char expected[] = "\n\n##file 0\n" + "1: int foo ( int u@1 , int v@2 )\n" + "2: {\n" + "3: ;\n" + "4:\n" + "5: return u@1 % v@2 ;\n" + "6: }\n"; + ASSERT_EQUALS(expected, tokenizeDebugListing(code, true)); } { From 472d8154ca0583de825598c4e64822c40005fea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 13 Feb 2011 22:09:04 +0100 Subject: [PATCH 02/17] Tokenizer::simplifyKnownVariables: Fixed TODO testcase (better handling of |) --- lib/tokenize.cpp | 8 ++++---- test/testtokenize.cpp | 23 ++++++++--------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 754091c7b..da057d0ac 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6618,10 +6618,10 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign // 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)) + 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 (!structname.empty()) { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index a768df9a0..e2f9a7d3b 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -1637,21 +1637,14 @@ private: " int i = v;\n" " return h | i;\n" "}\n"; - const char wanted[] = "\n\n##file 0\n" - "1: int foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4:\n" - "5: return u@1 | v@2 ;\n" - "6: }\n"; - const char current[] = "\n\n##file 0\n" - "1: int foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4: int i@4 ; i@4 = v@2 ;\n" - "5: return u@1 | i@4 ;\n" - "6: }\n"; - TODO_ASSERT_EQUALS(wanted, current, tokenizeDebugListing(code, true)); + const char expected[] = "\n\n##file 0\n" + "1: int foo ( int u@1 , int v@2 )\n" + "2: {\n" + "3: ;\n" + "4:\n" + "5: return u@1 | v@2 ;\n" + "6: }\n"; + ASSERT_EQUALS(expected, tokenizeDebugListing(code, true)); } { From 2182ede486af4cd74ca8f6edbd98ae007cb47b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 13 Feb 2011 22:13:19 +0100 Subject: [PATCH 03/17] Tokenizer::simplifyKnownVariables: Fixed TODO testcase (better handling of ^) --- lib/tokenize.cpp | 8 ++++---- test/testtokenize.cpp | 23 ++++++++--------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index da057d0ac..aa800124d 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6618,10 +6618,10 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign // 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)) + 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 (!structname.empty()) { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index e2f9a7d3b..11ccaa34d 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -1654,21 +1654,14 @@ private: " int i = v;\n" " return h ^ i;\n" "}\n"; - const char wanted[] = "\n\n##file 0\n" - "1: int foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4:\n" - "5: return u@1 ^ v@2 ;\n" - "6: }\n"; - const char current[] = "\n\n##file 0\n" - "1: int foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4: int i@4 ; i@4 = v@2 ;\n" - "5: return u@1 ^ i@4 ;\n" - "6: }\n"; - TODO_ASSERT_EQUALS(wanted, current, tokenizeDebugListing(code, true)); + const char expected[] = "\n\n##file 0\n" + "1: int foo ( int u@1 , int v@2 )\n" + "2: {\n" + "3: ;\n" + "4:\n" + "5: return u@1 ^ v@2 ;\n" + "6: }\n"; + ASSERT_EQUALS(expected, tokenizeDebugListing(code, true)); } { From 0d2d0c864af7385829ceedb31cbb67e15510ae58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 13 Feb 2011 22:24:45 +0100 Subject: [PATCH 04/17] Tokenizer::simplifyKnownVariables: Fixed TODO testcases (better handling of comparisons) --- lib/tokenize.cpp | 2 +- test/testtokenize.cpp | 107 +++++++++++++++++------------------------- 2 files changed, 45 insertions(+), 64 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index aa800124d..2797909b8 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6527,7 +6527,7 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign // 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, ("!|==|!=|<|<=|>|>= " + structname + " %varid% ==|!=|<|<=|>|>=|)|;").c_str(), varid) || Token::Match(tok3->previous(), "strlen|free ( %varid% )", varid)) { if (!structname.empty()) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 11ccaa34d..76b3b7a40 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -1722,22 +1722,14 @@ private: " int i = v;\n" " return h == i;\n" "}\n"; - const char wanted[] = "\n\n##file 0\n" - "1: bool foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4: ;\n" - "5: return u@1 == v@2 ;\n" - "6: }\n"; - const char current[] = "\n\n##file 0\n" - "1: bool foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4: int i@4 ; i@4 = v@2 ;\n" - "5: return u@1 == i@4 ;\n" - "6: }\n"; - - TODO_ASSERT_EQUALS(wanted, current, tokenizeDebugListing(code, true)); + const char expected[] = "\n\n##file 0\n" + "1: bool foo ( int u@1 , int v@2 )\n" + "2: {\n" + "3: ;\n" + "4:\n" + "5: return u@1 == v@2 ;\n" + "6: }\n"; + ASSERT_EQUALS(expected, tokenizeDebugListing(code, true)); } { @@ -1747,21 +1739,14 @@ private: " int i = v;\n" " return h != i;\n" "}\n"; - const char wanted[] = "\n\n##file 0\n" - "1: bool foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4: ;\n" - "5: return u@1 != v@2 ;\n" - "6: }\n"; - const char current[] = "\n\n##file 0\n" + const char expected[] = "\n\n##file 0\n" "1: bool foo ( int u@1 , int v@2 )\n" "2: {\n" "3: ;\n" - "4: int i@4 ; i@4 = v@2 ;\n" - "5: return u@1 != i@4 ;\n" + "4:\n" + "5: return u@1 != v@2 ;\n" "6: }\n"; - TODO_ASSERT_EQUALS(wanted, current, tokenizeDebugListing(code, true)); + ASSERT_EQUALS(expected, tokenizeDebugListing(code, true)); } { @@ -1771,15 +1756,14 @@ private: " int i = v;\n" " return h > i;\n" "}\n"; - const char wanted[] = "\n\n##file 0\n" - "1: bool foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4: ;\n" - "5: return u@1 > v@2 ;\n" - "6: }\n"; - const char current[] = "\n\n##file 0\n1: bool foo ( int u@1 , int v@2 )\n2: {\n3: ;\n4: int i@4 ; i@4 = v@2 ;\n5: return u@1 > i@4 ;\n6: }\n"; - TODO_ASSERT_EQUALS(wanted, current, tokenizeDebugListing(code, true)); + const char expected[] = "\n\n##file 0\n" + "1: bool foo ( int u@1 , int v@2 )\n" + "2: {\n" + "3: ;\n" + "4:\n" + "5: return u@1 > v@2 ;\n" + "6: }\n"; + ASSERT_EQUALS(expected, tokenizeDebugListing(code, true)); } { @@ -1789,15 +1773,14 @@ private: " int i = v;\n" " return h >= i;\n" "}\n"; - const char wanted[] = "\n\n##file 0\n" - "1: bool foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4: ;\n" - "5: return u@1 >= v@2 ;\n" - "6: }\n"; - const char current[] = "\n\n##file 0\n1: bool foo ( int u@1 , int v@2 )\n2: {\n3: ;\n4: int i@4 ; i@4 = v@2 ;\n5: return u@1 >= i@4 ;\n6: }\n"; - TODO_ASSERT_EQUALS(wanted, current, tokenizeDebugListing(code, true)); + const char expected[] = "\n\n##file 0\n" + "1: bool foo ( int u@1 , int v@2 )\n" + "2: {\n" + "3: ;\n" + "4:\n" + "5: return u@1 >= v@2 ;\n" + "6: }\n"; + ASSERT_EQUALS(expected, tokenizeDebugListing(code, true)); } { @@ -1807,15 +1790,14 @@ private: " int i = v;\n" " return h < i;\n" "}\n"; - const char wanted[] = "\n\n##file 0\n" - "1: bool foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4: ;\n" - "5: return u@1 < v@2 ;\n" - "6: }\n"; - const char current[] = "\n\n##file 0\n1: bool foo ( int u@1 , int v@2 )\n2: {\n3: ;\n4: int i@4 ; i@4 = v@2 ;\n5: return u@1 < i@4 ;\n6: }\n"; - TODO_ASSERT_EQUALS(wanted, current, tokenizeDebugListing(code, true)); + const char expected[] = "\n\n##file 0\n" + "1: bool foo ( int u@1 , int v@2 )\n" + "2: {\n" + "3: ;\n" + "4:\n" + "5: return u@1 < v@2 ;\n" + "6: }\n"; + ASSERT_EQUALS(expected, tokenizeDebugListing(code, true)); } { @@ -1825,15 +1807,14 @@ private: " int i = v;\n" " return h <= i;\n" "}\n"; - const char wanted[] = "\n\n##file 0\n" - "1: bool foo ( int u@1 , int v@2 )\n" - "2: {\n" - "3: ;\n" - "4: ;\n" - "5: return u@1 <= v@2 ;\n" - "6: }\n"; - const char current[] = "\n\n##file 0\n1: bool foo ( int u@1 , int v@2 )\n2: {\n3: ;\n4: int i@4 ; i@4 = v@2 ;\n5: return u@1 <= i@4 ;\n6: }\n"; - TODO_ASSERT_EQUALS(wanted, current, tokenizeDebugListing(code, true)); + const char expected[] = "\n\n##file 0\n" + "1: bool foo ( int u@1 , int v@2 )\n" + "2: {\n" + "3: ;\n" + "4:\n" + "5: return u@1 <= v@2 ;\n" + "6: }\n"; + ASSERT_EQUALS(expected, tokenizeDebugListing(code, true)); } { From aacb94c427586ae1ee416bff1197ac038d5052e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 13 Feb 2011 22:48:26 +0100 Subject: [PATCH 05/17] Revert "Buffer overruns: Removed TODO test case. We intentionally don't check struct/class arrays fully to avoid false positives" This reverts commit 87cc42e6f0b0c8db37a314e5ef5be2c48cc3f4bd. --- test/testbufferoverrun.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 768507400..40e7de150 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -1875,6 +1875,20 @@ private: " }\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + check("class A {\n" + " void foo();\n" + " bool b[7];\n" + "};\n" + "\n" + "void A::foo() {\n" + " for (int i=0; i<7; i++) {\n" + " b[i] = b[i+1];\n" + " }\n" + "}\n"); + TODO_ASSERT_EQUALS("error", // wanted result + "", // current result + errout.str()); } void buffer_overrun_bailoutIfSwitch() From d2a1d3f14a3e6acaf6ca3d9e9bb3644ca6e22504 Mon Sep 17 00:00:00 2001 From: Ettl Martin Date: Sun, 13 Feb 2011 23:57:07 +0100 Subject: [PATCH 06/17] fixed pre/post increment warings, found during selfcheck --- lib/preprocessor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 091da7ea0..fe35a7f81 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -218,7 +218,7 @@ std::string Preprocessor::preprocessCleanupDirectives(const std::string &process char prev = ' '; // hack to make it skip spaces between # and the directive code << "#"; std::string::const_iterator i = line.begin(); - i++; + ++i; // need space.. #if( => #if ( bool needSpace = true; @@ -247,7 +247,7 @@ std::string Preprocessor::preprocessCleanupDirectives(const std::string &process // skip double whitespace between arguments if (escapeStatus == ESC_NONE && prev == ' ' && *i == ' ') { - i++; + ++i; continue; } // Convert #if( to "#if (" @@ -272,7 +272,7 @@ std::string Preprocessor::preprocessCleanupDirectives(const std::string &process { prev = *i; } - i++; + ++i; } if (escapeStatus != ESC_NONE) { From cdd8d3f785eef2d9cdc4eaffcdfe38ac0012537f Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 13 Feb 2011 19:02:57 -0500 Subject: [PATCH 07/17] Really fix #2348 perl-tk --- lib/tokenize.cpp | 2 ++ test/testsimplifytokens.cpp | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 2797909b8..9398867d5 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -869,6 +869,8 @@ static Token *processFunc(Token *tok2, bool inOperator) tok2 = tok2->tokAt(5)->link(); else if (Token::Match(tok2->next(), "* ( * %type% ) (")) tok2 = tok2->tokAt(6)->link(); + else if (Token::Match(tok2->next(), "* ( * %type% ) ;")) + tok2 = tok2->tokAt(5); else if (Token::Match(tok2->next(), "* ( %type% [") && Token::Match(tok2->tokAt(4)->link(), "] ) ;|=")) tok2 = tok2->tokAt(4)->link()->next(); diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index b79b99f58..ac191e618 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -236,6 +236,7 @@ private: TEST_CASE(simplifyTypedef76); // ticket #2453 TEST_CASE(simplifyTypedef77); // ticket #2554 TEST_CASE(simplifyTypedef78); // ticket #2568 + TEST_CASE(simplifyTypedef79); // ticket #2348 TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -4858,6 +4859,21 @@ private: 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 simplifyTypedefFunction1() { { From 805773663e3f88d1e56d7eb61df7784da43b344d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 14 Feb 2011 19:37:58 +0100 Subject: [PATCH 08/17] Build: Renamed HAVE_DEPENDENCIES to HAVE_RULES --- Makefile | 2 +- cli/cmdlineparser.cpp | 4 ++-- lib/cppcheck.cpp | 4 ++-- tools/dmake.cpp | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 6dfbe39d4..d5fe8b8a2 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # This file is generated by tools/dmake, do not edit. ifndef CXXFLAGS - CXXFLAGS=-DHAVE_DEPENDENCIES -Wall -Wextra -Wshadow -pedantic -Wno-long-long -Wfloat-equal -Wcast-qual -Wsign-conversion -g + CXXFLAGS=-DHAVE_RULES -Wall -Wextra -Wshadow -pedantic -Wno-long-long -Wfloat-equal -Wcast-qual -Wsign-conversion -g endif ifndef CXX diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index d8f61bab5..428d6a2ae 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -28,7 +28,7 @@ #include "path.h" #include "filelister.h" -#ifdef HAVE_DEPENDENCIES +#ifdef HAVE_RULES // xml is used in rules #include #endif @@ -505,7 +505,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) _settings->_showtime = SHOWTIME_NONE; } -#ifdef HAVE_DEPENDENCIES +#ifdef HAVE_RULES // Rule given at command line else if (strncmp(argv[i], "--rule=", 7) == 0) { diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 9f3d81320..494feac58 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -30,7 +30,7 @@ #include #include "timer.h" -#ifdef HAVE_DEPENDENCIES +#ifdef HAVE_RULES #define PCRE_STATIC #include #endif @@ -309,7 +309,7 @@ void CppCheck::checkFile(const std::string &code, const char FileName[]) (*it)->runSimplifiedChecks(&_tokenizer, &_settings, this); } -#ifdef HAVE_DEPENDENCIES +#ifdef HAVE_RULES // Are there extra rules? if (!_settings.rules.empty()) { diff --git a/tools/dmake.cpp b/tools/dmake.cpp index 88aa47159..b8b739ff1 100644 --- a/tools/dmake.cpp +++ b/tools/dmake.cpp @@ -225,7 +225,7 @@ int main(int argc, char **argv) // Makefile settings.. if (release) { - makeConditionalVariable(fout, "CXXFLAGS", "-O2 -DNDEBUG -DHAVE_DEPENDENCIES -Wall"); + makeConditionalVariable(fout, "CXXFLAGS", "-O2 -DNDEBUG -DHAVE_RULES -Wall"); } else { @@ -235,7 +235,7 @@ int main(int argc, char **argv) // The _GLIBCXX_DEBUG doesn't work in cygwin makeConditionalVariable(fout, "CXXFLAGS", - "-DHAVE_DEPENDENCIES " + "-DHAVE_RULES " "-Wall " "-Wextra " "-Wshadow " From 3bb2850c5c34f48dea5a72fcdfdeeabd6ca09433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 14 Feb 2011 19:50:16 +0100 Subject: [PATCH 09/17] Renaming HAVE_DEPENDENCIES to HAVE_RULES --- cli/cli.pro | 2 +- readme.txt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/cli.pro b/cli/cli.pro index 2195098de..efc3e4da3 100644 --- a/cli/cli.pro +++ b/cli/cli.pro @@ -5,7 +5,7 @@ INCLUDEPATH += . ../lib OBJECTS_DIR = temp CONFIG += warn_on CONFIG -= qt app_bundle -DEFINES += HAVE_DEPENDENCIES +DEFINES += HAVE_RULES BASEPATH = ../externals/tinyxml/ include($$PWD/../externals/tinyxml/tinyxml.pri) diff --git a/readme.txt b/readme.txt index 8788f47aa..0b0a0ab15 100644 --- a/readme.txt +++ b/readme.txt @@ -18,8 +18,8 @@ Compiling To build the GUI, you need Qt. - To build the command line tool, PCRE is needed. More information about PCRE is found in - build.txt + To build the command line tool, no dependencies are required. However for + the handling of rules, PCRE is needed. There are multiple compilation choices: * qmake - cross platform build tool @@ -48,7 +48,7 @@ Compiling g++ -o cppcheck -Ilib cli/*.cpp lib/*.cpp If you want to use --rule and --rule-file then dependencies are needed: - g++ -o cppcheck -lpcre -DHAVE_DEPENDENCIES -Ilib -Iexternals cli/*.cpp lib/*.cpp externals/tinyxml/*.cpp + g++ -o cppcheck -lpcre -DHAVE_RULES -Ilib -Iexternals cli/*.cpp lib/*.cpp externals/tinyxml/*.cpp mingw ===== make LDFLAGS=-lshlwapi From 0ed0d077148718c037181570355919081f0160df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 14 Feb 2011 20:43:26 +0100 Subject: [PATCH 10/17] Tokenizer::simplifyCalculations: basic handling of bitwise operators --- lib/tokenize.cpp | 32 ++++++++++++++++++++++++++++---- test/testsimplifytokens.cpp | 2 ++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9398867d5..be64337b5 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -7071,10 +7071,11 @@ bool Tokenizer::simplifyCalculations() { // (1-2) - while (Token::Match(tok, "[[,(=<>+-*] %num% [+-*/] %num% [],);=<>+-*/]") || - Token::Match(tok, "<< %num% [+-*/] %num% [],);=<>+-*/]") || - Token::Match(tok, "[[,(=<>+-*] %num% [+-*/] %num% <<|>>") || - Token::Match(tok, "<< %num% [+-*/] %num% <<")) + 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(); @@ -7082,6 +7083,29 @@ bool Tokenizer::simplifyCalculations() 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(), "[+-/]")) { diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index ac191e618..a4c507cd4 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -2591,6 +2591,8 @@ private: ASSERT_EQUALS("a [ 0 ]", tok(code)); } + ASSERT_EQUALS("a [ 4 ] ;", tok("a[1+3|4];")); + ASSERT_EQUALS("x = 1 + 2 * y ;", tok("x=1+2*y;")); ASSERT_EQUALS("x = 7 ;", tok("x=1+2*3;")); ASSERT_EQUALS("x = 47185 ;", tok("x=(65536*72/100);")); From d4f204a25a70ed0dba47b909514f94197e80824f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 14 Feb 2011 21:11:06 +0100 Subject: [PATCH 11/17] renamed build.txt to build-pcre.txt --- build.txt => build-pcre.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename build.txt => build-pcre.txt (100%) diff --git a/build.txt b/build-pcre.txt similarity index 100% rename from build.txt rename to build-pcre.txt From 218464df8997604eb8445ebaa4424ab4aeecc51e Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Mon, 14 Feb 2011 19:50:13 -0500 Subject: [PATCH 12/17] fix #2580 (false postive with Unused private function) --- lib/symboldatabase.cpp | 9 ++++----- test/testunusedprivfunc.cpp | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index d29cc5a52..05a0aa0a5 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -906,12 +906,14 @@ const Token *SymbolDatabase::initBaseInfo(Scope *scope, const Token *tok) base.name += tok2->str(); base.scope = 0; - // don't add unhandled templates + // add unhandled templates if (tok2->next()->str() == "<") { int level1 = 1; while (tok2->next()) { + base.name += tok2->next()->str(); + if (tok2->next()->str() == ">") { level1--; @@ -926,10 +928,7 @@ const Token *SymbolDatabase::initBaseInfo(Scope *scope, const Token *tok) } // save pattern for base class name - else - { - scope->derivedFrom.push_back(base); - } + scope->derivedFrom.push_back(base); } tok2 = tok2->next(); } diff --git a/test/testunusedprivfunc.cpp b/test/testunusedprivfunc.cpp index c9358aae8..272df269f 100644 --- a/test/testunusedprivfunc.cpp +++ b/test/testunusedprivfunc.cpp @@ -67,6 +67,7 @@ private: TEST_CASE(testDoesNotIdentifyMethodAsLastFunctionArgument); TEST_CASE(multiFile); + TEST_CASE(unknownBaseTemplate); // ticket #2580 } @@ -571,6 +572,20 @@ private: ASSERT_EQUALS("", errout.str()); } + + void unknownBaseTemplate() // ticket #2580 + { + check("class Bla : public Base2 {\n" + "public:\n" + " Bla() {}\n" + "private:\n" + " virtual void F() const;\n" + "};\n" + "void Bla::F() const { }"); + + ASSERT_EQUALS("", errout.str()); + } + }; REGISTER_TEST(TestUnusedPrivateFunction) From 5998ec4af9b49525cb2d16452d79dfffe4acb15a Mon Sep 17 00:00:00 2001 From: Raphael Geissert Date: Tue, 15 Feb 2011 14:10:56 -0600 Subject: [PATCH 13/17] Really fix the build failure this time --- test/testbufferoverrun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 40e7de150..ba3cf9151 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -868,7 +868,7 @@ private: " a[256] = 0;\n" // 256 > CHAR_MAX "}\n"); ASSERT_EQUALS("[test.cpp:4]: (error) Array 'a[256]' index 256 out of bounds\n" - "[test.cpp:3]: (error) Array 'a[256]' index -1 out of bounds\n", errout.str()); + "[test.cpp:3]: (error) Array index -1 out of bounds\n", errout.str()); } check("void f(signed char n) {\n" From 8a85b18283beef59d2a79ba88d0d965f947f75fb Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Tue, 15 Feb 2011 23:05:27 +0000 Subject: [PATCH 14/17] use suppression wildcard glob instead of special-case empty filename --- lib/settings.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/settings.cpp b/lib/settings.cpp index dbd4f37c7..4b6f26c84 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -207,6 +207,10 @@ std::string Settings::Suppressions::FileMatcher::addFile(const std::string &name } _globs[name].insert(line); } + else if (name.empty()) + { + _globs["*"].insert(0U); + } else { _files[name].insert(line); @@ -216,10 +220,6 @@ std::string Settings::Suppressions::FileMatcher::addFile(const std::string &name bool Settings::Suppressions::FileMatcher::isSuppressed(const std::string &file, unsigned int line) { - // Check are all errors of this type filtered out - if (_files.find("") != _files.end()) - return true; - std::set lineset; std::map >::const_iterator f = _files.find(file); From 331788246b7d9d25811fa0f155646e0fbbf65b60 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Wed, 16 Feb 2011 22:26:16 +1300 Subject: [PATCH 15/17] factor out addSuppressionLine from file reading function --- lib/settings.cpp | 89 ++++++++++++++++++++++++++---------------------- lib/settings.h | 7 ++++ 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/lib/settings.cpp b/lib/settings.cpp index 4b6f26c84..b99a06c32 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -70,46 +70,7 @@ std::string Settings::Suppressions::parseFile(std::istream &istr) if (line.length() >= 2 && line[0] == '/' && line[1] == '/') continue; - std::istringstream lineStream(line); - std::string id; - std::string file; - unsigned int lineNumber = 0; - if (std::getline(lineStream, id, ':')) - { - if (std::getline(lineStream, file)) - { - // If there is not a dot after the last colon in "file" then - // the colon is a separator and the contents after the colon - // is a line number.. - - // Get position of last colon - const std::string::size_type pos = file.rfind(":"); - - // if a colon is found and there is no dot after it.. - if (pos != std::string::npos && - file.find(".", pos) == std::string::npos) - { - // Try to parse out the line number - try - { - std::istringstream istr1(file.substr(pos+1)); - istr1 >> lineNumber; - } - catch (...) - { - lineNumber = 0; - } - - if (lineNumber > 0) - { - file.erase(pos); - } - } - } - } - - // We could perhaps check if the id is valid and return error if it is not - const std::string errmsg(addSuppression(id, file, lineNumber)); + const std::string errmsg(addSuppressionLine(line)); if (!errmsg.empty()) return errmsg; } @@ -117,6 +78,54 @@ std::string Settings::Suppressions::parseFile(std::istream &istr) return ""; } +std::string Settings::Suppressions::addSuppressionLine(const std::string &line) +{ + std::istringstream lineStream(line); + std::string id; + std::string file; + unsigned int lineNumber = 0; + if (std::getline(lineStream, id, ':')) + { + if (std::getline(lineStream, file)) + { + // If there is not a dot after the last colon in "file" then + // the colon is a separator and the contents after the colon + // is a line number.. + + // Get position of last colon + const std::string::size_type pos = file.rfind(":"); + + // if a colon is found and there is no dot after it.. + if (pos != std::string::npos && + file.find(".", pos) == std::string::npos) + { + // Try to parse out the line number + try + { + std::istringstream istr1(file.substr(pos+1)); + istr1 >> lineNumber; + } + catch (...) + { + lineNumber = 0; + } + + if (lineNumber > 0) + { + file.erase(pos); + } + } + } + } + + // We could perhaps check if the id is valid and return error if it is not + const std::string errmsg(addSuppression(id, file, lineNumber)); + if (!errmsg.empty()) + return errmsg; + + return ""; +} + bool Settings::Suppressions::FileMatcher::match(const std::string &pattern, const std::string &name) { const char *p = pattern.c_str(); diff --git a/lib/settings.h b/lib/settings.h index d2d9a217d..f480b3bec 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -180,6 +180,13 @@ public: */ std::string parseFile(std::istream &istr); + /** + * @brief Don't show the given error. + * @param str Description of error to suppress (in id:file:line format). + * @return error message. empty upon success + */ + std::string addSuppressionLine(const std::string &line); + /** * @brief Don't show this error. If file and/or line are optional. In which case * the errorId alone is used for filtering. From 5d7432501599a901d8ac3a621a06fd883acb7291 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Wed, 16 Feb 2011 01:12:15 +0000 Subject: [PATCH 16/17] implement unmatchedSuppression information message --- Makefile | 4 + cli/cppcheckexecutor.cpp | 6 +- cli/threadexecutor.cpp | 25 ++++-- cli/threadexecutor.h | 4 +- lib/cppcheck.cpp | 20 +++-- lib/cppcheck.h | 9 +- lib/errorlogger.cpp | 17 +++- lib/errorlogger.h | 13 +++ lib/settings.cpp | 103 ++++++++++++++++++----- lib/settings.h | 49 ++++++++++- test/testcppcheck.cpp | 2 +- test/testsuppressions.cpp | 172 ++++++++++++++++++++++++++++++++++++++ 12 files changed, 378 insertions(+), 46 deletions(-) create mode 100644 test/testsuppressions.cpp diff --git a/Makefile b/Makefile index d5fe8b8a2..a1e087771 100644 --- a/Makefile +++ b/Makefile @@ -95,6 +95,7 @@ TESTOBJ = test/options.o \ test/testsimplifytokens.o \ test/teststl.o \ test/testsuite.o \ + test/testsuppressions.o \ test/testsymboldatabase.o \ test/testthreadexecutor.o \ test/testtoken.o \ @@ -329,6 +330,9 @@ 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 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 test/testsuite.h lib/cppcheck.h lib/settings.h lib/errorlogger.h cli/threadexecutor.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 test/redirect.h test/testutils.h lib/settings.h lib/tokenize.h lib/token.h lib/symboldatabase.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testsymboldatabase.o test/testsymboldatabase.cpp diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index c101b6592..491f48caa 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -123,7 +123,7 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c int CppCheckExecutor::check(int argc, const char* const argv[]) { - CppCheck cppCheck(*this); + CppCheck cppCheck(*this, true); if (!parseFromArgs(&cppCheck, argc, argv)) { return EXIT_FAILURE; @@ -152,11 +152,13 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) { // Multiple processes const std::vector &filenames = cppCheck.filenames(); - Settings settings = cppCheck.settings(); + Settings &settings = cppCheck.settings(); ThreadExecutor executor(filenames, settings, *this); returnValue = executor.check(); } + reportUnmatchedSuppressions(cppCheck.settings().nomsg.getUnmatchedGlobalSuppressions()); + if (_settings._xml) { reportErr(ErrorLogger::ErrorMessage::getXMLFooter(_settings._xml_version)); diff --git a/cli/threadexecutor.cpp b/cli/threadexecutor.cpp index c4119876d..7c33d2adb 100644 --- a/cli/threadexecutor.cpp +++ b/cli/threadexecutor.cpp @@ -31,7 +31,7 @@ #include #endif -ThreadExecutor::ThreadExecutor(const std::vector &filenames, const Settings &settings, ErrorLogger &errorLogger) +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__) @@ -95,12 +95,23 @@ int ThreadExecutor::handleRead(unsigned int &result) ErrorLogger::ErrorMessage msg; msg.deserialize(buf); - // Alert only about unique errors - std::string errmsg = msg.toString(_settings._verbose); - if (std::find(_errorList.begin(), _errorList.end(), errmsg) == _errorList.end()) + std::string file; + unsigned int line(0); + if (!msg._callStack.empty()) { - _errorList.push_back(errmsg); - _errorLogger.reportErr(msg); + file = msg._callStack.back().getfile(false); + line = msg._callStack.back().line; + } + + if (!_settings.nomsg.isSuppressed(msg._id, file, line)) + { + // Alert only about unique errors + std::string errmsg = msg.toString(_settings._verbose); + if (std::find(_errorList.begin(), _errorList.end(), errmsg) == _errorList.end()) + { + _errorList.push_back(errmsg); + _errorLogger.reportErr(msg); + } } } else if (type == '3') @@ -158,7 +169,7 @@ unsigned int ThreadExecutor::check() } else if (pid == 0) { - CppCheck fileChecker(*this); + CppCheck fileChecker(*this, false); fileChecker.settings(_settings); if (_fileContents.size() > 0 && _fileContents.find(_filenames[i]) != _fileContents.end()) diff --git a/cli/threadexecutor.h b/cli/threadexecutor.h index 1fb0af877..309e110ee 100644 --- a/cli/threadexecutor.h +++ b/cli/threadexecutor.h @@ -35,7 +35,7 @@ class ThreadExecutor : public ErrorLogger { public: - ThreadExecutor(const std::vector &filenames, const Settings &settings, ErrorLogger &_errorLogger); + ThreadExecutor(const std::vector &filenames, Settings &settings, ErrorLogger &_errorLogger); virtual ~ThreadExecutor(); unsigned int check(); virtual void reportOut(const std::string &outmsg); @@ -52,7 +52,7 @@ public: private: const std::vector &_filenames; - const Settings &_settings; + Settings &_settings; ErrorLogger &_errorLogger; unsigned int _fileCount; diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 494feac58..4febd096b 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -37,8 +37,8 @@ static TimerResults S_timerResults; -CppCheck::CppCheck(ErrorLogger &errorLogger) - : _errorLogger(errorLogger) +CppCheck::CppCheck(ErrorLogger &errorLogger, bool useGlobalSuppressions) + : _useGlobalSuppressions(useGlobalSuppressions), _errorLogger(errorLogger) { exitcode = 0; } @@ -197,6 +197,8 @@ unsigned int CppCheck::check() _errorLogger.reportOut("Bailing out from checking " + fixedpath + ": " + e.what()); } + reportUnmatchedSuppressions(_settings.nomsg.getUnmatchedLocalSuppressions()); + _errorLogger.reportStatus(c + 1, (unsigned int)_filenames.size()); } @@ -385,7 +387,7 @@ void CppCheck::checkFile(const std::string &code, const char FileName[]) #endif } -Settings CppCheck::settings() const +Settings &CppCheck::settings() { return _settings; } @@ -408,8 +410,16 @@ void CppCheck::reportErr(const ErrorLogger::ErrorMessage &msg) line = msg._callStack.back().line; } - if (_settings.nomsg.isSuppressed(msg._id, file, line)) - return; + if (_useGlobalSuppressions) + { + if (_settings.nomsg.isSuppressed(msg._id, file, line)) + return; + } + else + { + if (_settings.nomsg.isSuppressedLocal(msg._id, file, line)) + return; + } if (!_settings.nofail.isSuppressed(msg._id, file, line)) exitcode = 1; diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 9f00c86b2..3e02a4e3e 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -43,7 +43,7 @@ public: /** * @brief Constructor. */ - CppCheck(ErrorLogger &errorLogger); + CppCheck(ErrorLogger &errorLogger, bool useGlobalSuppressions); /** * @brief Destructor. @@ -66,10 +66,10 @@ public: void settings(const Settings &settings); /** - * @brief Get copy of current settings. - * @return a copy of current settings + * @brief Get reference to current settings. + * @return a reference to current settings */ - Settings settings() const; + Settings &settings(); /** * @brief Add new file to be checked. @@ -147,6 +147,7 @@ private: std::list _errorList; std::ostringstream _errout; Settings _settings; + bool _useGlobalSuppressions; std::vector _filenames; void reportProgress(const std::string &filename, const char stage[], const unsigned int value); diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 387603d8f..c96c12854 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -291,11 +291,26 @@ std::string ErrorLogger::ErrorMessage::toString(bool verbose, const std::string } } +void ErrorLogger::reportUnmatchedSuppressions(const std::list &unmatched) +{ + for (std::list::const_iterator i = unmatched.begin(); i != unmatched.end(); ++i) + { + std::list callStack; + callStack.push_back(ErrorLogger::ErrorMessage::FileLocation(i->file, i->line)); + reportErr(ErrorLogger::ErrorMessage(callStack, Severity::information, "Unmatched suppression: " + i->id, "unmatchedSuppression")); + } +} + std::string ErrorLogger::callStackToString(const std::list &callStack) { std::ostringstream ostr; for (std::list::const_iterator tok = callStack.begin(); tok != callStack.end(); ++tok) - ostr << (tok == callStack.begin() ? "" : " -> ") << "[" << (*tok).getfile() << ":" << (*tok).line << "]"; + { + ostr << (tok == callStack.begin() ? "" : " -> ") << "[" << (*tok).getfile(); + if ((*tok).line != 0) + ostr << ":" << (*tok).line; + ostr << "]"; + } return ostr.str(); } diff --git a/lib/errorlogger.h b/lib/errorlogger.h index da5b7835f..410bbf4c4 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -23,6 +23,8 @@ #include #include +#include "settings.h" + class Token; class Tokenizer; @@ -108,6 +110,11 @@ public: line = 0; } + FileLocation(const std::string &file, int aline) + : line(aline), _file(file) + { + } + /** * Return the filename. * @param convert If true convert path to native separators. @@ -230,6 +237,12 @@ public: (void)value; } + /** + * Report list of unmatched suppressions + * @param unmatched list of unmatched suppressions (from Settings::Suppressions::getUnmatched(Local|Global)Suppressions) + */ + void reportUnmatchedSuppressions(const std::list &unmatched); + static std::string callStackToString(const std::list &callStack); }; diff --git a/lib/settings.cpp b/lib/settings.cpp index b99a06c32..b523c1903 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -214,47 +214,64 @@ std::string Settings::Suppressions::FileMatcher::addFile(const std::string &name } } } - _globs[name].insert(line); + _globs[name][line] = false; } else if (name.empty()) { - _globs["*"].insert(0U); + _globs["*"][0U] = false; } else { - _files[name].insert(line); + _files[name][line] = false; } return ""; } bool Settings::Suppressions::FileMatcher::isSuppressed(const std::string &file, unsigned int line) { - std::set lineset; + if (isSuppressedLocal(file, line)) + return true; - std::map >::const_iterator f = _files.find(file); - if (f != _files.end()) - { - lineset.insert(f->second.begin(), f->second.end()); - } - for (std::map >::iterator g = _globs.begin(); g != _globs.end(); ++g) + for (std::map >::iterator g = _globs.begin(); g != _globs.end(); ++g) { if (match(g->first, file)) { - lineset.insert(g->second.begin(), g->second.end()); + if (g->second.find(0U) != g->second.end()) + { + g->second[0U] = true; + return true; + } + std::map::iterator l = g->second.find(line); + if (l != g->second.end()) + { + l->second = true; + return true; + } } } - if (lineset.empty()) - return false; + return false; +} - // Check should all errors in this file be filtered out - if (lineset.find(0U) != lineset.end()) - return true; +bool Settings::Suppressions::FileMatcher::isSuppressedLocal(const std::string &file, unsigned int line) +{ + std::map >::iterator f = _files.find(file); + if (f != _files.end()) + { + if (f->second.find(0U) != f->second.end()) + { + f->second[0U] = true; + return true; + } + std::map::iterator l = f->second.find(line); + if (l != f->second.end()) + { + l->second = true; + return true; + } + } - if (lineset.find(line) == lineset.end()) - return false; - - return true; + return false; } std::string Settings::Suppressions::addSuppression(const std::string &errorId, const std::string &file, unsigned int line) @@ -287,6 +304,52 @@ bool Settings::Suppressions::isSuppressed(const std::string &errorId, const std: return _suppressions[errorId].isSuppressed(file, line); } +bool Settings::Suppressions::isSuppressedLocal(const std::string &errorId, const std::string &file, unsigned int line) +{ + if (_suppressions.find(errorId) == _suppressions.end()) + return false; + + return _suppressions[errorId].isSuppressedLocal(file, line); +} + +std::list Settings::Suppressions::getUnmatchedLocalSuppressions() const +{ + std::list r; + for (std::map::const_iterator i = _suppressions.begin(); i != _suppressions.end(); ++i) + { + for (std::map >::const_iterator f = i->second._files.begin(); f != i->second._files.end(); ++f) + { + for (std::map::const_iterator l = f->second.begin(); l != f->second.end(); ++l) + { + if (!l->second) + { + r.push_back(SuppressionEntry(i->first, f->first, l->first)); + } + } + } + } + return r; +} + +std::list Settings::Suppressions::getUnmatchedGlobalSuppressions() const +{ + std::list r; + for (std::map::const_iterator i = _suppressions.begin(); i != _suppressions.end(); ++i) + { + for (std::map >::const_iterator g = i->second._globs.begin(); g != i->second._globs.end(); ++g) + { + for (std::map::const_iterator l = g->second.begin(); l != g->second.end(); ++l) + { + if (!l->second) + { + r.push_back(SuppressionEntry(i->first, g->first, l->first)); + } + } + } + } + return r; +} + std::string Settings::addEnabled(const std::string &str) { // Enable parameters may be comma separated... diff --git a/lib/settings.h b/lib/settings.h index f480b3bec..b65d741c4 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -138,11 +138,12 @@ public: private: class FileMatcher { + friend class Suppressions; private: - /** @brief List of filenames suppressed. */ - std::map > _files; - /** @brief List of globs suppressed. */ - std::map > _globs; + /** @brief List of filenames suppressed, bool flag indicates whether suppression matched. */ + std::map > _files; + /** @brief List of globs suppressed, bool flag indicates whether suppression matched. */ + std::map > _globs; /** * @brief Match a name against a glob pattern. @@ -168,6 +169,14 @@ public: * @return true if this filename/line matches */ bool isSuppressed(const std::string &file, unsigned int line); + + /** + * @brief Returns true if the file name matches a previously added file (only, not glob pattern). + * @param name File name to check + * @param line Line number + * @return true if this filename/line matches + */ + bool isSuppressedLocal(const std::string &file, unsigned int line); }; /** @brief List of error which the user doesn't want to see. */ @@ -205,6 +214,38 @@ public: * @return true if this error is suppressed. */ bool isSuppressed(const std::string &errorId, const std::string &file, unsigned int line); + + /** + * @brief Returns true if this message should not be shown to the user (explicit files only, not glob patterns). + * @param errorId the id for the error, e.g. "arrayIndexOutOfBounds" + * @param file File name with the path, e.g. "src/main.cpp" + * @param line number, e.g. "123" + * @return true if this error is suppressed. + */ + bool isSuppressedLocal(const std::string &errorId, const std::string &file, unsigned int line); + + struct SuppressionEntry + { + SuppressionEntry(const std::string &aid, const std::string &afile, const unsigned int &aline) + : id(aid), file(afile), line(aline) + { } + + std::string id; + std::string file; + unsigned int line; + }; + + /** + * @brief Returns list of unmatched local (per-file) suppressions. + * @return list of unmatched suppressions + */ + std::list getUnmatchedLocalSuppressions() const; + + /** + * @brief Returns list of unmatched global (glob pattern) suppressions. + * @return list of unmatched suppressions + */ + std::list getUnmatchedGlobalSuppressions() const; }; /** @brief suppress message (--suppressions) */ diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index d9b7ee5f0..f4fbb3f13 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -86,7 +86,7 @@ private: void getErrorMessages() { ErrorLogger2 errorLogger; - CppCheck cppCheck(errorLogger); + CppCheck cppCheck(errorLogger, true); cppCheck.getErrorMessages(); ASSERT(!errorLogger.id.empty()); diff --git a/test/testsuppressions.cpp b/test/testsuppressions.cpp new file mode 100644 index 000000000..b8adaad47 --- /dev/null +++ b/test/testsuppressions.cpp @@ -0,0 +1,172 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2011 Daniel Marjamäki and Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "cppcheck.h" +#include "settings.h" +#include "testsuite.h" +#include "threadexecutor.h" + +#include + +extern std::ostringstream errout; + +class TestSuppressions : public TestFixture +{ +public: + TestSuppressions() : TestFixture("TestSuppressions") + { } + +private: + + void run() + { + TEST_CASE(suppressionsSettings); + } + + // Check the suppression + void checkSuppression(const char code[], const std::string &suppression = "") + { + // Clear the error log + errout.str(""); + + Settings settings; + settings._inlineSuppressions = true; + if (!suppression.empty()) + settings.nomsg.addSuppressionLine(suppression); + + CppCheck cppCheck(*this, true); + cppCheck.settings(settings); + cppCheck.addFile("test.cpp", code); + cppCheck.check(); + + reportUnmatchedSuppressions(cppCheck.settings().nomsg.getUnmatchedGlobalSuppressions()); + } + + void checkSuppressionThreads(const char code[], const std::string &suppression = "") + { + errout.str(""); + output.str(""); + if (!ThreadExecutor::isEnabled()) + { + // Skip this check on systems which don't use this feature + return; + } + + std::vector filenames; + filenames.push_back("test.cpp"); + + Settings settings; + settings._jobs = 1; + settings._inlineSuppressions = true; + if (!suppression.empty()) + settings.nomsg.addSuppressionLine(suppression); + ThreadExecutor executor(filenames, settings, *this); + for (unsigned int i = 0; i < filenames.size(); ++i) + executor.addFileContent(filenames[i], code); + + executor.check(); + + reportUnmatchedSuppressions(settings.nomsg.getUnmatchedGlobalSuppressions()); + } + + void runChecks(void (TestSuppressions::*check)(const char[], const std::string &)) + { + // check to make sure the appropriate error is present + (this->*check)("void f() {\n" + " int a;\n" + " a++;\n" + "}\n", + ""); + ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str()); + + // suppress uninitvar globally + (this->*check)("void f() {\n" + " int a;\n" + " a++;\n" + "}\n", + "uninitvar"); + ASSERT_EQUALS("", errout.str()); + + // suppress uninitvar globally, without error present + (this->*check)("void f() {\n" + " int a;\n" + " b++;\n" + "}\n", + "uninitvar"); + ASSERT_EQUALS("[*]: (information) Unmatched suppression: uninitvar\n", errout.str()); + + // suppress uninitvar for this file only + (this->*check)("void f() {\n" + " int a;\n" + " a++;\n" + "}\n", + "uninitvar:test.cpp"); + ASSERT_EQUALS("", errout.str()); + + // suppress uninitvar for this file only, without error present + (this->*check)("void f() {\n" + " int a;\n" + " b++;\n" + "}\n", + "uninitvar:test.cpp"); + ASSERT_EQUALS("[test.cpp]: (information) Unmatched suppression: uninitvar\n", errout.str()); + + // suppress uninitvar for this file and line + (this->*check)("void f() {\n" + " int a;\n" + " a++;\n" + "}\n", + "uninitvar:test.cpp:3"); + ASSERT_EQUALS("", errout.str()); + + // suppress uninitvar for this file and line, without error present + (this->*check)("void f() {\n" + " int a;\n" + " b++;\n" + "}\n", + "uninitvar:test.cpp:3"); + ASSERT_EQUALS("[test.cpp:3]: (information) Unmatched suppression: uninitvar\n", errout.str()); + + // suppress uninitvar inline + (this->*check)("void f() {\n" + " int a;\n" + " // cppcheck-suppress uninitvar\n" + " a++;\n" + "}\n", + ""); + ASSERT_EQUALS("", errout.str()); + + // suppress uninitvar inline, without error present + (this->*check)("void f() {\n" + " int a;\n" + " // cppcheck-suppress uninitvar\n" + " b++;\n" + "}\n", + ""); + ASSERT_EQUALS("[test.cpp:4]: (information) Unmatched suppression: uninitvar\n", errout.str()); + } + + void suppressionsSettings() + { + runChecks(&TestSuppressions::checkSuppression); + runChecks(&TestSuppressions::checkSuppressionThreads); + } + +}; + +REGISTER_TEST(TestSuppressions) From de00ad693f5ad0736071145e72f2112096278c53 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Wed, 16 Feb 2011 22:18:06 +1300 Subject: [PATCH 17/17] add self to authors file --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index d225bca0e..e76ef76d6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,6 +3,7 @@ The cppcheck team, in alphabetical order: Bill Egert Daniel Marjamäki Gianluca Scacco +Greg Hewgill Hoang Tuan Su Kimmo Varis Leandro Penz