Coverage Report

Created: 2023-09-25 06:15

/src/cppcheck/lib/library.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Cppcheck - A tool for static C/C++ code analysis
3
 * Copyright (C) 2007-2023 Cppcheck team.
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18
19
#include "library.h"
20
21
#include "astutils.h"
22
#include "mathlib.h"
23
#include "path.h"
24
#include "symboldatabase.h"
25
#include "token.h"
26
#include "tokenlist.h"
27
#include "utils.h"
28
#include "valueflow.h"
29
#include "vfvalue.h"
30
31
#include <algorithm>
32
#include <cctype>
33
#include <climits>
34
#include <cstring>
35
#include <list>
36
#include <memory>
37
#include <sstream> // IWYU pragma: keep
38
#include <stack>
39
#include <stdexcept>
40
#include <string>
41
42
#include <tinyxml2.h>
43
44
static std::vector<std::string> getnames(const char *names)
45
0
{
46
0
    std::vector<std::string> ret;
47
0
    while (const char *p = std::strchr(names,',')) {
48
0
        ret.emplace_back(names, p-names);
49
0
        names = p + 1;
50
0
    }
51
0
    ret.emplace_back(names);
52
0
    return ret;
53
0
}
54
55
static void gettokenlistfromvalid(const std::string& valid, TokenList& tokenList)
56
0
{
57
0
    std::istringstream istr(valid + ',');
58
0
    tokenList.createTokens(istr);
59
0
    for (Token *tok = tokenList.front(); tok; tok = tok->next()) {
60
0
        if (Token::Match(tok,"- %num%")) {
61
0
            tok->str("-" + tok->strAt(1));
62
0
            tok->deleteNext();
63
0
        }
64
0
    }
65
0
}
66
67
Library::Error Library::load(const char exename[], const char path[])
68
0
{
69
0
    if (std::strchr(path,',') != nullptr) {
70
0
        std::string p(path);
71
0
        for (;;) {
72
0
            const std::string::size_type pos = p.find(',');
73
0
            if (pos == std::string::npos)
74
0
                break;
75
0
            const Error &e = load(exename, p.substr(0,pos).c_str());
76
0
            if (e.errorcode != ErrorCode::OK)
77
0
                return e;
78
0
            p = p.substr(pos+1);
79
0
        }
80
0
        if (!p.empty())
81
0
            return load(exename, p.c_str());
82
0
        return Error();
83
0
    }
84
85
0
    std::string absolute_path;
86
    // open file..
87
0
    tinyxml2::XMLDocument doc;
88
0
    tinyxml2::XMLError error = doc.LoadFile(path);
89
0
    if (error == tinyxml2::XML_ERROR_FILE_READ_ERROR && Path::getFilenameExtension(path).empty())
90
        // Reading file failed, try again...
91
0
        error = tinyxml2::XML_ERROR_FILE_NOT_FOUND;
92
0
    if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND) {
93
        // failed to open file.. is there no extension?
94
0
        std::string fullfilename(path);
95
0
        if (Path::getFilenameExtension(fullfilename).empty()) {
96
0
            fullfilename += ".cfg";
97
0
            error = doc.LoadFile(fullfilename.c_str());
98
0
            if (error != tinyxml2::XML_ERROR_FILE_NOT_FOUND)
99
0
                absolute_path = Path::getAbsoluteFilePath(fullfilename);
100
0
        }
101
102
0
        std::list<std::string> cfgfolders;
103
#ifdef FILESDIR
104
        cfgfolders.emplace_back(FILESDIR "/cfg");
105
#endif
106
0
        if (exename) {
107
0
            const std::string exepath(Path::fromNativeSeparators(Path::getPathFromFilename(Path::getCurrentExecutablePath(exename))));
108
0
            cfgfolders.push_back(exepath + "cfg");
109
0
            cfgfolders.push_back(exepath + "../cfg");
110
0
            cfgfolders.push_back(exepath);
111
0
        }
112
113
0
        while (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND && !cfgfolders.empty()) {
114
0
            const std::string cfgfolder(cfgfolders.back());
115
0
            cfgfolders.pop_back();
116
0
            const char *sep = (!cfgfolder.empty() && endsWith(cfgfolder,'/') ? "" : "/");
117
0
            const std::string filename(cfgfolder + sep + fullfilename);
118
0
            error = doc.LoadFile(filename.c_str());
119
0
            if (error != tinyxml2::XML_ERROR_FILE_NOT_FOUND)
120
0
                absolute_path = Path::getAbsoluteFilePath(filename);
121
0
        }
122
0
    } else
123
0
        absolute_path = Path::getAbsoluteFilePath(path);
124
125
0
    if (error == tinyxml2::XML_SUCCESS) {
126
0
        if (mFiles.find(absolute_path) == mFiles.end()) {
127
0
            Error err = load(doc);
128
0
            if (err.errorcode == ErrorCode::OK)
129
0
                mFiles.insert(absolute_path);
130
0
            return err;
131
0
        }
132
133
0
        return Error(ErrorCode::OK); // ignore duplicates
134
0
    }
135
136
0
    if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND)
137
0
        return Error(ErrorCode::FILE_NOT_FOUND);
138
139
0
    doc.PrintError();
140
0
    return Error(ErrorCode::BAD_XML);
141
0
}
142
143
Library::Container::Yield Library::Container::yieldFrom(const std::string& yieldName)
144
0
{
145
0
    if (yieldName == "at_index")
146
0
        return Container::Yield::AT_INDEX;
147
0
    if (yieldName == "item")
148
0
        return Container::Yield::ITEM;
149
0
    if (yieldName == "buffer")
150
0
        return Container::Yield::BUFFER;
151
0
    if (yieldName == "buffer-nt")
152
0
        return Container::Yield::BUFFER_NT;
153
0
    if (yieldName == "start-iterator")
154
0
        return Container::Yield::START_ITERATOR;
155
0
    if (yieldName == "end-iterator")
156
0
        return Container::Yield::END_ITERATOR;
157
0
    if (yieldName == "iterator")
158
0
        return Container::Yield::ITERATOR;
159
0
    if (yieldName == "size")
160
0
        return Container::Yield::SIZE;
161
0
    if (yieldName == "empty")
162
0
        return Container::Yield::EMPTY;
163
0
    return Container::Yield::NO_YIELD;
164
0
}
165
Library::Container::Action Library::Container::actionFrom(const std::string& actionName)
166
0
{
167
0
    if (actionName == "resize")
168
0
        return Container::Action::RESIZE;
169
0
    if (actionName == "clear")
170
0
        return Container::Action::CLEAR;
171
0
    if (actionName == "push")
172
0
        return Container::Action::PUSH;
173
0
    if (actionName == "pop")
174
0
        return Container::Action::POP;
175
0
    if (actionName == "find")
176
0
        return Container::Action::FIND;
177
0
    if (actionName == "insert")
178
0
        return Container::Action::INSERT;
179
0
    if (actionName == "erase")
180
0
        return Container::Action::ERASE;
181
0
    if (actionName == "change-content")
182
0
        return Container::Action::CHANGE_CONTENT;
183
0
    if (actionName == "change-internal")
184
0
        return Container::Action::CHANGE_INTERNAL;
185
0
    if (actionName == "change")
186
0
        return Container::Action::CHANGE;
187
0
    return Container::Action::NO_ACTION;
188
0
}
189
190
// cppcheck-suppress unusedFunction - only used in unit tests
191
bool Library::loadxmldata(const char xmldata[], std::size_t len)
192
0
{
193
0
    tinyxml2::XMLDocument doc;
194
0
    return (tinyxml2::XML_SUCCESS == doc.Parse(xmldata, len)) && (load(doc).errorcode == ErrorCode::OK);
195
0
}
196
197
Library::Error Library::load(const tinyxml2::XMLDocument &doc)
198
0
{
199
0
    const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
200
201
0
    if (rootnode == nullptr) {
202
0
        doc.PrintError();
203
0
        return Error(ErrorCode::BAD_XML);
204
0
    }
205
206
0
    if (strcmp(rootnode->Name(),"def") != 0)
207
0
        return Error(ErrorCode::UNSUPPORTED_FORMAT, rootnode->Name());
208
209
0
    const int format = rootnode->IntAttribute("format", 1); // Assume format version 1 if nothing else is specified (very old .cfg files had no 'format' attribute)
210
211
0
    if (format > 2 || format <= 0)
212
0
        return Error(ErrorCode::UNSUPPORTED_FORMAT);
213
214
0
    std::set<std::string> unknown_elements;
215
216
0
    for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
217
0
        const std::string nodename = node->Name();
218
0
        if (nodename == "memory" || nodename == "resource") {
219
            // get allocationId to use..
220
0
            int allocationId = 0;
221
0
            for (const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) {
222
0
                if (strcmp(memorynode->Name(),"dealloc")==0) {
223
0
                    const std::map<std::string, AllocFunc>::const_iterator it = mDealloc.find(memorynode->GetText());
224
0
                    if (it != mDealloc.end()) {
225
0
                        allocationId = it->second.groupId;
226
0
                        break;
227
0
                    }
228
0
                }
229
0
            }
230
0
            if (allocationId == 0) {
231
0
                if (nodename == "memory")
232
0
                    while (!ismemory(++mAllocId));
233
0
                else
234
0
                    while (!isresource(++mAllocId));
235
0
                allocationId = mAllocId;
236
0
            }
237
238
            // add alloc/dealloc/use functions..
239
0
            for (const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) {
240
0
                const std::string memorynodename = memorynode->Name();
241
0
                if (memorynodename == "alloc" || memorynodename == "realloc") {
242
0
                    AllocFunc temp = {0};
243
0
                    temp.groupId = allocationId;
244
245
0
                    temp.initData = memorynode->BoolAttribute("init", true);
246
0
                    temp.arg = memorynode->IntAttribute("arg", -1);
247
248
0
                    const char *bufferSize = memorynode->Attribute("buffer-size");
249
0
                    if (!bufferSize)
250
0
                        temp.bufferSize = AllocFunc::BufferSize::none;
251
0
                    else {
252
0
                        if (std::strncmp(bufferSize, "malloc", 6) == 0)
253
0
                            temp.bufferSize = AllocFunc::BufferSize::malloc;
254
0
                        else if (std::strncmp(bufferSize, "calloc", 6) == 0)
255
0
                            temp.bufferSize = AllocFunc::BufferSize::calloc;
256
0
                        else if (std::strncmp(bufferSize, "strdup", 6) == 0)
257
0
                            temp.bufferSize = AllocFunc::BufferSize::strdup;
258
0
                        else
259
0
                            return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, bufferSize);
260
0
                        temp.bufferSizeArg1 = 1;
261
0
                        temp.bufferSizeArg2 = 2;
262
0
                        if (bufferSize[6] == 0) {
263
                            // use default values
264
0
                        } else if (bufferSize[6] == ':' && bufferSize[7] >= '1' && bufferSize[7] <= '5') {
265
0
                            temp.bufferSizeArg1 = bufferSize[7] - '0';
266
0
                            if (bufferSize[8] == ',' && bufferSize[9] >= '1' && bufferSize[9] <= '5')
267
0
                                temp.bufferSizeArg2 = bufferSize[9] - '0';
268
0
                        } else
269
0
                            return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, bufferSize);
270
0
                    }
271
272
0
                    if (memorynodename == "realloc")
273
0
                        temp.reallocArg = memorynode->IntAttribute("realloc-arg", 1);
274
275
0
                    if (memorynodename != "realloc")
276
0
                        mAlloc[memorynode->GetText()] = temp;
277
0
                    else
278
0
                        mRealloc[memorynode->GetText()] = temp;
279
0
                } else if (memorynodename == "dealloc") {
280
0
                    AllocFunc temp = {0};
281
0
                    temp.groupId = allocationId;
282
0
                    temp.arg = memorynode->IntAttribute("arg", 1);
283
0
                    mDealloc[memorynode->GetText()] = temp;
284
0
                } else if (memorynodename == "use")
285
0
                    functions[memorynode->GetText()].use = true;
286
0
                else
287
0
                    unknown_elements.insert(memorynodename);
288
0
            }
