Fixed #2382 (Catching exceptions by value instead of reference)
This commit is contained in:
parent
f1f1a21c23
commit
d11b5163b7
|
@ -302,6 +302,34 @@ void CheckOther::checkIncorrectLogicOperator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// try {} catch (std::exception err) {} <- Should be "std::exception& err"
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void CheckOther::checkCatchExceptionByValue()
|
||||||
|
{
|
||||||
|
if (!_settings->_checkCodingStyle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char catchPattern[] = "} catch (";
|
||||||
|
const Token *tok = Token::findmatch(_tokenizer->tokens(), catchPattern);
|
||||||
|
const Token *endTok = tok ? tok->tokAt(2)->link() : NULL;
|
||||||
|
|
||||||
|
while (tok && endTok)
|
||||||
|
{
|
||||||
|
// Find a pass-by-value declaration in the catch(), excluding basic types
|
||||||
|
// e.g. catch (std::exception err)
|
||||||
|
const Token *tokType = Token::findmatch(tok, "%type% %var% )", endTok);
|
||||||
|
if (tokType &&
|
||||||
|
!Token::Match(tokType, "bool|char|double|enum|float|int|long|short|size_t|wchar_t"))
|
||||||
|
{
|
||||||
|
catchExceptionByValueError(tokType);
|
||||||
|
}
|
||||||
|
|
||||||
|
tok = Token::findmatch(endTok->next(), catchPattern);
|
||||||
|
endTok = tok ? tok->tokAt(2)->link() : NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// strtol(str, 0, radix) <- radix must be 0 or 2-36
|
// strtol(str, 0, radix) <- radix must be 0 or 2-36
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -2768,3 +2796,11 @@ void CheckOther::misusedScopeObjectError(const Token *tok, const std::string& va
|
||||||
reportError(tok, Severity::error,
|
reportError(tok, Severity::error,
|
||||||
"unusedScopedObject", "instance of \"" + varname + "\" object destroyed immediately");
|
"unusedScopedObject", "instance of \"" + varname + "\" object destroyed immediately");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckOther::catchExceptionByValueError(const Token *tok)
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::style,
|
||||||
|
"catchExceptionByStyle", "Exception should be caught by reference.\n"
|
||||||
|
"The exception is caught as a value. It could be caught "
|
||||||
|
"as a (const) reference which is usually recommended in C++.");
|
||||||
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ public:
|
||||||
checkOther.checkSelfAssignment();
|
checkOther.checkSelfAssignment();
|
||||||
checkOther.checkIncorrectLogicOperator();
|
checkOther.checkIncorrectLogicOperator();
|
||||||
checkOther.checkMisusedScopedObject();
|
checkOther.checkMisusedScopedObject();
|
||||||
|
checkOther.checkCatchExceptionByValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Are there C-style pointer casts in a c++ file? */
|
/** @brief Are there C-style pointer casts in a c++ file? */
|
||||||
|
@ -162,6 +163,9 @@ public:
|
||||||
/** @brief %Check for objects that are destroyed immediately */
|
/** @brief %Check for objects that are destroyed immediately */
|
||||||
void checkMisusedScopedObject();
|
void checkMisusedScopedObject();
|
||||||
|
|
||||||
|
/** @brief %Check for exceptions that are caught by value instead of by reference */
|
||||||
|
void checkCatchExceptionByValue();
|
||||||
|
|
||||||
// Error messages..
|
// Error messages..
|
||||||
void cstyleCastError(const Token *tok);
|
void cstyleCastError(const Token *tok);
|
||||||
void dangerousUsageStrtolError(const Token *tok);
|
void dangerousUsageStrtolError(const Token *tok);
|
||||||
|
@ -183,6 +187,7 @@ public:
|
||||||
void assignmentInAssertError(const Token *tok, const std::string &varname);
|
void assignmentInAssertError(const Token *tok, const std::string &varname);
|
||||||
void incorrectLogicOperatorError(const Token *tok);
|
void incorrectLogicOperatorError(const Token *tok);
|
||||||
void misusedScopeObjectError(const Token *tok, const std::string &varname);
|
void misusedScopeObjectError(const Token *tok, const std::string &varname);
|
||||||
|
void catchExceptionByValueError(const Token *tok);
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
|
@ -218,6 +223,7 @@ public:
|
||||||
c.allocatedButUnusedVariableError(0, "varname");
|
c.allocatedButUnusedVariableError(0, "varname");
|
||||||
c.unreadVariableError(0, "varname");
|
c.unreadVariableError(0, "varname");
|
||||||
c.unassignedVariableError(0, "varname");
|
c.unassignedVariableError(0, "varname");
|
||||||
|
c.catchExceptionByValueError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name() const
|
std::string name() const
|
||||||
|
@ -254,6 +260,7 @@ public:
|
||||||
"* look for calculations inside sizeof()\n"
|
"* look for calculations inside sizeof()\n"
|
||||||
"* assignment of a variable to itself\n"
|
"* assignment of a variable to itself\n"
|
||||||
"* mutual exclusion over || always evaluating to true\n"
|
"* mutual exclusion over || always evaluating to true\n"
|
||||||
|
"* exception caught by value instead of by reference\n"
|
||||||
|
|
||||||
// optimisations
|
// optimisations
|
||||||
"* optimisation: detect post increment/decrement\n";
|
"* optimisation: detect post increment/decrement\n";
|
||||||
|
|
|
@ -93,6 +93,7 @@ private:
|
||||||
|
|
||||||
TEST_CASE(assignmentInAssert);
|
TEST_CASE(assignmentInAssert);
|
||||||
TEST_CASE(incorrectLogicOperator);
|
TEST_CASE(incorrectLogicOperator);
|
||||||
|
TEST_CASE(catchExceptionByValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[], const char *filename = NULL)
|
void check(const char code[], const char *filename = NULL)
|
||||||
|
@ -125,6 +126,7 @@ private:
|
||||||
checkOther.invalidScanf();
|
checkOther.invalidScanf();
|
||||||
checkOther.checkMisusedScopedObject();
|
checkOther.checkMisusedScopedObject();
|
||||||
checkOther.checkIncorrectLogicOperator();
|
checkOther.checkIncorrectLogicOperator();
|
||||||
|
checkOther.checkCatchExceptionByValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1518,6 +1520,100 @@ private:
|
||||||
);
|
);
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void catchExceptionByValue()
|
||||||
|
{
|
||||||
|
check("void f() {\n"
|
||||||
|
" try\n"
|
||||||
|
" {\n"
|
||||||
|
" foo();\n"
|
||||||
|
" }\n"
|
||||||
|
" catch( ::std::exception err)\n"
|
||||||
|
" {\n"
|
||||||
|
" throw err;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
ASSERT_EQUALS("[test.cpp:6]: (style) Exception should be caught by reference.\n", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" try\n"
|
||||||
|
" {\n"
|
||||||
|
" foo();\n"
|
||||||
|
" }\n"
|
||||||
|
" catch(const exception err)\n"
|
||||||
|
" {\n"
|
||||||
|
" throw err;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
ASSERT_EQUALS("[test.cpp:6]: (style) Exception should be caught by reference.\n", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" try\n"
|
||||||
|
" {\n"
|
||||||
|
" foo();\n"
|
||||||
|
" }\n"
|
||||||
|
" catch( ::std::exception& err)\n"
|
||||||
|
" {\n"
|
||||||
|
" throw err;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" try\n"
|
||||||
|
" {\n"
|
||||||
|
" foo();\n"
|
||||||
|
" }\n"
|
||||||
|
" catch(exception* err)\n"
|
||||||
|
" {\n"
|
||||||
|
" throw err;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" try\n"
|
||||||
|
" {\n"
|
||||||
|
" foo();\n"
|
||||||
|
" }\n"
|
||||||
|
" catch(const exception& err)\n"
|
||||||
|
" {\n"
|
||||||
|
" throw err;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" try\n"
|
||||||
|
" {\n"
|
||||||
|
" foo();\n"
|
||||||
|
" }\n"
|
||||||
|
" catch(int err)\n"
|
||||||
|
" {\n"
|
||||||
|
" throw err;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" try\n"
|
||||||
|
" {\n"
|
||||||
|
" foo();\n"
|
||||||
|
" }\n"
|
||||||
|
" catch(exception* const err)\n"
|
||||||
|
" {\n"
|
||||||
|
" throw err;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestOther)
|
REGISTER_TEST(TestOther)
|
||||||
|
|
Loading…
Reference in New Issue