| 2024 | } |
| 2025 | |
| 2026 | void CheckStlImpl::string_c_str() |
| 2027 | { |
| 2028 | const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); |
| 2029 | const bool printPerformance = mSettings.severity.isEnabled(Severity::performance); |
| 2030 | |
| 2031 | const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); |
| 2032 | |
| 2033 | logChecker("CheckStl::string_c_str"); |
| 2034 | |
| 2035 | // Find all functions that take std::string as argument |
| 2036 | struct StrArg { |
| 2037 | nonneg int n; |
| 2038 | std::string argtype; |
| 2039 | }; |
| 2040 | std::multimap<const Function*, StrArg> c_strFuncParam; |
| 2041 | if (printPerformance) { |
| 2042 | for (const Scope &scope : symbolDatabase->scopeList) { |
| 2043 | for (const Function &func : scope.functionList) { |
| 2044 | nonneg int numpar = 0; |
| 2045 | for (const Variable &var : func.argumentList) { |
| 2046 | numpar++; |
| 2047 | if ((var.isStlStringType() || var.isStlStringViewType()) && (!var.isReference() || var.isConst())) |
| 2048 | c_strFuncParam.emplace(&func, StrArg{ numpar, var.getTypeName() }); |
| 2049 | } |
| 2050 | } |
| 2051 | } |
| 2052 | } |
| 2053 | |
| 2054 | auto isString = [](const Token* str) -> bool { |
| 2055 | while (Token::Match(str, "::|.")) |
| 2056 | str = str->astOperand2(); |
| 2057 | if (Token::Match(str, "(|[") && !(str->valueType() && str->valueType()->type == ValueType::ITERATOR)) |
| 2058 | str = str->previous(); |
| 2059 | return str && ((str->variable() && str->variable()->isStlStringType()) || // variable |
| 2060 | (str->function() && isStlStringType(str->function()->retDef)) || // function returning string |
| 2061 | (str->valueType() && str->valueType()->type == ValueType::ITERATOR && isStlStringType(str->valueType()->containerTypeToken))); // iterator pointing to string |
| 2062 | }; |
| 2063 | |
| 2064 | // Try to detect common problems when using string::c_str() |
| 2065 | for (const Scope &scope : symbolDatabase->scopeList) { |
| 2066 | if (scope.type != ScopeType::eFunction || !scope.function) |
| 2067 | continue; |
| 2068 | |
| 2069 | enum : std::uint8_t {charPtr, stdString, stdStringConstRef, Other} returnType = Other; |
| 2070 | if (Token::Match(scope.function->tokenDef->tokAt(-2), "char|wchar_t *")) |
| 2071 | returnType = charPtr; |
| 2072 | else if (Token::Match(scope.function->tokenDef->tokAt(-5), "const std :: string|wstring &")) |
| 2073 | returnType = stdStringConstRef; |
| 2074 | else if (Token::Match(scope.function->tokenDef->tokAt(-3), "std :: string|wstring !!&")) |
| 2075 | returnType = stdString; |
| 2076 | |
| 2077 | for (const Token *tok = scope.bodyStart; tok && tok != scope.bodyEnd; tok = tok->next()) { |
| 2078 | // Invalid usage.. |
| 2079 | if (Token::Match(tok, "throw %var% . c_str|data ( ) ;") && isLocal(tok->next()) && |
| 2080 | tok->next()->variable() && tok->next()->variable()->isStlStringType()) { |
| 2081 | string_c_strThrowError(tok); |
| 2082 | } else if (tok->variable() && tok->strAt(1) == "=") { |
| 2083 | if (Token::Match(tok->tokAt(2), "%var% . str ( ) . c_str|data ( ) ;")) { |
no test coverage detected