289
0
        }
290
291
0
        else if (nodename == "define") {
292
0
            const char *name = node->Attribute("name");
293
0
            if (name == nullptr)
294
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
295
0
            const char *value = node->Attribute("value");
296
0
            if (value == nullptr)
297
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "value");
298
0
            defines.push_back(std::string(name) +
299
0
                              " " +
300
0
                              value);
301
0
        }
302
303
0
        else if (nodename == "function") {
304
0
            const char *name = node->Attribute("name");
305
0
            if (name == nullptr)
306
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
307
0
            for (const std::string &s : getnames(name)) {
308
0
                const Error &err = loadFunction(node, s, unknown_elements);
309
0
                if (err.errorcode != ErrorCode::OK)
310
0
                    return err;
311
0
            }
312
0
        }
313
314
0
        else if (nodename == "reflection") {
315
0
            for (const tinyxml2::XMLElement *reflectionnode = node->FirstChildElement(); reflectionnode; reflectionnode = reflectionnode->NextSiblingElement()) {
316
0
                if (strcmp(reflectionnode->Name(), "call") != 0) {
317
0
                    unknown_elements.insert(reflectionnode->Name());
318
0
                    continue;
319
0
                }
320
321
0
                const char * const argString = reflectionnode->Attribute("arg");
322
0
                if (!argString)
323
0
                    return Error(ErrorCode::MISSING_ATTRIBUTE, "arg");
324
325
0
                mReflection[reflectionnode->GetText()] = strToInt<int>(argString);
326
0
            }
327
0
        }
328
329
0
        else if (nodename == "markup") {
330
0
            const char * const extension = node->Attribute("ext");
331
0
            if (!extension)
332
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "ext");
333
0
            mMarkupExtensions.insert(extension);
334
335
0
            mReportErrors[extension] = (node->Attribute("reporterrors", "true") != nullptr);
336
0
            mProcessAfterCode[extension] = (node->Attribute("aftercode", "true") != nullptr);
337
338
0
            for (const tinyxml2::XMLElement *markupnode = node->FirstChildElement(); markupnode; markupnode = markupnode->NextSiblingElement()) {
339
0
                const std::string markupnodename = markupnode->Name();
340
0
                if (markupnodename == "keywords") {
341
0
                    for (const tinyxml2::XMLElement *librarynode = markupnode->FirstChildElement(); librarynode; librarynode = librarynode->NextSiblingElement()) {
342
0
                        if (strcmp(librarynode->Name(), "keyword") == 0) {
343
0
                            const char* nodeName = librarynode->Attribute("name");
344
0
                            if (nodeName == nullptr)
345
0
                                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
346
0
                            mKeywords[extension].insert(nodeName);
347
0
                        } else
348
0
                            unknown_elements.insert(librarynode->Name());
349
0
                    }
350
0
                }
351
352
0
                else if (markupnodename == "exported") {
353
0
                    for (const tinyxml2::XMLElement *exporter = markupnode->FirstChildElement(); exporter; exporter = exporter->NextSiblingElement()) {
354
0
                        if (strcmp(exporter->Name(), "exporter") != 0) {
355
0
                            unknown_elements.insert(exporter->Name());
356
0
                            continue;
357
0
                        }
358
359
0
                        const char * const prefix = exporter->Attribute("prefix");
360
0
                        if (!prefix)
361
0
                            return Error(ErrorCode::MISSING_ATTRIBUTE, "prefix");
362
363
0
                        for (const tinyxml2::XMLElement *e = exporter->FirstChildElement(); e; e = e->NextSiblingElement()) {
364
0
                            const std::string ename = e->Name();
365
0
                            if (ename == "prefix")
366
0
                                mExporters[prefix].addPrefix(e->GetText());
367
0
                            else if (ename == "suffix")
368
0
                                mExporters[prefix].addSuffix(e->GetText());
369
0
                            else
370
0
                                unknown_elements.insert(ename);
371
0
                        }
372
0
                    }
373
0
                }
374
375
0
                else if (markupnodename == "imported") {
376
0
                    for (const tinyxml2::XMLElement *librarynode = markupnode->FirstChildElement(); librarynode; librarynode = librarynode->NextSiblingElement()) {
377
0
                        if (strcmp(librarynode->Name(), "importer") == 0)
378
0
                            mImporters[extension].insert(librarynode->GetText());
379
0
                        else
380
0
                            unknown_elements.insert(librarynode->Name());
381
0
                    }
382
0
                }
383
384
0
                else if (markupnodename == "codeblocks") {
385
0
                    for (const tinyxml2::XMLElement *blocknode = markupnode->FirstChildElement(); blocknode; blocknode = blocknode->NextSiblingElement()) {
386
0
                        const std::string blocknodename = blocknode->Name();
387
0
                        if (blocknodename == "block") {
388
0
                            const char * blockName = blocknode->Attribute("name");
389
0
                            if (blockName)
390
0
                                mExecutableBlocks[extension].addBlock(blockName);
391
0
                        } else if (blocknodename == "structure") {
392
0
                            const char * start = blocknode->Attribute("start");
393
0
                            if (start)
394
0
                                mExecutableBlocks[extension].setStart(start);
395
0
                            const char * end = blocknode->Attribute("end");
396
0
                            if (end)
397
0
                                mExecutableBlocks[extension].setEnd(end);
398
0
                            const char * offset = blocknode->Attribute("offset");
399
0
                            if (offset)
400
0
                                mExecutableBlocks[extension].setOffset(strToInt<int>(offset));
401
0
                        }
402
403
0
                        else
404
0
                            unknown_elements.insert(blocknodename);
405
0
                    }
406
0
                }
407
408
0
                else
409
0
                    unknown_elements.insert(markupnodename);
410
0
            }
411
0
        }
412
413
0
        else if (nodename == "container") {
414
0
            const char* const id = node->Attribute("id");
415
0
            if (!id)
416
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "id");
417
418
0
            Container& container = containers[id];
419
420
0
            const char* const inherits = node->Attribute("inherits");
421
0
            if (inherits) {
422
0
                const std::unordered_map<std::string, Container>::const_iterator i = containers.find(inherits);
423
0
                if (i != containers.end())
424
0
                    container = i->second; // Take values from parent and overwrite them if necessary
425
0
                else
426
0
                    return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, inherits);
427
0
            }
428
429
0
            const char* const startPattern = node->Attribute("startPattern");
430
0
            if (startPattern) {
431
0
                container.startPattern = startPattern;
432
0
                container.startPattern2 = container.startPattern + " !!::";
433
0
            }
434
0
            const char* const endPattern = node->Attribute("endPattern");
435
0
            if (endPattern)
436
0
                container.endPattern = endPattern;
437
0
            const char* const itEndPattern = node->Attribute("itEndPattern");
438
0
            if (itEndPattern)
439
0
                container.itEndPattern = itEndPattern;
440
0
            const char* const opLessAllowed = node->Attribute("opLessAllowed");
441
0
            if (opLessAllowed)
442
0
                container.opLessAllowed = strcmp(opLessAllowed, "true") == 0;
443
0
            const char* const hasInitializerListConstructor = node->Attribute("hasInitializerListConstructor");
444
0
            if (hasInitializerListConstructor)
445
0
                container.hasInitializerListConstructor = strcmp(hasInitializerListConstructor, "true") == 0;
446
0
            const char* const view = node->Attribute("view");
447
0
            if (view)
448
0
                container.view = strcmp(view, "true") == 0;
449
450
0
            for (const tinyxml2::XMLElement *containerNode = node->FirstChildElement(); containerNode; containerNode = containerNode->NextSiblingElement()) {
451
0
                const std::string containerNodeName = containerNode->Name();
452
0
                if (containerNodeName == "size" || containerNodeName == "access" || containerNodeName == "other") {
453
0
                    for (const tinyxml2::XMLElement *functionNode = containerNode->FirstChildElement(); functionNode; functionNode = functionNode->NextSiblingElement()) {
454
0
                        if (strcmp(functionNode->Name(), "function") != 0) {
455
0
                            unknown_elements.insert(functionNode->Name());
456
0
                            continue;
457
0
                        }
458
459
0
                        const char* const functionName = functionNode->Attribute("name");
460
0
                        if (!functionName)
461
0
                            return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
462
463
0
                        const char* const action_ptr = functionNode->Attribute("action");
464
0
                        Container::Action action = Container::Action::NO_ACTION;
465
0
                        if (action_ptr) {
466
0
                            std::string actionName = action_ptr;
467
0
                            action = Container::actionFrom(actionName);
468
0
                            if (action == Container::Action::NO_ACTION)
469
0
                                return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, actionName);
470
0
                        }
471
472
0
                        const char* const yield_ptr = functionNode->Attribute("yields");
473
0
                        Container::Yield yield = Container::Yield::NO_YIELD;
474
0
                        if (yield_ptr) {
475
0
                            std::string yieldName = yield_ptr;
476
0
                            yield = Container::yieldFrom(yieldName);
477
0
                            if (yield == Container::Yield::NO_YIELD)
478
0
                                return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, yieldName);
479
0
                        }
480
481
0
                        const char* const returnType = functionNode->Attribute("returnType");
482
0
                        if (returnType)
483
0
                            container.functions[functionName].returnType = returnType;
484
485
0
                        container.functions[functionName].action = action;
486
0
                        container.functions[functionName].yield = yield;
487
0
                    }
488
489
0
                    if (containerNodeName == "size") {
490
0
                        const char* const templateArg = containerNode->Attribute("templateParameter");
491
0
                        if (templateArg)
492
0
                            container.size_templateArgNo = strToInt<int>(templateArg);
493
0
                    } else if (containerNodeName == "access") {
494
0
                        const char* const indexArg = containerNode->Attribute("indexOperator");
495
0
                        if (indexArg)
496
0
                            container.arrayLike_indexOp = strcmp(indexArg, "array-like") == 0;
497
0
                    }
498
0
                } else if (containerNodeName == "type") {
499
0
                    const char* const templateArg = containerNode->Attribute("templateParameter");
500
0
                    if (templateArg)
501
0
                        container.type_templateArgNo = strToInt<int>(templateArg);
502
503
0
                    const char* const string = containerNode->Attribute("string");
504
0
                    if (string)
505
0
                        container.stdStringLike = strcmp(string, "std-like") == 0;
506
0
                    const char* const associative = containerNode->Attribute("associative");
507
0
                    if (associative)
508
0
                        container.stdAssociativeLike = strcmp(associative, "std-like") == 0;
509
0
                    const char* const unstable = containerNode->Attribute("unstable");
510
0
                    if (unstable) {
511
0
                        std::string unstableType = unstable;
512
0
                        if (unstableType.find("erase") != std::string::npos)
513
0
                            container.unstableErase = true;
514
0
                        if (unstableType.find("insert") != std::string::npos)
515
0
                            container.unstableInsert = true;
516
0
                    }
517
0
                } else if (containerNodeName == "rangeItemRecordType") {
518
0
                    for (const tinyxml2::XMLElement* memberNode = node->FirstChildElement(); memberNode; memberNode = memberNode->NextSiblingElement()) {
519
0
                        const char *memberName = memberNode->Attribute("name");
520
0
                        const char *memberTemplateParameter = memberNode->Attribute("templateParameter");
521
0
                        struct Container::RangeItemRecordTypeItem member;
522
0
                        member.name = memberName ? memberName : "";
523
0
                        member.templateParameter = memberTemplateParameter ? strToInt<int>(memberTemplateParameter) : -1;
524
0
                        container.rangeItemRecordType.emplace_back(std::move(member));
525
0
                    }
526
0
                } else
527
0
                    unknown_elements.insert(containerNodeName);
528
0
            }
529
0
        }
530
531
0
        else if (nodename == "smart-pointer") {
532
0
            const char *className = node->Attribute("class-name");
533
0
            if (!className)
534
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "class-name");
535
0
            SmartPointer& smartPointer = smartPointers[className];
536
0
            smartPointer.name = className;
537
0
            for (const tinyxml2::XMLElement* smartPointerNode = node->FirstChildElement(); smartPointerNode;
538
0
                 smartPointerNode = smartPointerNode->NextSiblingElement()) {
539
0
                const std::string smartPointerNodeName = smartPointerNode->Name();
540
0
                if (smartPointerNodeName == "unique")
541
0
                    smartPointer.unique = true;
542
0
            }
543
0
        }
544
545
0
        else if (nodename == "type-checks") {
546
0
            for (const tinyxml2::XMLElement *checkNode = node->FirstChildElement(); checkNode; checkNode = checkNode->NextSiblingElement()) {
547
0
                const std::string &checkName = checkNode->Name();
548
0
                for (const tinyxml2::XMLElement *checkTypeNode = checkNode->FirstChildElement(); checkTypeNode; checkTypeNode = checkTypeNode->NextSiblingElement()) {
549
0
                    const std::string checkTypeName = checkTypeNode->Name();
550
0
                    const char *typeName = checkTypeNode->GetText();
551
0
                    if (!typeName)
552
0
                        continue;
553
0
                    if (checkTypeName == "check")
554
0
                        mTypeChecks[std::pair<std::string,std::string>(checkName, typeName)] = TypeCheck::check;
555
0
                    else if (checkTypeName == "suppress")
556
0
                        mTypeChecks[std::pair<std::string,std::string>(checkName, typeName)] = TypeCheck::suppress;
557
0
                    else if (checkTypeName == "checkFiniteLifetime")
558
0
                        mTypeChecks[std::pair<std::string,std::string>(checkName, typeName)] = TypeCheck::checkFiniteLifetime;
559
0
                }
560
0
            }
561
0
        }
562
563
0
        else if (nodename == "podtype") {
564
0
            const char * const name = node->Attribute("name");
565
0
            if (!name)
566
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
567
0
            PodType podType = {0};
568
0
            podType.stdtype = PodType::Type::NO;
569
0
            const char * const stdtype = node->Attribute("stdtype");
570
0
            if (stdtype) {
571
0
                if (std::strcmp(stdtype, "bool") == 0)
572
0
                    podType.stdtype = PodType::Type::BOOL;
573
0
                else if (std::strcmp(stdtype, "char") == 0)
574
0
                    podType.stdtype = PodType::Type::CHAR;
575
0
                else if (std::strcmp(stdtype, "short") == 0)
576
0
                    podType.stdtype = PodType::Type::SHORT;
577
0
                else if (std::strcmp(stdtype, "int") == 0)
578
0
                    podType.stdtype = PodType::Type::INT;
579
0
                else if (std::strcmp(stdtype, "long") == 0)
580
0
                    podType.stdtype = PodType::Type::LONG;
581
0
                else if (std::strcmp(stdtype, "long long") == 0)
582
0
                    podType.stdtype = PodType::Type::LONGLONG;
583
0
            }
584
0
            const char * const size = node->Attribute("size");
585
0
            if (size)
586
0
                podType.size = strToInt<unsigned int>(size);
587
0
            const char * const sign = node->Attribute("sign");
588
0
            if (sign)
589
0
                podType.sign = *sign;
590
0
            for (const std::string &s : getnames(name))
591
0
                mPodTypes[s] = podType;
592
0
        }
593
594
0
        else if (nodename == "platformtype") {
595
0
            const char * const type_name = node->Attribute("name");
596
0
            if (type_name == nullptr)
597
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
598
0
            const char *value = node->Attribute("value");
599
0
            if (value == nullptr)
600
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "value");
601
0
            PlatformType type;
602
0
            type.mType = value;
603
0
            std::set<std::string> platform;
604
0
            for (const tinyxml2::XMLElement *typenode = node->FirstChildElement(); typenode; typenode = typenode->NextSiblingElement()) {
605
0
                const std::string typenodename = typenode->Name();
606
0
                if (typenodename == "platform") {
607
0
                    const char * const type_attribute = typenode->Attribute("type");
608
0
                    if (type_attribute == nullptr)
609
0
                        return Error(ErrorCode::MISSING_ATTRIBUTE, "type");
610
0
                    platform.insert(type_attribute);
611
0
                } else if (typenodename == "signed")
612
0
                    type.mSigned = true;
613
0
                else if (typenodename == "unsigned")
614
0
                    type.mUnsigned = true;
615
0
                else if (typenodename == "long")
616
0
                    type.mLong = true;
617
0
                else if (typenodename == "pointer")
618
0
                    type.mPointer= true;
619
0
                else if (typenodename == "ptr_ptr")
620
0
                    type.mPtrPtr = true;
621
0
                else if (typenodename == "const_ptr")
622
0
                    type.mConstPtr = true;
623
0
                else
624
0
                    unknown_elements.insert(typenodename);
625
0
            }
626
0
            if (platform.empty()) {
627
0
                const PlatformType * const type_ptr = platform_type(type_name, emptyString);
628
0
                if (type_ptr) {
629
0
                    if (*type_ptr == type)
630
0
                        return Error(ErrorCode::DUPLICATE_PLATFORM_TYPE, type_name);
631
0
                    return Error(ErrorCode::PLATFORM_TYPE_REDEFINED, type_name);
632
0
                }
633
0
                mPlatformTypes[type_name] = type;
634
0
            } else {
635
0
                for (const std::string &p : platform) {
636
0
                    const PlatformType * const type_ptr = platform_type(type_name, p);
637
0
                    if (type_ptr) {
638
0
                        if (*type_ptr == type)
639
0
                            return Error(ErrorCode::DUPLICATE_PLATFORM_TYPE, type_name);
640
0
                        return Error(ErrorCode::PLATFORM_TYPE_REDEFINED, type_name);
641
0
                    }
642
0
                    mPlatforms[p].mPlatformTypes[type_name] = type;
643
0
                }
644
0
            }
645
0
        }
646
647
0
        else if (nodename == "entrypoint") {
648
0
            const char * const type_name = node->Attribute("name");
649
0
            if (type_name == nullptr)
650
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
651
0
            mEntrypoints.emplace(type_name);
652
0
        }
653
654
0
        else
655
0
            unknown_elements.insert(nodename);
656
0
    }
657
0
    if (!unknown_elements.empty()) {
658
0
        std::string str;
659
0
        for (std::set<std::string>::const_iterator i = unknown_elements.cbegin(); i != unknown_elements.cend();) {
660
0
            str += *i;
661
0
            if (++i != unknown_elements.end())
662
0
                str += ", ";
663
0
        }
664
0
        return Error(ErrorCode::UNKNOWN_ELEMENT, str);
665
0
    }
666
0
    return Error(ErrorCode::OK);
667
0
}
668
669
Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, const std::string &name, std::set<std::string> &unknown_elements)
670
0
{
671
0
    if (name.empty())
672
0
        return Error(ErrorCode::OK);
673
674
    // TODO: write debug warning if we modify an existing entry
675
0
    Function& func = functions[name];
676
677
0
    for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) {
678
0
        const std::string functionnodename = functionnode->Name();
679
0
        if (functionnodename == "noreturn") {
680
0
            const char * const text = functionnode->GetText();
681
0
            if (strcmp(text, "false") == 0)
682
0
                mNoReturn[name] = FalseTrueMaybe::False;
683
0
            else if (strcmp(text, "maybe") == 0)
684
0
                mNoReturn[name] = FalseTrueMaybe::Maybe;
685
0
            else
686
0
                mNoReturn[name] = FalseTrueMaybe::True; // Safe
687
0
        } else if (functionnodename == "pure")
688
0
            func.ispure = true;
689
0
        else if (functionnodename == "const") {
690
0
            func.ispure = true;
691
0
            func.isconst = true; // a constant function is pure
692
0
        } else if (functionnodename == "leak-ignore")
693
0
            func.leakignore = true;
694
0
        else if (functionnodename == "not-overlapping-data") {
695
0
            NonOverlappingData nonOverlappingData;
696
0
            nonOverlappingData.ptr1Arg = functionnode->IntAttribute("ptr1-arg", -1);
697
0
            nonOverlappingData.ptr2Arg = functionnode->IntAttribute("ptr2-arg", -1);
698
0
            nonOverlappingData.sizeArg = functionnode->IntAttribute("size-arg", -1);
699
0
            nonOverlappingData.strlenArg = functionnode->IntAttribute("strlen-arg", -1);
700
0
            mNonOverlappingData[name] = nonOverlappingData;
701
0
        } else if (functionnodename == "use-retval") {
702
0
            func.useretval = Library::UseRetValType::DEFAULT;
703
0
            if (const char *type = functionnode->Attribute("type"))
704
0
                if (std::strcmp(type, "error-code") == 0)
705
0
                    func.useretval = Library::UseRetValType::ERROR_CODE;
706
0
        } else if (functionnodename == "returnValue") {
707
0
            if (const char *expr = functionnode->GetText())
708
0
                mReturnValue[name] = expr;
709
0
            if (const char *type = functionnode->Attribute("type"))
710
0
                mReturnValueType[name] = type;
711
0
            if (const char *container = functionnode->Attribute("container"))
712
0
                mReturnValueContainer[name] = strToInt<int>(container);
713
0
            if (const char *unknownReturnValues = functionnode->Attribute("unknownValues")) {
714
0
                if (std::strcmp(unknownReturnValues, "all") == 0) {
715
0
                    std::vector<MathLib::bigint> values{LLONG_MIN, LLONG_MAX};
716
0
                    mUnknownReturnValues[name] = values;
717
0
                }
718
0
            }
719
0
        } else if (functionnodename == "arg") {
720
0
            const char* argNrString = functionnode->Attribute("nr");
721
0
            if (!argNrString)
722
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "nr");
723
0
            const bool bAnyArg = strcmp(argNrString, "any") == 0;
724
0
            const bool bVariadicArg = strcmp(argNrString, "variadic") == 0;
725
0
            const int nr = (bAnyArg || bVariadicArg) ? -1 : strToInt<int>(argNrString);
726
0
            ArgumentChecks &ac = func.argumentChecks[nr];
727
0
            ac.optional  = functionnode->Attribute("default") != nullptr;
728
0
            ac.variadic = bVariadicArg;
729
0
            const char * const argDirection = functionnode->Attribute("direction");
730
0
            if (argDirection) {
731
0
                const size_t argDirLen = strlen(argDirection);
732
0
                if (!strncmp(argDirection, "in", argDirLen)) {
733
0
                    ac.direction = ArgumentChecks::Direction::DIR_IN;
734
0
                } else if (!strncmp(argDirection, "out", argDirLen)) {
735
0
                    ac.direction = ArgumentChecks::Direction::DIR_OUT;
736
0
                } else if (!strncmp(argDirection, "inout", argDirLen)) {
737
0
                    ac.direction = ArgumentChecks::Direction::DIR_INOUT;
738
0
                }
739
0
            }
740
0
            for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
741
0
                const std::string argnodename = argnode->Name();
742
0
                int indirect = 0;
743
0
                const char * const indirectStr = argnode->Attribute("indirect");
744
0
                if (indirectStr)
745
0
                    indirect = strToInt<int>(indirectStr);
746
0
                if (argnodename == "not-bool")
747
0
                    ac.notbool = true;
748
0
                else if (argnodename == "not-null")
749
0
                    ac.notnull = true;
750
0
                else if (argnodename == "not-uninit")
751
0
                    ac.notuninit = indirect;
752
0
                else if (argnodename == "formatstr")
753
0
                    ac.formatstr = true;
754
0
                else if (argnodename == "strz")
755
0
                    ac.strz = true;
756
0
                else if (argnodename == "valid") {
757
                    // Validate the validation expression
758
0
                    const char *p = argnode->GetText();
759
0
                    if (!isCompliantValidationExpression(p))
760
0
                        return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, (!p ? "\"\"" : p));
761
                    // Set validation expression
762
0
                    ac.valid = p;
763
0
                }
764
0
                else if (argnodename == "minsize") {
765
0
                    const char *typeattr = argnode->Attribute("type");
766
0
                    if (!typeattr)
767
0
                        return Error(ErrorCode::MISSING_ATTRIBUTE, "type");
768
769
0
                    ArgumentChecks::MinSize::Type type;
770
0
                    if (strcmp(typeattr,"strlen")==0)
771
0
                        type = ArgumentChecks::MinSize::Type::STRLEN;
772
0
                    else if (strcmp(typeattr,"argvalue")==0)
773
0
                        type = ArgumentChecks::MinSize::Type::ARGVALUE;
774
0
                    else if (strcmp(typeattr,"sizeof")==0)
775
0
                        type = ArgumentChecks::MinSize::Type::SIZEOF;
776
0
                    else if (strcmp(typeattr,"mul")==0)
777
0
                        type = ArgumentChecks::MinSize::Type::MUL;
778
0
                    else if (strcmp(typeattr,"value")==0)
779
0
                        type = ArgumentChecks::MinSize::Type::VALUE;
780
0
                    else
781
0
                        return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, typeattr);
782
783
0
                    if (type == ArgumentChecks::MinSize::Type::VALUE) {
784
0
                        const char *valueattr = argnode->Attribute("value");
785
0
                        if (!valueattr)
786
0
                            return Error(ErrorCode::MISSING_ATTRIBUTE, "value");
787
0
                        long long minsizevalue = 0;
788
0
                        try {
789
0
                            minsizevalue = strToInt<long long>(valueattr);
790
0
                        } catch (const std::runtime_error&) {
791
0
                            return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, valueattr);
792
0
                        }
793
0
                        if (minsizevalue <= 0)
794
0
                            return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, valueattr);
795
0
                        ac.minsizes.emplace_back(type, 0);
796
0
                        ac.minsizes.back().value = minsizevalue;
797
0
                    } else {
798
0
                        const char *argattr = argnode->Attribute("arg");
799
0
                        if (!argattr)
800
0
                            return Error(ErrorCode::MISSING_ATTRIBUTE, "arg");
801
0
                        if (strlen(argattr) != 1 || argattr[0]<'0' || argattr[0]>'9')
802
0
                            return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, argattr);
803
804
0
                        ac.minsizes.reserve(type == ArgumentChecks::MinSize::Type::MUL ? 2 : 1);
805
0
                        ac.minsizes.emplace_back(type, argattr[0] - '0');
806
0
                        if (type == ArgumentChecks::MinSize::Type::MUL) {
807
0
                            const char *arg2attr = argnode->Attribute("arg2");
808
0
                            if (!arg2attr)
809
0
                                return Error(ErrorCode::MISSING_ATTRIBUTE, "arg2");
810
0
                            if (strlen(arg2attr) != 1 || arg2attr[0]<'0' || arg2attr[0]>'9')
811
0
                                return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, arg2attr);
812
0
                            ac.minsizes.back().arg2 = arg2attr[0] - '0';
813
0
                        }
814
0
                    }
815
0
                    const char* baseTypeAttr = argnode->Attribute("baseType"); // used by VALUE, ARGVALUE
816
0
                    if (baseTypeAttr)
817
0
                        ac.minsizes.back().baseType = baseTypeAttr;
818
0
                }
819
820
0
                else if (argnodename == "iterator") {
821
0
                    ac.iteratorInfo.it = true;
822
0
                    const char* str = argnode->Attribute("type");
823
0
                    ac.iteratorInfo.first = (str && std::strcmp(str, "first") == 0);
824
0
                    ac.iteratorInfo.last = (str && std::strcmp(str, "last") == 0);
825
0
                    ac.iteratorInfo.container = argnode->IntAttribute("container", 0);
826
0
                }
827
828
0
                else
829
0
                    unknown_elements.insert(argnodename);
830
0
            }
831
0
            if (ac.notuninit == 0)
832
0
                ac.notuninit = ac.notnull ? 1 : 0;
833
0
        } else if (functionnodename == "ignorefunction") {
834
0
            func.ignore = true;
835
0
        } else if (functionnodename == "formatstr") {
836
0
            func.formatstr = true;
837
0
            const tinyxml2::XMLAttribute* scan = functionnode->FindAttribute("scan");
838
0
            const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure");
839
0
            func.formatstr_scan = scan && scan->BoolValue();
840
0
            func.formatstr_secure = secure && secure->BoolValue();
841
0
        } else if (functionnodename == "warn") {
842
0
            WarnInfo wi;
843
0
            const char* const severity = functionnode->Attribute("severity");
844
0
            if (severity == nullptr)
845
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "severity");
846
0
            wi.severity = Severity::fromString(severity);
847
848
0
            const char* const cstd = functionnode->Attribute("cstd");
849
0
            if (cstd) {
850
0
                if (!wi.standards.setC(cstd))
851
0
                    return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, cstd);
852
0
            } else
853
0
                wi.standards.c = Standards::C89;
854
855
0
            const char* const cppstd = functionnode->Attribute("cppstd");
856
0
            if (cppstd) {
857
0
                if (!wi.standards.setCPP(cppstd))
858
0
                    return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, cppstd);
859
0
            } else
860
0
                wi.standards.cpp = Standards::CPP03;
861
862
0
            const char* const reason = functionnode->Attribute("reason");
863
0
            const char* const alternatives = functionnode->Attribute("alternatives");
864
0
            if (reason && alternatives) {
865
                // Construct message
866
0
                wi.message = std::string(reason) + " function '" + name + "' called. It is recommended to use ";
867
0
                std::vector<std::string> alt = getnames(alternatives);
868
0
                for (std::size_t i = 0; i < alt.size(); ++i) {
869
0
                    wi.message += "'" + alt[i] + "'";
870
0
                    if (i == alt.size() - 1)
871
0
                        wi.message += " instead.";
872
0
                    else if (i == alt.size() - 2)
873
0
                        wi.message += " or ";
874
0
                    else
875
0
                        wi.message += ", ";
876
0
                }
877
0
            } else {
878
0
                const char * const message = functionnode->GetText();
879
0
                if (!message)
880
0
                    return Error(ErrorCode::MISSING_ATTRIBUTE, "\"reason\" and \"alternatives\" or some text.");
881
882
0
                wi.message = message;
883
0
            }
884
885
0
            functionwarn[name] = wi;
886
0
        } else if (functionnodename == "container") {
887
0
            const char* const action_ptr = functionnode->Attribute("action");
888
0
            Container::Action action = Container::Action::NO_ACTION;
889
0
            if (action_ptr) {
890
0
                std::string actionName = action_ptr;
891
0
                action = Container::actionFrom(actionName);
892
0
                if (action == Container::Action::NO_ACTION)
893
0
                    return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, actionName);
894
0
            }
895
0
            func.containerAction = action;
896
897
0
            const char* const yield_ptr = functionnode->Attribute("yields");
898
0
            Container::Yield yield = Container::Yield::NO_YIELD;
899
0
            if (yield_ptr) {
900
0
                std::string yieldName = yield_ptr;
901
0
                yield = Container::yieldFrom(yieldName);
902
0
                if (yield == Container::Yield::NO_YIELD)
903
0
                    return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, yieldName);
904
0
            }
905
0
            func.containerYield = yield;
906
907
0
            const char* const returnType = functionnode->Attribute("returnType");
908
0
            if (returnType)
909
0
                func.returnType = returnType;
910
0
        } else
911
0
            unknown_elements.insert(functionnodename);
912
0
    }
913
0
    return Error(ErrorCode::OK);
914
0
}
915
916
bool Library::isIntArgValid(const Token *ftok, int argnr, const MathLib::bigint argvalue) const
917
2.27k
{
918
2.27k
    const ArgumentChecks *ac = getarg(ftok, argnr);
919
2.27k
    if (!ac || ac->valid.empty())
920
2.27k
        return true;
921
0
    if (ac->valid.find('.') != std::string::npos)
922
0
        return isFloatArgValid(ftok, argnr, argvalue);
923
0
    TokenList tokenList(nullptr);
924
0
    gettokenlistfromvalid(ac->valid, tokenList);
925
0
    for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
926
0
        if (tok->isNumber() && argvalue == MathLib::toLongNumber(tok->str()))
927
0
            return true;
928
0
        if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toLongNumber(tok->str()) && argvalue <= MathLib::toLongNumber(tok->strAt(2)))
929
0
            return true;
930
0
        if (Token::Match(tok, "%num% : ,") && argvalue >= MathLib::toLongNumber(tok->str()))
931
0
            return true;
932
0
        if ((!tok->previous() || tok->previous()->str() == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toLongNumber(tok->strAt(1)))
933
0
            return true;
934
0
    }
935
0
    return false;
936
0
}
937
938
bool Library::isFloatArgValid(const Token *ftok, int argnr, double argvalue) const
939
0
{
940
0
    const ArgumentChecks *ac = getarg(ftok, argnr);
941
0
    if (!ac || ac->valid.empty())
942
0
        return true;
943
0
    TokenList tokenList(nullptr);
944
0
    gettokenlistfromvalid(ac->valid, tokenList);
945
0
    for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
946
0
        if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toDoubleNumber(tok->str()) && argvalue <= MathLib::toDoubleNumber(tok->strAt(2)))
947
0
            return true;
948
0
        if (Token::Match(tok, "%num% : ,") && argvalue >= MathLib::toDoubleNumber(tok->str()))
949
0
            return true;
950
0
        if ((!tok->previous() || tok->previous()->str() == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toDoubleNumber(tok->strAt(1)))
951
0
            return true;
952
0
        if (Token::Match(tok, "%num%") && MathLib::isFloat(tok->str()) && MathLib::isEqual(tok->str(), MathLib::toString(argvalue)))
953
0
            return true;
954
0
        if (Token::Match(tok, "! %num%") && MathLib::isFloat(tok->next()->str()))
955
0
            return MathLib::isNotEqual(tok->next()->str(), MathLib::toString(argvalue));
956
0
    }
957
0
    return false;
958
0
}
959
960
std::string Library::getFunctionName(const Token *ftok, bool &error) const
961
4.92k
{
962
4.92k
    if (!ftok) {
963
0
        error = true;
964
0
        return "";
965
0
    }
966
4.92k
    if (ftok->isName()) {
967
17.1k
        for (const Scope *scope = ftok->scope(); scope; scope = scope->nestedIn) {
968
12.1k
            if (!scope->isClassOrStruct())
969
12.1k
                continue;
970
0
            const std::vector<Type::BaseInfo> &derivedFrom = scope->definedType->derivedFrom;
971
0
            for (const Type::BaseInfo & baseInfo : derivedFrom) {
972
0
                std::string name;
973
0
                const Token* tok = baseInfo.nameTok; // baseInfo.name still contains template parameters, but is missing namespaces
974
0
                if (tok->str() == "::")
975
0
                    tok = tok->next();
976
0
                while (Token::Match(tok, "%name%|::")) {
977
0
                    name += tok->str();
978
0
                    tok = tok->next();
979
0
                }
980
0
                name += "::" + ftok->str();
981
0
                if (functions.find(name) != functions.end() && matchArguments(ftok, name))
982
0
                    return name;
983
0
            }
984
0
        }
985
4.92k
        return ftok->str();
986
4.92k
    }
987
0
    if (ftok->str() == "::") {
988
0
        if (!ftok->astOperand2())
989
0
            return getFunctionName(ftok->astOperand1(), error);
990
0
        return getFunctionName(ftok->astOperand1(),error) + "::" + getFunctionName(ftok->astOperand2(),error);
991
0
    }
992
0
    if (ftok->str() == "." && ftok->astOperand1()) {
993
0
        const std::string type = astCanonicalType(ftok->astOperand1(), ftok->originalName() == "->");
994
0
        if (type.empty()) {
995
0
            error = true;
996
0
            return "";
997
0
        }
998
999
0
        return type + "::" + getFunctionName(ftok->astOperand2(),error);
1000
0
    }
1001
0
    error = true;
1002
0
    return "";
1003
0
}
1004
1005
std::string Library::getFunctionName(const Token *ftok) const
1006
46.3k
{
1007
46.3k
    if (!Token::Match(ftok, "%name% )| (") && (ftok->strAt(-1) != "&" || ftok->previous()->astOperand2()))
1008
37.7k
        return "";
1009
1010
    // Lookup function name using AST..
1011
8.61k
    if (ftok->astParent()) {
1012
4.92k
        bool error = false;
1013
4.92k
        const Token * tok = ftok->astParent()->isUnaryOp("&") ? ftok->astParent()->astOperand1() : ftok->next()->astOperand1();
1014
4.92k
        const std::string ret = getFunctionName(tok, error);
1015
4.92k
        return error ? std::string() : ret;
1016
4.92k
    }
1017
1018
    // Lookup function name without using AST..
1019
3.68k
    if (Token::simpleMatch(ftok->previous(), "."))
1020
0
        return "";
1021
3.68k
    if (!Token::Match(ftok->tokAt(-2), "%name% ::"))
1022
3.68k
        return ftok->str();
1023
0
    std::string ret(ftok->str());
1024
0
    ftok = ftok->tokAt(-2);
1025
0
    while (Token::Match(ftok, "%name% ::")) {
1026
0
        ret = ftok->str() + "::" + ret;
1027
0
        ftok = ftok->tokAt(-2);
1028
0
    }
1029
0
    return ret;
1030
3.68k
}
1031
1032
bool Library::isnullargbad(const Token *ftok, int argnr) const
1033
1.38k
{
1034
1.38k
    const ArgumentChecks *arg = getarg(ftok, argnr);
1035
1.38k
    if (!arg) {
1036
        // scan format string argument should not be null
1037
1.38k
        const std::string funcname = getFunctionName(ftok);
1038
1.38k
        const std::unordered_map<std::string, Function>::const_iterator it = functions.find(funcname);
1039
1.38k
        if (it != functions.cend() && it->second.formatstr && it->second.formatstr_scan)
1040
0
            return true;
1041
1.38k
    }
1042
1.38k
    return arg && arg->notnull;
1043
1.38k
}
1044
1045
bool Library::isuninitargbad(const Token *ftok, int argnr, int indirect, bool *hasIndirect) const
1046
0
{
1047
0
    const ArgumentChecks *arg = getarg(ftok, argnr);
1048
0
    if (!arg) {
1049
        // non-scan format string argument should not be uninitialized
1050
0
        const std::string funcname = getFunctionName(ftok);
1051
0
        const std::unordered_map<std::string, Function>::const_iterator it = functions.find(funcname);
1052
0
        if (it != functions.cend() && it->second.formatstr && !it->second.formatstr_scan)
1053
0
            return true;
1054
0
    }
1055
0
    if (hasIndirect && arg && arg->notuninit >= 1)
1056
0
        *hasIndirect = true;
1057
0
    return arg && arg->notuninit >= indirect;
1058
0
}
1059
1060
1061
/** get allocation info for function */
1062
const Library::AllocFunc* Library::getAllocFuncInfo(const Token *tok) const
1063
2.23k
{
1064
2.23k
    const std::string funcname = getFunctionName(tok);
1065
2.23k
    return isNotLibraryFunction(tok) && functions.find(funcname) != functions.end() ? nullptr : getAllocDealloc(mAlloc, funcname);
1066
2.23k
}
1067
1068
/** get deallocation info for function */
1069
const Library::AllocFunc* Library::getDeallocFuncInfo(const Token *tok) const
1070
56
{
1071
56
    const std::string funcname = getFunctionName(tok);
1072
56
    return isNotLibraryFunction(tok) && functions.find(funcname) != functions.end() ? nullptr : getAllocDealloc(mDealloc, funcname);
1073
56
}
1074
1075
/** get reallocation info for function */
1076
const Library::AllocFunc* Library::getReallocFuncInfo(const Token *tok) const
1077
2.27k
{
1078
2.27k
    const std::string funcname = getFunctionName(tok);
1079
2.27k
    return isNotLibraryFunction(tok) && functions.find(funcname) != functions.end() ? nullptr : getAllocDealloc(mRealloc, funcname);
1080
2.27k
}
1081
1082
/** get allocation id for function */
1083
int Library::getAllocId(const Token *tok, int arg) const
1084
1.46k
{
1085
1.46k
    const Library::AllocFunc* af = getAllocFuncInfo(tok);
1086
1.46k
    return (af && af->arg == arg) ? af->groupId : 0;
1087
1.46k
}
1088
1089
/** get deallocation id for function */
1090
int Library::getDeallocId(const Token *tok, int arg) const
1091
0
{
1092
0
    const Library::AllocFunc* af = getDeallocFuncInfo(tok);
1093
0
    return (af && af->arg == arg) ? af->groupId : 0;
1094
0
}
1095
1096
/** get reallocation id for function */
1097
int Library::getReallocId(const Token *tok, int arg) const
1098
0
{
1099
0
    const Library::AllocFunc* af = getReallocFuncInfo(tok);
1100
0
    return (af && af->arg == arg) ? af->groupId : 0;
1101
0
}
1102
1103
1104
const Library::ArgumentChecks * Library::getarg(const Token *ftok, int argnr) const
1105
7.46k
{
1106
7.46k
    if (isNotLibraryFunction(ftok))
1107
7.46k
        return nullptr;
1108
0
    const std::unordered_map<std::string, Function>::const_iterator it1 = functions.find(getFunctionName(ftok));
1109
0
    if (it1 == functions.cend())
1110
0
        return nullptr;
1111
0
    const std::map<int,ArgumentChecks>::const_iterator it2 = it1->second.argumentChecks.find(argnr);
1112
0
    if (it2 != it1->second.argumentChecks.cend())
1113
0
        return &it2->second;
1114
0
    const std::map<int,ArgumentChecks>::const_iterator it3 = it1->second.argumentChecks.find(-1);
1115
0
    if (it3 != it1->second.argumentChecks.cend())
1116
0
        return &it3->second;
1117
0
    return nullptr;
1118
0
}
1119
1120
bool Library::isScopeNoReturn(const Token *end, std::string *unknownFunc) const
1121
89
{
1122
89
    if (unknownFunc)
1123
89
        unknownFunc->clear();
1124
1125
89
    if (Token::Match(end->tokAt(-2), "!!{ ; }")) {
1126
3
        const Token *lastTop = end->tokAt(-2)->astTop();
1127
3
        if (Token::simpleMatch(lastTop, "<<") &&
1128
3
            Token::simpleMatch(lastTop->astOperand1(), "(") &&
1129
3
            Token::Match(lastTop->astOperand1()->previous(), "%name% ("))
1130
0
            return isnoreturn(lastTop->astOperand1()->previous());
1131
3
    }
1132
1133
89
    if (!Token::simpleMatch(end->tokAt(-2), ") ; }"))
1134
89
        return false;
1135
1136
0
    const Token *funcname = end->linkAt(-2)->previous();
1137
0
    const Token *start = funcname;
1138
0
    if (Token::Match(funcname->tokAt(-3),"( * %name% )")) {
1139
0
        funcname = funcname->previous();
1140
0
        start = funcname->tokAt(-3);
1141
0
    } else if (funcname->isName()) {
1142
0
        while (Token::Match(start, "%name%|.|::"))
1143
0
            start = start->previous();
1144
0
    } else {
1145
0
        return false;
1146
0
    }
1147
0
    if (Token::Match(start,"[;{}]") && Token::Match(funcname, "%name% )| (")) {
1148
0
        if (funcname->isKeyword())
1149
0
            return false;
1150
0
        if (funcname->str() == "exit")
1151
0
            return true;
1152
0
        if (!isnotnoreturn(funcname)) {
1153
0
            if (unknownFunc && !isnoreturn(funcname))
1154
0
                *unknownFunc = funcname->str();
1155
0
            return true;
1156
0
        }
1157
0
    }
1158
0
    return false;
1159
0
}
1160
1161
const Library::Container* Library::detectContainerInternal(const Token* const typeStart, DetectContainer detect, bool* isIterator, bool withoutStd) const
1162
119k
{
1163
119k
    const Token* firstLinkedTok = nullptr;
1164
252k
    for (const Token* tok = typeStart; tok && !tok->varId(); tok = tok->next()) {
1165
159k
        if (!tok->link())
1166
133k
            continue;
1167
1168
26.2k
        firstLinkedTok = tok;
1169
26.2k
        break;
1170
159k
    }
1171
1172
119k
    for (const std::pair<const std::string, Library::Container> & c : containers) {
1173
0
        const Container& container = c.second;
1174
0
        if (container.startPattern.empty())
1175
0
            continue;
1176
1177
0
        const int offset = (withoutStd && startsWith(container.startPattern2, "std :: ")) ? 7 : 0;
1178
1179
        // If endPattern is undefined, it will always match, but itEndPattern has to be defined.
1180
0
        if (detect != IteratorOnly && container.endPattern.empty()) {
1181
0
            if (!Token::Match(typeStart, container.startPattern2.c_str() + offset))
1182
0
                continue;
1183
1184
0
            if (isIterator)
1185
0
                *isIterator = false;
1186
0
            return &container;
1187
0
        }
1188
1189
0
        if (!firstLinkedTok)
1190
0
            continue;
1191
1192
0
        const bool matchedStartPattern = Token::Match(typeStart, container.startPattern2.c_str() + offset);
1193
0
        if (!matchedStartPattern)
1194
0
            continue;
1195
1196
0
        if (detect != ContainerOnly && Token::Match(firstLinkedTok->link(), container.itEndPattern.c_str())) {
1197
0
            if (isIterator)
1198
0
                *isIterator = true;
1199
0
            return &container;
1200
0
        }
1201
0
        if (detect != IteratorOnly && Token::Match(firstLinkedTok->link(), container.endPattern.c_str())) {
1202
0
            if (isIterator)
1203
0
                *isIterator = false;
1204
0
            return &container;
1205
0
        }
1206
0
    }
1207
119k
    return nullptr;
1208
119k
}
1209
1210
const Library::Container* Library::detectContainer(const Token* typeStart) const
1211
6.80k
{
1212
6.80k
    return detectContainerInternal(typeStart, ContainerOnly);
1213
6.80k
}
1214
1215
const Library::Container* Library::detectIterator(const Token* typeStart) const
1216
0
{
1217
0
    return detectContainerInternal(typeStart, IteratorOnly);
1218
0
}
1219
1220
const Library::Container* Library::detectContainerOrIterator(const Token* typeStart, bool* isIterator, bool withoutStd) const
1221
112k
{
1222
112k
    bool res;
1223
112k
    const Library::Container* c = detectContainerInternal(typeStart, Both, &res, withoutStd);
1224
112k
    if (c && isIterator)
1225
0
        *isIterator = res;
1226
112k
    return c;
1227
112k
}
1228
1229
bool Library::isContainerYield(const Token * const cond, Library::Container::Yield y, const std::string& fallback)
1230
444
{
1231
444
    if (!cond)
1232
0
        return false;
1233
444
    if (cond->str() == "(") {
1234
0
        const Token* tok = cond->astOperand1();
1235
0
        if (tok && tok->str() == ".") {
1236
0
            if (tok->astOperand1() && tok->astOperand1()->valueType()) {
1237
0
                if (const Library::Container *container = tok->astOperand1()->valueType()->container) {
1238
0
                    return tok->astOperand2() && y == container->getYield(tok->astOperand2()->str());
1239
0
                }
1240
0
            } else if (!fallback.empty()) {
1241
0
                return Token::simpleMatch(cond, "( )") && cond->previous()->str() == fallback;
1242
0
            }
1243
0
        }
1244
0
    }
1245
444
    return false;
1246
444
}
1247
1248
// returns true if ftok is not a library function
1249
bool Library::isNotLibraryFunction(const Token *ftok) const
1250
89.1k
{
1251
89.1k
    if (ftok->isKeyword() || ftok->isStandardType())
1252
35.5k
        return true;
1253
1254
53.5k
    if (ftok->function() && ftok->function()->nestedIn && ftok->function()->nestedIn->type != Scope::eGlobal)
1255
0
        return true;
1256
1257
    // variables are not library functions.
1258
53.5k
    if (ftok->varId())
1259
13.1k
        return true;
1260
1261
40.4k
    return !matchArguments(ftok, getFunctionName(ftok));
1262
53.5k
}
1263
1264
bool Library::matchArguments(const Token *ftok, const std::string &functionName) const
1265
40.4k
{
1266
40.4k
    if (functionName.empty())
1267
36.9k
        return false;
1268
3.48k
    const int callargs = numberOfArgumentsWithoutAst(ftok);
1269
3.48k
    const std::unordered_map<std::string, Function>::const_iterator it = functions.find(functionName);
1270
3.48k
    if (it == functions.cend())
1271
3.48k
        return false;
1272
0
    int args = 0;
1273
0
    int firstOptionalArg = -1;
1274
0
    for (const std::pair<const int, Library::ArgumentChecks> & argCheck : it->second.argumentChecks) {
1275
0
        if (argCheck.first > args)
1276
0
            args = argCheck.first;
1277
0
        if (argCheck.second.optional && (firstOptionalArg == -1 || firstOptionalArg > argCheck.first))
1278
0
            firstOptionalArg = argCheck.first;
1279
1280
0
        if (argCheck.second.formatstr || argCheck.second.variadic)
1281
0
            return args <= callargs;
1282
0
    }
1283
0
    return (firstOptionalArg < 0) ? args == callargs : (callargs >= firstOptionalArg-1 && callargs <= args);
1284
0
}
1285
1286
const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
1287
7.68k
{
1288
7.68k
    if (isNotLibraryFunction(ftok))
1289
7.68k
        return nullptr;
1290
0
    const std::map<std::string, WarnInfo>::const_iterator i = functionwarn.find(getFunctionName(ftok));
1291
0
    if (i == functionwarn.cend())
1292
0
        return nullptr;
1293
0
    return &i->second;
1294
0
}
1295
1296
bool Library::isCompliantValidationExpression(const char* p)
1297
0
{
1298
0
    if (!p || !*p)
1299
0
        return false;
1300
1301
0
    bool error = false;
1302
0
    bool range = false;
1303
0
    bool has_dot = false;
1304
0
    bool has_E = false;
1305
1306
0
    error = *p == '.';
1307
0
    for (; *p; p++) {
1308
0
        if (std::isdigit(*p)) {
1309
0
            error |= (*(p + 1) == '-');
1310
0
        }
1311
0
        else if (*p == ':') {
1312
0
            error |= range | (*(p + 1) == '.');
1313
0
            range = true;
1314
0
            has_dot = false;
1315
0
            has_E = false;
1316
0
        }
1317
0
        else if ((*p == '-') || (*p == '+')) {
1318
0
            error |= (!std::isdigit(*(p + 1)));
1319
0
        }
1320
0
        else if (*p == ',') {
1321
0
            range = false;
1322
0
            error |= *(p + 1) == '.';
1323
0
            has_dot = false;
1324
0
            has_E = false;
1325
0
        } else if (*p == '.') {
1326
0
            error |= has_dot | (!std::isdigit(*(p + 1)));
1327
0
            has_dot = true;
1328
0
        } else if (*p == 'E' || *p == 'e') {
1329
0
            error |= has_E;
1330
0
            has_E = true;
1331
0
        } else if (*p == '!') {
1332
0
            error |= !((*(p+1) == '-') || (*(p+1) == '+') || (std::isdigit(*(p + 1))));
1333
0
        } else
1334
0
            return false;
1335
0
    }
1336
0
    return !error;
1337
0
}
1338
1339
bool Library::formatstr_function(const Token* ftok) const
1340
3.37k
{
1341
3.37k
    if (isNotLibraryFunction(ftok))
1342
3.37k
        return false;
1343
1344
0
    const std::unordered_map<std::string, Function>::const_iterator it = functions.find(getFunctionName(ftok));
1345
0
    if (it != functions.cend())
1346
0
        return it->second.formatstr;
1347
0
    return false;
1348
0
}
1349
1350
int Library::formatstr_argno(const Token* ftok) const
1351
0
{
1352
0
    const std::map<int, Library::ArgumentChecks>& argumentChecksFunc = functions.at(getFunctionName(ftok)).argumentChecks;
1353
0
    auto it = std::find_if(argumentChecksFunc.cbegin(), argumentChecksFunc.cend(), [](const std::pair<const int, Library::ArgumentChecks>& a) {
1354
0
        return a.second.formatstr;
1355
0
    });
1356
0
    return it == argumentChecksFunc.cend() ? -1 : it->first - 1;
1357
0
}
1358
1359
bool Library::formatstr_scan(const Token* ftok) const
1360
0
{
1361
0
    return functions.at(getFunctionName(ftok)).formatstr_scan;
1362
0
}
1363
1364
bool Library::formatstr_secure(const Token* ftok) const
1365
0
{
1366
0
    return functions.at(getFunctionName(ftok)).formatstr_secure;
1367
0
}
1368
1369
const Library::NonOverlappingData* Library::getNonOverlappingData(const Token *ftok) const
1370
1.46k
{
1371
1.46k
    if (isNotLibraryFunction(ftok))
1372
1.46k
        return nullptr;
1373
0
    const std::unordered_map<std::string, NonOverlappingData>::const_iterator it = mNonOverlappingData.find(getFunctionName(ftok));
1374
0
    return (it != mNonOverlappingData.cend()) ? &it->second : nullptr;
1375
1.46k
}
1376
1377
Library::UseRetValType Library::getUseRetValType(const Token *ftok) const
1378
0
{
1379
0
    if (isNotLibraryFunction(ftok)) {
1380
0
        if (Token::simpleMatch(ftok->astParent(), ".")) {
1381
0
            const Token* contTok = ftok->astParent()->astOperand1();
1382
0
            using Yield = Library::Container::Yield;
1383
0
            const Yield yield = astContainerYield(contTok);
1384
0
            if (yield == Yield::START_ITERATOR || yield == Yield::END_ITERATOR || yield == Yield::AT_INDEX ||
1385
0
                yield == Yield::SIZE || yield == Yield::EMPTY || yield == Yield::BUFFER || yield == Yield::BUFFER_NT ||
1386
0
                ((yield == Yield::ITEM || yield == Yield::ITERATOR) && astContainerAction(contTok) == Library::Container::Action::NO_ACTION))
1387
0
                return Library::UseRetValType::DEFAULT;
1388
0
        }
1389
0
        return Library::UseRetValType::NONE;
1390
0
    }
1391
0
    const std::unordered_map<std::string, Function>::const_iterator it = functions.find(getFunctionName(ftok));
1392
0
    if (it != functions.cend())
1393
0
        return it->second.useretval;
1394
0
    return Library::UseRetValType::NONE;
1395
0
}
1396
1397
const std::string& Library::returnValue(const Token *ftok) const
1398
0
{
1399
0
    if (isNotLibraryFunction(ftok))
1400
0
        return emptyString;
1401
0
    const std::map<std::string, std::string>::const_iterator it = mReturnValue.find(getFunctionName(ftok));
1402
0
    return it != mReturnValue.cend() ? it->second : emptyString;
1403
0
}
1404
1405
const std::string& Library::returnValueType(const Token *ftok) const
1406
24.3k
{
1407
24.3k
    if (isNotLibraryFunction(ftok)) {
1408
24.3k
        if (Token::simpleMatch(ftok->astParent(), ".") && ftok->astParent()->astOperand1()) {
1409
0
            const Token* contTok = ftok->astParent()->astOperand1();
1410
0
            if (contTok->valueType() && contTok->valueType()->container)
1411
0
                return contTok->valueType()->container->getReturnType(ftok->str());
1412
0
        }
1413
24.3k
        return emptyString;
1414
24.3k
    }
1415
0
    const std::map<std::string, std::string>::const_iterator it = mReturnValueType.find(getFunctionName(ftok));
1416
0
    return it != mReturnValueType.cend() ? it->second : emptyString;
1417
24.3k
}
1418
1419
int Library::returnValueContainer(const Token *ftok) const
1420
206
{
1421
206
    if (isNotLibraryFunction(ftok))
1422
206
        return -1;
1423
0
    const std::map<std::string, int>::const_iterator it = mReturnValueContainer.find(getFunctionName(ftok));
1424
0
    return it != mReturnValueContainer.cend() ? it->second : -1;
1425
206
}
1426
1427
std::vector<MathLib::bigint> Library::unknownReturnValues(const Token *ftok) const
1428
0
{
1429
0
    if (isNotLibraryFunction(ftok))
1430
0
        return std::vector<MathLib::bigint>();
1431
0
    const std::map<std::string, std::vector<MathLib::bigint>>::const_iterator it = mUnknownReturnValues.find(getFunctionName(ftok));
1432
0
    return (it == mUnknownReturnValues.cend()) ? std::vector<MathLib::bigint>() : it->second;
1433
0
}
1434
1435
const Library::Function *Library::getFunction(const Token *ftok) const
1436
5.61k
{
1437
5.61k
    if (isNotLibraryFunction(ftok))
1438
5.61k
        return nullptr;
1439
0
    const std::unordered_map<std::string, Function>::const_iterator it1 = functions.find(getFunctionName(ftok));
1440
0
    if (it1 == functions.cend())
1441
0
        return nullptr;
1442
0
    return &it1->second;
1443
0
}
1444
1445
1446
bool Library::hasminsize(const Token *ftok) const
1447
1.46k
{
1448
1.46k
    if (isNotLibraryFunction(ftok))
1449
1.46k
        return false;
1450
0
    const std::unordered_map<std::string, Function>::const_iterator it = functions.find(getFunctionName(ftok));
1451
0
    if (it == functions.cend())
1452
0
        return false;
1453
0
    return std::any_of(it->second.argumentChecks.cbegin(), it->second.argumentChecks.cend(), [](const std::pair<const int, Library::ArgumentChecks>& a) {
1454
0
        return !a.second.minsizes.empty();
1455
0
    });
1456
0
}
1457
1458
Library::ArgumentChecks::Direction Library::getArgDirection(const Token* ftok, int argnr) const
1459
0
{
1460
0
    const ArgumentChecks* arg = getarg(ftok, argnr);
1461
0
    if (arg)
1462
0
        return arg->direction;
1463
0
    if (formatstr_function(ftok)) {
1464
0
        const int fs_argno = formatstr_argno(ftok);
1465
0
        if (fs_argno >= 0 && argnr >= fs_argno) {
1466
0
            if (formatstr_scan(ftok))
1467
0
                return ArgumentChecks::Direction::DIR_OUT;
1468
0
            return ArgumentChecks::Direction::DIR_IN;
1469
0
        }
1470
0
    }
1471
0
    return ArgumentChecks::Direction::DIR_UNKNOWN;
1472
0
}
1473
1474
bool Library::ignorefunction(const std::string& functionName) const
1475
0
{
1476
0
    const std::unordered_map<std::string, Function>::const_iterator it = functions.find(functionName);
1477
0
    if (it != functions.cend())
1478
0
        return it->second.ignore;
1479
0
    return false;
1480
0
}
1481
bool Library::isUse(const std::string& functionName) const
1482
0
{
1483
0
    const std::unordered_map<std::string, Function>::const_iterator it = functions.find(functionName);
1484
0
    if (it != functions.cend())
1485
0
        return it->second.use;
1486
0
    return false;
1487
0
}
1488
bool Library::isLeakIgnore(const std::string& functionName) const
1489
0
{
1490
0
    const std::unordered_map<std::string, Function>::const_iterator it = functions.find(functionName);
1491
0
    if (it != functions.cend())
1492
0
        return it->second.leakignore;
1493
0
    return false;
1494
0
}
1495
bool Library::isFunctionConst(const std::string& functionName, bool pure) const
1496
1.46k
{
1497
1.46k
    const std::unordered_map<std::string, Function>::const_iterator it = functions.find(functionName);
1498
1.46k
    if (it != functions.cend())
1499
0
        return pure ? it->second.ispure : it->second.isconst;
1500
1.46k
    return false;
1501
1.46k
}
1502
bool Library::isFunctionConst(const Token *ftok) const
1503
45
{
1504
45
    if (ftok->function() && ftok->function()->isConst())
1505
0
        return true;
1506
45
    if (isNotLibraryFunction(ftok)) {
1507
45
        if (Token::simpleMatch(ftok->astParent(), ".")) {
1508
0
            using Yield = Library::Container::Yield;
1509
0
            const Yield yield = astContainerYield(ftok->astParent()->astOperand1());
1510
0
            if (yield == Yield::EMPTY || yield == Yield::SIZE || yield == Yield::BUFFER_NT)
1511
0
                return true;
1512
0
        }
1513
45
        return false;
1514
45
    }
1515
0
    const std::unordered_map<std::string, Function>::const_iterator it = functions.find(getFunctionName(ftok));
1516
0
    return (it != functions.cend() && it->second.isconst);
1517
45
}
1518
1519
bool Library::isnoreturn(const Token *ftok) const
1520
31.0k
{
1521
31.0k
    if (ftok->function() && ftok->function()->isAttributeNoreturn())
1522
0
        return true;
1523
31.0k
    if (isNotLibraryFunction(ftok)) {
1524
31.0k
        if (Token::simpleMatch(ftok->astParent(), ".")) {
1525
0
            const Token* contTok = ftok->astParent()->astOperand1();
1526
0
            if (astContainerAction(contTok) != Library::Container::Action::NO_ACTION ||
1527
0
                astContainerYield(contTok) != Library::Container::Yield::NO_YIELD)
1528
0
                return false;
1529
0
        }
1530
31.0k
        return false;
1531
31.0k
    }
1532
0
    const std::unordered_map<std::string, FalseTrueMaybe>::const_iterator it = mNoReturn.find(getFunctionName(ftok));
1533
0
    if (it == mNoReturn.end())
1534
0
        return false;
1535
0
    if (it->second == FalseTrueMaybe::Maybe)
1536
0
        return true;
1537
0
    return it->second == FalseTrueMaybe::True;
1538
0
}
1539
1540
bool Library::isnotnoreturn(const Token *ftok) const
1541
0
{
1542
0
    if (ftok->function() && ftok->function()->isAttributeNoreturn())
1543
0
        return false;
1544
0
    if (isNotLibraryFunction(ftok))
1545
0
        return false;
1546
0
    const std::unordered_map<std::string, FalseTrueMaybe>::const_iterator it = mNoReturn.find(getFunctionName(ftok));
1547
0
    if (it == mNoReturn.end())
1548
0
        return false;
1549
0
    if (it->second == FalseTrueMaybe::Maybe)
1550
0
        return false;
1551
0
    return it->second == FalseTrueMaybe::False;
1552
0
}
1553
1554
bool Library::markupFile(const std::string &path) const
1555
4.08k
{
1556
4.08k
    return mMarkupExtensions.find(Path::getFilenameExtensionInLowerCase(path)) != mMarkupExtensions.end();
1557
4.08k
}
1558
1559
bool Library::processMarkupAfterCode(const std::string &path) const
1560
0
{
1561
0
    const std::map<std::string, bool>::const_iterator it = mProcessAfterCode.find(Path::getFilenameExtensionInLowerCase(path));
1562
0
    return (it == mProcessAfterCode.cend() || it->second);
1563
0
}
1564
1565
bool Library::reportErrors(const std::string &path) const
1566
1.48k
{
1567
1.48k
    const std::map<std::string, bool>::const_iterator it = mReportErrors.find(Path::getFilenameExtensionInLowerCase(path));
1568
1.48k
    return (it == mReportErrors.cend() || it->second);
1569
1.48k
}
1570
1571
bool Library::isexecutableblock(const std::string &file, const std::string &token) const
1572
92.2k
{
1573
92.2k
    const std::unordered_map<std::string, CodeBlock>::const_iterator it = mExecutableBlocks.find(Path::getFilenameExtensionInLowerCase(file));
1574
92.2k
    return (it != mExecutableBlocks.cend() && it->second.isBlock(token));
1575
92.2k
}
1576
1577
int Library::blockstartoffset(const std::string &file) const
1578
0
{
1579
0
    int offset = -1;
1580
0
    const std::unordered_map<std::string, CodeBlock>::const_iterator map_it
1581
0
        = mExecutableBlocks.find(Path::getFilenameExtensionInLowerCase(file));
1582
1583
0
    if (map_it != mExecutableBlocks.end()) {
1584
0
        offset = map_it->second.offset();
1585
0
    }
1586
0
    return offset;
1587
0
}
1588
1589
const std::string& Library::blockstart(const std::string &file) const
1590
0
{
1591
0
    const std::unordered_map<std::string, CodeBlock>::const_iterator map_it
1592
0
        = mExecutableBlocks.find(Path::getFilenameExtensionInLowerCase(file));
1593
1594
0
    if (map_it != mExecutableBlocks.end()) {
1595
0
        return map_it->second.start();
1596
0
    }
1597
0
    return emptyString;
1598
0
}
1599
1600
const std::string& Library::blockend(const std::string &file) const
1601
0
{
1602
0
    const std::unordered_map<std::string, CodeBlock>::const_iterator map_it
1603
0
        = mExecutableBlocks.find(Path::getFilenameExtensionInLowerCase(file));
1604
1605
0
    if (map_it != mExecutableBlocks.end()) {
1606
0
        return map_it->second.end();
1607
0
    }
1608
0
    return emptyString;
1609
0
}
1610
1611
bool Library::iskeyword(const std::string &file, const std::string &keyword) const
1612
0
{
1613
0
    const std::map<std::string, std::set<std::string>>::const_iterator it =
1614
0
        mKeywords.find(Path::getFilenameExtensionInLowerCase(file));
1615
0
    return (it != mKeywords.end() && it->second.count(keyword));
1616
0
}
1617
1618
bool Library::isimporter(const std::string& file, const std::string &importer) const
1619
0
{
1620
0
    const std::map<std::string, std::set<std::string>>::const_iterator it =
1621
0
        mImporters.find(Path::getFilenameExtensionInLowerCase(file));
1622
0
    return (it != mImporters.end() && it->second.count(importer) > 0);
1623
0
}
1624
1625
const Token* Library::getContainerFromYield(const Token* tok, Library::Container::Yield yield) const
1626
7.52k
{
1627
7.52k
    if (!tok)
1628
0
        return nullptr;
1629
7.52k
    if (Token::Match(tok->tokAt(-2), ". %name% (")) {
1630
0
        const Token* containerTok = tok->tokAt(-2)->astOperand1();
1631
0
        if (!astIsContainer(containerTok))
1632
0
            return nullptr;
1633
0
        if (containerTok->valueType()->container &&
1634
0
            containerTok->valueType()->container->getYield(tok->strAt(-1)) == yield)
1635
0
            return containerTok;
1636
0
        if (yield == Library::Container::Yield::EMPTY && Token::simpleMatch(tok->tokAt(-1), "empty ( )"))
1637
0
            return containerTok;
1638
0
        if (yield == Library::Container::Yield::SIZE && Token::Match(tok->tokAt(-1), "size|length ( )"))
1639
0
            return containerTok;
1640
7.52k
    } else if (Token::Match(tok->previous(), "%name% (")) {
1641
5.40k
        if (const Library::Function* f = this->getFunction(tok->previous())) {
1642
0
            if (f->containerYield == yield) {
1643
0
                return tok->astOperand2();
1644
0
            }
1645
0
        }
1646
5.40k
    }
1647
7.52k
    return nullptr;
1648
7.52k
}
1649
1650
// cppcheck-suppress unusedFunction
1651
const Token* Library::getContainerFromAction(const Token* tok, Library::Container::Action action) const
1652
0
{
1653
0
    if (!tok)
1654
0
        return nullptr;
1655
0
    if (Token::Match(tok->tokAt(-2), ". %name% (")) {
1656
0
        const Token* containerTok = tok->tokAt(-2)->astOperand1();
1657
0
        if (!astIsContainer(containerTok))
1658
0
            return nullptr;
1659
0
        if (containerTok->valueType()->container &&
1660
0
            containerTok->valueType()->container->getAction(tok->strAt(-1)) == action)
1661
0
            return containerTok;
1662
0
        if (Token::simpleMatch(tok->tokAt(-1), "empty ( )"))
1663
0
            return containerTok;
1664
0
    } else if (Token::Match(tok->previous(), "%name% (")) {
1665
0
        if (const Library::Function* f = this->getFunction(tok->previous())) {
1666
0
            if (f->containerAction == action) {
1667
0
                return tok->astOperand2();
1668
0
            }
1669
0
        }
1670
0
    }
1671
0
    return nullptr;
1672
0
}
1673
1674
bool Library::isSmartPointer(const Token* tok) const
1675
36.4k
{
1676
36.4k
    return detectSmartPointer(tok);
1677
36.4k
}
1678
1679
const Library::SmartPointer* Library::detectSmartPointer(const Token* tok, bool withoutStd) const
1680
148k
{
1681
148k
    std::string typestr = withoutStd ? "std::" : "";
1682
380k
    while (Token::Match(tok, "%name%|::")) {
1683
232k
        typestr += tok->str();
1684
232k
        tok = tok->next();
1685
232k
    }
1686
148k
    auto it = smartPointers.find(typestr);
1687
148k
    if (it == smartPointers.end())
1688
148k
        return nullptr;
1689
0
    return &it->second;
1690
148k
}
1691
1692
const Library::Container * getLibraryContainer(const Token * tok)
1693
396k
{
1694
396k
    if (!tok)
1695
0
        return nullptr;
1696
    // TODO: Support dereferencing iterators
1697
    // TODO: Support dereferencing with ->
1698
396k
    if (tok->isUnaryOp("*") && astIsPointer(tok->astOperand1())) {
1699
0
        for (const ValueFlow::Value& v:tok->astOperand1()->values()) {
1700
0
            if (!v.isLocalLifetimeValue())
1701
0
                continue;
1702
0
            if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
1703
0
                continue;
1704
0
            return getLibraryContainer(v.tokvalue);
1705
0
        }
1706
0
    }
1707
396k
    if (!tok->valueType())
1708
204k
        return nullptr;
1709
192k
    return tok->valueType()->container;
1710
396k
}
1711
1712
Library::TypeCheck Library::getTypeCheck(std::string check,  std::string typeName) const
1713
0
{
1714
0
    auto it = mTypeChecks.find(std::pair<std::string, std::string>(std::move(check), std::move(typeName)));
1715
0
    return it == mTypeChecks.end() ? TypeCheck::def : it->second;
1716
0
}
1717
1718
bool Library::hasAnyTypeCheck(const std::string& typeName) const
1719
0
{
1720
0
    return std::any_of(mTypeChecks.begin(), mTypeChecks.end(), [&](const std::pair<std::pair<std::string, std::string>, Library::TypeCheck>& tc) {
1721
0
        return tc.first.second == typeName;
1722
0
    });
1723
0
}
1724
1725
std::shared_ptr<Token> createTokenFromExpression(const std::string& returnValue,
1726
                                                 const Settings* settings,
1727
                                                 std::unordered_map<nonneg int, const Token*>* lookupVarId)
1728
0
{
1729
0
    std::shared_ptr<TokenList> tokenList = std::make_shared<TokenList>(settings);
1730
0
    {
1731
0
        const std::string code = "return " + returnValue + ";";
1732
0
        std::istringstream istr(code);
1733
0
        if (!tokenList->createTokens(istr))
1734
0
            return nullptr;
1735
0
    }
1736
1737
    // combine operators, set links, etc..
1738
0
    std::stack<Token*> lpar;
1739
0
    for (Token* tok2 = tokenList->front(); tok2; tok2 = tok2->next()) {
1740
0
        if (Token::Match(tok2, "[!<>=] =")) {
1741
0
            tok2->str(tok2->str() + "=");
1742
0
            tok2->deleteNext();
1743
0
        } else if (tok2->str() == "(")
1744
0
            lpar.push(tok2);
1745
0
        else if (tok2->str() == ")") {
1746
0
            if (lpar.empty())
1747
0
                return nullptr;
1748
0
            Token::createMutualLinks(lpar.top(), tok2);
1749
0
            lpar.pop();
1750
0
        }
1751
0
    }
1752
0
    if (!lpar.empty())
1753
0
        return nullptr;
1754
1755
    // set varids
1756
0
    for (Token* tok2 = tokenList->front(); tok2; tok2 = tok2->next()) {
1757
0
        if (!startsWith(tok2->str(), "arg"))
1758
0
            continue;
1759
0
        nonneg int const id = strToInt<nonneg int>(tok2->str().c_str() + 3);
1760
0
        tok2->varId(id);
1761
0
        if (lookupVarId)
1762
0
            (*lookupVarId)[id] = tok2;
1763
0
    }
1764
1765
    // Evaluate expression
1766
0
    tokenList->createAst();
1767
0
    Token* expr = tokenList->front()->astOperand1();
1768
0
    ValueFlow::valueFlowConstantFoldAST(expr, settings);
1769
0
    return {tokenList, expr};
1770
0
}