diff --git a/lib/checkinternal.cpp b/lib/checkinternal.cpp index 1a2b0ec84..cee93e6e8 100644 --- a/lib/checkinternal.cpp +++ b/lib/checkinternal.cpp @@ -283,6 +283,32 @@ void CheckInternal::checkRedundantNextPrevious() } } +void CheckInternal::checkExtraWhitespace() +{ + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { + if (!Token::simpleMatch(tok, "Token :: simpleMatch (") && + !Token::simpleMatch(tok, "Token :: findsimplematch (") && + !Token::simpleMatch(tok, "Token :: Match (") && + !Token::simpleMatch(tok, "Token :: findmatch (")) + continue; + + const std::string& funcname = tok->strAt(2); + + // Get pattern string + const Token *pattern_tok = tok->tokAt(4)->nextArgument(); + if (!pattern_tok || pattern_tok->type() != Token::eString) + continue; + + const std::string pattern = pattern_tok->strValue(); + if (!pattern.empty() && (pattern[0] == ' ' || *pattern.rbegin() == ' ')) + extraWhitespaceError(tok, pattern, funcname); + + // two whitespaces or more + if (pattern.find(" ") != std::string::npos) + extraWhitespaceError(tok, pattern, funcname); + } +} + void CheckInternal::multiComparePatternError(const Token* tok, const std::string& pattern, const std::string &funcname) { reportError(tok, Severity::error, "multiComparePatternError", @@ -329,4 +355,11 @@ void CheckInternal::orInComplexPattern(const Token* tok, const std::string& patt "Token::" + funcname + "() pattern \"" + pattern + "\" contains \"||\" or \"|\". Replace it by \"%oror%\" or \"%or%\"."); } +void CheckInternal::extraWhitespaceError(const Token* tok, const std::string& pattern, const std::string &funcname) +{ + reportError(tok, Severity::warning, "extraWhitespaceError", + "Found extra whitespace inside Token::" + funcname + "() call: \"" + pattern + "\"" + ); +} + #endif // #ifdef CHECK_INTERNAL diff --git a/lib/checkinternal.h b/lib/checkinternal.h index 77372665d..f6faf6d76 100644 --- a/lib/checkinternal.h +++ b/lib/checkinternal.h @@ -53,6 +53,7 @@ public: checkInternal.checkMissingPercentCharacter(); checkInternal.checkUnknownPattern(); checkInternal.checkRedundantNextPrevious(); + checkInternal.checkExtraWhitespace(); } /** @brief %Check if a simple pattern is used inside Token::Match or Token::findmatch */ @@ -70,6 +71,9 @@ public: /** @brief %Check for inefficient usage of Token::next(), Token::previous() and Token::tokAt() */ void checkRedundantNextPrevious(); + /** @brief %Check if there is whitespace at the beginning or at the end of a pattern */ + void checkExtraWhitespace(); + private: void multiComparePatternError(const Token *tok, const std::string &pattern, const std::string &funcname); void simplePatternError(const Token *tok, const std::string &pattern, const std::string &funcname); @@ -78,6 +82,7 @@ private: void unknownPatternError(const Token* tok, const std::string& pattern); void redundantNextPreviousError(const Token* tok, const std::string& func1, const std::string& func2); void orInComplexPattern(const Token *tok, const std::string &pattern, const std::string &funcname); + void extraWhitespaceError(const Token *tok, const std::string &pattern, const std::string &funcname); void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { CheckInternal c(0, settings, errorLogger); @@ -88,6 +93,7 @@ private: c.unknownPatternError(0, "%typ"); c.redundantNextPreviousError(0, "previous", "next"); c.orInComplexPattern(0, "||", "Match"); + c.extraWhitespaceError(0, "%str% ", "Match"); } static std::string myName() { diff --git a/test/testinternal.cpp b/test/testinternal.cpp index 07161beea..745f4a9a1 100644 --- a/test/testinternal.cpp +++ b/test/testinternal.cpp @@ -42,6 +42,7 @@ private: TEST_CASE(internalError) TEST_CASE(invalidMultiCompare); TEST_CASE(orInComplexPattern); + TEST_CASE(extraWhitespace); } void check(const char code[]) { @@ -375,6 +376,50 @@ private: "}"); ASSERT_EQUALS("", errout.str()); } + + void extraWhitespace() { + // whitespace at the end + check("void f() {\n" + " const Token *tok;\n" + " Token::Match(tok, \"%str% \");\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (warning) Found extra whitespace inside Token::Match() call: \"%str% \"\n", errout.str()); + + // whitespace at the begin + check("void f() {\n" + " const Token *tok;\n" + " Token::Match(tok, \" %str%\");\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (warning) Found extra whitespace inside Token::Match() call: \" %str%\"\n", errout.str()); + + // two whitespaces or more + check("void f() {\n" + " const Token *tok;\n" + " Token::Match(tok, \"%str% bar\");\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (warning) Found extra whitespace inside Token::Match() call: \"%str% bar\"\n", errout.str()); + + // test simpleMatch + check("void f() {\n" + " const Token *tok;\n" + " Token::simpleMatch(tok, \"foobar \");\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (warning) Found extra whitespace inside Token::simpleMatch() call: \"foobar \"\n", errout.str()); + + // test findmatch + check("void f() {\n" + " const Token *tok;\n" + " Token::findmatch(tok, \"%str% \");\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (warning) Found extra whitespace inside Token::findmatch() call: \"%str% \"\n", errout.str()); + + // test findsimplematch + check("void f() {\n" + " const Token *tok;\n" + " Token::findsimplematch(tok, \"foobar \");\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (warning) Found extra whitespace inside Token::findsimplematch() call: \"foobar \"\n", errout.str()); + } }; REGISTER_TEST(TestInternal)