44 #include <unordered_map>
138 for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
143 const Token* accessTok = parent;
152 if (!value.isContainerSizeValue())
154 if (value.isImpossible())
160 if (value.intvalue == 0 && (indexTok ||
163 std::string indexExpr;
170 std::vector<ValueFlow::Value> indexValues =
172 if (!indexValues.empty()) {
182 if (!v.isSymbolicValue())
184 if (v.isImpossible())
188 const Token* sizeTok = v.tokvalue;
189 if (sizeTok && sizeTok->isCast())
190 sizeTok = sizeTok->astOperand2() ? sizeTok->astOperand2() : sizeTok->astOperand1();
191 const Token* containerTok = getContainerFromSize(container, sizeTok);
194 return containerTok->exprId() == tok->exprId();
207 return "at position " + std::to_string(indexValue.
intvalue) +
" from the beginning";
209 return "at position " + std::to_string(-indexValue.
intvalue) +
" from the end";
210 std::string indexString = std::to_string(indexValue.
intvalue);
212 indexString = containerName +
".size()";
214 indexString +=
"+" + std::to_string(indexValue.
intvalue);
217 return "greater or equal to " + indexString;
227 const std::string expression = tok ? tok->
expressionString() : (containerName+
"[x]");
230 if (!containerSize) {
233 "' can have the value " +
indexValueString(*indexValue, containerName) +
". Expression '" +
234 expression +
"' causes access out of bounds.";
236 errmsg =
"Out of bounds access in expression '" + expression +
"'";
237 }
else if (containerSize->
intvalue == 0) {
241 errmsg =
"Out of bounds access in expression '" + expression +
"' because '$symbol' is empty and '" + index +
"' may be non-zero.";
243 errmsg =
"Out of bounds access in expression '" + expression +
"' because '$symbol' is empty.";
244 }
else if (indexValue) {
250 errmsg =
"Out of bounds access in '" + expression +
"', if '$symbol' size is " + std::to_string(containerSize->
intvalue) +
" and '" + index +
"' is " +
indexValueString(*indexValue);
258 errorPath =
getErrorPath(tok, containerSize,
"Access out of bounds");
262 if (errorPath1.size() <= 1)
263 errorPath = std::move(errorPath2);
264 else if (errorPath2.size() <= 1)
265 errorPath = std::move(errorPath1);
267 errorPath = std::move(errorPath1);
268 errorPath.splice(errorPath.end(), errorPath2);
274 "containerOutOfBounds",
275 "$symbol:" + containerName +
"\n" + errmsg,
297 if (expr->
str() ==
"*") {
307 if (expr->
str() ==
"+") {
322 logChecker(
"CheckStl::outOfBoundsIndexExpression");
324 for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
325 if (!tok->isName() || !tok->valueType())
342 const std::string varname = tok ? tok->
str() : std::string(
"var");
343 const std::string i = index ? index->
expressionString() : std::string(varname +
".size()");
345 std::string errmsg =
"Out of bounds access of $symbol, index '" + i +
"' is out of bounds.";
349 "containerOutOfBoundsIndexExpression",
350 "$symbol:" + varname +
"\n" + errmsg,
366 "$symbol:" + containerName1 +
"\n"
367 "$symbol:" + containerName2 +
"\n"
368 "Same iterator is used with different containers '" + containerName1 +
"' and '" + containerName2 +
"'.",
CWE664,
Certainty::normal);
373 std::list<const Token*> callstack = { tok, containerTok };
375 "$symbol:" + containerName1 +
"\n"
376 "$symbol:" + containerName2 +
"\n"
377 "Same iterator is used with different containers '" + containerName1 +
"' and '" + containerName2 +
"'.",
CWE664,
Certainty::normal);
382 std::list<const Token*> callstack = { tok, containerTok };
386 "$symbol:" + containerName +
388 "Same iterator is used with containers '$symbol' that are temporaries or defined in different scopes.",
397 std::list<const Token*> callstack = { deref, erased };
399 "$symbol:" + itername +
"\n"
400 "Iterator '$symbol' used after element has been erased.\n"
401 "The iterator '$symbol' is invalid after the element it pointed to has been erased. "
405 "$symbol:" + itername +
"\n"
406 "Invalid iterator '$symbol' used.\n"
407 "The iterator '$symbol' is invalid before being assigned. "
425 inconclusiveType =
false;
433 if (!end || end->
argCount() > 0 || !incOperator)
436 inconclusiveType =
true;
445 return std::string();
446 std::string ret(containerToken->
str());
447 for (
const Token *nametok = containerToken; nametok; nametok = nametok->
tokAt(-2)) {
450 ret = nametok->strAt(-2) +
'.' + ret;
471 std::map<int, const Token*> iteratorScopeBeginInfo;
473 bool inconclusiveType=
false;
476 const int iteratorId = var->declarationId();
478 iteratorScopeBeginInfo[iteratorId] = var->nameToken();
482 bool inconclusiveType=
false;
488 const int iteratorId = var->declarationId();
491 bool validIterator =
Token::Match(var->nameToken()->next(),
"[(=:{]");
492 const Scope* invalidationScope =
nullptr;
495 const Token* containerToken =
nullptr;
496 const Scope* containerAssignScope =
nullptr;
499 const Token* validatingToken =
nullptr;
501 const Token* eraseToken =
nullptr;
505 for (
const Token *tok2 = var->nameToken(); tok2 && tok2 != var->
scope()->bodyEnd; tok2 = tok2->next()) {
506 if (invalidationScope && tok2 == invalidationScope->
bodyEnd)
507 validIterator =
true;
508 if (containerAssignScope && tok2 == containerAssignScope->
bodyEnd)
509 containerToken =
nullptr;
511 if (tok2 == validatingToken) {
512 validIterator =
true;
513 eraseToken =
nullptr;
514 invalidationScope =
nullptr;
518 if (
Token::Match(tok2,
"%name% . insert|erase ( *| %varid% )|,", iteratorId) && !
isVector(tok2)) {
520 if (itTok->
str() ==
"*") {
521 if (tok2->strAt(2) ==
"insert")
524 itTok = itTok->
next();
532 if (containerToken && tok2->
varId() != containerToken->
varId()) {
534 const Variable *variableInfo = tok2->variable();
545 if (tok2->strAt(2) ==
"insert") {
549 while (par2->
str() !=
")") {
552 bool inconclusiveType2=
false;
555 if (par2->
str() ==
"(")
559 if (par2->
str() !=
")")
564 if (containerToken && containerToken->
variable() && containerToken->
variable()->isReference()) {
565 const Token *nameToken = containerToken->
variable()->nameToken();
568 const Token *name2 = tok2;
570 name1 = name1->
next();
571 name2 = name2->
next();
583 else if (tok2->strAt(2) ==
"erase" && (tok2->strAt(4) !=
"*" || (containerToken && tok2->
varId() == containerToken->
varId()))) {
584 validIterator =
false;
586 invalidationScope = tok2->scope();
590 tok2 = itTok->
next();
595 else if (
Token::Match(tok2,
"%varid% = %name% .", iteratorId) &&
599 tok2 = validatingToken->
link();
603 else if (
Token::Match(tok2,
"%varid% = %name% .", iteratorId) &&
608 containerToken =
nullptr;
609 containerAssignScope = tok2->scope();
612 tok2 = validatingToken->
link();
621 else if (
Token::Match(tok2,
"%varid% ,|)", iteratorId)) {
622 validIterator =
true;
626 else if (!validIterator &&
Token::Match(tok2,
"* %varid%", iteratorId)) {
629 }
else if (!validIterator &&
Token::Match(tok2,
"%varid% . %name%", iteratorId)) {
631 tok2 = tok2->tokAt(2);
636 else if (tok2->scope() == invalidationScope &&
Token::Match(tok2,
"return|break|continue")) {
642 else if (tok2->str() ==
"else") {
643 validIterator =
true;
651 const std::string container(containerTok ? containerTok->
expressionString() : std::string(
"v1"));
652 const std::string container2(containerTok2 ? containerTok2->
expressionString() : std::string(
"v2"));
653 const std::string iter(iterTok ? iterTok->
expressionString() : std::string(
"it"));
656 "mismatchingContainerIterator",
657 "Iterator '" + iter +
"' referring to container '" + container2 +
"' is used with container '" + container +
"'.",
665 const std::string expr1(tok1 ? tok1->
expressionString() : std::string(
"v1"));
666 const std::string expr2(tok2 ? tok2->
expressionString() : std::string(
"v2"));
669 "mismatchingContainers",
670 "Iterators of different containers '" + expr1 +
"' and '" + expr2 +
"' are used together.",
677 const std::string expr1(tok1 ? tok1->
expressionString() : std::string(
"v1"));
678 const std::string expr2(tok2 ? tok2->
expressionString() : std::string(
"v2"));
680 "Iterators to containers from different expressions '" +
696 std::vector<const Token*> res;
697 for (
const auto& v : values) {
699 res.emplace_back(v.tokvalue);
702 res.emplace_back(tok);
719 return std::any_of(address1.begin(), address1.end(), [&](
const Token* tok1) {
720 return std::any_of(address2.begin(), address2.end(), [&](const Token* tok2) {
721 return isSameExpression(false, tok1, tok2, settings, false, false);
730 auto findIterVal = [](
const std::vector<ValueFlow::Value>& values,
const std::vector<ValueFlow::Value>::const_iterator beg) {
732 return v.lifetimeKind == ValueFlow::Value::LifetimeKind::Iterator;
736 auto it = findIterVal(values, values.begin());
737 if (it != values.end()) {
738 auto it2 = findIterVal(values, it + 1);
739 if (it2 == values.cend())
742 if (values.size() == 1)
743 return values.front();
789 struct ArgIteratorInfo {
797 logChecker(
"CheckStl::misMatchingContainers");
809 const Token *
const ftok = tok;
811 const std::vector<const Token *> args =
getArguments(ftok);
816 std::map<int, std::vector<ArgIteratorInfo>> containers;
817 for (
int argnr = 1; argnr <= args.size(); ++argnr) {
821 const Token *
const argTok = args[argnr - 1];
822 containers[i->
container].emplace_back(ArgIteratorInfo{argTok, i});
827 for (
const auto& p : containers)
829 const std::vector<ArgIteratorInfo>& cargs = p.second;
830 for (ArgIteratorInfo iter1 : cargs) {
831 for (ArgIteratorInfo iter2 : cargs) {
832 if (iter1.tok == iter2.tok)
834 if (iter1.info->first && iter2.info->last &&
846 if (var && var->isStlStringType() &&
Token::Match(var->nameToken(),
"%var% (") &&
847 Token::Match(var->nameToken()->tokAt(2),
"%name% . begin|cbegin|rbegin|crbegin ( ) , %name% . end|cend|rend|crend ( ) ,|)")) {
848 if (var->nameToken()->strAt(2) != var->nameToken()->strAt(8)) {
857 logChecker(
"CheckStl::misMatchingContainerIterator");
870 const std::vector<const Token *> args =
getArguments(ftok);
874 const Token* iterTok =
nullptr;
881 iterTok = args.front();
885 iterTok = args.front();
914 const Token* ftok =
nullptr;
921 if (c->unstableErase) {
925 if (c->unstableInsert) {
948 struct InvalidContainerAnalyzer {
955 std::unordered_map<int, Reference> expressions;
957 void add(
const std::vector<Reference>& refs) {
965 expressions.insert(std::make_pair(r.tok->exprId(), r));
968 std::vector<Reference> invalidTokens()
const {
969 std::vector<Reference> result;
970 std::transform(expressions.cbegin(), expressions.cend(), std::back_inserter(result),
SelectMapValues{});
974 std::unordered_map<const Function*, Info> invalidMethods;
976 std::vector<Info::Reference> invalidatesContainer(
const Token* tok)
const {
977 std::vector<Info::Reference> result;
984 auto it = invalidMethods.find(f);
985 if (it != invalidMethods.end()) {
986 std::vector<Info::Reference> refs = it->second.invalidTokens();
987 std::copy_if(refs.cbegin(), refs.cend(), std::back_inserter(result), [&](
const Info::Reference& r) {
988 const Variable* var = r.tok->variable();
991 if (dependsOnThis && !var->isLocal() && !var->isGlobal() && !var->isStatic())
993 if (!var->isArgument())
995 if (!var->isReference())
1001 r.errorPath.push_front(epi);
1003 const Variable* var = r.tok->variable();
1008 const Token* tok2 =
nullptr;
1009 if (n >= 0 && n < args.size())
1019 ep.emplace_front(ftok,
1021 "', iterators or references to the container's data may be invalid .");
1036 std::vector<Info::Reference> c = invalidatesContainer(tok);
1039 invalidMethods[f].add(c);
1066 if (!val.isLocalLifetimeValue())
1071 val.lifetimeKind)) {
1072 if (val.isInconclusive())
1077 errorPath->insert(errorPath->end(), val.errorPath.cbegin(), val.errorPath.cend());
1080 if (!val.tokvalue->variable())
1082 if (val.tokvalue->varId() !=
id)
1100 return parent->
next();
1109 InvalidContainerAnalyzer analyzer;
1110 analyzer.analyze(symbolDatabase);
1115 const Token* blockEnd = blockStart->
link();
1116 if (contTok->exprId() == 0)
1120 for (
const Token* tok2 = blockStart; tok2 != blockEnd; tok2 = tok2->
next()) {
1125 if (r.tok->exprId() != contTok->exprId())
1127 const Scope* s = tok2->scope();
1143 std::set<nonneg int> skipVarIds;
1166 if (skipVarIds.count(info.
tok->
varId()) > 0)
1171 skipVarIds.insert(info.
tok->
varId());
1176 bool addressOf = false;
1177 const Variable* var = ValueFlow::getLifetimeVariable(info.tok, ep, *mSettings, &addressOf);
1179 if (var && var->declarationId() == r.tok->varId() && !addressOf) {
1181 if (var->isArgument() ||
1182 (!var->isReference() && !var->isRValueReference() && !isVariableDecl(tok) &&
1183 reaches(var->nameToken(), tok, library, &ep))) {
1184 errorPath = std::move(ep);
1194 errorPath = std::move(ep);
1201 errorPath.insert(errorPath.end(), info.errorPath.cbegin(), info.errorPath.cend());
1202 errorPath.insert(errorPath.end(), r.errorPath.cbegin(), r.errorPath.cend());
1216 const std::string method = tok ? tok->
str() :
"erase";
1217 errorPath.emplace_back(loopTok,
"Iterating container here.");
1221 return epi.first == tok;
1224 const std::string msg =
"Calling '" + method +
"' while iterating the container is invalid.";
1225 errorPath.emplace_back(tok,
"");
1235 errorPath.emplace_back(tok,
"");
1242 std::string msg =
"Reference to " +
name;
1243 errorPath.emplace_back(tok,
"");
1260 const Token *condition =
nullptr;
1272 std::vector<const Token *> conds;
1275 [&](
const Token *cond) {
1279 conds.emplace_back(cond);
1283 for (
const Token *cond : conds) {
1284 const Token *vartok;
1285 const Token *containerToken;
1292 containerToken = cond->
next();
1308 const int numId = vartok->
varId();
1311 const int declarationId = containerToken->
varId();
1312 const std::string &containerName = containerToken->
str();
1315 if (tok3->varId() == declarationId) {
1316 tok3 = tok3->next();
1322 else if (
Token::Match(tok3,
". %name% ( %varid% )", numId)) {
1368 std::ostringstream errmsg;
1371 <<
", otherwise there is negative array index " << index.
intvalue <<
".";
1373 errmsg <<
"Array index " << index.
intvalue <<
" is out of bounds.";
1376 reportError(errorPath, severity,
"negativeContainerIndex", errmsg.str(),
CWE786, certainty);
1402 bool inconclusiveType=
false;
1406 if (tok->
str() !=
"(")
1416 int indentlevel = 0U;
1418 for (; tok2 != scope.
bodyEnd; tok2 = tok2->
next()) {
1419 if (tok2->
str() ==
"{") {
1423 if (tok2->
str() ==
"}") {
1424 if (indentlevel > 0U)
1436 if (indentlevel == 0U &&
Token::Match(tok2,
"break|return|goto"))
1472 "Dangerous comparison using operator< on iterator.\n"
1473 "Iterator compared with operator<. This is dangerous since the order of items in the "
1474 "container is not guaranteed. One should use operator!= instead to compare iterators.",
CWE664,
Certainty::normal);
1483 if (stdStringLike) {
1491 if (tok->
str() ==
".")
1502 if (!printWarning && !printPerformance)
1517 for (
const Token *tok = conditionStart; tok->
str() !=
"{"; tok = tok->
next()) {
1518 const Token* funcTok =
nullptr;
1526 funcTok = tok->
tokAt(2);
1538 if (tok->
variable()->isArrayOrPointer())
1544 tok2 = tok2->
next();
1550 container =
nullptr;
1562 else if (printPerformance && container->
stdStringLike && funcTok->
str() ==
"find")
1564 }
else if (printWarning &&
Token::Match(tok,
"std :: find|find_if (")) {
1579 "Inefficient usage of string::find() in condition; string::starts_with() could be faster.\n"
1580 "Either inefficient or wrong usage of string::find(). string::starts_with() will be faster if "
1581 "string::find's result is compared with 0, because it will not scan the whole "
1582 "string. If your intention is to check that there are no findings in the string, "
1651 const Token *icontainerTok =
nullptr;
1652 const Token *ikeyTok =
nullptr;
1653 const Token *ivalueTok =
nullptr;
1655 icontainerTok = top->
astOperand1()->astOperand1();
1660 icontainerTok = top->
astOperand1()->astOperand1();
1669 if (!ikeyTok || !icontainerTok)
1671 if (
isSameExpression(
true, containerTok, icontainerTok, settings,
true,
false) &&
1697 const Token *containerTok;
1698 const Token *keyTok;
1712 const Token *valueTok2 =
1728 std::string replaceExpr;
1734 replaceExpr =
" Instead of '" + tok->
astParent()->expressionString() +
"' consider using '" +
1735 tok->
astParent()->astOperand1()->astOperand1()->expressionString() +
1737 tok->
astParent()->astOperand1()->astOperand2()->expressionString() +
1774 const Token *varTok = tok;
1775 if (tok->
strAt(2) !=
"size")
1776 varTok = varTok->
tokAt(2);
1809 const std::string varname = tok ? tok->
str() : std::string(
"list");
1811 "$symbol:" + varname +
"\n"
1812 "Possible inefficient checking for '$symbol' emptiness.\n"
1813 "Checking for '$symbol' emptiness might be inefficient. "
1814 "Using $symbol.empty() instead of $symbol.size() can be faster. "
1815 "$symbol.size() can take linear time but $symbol.empty() is "
1833 if (!
Token::Match(tok,
"%name% . find ( %any% ) != %name% . end|rend|cend|crend ( ) ) { %name% . remove|erase ( %any% ) ;"))
1837 const Token *var1 = tok;
1844 if (var1->
str() == var2->
str() &&
1845 var2->
str() == var3->
str() &&
1846 any1->
str() == any2->
str()) {
1855 "Redundant checking of STL container element existence before removing it.\n"
1856 "Redundant checking of STL container element existence before removing it. "
1874 if (tok2->str() ==
";")
1877 if (!
Token::Match(tok2,
"%var% = %name% . begin|rbegin|cbegin|crbegin ( ) ; %name% != %name% . end|rend|cend|crend ( ) ; ++| %name% ++| ) {"))
1881 if (tok2->strAt(2) != tok2->strAt(10))
1884 const int iteratorId(tok2->varId());
1887 if (iteratorId == tok2->tokAt(10)->varId())
1891 if (!
Token::Match(tok2->tokAt(16),
"++ %varid% )", iteratorId) &&
1892 !
Token::Match(tok2->tokAt(16),
"%varid% ++ )", iteratorId)) {
1896 const Token *incrementToken =
nullptr;
1899 if (tok3->varId() == iteratorId) {
1900 if (
Token::Match(tok3,
"%varid% = %name% . insert ( ++| %varid% ++| ,", iteratorId)) {
1906 incrementToken = tok3;
1914 incrementToken =
nullptr;
1915 }
else if (tok3->str() ==
"break" || tok3->str() ==
"return")
1916 incrementToken =
nullptr;
1926 std::list<const Token*> callstack = { incrementToken1,incrementToken2 };
1928 std::ostringstream errmsg;
1929 errmsg <<
"Missing bounds check for extra iterator increment in loop.\n"
1930 <<
"The iterator incrementing is suspicious - it is incremented at line ";
1931 if (incrementToken1)
1932 errmsg << incrementToken1->
linenr();
1933 errmsg <<
" and then at line ";
1934 if (incrementToken2)
1935 errmsg << incrementToken2->
linenr();
1936 errmsg <<
". The loop might unintentionally skip an element in the container. "
1937 <<
"There is no comparison between these increments to prevent that the iterator is "
1938 <<
"incremented beyond the end.";
1951 const std::set<std::string> stl_string_stream = {
1952 "istringstream",
"ostringstream",
"stringstream",
"wstringstream"
1968 std::string argtype;
1970 std::multimap<const Function*, StrArg> c_strFuncParam;
1971 if (printPerformance) {
1978 c_strFuncParam.emplace(&func, StrArg{ numpar, var.
getTypeName() });
1984 auto isString = [](
const Token* str) ->
bool {
1986 str = str->astOperand2();
1988 str = str->previous();
1989 return str && ((str->variable() && str->variable()->isStlStringType()) ||
1999 enum {charPtr, stdString, stdStringConstRef, Other} returnType = Other;
2001 returnType = charPtr;
2003 returnType = stdStringConstRef;
2005 returnType = stdString;
2030 const auto range = c_strFuncParam.equal_range(tok->
function());
2031 for (std::multimap<const Function*, StrArg>::const_iterator i = range.first; i != range.second; ++i) {
2032 if (i->second.n == 0)
2037 for (j = 0; tok2 && j < i->second.n - 1; j++)
2043 if (!tok2 && j == i->second.n - 1)
2054 if (ssVar && ssVar->
isStlType(stl_string_stream))
2059 }
else if (printPerformance &&
Token::Match(tok,
"%var% (|{ %var% . c_str|data ( ) !!,") &&
2069 if (isString(str)) {
2070 const Token* strm = tok;
2079 else if ((returnType == charPtr || (printPerformance && (returnType == stdString || returnType == stdStringConstRef))) && tok->
str() ==
"return") {
2089 bool is_implicit_std_string = printInconclusive;
2091 for (
const Token *search_tok = tok2->
next(); search_tok != search_end; search_tok = search_tok->
next()) {
2093 search_tok->next()->variable() && search_tok->next()->variable()->isStlStringType()) {
2094 is_implicit_std_string =
true;
2097 if (
Token::Match(search_tok,
"+ std :: string|wstring (")) {
2098 is_implicit_std_string =
true;
2103 if (is_implicit_std_string)
2108 bool ptrOrRef =
false;
2110 const Function* lastFunc =
nullptr;
2111 bool funcStr =
false;
2114 bool refToNonLocal =
false;
2117 refToNonLocal =
true;
2121 ptrOrRef = refToNonLocal || (tok2->
variable() && (tok2->
variable()->isPointer() || tok2->
variable()->isSmartPointer()));
2128 tok2 = tok2->
tokAt(2);
2132 funcStr = tok2->
str() ==
"str";
2139 if ((local || returnType != charPtr) && lastVar && lastVar->
isStlStringType())
2141 else if (funcStr && lastVar && lastVar->
isStlType(stl_string_stream))
2148 if (returnType == charPtr)
2160 reportError(tok,
Severity::error,
"stlcstrthrow",
"Dangerous usage of c_str(). The value returned by c_str() is invalid after throwing exception.\n"
2161 "Dangerous usage of c_str(). The string is destroyed after the c_str() call so the thrown pointer is invalid.");
2166 reportError(tok,
Severity::error,
"stlcstr",
"Dangerous usage of c_str(). The value returned by c_str() is invalid after this call.\n"
2167 "Dangerous usage of c_str(). The c_str() return value is only valid until its string is deleted.",
CWE664,
Certainty::normal);
2173 "The conversion from const char* as returned by c_str() to std::string creates an unnecessary string copy. Solve that by directly returning the string.",
CWE704,
Certainty::normal);
2178 std::ostringstream oss;
2179 oss <<
"Passing the result of c_str() to a function that takes " << argtype <<
" as argument no. " << number <<
" is slow and redundant.\n"
2180 "The conversion from const char* as returned by c_str() to " << argtype <<
" creates an unnecessary string copy or length calculation. Solve that by directly passing the string.";
2186 std::string msg =
"Constructing a " + argtype +
" from the result of c_str() is slow and redundant.\n"
2187 "Constructing a " + argtype +
" from const char* requires a call to strlen(). Solve that by directly passing the string.";
2193 std::string msg =
"Assigning the result of c_str() to a " + argtype +
" is slow and redundant.\n"
2194 "Assigning a const char* to a " + argtype +
" requires a call to strlen(). Solve that by directly assigning the string.";
2200 std::string msg =
"Concatenating the result of c_str() and a std::string is slow and redundant.\n"
2201 "Concatenating a const char* with a std::string requires a call to strlen(). Solve that by directly concatenating the strings.";
2207 std::string msg =
"Passing the result of c_str() to a stream is slow and redundant.\n"
2208 "Passing a const char* to a stream requires a call to strlen(). Solve that by directly passing the string.";
2217 const std::set<std::string> stl_containers_with_empty_and_clear = {
2218 "deque",
"forward_list",
"list",
2219 "map",
"multimap",
"multiset",
"set",
"string",
2220 "unordered_map",
"unordered_multimap",
"unordered_multiset",
2221 "unordered_set",
"vector",
"wstring"
2230 if (!printPerformance && !printWarning)
2238 if (printWarning &&
Token::Match(tok,
"%var% . compare|find|rfind|find_first_not_of|find_first_of|find_last_not_of|find_last_of ( %name% [,)]") &&
2244 }
else if (printPerformance &&
Token::Match(tok,
"%var% . swap ( %name% )") &&
2252 const std::vector<const Token*> args =
getArguments(funcTok);
2254 !args.empty() && args[0]->hasKnownIntValue() && args[0]->getKnownIntValue() == 0) {
2256 }
else if (args.empty() || (args[0]->hasKnownIntValue() && args[0]->getKnownIntValue() == 0 &&
2259 }
else if (args.size() == 2 && args[1]->hasKnownIntValue() && args[1]->getKnownIntValue() == 0) {
2262 }
else if (printWarning &&
Token::Match(tok,
"[{};] %var% . empty ( ) ;") &&
2272 std::string pattern =
"%var% = ";
2274 pattern += t->str();
2277 pattern +=
"{|( %varid% . begin ( ) ,";
2289 std::ostringstream errmsg;
2290 errmsg <<
"$symbol:" << varname <<
'\n';
2291 errmsg <<
"$symbol:" <<
function <<
'\n';
2292 errmsg <<
"It is inefficient to call '" << varname <<
"." <<
function <<
"(" << varname <<
")' as it always returns 0.\n"
2293 <<
"'std::string::" <<
function <<
"()' returns zero when given itself as parameter "
2294 <<
"(" << varname <<
"." <<
function <<
"(" << varname <<
")). As it is currently the "
2295 <<
"code is inefficient. It is possible either the string searched ('"
2296 << varname <<
"') or searched for ('" << varname <<
"') is wrong.";
2303 "$symbol:" + varname +
"\n"
2304 "It is inefficient to swap a object with itself by calling '$symbol.swap($symbol)'\n"
2305 "The 'swap()' function has no logical effect when given itself as parameter "
2306 "($symbol.swap($symbol)). As it is currently the "
2312 std::string msg =
"Ineffective call of function 'substr' because ";
2315 msg +=
"it returns an empty string.";
2318 msg +=
"it returns a copy of the object. Use operator= instead.";
2321 msg +=
"a prefix of the string is assigned to itself. Use resize() or pop_back() instead.";
2324 msg +=
"a prefix of the string is assigned to itself. Use replace() instead.";
2332 const std::string msg =
"Inefficient constructor call: container '" + tok->
str() +
"' is assigned a partial copy of itself. Use erase() or resize() instead.";
2344 "$symbol:" +
function +
"\n"
2345 "Return value of std::$symbol() ignored. Elements remain in container.\n"
2346 "The return value of std::$symbol() is ignored. This function returns an iterator to the end of the range containing those elements that should be kept. "
2347 "Elements past new end remain valid but with unspecified values. Use the erase method of the container to delete them.",
CWE762,
Certainty::normal);
2357 logChecker(
"CheckStl::checkDereferenceInvalidIterator");
2366 const Token* startOfCondition = tok->
next();
2368 startOfCondition = startOfCondition->
link()->tokAt(2);
2369 if (!startOfCondition)
2371 const Token* endOfCondition = startOfCondition->
link();
2372 if (!endOfCondition)
2378 if (!startOfCondition)
2381 if (!endOfCondition)
2387 const bool isOrExpression =
2389 const bool isAndExpression =
2393 const Token* validityCheckTok =
nullptr;
2394 if (!isOrExpression && isAndExpression) {
2396 Token::findmatch(startOfCondition,
"&& %var% != %name% . end|rend|cend|crend ( )", endOfCondition);
2397 }
else if (isOrExpression && !isAndExpression) {
2399 Token::findmatch(startOfCondition,
"%oror% %var% == %name% . end|rend|cend|crend ( )", endOfCondition);
2402 if (!validityCheckTok)
2404 const int iteratorVarId = validityCheckTok->
next()->
varId();
2408 const Token*
const dereferenceTok =
2409 Token::findmatch(startOfCondition,
"* %varid%", validityCheckTok, iteratorVarId);
2420 logChecker(
"CheckStl::checkDereferenceInvalidIterator2");
2423 if (
Token::Match(tok,
"sizeof|decltype|typeid|typeof (")) {
2431 std::vector<ValueFlow::Value> contValues;
2433 if (value.isImpossible())
2435 if (!printInconclusive && value.isInconclusive())
2437 return value.isContainerSizeValue();
2449 bool isInvalidIterator =
false;
2452 isInvalidIterator = value.
intvalue > 0;
2454 isInvalidIterator =
true;
2456 auto it = std::find_if(contValues.cbegin(), contValues.cend(), [&](
const ValueFlow::Value& c) {
2457 if (value.path != c.path)
2459 if (value.isIteratorStartValue() && value.intvalue >= c.intvalue)
2461 if (value.isIteratorEndValue() && -value.intvalue > c.intvalue)
2465 if (it == contValues.end())
2469 isInvalidIterator =
true;
2472 bool unknown =
false;
2473 const Token* emptyAdvance =
nullptr;
2474 const Token* advanceIndex =
nullptr;
2475 if (cValue && cValue->
intvalue == 0) {
2516 if (!tok || !value) {
2529 std::string errmsg = std::string(value->
isKnown() ?
"Dereference" :
"Possible dereference") +
" of an invalid iterator";
2530 if (!varname.empty())
2531 errmsg =
"$symbol:" + varname +
'\n' + errmsg +
": $symbol";
2535 "derefInvalidIterator",
2544 "derefInvalidIterator",
2545 "$symbol:" + iterName +
"\n"
2546 "Possible dereference of an invalid iterator: $symbol\n"
2547 "Possible dereference of an invalid iterator: $symbol. Make sure to check that the iterator is valid before dereferencing it - not after.",
CWE825,
Certainty::normal);
2558 if (start->
str() !=
"{")
2567 if (endStatement->
next() != endToken)
2574 if (start->
str() !=
"{")
2580 if (endStatement->
next() != endToken)
2582 return endStatement;
2604 if (start->
str() !=
"{")
2612 if (endStatement->
next() != endToken)
2626 if (start->
str() !=
"{")
2628 const Token *varTok =
nullptr;
2630 varTok = start->
tokAt(2);
2632 varTok = start->
tokAt(1);
2635 input = varTok->
varId() == varid;
2641 if (start->
str() !=
"{")
2649 const Token *endBodyTok = bodyTok->
link();
2652 if (endBodyTok->
next() != endToken)
2682 if (
Token::Match(tok,
"= %varid% %oror%|%or%|&&|& %bool% ;", varid) &&
2695 if (
Token::Match(tok,
"= %varid% %oror%|%or%|&&|&", varid)) {
2715 if (algo ==
"std::max_element")
2716 return "std::min_element";
2717 if (algo ==
"std::min_element")
2718 return "std::max_element";
2725 return "std::accumulate";
2726 if (!
hasVarIds(condTok, loopVar, assignVar))
2727 return "std::accumulate";
2728 std::string algo =
"std::max_element";
2730 algo =
"std::min_element";
2739 struct LoopAnalyzer {
2740 const Token* bodyTok =
nullptr;
2741 const Token* loopVar =
nullptr;
2742 const Settings* settings =
nullptr;
2743 std::set<nonneg int> varsChanged;
2745 explicit LoopAnalyzer(
const Token* tok,
const Settings* psettings)
2746 : bodyTok(tok->next()->link()->next()), settings(psettings)
2753 findChangedVariables();
2756 bool isLoopVarChanged()
const {
2757 return varsChanged.count(loopVar->
varId()) > 0;
2760 bool isModified(
const Token* tok)
const
2765 for (
int i = 0; i < n; i++) {
2777 template<
class Predicate,
class F>
2786 template<
class Predicate>
2796 bool hasGotoOrBreak()
const
2803 bool valid()
const {
2804 return bodyTok && loopVar;
2807 std::string findAlgo()
const
2811 bool loopVarChanged = isLoopVarChanged();
2812 if (!loopVarChanged && varsChanged.empty()) {
2813 if (hasGotoOrBreak())
2815 bool alwaysTrue =
true;
2816 bool alwaysFalse =
true;
2817 auto hasReturn = [](
const Token* tok) {
2824 alwaysFalse =
false;
2827 (returnTok->
values().front().intvalue ? alwaysTrue : alwaysFalse) &=
true;
2828 (returnTok->
values().front().intvalue ? alwaysFalse : alwaysTrue) &=
false;
2830 if (alwaysTrue == alwaysFalse)
2833 return "std::any_of";
2834 return "std::all_of or std::none_of";
2839 bool isLocalVar(
const Variable* var)
const
2852 void findChangedVariables()
2854 std::set<nonneg int> vars;
2856 if (tok->
varId() == 0)
2858 if (vars.count(tok->
varId()) > 0)
2861 vars.insert(tok->
varId());
2864 if (!isModified(tok))
2866 varsChanged.insert(tok->
varId());
2867 vars.insert(tok->
varId());
2880 auto checkAssignee = [](
const Token* tok) {
2886 auto isConditionWithoutSideEffects = [
this](
const Token* tok) ->
bool {
2893 for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
2900 std::string algoName = a.findAlgo();
2901 if (!algoName.empty()) {
2908 const Token* loopVar{};
2909 bool isIteratorLoop =
false;
2912 if (loopVar->
varId() == 0)
2921 if (!initTok || !condTok || !stepTok)
2930 isIteratorLoop =
true;
2934 bool useLoopVarInAssign{}, hasBreak{};
2939 const int assignVarId = assignTok->
astOperand1()->varId();
2941 if (assignVarId == loopVar->
varId()) {
2942 if (useLoopVarInAssign)
2943 algo =
"std::transform";
2947 algo =
"std::generate";
2949 algo =
"std::fill or std::generate";
2951 if (
addByOne(assignTok, assignVarId))
2952 algo =
"std::distance";
2954 algo =
"std::any_of, std::all_of, std::none_of, or std::accumulate";
2958 algo =
"std::accumulate";
2964 bool useLoopVarInMemCall;
2966 if (memberAccessTok && !isIteratorLoop) {
2968 const int contVarId = memberAccessTok->
astOperand1()->varId();
2969 if (contVarId == loopVar->
varId())
2971 if (memberCallTok->
str() ==
"push_back" ||
2972 memberCallTok->
str() ==
"push_front" ||
2973 memberCallTok->
str() ==
"emplace_back") {
2975 if (useLoopVarInMemCall)
2978 algo =
"std::transform";
2985 bool useLoopVarInIncrement;
2989 if (useLoopVarInIncrement)
2990 algo =
"std::transform";
2992 algo =
"std::distance";
3005 const int assignVarId = assignTok->
astOperand1()->varId();
3007 if (assignVarId == loopVar->
varId()) {
3008 if (useLoopVarInAssign)
3009 algo =
"std::transform";
3011 algo =
"std::replace_if";
3013 if (
addByOne(assignTok, assignVarId))
3014 algo =
"std::count_if";
3016 algo =
"std::any_of, std::all_of, std::none_of, or std::accumulate";
3017 else if (assignTok->
str() !=
"=")
3018 algo =
"std::accumulate";
3019 else if (hasBreak && isConditionWithoutSideEffects(condBodyTok))
3020 algo =
"std::any_of, std::all_of, std::none_of";
3030 if (memberAccessTok) {
3032 const int contVarId = memberAccessTok->
astOperand1()->varId();
3033 if (contVarId == loopVar->
varId())
3035 if (memberCallTok->
str() ==
"push_back" ||
3036 memberCallTok->
str() ==
"push_front" ||
3037 memberCallTok->
str() ==
"emplace_back") {
3038 if (useLoopVarInMemCall)
3049 if (useLoopVarInIncrement)
3050 algo =
"std::transform";
3052 algo =
"std::count_if";
3063 algo =
"std::find_if";
3065 algo =
"std::any_of";
3076 const std::string var = tok ? tok->
expressionString() : std::string(
"var");
3080 msg =
"Using " + algo +
" with iterator '" + var +
"' that is always empty.";
3082 msg =
"Iterating over container '" + var +
"' that is always empty.";
3086 "knownEmptyContainer",
3097 if (!v.isContainerSizeValue())
3099 if (v.intvalue != 0)
3111 for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
3117 if (tok->
str() ==
"for") {
3128 const std::vector<const Token *> args =
getArguments(tok);
3132 for (
int argnr = 1; argnr <= args.size(); ++argnr) {
3136 const Token *
const argTok = args[argnr - 1];
3150 if (!ftok || !itertok || !val) {
3154 "Either the condition 'x' is redundant or function 'erase()' is called on the iterator 'iter' which is out of bounds.",
CWE628,
Certainty::normal);
3157 const std::string& func = ftok->
str();
3160 const bool isConditional = val->
isPossible();
3162 if (isConditional) {
3165 msg =
"Calling function '" + func +
"()' on the iterator '" + iter +
"' which is out of bounds.";
3169 const std::string
id = isConditional ?
"eraseIteratorOutOfBoundsCond" :
"eraseIteratorOutOfBounds";
3178 if (v.isPossible() || v.isKnown()) {
3179 switch (v.valueType) {
3180 case ValueFlow::Value::ValueType::ITERATOR_END:
3181 return v.intvalue >= 0;
3182 case ValueFlow::Value::ValueType::ITERATOR_START:
3183 return (v.intvalue < 0) || (sizeVal && v.intvalue >= sizeVal->intvalue);
3190 return it != tok->
values().end() ? &*it :
nullptr;
3195 logChecker(
"CheckStl::eraseIteratorOutOfBounds");
3197 for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
3208 const std::vector<const Token*> args =
getArguments(ftok);
3209 if (args.size() != 1)
3222 return Token::Match(tok,
"std :: mutex|recursive_mutex|timed_mutex|recursive_timed_mutex|shared_mutex");
3228 return Token::Match(tok,
"std :: lock_guard|unique_lock|scoped_lock|shared_lock");
3244 "Lock guard is defined globally. Lock guards are intended to be local. A global lock guard could lead to a deadlock since it won't unlock until the end of the program.",
CWE833,
Certainty::normal);
3251 "The lock is ineffective because the mutex is locked at the same scope as the mutex itself.",
CWE667,
Certainty::normal);
3260 std::set<nonneg int> checkedVars;
3261 for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
3274 }
else if (
Token::Match(tok,
"%var% (|{ %var% )|}|,")) {
bool astIsContainer(const Token *tok)
const Token * getIteratorExpression(const Token *tok)
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
bool astIsIntegral(const Token *tok, bool unknown)
Is expression of integral type?
bool exprDependsOnThis(const Token *expr, bool onVar, nonneg int depth)
bool isTemporary(const Token *tok, const Library *library, bool unknown)
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
bool astIsPointer(const Token *tok)
bool isStlStringType(const Token *tok)
bool astIsContainerOwned(const Token *tok)
bool astIsLHS(const Token *tok)
bool astIsBool(const Token *tok)
Is expression of boolean type?
bool isVariableDecl(const Token *tok)
static int getArgumentPos(const Token *ftok, const Token *tokToFind)
Token * getInitTok(Token *tok)
const Token * astParentSkipParens(const Token *tok)
Token * getCondTok(Token *tok)
bool astIsRHS(const Token *tok)
bool astIsFloat(const Token *tok, bool unknown)
Is expression of floating point type?
const Token * nextAfterAstRightmostLeaf(const Token *tok)
Token * getStepTok(Token *tok)
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive)
Is variable changed by function call? In case the answer of the question is inconclusive,...
bool isReturnScope(const Token *const endToken, const Library &library, const Token **unknownFunc, bool functionScope)
Is scope a return scope (scope will unconditionally return)
bool astIsIterator(const Token *tok)
bool isConstExpression(const Token *tok, const Library &library)
Library::Container::Yield astContainerYield(const Token *tok, const Token **ftok)
bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
static std::string flipMinMax(const std::string &algo)
static const CWE CWE788(788U)
static const Token * getContainerIndex(const Library::Container *container, const Token *parent)
static bool isElementAccessYield(Library::Container::Yield yield)
static const CWE CWE398(398U)
static const CWE CWE762(762U)
static bool accumulateBool(const Token *tok, nonneg int varid)
static const Token * singleConditionalInScope(const Token *start, nonneg int varid, const Settings &settings)
static bool isVector(const Token *tok)
static const Token * singleIncrementInScope(const Token *start, nonneg int varid, bool &input)
static bool containerAppendsElement(const Library::Container *container, const Token *parent)
static const Token * singleMemberCallInScope(const Token *start, nonneg int varid, bool &input, const Settings &settings)
static bool isKnownEmptyContainer(const Token *tok)
static std::vector< const Token * > getAddressContainer(const Token *tok)
static const CWE CWE704(704U)
static const CWE CWE597(597U)
static bool isLocalMutex(const Variable *var, const Scope *scope)
static bool containerYieldsElement(const Library::Container *container, const Token *parent)
static const Token * getInvalidMethod(const Token *tok)
static const CWE CWE825(825U)
static const Token * getContainerFromSize(const Library::Container *container, const Token *tok)
static bool isLocal(const Token *tok)
static const Token * endOfExpression(const Token *tok)
static const Token * singleStatement(const Token *start)
static bool isEarlyExit(const Token *start)
static const CWE CWE833(833U)
static bool containerPopsElement(const Library::Container *container, const Token *parent)
static const Token * skipLocalVars(const Token *const tok)
static const CWE CWE667(667U)
static std::pair< const Token *, const Token * > isMapFind(const Token *tok)
static bool isCpp03ContainerSizeSlow(const Token *tok)
Is container.size() slow?
static const Token * findInsertValue(const Token *tok, const Token *containerTok, const Token *keyTok, const Settings &settings)
static std::string indexValueString(const ValueFlow::Value &indexValue, const std::string &containerName=emptyString)
static const CWE CWE786(786U)
static std::string minmaxCompare(const Token *condTok, nonneg int loopVar, nonneg int assignVar, bool invert=false)
static const CWE CWE834(834U)
static bool hasVarIds(const Token *tok, nonneg int var1, nonneg int var2)
static bool isLockGuard(const Variable *var)
static bool isSameIteratorContainerExpression(const Token *tok1, const Token *tok2, const Settings &settings, ValueFlow::Value::LifetimeKind kind=ValueFlow::Value::LifetimeKind::Iterator)
static bool accumulateBoolLiteral(const Token *tok, nonneg int varid)
static const Token * getLoopContainer(const Token *tok)
static const ValueFlow::Value * getOOBIterValue(const Token *tok, const ValueFlow::Value *sizeVal)
static std::string getContainerName(const Token *containerToken)
static bool addByOne(const Token *tok, nonneg int varid)
static bool isMutex(const Variable *var)
static const CWE CWE664(664U)
static const Token * singleAssignInScope(const Token *start, nonneg int varid, bool &input, bool &hasBreak, const Settings &settings)
static const CWE CWE628(628U)
static bool if_findCompare(const Token *const tokBack, bool stdStringLike)
static const Token * skipMembers(const Token *tok)
static const ValueFlow::Value * getInnerLifetime(const Token *tok, nonneg int id, ErrorPath *errorPath=nullptr, int depth=4)
static bool isIterator(const Variable *var, bool &inconclusiveType)
static ValueFlow::Value getLifetimeIteratorValue(const Token *tok, MathLib::bigint path=0)
bool isPointerDeRef(const Token *tok, bool &unknown) const
Is there a pointer dereference? Everything that should result in a nullpointer dereference error mess...
Check STL usage (invalidation of iterators, mismatching containers, etc)
void outOfBoundsIndexExpression()
Accessing container out of bounds, following index expression.
void missingComparison()
Missing inner comparison, when incrementing iterator inside loop Dangers:
void erase()
Dangerous usage of erase.
void missingComparisonError(const Token *incrementToken1, const Token *incrementToken2)
void sizeError(const Token *tok)
void uselessCalls()
Check calls that using them is useless
void checkDereferenceInvalidIterator2()
void stlBoundariesError(const Token *tok)
void uselessCallsSubstrError(const Token *tok, SubstrErrorType type)
void invalidContainerError(const Token *tok, const Token *contTok, const ValueFlow::Value *val, ErrorPath errorPath)
void mismatchingContainerIteratorError(const Token *containerTok, const Token *iterTok, const Token *containerTok2)
void uselessCallsSwapError(const Token *tok, const std::string &varname)
void knownEmptyContainerError(const Token *tok, const std::string &algo)
void size()
Suggest using empty() instead of checking size() against zero for containers.
void mismatchingContainersError(const Token *tok1, const Token *tok2)
void eraseIteratorOutOfBoundsError(const Token *ftok, const Token *itertok, const ValueFlow::Value *val=nullptr)
void string_c_strStream(const Token *tok)
void uselessCallsRemoveError(const Token *tok, const std::string &function)
void uselessCallsReturnValueError(const Token *tok, const std::string &varname, const std::string &function)
void sameIteratorExpressionError(const Token *tok)
bool isContainerSize(const Token *containerToken, const Token *expr) const
void stlOutOfBounds()
Finds errors like this: for (unsigned ii = 0; ii <= foo.size(); ++ii)
void string_c_strParam(const Token *tok, nonneg int number, const std::string &argtype="std::string")
void dereferenceInvalidIteratorError(const Token *deref, const std::string &iterName)
void invalidIteratorError(const Token *tok, const std::string &iteratorName)
void negativeIndexError(const Token *tok, const ValueFlow::Value &index)
void outOfBounds()
Accessing container out of bounds using ValueFlow.
void mismatchingContainerIterator()
void negativeIndex()
negative index for array like containers
void dereferenceErasedError(const Token *erased, const Token *deref, const std::string &itername, bool inconclusive)
Dereferencing an erased iterator.
void mismatchingContainerExpressionError(const Token *tok1, const Token *tok2)
void if_find()
if (a.find(x)) - possibly incorrect condition
void stlOutOfBoundsError(const Token *tok, const std::string &num, const std::string &var, bool at)
void checkFindInsertError(const Token *tok)
void useStlAlgorithm()
Look for loops that can replaced with std algorithms.
void invalidContainerReferenceError(const Token *tok, const Token *contTok, ErrorPath errorPath)
void iterators()
Finds errors like this: for (it = foo.begin(); it != bar.end(); ++it)
void string_c_strThrowError(const Token *tok)
void useStlAlgorithmError(const Token *tok, const std::string &algoName)
void outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue)
void stlBoundaries()
bad condition.
void string_c_str()
Check for common mistakes when using the function string::c_str()
void mismatchingContainers()
Mismatching containers: std::find(foo.begin(), bar.end(), x)
void knownEmptyContainer()
void string_c_strConcat(const Token *tok)
bool isContainerSizeGE(const Token *containerToken, const Token *expr) const
void globalLockGuardError(const Token *tok)
void checkDereferenceInvalidIterator()
Check for dereferencing an iterator that is invalid
void iteratorsError(const Token *tok, const std::string &containerName1, const std::string &containerName2)
void redundantCondition()
Check for redundant condition 'if (ints.find(1) != ints.end()) ints.remove(123);'.
void localMutexError(const Token *tok)
void eraseCheckLoopVar(const Scope &scope, const Variable *var)
void redundantIfRemoveError(const Token *tok)
void eraseIteratorOutOfBounds()
void uselessCallsConstructorError(const Token *tok)
void string_c_strError(const Token *tok)
void string_c_strAssignment(const Token *tok, const std::string &argtype="std::string")
void string_c_strConstructor(const Token *tok, const std::string &argtype="std::string")
bool checkIteratorPair(const Token *tok1, const Token *tok2)
void if_findError(const Token *tok, bool str)
void string_c_strReturn(const Token *tok)
void invalidContainerLoopError(const Token *tok, const Token *loopTok, ErrorPath errorPath)
void outOfBoundsIndexExpressionError(const Token *tok, const Token *index)
void uselessCallsEmptyError(const Token *tok)
void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg)
report an error
const Settings *const mSettings
ErrorPath getErrorPath(const Token *errtok, const ValueFlow::Value *value, std::string bug) const
const Tokenizer *const mTokenizer
void logChecker(const char id[])
log checker
const std::string & name() const
class name, used to generate documentation
nonneg int argCount() const
const Token * tokenDef
function name token in class definition
std::list< Variable > argumentList
argument list, must remain list due to clangimport usage!
Action getAction(const std::string &function) const
Yield getYield(const std::string &function) const
Library definitions handling.
const Container * detectIterator(const Token *typeStart) const
const ArgumentChecks::IteratorInfo * getArgIteratorInfo(const Token *ftok, int argnr) const
const Container * detectContainer(const Token *typeStart) const
std::list< Function > functionList
bool isNestedIn(const Scope *outer) const
Function * function
function info for this function
const Token * classDef
class/struct/union/namespace token
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
bool isExecutable() const
This is just a container for general settings so that we don't need to pass individual values to func...
bool isEnabled(const ValueFlow::Value *value, bool inconclusiveCheck=false) const
Returns true if given value can be shown.
bool isPremiumEnabled(const char id[]) const
Is checker id enabled by premiumArgs.
SimpleEnableGroup< Certainty > certainty
SimpleEnableGroup< Severity > severity
Standards standards
Struct contains standards settings.
bool isEnabled(T flag) const
const std::vector< const Variable * > & variableList() const
std::vector< const Scope * > functionScopes
Fast access to function scopes.
std::list< Scope > scopeList
Information about all namespaces/classes/structures.
The token list that the TokenList generates is a linked-list of this class.
bool hasKnownValue() const
const ValueFlow::Value * getValue(const MathLib::bigint val) const
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
bool hasKnownIntValue() const
MathLib::bigint getKnownIntValue() const
static std::pair< const Token *, const Token * > typeDecl(const Token *tok, bool pointedToType=false)
const Token * nextTemplateArgument() const
bool isArithmeticalOp() const
const ValueFlow::Value * getKnownValue(ValueFlow::Value::ValueType t) const
const ValueType * valueType() const
const std::string & strAt(int index) const
void astOperand1(Token *tok)
void function(const Function *f)
Associate this token with given function.
std::string expressionString() const
const ValueFlow::Value * getValueGE(const MathLib::bigint val, const Settings &settings) const
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
const Token * tokAt(int index) const
Token::Type tokType() const
void astOperand2(Token *tok)
void scope(const Scope *s)
Associate this token with given scope.
void link(Token *linkToToken)
Create link to given token.
const Token * linkAt(int index) const
bool isAssignmentOp() const
nonneg int linenr() const
void variable(const Variable *v)
Associate this token with given variable.
bool isComparisonOp() const
const std::list< ValueFlow::Value > & values() const
const Token * nextArgument() const
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
void astParent(Token *tok)
const Token * tokens() const
const SymbolDatabase * getSymbolDatabase() const
const Function * getFunction(const std::string &funcName) const
bool isSymbolicValue() const
Bound bound
The value bound
MathLib::bigint path
Path id.
bool isIteratorValue() const
bool errorSeverity() const
bool isLifetimeValue() const
bool isImpossible() const
const Token * condition
Condition that this value depends on.
const Token * tokvalue
token value - the token that has the value.
long long intvalue
int value (or sometimes bool value?)
enum ValueFlow::Value::LifetimeKind lifetimeKind
bool isIteratorStartValue() const
bool isIteratorEndValue() const
bool isInconclusive() const
enum ValueType::Type type
const Library::Container * container
If the type is a container defined in a cfg file, this is the used.
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
Information about a member variable.
bool isArgument() const
Is variable a function argument.
bool isReference() const
Is reference variable.
bool isStlStringViewType() const
std::string getTypeName() const
bool isRValueReference() const
Is reference variable.
bool isStlType() const
Checks if the variable is an STL type ('std::') E.g.
bool isLocal() const
Is variable local.
const Type * type() const
Get Type pointer of known type.
const Scope * scope() const
Get Scope pointer of enclosing scope.
bool isGlobal() const
Is variable global.
const Token * typeEndToken() const
Get type end token.
bool isConst() const
Is variable const.
const Token * nameToken() const
Get name token.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
const Token * typeStartToken() const
Get type start token.
bool isPointer() const
Is pointer variable.
bool isStlStringType() const
Checks if the variable is an STL type ('std::') E.g.
bool isStatic() const
Is variable static.
static const std::string emptyString
T * findToken(T *start, const Token *end, const Predicate &pred)
std::vector< T * > findTokens(T *start, const Token *end, const Predicate &pred)
Severity
enum class for severity.
std::pair< const Token *, std::string > ErrorPathItem
const Library::Container * getLibraryContainer(const Token *tok)
std::list< ErrorPathItem > ErrorPath
@ performance
Performance warning.
@ error
Programming error.
std::string eitherTheConditionIsRedundant(const Token *condition)
const Value * findValue(const std::list< Value > &values, const Settings &settings, const std::function< bool(const Value &)> &pred)
std::string lifetimeMessage(const Token *tok, const Value *val, Value::ErrorPath &errorPath)
std::vector< Value > isOutOfBounds(const Value &size, const Token *indexTok, bool possible=true)
CPPCHECKLIB std::vector< Value > getLifetimeObjValues(const Token *tok, bool inconclusive=false, MathLib::bigint path=0)
static const Token * assignExpr(const Token *tok)
bool reaches(const Token *start, const Token *dest, const Library &library, ErrorPath *errorPath)
Returns true if there is a path between the two tokens.
enum Standards::cppstd_t cpp
bool contains(const Range &r, const T &x)