diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 739c4cc7c..fcd7ddb40 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -664,6 +664,29 @@ void CheckOther::switchCaseFallThrough(const Token *tok) "switchCaseFallThrough", "Switch falls through case without comment"); } +//--------------------------------------------------------------------------- +// std::cout << std::cout; +//--------------------------------------------------------------------------- +void CheckOther::checkCoutCerrMisusage() +{ + bool firstCout = false; + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { + if (Token::Match(tok, "std :: cout|cerr")) { + if (firstCout && tok->strAt(-1) == "<<" && tok->strAt(3) != ".") { + coutCerrMisusageError(tok, tok->strAt(2)); + firstCout = false; + } else if (tok->strAt(3) == "<<") + firstCout = true; + } else if (firstCout && tok->str() == ";") + firstCout = false; + } +} + +void CheckOther::coutCerrMisusageError(const Token* tok, const std::string& streamName) +{ + reportError(tok, Severity::error, "coutCerrMisusage", "Invalid usage of output stream: '<< std::" + streamName + "'."); +} + //--------------------------------------------------------------------------- // int x = 1; // x = x; // <- redundant assignment to self diff --git a/lib/checkother.h b/lib/checkother.h index 2269473d0..5b248a6dd 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -89,6 +89,7 @@ public: checkOther.checkFflushOnInputStream(); checkOther.invalidScanf(); + checkOther.checkCoutCerrMisusage(); checkOther.checkIncorrectLogicOperator(); checkOther.checkMisusedScopedObject(); checkOther.checkCatchExceptionByValue(); @@ -171,6 +172,9 @@ public: /** @brief %Check for switch case fall through without comment */ void checkSwitchCaseFallThrough(); + /** @brief %Check for missusage of std::cout */ + void checkCoutCerrMisusage(); + /** @brief %Check for assigning a variable to itself*/ void checkSelfAssignment(); @@ -246,6 +250,7 @@ public: void variableScopeError(const Token *tok, const std::string &varname); void strPlusCharError(const Token *tok); void zerodivError(const Token *tok); + void coutCerrMisusageError(const Token* tok, const std::string& streamName); void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1); void fflushOnInputStreamError(const Token *tok, const std::string &varname); void redundantAssignmentInSwitchError(const Token *tok, const std::string &varname); @@ -289,6 +294,7 @@ public: c.misusedScopeObjectError(NULL, "varname"); c.sizeofForArrayParameterError(0); c.sizeofForNumericParameterError(0); + c.coutCerrMisusageError(0, "cout"); // style/warning c.cstyleCastError(0); @@ -345,6 +351,7 @@ public: "* sizeof for array given as function argument\n" "* sizeof for numeric given as function argument\n" "* incorrect length arguments for 'substr' and 'strncmp'\n" + "* invalid usage of output stream. For example: std::cout << std::cout;'\n" // style "* C-style pointer cast in cpp file\n" diff --git a/test/testother.cpp b/test/testother.cpp index e35a0e959..338b48dbf 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -81,6 +81,8 @@ private: TEST_CASE(switchFallThroughCase); TEST_CASE(duplicateBreak); + TEST_CASE(coutCerrMisusage); + TEST_CASE(selfAssignment); TEST_CASE(testScanf1); TEST_CASE(testScanf2); @@ -180,6 +182,7 @@ private: checkOther.checkFflushOnInputStream(); checkOther.checkSelfAssignment(); checkOther.invalidScanf(); + checkOther.checkCoutCerrMisusage(); checkOther.checkMisusedScopedObject(); checkOther.checkIncorrectLogicOperator(); checkOther.checkCatchExceptionByValue(); @@ -1286,15 +1289,15 @@ private: check("void foo(char *str, int a)\n" "{\n" - " int z = 0;\n" + " int z = 0;\n" " switch (a)\n" " {\n" " case 2:\n" " strcpy(str, \"a'\");\n" - " z++;\n" + " z++;\n" " case 3:\n" " strcpy(str, \"b'\");\n" - " z++;\n" + " z++;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:7]: (warning) Switch case fall-through. Redundant strcpy of \"str\".\n", errout.str()); @@ -1305,10 +1308,10 @@ private: " {\n" " case 2:\n" " strcpy(str, \"a'\");\n" - " break;\n" + " break;\n" " case 3:\n" " strcpy(str, \"b'\");\n" - " break;\n" + " break;\n" " }\n" "}\n"); ASSERT_EQUALS("", errout.str()); @@ -1319,7 +1322,7 @@ private: " {\n" " case 2:\n" " strcpy(str, \"a'\");\n" - " printf(str);\n" + " printf(str);\n" " case 3:\n" " strcpy(str, \"b'\");\n" " }\n" @@ -3747,6 +3750,39 @@ private: "}"); ASSERT_EQUALS("", errout.str()); } + + void coutCerrMisusage() { + check( + "void foo() {\n" + " std::cout << std::cout;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (error) Invalid usage of output stream: '<< std::cout'.\n", errout.str()); + + check( + "void foo() {\n" + " std::cout << \"xyz\" << std::cout;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (error) Invalid usage of output stream: '<< std::cout'.\n", errout.str()); + + check( + "void foo(int i) {\n" + " std::cout << i << std::cerr;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (error) Invalid usage of output stream: '<< std::cerr'.\n", errout.str()); + + check( + "void foo() {\n" + " std::cout << \"xyz\";\n" + " std::cout << \"xyz\";\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check( + "void foo() {\n" + " std::cout << std::cout.good();\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestOther)