45 static std::vector<std::string>
getnames(
const char *names)
47 std::vector<std::string> ret;
48 while (
const char *p = std::strchr(names,
',')) {
49 ret.emplace_back(names, p-names);
52 ret.emplace_back(names);
58 std::istringstream istr(valid +
',');
59 tokenList.
createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C);
62 tok->str(
"-" + tok->strAt(1));
70 if (std::strchr(path,
',') !=
nullptr) {
73 const std::string::size_type pos = p.find(
',');
74 if (pos == std::string::npos)
76 const Error &e =
load(exename, p.substr(0,pos).c_str());
82 return load(exename, p.c_str());
86 std::string absolute_path;
88 tinyxml2::XMLDocument doc;
89 tinyxml2::XMLError
error = doc.LoadFile(path);
92 error = tinyxml2::XML_ERROR_FILE_NOT_FOUND;
93 if (
error == tinyxml2::XML_ERROR_FILE_NOT_FOUND) {
95 std::string fullfilename(path);
97 fullfilename +=
".cfg";
98 error = doc.LoadFile(fullfilename.c_str());
99 if (
error != tinyxml2::XML_ERROR_FILE_NOT_FOUND)
103 std::list<std::string> cfgfolders;
105 cfgfolders.emplace_back(FILESDIR
"/cfg");
109 cfgfolders.push_back(exepath +
"cfg");
110 cfgfolders.push_back(exepath +
"../cfg");
111 cfgfolders.push_back(exepath);
114 while (
error == tinyxml2::XML_ERROR_FILE_NOT_FOUND && !cfgfolders.empty()) {
115 const std::string cfgfolder(cfgfolders.back());
116 cfgfolders.pop_back();
117 const char *sep = (!cfgfolder.empty() &&
endsWith(cfgfolder,
'/') ?
"" :
"/");
118 const std::string filename(cfgfolder + sep + fullfilename);
119 error = doc.LoadFile(filename.c_str());
120 if (
error != tinyxml2::XML_ERROR_FILE_NOT_FOUND)
126 if (
error == tinyxml2::XML_SUCCESS) {
130 mFiles.insert(absolute_path);
137 if (
error == tinyxml2::XML_ERROR_FILE_NOT_FOUND)
146 if (yieldName ==
"at_index")
148 if (yieldName ==
"item")
150 if (yieldName ==
"buffer")
152 if (yieldName ==
"buffer-nt")
154 if (yieldName ==
"start-iterator")
156 if (yieldName ==
"end-iterator")
158 if (yieldName ==
"iterator")
160 if (yieldName ==
"size")
162 if (yieldName ==
"empty")
168 if (actionName ==
"resize")
170 if (actionName ==
"clear")
172 if (actionName ==
"push")
174 if (actionName ==
"pop")
176 if (actionName ==
"find")
178 if (actionName ==
"find-const")
180 if (actionName ==
"insert")
182 if (actionName ==
"erase")
184 if (actionName ==
"change-content")
186 if (actionName ==
"change-internal")
188 if (actionName ==
"change")
195 const tinyxml2::XMLElement *
const rootnode = doc.FirstChildElement();
197 if (rootnode ==
nullptr) {
202 if (strcmp(rootnode->Name(),
"def") != 0)
205 const int format = rootnode->IntAttribute(
"format", 1);
207 if (format > 2 || format <= 0)
210 std::set<std::string> unknown_elements;
212 for (
const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
213 const std::string nodename = node->Name();
214 if (nodename ==
"memory" || nodename ==
"resource") {
216 int allocationId = 0;
217 for (
const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) {
218 if (strcmp(memorynode->Name(),
"dealloc")==0) {
219 const auto names =
getnames(memorynode->GetText());
220 for (
const auto& n : names) {
221 const std::map<std::string, AllocFunc>::const_iterator it =
mDealloc.find(n);
223 allocationId = it->second.groupId;
227 if (allocationId != 0)
231 if (allocationId == 0) {
232 if (nodename ==
"memory")
240 for (
const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) {
241 const std::string memorynodename = memorynode->Name();
242 const auto names =
getnames(memorynode->GetText());
243 if (memorynodename ==
"alloc" || memorynodename ==
"realloc") {
247 temp.
initData = memorynode->BoolAttribute(
"init",
true);
248 temp.
arg = memorynode->IntAttribute(
"arg", -1);
250 const char *bufferSize = memorynode->Attribute(
"buffer-size");
254 if (std::strncmp(bufferSize,
"malloc", 6) == 0)
256 else if (std::strncmp(bufferSize,
"calloc", 6) == 0)
258 else if (std::strncmp(bufferSize,
"strdup", 6) == 0)
264 if (bufferSize[6] == 0) {
266 }
else if (bufferSize[6] ==
':' && bufferSize[7] >=
'1' && bufferSize[7] <=
'5') {
268 if (bufferSize[8] ==
',' && bufferSize[9] >=
'1' && bufferSize[9] <=
'5')
274 if (memorynodename ==
"realloc")
275 temp.
reallocArg = memorynode->IntAttribute(
"realloc-arg", 1);
278 for (
const auto& n : names)
280 }
else if (memorynodename ==
"dealloc") {
283 temp.
arg = memorynode->IntAttribute(
"arg", 1);
284 for (
const auto& n : names)
286 }
else if (memorynodename ==
"use")
287 for (
const auto& n : names)
290 unknown_elements.insert(memorynodename);
294 else if (nodename ==
"define") {
295 const char *name = node->Attribute(
"name");
298 const char *value = node->Attribute(
"value");
299 if (value ==
nullptr)
301 auto result =
defines.insert(std::string(name) +
" " + value);
306 else if (nodename ==
"function") {
307 const char *name = node->Attribute(
"name");
310 for (
const std::string &s :
getnames(name)) {
317 else if (nodename ==
"reflection") {
318 for (
const tinyxml2::XMLElement *reflectionnode = node->FirstChildElement(); reflectionnode; reflectionnode = reflectionnode->NextSiblingElement()) {
319 if (strcmp(reflectionnode->Name(),
"call") != 0) {
320 unknown_elements.insert(reflectionnode->Name());
324 const char *
const argString = reflectionnode->Attribute(
"arg");
328 mReflection[reflectionnode->GetText()] = strToInt<int>(argString);
332 else if (nodename ==
"markup") {
333 const char *
const extension = node->Attribute(
"ext");
338 mReportErrors[extension] = (node->Attribute(
"reporterrors",
"true") !=
nullptr);
339 mProcessAfterCode[extension] = (node->Attribute(
"aftercode",
"true") !=
nullptr);
341 for (
const tinyxml2::XMLElement *markupnode = node->FirstChildElement(); markupnode; markupnode = markupnode->NextSiblingElement()) {
342 const std::string markupnodename = markupnode->Name();
343 if (markupnodename ==
"keywords") {
344 for (
const tinyxml2::XMLElement *librarynode = markupnode->FirstChildElement(); librarynode; librarynode = librarynode->NextSiblingElement()) {
345 if (strcmp(librarynode->Name(),
"keyword") == 0) {
346 const char* nodeName = librarynode->Attribute(
"name");
347 if (nodeName ==
nullptr)
351 unknown_elements.insert(librarynode->Name());
355 else if (markupnodename ==
"exported") {
356 for (
const tinyxml2::XMLElement *exporter = markupnode->FirstChildElement(); exporter; exporter = exporter->NextSiblingElement()) {
357 if (strcmp(exporter->Name(),
"exporter") != 0) {
358 unknown_elements.insert(exporter->Name());
362 const char *
const prefix = exporter->Attribute(
"prefix");
366 for (
const tinyxml2::XMLElement *e = exporter->FirstChildElement(); e; e = e->NextSiblingElement()) {
367 const std::string ename = e->Name();
368 if (ename ==
"prefix")
370 else if (ename ==
"suffix")
373 unknown_elements.insert(ename);
378 else if (markupnodename ==
"imported") {
379 for (
const tinyxml2::XMLElement *librarynode = markupnode->FirstChildElement(); librarynode; librarynode = librarynode->NextSiblingElement()) {
380 if (strcmp(librarynode->Name(),
"importer") == 0)
381 mImporters[extension].insert(librarynode->GetText());
383 unknown_elements.insert(librarynode->Name());
387 else if (markupnodename ==
"codeblocks") {
388 for (
const tinyxml2::XMLElement *blocknode = markupnode->FirstChildElement(); blocknode; blocknode = blocknode->NextSiblingElement()) {
389 const std::string blocknodename = blocknode->Name();
390 if (blocknodename ==
"block") {
391 const char * blockName = blocknode->Attribute(
"name");
394 }
else if (blocknodename ==
"structure") {
395 const char * start = blocknode->Attribute(
"start");
398 const char * end = blocknode->Attribute(
"end");
401 const char * offset = blocknode->Attribute(
"offset");
409 unknown_elements.insert(blocknodename);
414 unknown_elements.insert(markupnodename);
418 else if (nodename ==
"container") {
419 const char*
const id = node->Attribute(
"id");
425 const char*
const inherits = node->Attribute(
"inherits");
427 const std::unordered_map<std::string, Container>::const_iterator i =
containers.find(inherits);
429 container = i->second;
434 const char*
const startPattern = node->Attribute(
"startPattern");
441 const char*
const endPattern = node->Attribute(
"endPattern");
444 const char*
const itEndPattern = node->Attribute(
"itEndPattern");
447 const char*
const opLessAllowed = node->Attribute(
"opLessAllowed");
449 container.
opLessAllowed = strcmp(opLessAllowed,
"true") == 0;
450 const char*
const hasInitializerListConstructor = node->Attribute(
"hasInitializerListConstructor");
451 if (hasInitializerListConstructor)
453 const char*
const view = node->Attribute(
"view");
455 container.
view = strcmp(view,
"true") == 0;
457 for (
const tinyxml2::XMLElement *containerNode = node->FirstChildElement(); containerNode; containerNode = containerNode->NextSiblingElement()) {
458 const std::string containerNodeName = containerNode->Name();
459 if (containerNodeName ==
"size" || containerNodeName ==
"access" || containerNodeName ==
"other") {
460 for (
const tinyxml2::XMLElement *functionNode = containerNode->FirstChildElement(); functionNode; functionNode = functionNode->NextSiblingElement()) {
461 if (strcmp(functionNode->Name(),
"function") != 0) {
462 unknown_elements.insert(functionNode->Name());
466 const char*
const functionName = functionNode->Attribute(
"name");
470 const char*
const action_ptr = functionNode->Attribute(
"action");
473 std::string actionName = action_ptr;
479 const char*
const yield_ptr = functionNode->Attribute(
"yields");
482 std::string yieldName = yield_ptr;
488 const char*
const returnType = functionNode->Attribute(
"returnType");
490 container.
functions[functionName].returnType = returnType;
492 container.
functions[functionName].action = action;
493 container.
functions[functionName].yield = yield;
496 if (containerNodeName ==
"size") {
497 const char*
const templateArg = containerNode->Attribute(
"templateParameter");
500 }
else if (containerNodeName ==
"access") {
501 const char*
const indexArg = containerNode->Attribute(
"indexOperator");
505 }
else if (containerNodeName ==
"type") {
506 const char*
const templateArg = containerNode->Attribute(
"templateParameter");
510 const char*
const string = containerNode->Attribute(
"string");
513 const char*
const associative = containerNode->Attribute(
"associative");
516 const char*
const unstable = containerNode->Attribute(
"unstable");
518 std::string unstableType = unstable;
519 if (unstableType.find(
"erase") != std::string::npos)
521 if (unstableType.find(
"insert") != std::string::npos)
524 }
else if (containerNodeName ==
"rangeItemRecordType") {
525 for (
const tinyxml2::XMLElement* memberNode = node->FirstChildElement(); memberNode; memberNode = memberNode->NextSiblingElement()) {
526 const char *memberName = memberNode->Attribute(
"name");
527 const char *memberTemplateParameter = memberNode->Attribute(
"templateParameter");
529 member.
name = memberName ? memberName :
"";
530 member.
templateParameter = memberTemplateParameter ? strToInt<int>(memberTemplateParameter) : -1;
534 unknown_elements.insert(containerNodeName);
538 else if (nodename ==
"smart-pointer") {
539 const char *className = node->Attribute(
"class-name");
543 smartPointer.
name = className;
544 for (
const tinyxml2::XMLElement* smartPointerNode = node->FirstChildElement(); smartPointerNode;
545 smartPointerNode = smartPointerNode->NextSiblingElement()) {
546 const std::string smartPointerNodeName = smartPointerNode->Name();
547 if (smartPointerNodeName ==
"unique")
548 smartPointer.
unique =
true;
552 else if (nodename ==
"type-checks") {
553 for (
const tinyxml2::XMLElement *checkNode = node->FirstChildElement(); checkNode; checkNode = checkNode->NextSiblingElement()) {
554 const std::string &checkName = checkNode->Name();
555 for (
const tinyxml2::XMLElement *checkTypeNode = checkNode->FirstChildElement(); checkTypeNode; checkTypeNode = checkTypeNode->NextSiblingElement()) {
556 const std::string checkTypeName = checkTypeNode->Name();
557 const char *typeName = checkTypeNode->GetText();
560 if (checkTypeName ==
"check")
562 else if (checkTypeName ==
"suppress")
564 else if (checkTypeName ==
"checkFiniteLifetime")
570 else if (nodename ==
"podtype") {
571 const char *
const name = node->Attribute(
"name");
576 const char *
const stdtype = node->Attribute(
"stdtype");
578 if (std::strcmp(stdtype,
"bool") == 0)
580 else if (std::strcmp(stdtype,
"char") == 0)
582 else if (std::strcmp(stdtype,
"short") == 0)
584 else if (std::strcmp(stdtype,
"int") == 0)
586 else if (std::strcmp(stdtype,
"long") == 0)
588 else if (std::strcmp(stdtype,
"long long") == 0)
591 const char *
const size = node->Attribute(
"size");
593 podType.
size = strToInt<unsigned int>(size);
594 const char *
const sign = node->Attribute(
"sign");
597 for (
const std::string &s :
getnames(name))
601 else if (nodename ==
"platformtype") {
602 const char *
const type_name = node->Attribute(
"name");
603 if (type_name ==
nullptr)
605 const char *value = node->Attribute(
"value");
606 if (value ==
nullptr)
610 std::set<std::string> platform;
611 for (
const tinyxml2::XMLElement *typenode = node->FirstChildElement(); typenode; typenode = typenode->NextSiblingElement()) {
612 const std::string typenodename = typenode->Name();
613 if (typenodename ==
"platform") {
614 const char *
const type_attribute = typenode->Attribute(
"type");
615 if (type_attribute ==
nullptr)
617 platform.insert(type_attribute);
618 }
else if (typenodename ==
"signed")
620 else if (typenodename ==
"unsigned")
622 else if (typenodename ==
"long")
624 else if (typenodename ==
"pointer")
626 else if (typenodename ==
"ptr_ptr")
628 else if (typenodename ==
"const_ptr")
631 unknown_elements.insert(typenodename);
633 if (platform.empty()) {
636 if (*type_ptr == type)
642 for (
const std::string &p : platform) {
645 if (*type_ptr == type)
649 mPlatforms[p].mPlatformTypes[type_name] = type;
654 else if (nodename ==
"entrypoint") {
655 const char *
const type_name = node->Attribute(
"name");
656 if (type_name ==
nullptr)
662 unknown_elements.insert(nodename);
664 if (!unknown_elements.empty()) {
666 for (std::set<std::string>::const_iterator i = unknown_elements.cbegin(); i != unknown_elements.cend();) {
668 if (++i != unknown_elements.end())
684 for (
const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) {
685 const std::string functionnodename = functionnode->Name();
686 if (functionnodename ==
"noreturn") {
687 const char *
const text = functionnode->GetText();
688 if (strcmp(text,
"false") == 0)
690 else if (strcmp(text,
"maybe") == 0)
694 }
else if (functionnodename ==
"pure")
696 else if (functionnodename ==
"const") {
699 }
else if (functionnodename ==
"leak-ignore")
701 else if (functionnodename ==
"not-overlapping-data") {
703 nonOverlappingData.
ptr1Arg = functionnode->IntAttribute(
"ptr1-arg", -1);
704 nonOverlappingData.
ptr2Arg = functionnode->IntAttribute(
"ptr2-arg", -1);
705 nonOverlappingData.
sizeArg = functionnode->IntAttribute(
"size-arg", -1);
706 nonOverlappingData.
strlenArg = functionnode->IntAttribute(
"strlen-arg", -1);
707 nonOverlappingData.
countArg = functionnode->IntAttribute(
"count-arg", -1);
709 }
else if (functionnodename ==
"use-retval") {
711 if (
const char *type = functionnode->Attribute(
"type"))
712 if (std::strcmp(type,
"error-code") == 0)
714 }
else if (functionnodename ==
"returnValue") {
715 if (
const char *expr = functionnode->GetText())
717 if (
const char *type = functionnode->Attribute(
"type"))
719 if (
const char *container = functionnode->Attribute(
"container"))
724 std::vector<MathLib::bigint> values{LLONG_MIN, LLONG_MAX};
728 }
else if (functionnodename ==
"arg") {
729 const char* argNrString = functionnode->Attribute(
"nr");
732 const bool bAnyArg = strcmp(argNrString,
"any") == 0;
733 const bool bVariadicArg = strcmp(argNrString,
"variadic") == 0;
734 const int nr = (bAnyArg || bVariadicArg) ? -1 : strToInt<int>(argNrString);
736 ac.
optional = functionnode->Attribute(
"default") !=
nullptr;
738 const char *
const argDirection = functionnode->Attribute(
"direction");
740 const size_t argDirLen = strlen(argDirection);
741 if (!strncmp(argDirection,
"in", argDirLen)) {
743 }
else if (!strncmp(argDirection,
"out", argDirLen)) {
745 }
else if (!strncmp(argDirection,
"inout", argDirLen)) {
749 for (
const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
750 const std::string argnodename = argnode->Name();
752 const char *
const indirectStr = argnode->Attribute(
"indirect");
754 indirect = strToInt<int>(indirectStr);
755 if (argnodename ==
"not-bool")
757 else if (argnodename ==
"not-null")
759 else if (argnodename ==
"not-uninit")
761 else if (argnodename ==
"formatstr")
763 else if (argnodename ==
"strz")
765 else if (argnodename ==
"valid") {
767 const char *p = argnode->GetText();
773 else if (argnodename ==
"minsize") {
774 const char *typeattr = argnode->Attribute(
"type");
779 if (strcmp(typeattr,
"strlen")==0)
781 else if (strcmp(typeattr,
"argvalue")==0)
783 else if (strcmp(typeattr,
"sizeof")==0)
785 else if (strcmp(typeattr,
"mul")==0)
787 else if (strcmp(typeattr,
"value")==0)
793 const char *valueattr = argnode->Attribute(
"value");
796 long long minsizevalue = 0;
798 minsizevalue = strToInt<long long>(valueattr);
799 }
catch (
const std::runtime_error&) {
802 if (minsizevalue <= 0)
805 ac.
minsizes.back().value = minsizevalue;
807 const char *argattr = argnode->Attribute(
"arg");
810 if (strlen(argattr) != 1 || argattr[0]<
'0' || argattr[0]>
'9')
814 ac.
minsizes.emplace_back(type, argattr[0] -
'0');
816 const char *arg2attr = argnode->Attribute(
"arg2");
819 if (strlen(arg2attr) != 1 || arg2attr[0]<
'0' || arg2attr[0]>
'9')
821 ac.
minsizes.back().arg2 = arg2attr[0] -
'0';
824 const char* baseTypeAttr = argnode->Attribute(
"baseType");
826 ac.
minsizes.back().baseType = baseTypeAttr;
829 else if (argnodename ==
"iterator") {
831 const char* str = argnode->Attribute(
"type");
838 unknown_elements.insert(argnodename);
842 }
else if (functionnodename ==
"ignorefunction") {
844 }
else if (functionnodename ==
"formatstr") {
846 const tinyxml2::XMLAttribute* scan = functionnode->FindAttribute(
"scan");
847 const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute(
"secure");
850 }
else if (functionnodename ==
"warn") {
852 const char*
const severity = functionnode->Attribute(
"severity");
853 if (severity ==
nullptr)
857 const char*
const cstd = functionnode->Attribute(
"cstd");
864 const char*
const cppstd = functionnode->Attribute(
"cppstd");
871 const char*
const reason = functionnode->Attribute(
"reason");
872 const char*
const alternatives = functionnode->Attribute(
"alternatives");
873 if (reason && alternatives) {
875 wi.
message = std::string(reason) +
" function '" + name +
"' called. It is recommended to use ";
876 std::vector<std::string> alt =
getnames(alternatives);
877 for (std::size_t i = 0; i < alt.size(); ++i) {
878 wi.
message +=
"'" + alt[i] +
"'";
879 if (i == alt.size() - 1)
881 else if (i == alt.size() - 2)
887 const char *
const message = functionnode->GetText();
895 }
else if (functionnodename ==
"container") {
896 const char*
const action_ptr = functionnode->Attribute(
"action");
899 std::string actionName = action_ptr;
906 const char*
const yield_ptr = functionnode->Attribute(
"yields");
909 std::string yieldName = yield_ptr;
916 const char*
const returnType = functionnode->Attribute(
"returnType");
920 unknown_elements.insert(functionnodename);
928 if (!ac || ac->
valid.empty())
930 if (ac->
valid.find(
'.') != std::string::npos)
934 for (
const Token *tok = tokenList.
front(); tok; tok = tok->
next()) {
950 if (!ac || ac->
valid.empty())
954 for (
const Token *tok = tokenList.
front(); tok; tok = tok->
next()) {
978 for (
const Scope *scope = ftok->
scope(); scope; scope = scope->nestedIn) {
979 if (!scope->isClassOrStruct())
981 const std::vector<Type::BaseInfo> &derivedFrom = scope->definedType->derivedFrom;
984 const Token* tok = baseInfo.nameTok;
985 if (tok->
str() ==
"::")
991 name +=
"::" + ftok->
str();
998 if (ftok->
str() ==
"::") {
1038 std::string ret(ftok->
str());
1039 ftok = ftok->
tokAt(-2);
1041 ret = ftok->
str() +
"::" + ret;
1042 ftok = ftok->
tokAt(-2);
1053 const std::unordered_map<std::string, Function>::const_iterator it =
functions.find(funcname);
1054 if (it !=
functions.cend() && it->second.formatstr && it->second.formatstr_scan)
1066 const std::unordered_map<std::string, Function>::const_iterator it =
functions.find(funcname);
1067 if (it !=
functions.cend() && it->second.formatstr && !it->second.formatstr_scan)
1070 if (hasIndirect && arg && arg->
notuninit >= 1)
1071 *hasIndirect =
true;
1072 return arg && arg->
notuninit >= indirect;
1107 return (af && af->
arg == arg) ? af->
groupId : 0;
1114 return (af && af->
arg == arg) ? af->
groupId : 0;
1121 return (af && af->
arg == arg) ? af->
groupId : 0;
1132 const std::map<int,ArgumentChecks>::const_iterator it2 = it1->second.argumentChecks.find(argnr);
1133 if (it2 != it1->second.argumentChecks.cend())
1134 return &it2->second;
1135 const std::map<int,ArgumentChecks>::const_iterator it3 = it1->second.argumentChecks.find(-1);
1136 if (it3 != it1->second.argumentChecks.cend())
1137 return &it3->second;
1144 unknownFunc->clear();
1158 const Token *start = funcname;
1161 start = funcname->
tokAt(-3);
1162 }
else if (funcname->
isName()) {
1171 if (funcname->
str() ==
"exit")
1175 *unknownFunc = funcname->
str();
1184 const Token* firstLinkedTok =
nullptr;
1185 for (
const Token* tok = typeStart; tok && !tok->
varId(); tok = tok->next()) {
1189 firstLinkedTok = tok;
1193 for (
const std::pair<const std::string, Library::Container> & c :
containers) {
1210 if (!firstLinkedTok)
1214 if (!matchedStartPattern)
1254 if (cond->
str() ==
"(") {
1256 if (tok && tok->
str() ==
".") {
1261 }
else if (!fallback.empty()) {
1273 if (tok && tok->
str() ==
".") {
1277 return container->getYield(tok->
astOperand2()->str());
1303 if (functionName.empty())
1306 const std::unordered_map<std::string, Function>::const_iterator it =
functions.find(functionName);
1310 int firstOptionalArg = -1;
1311 for (
const std::pair<const int, Library::ArgumentChecks> & argCheck : it->second.argumentChecks) {
1312 if (argCheck.first > args)
1313 args = argCheck.first;
1314 if (argCheck.second.optional && (firstOptionalArg == -1 || firstOptionalArg > argCheck.first))
1315 firstOptionalArg = argCheck.first;
1317 if (argCheck.second.formatstr || argCheck.second.variadic)
1318 return args <= callargs;
1320 return (firstOptionalArg < 0) ? args == callargs : (callargs >= firstOptionalArg-1 && callargs <= args);
1340 bool has_dot =
false;
1345 if (std::isdigit(*p)) {
1346 error |= (*(p + 1) ==
'-');
1348 else if (*p ==
':') {
1350 error |= range | (*(p + 1) ==
'.');
1355 else if ((*p ==
'-') || (*p ==
'+')) {
1356 error |= (!std::isdigit(*(p + 1)));
1358 else if (*p ==
',') {
1360 error |= *(p + 1) ==
'.';
1363 }
else if (*p ==
'.') {
1365 error |= has_dot | (!std::isdigit(*(p + 1)));
1367 }
else if (*p ==
'E' || *p ==
'e') {
1370 }
else if (*p ==
'!') {
1371 error |= !((*(p+1) ==
'-') || (*(p+1) ==
'+') || (std::isdigit(*(p + 1))));
1385 return it->second.formatstr;
1391 const std::map<int, Library::ArgumentChecks>& argumentChecksFunc =
functions.at(
getFunctionName(ftok)).argumentChecks;
1392 auto it = std::find_if(argumentChecksFunc.cbegin(), argumentChecksFunc.cend(), [](
const std::pair<const int, Library::ArgumentChecks>& a) {
1393 return a.second.formatstr;
1395 return it == argumentChecksFunc.cend() ? -1 : it->first - 1;
1423 if (yield == Yield::START_ITERATOR || yield == Yield::END_ITERATOR || yield == Yield::AT_INDEX ||
1424 yield == Yield::SIZE || yield == Yield::EMPTY || yield == Yield::BUFFER || yield == Yield::BUFFER_NT ||
1432 return it->second.useretval;
1469 return std::vector<MathLib::bigint>();
1481 return &it1->second;
1492 return std::any_of(it->second.argumentChecks.cbegin(), it->second.argumentChecks.cend(), [](
const std::pair<const int, Library::ArgumentChecks>& a) {
1493 return !a.second.minsizes.empty();
1504 if (fs_argno >= 0 && argnr >= fs_argno) {
1515 const std::unordered_map<std::string, Function>::const_iterator it =
functions.find(functionName);
1517 return it->second.ignore;
1522 const std::unordered_map<std::string, Function>::const_iterator it =
functions.find(functionName);
1524 return it->second.use;
1529 const std::unordered_map<std::string, Function>::const_iterator it =
functions.find(functionName);
1531 return it->second.leakignore;
1536 const std::unordered_map<std::string, Function>::const_iterator it =
functions.find(functionName);
1538 return pure ? it->second.ispure : it->second.isconst;
1549 if (yield == Yield::EMPTY || yield == Yield::SIZE || yield == Yield::BUFFER_NT)
1555 return (it !=
functions.cend() && it->second.isconst);
1619 const std::unordered_map<std::string, CodeBlock>::const_iterator map_it
1623 offset = map_it->second.offset();
1630 const std::unordered_map<std::string, CodeBlock>::const_iterator map_it
1634 return map_it->second.start();
1641 const std::unordered_map<std::string, CodeBlock>::const_iterator map_it
1645 return map_it->second.end();
1652 const std::map<std::string, std::set<std::string>>::const_iterator it =
1654 return (it !=
mKeywords.end() && it->second.count(keyword));
1659 const std::map<std::string, std::set<std::string>>::const_iterator it =
1661 return (it !=
mImporters.end() && it->second.count(importer) > 0);
1674 return containerTok;
1676 return containerTok;
1678 return containerTok;
1681 if (f->containerYield == yield) {
1700 return containerTok;
1702 return containerTok;
1705 if (f->containerAction == action) {
1720 std::string typestr = withoutStd ?
"std::" :
"";
1722 typestr += tok->
str();
1739 if (!v.isLocalLifetimeValue())
1753 auto it =
mTypeChecks.find(std::pair<std::string, std::string>(std::move(check), std::move(typeName)));
1760 return tc.first.second == typeName;
1767 std::unordered_map<nonneg int, const Token*>* lookupVarId)
1769 std::shared_ptr<TokenList> tokenList = std::make_shared<TokenList>(&settings);
1771 const std::string code =
"return " +
returnValue +
";";
1772 std::istringstream istr(code);
1773 if (!tokenList->createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C))
1778 std::stack<Token*> lpar;
1779 for (
Token* tok2 = tokenList->front(); tok2; tok2 = tok2->
next()) {
1781 tok2->str(tok2->str() +
"=");
1783 }
else if (tok2->str() ==
"(")
1785 else if (tok2->str() ==
")") {
1796 for (
Token* tok2 = tokenList->front(); tok2; tok2 = tok2->
next()) {
1799 nonneg int const id = strToInt<nonneg int>(tok2->str().c_str() + 3);
1802 (*lookupVarId)[id] = tok2;
1806 tokenList->createAst();
1809 return {tokenList, expr};
int numberOfArgumentsWithoutAst(const Token *start)
Get number of arguments without using AST.
bool astIsContainer(const Token *tok)
bool astIsPointer(const Token *tok)
Library::Container::Action astContainerAction(const Token *tok, const Token **ftok)
std::string astCanonicalType(const Token *expr, bool pointedToType)
Get canonical type of expression.
Library::Container::Yield astContainerYield(const Token *tok, const Token **ftok)
static int sign(const T v)
static bool isIterator(const Variable *var, bool &inconclusiveType)
const std::string & getReturnType(const std::string &function) const
bool hasInitializerListConstructor
static Yield yieldFrom(const std::string &yieldName)
static Action actionFrom(const std::string &actionName)
std::string startPattern2
std::vector< RangeItemRecordTypeItem > rangeItemRecordType
std::map< std::string, Function > functions
Action getAction(const std::string &function) const
Yield getYield(const std::string &function) const
const Container * detectContainerOrIterator(const Token *typeStart, bool *isIterator=nullptr, bool withoutStd=false) const
bool isexecutableblock(const std::string &file, const std::string &token) const
std::map< std::string, AllocFunc > mAlloc
std::set< std::string > mFiles
ArgumentChecks::Direction getArgDirection(const Token *ftok, int argnr) const
static bool isresource(const int id)
is allocation type resource?
std::map< std::string, std::vector< MathLib::bigint > > mUnknownReturnValues
@ DUPLICATE_PLATFORM_TYPE
@ PLATFORM_TYPE_REDEFINED
bool isuninitargbad(const Token *ftok, int argnr, int indirect=0, bool *hasIndirect=nullptr) const
int getAllocId(const Token *tok, int arg) const
get allocation id for function
static bool isContainerYield(const Token *const cond, Library::Container::Yield y, const std::string &fallback=emptyString)
std::vector< MathLib::bigint > unknownReturnValues(const Token *ftok) const
const NonOverlappingData * getNonOverlappingData(const Token *ftok) const
const Token * getContainerFromAction(const Token *tok, Container::Action action) const
bool isnullargbad(const Token *ftok, int argnr) const
Error loadFunction(const tinyxml2::XMLElement *const node, const std::string &name, std::set< std::string > &unknown_elements)
const Token * getContainerFromYield(const Token *tok, Container::Yield yield) const
bool formatstr_function(const Token *ftok) const
const SmartPointer * detectSmartPointer(const Token *tok, bool withoutStd=false) const
std::map< std::string, std::set< std::string > > mKeywords
const Container * detectIterator(const Token *typeStart) const
bool hasAnyTypeCheck(const std::string &typeName) const
bool isSmartPointer(const Token *tok) const
std::map< std::string, std::set< std::string > > mImporters
std::map< std::pair< std::string, std::string >, TypeCheck > mTypeChecks
static bool ismemory(const int id)
is allocation type memory?
int getDeallocId(const Token *tok, int arg) const
get deallocation id for function
bool isFloatArgValid(const Token *ftok, int argnr, double argvalue) const
const std::string & blockstart(const std::string &file) const
const std::string & returnValue(const Token *ftok) const
bool isIntArgValid(const Token *ftok, int argnr, const MathLib::bigint argvalue) const
bool formatstr_secure(const Token *ftok) const
static const AllocFunc * getAllocDealloc(const std::map< std::string, AllocFunc > &data, const std::string &name)
bool isnoreturn(const Token *ftok) const
bool hasminsize(const Token *ftok) const
bool isLeakIgnore(const std::string &functionName) const
std::map< std::string, ExportedFunctions > mExporters
bool isnotnoreturn(const Token *ftok) const
const ArgumentChecks * getarg(const Token *ftok, int argnr) const
int getReallocId(const Token *tok, int arg) const
get reallocation id for function
const std::string & blockend(const std::string &file) const
Error load(const char exename[], const char path[])
UseRetValType getUseRetValType(const Token *ftok) const
const AllocFunc * getAllocFuncInfo(const Token *tok) const
get allocation info for function
const Library::Container * detectContainerInternal(const Token *typeStart, DetectContainer detect, bool *isIterator=nullptr, bool withoutStd=false) const
int formatstr_argno(const Token *ftok) const
std::unordered_set< std::string > mEntrypoints
std::map< std::string, AllocFunc > mDealloc
static Library::Container::Yield getContainerYield(const Token *const cond)
const WarnInfo * getWarnInfo(const Token *ftok) const
bool isScopeNoReturn(const Token *end, std::string *unknownFunc) const
std::set< std::string > mMarkupExtensions
TypeCheck getTypeCheck(std::string check, std::string typeName) const
static bool isCompliantValidationExpression(const char *p)
const AllocFunc * getReallocFuncInfo(const Token *tok) const
get reallocation info for function
std::set< std::string > defines
TypeCheck
Suppress/check a type.
std::map< std::string, std::string > mReturnValue
std::map< std::string, int > mReturnValueContainer
bool reportErrors(const std::string &path) const
const Function * getFunction(const Token *ftok) const
bool iskeyword(const std::string &file, const std::string &keyword) const
std::map< std::string, bool > mProcessAfterCode
std::string getFunctionName(const Token *ftok) const
Get function name for function call.
std::unordered_map< std::string, CodeBlock > mExecutableBlocks
const AllocFunc * getDeallocFuncInfo(const Token *tok) const
get deallocation info for function
std::map< std::string, bool > mReportErrors
std::map< std::string, std::string > mReturnValueType
std::map< std::string, PlatformType > mPlatformTypes
bool isUse(const std::string &functionName) const
int returnValueContainer(const Token *ftok) const
bool markupFile(const std::string &path) const
std::map< std::string, WarnInfo > functionwarn
std::unordered_map< std::string, Container > containers
std::unordered_map< std::string, SmartPointer > smartPointers
std::unordered_map< std::string, PodType > mPodTypes
bool isimporter(const std::string &file, const std::string &importer) const
std::unordered_map< std::string, NonOverlappingData > mNonOverlappingData
bool isNotLibraryFunction(const Token *ftok) const
std::unordered_map< std::string, FalseTrueMaybe > mNoReturn
const Container * detectContainer(const Token *typeStart) const
std::map< std::string, AllocFunc > mRealloc
const std::string & returnValueType(const Token *ftok) const
std::unordered_map< std::string, Function > functions
bool matchArguments(const Token *ftok, const std::string &functionName) const
bool processMarkupAfterCode(const std::string &path) const
bool isFunctionConst(const std::string &functionName, bool pure) const
bool ignorefunction(const std::string &functionName) const
const PlatformType * platform_type(const std::string &name, const std::string &platform) const
int blockstartoffset(const std::string &file) const
std::map< std::string, int > mReflection
std::map< std::string, Platform > mPlatforms
bool formatstr_scan(const Token *ftok) const
static std::string toString(T value)=delete
static bool isEqual(const std::string &first, const std::string &second)
static bool isNotEqual(const std::string &first, const std::string &second)
static bigint toBigNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
static bool isFloat(const std::string &str)
static double toDoubleNumber(const std::string &str)
for conversion of numeric literals
static std::string getFilenameExtension(const std::string &path, bool lowercase=false)
Get an extension of the filename.
static std::string fromNativeSeparators(std::string path)
Convert path to use internal path separators.
static std::string getCurrentExecutablePath(const char *fallback)
Returns the absolute path to the current executable.
static std::string getPathFromFilename(const std::string &filename)
Lookup the path part from a filename (e.g., '/tmp/a.h' -> '/tmp/', 'a.h' -> '')
static std::string getAbsoluteFilePath(const std::string &filePath)
Get an absolute file path from a relative one.
static std::string getFilenameExtensionInLowerCase(const std::string &path)
Get an extension of the filename in lower case.
This is just a container for general settings so that we don't need to pass individual values to func...
const Token * front() const
get first token of list
bool createTokens(std::istream &code, const std::string &file0)
Create tokens from code.
The token list that the TokenList generates is a linked-list of this class.
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
const std::string & originalName() const
static void createMutualLinks(Token *begin, Token *end)
Links two elements against each other.
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.
bool isUnaryOp(const std::string &s) const
const Token * tokAt(int index) 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 isStandardType() 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 Library::Container * container
If the type is a container defined in a cfg file, this is the used.
static const std::string emptyString
std::shared_ptr< Token > createTokenFromExpression(const std::string &returnValue, const Settings &settings, bool cpp, std::unordered_map< nonneg int, const Token * > *lookupVarId)
Severity severityFromString(const std::string &severity)
const Library::Container * getLibraryContainer(const Token *tok)
@ error
Programming error.
static void gettokenlistfromvalid(const std::string &valid, bool cpp, TokenList &tokenList)
static std::vector< std::string > getnames(const char *names)
const Value * valueFlowConstantFoldAST(Token *expr, const Settings &settings)
Constant folding of expression. This can be used before the full ValueFlow has been executed (ValueFl...
std::vector< MinSize > minsizes
IteratorInfo iteratorInfo
@ DIR_UNKNOWN
direction not known / specified
@ DIR_IN
Input to called function. Data is treated as read-only.
@ DIR_OUT
Output to caller. Data is passed by reference or address and is potentially written.
@ DIR_INOUT
Input to called function, and output to caller. Data is passed by reference or address and is potenti...
std::map< int, ArgumentChecks > argumentChecks
Container::Action containerAction
Container::Yield containerYield
enum Library::PodType::Type stdtype
bool setC(const std::string &str)
bool setCPP(std::string str)
enum Standards::cppstd_t cpp
bool startsWith(const std::string &str, const char start[], std::size_t startlen)
bool endsWith(const std::string &str, char c)