diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index a8e6c435e..178482a66 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1936,6 +1936,14 @@ void CheckStl::string_c_str() } } + auto isString = [](const Token* str) -> bool { + if (Token::Match(str, "(|[") && !(str->valueType() && str->valueType()->type == ValueType::ITERATOR)) + str = str->previous(); + return str && ((str->variable() && str->variable()->isStlStringType()) || // variable + (str->function() && isStlStringType(str->function()->retDef)) || // function returning string + (str->valueType() && str->valueType()->type == ValueType::ITERATOR && isStlStringType(str->valueType()->containerTypeToken))); // iterator pointing to string + }; + // Try to detect common problems when using string::c_str() for (const Scope &scope : symbolDatabase->scopeList) { if (scope.type != Scope::eFunction || !scope.function) @@ -1991,16 +1999,13 @@ void CheckStl::string_c_str() else break; if (tok2 && Token::Match(tok2->tokAt(-4), ". c_str|data ( )")) { - const Variable* var = tok2->tokAt(-5)->variable(); - if (var && (var->isStlStringType() || - (var->valueType() && var->valueType()->type == ValueType::ITERATOR && isStlStringType(var->valueType()->containerTypeToken)))) { + if (isString(tok2->tokAt(-4)->astOperand1())) { string_c_strParam(tok, i->second); } else if (Token::Match(tok2->tokAt(-9), "%name% . str ( )")) { // Check ss.str().c_str() as parameter const Variable* ssVar = tok2->tokAt(-9)->variable(); if (ssVar && ssVar->isStlType(stl_string_stream)) string_c_strParam(tok, i->second); } - } } } else if (printPerformance && Token::Match(tok, "%var% (|{ %var% . c_str|data ( )") && @@ -2010,13 +2015,9 @@ void CheckStl::string_c_str() ((Token::Match(tok->previous(), "%var% + %var% . c_str|data ( )") && tok->previous()->variable() && tok->previous()->variable()->isStlStringType()) || (Token::Match(tok->tokAt(-5), "%var% . c_str|data ( ) + %var%") && tok->tokAt(-5)->variable() && tok->tokAt(-5)->variable()->isStlStringType()))) { string_c_strConcat(tok); - } else if (printPerformance && Token::simpleMatch(tok, "<<") && tok->astOperand2() && Token::simpleMatch(tok->astOperand2()->astOperand1(), ". c_str ( )")) { + } else if (printPerformance && Token::simpleMatch(tok, "<<") && tok->astOperand2() && Token::Match(tok->astOperand2()->astOperand1(), ". c_str|data ( )")) { const Token* str = tok->astOperand2()->astOperand1()->astOperand1(); - if (Token::Match(str, "(|[") && !(str->valueType() && str->valueType()->type == ValueType::ITERATOR)) - str = str->previous(); - if (str && ((str->variable() && str->variable()->isStlStringType()) || - (str->function() && isStlStringType(str->function()->retDef)) || - (str->valueType() && str->valueType()->type == ValueType::ITERATOR && isStlStringType(str->valueType()->containerTypeToken)))) { + if (isString(str)) { const Token* strm = tok; while (Token::simpleMatch(strm, "<<")) strm = strm->astOperand1(); diff --git a/test/teststl.cpp b/test/teststl.cpp index ecdf63077..06608de9c 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -3895,11 +3895,21 @@ private: errout.str()); check("void f(const std::string& s);\n" // #8336 - "void g(const std::vector& v) {\n" + "struct T {\n" + " std::string g();\n" + " std::string a[1];\n" + "};\n" + "void g(const std::vector& v, T& t) {\n" " for (std::vector::const_iterator it = v.begin(); it != v.end(); ++it)\n" " f(it->c_str());\n" + " f(v.begin()->c_str());\n" + " f(t.g().c_str());\n" + " f(t.a[0].c_str());\n" "}\n"); - ASSERT_EQUALS("[test.cpp:4]: (performance) Passing the result of c_str() to a function that takes std::string as argument no. 1 is slow and redundant.\n", + ASSERT_EQUALS("[test.cpp:8]: (performance) Passing the result of c_str() to a function that takes std::string as argument no. 1 is slow and redundant.\n" + "[test.cpp:9]: (performance) Passing the result of c_str() to a function that takes std::string as argument no. 1 is slow and redundant.\n" + "[test.cpp:10]: (performance) Passing the result of c_str() to a function that takes std::string as argument no. 1 is slow and redundant.\n" + "[test.cpp:11]: (performance) Passing the result of c_str() to a function that takes std::string as argument no. 1 is slow and redundant.\n", errout.str()); check("void svgFile(const std::string &content, const std::string &fileName, const double end = 1000., const double start = 0.);\n"