25 #include "simplecpp.h"
45 #include <type_traits>
46 #include <unordered_set>
51 template<
class T,
class U>
52 bool operator()(
const T &x,
const U &y)
const {
61 mTokensFrontBack(tokensFrontBack)
67 :
Token(const_cast<
Token*>(tok)->mTokensFrontBack)
140 if (
mStr ==
"true" ||
mStr ==
"false")
146 else if (std::isalpha((
unsigned char)
mStr[0]) ||
mStr[0] ==
'_' ||
mStr[0] ==
'$') {
155 }
else if (simplecpp::Token::isNumberLike(
mStr)) {
160 }
else if (
mStr ==
"=" ||
mStr ==
"<<=" ||
mStr ==
">>=" ||
161 (
mStr.size() == 2U &&
mStr[1] ==
'=' && std::strchr(
"+-*/%&^|",
mStr[0])))
163 else if (
mStr.size() == 1 &&
mStr.find_first_of(
",[]()?:") != std::string::npos)
165 else if (
mStr==
"<<" ||
mStr==
">>" || (
mStr.size()==1 &&
mStr.find_first_of(
"+-*/%") != std::string::npos))
167 else if (
mStr.size() == 1 &&
mStr.find_first_of(
"&|^~") != std::string::npos)
169 else if (
mStr.size() <= 2 &&
182 else if (
mStr ==
"<=>")
184 else if (
mStr.size() == 2 &&
188 else if (
mStr.size() == 1 && (
mStr.find_first_of(
"{}") != std::string::npos || (
mLink &&
mStr.find_first_of(
"<>") != std::string::npos)))
190 else if (
mStr ==
"...")
202 static const std::unordered_set<std::string>
stdTypes = {
"bool"
241 return std::none_of(
mStr.begin(),
mStr.end(), [](
char c) {
242 return std::islower(c);
252 mStr.insert(0, b.substr(0, b.find(
'"')));
261 std::string::size_type pos = 0U;
262 while ((pos = ret.find(
'\\', pos)) != std::string::npos) {
264 if (ret[pos] >=
'a') {
267 else if (ret[pos] ==
'r')
269 else if (ret[pos] ==
't')
273 return ret.substr(0,pos);
281 while (
mNext && count > 0) {
352 fromToken->
mImpl =
nullptr;
393 if (replaceThis->
next())
406 for (
Token *tok = start; tok != end->
next(); tok = tok->
next())
413 template<
class T,
REQUIRES(
"T must be a Token class", std::is_convertible<T*, const Token*> )>
416 while (index > 0 && tok) {
420 while (index < 0 && tok) {
421 tok = tok->previous();
437 template<
class T,
REQUIRES(
"T must be a Token class", std::is_convertible<T*, const Token*> )>
440 T *tok = thisTok->tokAt(index);
442 throw InternalError(thisTok,
"Internal error. Token::linkAt called with index outside the tokens range.");
464 #if defined(__GNUC__)
467 inline __attribute__((always_inline))
473 switch (haystack[0]) {
475 if (haystack[3] ==
'%') {
477 if (tok->
varId() != 0)
481 throw InternalError(tok,
"Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
486 if (tok->
varId() == varid)
501 if (haystack[3] ==
'%') {
514 if (haystack[4] ==
'%') {
528 if (haystack[0] ==
'h') {
534 else if (haystack[1] ==
'p') {
565 if (haystack[1] ==
'%') {
567 if (haystack[0] ==
'p') {
593 if (*haystack ==
'|')
602 #if defined(__GNUC__)
604 inline __attribute__((always_inline))
608 const char *needle = tok->
str().c_str();
609 const char *needlePointer = needle;
611 if (needlePointer == needle && haystack[0] ==
'%' && haystack[1] !=
'|' && haystack[1] !=
'\0' && haystack[1] !=
' ') {
615 }
else if (*haystack ==
'|') {
616 if (*needlePointer == 0) {
621 needlePointer = needle;
623 }
else if (*needlePointer == *haystack) {
624 if (*needlePointer ==
'\0')
628 }
else if (*haystack ==
' ' || *haystack ==
'\0') {
629 if (needlePointer == needle)
636 needlePointer = needle;
641 if (*haystack ==
' ' || *haystack ==
'\0') {
644 if (*haystack ==
'|') {
653 if (*needlePointer ==
'\0')
669 const char *current = pattern;
670 const char *end = pattern + pattern_len;
672 const char *
next =
static_cast<const char*
>(std::memchr(pattern,
' ', pattern_len));
677 const std::size_t length =
next - current;
679 if (!tok || length != tok->
mStr.length() || std::strncmp(current, tok->
mStr.c_str(), length) != 0)
684 next = std::strchr(++current,
' ');
698 return (*
str ==
' ' && *word == 0);
712 if (*
str ==
' ' || *
str == 0)
727 const char *p = pattern;
739 if (p[0] ==
'!' && p[1] ==
'!' && p[2] !=
'\0') {
740 while (*p && *p !=
' ')
750 if (tok->
str().length() != 1)
753 const char *temp = p+1;
754 bool chrFound =
false;
756 while (*temp && *temp !=
' ') {
761 else if (*temp == tok->
str()[0]) {
769 if (count > 1 && tok->
str()[0] ==
']')
779 else if (p[0] ==
'!' && p[1] ==
'!' && p[2] !=
'\0') {
790 while (*p && *p !=
' ')
801 if (!(p = strchr(p,
' ')))
813 assert(tok !=
nullptr);
819 std::string::const_iterator it =
str.cbegin();
820 const std::string::const_iterator end =
str.cend();
843 assert(tok !=
nullptr);
847 int sizeofstring = 1;
848 for (
int i = 0; i < (int)
str.size(); i++) {
859 nonneg int sizeofType = 1;
882 newLocation->
next(srcStart);
885 for (
Token *tok = srcStart; tok != srcEnd->
next(); tok = tok->
next())
889 template<
class T,
REQUIRES(
"T must be a Token class", std::is_convertible<T*, const Token*> )>
892 for (T* tok = thisTok; tok; tok = tok->next()) {
893 if (tok->str() ==
",")
915 for (
const Token* tok =
this; tok; tok = tok->
next()) {
916 if (tok->str() ==
",")
920 else if (tok->str() ==
"<") {
932 for (
const Token* tok =
this; tok; tok = tok->
next()) {
933 if (tok->str() ==
",")
948 return tok->
strAt(-1) ==
"operator";
964 const Token *closing =
nullptr;
965 const bool templateParameter(
strAt(-1) ==
"template");
966 std::set<std::string> templateParameters;
970 if (prev->str() ==
"=")
978 unsigned int depth = 0;
979 for (closing =
this; closing !=
nullptr; closing = closing->
next()) {
981 closing = closing->
link();
987 else if (closing->
str() ==
"<" && closing->
previous() &&
989 (templateParameter ? templateParameters.find(closing->
strAt(-1)) == templateParameters.end() :
true))
991 else if (closing->
str() ==
">") {
994 }
else if (closing->
str() ==
">>" || closing->
str() ==
">>=") {
995 if (!isDecl && depth == 1)
1002 else if (templateParameter && depth == 1 && closing->
str() ==
"," &&
1004 templateParameters.insert(closing->
strAt(-1));
1021 const Token *opening =
nullptr;
1023 unsigned int depth = 0;
1024 for (opening =
this; opening !=
nullptr; opening = opening->
previous()) {
1026 opening = opening->
link();
1031 else if (opening->
str() ==
">")
1033 else if (opening->
str() ==
"<") {
1050 template<
class T,
REQUIRES(
"T must be a Token class", std::is_convertible<T*, const Token*> )>
1053 for (T* tok = startTok; tok; tok = tok->next()) {
1070 template<
class T,
REQUIRES(
"T must be a Token class", std::is_convertible<T*, const Token*> )>
1073 for (T* tok = startTok; tok && tok != end; tok = tok->
next()) {
1089 template<
class T,
REQUIRES(
"T must be a Token class", std::is_convertible<T*, const Token*> )>
1092 for (T* tok = startTok; tok; tok = tok->next()) {
1108 template<
class T,
REQUIRES(
"T must be a Token class", std::is_convertible<T*, const Token*> )>
1111 for (T* tok = startTok; tok && tok != end; tok = tok->
next()) {
1139 Token*
Token::insertToken(
const std::string& tokenStr,
const std::string& originalNameStr,
const std::string& macroNameStr,
bool prepend)
1146 newToken->
str(tokenStr);
1150 if (newToken !=
this) {
1163 newToken->
next(
this);
1171 this->
next(newToken);
1177 if (newToken->
str() ==
"{") {
1178 std::string nextScopeNameAddition;
1180 Token *tok1 = newToken;
1189 if (tok1->
strAt(-1) !=
")")
1192 tok1 = tok1->
tokAt(-2);
1193 if (tok1->
strAt(-1) !=
")")
1196 if (tok1->
strAt(-1) ==
">")
1199 tok1 = tok1->
tokAt(-2);
1204 tok1 = tok1->
tokAt(-2);
1206 nextScopeNameAddition +=
scope;
1213 while (nameTok && !
Token::Match(nameTok,
"namespace|class|struct|union %name% {|::|:|<")) {
1217 for (nameTok = nameTok->
next(); nameTok && !
Token::Match(nameTok,
"{|:|<"); nameTok = nameTok->
next()) {
1218 nextScopeNameAddition.append(nameTok->
str());
1219 nextScopeNameAddition.append(
" ");
1221 if (!nextScopeNameAddition.empty())
1222 nextScopeNameAddition.pop_back();
1229 if (!newScopeInfo->name.empty() && !nextScopeNameAddition.empty()) newScopeInfo->name.append(
" :: ");
1230 newScopeInfo->name.append(nextScopeNameAddition);
1231 nextScopeNameAddition =
"";
1233 newToken->
scopeInfo(std::move(newScopeInfo));
1234 }
else if (newToken->
str() ==
"}") {
1240 matchingTok = matchingTok->
previous();
1242 if (matchingTok && matchingTok->
previous()) {
1246 if (prepend && newToken->
previous()) {
1251 if (newToken->
str() ==
";") {
1252 const Token* statementStart;
1254 if (
Token::Match(statementStart,
"using namespace %name% ::|;")) {
1255 const Token * tok1 = statementStart->
tokAt(2);
1256 std::string nameSpace;
1257 while (tok1 && tok1->
str() !=
";") {
1258 if (!nameSpace.empty())
1260 nameSpace += tok1->
str();
1261 tok1 = tok1->
next();
1274 if (!begin || begin == end)
1277 while (begin->
next() && begin->
next() != end) {
1284 assert(begin !=
nullptr);
1285 assert(end !=
nullptr);
1286 assert(begin != end);
1293 if (title && title[0])
1294 std::cout <<
"\n### " << title <<
" ###\n";
1300 if (title && title[0])
1301 std::cout <<
"\n### " << title <<
" ###\n";
1308 const Token *end =
this;
1331 if (
isName() &&
mStr.find(
' ') != std::string::npos) {
1332 for (
const char i :
mStr) {
1336 }
else if (
mStr[0] !=
'\"' ||
mStr.find(
'\0') == std::string::npos)
1339 for (
const char i :
mStr) {
1348 ret += (options.
idtype ?
"var" :
"");
1352 ret += (options.
idtype ?
"expr" :
"");
1365 options.
varid = varid;
1367 options.
macro = macro;
1381 std::map<int, unsigned int> lineNumbers;
1382 for (
const Token *tok =
this; tok != end; tok = tok->
next()) {
1383 assert(tok &&
"end precedes token");
1386 bool fileChange =
false;
1387 if (tok->mImpl->mFileIndex !=
fileIndex) {
1389 lineNumbers[
fileIndex] = tok->mImpl->mFileIndex;
1393 if (options.
files) {
1394 ret +=
"\n\n##file ";
1395 if (fileNames && fileNames->size() > tok->mImpl->mFileIndex)
1396 ret += fileNames->at(tok->mImpl->mFileIndex);
1406 if (options.
linebreaks && (lineNumber != tok->linenr() || fileChange)) {
1407 if (lineNumber+4 < tok->linenr() &&
fileIndex == tok->mImpl->mFileIndex) {
1409 ret += std::to_string(lineNumber+1);
1411 ret += std::to_string(tok->linenr()-1);
1413 ret += std::to_string(tok->linenr());
1416 ret += std::to_string(tok->linenr());
1418 }
else if (lineNumber > tok->linenr()) {
1419 lineNumber = tok->linenr();
1422 ret += std::to_string(lineNumber);
1427 while (lineNumber < tok->
linenr()) {
1431 ret += std::to_string(lineNumber);
1433 if (lineNumber == tok->linenr())
1438 lineNumber = tok->linenr();
1441 ret += tok->stringify(options);
1442 if (tok->next() != end && (!options.
linebreaks || (tok->next()->linenr() == tok->linenr() && tok->next()->fileIndex() == tok->fileIndex())))
1449 std::string
Token::stringifyList(
bool varid,
bool attributes,
bool linenumbers,
bool linebreaks,
bool files,
const std::vector<std::string>* fileNames,
const Token* end)
const
1452 options.
varid = varid;
1454 options.
macro = attributes;
1457 options.
files = files;
1463 return stringifyList(
false, attributes,
false,
false,
false,
nullptr, end);
1468 return stringifyList(varid,
false,
true,
true,
true,
nullptr,
nullptr);
1473 const Token* tok2 = tok;
1476 throw InternalError(
this,
"Internal error. AST cyclic dependency.");
1518 for (
const Token *tok = start; tok && tok != end; tok = tok->
next()) {
1519 if (tok->str() ==
"(")
1521 else if (tok->str() ==
")") {
1523 start = tok->
link();
1535 for (
const Token *tok = end; tok && tok != start; tok = tok->
previous()) {
1536 if (tok->str() ==
")")
1538 else if (tok->str() ==
"(") {
1550 const Token *
const top =
this;
1553 const Token *start = top;
1558 const Token *end = top;
1561 if (end->
str() ==
"[") {
1583 throw InternalError(start,
"Cannot find start of expression");
1587 return std::pair<const Token *, const Token *>(start,end);
1604 std::stack<const Token *> operands;
1605 operands.push(
this);
1606 while (!operands.empty()) {
1607 const Token *op = operands.top();
1634 for (
int distance = 1; distance < 10 && tokbefore; distance++) {
1650 for (
const Token *tok = start; tok && tok != end; tok = tok->
next()) {
1651 if (tok->isUnsigned())
1653 if (tok->isLong() && !tok->isLiteral())
1656 for (
const unsigned char c: tok->str()) {
1663 else if (c >=
' ' && c <= 126)
1667 sprintf(str,
"\\x%02x", c);
1671 }
else if (tok->originalName().empty() || tok->isUnsigned() || tok->isLong()) {
1674 ret += tok->originalName();
1689 const std::string strindent(
indent,
' ');
1691 out << strindent <<
"<token str=\"" << tok->
str() <<
'\"';
1693 out <<
" varId=\"" << tok->
varId() <<
'\"';
1695 out <<
" variable=\"" << tok->
variable() <<
'\"';
1697 out <<
" function=\"" << tok->
function() <<
'\"';
1698 if (!tok->
values().empty())
1699 out <<
" values=\"" << &tok->
values() <<
'\"';
1702 out <<
"/>" << std::endl;
1706 out << '>
' << std::endl;
1707 if (tok->astOperand1())
1708 astStringXml(tok->astOperand1(), indent+2U, out);
1709 if (tok->astOperand2())
1710 astStringXml(tok->astOperand2(), indent+2U, out);
1711 out << strindent << "</token>" << std::endl;
1715 void Token::printAst(bool verbose, bool xml, const std::vector<std::string> &fileNames, std::ostream &out) const
1718 out << "\n\n##AST" << std::endl;
1720 std::set<const Token *> printed;
1721 for (const Token *tok = this; tok; tok = tok->next()) {
1722 if (!tok->mImpl->mAstParent && tok->mImpl->mAstOperand1) {
1723 if (printed.find(tok) != printed.end())
1725 printed.insert(tok);
1728 out << "<ast scope=\"" << tok->scope() << "\" fileIndex=\"" << tok->fileIndex() << "\" linenr=\"" << tok->linenr()
1729 << "\" column=\"" << tok->column() << "\">" << std::endl;
1730 astStringXml(tok, 2U, out);
1731 out << "</ast>" << std::endl;
1733 out << "[" << fileNames[tok->fileIndex()] << ":" << tok->linenr() << "]" << std::endl << tok->astStringVerbose() << std::endl;
1735 out << tok->astString(" ") << std::endl;
1736 if (tok->str() == "(")
1742 static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2)
1744 for (int i = 0; i < indent1; ++i)
1746 for (int i = indent1; i < indent2; i += 2)
1750 void Token::astStringVerboseRecursive(std::string& ret, const nonneg int indent1, const nonneg int indent2) const
1752 if (isExpandedMacro())
1755 if (mImpl->mValueType)
1756 ret += " \'" + mImpl->mValueType->str() + '\
'';
1758 std::ostringstream ostr;
1759 ostr << std::hex <<
function();
1760 ret +=
" f:" + ostr.str();
1764 if (mImpl->mAstOperand1) {
1765 int i1 = indent1, i2 = indent2 + 2;
1766 if (indent1 == indent2 && !mImpl->mAstOperand2)
1768 indent(ret, indent1, indent2);
1769 ret += mImpl->mAstOperand2 ?
"|-" :
"`-";
1770 mImpl->mAstOperand1->astStringVerboseRecursive(ret, i1, i2);
1772 if (mImpl->mAstOperand2) {
1773 int i1 = indent1, i2 = indent2 + 2;
1774 if (indent1 == indent2)
1776 indent(ret, indent1, indent2);
1778 mImpl->mAstOperand2->astStringVerboseRecursive(ret, i1, i2);
1806 outs +=
" <valueflow>\n";
1808 outs +=
"\n\n##Value flow\n";
1809 for (
const Token *tok =
this; tok; tok = tok->
next()) {
1817 outs +=
" <values id=\"";
1829 if (line != tok->
linenr()) {
1831 outs += std::to_string(tok->
linenr());
1840 return value.valueKind == valueKind;
1846 switch (valueKind) {
1852 outs +=
"inconclusive ";
1855 outs +=
"possible ";
1865 switch (value.valueType) {
1868 outs +=
"intvalue=\"";
1873 outs +=
"intvalue=\"";
1874 outs += std::to_string(value.intvalue);
1879 outs +=
"tokvalue=\"";
1884 outs +=
"floatvalue=\"";
1885 outs += std::to_string(value.floatValue);
1889 outs +=
"movedvalue=\"";
1894 outs +=
"uninit=\"1\"";
1897 outs +=
"buffer-size=\"";
1898 outs += std::to_string(value.intvalue);
1902 outs +=
"container-size=\"";
1903 outs += std::to_string(value.intvalue);
1907 outs +=
"iterator-start=\"";
1908 outs += std::to_string(value.intvalue);
1912 outs +=
"iterator-end=\"";
1913 outs += std::to_string(value.intvalue);
1917 outs +=
"lifetime=\"";
1920 outs +=
" lifetime-scope=\"";
1923 outs +=
" lifetime-kind=\"";
1928 outs +=
"symbolic=\"";
1931 outs +=
" symbolic-delta=\"";
1932 outs += std::to_string(value.intvalue);
1936 outs +=
" bound=\"";
1939 if (value.condition) {
1940 outs +=
" condition-line=\"";
1941 outs += std::to_string(value.condition->linenr());
1944 if (value.isKnown())
1945 outs +=
" known=\"true\"";
1946 else if (value.isPossible())
1947 outs +=
" possible=\"true\"";
1948 else if (value.isImpossible())
1949 outs +=
" impossible=\"true\"";
1950 else if (value.isInconclusive())
1951 outs +=
" inconclusive=\"true\"";
1954 outs += std::to_string(value.path);
1961 if (&value != &
values->front())
1963 outs += value.toString();
1967 outs +=
" </values>\n";
1968 else if (
values->size() > 1U)
1974 outs +=
" </valueflow>\n";
1984 return !v.isImpossible() && v.isIntValue() && v.intvalue <= val;
1993 return !v.isImpossible() && v.isIntValue() && v.intvalue >= val;
2002 for (std::list<ValueFlow::Value>::const_iterator it =
mImpl->
mValues->begin(); it !=
mImpl->
mValues->end(); ++it) {
2003 if (it->isImpossible())
2026 const Token *ret =
nullptr;
2027 int minsize = INT_MAX;
2028 for (std::list<ValueFlow::Value>::const_iterator it =
mImpl->
mValues->begin(); it !=
mImpl->
mValues->end(); ++it) {
2029 if (it->isTokValue() && it->tokvalue && it->tokvalue->tokType() ==
Token::eString) {
2030 const int size =
getStrSize(it->tokvalue, settings);
2031 if (!ret || size < minsize) {
2046 const Token *ret =
nullptr;
2048 for (std::list<ValueFlow::Value>::const_iterator it =
mImpl->
mValues->begin(); it !=
mImpl->
mValues->end(); ++it) {
2049 if (it->isTokValue() && it->tokvalue && it->tokvalue->tokType() ==
Token::eString) {
2051 if (!ret || length > maxlength) {
2069 static bool removePointValue(std::list<ValueFlow::Value>& values, std::list<ValueFlow::Value>::iterator& x)
2075 x = values.erase(x);
2081 bool result =
false;
2082 for (
auto itx = values.begin(); itx != values.end(); ++itx) {
2083 if (itx->isNonValue())
2088 for (; ity != values.end(); ++ity) {
2089 if (ity->isNonValue())
2093 if (itx->valueType != ity->valueType)
2095 if (itx->isImpossible() == ity->isImpossible())
2099 if (!itx->equalValue(*ity)) {
2100 auto compare = [](
const std::list<ValueFlow::Value>::const_iterator& x,
const std::list<ValueFlow::Value>::const_iterator& y) {
2101 return x->compareValue(*y, less{});
2103 auto itMax = std::max(itx, ity, compare);
2104 auto itMin = std::min(itx, ity, compare);
2107 values.erase(itMin);
2111 values.erase(itMax);
2116 const bool removex = !itx->isImpossible() || ity->isKnown();
2117 const bool removey = !ity->isImpossible() || itx->isKnown();
2118 if (itx->bound == ity->bound) {
2126 result = removex || removey;
2141 template<
class Iterator>
2145 return std::next(x);
2151 (*it)->bound = x->bound;
2152 std::for_each(std::move(start), std::move(it), [&](
ValueIterator y) {
2155 return values.erase(x);
2160 for (
auto x = values.begin(); x != values.end();) {
2161 if (x->isNonValue()) {
2169 std::vector<ValueIterator> adjValues;
2170 for (
auto y = values.begin(); y != values.end(); y++) {
2173 if (y->isNonValue())
2175 if (x->valueType != y->valueType)
2177 if (x->valueKind != y->valueKind)
2181 if (x->bound != y->bound) {
2196 adjValues.push_back(y);
2198 if (adjValues.empty()) {
2204 assert(xx != values.end() && yy != values.end());
2205 return xx->compareValue(*yy, less{});
2230 if (!x.equalValue(y))
2232 if (x.bound != y.
bound)
2245 for (
int i = 0; i < 4; i++) {
2274 return x.isKnown() && sameValueType(x, value) && !x.equalValue(value);
2290 std::list<ValueFlow::Value>::iterator it;
2300 if (!it->equalValue(value))
2343 int total_count = 0;
2344 for (
Token *tok2 = tok; tok2; tok2 = tok2->
next())
2347 for (
Token *tok2 = tok; tok2; tok2 = tok2->
next())
2348 tok2->mImpl->mProgressValue = count++ *100 / total_count;
2355 for (
Token *tok =
this; tok; tok = tok->
next())
2381 if (typeTok !=
nullptr)
2383 const Token* lhsVarTok{};
2422 vars.cbegin(), vars.cend(), [&](
const Variable* var) {
2423 return var->type() == vars.front()->type();
2425 return vars.front()->type();
2436 return {tok, tok->
next()};
2451 std::pair<const Token*, const Token*> result;
2455 tok2 = tok2->
tokAt(2);
2465 const Token* varTok = tok2;
2467 varTok = varTok->
next();
2469 varTok = varTok->
tokAt(2);
2470 std::pair<const Token*, const Token*> r =
typeDecl(varTok);
2479 declEnd = declEnd->
link()->next();
2480 return { tok2->
next(), declEnd };
2482 const Token *typeBeg{}, *typeEnd{};
2487 else if (tok2->
str() ==
"{") {
2492 result = { typeBeg->
next(), typeEnd };
2513 return {
function->
retDef,
function->returnDefEnd() };
2518 return {
function->retDef,
function->returnDefEnd()};
2525 const ::Type * t =
typeOf(tok);
2526 if (!t || !t->classDef)
2528 return {t->classDef->next(), t->classDef->tokAt(2)};
2534 std::string ret = vt->
str();
2539 if (!r.first || !r.second)
2541 return r.first->stringifyList(r.second,
false);
2558 return value.isKnown() && value.isIntValue();
2571 return value.isKnown() && value.valueType == t;
2581 return value.isKnown() && value.isSymbolicValue() && value.tokvalue &&
2582 value.tokvalue->exprId() == tok->exprId();
2591 return value.isKnown() && value.valueType == t;
2601 return value.isIntValue() && !value.isImpossible() && value.intvalue == val;
2606 template<
class Compare>
2614 if (!value.isIntValue())
2616 if (value.isImpossible())
2618 if (path > -0 && value.path != 0 && value.path != path)
2620 if ((!ret || compare(value.intvalue, ret->
intvalue)) && ((value.condition !=
nullptr) == condition))
2645 return value.isMovedValue() && !value.isImpossible() &&
2646 value.moveKind != ValueFlow::Value::MoveKind::NonMovedVariable;
2657 return value.isContainerSizeValue() && !value.isImpossible() && value.intvalue == val;
2670 templateSimplifierPointer->token(
nullptr);
2685 while (attr && attr->
type != type)
2688 attr->
value = value;
2692 attr->
value = value;
2701 while (attr && attr->
type != type)
2704 value = attr->
value;
2705 return attr !=
nullptr;
2710 while (
Token::Match(tok,
"%name%|.|::|*|&|&&|<|(|template|decltype|sizeof")) {
2735 while (
Token::Match(tok,
"mutable|constexpr|consteval|noexcept|.")) {
bool astIsContainer(const Token *tok)
bool astIsRangeBasedForDecl(const Token *tok)
Is given token a range-declaration in a range-based for loop.
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
const Token * getTokenArgumentFunction(const Token *tok, int &argn)
Return the token to the function and the argument number.
bool astIsSmartPointer(const Token *tok)
const Token * findLambdaEndToken(const Token *first)
find lambda function end token
const Token * nextAfterAstRightmostLeaf(const Token *tok)
bool astIsIterator(const Token *tok)
const Token * previousBeforeAstLeftmostLeaf(const Token *tok)
std::vector< const Variable * > getArgumentVars(const Token *tok, int argnr)
const Token * getLHSVariableToken(const Token *tok)
bool succeeds(const Token *tok1, const Token *tok2)
If tok1 comes after tok2.
const Token * retDef
function return type token
const ::Type * retType
function return type
bool isFloatArgValid(const Token *ftok, int argnr, double argvalue) const
bool isIntArgValid(const Token *ftok, int argnr, const MathLib::bigint argvalue) const
static bool isFloat(const std::string &str)
static bool isInt(const std::string &str)
unsigned long long biguint
Function * function
function info for this function
This is just a container for general settings so that we don't need to pass individual values to func...
SimpleEnableGroup< Certainty > certainty
SimpleEnableGroup< Severity > severity
bool isEnabled(T flag) const
bool isKeyword(const std::string &str) const
const std::vector< std::string > & getFiles() const
Get filenames (the sourcefile + the files it include).
The token list that the TokenList generates is a linked-list of this class.
Token(const Token &)=delete
void update_property_info()
Updates internal property cache like _isName or _isBoolean.
const ValueFlow::Value * getMovedValue() const
bool hasKnownValue() const
const ValueFlow::Value * getValue(const MathLib::bigint val) const
const ValueFlow::Value * getContainerSizeValue(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 bool firstWordEquals(const char *str, const char *word)
Works almost like strcmp() except returns only true or false and if str has empty space ' ' character...
void deleteThis()
Remove the contents for this token from the token list.
nonneg int exprId() const
void takeData(Token *fromToken)
used by deleteThis() to take data from token to delete
void setMacroName(std::string name)
void printLines(int lines=5) const
print out tokens - used for debugging
const std::string & originalName() const
void printOut(const char *title=nullptr) const
For debugging purposes, prints token and all tokens followed by it.
const ValueFlow::Value * getMinValue(bool condition, MathLib::bigint path=0) const
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
std::string stringify(const stringifyOptions &options) const
bool addValue(const ValueFlow::Value &value)
Add token value.
std::string astStringZ3() const
static int multiCompare(const Token *tok, const char *haystack, nonneg int varid)
Needle is build from multiple alternatives.
bool hasKnownIntValue() const
const ValueFlow::Value * getMaxValue(bool condition, MathLib::bigint path=0) const
static void replace(Token *replaceThis, Token *start, Token *end)
Replace token replaceThis with tokens between start and end, including start and end.
bool isExpandedMacro() const
void concatStr(std::string const &b)
Concatenate two (quoted) strings.
static std::pair< const Token *, const Token * > typeDecl(const Token *tok, bool pointedToType=false)
const Token * nextTemplateArgument() const
void templateSimplifierPointer(TemplateSimplifier::TokenAndName *tokenAndName)
const ValueFlow::Value * getInvalidValue(const Token *ftok, nonneg int argnr, const Settings *settings) const
std::string stringifyList(const stringifyOptions &options, const std::vector< std::string > *fileNames=nullptr, const Token *end=nullptr) const
static nonneg int getStrSize(const Token *tok, const Settings &settings)
const Token * getValueTokenMaxStrLength() const
std::shared_ptr< ScopeInfo2 > scopeInfo() const
const Token * getValueTokenMinStrSize(const Settings &settings, MathLib::bigint *path=nullptr) const
bool isUpperCaseName() const
static void createMutualLinks(Token *begin, Token *end)
Links two elements against each other.
const Scope * scope() const
void setValueType(ValueType *vt)
static nonneg int getStrLength(const Token *tok)
const ValueFlow::Value * getKnownValue(ValueFlow::Value::ValueType t) const
ConstTokenRange until(const Token *t) const
static const ::Type * typeOf(const Token *tok, const Token **typeTok=nullptr)
const ValueType * valueType() const
const std::string & strAt(int index) const
static void assignProgressValues(Token *tok)
Calculate progress values for all tokens.
bool hasKnownSymbolicValue(const Token *tok) const
void astOperand1(Token *tok)
TokensFrontBack & mTokensFrontBack
bool isCalculation() const
Is current token a calculation? Only true for operands.
const Function * function() const
void function(const Function *f)
Associate this token with given function.
std::pair< const Token *, const Token * > findExpressionStartEndTokens() const
static void move(Token *srcStart, Token *srcEnd, Token *newLocation)
Move srcStart and srcEnd tokens and all tokens between them into new a location.
std::string expressionString() const
const std::string & str() const
const Token * findClosingBracket() const
Returns the closing bracket of opening '<'.
void astStringVerboseRecursive(std::string &ret, const nonneg int indent1=0, const nonneg int indent2=0) const
Internal helper function to avoid excessive string allocations.
void setFlag(uint64_t flag_, bool state_)
Set specified flag state.
void printValueFlow(bool xml, std::ostream &out) const
std::string astStringVerbose() const
static const char * chrInFirstWord(const char *str, char c)
Works almost like strchr() except if str has empty space ' ' character, that character is handled as ...
const ::Type * type() const
void update_property_isStandardType()
Update internal property cache about isStandardType()
bool isUnaryPreOp() const
static nonneg int getStrArraySize(const Token *tok)
void scopeInfo(std::shared_ptr< ScopeInfo2 > newScopeInfo)
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
const Token * tokAt(int index) const
void deleteNext(nonneg int count=1)
Unlink and delete the next 'count' tokens.
Token * insertToken(const std::string &tokenStr, const std::string &originalNameStr=emptyString, const std::string ¯oNameStr=emptyString, bool prepend=false)
Insert new token after this token.
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
std::string strValue() const
This can be called only for tokens that are strings, else the assert() is called.
void type(const ::Type *t)
Associate this token with given type.
static std::string typeStr(const Token *tok)
const ValueFlow::Value * getValueGE(const MathLib::bigint val, const Settings *settings) const
bool isAssignmentOp() const
static void eraseTokens(Token *begin, const Token *end)
Delete tokens between begin and end.
nonneg int linenr() const
bool isStandardType() const
const Token * nextArgumentBeforeCreateLinks2() const
void variable(const Variable *v)
Associate this token with given variable.
bool isComparisonOp() const
const ValueFlow::Value * getValueLE(const MathLib::bigint val, const Settings *settings) const
const std::list< ValueFlow::Value > & values() const
void update_property_char_string_literal()
Update internal property cache about string and char literals.
const Token * nextArgument() const
void swapWithNext()
Swap the contents of this token with the next token.
const Token * findOpeningBracket() const
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
nonneg int fileIndex() const
void deletePrevious(nonneg int count=1)
Unlink and delete the previous 'count' tokens.
void astParent(Token *tok)
bool isSymbolicValue() const
Bound bound
The value bound
std::string toString() const
enum ValueFlow::Value::ValueType valueType
ValueKind
How known is this value.
@ Inconclusive
Inconclusive.
@ Impossible
Listed values are impossible.
@ Known
Only listed values are possible.
@ Possible
This value is possible, other unlisted values may also be possible.
bool isLifetimeValue() const
static bool sameToken(const Token *tok1, const Token *tok2)
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?)
nonneg int varId
For calculated values - varId that calculated value depends on.
enum ValueFlow::Value::ValueKind valueKind
bool isInconclusive() const
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
const Token * smartPointerTypeToken
Smart pointer type token.
const Token * containerTypeToken
The container type token.
enum ValueType::Sign sign
Information about a member variable.
const Token * declEndToken() const
Get end token of variable declaration E.g.
const Token * typeEndToken() const
Get type end token.
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.
const ValueType * valueType() const
#define REQUIRES(msg,...)
static const std::string emptyString
Token * findTypeEnd(Token *tok)
Token * findLambdaEndScope(Token *tok)
const Value * findValue(const std::list< Value > &values, const Settings *settings, const std::function< bool(const Value &)> &pred)
size_t getSizeOf(const ValueType &vt, const Settings &settings, int maxRecursion=0)
Simple container to be thrown when internal error is detected.
enum TokenImpl::CppcheckAttributes::Type type
CppcheckAttributes * next
std::list< ValueFlow::Value > * mValues
const Function * mFunction
std::string * mOriginalName
static const std::list< ValueFlow::Value > mEmptyValueList
nonneg int mProgressValue
A value from 0-100 that provides a rough idea about where in the token list this token is located.
std::set< TemplateSimplifier::TokenAndName * > * mTemplateSimplifierPointers
CppcheckAttributes * mCppcheckAttributes
std::shared_ptr< ScopeInfo2 > mScopeInfo
void setCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint value)
nonneg int mIndex
Token index.
bool getCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint &value) const
static stringifyOptions forDebugExprId()
static stringifyOptions forPrintOut()
This struct stores pointers to the front and back tokens of the list this token is in.
static const Token * goToRightParenthesis(const Token *start, const Token *end)
static const std::unordered_set< std::string > baseKeywords
static const std::unordered_set< std::string > controlFlowKeywords
std::list< ValueFlow::Value >::iterator ValueIterator
static int multiCompareImpl(const Token *tok, const char *haystack, nonneg int varid)
static void removeOverlaps(std::list< ValueFlow::Value > &values)
static T * findmatchImpl(T *const startTok, const char pattern[], const nonneg int varId)
static const Token * goToLeftParenthesis(const Token *start, const Token *end)
static bool sameValueType(const ValueFlow::Value &x, const ValueFlow::Value &y)
static const std::unordered_set< std::string > stdTypes
static std::string stringFromTokenRange(const Token *start, const Token *end)
static bool isOperator(const Token *tok)
static bool removeContradiction(std::list< ValueFlow::Value > &values)
static void mergeAdjacent(std::list< ValueFlow::Value > &values)
static bool isAdjacent(const ValueFlow::Value &x, const ValueFlow::Value &y)
static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2)
static int multiComparePercent(const Token *tok, const char *&haystack, nonneg int varid)
static T * findsimplematchImpl(T *const startTok, const char pattern[], size_t pattern_len)
static T * linkAtImpl(T *thisTok, int index)
static const ValueFlow::Value * getCompareValue(const std::list< ValueFlow::Value > &values, bool condition, MathLib::bigint path, Compare compare)
static void removeContradictions(std::list< ValueFlow::Value > &values)
static T * nextArgumentImpl(T *thisTok)
static bool removePointValue(std::list< ValueFlow::Value > &values, std::list< ValueFlow::Value >::iterator &x)
static ValueIterator removeAdjacentValues(std::list< ValueFlow::Value > &values, ValueIterator x, Iterator start, Iterator last)
static T * tokAtImpl(T *tok, int index)
static void astStringXml(const Token *tok, nonneg int indent, std::ostream &out)
static bool isStringLiteral(const std::string &str)
static std::string id_string(const void *p)
static bool isPrefixStringCharLiteral(const std::string &str, char q, const std::string &p)
static std::string getStringLiteral(const std::string &str)
static bool isCharLiteral(const std::string &str)