diff --git a/lib/checkio.cpp b/lib/checkio.cpp index 111a22383..81e6b41d6 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -407,6 +407,7 @@ void CheckIO::checkWrongPrintfScanfArguments() { const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); bool warning = _settings->isEnabled("warning"); + bool windows = _settings->isWindowsPlatform(); std::size_t functions = symbolDatabase->functionScopes.size(); for (std::size_t j = 0; j < functions; ++j) { @@ -437,7 +438,11 @@ void CheckIO::checkWrongPrintfScanfArguments() if (!formatString.empty()) { /* formatstring found in library */ - } else if (Token::Match(tok, "printf|scanf|wprintf|wscanf ( %str%")) { + } else if (Token::Match(tok, "printf|scanf|wprintf|wscanf ( %str%") || + (windows && (Token::Match(tok, "Format|AppendFormat ( %str%") && + Token::Match(tok->tokAt(-2), "%var% .") && tok->tokAt(-2)->variable() && + tok->tokAt(-2)->variable()->typeStartToken()->str() == "CString"))) { + formatString = tok->strAt(2); if (tok->strAt(3) == ",") { argListTok = tok->tokAt(4); diff --git a/lib/settings.h b/lib/settings.h index b6a7efc2b..23d02651e 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -240,6 +240,16 @@ public: /** set the platform type for user specified platforms */ bool platformFile(const std::string &filename); + + /** + * @brief Returns true if platform type is Windows + * @return true if Windows platform type. + */ + bool isWindowsPlatform() const { + return platformType == Win32A || + platformType == Win32W || + platformType == Win64; + } }; /// @} diff --git a/test/testio.cpp b/test/testio.cpp index 1a880ae1c..6eb5091c0 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -49,6 +49,7 @@ private: TEST_CASE(testPosixPrintfScanfParameterPosition); // #4900 TEST_CASE(testMicrosoftPrintfArgument); // ticket #4902 + TEST_CASE(testMicrosoftCStringFormatArguments); // ticket #4920 TEST_CASE(testlibrarycfg); // library configuration } @@ -2132,6 +2133,33 @@ private: "[test.cpp:17]: (warning) 'I64' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n", errout.str()); } + void testMicrosoftCStringFormatArguments() { // ticket #4920 + check("void foo() {\n" + " unsigned __int32 u32;\n" + " String string;\n" + " string.Format(\"%I32d\", u32);\n" + " string.AppendFormat(\"%I32d\", u32);\n" + "}", false, false, Settings::Win32A); + ASSERT_EQUALS("", errout.str()); + + check("void foo() {\n" + " unsigned __int32 u32;\n" + " CString string;\n" + " string.Format(\"%I32d\", u32);\n" + " string.AppendFormat(\"%I32d\", u32);\n" + "}", false, false, Settings::Unix32); + ASSERT_EQUALS("", errout.str()); + + check("void foo() {\n" + " unsigned __int32 u32;\n" + " CString string;\n" + " string.Format(\"%I32d\", u32);\n" + " string.AppendFormat(\"%I32d\", u32);\n" + "}", false, false, Settings::Win32A); + ASSERT_EQUALS("[test.cpp:4]: (warning) %I32d in format string (no. 1) requires a signed integer but the argument type is 'unsigned __int32 {aka unsigned int}'.\n" + "[test.cpp:5]: (warning) %I32d in format string (no. 1) requires a signed integer but the argument type is 'unsigned __int32 {aka unsigned int}'.\n", errout.str()); + } + void testlibrarycfg() { const char code[] = "void f() {\n" " format(\"%s\");\n"