@@ -1959,6 +1959,53 @@ static bool isLocal(const Token *tok)
19591959 return var && !var->isStatic () && var->isLocal ();
19601960}
19611961
1962+ static bool isc_strCall (const Token* tok, const Library::Container* container)
1963+ {
1964+ if (!Token::simpleMatch (tok, " (" ))
1965+ return false ;
1966+ const Token* dot = tok->astOperand1 ();
1967+ if (!Token::simpleMatch (dot, " ." ))
1968+ return false ;
1969+ const Token* obj = dot->astOperand1 ();
1970+ if (!obj || !obj->valueType ())
1971+ return false ;
1972+ const Library::Container* objContainer = obj->valueType ()->container ;
1973+ if (!objContainer || !container || !objContainer->stdStringLike || (objContainer != container && !container->view ))
1974+ return false ;
1975+ return Token::Match (dot->astOperand2 (), " c_str|data ( )" );
1976+ }
1977+
1978+ static bool isc_strConcat (const Token* tok)
1979+ {
1980+ if (!tok->isBinaryOp () || !Token::simpleMatch (tok, " +" ))
1981+ return false ;
1982+ for (const Token* op : { tok->astOperand1 (), tok->astOperand2 () }) { // NOLINT(readability-use-anyofallof)
1983+ const Token* sibling = op->astSibling ();
1984+ if (!sibling->valueType ())
1985+ continue ;
1986+ if (isc_strCall (op, sibling->valueType ()->container ))
1987+ return true ;
1988+ }
1989+ return false ;
1990+ }
1991+
1992+ static bool isc_strAssignment (const Token* tok)
1993+ {
1994+ if (!Token::simpleMatch (tok, " =" ))
1995+ return false ;
1996+ const Token* strTok = tok->astOperand1 ();
1997+ if (!strTok || !strTok->valueType ())
1998+ return false ;
1999+ return isc_strCall (tok->astOperand2 (), strTok->valueType ()->container );
2000+ }
2001+
2002+ static bool isc_strConstructor (const Token* tok)
2003+ {
2004+ if (!tok->valueType () || !Token::Match (tok, " %var% (|{" ))
2005+ return false ;
2006+ return isc_strCall (tok->tokAt (1 )->astOperand2 (), tok->valueType ()->container );
2007+ }
2008+
19622009namespace {
19632010 const std::set<std::string> stl_string_stream = {
19642011 " istringstream" , " ostringstream" , " stringstream" , " wstringstream"
@@ -2027,16 +2074,14 @@ void CheckStl::string_c_str()
20272074 const Variable* var2 = tok->tokAt (2 )->variable ();
20282075 if (var->isPointer () && var2 && var2->isStlType (stl_string_stream))
20292076 string_c_strError (tok);
2077+ } else if (printPerformance && isc_strAssignment (tok->tokAt (1 ))) {
2078+ string_c_strAssignment (tok, tok->variable ()->getTypeName ());
20302079 } else if (Token::Match (tok->tokAt (2 ), " %name% (" ) &&
20312080 Token::Match (tok->linkAt (3 ), " ) . c_str|data ( ) ;" ) &&
20322081 tok->tokAt (2 )->function () && Token::Match (tok->tokAt (2 )->function ()->retDef , " std :: string|wstring %name%" )) {
20332082 const Variable* var = tok->variable ();
20342083 if (var->isPointer ())
20352084 string_c_strError (tok);
2036- } else if (printPerformance && tok->tokAt (1 )->astOperand2 () && Token::Match (tok->tokAt (1 )->astOperand2 ()->tokAt (-3 ), " %var% . c_str|data ( ) ;" )) {
2037- const Token* vartok = tok->tokAt (1 )->astOperand2 ()->tokAt (-3 );
2038- if ((tok->variable ()->isStlStringType () || tok->variable ()->isStlStringViewType ()) && vartok->variable () && vartok->variable ()->isStlStringType ())
2039- string_c_strAssignment (tok, tok->variable ()->getTypeName ());
20402085 }
20412086 } else if (printPerformance && tok->function () && Token::Match (tok, " %name% ( !!)" ) && tok->str () != scope.className ) {
20422087 const auto range = c_strFuncParam.equal_range (tok->function ());
@@ -2068,13 +2113,9 @@ void CheckStl::string_c_str()
20682113 }
20692114 }
20702115 }
2071- } else if (printPerformance && Token::Match (tok, " %var% (|{ %var% . c_str|data ( ) !!," ) &&
2072- tok->variable () && (tok->variable ()->isStlStringType () || tok->variable ()->isStlStringViewType ()) &&
2073- tok->tokAt (2 )->variable () && tok->tokAt (2 )->variable ()->isStlStringType ()) {
2116+ } else if (printPerformance && isc_strConstructor (tok)) {
20742117 string_c_strConstructor (tok, tok->variable ()->getTypeName ());
2075- } else if (printPerformance && tok->next () && tok->next ()->variable () && tok->next ()->variable ()->isStlStringType () && tok->valueType () && tok->valueType ()->type == ValueType::CONTAINER &&
2076- ((Token::Match (tok->previous (), " %var% + %var% . c_str|data ( )" ) && tok->previous ()->variable () && tok->previous ()->variable ()->isStlStringType ()) ||
2077- (Token::Match (tok->tokAt (-5 ), " %var% . c_str|data ( ) + %var%" ) && tok->tokAt (-5 )->variable () && tok->tokAt (-5 )->variable ()->isStlStringType ()))) {
2118+ } else if (printPerformance && isc_strConcat (tok)) {
20782119 string_c_strConcat (tok);
20792120 } else if (printPerformance && Token::simpleMatch (tok, " <<" ) && tok->astOperand2 () && Token::Match (tok->astOperand2 ()->astOperand1 (), " . c_str|data ( )" )) {
20802121 const Token* str = tok->astOperand2 ()->astOperand1 ()->astOperand1 ();
0 commit comments