diff --git a/Makefile b/Makefile index f0a45d03a..c37334e1c 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ OBJECTS = src/checkautovariables.o \ src/checkbufferoverrun.o \ src/checkclass.o \ src/checkdangerousfunctions.o \ + src/checkexceptionsafety.o \ src/checkheaders.o \ src/checkmemoryleak.o \ src/checkother.o \ @@ -34,6 +35,7 @@ TESTOBJ = test/testautovariables.o \ test/testcppcheck.o \ test/testdangerousfunctions.o \ test/testdivision.o \ + test/testexceptionsafety.o \ test/testfilelister.o \ test/testincompletestatement.o \ test/testmathlib.o \ @@ -54,6 +56,7 @@ TESTOBJ = test/testautovariables.o \ src/checkbufferoverrun.o \ src/checkclass.o \ src/checkdangerousfunctions.o \ + src/checkexceptionsafety.o \ src/checkheaders.o \ src/checkmemoryleak.o \ src/checkother.o \ @@ -111,6 +114,9 @@ src/checkclass.o: src/checkclass.cpp src/checkclass.h src/check.h src/token.h sr src/checkdangerousfunctions.o: src/checkdangerousfunctions.cpp src/checkdangerousfunctions.h src/check.h src/token.h src/tokenize.h src/classinfo.h src/settings.h src/errorlogger.h $(CXX) $(CXXFLAGS) -c -o src/checkdangerousfunctions.o src/checkdangerousfunctions.cpp +src/checkexceptionsafety.o: src/checkexceptionsafety.cpp + $(CXX) $(CXXFLAGS) -c -o src/checkexceptionsafety.o src/checkexceptionsafety.cpp + src/checkheaders.o: src/checkheaders.cpp src/checkheaders.h src/tokenize.h src/classinfo.h src/token.h src/errorlogger.h src/settings.h src/filelister.h $(CXX) $(CXXFLAGS) -c -o src/checkheaders.o src/checkheaders.cpp @@ -156,7 +162,7 @@ src/threadexecutor.o: src/threadexecutor.cpp src/threadexecutor.h src/settings.h src/token.o: src/token.cpp src/token.h $(CXX) $(CXXFLAGS) -c -o src/token.o src/token.cpp -src/tokenize.o: src/tokenize.cpp src/tokenize.h src/classinfo.h src/token.h src/filelister.h src/mathlib.h src/settings.h src/errorlogger.h +src/tokenize.o: src/tokenize.cpp src/tokenize.h src/classinfo.h src/token.h src/filelister.h src/mathlib.h src/settings.h src/errorlogger.h src/check.h $(CXX) $(CXXFLAGS) -c -o src/tokenize.o src/tokenize.cpp test/testautovariables.o: test/testautovariables.cpp src/tokenize.h src/classinfo.h src/token.h src/checkautovariables.h src/check.h src/settings.h src/errorlogger.h test/testsuite.h @@ -183,6 +189,9 @@ test/testdangerousfunctions.o: test/testdangerousfunctions.cpp src/tokenize.h sr test/testdivision.o: test/testdivision.cpp src/tokenize.h src/classinfo.h src/token.h src/checkother.h src/check.h src/settings.h src/errorlogger.h test/testsuite.h $(CXX) $(CXXFLAGS) -c -o test/testdivision.o test/testdivision.cpp +test/testexceptionsafety.o: test/testexceptionsafety.cpp + $(CXX) $(CXXFLAGS) -c -o test/testexceptionsafety.o test/testexceptionsafety.cpp + test/testfilelister.o: test/testfilelister.cpp test/testsuite.h src/errorlogger.h src/settings.h src/filelister.h $(CXX) $(CXXFLAGS) -c -o test/testfilelister.o test/testfilelister.cpp diff --git a/src/checkexceptionsafety.cpp b/src/checkexceptionsafety.cpp new file mode 100644 index 000000000..2758221a7 --- /dev/null +++ b/src/checkexceptionsafety.cpp @@ -0,0 +1,76 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 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 "checkexceptionsafety.h" + +#include "tokenize.h" +#include "token.h" +#include "errorlogger.h" + +//--------------------------------------------------------------------------- + +// Register CheckExceptionSafety.. +namespace +{ +CheckExceptionSafety instance; +} + + +//--------------------------------------------------------------------------- + +void CheckExceptionSafety::destructors() +{ + // This is a style error.. + if (!_settings->_checkCodingStyle) + return; + + // Perform check.. + for (const Token * tok = _tokenizer->tokens(); tok; tok = tok->next()) + { + if (Token::simpleMatch(tok, ") {")) + tok = tok->next()->link(); + + if (!Token::Match(tok, "~ %var% ( ) {")) + continue; + + // Inspect this destructor.. + unsigned int indentlevel = 0; + for (const Token *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + { + ++indentlevel; + } + + else if (tok2->str() == "}") + { + if (indentlevel <= 1) + break; + --indentlevel; + } + + else if (tok2->str() == "throw") + { + destructorsError(tok2); + break; + } + } + } +} + diff --git a/src/checkexceptionsafety.h b/src/checkexceptionsafety.h new file mode 100644 index 000000000..1a517ccd7 --- /dev/null +++ b/src/checkexceptionsafety.h @@ -0,0 +1,81 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 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 . + */ + +//--------------------------------------------------------------------------- +#ifndef checkexceptionsafetyH +#define checkexceptionsafetyH +//--------------------------------------------------------------------------- + +#include "check.h" +#include "settings.h" + +class Token; + +/// @addtogroup Checks +/// @{ + + +class CheckExceptionSafety : public Check +{ +public: + /** This constructor is used when registering the CheckClass */ + CheckExceptionSafety() : Check() + { } + + /** This constructor is used when running checks.. */ + CheckExceptionSafety(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) + : Check(tokenizer, settings, errorLogger) + { } + + void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) + { + CheckExceptionSafety checkExceptionSafety(tokenizer, settings, errorLogger); + checkExceptionSafety.destructors(); + } + + + /** Don't throw exceptions in destructors */ + void destructors(); + +private: + /** Don't throw exceptions in destructors */ + void destructorsError(const Token * const tok) + { + reportError(tok, Severity::style, "throwInDestructor", "Throwing exception in destructor is not recommended"); + } + + void getErrorMessages() + { + destructorsError(0); + } + + std::string name() const + { + return "Exception Safety"; + } + + std::string classInfo() const + { + return "Checking exception safety\n" + " * Don't throw exceptions in destructors"; + } +}; +/// @} +//--------------------------------------------------------------------------- +#endif + diff --git a/test/testexceptionsafety.cpp b/test/testexceptionsafety.cpp new file mode 100644 index 000000000..f1d91c799 --- /dev/null +++ b/test/testexceptionsafety.cpp @@ -0,0 +1,70 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 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 "../src/tokenize.h" +#include "../src/checkexceptionsafety.h" +#include "testsuite.h" +#include + +extern std::ostringstream errout; + +class TestExceptionSafety : public TestFixture +{ +public: + TestExceptionSafety() : TestFixture("TestExceptionSafety") + { } + +private: + + void run() + { + TEST_CASE(destructors); + } + + void check(const char code[]) + { + // Tokenize.. + Tokenizer tokenizer; + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + tokenizer.simplifyTokenList(); + + // Clear the error buffer.. + errout.str(""); + + // Check char variable usage.. + Settings settings; + settings._checkCodingStyle = true; + CheckExceptionSafety checkExceptionSafety(&tokenizer, &settings, this); + checkExceptionSafety.destructors(); + } + + void destructors() + { + check("x::~x()\n" + "{\n" + " throw e;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (style) Throwing exception in destructor is not recommended\n", errout.str()); + } + +}; + +REGISTER_TEST(TestExceptionSafety) +