From dfe867fded96b6c3662f3851757eec2731f0e060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 19 Mar 2009 20:52:18 +0100 Subject: [PATCH 1/3] added checkautovariables and integrated it into cppcheck --- Makefile | 9 +- src/checkautovariables.cpp | 205 +++++++++++++++++++++++++++++++++++++ src/checkautovariables.h | 56 ++++++++++ src/errorlogger.h | 9 ++ tools/errmsg.cpp | 3 + 5 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 src/checkautovariables.cpp create mode 100644 src/checkautovariables.h diff --git a/Makefile b/Makefile index d386bea27..9843dc28a 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,8 @@ BIN=${DESTDIR}/usr/bin ###### Object Files -OBJECTS = src/checkbufferoverrun.o \ +OBJECTS = src/checkautovariables.o \ + src/checkbufferoverrun.o \ src/checkclass.o \ src/checkdangerousfunctions.o \ src/checkfunctionusage.o \ @@ -49,6 +50,7 @@ TESTOBJ = test/testbufferoverrun.o \ test/testtokenize.o \ test/testunusedprivfunc.o \ test/testunusedvar.o \ + src/checkautovariables.o \ src/checkbufferoverrun.o \ src/checkclass.o \ src/checkdangerousfunctions.o \ @@ -100,6 +102,9 @@ install: cppcheck ###### Build +src/checkautovariables.o: src/checkautovariables.cpp src/checkautovariables.h src/check.h src/settings.h src/token.h src/tokenize.h src/errorlogger.h + $(CXX) $(CXXFLAGS) -c -o src/checkautovariables.o src/checkautovariables.cpp + src/checkbufferoverrun.o: src/checkbufferoverrun.cpp src/checkbufferoverrun.h src/settings.h src/tokenize.h src/errorlogger.h src/token.h $(CXX) $(CXXFLAGS) -c -o src/checkbufferoverrun.o src/checkbufferoverrun.cpp @@ -127,7 +132,7 @@ src/checksecurity.o: src/checksecurity.cpp src/checksecurity.h src/errorlogger.h src/checkstl.o: src/checkstl.cpp src/checkstl.h src/check.h src/settings.h src/tokenize.h src/errorlogger.h src/token.h $(CXX) $(CXXFLAGS) -c -o src/checkstl.o src/checkstl.cpp -src/cppcheck.o: src/cppcheck.cpp src/cppcheck.h src/settings.h src/errorlogger.h src/checkfunctionusage.h src/tokenize.h src/token.h src/preprocessor.h src/checkmemoryleak.h src/checkbufferoverrun.h src/checkdangerousfunctions.h src/checkclass.h src/checkheaders.h src/checkother.h src/filelister.h +src/cppcheck.o: src/cppcheck.cpp src/cppcheck.h src/settings.h src/errorlogger.h src/checkfunctionusage.h src/tokenize.h src/token.h src/preprocessor.h src/checkmemoryleak.h src/checkbufferoverrun.h src/checkdangerousfunctions.h src/checkclass.h src/checkheaders.h src/checkother.h src/filelister.h src/check.h $(CXX) $(CXXFLAGS) -c -o src/cppcheck.o src/cppcheck.cpp src/cppcheckexecutor.o: src/cppcheckexecutor.cpp src/cppcheckexecutor.h src/errorlogger.h src/settings.h src/cppcheck.h src/checkfunctionusage.h src/tokenize.h src/token.h src/threadexecutor.h diff --git a/src/checkautovariables.cpp b/src/checkautovariables.cpp new file mode 100644 index 000000000..85315eaae --- /dev/null +++ b/src/checkautovariables.cpp @@ -0,0 +1,205 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 Daniel Marjamäki, Reijo Tomperi, Nicolas Le Cam, + * Leandro Penz, Kimmo Varis, Vesa Pikki + * + * 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 +#include +#include +#include +#include + +#include // <- strtoul + +//--------------------------------------------------------------------------- + + +// Register this check class into cppcheck by creating a static instance of it.. +namespace +{ + static CheckAutoVariables instance; +} + + +// _callStack used when parsing into subfunctions. + + +bool CheckAutoVariables::error_av(const Token* left,const Token* right) +{ + std::string left_var=left->str(); + std::string right_var=right->str(); + std::list::iterator it_fp; + + for(it_fp=fp_list.begin();it_fp!=fp_list.end();it_fp++) + { + std::string vname=(*it_fp); + //cout << "error_av " << vname << " " << left_var << endl; + if (vname==left_var){ + //cout << "Beccato" << endl; + break; //The left argument is a formal parameter + } + + } + if (it_fp==fp_list.end()) + return false; //The left argument is NOT a formal parameter + + std::list::iterator id_vd; + for(id_vd=vd_list.begin();id_vd!=vd_list.end();id_vd++) + { + std::string vname=(*id_vd); + if (vname==right_var) + break; //The left argument is a variable declaration + } + if (id_vd==vd_list.end()) + return false; //The left argument is NOT a variable declaration + //If I reach this point there is a wrong assignement of an auto-variable to an effective parameter of a function + return true; + +} +bool CheckAutoVariables::is_auto_var(const Token* t) +{ + std::list::iterator id_vd; + std::string v=t->str(); + for(id_vd=vd_list.begin();id_vd!=vd_list.end();id_vd++) + { + std::string vname=(*id_vd); + if (vname==v) + return true; + } + return false; +} +void print(const Token *tok, int num) +{ + const Token *t=tok; + std::cout << tok->linenr() << " PRINT "; + for (int i=0;istr() << "] "; + t=t->next(); + } + std::cout << std::endl; +} +bool isTypeName(const Token *tok) +{ + bool ret = false; + std::string _str=tok->str(); + const char *type[] = {"case", "return","delete",0}; + for (int i = 0; type[i]; i++) + ret |= (_str == type[i]); + return !ret; +} +void CheckAutoVariables::addVD(const Token* tok) +{ + std::string var_name; + var_name=tok->str(); + //cout << "VD " << tok->linenr() << " " << var_name << endl; + vd_list.push_back(var_name); +} +void CheckAutoVariables::autoVariables() +{ + bool begin_function=false; + bool begin_function_decl=false; + int bindent=0; + + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) + { + + if (Token::Match(tok, "%type% %var% (") || + Token::Match(tok, "%type% * %var% (") || + Token::Match(tok, "%type% :: %var% (")) + { + begin_function=true; + fp_list.clear(); + vd_list.clear(); + } + else if (begin_function && begin_function_decl && Token::Match(tok, "%type% * %var%")) + { + std::string var_name; + + var_name=tok->tokAt(2)->str(); + //cout << "FP " << tok->linenr() << " " << var_name << endl; + fp_list.push_back(var_name); + } + else if (begin_function && Token::Match(tok, "(")) + begin_function_decl=true; + else if (begin_function && Token::Match(tok, ")")) + { + begin_function_decl=false; + } + else if (begin_function && Token::Match(tok, "{")) + bindent++; + else if (begin_function && Token::Match(tok, "}")) + { + bindent--; + } + else if (bindent>0 && Token::Match(tok, "%type% :: %any%")) //Inside a function + { + std::string var_name; + //print(tok,5); + var_name=tok->tokAt(2)->str(); + vd_list.push_back(var_name); + } + else if (bindent>0 && Token::Match(tok, "%var% %var% ;")) //Inside a function + { + if (!isTypeName(tok)) + continue; + addVD(tok->tokAt(1)); + } + else if (bindent>0 && Token::Match(tok, "const %var% %var% ;")) //Inside a function + { + if (!isTypeName(tok->tokAt(1))) + continue; + addVD(tok->tokAt(2)); + } + else if (bindent>0 && Token::Match(tok, "%var% = & %var%")) //Critical assignement + { + if (error_av(tok->tokAt(0),tok->tokAt(3))) + _errorLogger->genericError(_tokenizer, + tok, + "Wrong assignement of an auto-variable to an effective parameter of a function"); + } + else if (bindent>0 && Token::Match(tok, "%var% [ %any% ] = & %var%")) //Critical assignement + { + if (error_av(tok->tokAt(0),tok->tokAt(6))) + _errorLogger->genericError(_tokenizer, + tok, + "Wrong assignement of an auto-variable to an effective parameter of a function"); + } + else if (bindent>0 && Token::Match(tok, "return & %var%")) //Critical return + { + if (is_auto_var(tok->tokAt(2))) + _errorLogger->genericError(_tokenizer, + tok, + "Return of the address of an auto-variable"); + } + } + vd_list.clear(); + fp_list.clear(); +} +//--------------------------------------------------------------------------- + + + + diff --git a/src/checkautovariables.h b/src/checkautovariables.h new file mode 100644 index 000000000..5944f4e49 --- /dev/null +++ b/src/checkautovariables.h @@ -0,0 +1,56 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 Daniel Marjamäki, Reijo Tomperi, Nicolas Le Cam, + * Leandro Penz, Kimmo Varis, Vesa Pikki + * + * 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 + +class CheckAutoVariables : public Check +{ +public: + void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) + { + _tokenizer = tokenizer; + _settings = settings; + _errorLogger = errorLogger; + autoVariables(); + } + + /** Check for buffer overruns */ + void autoVariables(); +private: + std::list fp_list; + std::list vd_list; + bool error_av(const Token* left,const Token* right); + bool is_auto_var(const Token* t); + void addVD(const Token* t); + const Tokenizer *_tokenizer; + const Settings *_settings; + ErrorLogger *_errorLogger; +}; + +//--------------------------------------------------------------------------- +#endif + diff --git a/src/errorlogger.h b/src/errorlogger.h index c383c7b48..a18c996c8 100644 --- a/src/errorlogger.h +++ b/src/errorlogger.h @@ -95,6 +95,15 @@ public: */ virtual void reportStatus(unsigned int index, unsigned int max) = 0; + void genericError(const Tokenizer *tokenizer, const Token *Location, const std::string &msg) + { + _writemsg(tokenizer, Location, "error", "" + msg + "", "genericError"); + } + static bool genericError() + { + return true; + } + void arrayIndexOutOfBounds(const Tokenizer *tokenizer, const std::list &Location) { _writemsg(tokenizer, Location, "all", "Array index out of bounds", "arrayIndexOutOfBounds"); diff --git a/tools/errmsg.cpp b/tools/errmsg.cpp index 50de00a22..a0cf999f6 100644 --- a/tools/errmsg.cpp +++ b/tools/errmsg.cpp @@ -57,6 +57,9 @@ int main() // Error messages.. std::list err; + // Generic error message + err.push_back(Message("genericError", Message::error, "%1", "msg")); + // checkbufferoverrun.cpp err.push_back(Message("arrayIndexOutOfBounds", Message::all, "Array index out of bounds")); err.push_back(Message("bufferOverrun", Message::all, "Buffer overrun")); From d4fdfc0f5abecbdfdef3e7b4ba95ce252648b0fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 19 Mar 2009 20:53:23 +0100 Subject: [PATCH 2/3] astyle formatting --- src/checkautovariables.cpp | 247 ++++++++++++++--------------- src/checkautovariables.h | 10 +- test/teststl.cpp | 310 ++++++++++++++++++------------------- 3 files changed, 284 insertions(+), 283 deletions(-) diff --git a/src/checkautovariables.cpp b/src/checkautovariables.cpp index 85315eaae..fe4e4d97c 100644 --- a/src/checkautovariables.cpp +++ b/src/checkautovariables.cpp @@ -39,164 +39,165 @@ // Register this check class into cppcheck by creating a static instance of it.. namespace { - static CheckAutoVariables instance; +static CheckAutoVariables instance; } // _callStack used when parsing into subfunctions. -bool CheckAutoVariables::error_av(const Token* left,const Token* right) +bool CheckAutoVariables::error_av(const Token* left, const Token* right) { - std::string left_var=left->str(); - std::string right_var=right->str(); - std::list::iterator it_fp; + std::string left_var = left->str(); + std::string right_var = right->str(); + std::list::iterator it_fp; - for(it_fp=fp_list.begin();it_fp!=fp_list.end();it_fp++) - { - std::string vname=(*it_fp); - //cout << "error_av " << vname << " " << left_var << endl; - if (vname==left_var){ - //cout << "Beccato" << endl; - break; //The left argument is a formal parameter - } + for (it_fp = fp_list.begin();it_fp != fp_list.end();it_fp++) + { + std::string vname = (*it_fp); + //cout << "error_av " << vname << " " << left_var << endl; + if (vname == left_var) + { + //cout << "Beccato" << endl; + break; //The left argument is a formal parameter + } - } - if (it_fp==fp_list.end()) - return false; //The left argument is NOT a formal parameter + } + if (it_fp == fp_list.end()) + return false; //The left argument is NOT a formal parameter - std::list::iterator id_vd; - for(id_vd=vd_list.begin();id_vd!=vd_list.end();id_vd++) - { - std::string vname=(*id_vd); - if (vname==right_var) - break; //The left argument is a variable declaration - } - if (id_vd==vd_list.end()) - return false; //The left argument is NOT a variable declaration - //If I reach this point there is a wrong assignement of an auto-variable to an effective parameter of a function - return true; + std::list::iterator id_vd; + for (id_vd = vd_list.begin();id_vd != vd_list.end();id_vd++) + { + std::string vname = (*id_vd); + if (vname == right_var) + break; //The left argument is a variable declaration + } + if (id_vd == vd_list.end()) + return false; //The left argument is NOT a variable declaration + //If I reach this point there is a wrong assignement of an auto-variable to an effective parameter of a function + return true; } bool CheckAutoVariables::is_auto_var(const Token* t) { - std::list::iterator id_vd; - std::string v=t->str(); - for(id_vd=vd_list.begin();id_vd!=vd_list.end();id_vd++) - { - std::string vname=(*id_vd); - if (vname==v) - return true; - } - return false; + std::list::iterator id_vd; + std::string v = t->str(); + for (id_vd = vd_list.begin();id_vd != vd_list.end();id_vd++) + { + std::string vname = (*id_vd); + if (vname == v) + return true; + } + return false; } void print(const Token *tok, int num) { - const Token *t=tok; - std::cout << tok->linenr() << " PRINT "; - for (int i=0;istr() << "] "; - t=t->next(); - } - std::cout << std::endl; + const Token *t = tok; + std::cout << tok->linenr() << " PRINT "; + for (int i = 0;i < num;i++) + { + std::cout << " [" << t->str() << "] "; + t = t->next(); + } + std::cout << std::endl; } bool isTypeName(const Token *tok) { - bool ret = false; - std::string _str=tok->str(); - const char *type[] = {"case", "return","delete",0}; + bool ret = false; + std::string _str = tok->str(); + const char *type[] = {"case", "return", "delete", 0}; for (int i = 0; type[i]; i++) ret |= (_str == type[i]); return !ret; } void CheckAutoVariables::addVD(const Token* tok) { - std::string var_name; - var_name=tok->str(); - //cout << "VD " << tok->linenr() << " " << var_name << endl; - vd_list.push_back(var_name); + std::string var_name; + var_name = tok->str(); + //cout << "VD " << tok->linenr() << " " << var_name << endl; + vd_list.push_back(var_name); } void CheckAutoVariables::autoVariables() { - bool begin_function=false; - bool begin_function_decl=false; - int bindent=0; + bool begin_function = false; + bool begin_function_decl = false; + int bindent = 0; for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, "%type% %var% (") || - Token::Match(tok, "%type% * %var% (") || - Token::Match(tok, "%type% :: %var% (")) - { - begin_function=true; - fp_list.clear(); - vd_list.clear(); - } - else if (begin_function && begin_function_decl && Token::Match(tok, "%type% * %var%")) - { - std::string var_name; + if (Token::Match(tok, "%type% %var% (") || + Token::Match(tok, "%type% * %var% (") || + Token::Match(tok, "%type% :: %var% (")) + { + begin_function = true; + fp_list.clear(); + vd_list.clear(); + } + else if (begin_function && begin_function_decl && Token::Match(tok, "%type% * %var%")) + { + std::string var_name; - var_name=tok->tokAt(2)->str(); - //cout << "FP " << tok->linenr() << " " << var_name << endl; - fp_list.push_back(var_name); - } - else if (begin_function && Token::Match(tok, "(")) - begin_function_decl=true; - else if (begin_function && Token::Match(tok, ")")) - { - begin_function_decl=false; - } - else if (begin_function && Token::Match(tok, "{")) - bindent++; - else if (begin_function && Token::Match(tok, "}")) - { - bindent--; - } - else if (bindent>0 && Token::Match(tok, "%type% :: %any%")) //Inside a function - { - std::string var_name; - //print(tok,5); - var_name=tok->tokAt(2)->str(); - vd_list.push_back(var_name); - } - else if (bindent>0 && Token::Match(tok, "%var% %var% ;")) //Inside a function - { - if (!isTypeName(tok)) - continue; - addVD(tok->tokAt(1)); - } - else if (bindent>0 && Token::Match(tok, "const %var% %var% ;")) //Inside a function - { - if (!isTypeName(tok->tokAt(1))) - continue; - addVD(tok->tokAt(2)); - } - else if (bindent>0 && Token::Match(tok, "%var% = & %var%")) //Critical assignement - { - if (error_av(tok->tokAt(0),tok->tokAt(3))) - _errorLogger->genericError(_tokenizer, - tok, - "Wrong assignement of an auto-variable to an effective parameter of a function"); - } - else if (bindent>0 && Token::Match(tok, "%var% [ %any% ] = & %var%")) //Critical assignement - { - if (error_av(tok->tokAt(0),tok->tokAt(6))) - _errorLogger->genericError(_tokenizer, - tok, - "Wrong assignement of an auto-variable to an effective parameter of a function"); - } - else if (bindent>0 && Token::Match(tok, "return & %var%")) //Critical return - { - if (is_auto_var(tok->tokAt(2))) - _errorLogger->genericError(_tokenizer, - tok, - "Return of the address of an auto-variable"); - } + var_name = tok->tokAt(2)->str(); + //cout << "FP " << tok->linenr() << " " << var_name << endl; + fp_list.push_back(var_name); + } + else if (begin_function && Token::Match(tok, "(")) + begin_function_decl = true; + else if (begin_function && Token::Match(tok, ")")) + { + begin_function_decl = false; + } + else if (begin_function && Token::Match(tok, "{")) + bindent++; + else if (begin_function && Token::Match(tok, "}")) + { + bindent--; + } + else if (bindent > 0 && Token::Match(tok, "%type% :: %any%")) //Inside a function + { + std::string var_name; + //print(tok,5); + var_name = tok->tokAt(2)->str(); + vd_list.push_back(var_name); + } + else if (bindent > 0 && Token::Match(tok, "%var% %var% ;")) //Inside a function + { + if (!isTypeName(tok)) + continue; + addVD(tok->tokAt(1)); + } + else if (bindent > 0 && Token::Match(tok, "const %var% %var% ;")) //Inside a function + { + if (!isTypeName(tok->tokAt(1))) + continue; + addVD(tok->tokAt(2)); + } + else if (bindent > 0 && Token::Match(tok, "%var% = & %var%")) //Critical assignement + { + if (error_av(tok->tokAt(0), tok->tokAt(3))) + _errorLogger->genericError(_tokenizer, + tok, + "Wrong assignement of an auto-variable to an effective parameter of a function"); + } + else if (bindent > 0 && Token::Match(tok, "%var% [ %any% ] = & %var%")) //Critical assignement + { + if (error_av(tok->tokAt(0), tok->tokAt(6))) + _errorLogger->genericError(_tokenizer, + tok, + "Wrong assignement of an auto-variable to an effective parameter of a function"); + } + else if (bindent > 0 && Token::Match(tok, "return & %var%")) //Critical return + { + if (is_auto_var(tok->tokAt(2))) + _errorLogger->genericError(_tokenizer, + tok, + "Return of the address of an auto-variable"); + } } - vd_list.clear(); - fp_list.clear(); + vd_list.clear(); + fp_list.clear(); } //--------------------------------------------------------------------------- diff --git a/src/checkautovariables.h b/src/checkautovariables.h index 5944f4e49..5f187717b 100644 --- a/src/checkautovariables.h +++ b/src/checkautovariables.h @@ -41,11 +41,11 @@ public: /** Check for buffer overruns */ void autoVariables(); private: - std::list fp_list; - std::list vd_list; - bool error_av(const Token* left,const Token* right); - bool is_auto_var(const Token* t); - void addVD(const Token* t); + std::list fp_list; + std::list vd_list; + bool error_av(const Token* left, const Token* right); + bool is_auto_var(const Token* t); + void addVD(const Token* t); const Tokenizer *_tokenizer; const Settings *_settings; ErrorLogger *_errorLogger; diff --git a/test/teststl.cpp b/test/teststl.cpp index c7acdb7f0..39fedcf15 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -49,195 +49,195 @@ private: TEST_CASE(invalidcode); } - void check(const char code[]) - { - // Tokenize.. - Tokenizer tokenizer; - std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); + void check(const char code[]) + { + // Tokenize.. + Tokenizer tokenizer; + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); - // Clear the error buffer.. - errout.str(""); + // Clear the error buffer.. + errout.str(""); - // Check.. - CheckStl checkStl; - checkStl.runChecks(&tokenizer, (const Settings *)0, this); - } + // Check.. + CheckStl checkStl; + checkStl.runChecks(&tokenizer, (const Settings *)0, this); + } - void iterator1() + void iterator1() + { + check("void foo()\n" + "{\n" + " for (it = foo.begin(); it != bar.end(); ++it)\n" + " { }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (error) Same iterator is used with both foo and bar\n", errout.str()); + } + + void iterator2() + { + check("void foo()\n" + "{\n" + " it = foo.begin();\n" + " while (it != bar.end())\n" + " {\n" + " ++it;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (error) Same iterator is used with both foo and bar\n", errout.str()); + } + + + void STLSize() + { + check("void foo()\n" + "{\n" + " std::vector foo;\n" + " for (unsigned int ii = 0; ii <= foo.size(); ++ii)\n" + " {\n" + " foo[ii] = 0;\n" + " }\n" + "}\n"); + ASSERT_EQUALS(std::string("[test.cpp:6]: (error) When ii == size(), foo [ ii ] is out of bounds\n"), errout.str()); + } + + void STLSizeNoErr() + { { check("void foo()\n" "{\n" - " for (it = foo.begin(); it != bar.end(); ++it)\n" - " { }\n" - "}\n"); - ASSERT_EQUALS("[test.cpp:3]: (error) Same iterator is used with both foo and bar\n", errout.str()); - } - - void iterator2() - { - check("void foo()\n" - "{\n" - " it = foo.begin();\n" - " while (it != bar.end())\n" + " std::vector foo;\n" + " for (unsigned int ii = 0; ii < foo.size(); ++ii)\n" " {\n" - " ++it;\n" + " foo[ii] = 0;\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:3]: (error) Same iterator is used with both foo and bar\n", errout.str()); + ASSERT_EQUALS(std::string(""), errout.str()); } - - void STLSize() { check("void foo()\n" "{\n" " std::vector foo;\n" " for (unsigned int ii = 0; ii <= foo.size(); ++ii)\n" " {\n" - " foo[ii] = 0;\n" " }\n" "}\n"); - ASSERT_EQUALS(std::string("[test.cpp:6]: (error) When ii == size(), foo [ ii ] is out of bounds\n"), errout.str()); + ASSERT_EQUALS(std::string(""), errout.str()); } - void STLSizeNoErr() { - { - check("void foo()\n" - "{\n" - " std::vector foo;\n" - " for (unsigned int ii = 0; ii < foo.size(); ++ii)\n" - " {\n" - " foo[ii] = 0;\n" - " }\n" - "}\n"); - ASSERT_EQUALS(std::string(""), errout.str()); - } - - { - check("void foo()\n" - "{\n" - " std::vector foo;\n" - " for (unsigned int ii = 0; ii <= foo.size(); ++ii)\n" - " {\n" - " }\n" - "}\n"); - ASSERT_EQUALS(std::string(""), errout.str()); - } - - { - check("void foo()\n" - "{\n" - " std::vector foo;\n" - " for (unsigned int ii = 0; ii <= foo.size(); ++ii)\n" - " {\n" - " if (ii == foo.size())\n" - " {\n" - " }\n" - " else\n" - " {\n" - " foo[ii] = 0;\n" - " }\n" - " }\n" - "}\n"); - // TODO ASSERT_EQUALS(std::string(""), errout.str()); - } - } - - - - - - void erase() - { - check("void f()\n" + check("void foo()\n" "{\n" - " for (it = foo.begin(); it != foo.end(); ++it)\n" + " std::vector foo;\n" + " for (unsigned int ii = 0; ii <= foo.size(); ++ii)\n" " {\n" - " foo.erase(it);\n" + " if (ii == foo.size())\n" + " {\n" + " }\n" + " else\n" + " {\n" + " foo[ii] = 0;\n" + " }\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5]: (error) Dangerous usage of erase\n", errout.str()); - } - - void eraseBreak() - { - check("void f()\n" - "{\n" - " for (it = foo.begin(); it != foo.end(); ++it)\n" - " {\n" - " foo.erase(it);\n" - " break;\n" - " }\n" - "}\n"); - ASSERT_EQUALS("", errout.str()); - } - - void eraseReturn() - { - check("void f()\n" - "{\n" - " for (it = foo.begin(); it != foo.end(); ++it)\n" - " {\n" - " foo.erase(it);\n" - " return;\n" - " }\n" - "}\n"); - ASSERT_EQUALS("", errout.str()); - } - - void eraseGoto() - { - check("void f()\n" - "{\n" - " for (it = foo.begin(); it != foo.end(); ++it)\n" - " {\n" - " foo.erase(it);\n" - " goto abc;\n" - " }\n" - "bar:\n" - "}\n"); - ASSERT_EQUALS("", errout.str()); - } - - void eraseAssign() - { - check("void f()\n" - "{\n" - " for (it = foo.begin(); it != foo.end(); ++it)\n" - " {\n" - " foo.erase(it);\n" - " it = foo.begin();\n" - " }\n" - "}\n"); - ASSERT_EQUALS("", errout.str()); + // TODO ASSERT_EQUALS(std::string(""), errout.str()); } + } - void pushback1() - { - check("void f()\n" - "{\n" - " std::vector::const_iterator it = foo.begin();\n" - " foo.push_back(123);\n" - " *it;\n" - "}\n"); - ASSERT_EQUALS("[test.cpp:5]: (error) After push_back or push_front, the iterator 'it' may be invalid\n", errout.str()); - } + void erase() + { + check("void f()\n" + "{\n" + " for (it = foo.begin(); it != foo.end(); ++it)\n" + " {\n" + " foo.erase(it);\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5]: (error) Dangerous usage of erase\n", errout.str()); + } - void invalidcode() - { - check("void f()\n" - "{\n" - " for ( \n" - "}\n"); - ASSERT_EQUALS("", errout.str()); - } + void eraseBreak() + { + check("void f()\n" + "{\n" + " for (it = foo.begin(); it != foo.end(); ++it)\n" + " {\n" + " foo.erase(it);\n" + " break;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + + void eraseReturn() + { + check("void f()\n" + "{\n" + " for (it = foo.begin(); it != foo.end(); ++it)\n" + " {\n" + " foo.erase(it);\n" + " return;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + + void eraseGoto() + { + check("void f()\n" + "{\n" + " for (it = foo.begin(); it != foo.end(); ++it)\n" + " {\n" + " foo.erase(it);\n" + " goto abc;\n" + " }\n" + "bar:\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + + void eraseAssign() + { + check("void f()\n" + "{\n" + " for (it = foo.begin(); it != foo.end(); ++it)\n" + " {\n" + " foo.erase(it);\n" + " it = foo.begin();\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + + + + + + void pushback1() + { + check("void f()\n" + "{\n" + " std::vector::const_iterator it = foo.begin();\n" + " foo.push_back(123);\n" + " *it;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5]: (error) After push_back or push_front, the iterator 'it' may be invalid\n", errout.str()); + } + + void invalidcode() + { + check("void f()\n" + "{\n" + " for ( \n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestStl) From 5565be0c74cbda4de3582dab1d057710de76d7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 19 Mar 2009 21:20:08 +0100 Subject: [PATCH 3/3] refactoring: minor cleanup --- src/checkstl.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/checkstl.cpp b/src/checkstl.cpp index 9acc0b40e..8c33129c4 100644 --- a/src/checkstl.cpp +++ b/src/checkstl.cpp @@ -22,9 +22,11 @@ #include "token.h" -// Create a static instance of this -static CheckStl instance; - +// Register this check class (by creating a static instance of it) +namespace +{ + CheckStl instance; +} void CheckStl::iterators() {