Coverage Report

Created: 2025-01-24 06:31

/src/cppcheck/oss-fuzz/build/library.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "matchcompiler.h"
2
#include <string>
3
#include <cstring>
4
#include "errorlogger.h"
5
#include "token.h"
6
// pattern: - %num%
7
0
static inline bool match1(const Token* tok) {
8
0
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")))
9
0
        return false;
10
0
    tok = tok->next();
11
0
    if (!tok || !tok->isNumber())
12
0
        return false;
13
0
    return true;
14
0
}
15
// pattern: %num% : %num%
16
0
static inline bool match2(const Token* tok) {
17
0
    if (!tok || !tok->isNumber())
18
0
        return false;
19
0
    tok = tok->next();
20
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")))
21
0
        return false;
22
0
    tok = tok->next();
23
0
    if (!tok || !tok->isNumber())
24
0
        return false;
25
0
    return true;
26
0
}
27
// pattern: %num% : ,
28
0
static inline bool match3(const Token* tok) {
29
0
    if (!tok || !tok->isNumber())
30
0
        return false;
31
0
    tok = tok->next();
32
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")))
33
0
        return false;
34
0
    tok = tok->next();
35
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")))
36
0
        return false;
37
0
    return true;
38
0
}
39
// pattern: : %num%
40
0
static inline bool match4(const Token* tok) {
41
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")))
42
0
        return false;
43
0
    tok = tok->next();
44
0
    if (!tok || !tok->isNumber())
45
0
        return false;
46
0
    return true;
47
0
}
48
// pattern: %num%
49
0
static inline bool match5(const Token* tok) {
50
0
    if (!tok || !tok->isNumber())
51
0
        return false;
52
0
    return true;
53
0
}
54
// pattern: ! %num%
55
0
static inline bool match6(const Token* tok) {
56
0
    if (!tok || !((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")))
57
0
        return false;
58
0
    tok = tok->next();
59
0
    if (!tok || !tok->isNumber())
60
0
        return false;
61
0
    return true;
62
0
}
63
// pattern: ::
64
4.34k
static inline bool match7(const Token* tok) {
65
4.34k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
66
4.34k
        return false;
67
0
    return true;
68
4.34k
}
69
// pattern: %name%|::
70
208k
static inline bool match8(const Token* tok) {
71
208k
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString("::"))))
72
72.5k
        return false;
73
136k
    return true;
74
208k
}
75
// pattern: %name% )| (
76
29.2k
static inline bool match9(const Token* tok) {
77
29.2k
    if (!tok || !tok->isName())
78
19.4k
        return false;
79
9.85k
    tok = tok->next();
80
9.85k
    if (tok && (((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))))
81
237
        tok = tok->next();
82
9.85k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
83
4.93k
        return false;
84
4.91k
    return true;
85
9.85k
}
86
// pattern: .
87
35.7k
static inline bool match10(const Token* tok) {
88
35.7k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
89
35.7k
        return false;
90
0
    return true;
91
35.7k
}
92
// pattern: %name% ::
93
2.58k
static inline bool match11(const Token* tok) {
94
2.58k
    if (!tok || !tok->isName())
95
2.52k
        return false;
96
54
    tok = tok->next();
97
54
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
98
54
        return false;
99
0
    return true;
100
54
}
101
// pattern: !!{ ; }
102
29
static inline bool match12(const Token* tok) {
103
29
    if (tok && tok->str() == MatchCompiler::makeConstString("{"))
104
0
        return false;
105
29
    tok = tok ? tok->next() : nullptr;
106
29
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
107
29
        return false;
108
0
    tok = tok->next();
109
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
110
0
        return false;
111
0
    return true;
112
0
}
113
// pattern: <<
114
0
static inline bool match13(const Token* tok) {
115
0
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")))
116
0
        return false;
117
0
    return true;
118
0
}
119
// pattern: (
120
0
static inline bool match14(const Token* tok) {
121
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
122
0
        return false;
123
0
    return true;
124
0
}
125
// pattern: %name% (
126
2.85k
static inline bool match15(const Token* tok) {
127
2.85k
    if (!tok || !tok->isName())
128
279
        return false;
129
2.57k
    tok = tok->next();
130
2.57k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
131
109
        return false;
132
2.46k
    return true;
133
2.57k
}
134
// pattern: ) ; }
135
29
static inline bool match16(const Token* tok) {
136
29
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
137
0
        return false;
138
29
    tok = tok->next();
139
29
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
140
29
        return false;
141
0
    tok = tok->next();
142
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
143
0
        return false;
144
0
    return true;
145
0
}
146
// pattern: ( * %name% )
147
0
static inline bool match17(const Token* tok) {
148
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
149
0
        return false;
150
0
    tok = tok->next();
151
0
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")))
152
0
        return false;
153
0
    tok = tok->next();
154
0
    if (!tok || !tok->isName())
155
0
        return false;
156
0
    tok = tok->next();
157
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
158
0
        return false;
159
0
    return true;
160
0
}
161
// pattern: %name%|.|::
162
0
static inline bool match18(const Token* tok) {
163
0
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString(".")) || (tok->str() == MatchCompiler::makeConstString("::"))))
164
0
        return false;
165
0
    return true;
166
0
}
167
// pattern: [;{}]
168
0
static inline bool match19(const Token* tok) {
169
0
    if (!tok || tok->str().size() != 1U || !strchr(";{}", tok->str()[0]))
170
0
        return false;
171
0
    return true;
172
0
}
173
// pattern: ( )
174
0
static inline bool match20(const Token* tok) {
175
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
176
0
        return false;
177
0
    tok = tok->next();
178
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
179
0
        return false;
180
0
    return true;
181
0
}
182
// pattern: . %name% (
183
2.85k
static inline bool match21(const Token* tok) {
184
2.85k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
185
2.85k
        return false;
186
0
    tok = tok->next();
187
0
    if (!tok || !tok->isName())
188
0
        return false;
189
0
    tok = tok->next();
190
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
191
0
        return false;
192
0
    return true;
193
0
}
194
// pattern: empty ( )
195
0
static inline bool match22(const Token* tok) {
196
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("empty")))
197
0
        return false;
198
0
    tok = tok->next();
199
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
200
0
        return false;
201
0
    tok = tok->next();
202
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
203
0
        return false;
204
0
    return true;
205
0
}
206
// pattern: size|length ( )
207
0
static inline bool match23(const Token* tok) {
208
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("size")) || (tok->str() == MatchCompiler::makeConstString("length"))))
209
0
        return false;
210
0
    tok = tok->next();
211
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
212
0
        return false;
213
0
    tok = tok->next();
214
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
215
0
        return false;
216
0
    return true;
217
0
}
218
/*
219
 * Cppcheck - A tool for static C/C++ code analysis
220
 * Copyright (C) 2007-2024 Cppcheck team.
221
 *
222
 * This program is free software: you can redistribute it and/or modify
223
 * it under the terms of the GNU General Public License as published by
224
 * the Free Software Foundation, either version 3 of the License, or
225
 * (at your option) any later version.
226
 *
227
 * This program is distributed in the hope that it will be useful,
228
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
229
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
230
 * GNU General Public License for more details.
231
 *
232
 * You should have received a copy of the GNU General Public License
233
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
234
 */
235
236
#include "library.h"
237
238
#include "astutils.h"
239
#include "errortypes.h"
240
#include "mathlib.h"
241
#include "path.h"
242
#include "symboldatabase.h"
243
#include "token.h"
244
#include "tokenlist.h"
245
#include "utils.h"
246
#include "vfvalue.h"
247
248
#include <algorithm>
249
#include <cctype>
250
#include <climits>
251
#include <cstring>
252
#include <iostream>
253
#include <list>
254
#include <memory>
255
#include <sstream>
256
#include <stdexcept>
257
#include <string>
258
#include <unordered_set>
259
260
#include "xml.h"
261
262
struct Library::LibraryData
263
{
264
    struct Platform {
265
0
        const PlatformType *platform_type(const std::string &name) const {
266
0
            const auto it = utils::as_const(mPlatformTypes).find(name);
267
0
            return (it != mPlatformTypes.end()) ? &(it->second) : nullptr;
268
0
        }
269
        std::map<std::string, PlatformType> mPlatformTypes;
270
    };
271
272
    class ExportedFunctions {
273
    public:
274
0
        void addPrefix(std::string prefix) {
275
0
            mPrefixes.insert(std::move(prefix));
276
0
        }
277
0
        void addSuffix(std::string suffix) {
278
0
            mSuffixes.insert(std::move(suffix));
279
0
        }
280
0
        bool isPrefix(const std::string& prefix) const {
281
0
            return (mPrefixes.find(prefix) != mPrefixes.end());
282
0
        }
283
0
        bool isSuffix(const std::string& suffix) const {
284
0
            return (mSuffixes.find(suffix) != mSuffixes.end());
285
0
        }
286
287
    private:
288
        std::set<std::string> mPrefixes;
289
        std::set<std::string> mSuffixes;
290
    };
291
292
    class CodeBlock {
293
    public:
294
0
        CodeBlock() = default;
295
296
0
        void setStart(const char* s) {
297
0
            mStart = s;
298
0
        }
299
0
        void setEnd(const char* e) {
300
0
            mEnd = e;
301
0
        }
302
0
        void setOffset(const int o) {
303
0
            mOffset = o;
304
0
        }
305
0
        void addBlock(const char* blockName) {
306
0
            mBlocks.insert(blockName);
307
0
        }
308
0
        const std::string& start() const {
309
0
            return mStart;
310
0
        }
311
0
        const std::string& end() const {
312
0
            return mEnd;
313
0
        }
314
0
        int offset() const {
315
0
            return mOffset;
316
0
        }
317
0
        bool isBlock(const std::string& blockName) const {
318
0
            return mBlocks.find(blockName) != mBlocks.end();
319
0
        }
320
321
    private:
322
        std::string mStart;
323
        std::string mEnd;
324
        int mOffset{};
325
        std::set<std::string> mBlocks;
326
    };
327
328
    enum class FalseTrueMaybe : std::uint8_t { False, True, Maybe };
329
330
    std::map<std::string, WarnInfo> mFunctionwarn;
331
    std::set<std::string> mDefines;
332
333
    std::unordered_map<std::string, Container> mContainers;
334
    std::unordered_map<std::string, Function> mFunctions;
335
    std::unordered_map<std::string, SmartPointer> mSmartPointers;
336
337
    int mAllocId{};
338
    std::set<std::string> mFiles;
339
    std::map<std::string, AllocFunc> mAlloc; // allocation functions
340
    std::map<std::string, AllocFunc> mDealloc; // deallocation functions
341
    std::map<std::string, AllocFunc> mRealloc; // reallocation functions
342
    std::unordered_map<std::string, FalseTrueMaybe> mNoReturn; // is function noreturn?
343
    std::map<std::string, std::string> mReturnValue;
344
    std::map<std::string, std::string> mReturnValueType;
345
    std::map<std::string, int> mReturnValueContainer;
346
    std::map<std::string, std::vector<MathLib::bigint>> mUnknownReturnValues;
347
    std::map<std::string, bool> mReportErrors;
348
    std::map<std::string, bool> mProcessAfterCode;
349
    std::set<std::string> mMarkupExtensions; // file extensions of markup files
350
    std::map<std::string, std::set<std::string>> mKeywords;  // keywords for code in the library
351
    std::unordered_map<std::string, CodeBlock> mExecutableBlocks; // keywords for blocks of executable code
352
    std::map<std::string, ExportedFunctions> mExporters; // keywords that export variables/functions to libraries (meta-code/macros)
353
    std::map<std::string, std::set<std::string>> mImporters;  // keywords that import variables/functions
354
    std::map<std::string, int> mReflection; // invocation of reflection
355
    std::unordered_map<std::string, struct PodType> mPodTypes; // pod types
356
    std::map<std::string, PlatformType> mPlatformTypes; // platform independent typedefs
357
    std::map<std::string, Platform> mPlatforms; // platform dependent typedefs
358
    std::map<std::pair<std::string,std::string>, TypeCheck> mTypeChecks;
359
    std::unordered_map<std::string, NonOverlappingData> mNonOverlappingData;
360
    std::unordered_set<std::string> mEntrypoints;
361
};
362
363
Library::Library()
364
996
    : mData(new LibraryData())
365
996
{}
366
367
996
Library::~Library() = default;
368
369
Library::Library(const Library& other)
370
0
    : mData(new LibraryData(*other.mData))
371
0
{}
372
373
Library& Library::operator=(const Library& other) &
374
0
{
375
0
    mData.reset(new LibraryData(*other.mData));
376
0
    return *this;
377
0
}
378
379
static std::vector<std::string> getnames(const char *names)
380
0
{
381
0
    std::vector<std::string> ret;
382
0
    while (const char *p = std::strchr(names,',')) {
383
0
        ret.emplace_back(names, p-names);
384
0
        names = p + 1;
385
0
    }
386
0
    ret.emplace_back(names);
387
0
    return ret;
388
0
}
389
390
static void gettokenlistfromvalid(const std::string& valid, bool cpp, TokenList& tokenList)
391
0
{
392
0
    std::istringstream istr(valid + ',');
393
0
    tokenList.createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C); // TODO: check result?
394
0
    for (Token *tok = tokenList.front(); tok; tok = tok->next()) {
395
0
        if (match1(tok)) {
396
0
            tok->str("-" + tok->strAt(1));
397
0
            tok->deleteNext();
398
0
        }
399
0
    }
400
0
}
401
402
Library::Error Library::load(const char exename[], const char path[], bool debug)
403
0
{
404
0
    if (std::strchr(path,',') != nullptr) {
405
0
        throw std::runtime_error("handling of multiple libraries not supported");
406
0
    }
407
408
0
    const bool is_abs_path = Path::isAbsolute(path);
409
410
0
    std::string absolute_path;
411
    // open file..
412
0
    tinyxml2::XMLDocument doc;
413
0
    if (debug)
414
0
        std::cout << "looking for library '" + std::string(path) + "'" << std::endl;
415
0
    tinyxml2::XMLError error = xml_LoadFile(doc, path);
416
0
    if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND) {
417
        // failed to open file.. is there no extension?
418
0
        std::string fullfilename(path);
419
0
        if (Path::getFilenameExtension(fullfilename).empty()) {
420
0
            fullfilename += ".cfg";
421
0
            if (debug)
422
0
                std::cout << "looking for library '" + fullfilename + "'" << std::endl;
423
0
            error = xml_LoadFile(doc, fullfilename.c_str());
424
0
            if (error != tinyxml2::XML_ERROR_FILE_NOT_FOUND)
425
0
                absolute_path = Path::getAbsoluteFilePath(fullfilename);
426
0
        }
427
428
        // only perform further lookups when the given path was not absolute
429
0
        if (!is_abs_path && error == tinyxml2::XML_ERROR_FILE_NOT_FOUND)
430
0
        {
431
0
            std::list<std::string> cfgfolders;
432
    #ifdef FILESDIR
433
            cfgfolders.emplace_back(FILESDIR "/cfg");
434
    #endif
435
0
            if (exename) {
436
0
                const std::string exepath(Path::fromNativeSeparators(Path::getPathFromFilename(Path::getCurrentExecutablePath(exename))));
437
0
                cfgfolders.push_back(exepath + "cfg");
438
0
                cfgfolders.push_back(exepath);
439
0
            }
440
441
0
            while (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND && !cfgfolders.empty()) {
442
0
                const std::string cfgfolder(cfgfolders.back());
443
0
                cfgfolders.pop_back();
444
0
                const char *sep = (!cfgfolder.empty() && endsWith(cfgfolder,'/') ? "" : "/");
445
0
                const std::string filename(cfgfolder + sep + fullfilename);
446
0
                if (debug)
447
0
                    std::cout << "looking for library '" + std::string(filename) + "'" << std::endl;
448
0
                error = xml_LoadFile(doc, filename.c_str());
449
0
                if (error != tinyxml2::XML_ERROR_FILE_NOT_FOUND)
450
0
                    absolute_path = Path::getAbsoluteFilePath(filename);
451
0
            }
452
0
        }
453
0
    } else
454
0
        absolute_path = Path::getAbsoluteFilePath(path);
455
456
0
    if (error == tinyxml2::XML_SUCCESS) {
457
0
        if (mData->mFiles.find(absolute_path) == mData->mFiles.end()) {
458
0
            Error err = load(doc);
459
0
            if (err.errorcode == ErrorCode::OK)
460
0
                mData->mFiles.insert(absolute_path);
461
0
            return err;
462
0
        }
463
464
0
        return Error(ErrorCode::OK); // ignore duplicates
465
0
    }
466
467
0
    if (debug)
468
0
        std::cout << "library not found: '" + std::string(path) + "'" << std::endl;
469
470
0
    if (error == tinyxml2::XML_ERROR_FILE_NOT_FOUND)
471
0
        return Error(ErrorCode::FILE_NOT_FOUND);
472
473
0
    doc.PrintError(); // TODO: do not print stray messages
474
0
    return Error(ErrorCode::BAD_XML);
475
0
}
476
477
Library::Container::Yield Library::Container::yieldFrom(const std::string& yieldName)
478
0
{
479
0
    if (yieldName == MatchCompiler::makeConstString("at_index"))
480
0
        return Container::Yield::AT_INDEX;
481
0
    if (yieldName == MatchCompiler::makeConstString("item"))
482
0
        return Container::Yield::ITEM;
483
0
    if (yieldName == MatchCompiler::makeConstString("buffer"))
484
0
        return Container::Yield::BUFFER;
485
0
    if (yieldName == MatchCompiler::makeConstString("buffer-nt"))
486
0
        return Container::Yield::BUFFER_NT;
487
0
    if (yieldName == MatchCompiler::makeConstString("start-iterator"))
488
0
        return Container::Yield::START_ITERATOR;
489
0
    if (yieldName == MatchCompiler::makeConstString("end-iterator"))
490
0
        return Container::Yield::END_ITERATOR;
491
0
    if (yieldName == MatchCompiler::makeConstString("iterator"))
492
0
        return Container::Yield::ITERATOR;
493
0
    if (yieldName == MatchCompiler::makeConstString("size"))
494
0
        return Container::Yield::SIZE;
495
0
    if (yieldName == MatchCompiler::makeConstString("empty"))
496
0
        return Container::Yield::EMPTY;
497
0
    return Container::Yield::NO_YIELD;
498
0
}
499
Library::Container::Action Library::Container::actionFrom(const std::string& actionName)
500
0
{
501
0
    if (actionName == MatchCompiler::makeConstString("resize"))
502
0
        return Container::Action::RESIZE;
503
0
    if (actionName == MatchCompiler::makeConstString("clear"))
504
0
        return Container::Action::CLEAR;
505
0
    if (actionName == MatchCompiler::makeConstString("push"))
506
0
        return Container::Action::PUSH;
507
0
    if (actionName == MatchCompiler::makeConstString("pop"))
508
0
        return Container::Action::POP;
509
0
    if (actionName == MatchCompiler::makeConstString("find"))
510
0
        return Container::Action::FIND;
511
0
    if (actionName == MatchCompiler::makeConstString("find-const"))
512
0
        return Container::Action::FIND_CONST;
513
0
    if (actionName == MatchCompiler::makeConstString("insert"))
514
0
        return Container::Action::INSERT;
515
0
    if (actionName == MatchCompiler::makeConstString("erase"))
516
0
        return Container::Action::ERASE;
517
0
    if (actionName == MatchCompiler::makeConstString("append"))
518
0
        return Container::Action::APPEND;
519
0
    if (actionName == MatchCompiler::makeConstString("change-content"))
520
0
        return Container::Action::CHANGE_CONTENT;
521
0
    if (actionName == MatchCompiler::makeConstString("change-internal"))
522
0
        return Container::Action::CHANGE_INTERNAL;
523
0
    if (actionName == MatchCompiler::makeConstString("change"))
524
0
        return Container::Action::CHANGE;
525
0
    return Container::Action::NO_ACTION;
526
0
}
527
528
Library::Error Library::load(const tinyxml2::XMLDocument &doc)
529
0
{
530
0
    const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
531
532
0
    if (rootnode == nullptr) {
533
0
        doc.PrintError();
534
0
        return Error(ErrorCode::BAD_XML);
535
0
    }
536
537
0
    if (strcmp(rootnode->Name(),"def") != 0)
538
0
        return Error(ErrorCode::UNSUPPORTED_FORMAT, rootnode->Name());
539
540
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)
541
542
0
    if (format > 2 || format <= 0)
543
0
        return Error(ErrorCode::UNSUPPORTED_FORMAT);
544
545
0
    std::set<std::string> unknown_elements;
546
547
0
    for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
548
0
        const std::string nodename = node->Name();
549
0
        if (nodename == MatchCompiler::makeConstString("memory") || nodename == MatchCompiler::makeConstString("resource")) {
550
            // get allocationId to use..
551
0
            int allocationId = 0;
552
0
            for (const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) {
553
0
                if (strcmp(memorynode->Name(),"dealloc")==0) {
554
0
                    const auto names = getnames(memorynode->GetText());
555
0
                    for (const auto& n : names) {
556
0
                        const auto it = utils::as_const(mData->mDealloc).find(n);
557
0
                        if (it != mData->mDealloc.end()) {
558
0
                            allocationId = it->second.groupId;
559
0
                            break;
560
0
                        }
561
0
                    }
562
0
                    if (allocationId != 0)
563
0
                        break;
564
0
                }
565
0
            }
566
0
            if (allocationId == 0) {
567
0
                if (nodename == MatchCompiler::makeConstString("memory")) {
568
0
                    while (!ismemory(++mData->mAllocId)) {}
569
0
                }
570
0
                else {
571
0
                    while (!isresource(++mData->mAllocId)) {}
572
0
                }
573
0
                allocationId = mData->mAllocId;
574
0
            }
575
576
            // add alloc/dealloc/use functions..
577
0
            for (const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) {
578
0
                const std::string memorynodename = memorynode->Name();
579
0
                const auto names = getnames(memorynode->GetText());
580
0
                if (memorynodename == MatchCompiler::makeConstString("alloc") || memorynodename == MatchCompiler::makeConstString("realloc")) {
581
0
                    AllocFunc temp;
582
0
                    temp.groupId = allocationId;
583
584
0
                    temp.initData = memorynode->BoolAttribute("init", true);
585
0
                    temp.arg = memorynode->IntAttribute("arg", -1);
586
587
0
                    const char *bufferSize = memorynode->Attribute("buffer-size");
588
0
                    if (!bufferSize)
589
0
                        temp.bufferSize = AllocFunc::BufferSize::none;
590
0
                    else {
591
0
                        if (std::strncmp(bufferSize, "malloc", 6) == 0)
592
0
                            temp.bufferSize = AllocFunc::BufferSize::malloc;
593
0
                        else if (std::strncmp(bufferSize, "calloc", 6) == 0)
594
0
                            temp.bufferSize = AllocFunc::BufferSize::calloc;
595
0
                        else if (std::strncmp(bufferSize, "strdup", 6) == 0)
596
0
                            temp.bufferSize = AllocFunc::BufferSize::strdup;
597
0
                        else
598
0
                            return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, bufferSize);
599
0
                        temp.bufferSizeArg1 = 1;
600
0
                        temp.bufferSizeArg2 = 2;
601
0
                        if (bufferSize[6] == 0) {
602
                            // use default values
603
0
                        } else if (bufferSize[6] == ':' && bufferSize[7] >= '1' && bufferSize[7] <= '5') {
604
0
                            temp.bufferSizeArg1 = bufferSize[7] - '0';
605
0
                            if (bufferSize[8] == ',' && bufferSize[9] >= '1' && bufferSize[9] <= '5')
606
0
                                temp.bufferSizeArg2 = bufferSize[9] - '0';
607
0
                        } else
608
0
                            return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, bufferSize);
609
0
                    }
610
611
0
                    if (memorynodename == MatchCompiler::makeConstString("realloc"))
612
0
                        temp.reallocArg = memorynode->IntAttribute("realloc-arg", 1);
613
614
0
                    auto& map = (memorynodename == MatchCompiler::makeConstString("realloc")) ? mData->mRealloc : mData->mAlloc;
615
0
                    for (const auto& n : names)
616
0
                        map[n] = temp;
617
0
                } else if (memorynodename == MatchCompiler::makeConstString("dealloc")) {
618
0
                    AllocFunc temp;
619
0
                    temp.groupId = allocationId;
620
0
                    temp.arg = memorynode->IntAttribute("arg", 1);
621
0
                    for (const auto& n : names)
622
0
                        mData->mDealloc[n] = temp;
623
0
                } else if (memorynodename == MatchCompiler::makeConstString("use"))
624
0
                    for (const auto& n : names)
625
0
                        mData->mFunctions[n].use = true;
626
0
                else
627
0
                    unknown_elements.insert(memorynodename);
628
0
            }
629
0
        }
630
631
0
        else if (nodename == MatchCompiler::makeConstString("define")) {
632
0
            const char *name = node->Attribute("name");
633
0
            if (name == nullptr)
634
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
635
0
            const char *value = node->Attribute("value");
636
0
            if (value == nullptr)
637
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "value");
638
0
            auto result = mData->mDefines.insert(std::string(name) + " " + value);
639
0
            if (!result.second)
640
0
                return Error(ErrorCode::DUPLICATE_DEFINE, name);
641
0
        }
642
643
0
        else if (nodename == MatchCompiler::makeConstString("function")) {
644
0
            const char *name = node->Attribute("name");
645
0
            if (name == nullptr)
646
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
647
0
            for (const std::string &s : getnames(name)) {
648
0
                const Error &err = loadFunction(node, s, unknown_elements);
649
0
                if (err.errorcode != ErrorCode::OK)
650
0
                    return err;
651
0
            }
652
0
        }
653
654
0
        else if (nodename == MatchCompiler::makeConstString("reflection")) {
655
0
            for (const tinyxml2::XMLElement *reflectionnode = node->FirstChildElement(); reflectionnode; reflectionnode = reflectionnode->NextSiblingElement()) {
656
0
                if (strcmp(reflectionnode->Name(), "call") != 0) {
657
0
                    unknown_elements.insert(reflectionnode->Name());
658
0
                    continue;
659
0
                }
660
661
0
                const char * const argString = reflectionnode->Attribute("arg");
662
0
                if (!argString)
663
0
                    return Error(ErrorCode::MISSING_ATTRIBUTE, "arg");
664
665
0
                mData->mReflection[reflectionnode->GetText()] = strToInt<int>(argString);
666
0
            }
667
0
        }
668
669
0
        else if (nodename == MatchCompiler::makeConstString("markup")) {
670
0
            const char * const extension = node->Attribute("ext");
671
0
            if (!extension)
672
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "ext");
673
0
            mData->mMarkupExtensions.insert(extension);
674
675
0
            mData->mReportErrors[extension] = (node->Attribute("reporterrors", "true") != nullptr);
676
0
            mData->mProcessAfterCode[extension] = (node->Attribute("aftercode", "true") != nullptr);
677
678
0
            for (const tinyxml2::XMLElement *markupnode = node->FirstChildElement(); markupnode; markupnode = markupnode->NextSiblingElement()) {
679
0
                const std::string markupnodename = markupnode->Name();
680
0
                if (markupnodename == MatchCompiler::makeConstString("keywords")) {
681
0
                    for (const tinyxml2::XMLElement *librarynode = markupnode->FirstChildElement(); librarynode; librarynode = librarynode->NextSiblingElement()) {
682
0
                        if (strcmp(librarynode->Name(), "keyword") == 0) {
683
0
                            const char* nodeName = librarynode->Attribute("name");
684
0
                            if (nodeName == nullptr)
685
0
                                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
686
0
                            mData->mKeywords[extension].insert(nodeName);
687
0
                        } else
688
0
                            unknown_elements.insert(librarynode->Name());
689
0
                    }
690
0
                }
691
692
0
                else if (markupnodename == MatchCompiler::makeConstString("exported")) {
693
0
                    for (const tinyxml2::XMLElement *exporter = markupnode->FirstChildElement(); exporter; exporter = exporter->NextSiblingElement()) {
694
0
                        if (strcmp(exporter->Name(), "exporter") != 0) {
695
0
                            unknown_elements.insert(exporter->Name());
696
0
                            continue;
697
0
                        }
698
699
0
                        const char * const prefix = exporter->Attribute("prefix");
700
0
                        if (!prefix)
701
0
                            return Error(ErrorCode::MISSING_ATTRIBUTE, "prefix");
702
703
0
                        for (const tinyxml2::XMLElement *e = exporter->FirstChildElement(); e; e = e->NextSiblingElement()) {
704
0
                            const std::string ename = e->Name();
705
0
                            if (ename == MatchCompiler::makeConstString("prefix"))
706
0
                                mData->mExporters[prefix].addPrefix(e->GetText());
707
0
                            else if (ename == MatchCompiler::makeConstString("suffix"))
708
0
                                mData->mExporters[prefix].addSuffix(e->GetText());
709
0
                            else
710
0
                                unknown_elements.insert(ename);
711
0
                        }
712
0
                    }
713
0
                }
714
715
0
                else if (markupnodename == MatchCompiler::makeConstString("imported")) {
716
0
                    for (const tinyxml2::XMLElement *librarynode = markupnode->FirstChildElement(); librarynode; librarynode = librarynode->NextSiblingElement()) {
717
0
                        if (strcmp(librarynode->Name(), "importer") == 0)
718
0
                            mData->mImporters[extension].insert(librarynode->GetText());
719
0
                        else
720
0
                            unknown_elements.insert(librarynode->Name());
721
0
                    }
722
0
                }
723
724
0
                else if (markupnodename == MatchCompiler::makeConstString("codeblocks")) {
725
0
                    for (const tinyxml2::XMLElement *blocknode = markupnode->FirstChildElement(); blocknode; blocknode = blocknode->NextSiblingElement()) {
726
0
                        const std::string blocknodename = blocknode->Name();
727
0
                        if (blocknodename == MatchCompiler::makeConstString("block")) {
728
0
                            const char * blockName = blocknode->Attribute("name");
729
0
                            if (blockName)
730
0
                                mData->mExecutableBlocks[extension].addBlock(blockName);
731
0
                        } else if (blocknodename == MatchCompiler::makeConstString("structure")) {
732
0
                            const char * start = blocknode->Attribute("start");
733
0
                            if (start)
734
0
                                mData->mExecutableBlocks[extension].setStart(start);
735
0
                            const char * end = blocknode->Attribute("end");
736
0
                            if (end)
737
0
                                mData->mExecutableBlocks[extension].setEnd(end);
738
0
                            const char * offset = blocknode->Attribute("offset");
739
0
                            if (offset) {
740
                                // cppcheck-suppress templateInstantiation - TODO: fix this - see #11631
741
0
                                mData->mExecutableBlocks[extension].setOffset(strToInt<int>(offset));
742
0
                            }
743
0
                        }
744
745
0
                        else
746
0
                            unknown_elements.insert(blocknodename);
747
0
                    }
748
0
                }
749
750
0
                else
751
0
                    unknown_elements.insert(markupnodename);
752
0
            }
753
0
        }
754
755
0
        else if (nodename == MatchCompiler::makeConstString("container")) {
756
0
            const char* const id = node->Attribute("id");
757
0
            if (!id)
758
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "id");
759
760
0
            Container& container = mData->mContainers[id];
761
762
0
            const char* const inherits = node->Attribute("inherits");
763
0
            if (inherits) {
764
0
                const auto i = utils::as_const(mData->mContainers).find(inherits);
765
0
                if (i != mData->mContainers.end())
766
0
                    container = i->second; // Take values from parent and overwrite them if necessary
767
0
                else
768
0
                    return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, inherits);
769
0
            }
770
771
0
            const char* const startPattern = node->Attribute("startPattern");
772
0
            if (startPattern) {
773
0
                container.startPattern = startPattern;
774
0
                container.startPattern2 = startPattern;
775
0
                if (!endsWith(container.startPattern, '<'))
776
0
                    container.startPattern2 += " !!::";
777
0
            }
778
0
            const char* const endPattern = node->Attribute("endPattern");
779
0
            if (endPattern)
780
0
                container.endPattern = endPattern;
781
0
            const char* const itEndPattern = node->Attribute("itEndPattern");
782
0
            if (itEndPattern)
783
0
                container.itEndPattern = itEndPattern;
784
0
            const char* const opLessAllowed = node->Attribute("opLessAllowed");
785
0
            if (opLessAllowed)
786
0
                container.opLessAllowed = strcmp(opLessAllowed, "true") == 0;
787
0
            const char* const hasInitializerListConstructor = node->Attribute("hasInitializerListConstructor");
788
0
            if (hasInitializerListConstructor)
789
0
                container.hasInitializerListConstructor = strcmp(hasInitializerListConstructor, "true") == 0;
790
0
            const char* const view = node->Attribute("view");
791
0
            if (view)
792
0
                container.view = strcmp(view, "true") == 0;
793
794
0
            for (const tinyxml2::XMLElement *containerNode = node->FirstChildElement(); containerNode; containerNode = containerNode->NextSiblingElement()) {
795
0
                const std::string containerNodeName = containerNode->Name();
796
0
                if (containerNodeName == MatchCompiler::makeConstString("size") || containerNodeName == MatchCompiler::makeConstString("access") || containerNodeName == MatchCompiler::makeConstString("other")) {
797
0
                    for (const tinyxml2::XMLElement *functionNode = containerNode->FirstChildElement(); functionNode; functionNode = functionNode->NextSiblingElement()) {
798
0
                        if (strcmp(functionNode->Name(), "function") != 0) {
799
0
                            unknown_elements.insert(functionNode->Name());
800
0
                            continue;
801
0
                        }
802
803
0
                        const char* const functionName = functionNode->Attribute("name");
804
0
                        if (!functionName)
805
0
                            return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
806
807
0
                        const char* const action_ptr = functionNode->Attribute("action");
808
0
                        Container::Action action = Container::Action::NO_ACTION;
809
0
                        if (action_ptr) {
810
0
                            std::string actionName = action_ptr;
811
0
                            action = Container::actionFrom(actionName);
812
0
                            if (action == Container::Action::NO_ACTION)
813
0
                                return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, actionName);
814
0
                        }
815
816
0
                        const char* const yield_ptr = functionNode->Attribute("yields");
817
0
                        Container::Yield yield = Container::Yield::NO_YIELD;
818
0
                        if (yield_ptr) {
819
0
                            std::string yieldName = yield_ptr;
820
0
                            yield = Container::yieldFrom(yieldName);
821
0
                            if (yield == Container::Yield::NO_YIELD)
822
0
                                return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, yieldName);
823
0
                        }
824
825
0
                        const char* const returnType = functionNode->Attribute("returnType");
826
0
                        if (returnType)
827
0
                            container.functions[functionName].returnType = returnType;
828
829
0
                        container.functions[functionName].action = action;
830
0
                        container.functions[functionName].yield = yield;
831
0
                    }
832
833
0
                    if (containerNodeName == MatchCompiler::makeConstString("size")) {
834
0
                        const char* const templateArg = containerNode->Attribute("templateParameter");
835
0
                        if (templateArg)
836
0
                            container.size_templateArgNo = strToInt<int>(templateArg);
837
0
                    } else if (containerNodeName == MatchCompiler::makeConstString("access")) {
838
0
                        const char* const indexArg = containerNode->Attribute("indexOperator");
839
0
                        if (indexArg)
840
0
                            container.arrayLike_indexOp = strcmp(indexArg, "array-like") == 0;
841
0
                    }
842
0
                } else if (containerNodeName == MatchCompiler::makeConstString("type")) {
843
0
                    const char* const templateArg = containerNode->Attribute("templateParameter");
844
0
                    if (templateArg)
845
0
                        container.type_templateArgNo = strToInt<int>(templateArg);
846
847
0
                    const char* const string = containerNode->Attribute("string");
848
0
                    if (string)
849
0
                        container.stdStringLike = strcmp(string, "std-like") == 0;
850
0
                    const char* const associative = containerNode->Attribute("associative");
851
0
                    if (associative)
852
0
                        container.stdAssociativeLike = strcmp(associative, "std-like") == 0;
853
0
                    const char* const unstable = containerNode->Attribute("unstable");
854
0
                    if (unstable) {
855
0
                        std::string unstableType = unstable;
856
0
                        if (unstableType.find("erase") != std::string::npos)
857
0
                            container.unstableErase = true;
858
0
                        if (unstableType.find("insert") != std::string::npos)
859
0
                            container.unstableInsert = true;
860
0
                    }
861
0
                } else if (containerNodeName == MatchCompiler::makeConstString("rangeItemRecordType")) {
862
0
                    for (const tinyxml2::XMLElement* memberNode = node->FirstChildElement(); memberNode; memberNode = memberNode->NextSiblingElement()) {
863
0
                        const char *memberName = memberNode->Attribute("name");
864
0
                        const char *memberTemplateParameter = memberNode->Attribute("templateParameter");
865
0
                        Container::RangeItemRecordTypeItem member;
866
0
                        member.name = memberName ? memberName : "";
867
0
                        member.templateParameter = memberTemplateParameter ? strToInt<int>(memberTemplateParameter) : -1;
868
0
                        container.rangeItemRecordType.emplace_back(std::move(member));
869
0
                    }
870
0
                } else
871
0
                    unknown_elements.insert(containerNodeName);
872
0
            }
873
0
        }
874
875
0
        else if (nodename == MatchCompiler::makeConstString("smart-pointer")) {
876
0
            const char *className = node->Attribute("class-name");
877
0
            if (!className)
878
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "class-name");
879
0
            SmartPointer& smartPointer = mData->mSmartPointers[className];
880
0
            smartPointer.name = className;
881
0
            for (const tinyxml2::XMLElement* smartPointerNode = node->FirstChildElement(); smartPointerNode;
882
0
                 smartPointerNode = smartPointerNode->NextSiblingElement()) {
883
0
                const std::string smartPointerNodeName = smartPointerNode->Name();
884
0
                if (smartPointerNodeName == MatchCompiler::makeConstString("unique"))
885
0
                    smartPointer.unique = true;
886
0
            }
887
0
        }
888
889
0
        else if (nodename == MatchCompiler::makeConstString("type-checks")) {
890
0
            for (const tinyxml2::XMLElement *checkNode = node->FirstChildElement(); checkNode; checkNode = checkNode->NextSiblingElement()) {
891
0
                const std::string &checkName = checkNode->Name();
892
0
                for (const tinyxml2::XMLElement *checkTypeNode = checkNode->FirstChildElement(); checkTypeNode; checkTypeNode = checkTypeNode->NextSiblingElement()) {
893
0
                    const std::string checkTypeName = checkTypeNode->Name();
894
0
                    const char *typeName = checkTypeNode->GetText();
895
0
                    if (!typeName)
896
0
                        continue;
897
0
                    if (checkTypeName == MatchCompiler::makeConstString("check"))
898
0
                        mData->mTypeChecks[std::pair<std::string,std::string>(checkName, typeName)] = TypeCheck::check;
899
0
                    else if (checkTypeName == MatchCompiler::makeConstString("suppress"))
900
0
                        mData->mTypeChecks[std::pair<std::string,std::string>(checkName, typeName)] = TypeCheck::suppress;
901
0
                    else if (checkTypeName == MatchCompiler::makeConstString("checkFiniteLifetime"))
902
0
                        mData->mTypeChecks[std::pair<std::string,std::string>(checkName, typeName)] = TypeCheck::checkFiniteLifetime;
903
0
                }
904
0
            }
905
0
        }
906
907
0
        else if (nodename == MatchCompiler::makeConstString("podtype")) {
908
0
            const char * const name = node->Attribute("name");
909
0
            if (!name)
910
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
911
0
            PodType podType;
912
0
            podType.stdtype = PodType::Type::NO;
913
0
            const char * const stdtype = node->Attribute("stdtype");
914
0
            if (stdtype) {
915
0
                if (std::strcmp(stdtype, "bool") == 0)
916
0
                    podType.stdtype = PodType::Type::BOOL;
917
0
                else if (std::strcmp(stdtype, "char") == 0)
918
0
                    podType.stdtype = PodType::Type::CHAR;
919
0
                else if (std::strcmp(stdtype, "short") == 0)
920
0
                    podType.stdtype = PodType::Type::SHORT;
921
0
                else if (std::strcmp(stdtype, "int") == 0)
922
0
                    podType.stdtype = PodType::Type::INT;
923
0
                else if (std::strcmp(stdtype, "long") == 0)
924
0
                    podType.stdtype = PodType::Type::LONG;
925
0
                else if (std::strcmp(stdtype, "long long") == 0)
926
0
                    podType.stdtype = PodType::Type::LONGLONG;
927
0
            }
928
0
            const char * const size = node->Attribute("size");
929
0
            if (size)
930
0
                podType.size = strToInt<unsigned int>(size);
931
0
            const char * const sign = node->Attribute("sign");
932
0
            if (sign)
933
0
                podType.sign = *sign;
934
0
            for (const std::string &s : getnames(name))
935
0
                mData->mPodTypes[s] = podType;
936
0
        }
937
938
0
        else if (nodename == MatchCompiler::makeConstString("platformtype")) {
939
0
            const char * const type_name = node->Attribute("name");
940
0
            if (type_name == nullptr)
941
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
942
0
            const char *value = node->Attribute("value");
943
0
            if (value == nullptr)
944
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "value");
945
0
            PlatformType type;
946
0
            type.mType = value;
947
0
            std::set<std::string> platform;
948
0
            for (const tinyxml2::XMLElement *typenode = node->FirstChildElement(); typenode; typenode = typenode->NextSiblingElement()) {
949
0
                const std::string typenodename = typenode->Name();
950
0
                if (typenodename == MatchCompiler::makeConstString("platform")) {
951
0
                    const char * const type_attribute = typenode->Attribute("type");
952
0
                    if (type_attribute == nullptr)
953
0
                        return Error(ErrorCode::MISSING_ATTRIBUTE, "type");
954
0
                    platform.insert(type_attribute);
955
0
                } else if (typenodename == MatchCompiler::makeConstString("signed"))
956
0
                    type.mSigned = true;
957
0
                else if (typenodename == MatchCompiler::makeConstString("unsigned"))
958
0
                    type.mUnsigned = true;
959
0
                else if (typenodename == MatchCompiler::makeConstString("long"))
960
0
                    type.mLong = true;
961
0
                else if (typenodename == MatchCompiler::makeConstString("pointer"))
962
0
                    type.mPointer= true;
963
0
                else if (typenodename == MatchCompiler::makeConstString("ptr_ptr"))
964
0
                    type.mPtrPtr = true;
965
0
                else if (typenodename == MatchCompiler::makeConstString("const_ptr"))
966
0
                    type.mConstPtr = true;
967
0
                else
968
0
                    unknown_elements.insert(typenodename);
969
0
            }
970
0
            if (platform.empty()) {
971
0
                const PlatformType * const type_ptr = platform_type(type_name, emptyString);
972
0
                if (type_ptr) {
973
0
                    if (*type_ptr == type)
974
0
                        return Error(ErrorCode::DUPLICATE_PLATFORM_TYPE, type_name);
975
0
                    return Error(ErrorCode::PLATFORM_TYPE_REDEFINED, type_name);
976
0
                }
977
0
                mData->mPlatformTypes[type_name] = std::move(type);
978
0
            } else {
979
0
                for (const std::string &p : platform) {
980
0
                    const PlatformType * const type_ptr = platform_type(type_name, p);
981
0
                    if (type_ptr) {
982
0
                        if (*type_ptr == type)
983
0
                            return Error(ErrorCode::DUPLICATE_PLATFORM_TYPE, type_name);
984
0
                        return Error(ErrorCode::PLATFORM_TYPE_REDEFINED, type_name);
985
0
                    }
986
0
                    mData->mPlatforms[p].mPlatformTypes[type_name] = type;
987
0
                }
988
0
            }
989
0
        }
990
991
0
        else if (nodename == MatchCompiler::makeConstString("entrypoint")) {
992
0
            const char * const type_name = node->Attribute("name");
993
0
            if (type_name == nullptr)
994
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
995
0
            mData->mEntrypoints.emplace(type_name);
996
0
        }
997
998
0
        else
999
0
            unknown_elements.insert(nodename);
1000
0
    }
1001
0
    if (!unknown_elements.empty()) {
1002
0
        std::string str;
1003
0
        for (auto i = unknown_elements.cbegin(); i != unknown_elements.cend();) {
1004
0
            str += *i;
1005
0
            if (++i != unknown_elements.end())
1006
0
                str += ", ";
1007
0
        }
1008
0
        return Error(ErrorCode::UNKNOWN_ELEMENT, str);
1009
0
    }
1010
0
    return Error(ErrorCode::OK);
1011
0
}
1012
1013
Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, const std::string &name, std::set<std::string> &unknown_elements)
1014
0
{
1015
0
    if (name.empty())
1016
0
        return Error(ErrorCode::OK);
1017
1018
    // TODO: write debug warning if we modify an existing entry
1019
0
    Function& func = mData->mFunctions[name];
1020
1021
0
    for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) {
1022
0
        const std::string functionnodename = functionnode->Name();
1023
0
        if (functionnodename == MatchCompiler::makeConstString("noreturn")) {
1024
0
            const char * const text = functionnode->GetText();
1025
0
            if (strcmp(text, "false") == 0)
1026
0
                mData->mNoReturn[name] = LibraryData::FalseTrueMaybe::False;
1027
0
            else if (strcmp(text, "maybe") == 0)
1028
0
                mData->mNoReturn[name] = LibraryData::FalseTrueMaybe::Maybe;
1029
0
            else
1030
0
                mData->mNoReturn[name] = LibraryData::FalseTrueMaybe::True; // Safe
1031
0
        } else if (functionnodename == MatchCompiler::makeConstString("pure"))
1032
0
            func.ispure = true;
1033
0
        else if (functionnodename == MatchCompiler::makeConstString("const")) {
1034
0
            func.ispure = true;
1035
0
            func.isconst = true; // a constant function is pure
1036
0
        } else if (functionnodename == MatchCompiler::makeConstString("leak-ignore"))
1037
0
            func.leakignore = true;
1038
0
        else if (functionnodename == MatchCompiler::makeConstString("not-overlapping-data")) {
1039
0
            NonOverlappingData nonOverlappingData;
1040
0
            nonOverlappingData.ptr1Arg = functionnode->IntAttribute("ptr1-arg", -1);
1041
0
            nonOverlappingData.ptr2Arg = functionnode->IntAttribute("ptr2-arg", -1);
1042
0
            nonOverlappingData.sizeArg = functionnode->IntAttribute("size-arg", -1);
1043
0
            nonOverlappingData.strlenArg = functionnode->IntAttribute("strlen-arg", -1);
1044
0
            nonOverlappingData.countArg = functionnode->IntAttribute("count-arg", -1);
1045
0
            mData->mNonOverlappingData[name] = nonOverlappingData;
1046
0
        } else if (functionnodename == MatchCompiler::makeConstString("use-retval")) {
1047
0
            func.useretval = Library::UseRetValType::DEFAULT;
1048
0
            if (const char *type = functionnode->Attribute("type"))
1049
0
                if (std::strcmp(type, "error-code") == 0)
1050
0
                    func.useretval = Library::UseRetValType::ERROR_CODE;
1051
0
        } else if (functionnodename == MatchCompiler::makeConstString("returnValue")) {
1052
0
            if (const char *expr = functionnode->GetText())
1053
0
                mData->mReturnValue[name] = expr;
1054
0
            if (const char *type = functionnode->Attribute("type"))
1055
0
                mData->mReturnValueType[name] = type;
1056
0
            if (const char *container = functionnode->Attribute("container"))
1057
0
                mData->mReturnValueContainer[name] = strToInt<int>(container);
1058
            // cppcheck-suppress shadowFunction - TODO: fix this
1059
0
            if (const char *unknownReturnValues = functionnode->Attribute("unknownValues")) {
1060
0
                if (std::strcmp(unknownReturnValues, "all") == 0) {
1061
0
                    std::vector<MathLib::bigint> values{LLONG_MIN, LLONG_MAX};
1062
0
                    mData->mUnknownReturnValues[name] = std::move(values);
1063
0
                }
1064
0
            }
1065
0
        } else if (functionnodename == MatchCompiler::makeConstString("arg")) {
1066
0
            const char* argNrString = functionnode->Attribute("nr");
1067
0
            if (!argNrString)
1068
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "nr");
1069
0
            const bool bAnyArg = strcmp(argNrString, "any") == 0;
1070
0
            const bool bVariadicArg = strcmp(argNrString, "variadic") == 0;
1071
0
            const int nr = (bAnyArg || bVariadicArg) ? -1 : strToInt<int>(argNrString);
1072
0
            ArgumentChecks &ac = func.argumentChecks[nr];
1073
0
            ac.optional  = functionnode->Attribute("default") != nullptr;
1074
0
            ac.variadic = bVariadicArg;
1075
0
            const char * const argDirection = functionnode->Attribute("direction");
1076
0
            if (argDirection) {
1077
0
                const size_t argDirLen = strlen(argDirection);
1078
0
                ArgumentChecks::Direction dir = ArgumentChecks::Direction::DIR_UNKNOWN;
1079
0
                if (!strncmp(argDirection, "in", argDirLen)) {
1080
0
                    dir = ArgumentChecks::Direction::DIR_IN;
1081
0
                } else if (!strncmp(argDirection, "out", argDirLen)) {
1082
0
                    dir = ArgumentChecks::Direction::DIR_OUT;
1083
0
                } else if (!strncmp(argDirection, "inout", argDirLen)) {
1084
0
                    dir = ArgumentChecks::Direction::DIR_INOUT;
1085
0
                }
1086
0
                if (const char* const argIndirect = functionnode->Attribute("indirect")) {
1087
0
                    const int indirect = strToInt<int>(argIndirect);
1088
0
                    ac.direction[indirect] = dir; // TODO: handle multiple directions/indirect levels
1089
0
                }
1090
0
                else
1091
0
                    ac.direction.fill(dir);
1092
0
            }
1093
0
            for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
1094
0
                const std::string argnodename = argnode->Name();
1095
0
                int indirect = 0;
1096
0
                const char * const indirectStr = argnode->Attribute("indirect");
1097
0
                if (indirectStr)
1098
0
                    indirect = strToInt<int>(indirectStr);
1099
0
                if (argnodename == MatchCompiler::makeConstString("not-bool"))
1100
0
                    ac.notbool = true;
1101
0
                else if (argnodename == MatchCompiler::makeConstString("not-null"))
1102
0
                    ac.notnull = true;
1103
0
                else if (argnodename == MatchCompiler::makeConstString("not-uninit"))
1104
0
                    ac.notuninit = indirect;
1105
0
                else if (argnodename == MatchCompiler::makeConstString("formatstr"))
1106
0
                    ac.formatstr = true;
1107
0
                else if (argnodename == MatchCompiler::makeConstString("strz"))
1108
0
                    ac.strz = true;
1109
0
                else if (argnodename == MatchCompiler::makeConstString("valid")) {
1110
                    // Validate the validation expression
1111
0
                    const char *p = argnode->GetText();
1112
0
                    if (!isCompliantValidationExpression(p))
1113
0
                        return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, (!p ? "\"\"" : p));
1114
                    // Set validation expression
1115
0
                    ac.valid = p;
1116
0
                }
1117
0
                else if (argnodename == MatchCompiler::makeConstString("minsize")) {
1118
0
                    const char *typeattr = argnode->Attribute("type");
1119
0
                    if (!typeattr)
1120
0
                        return Error(ErrorCode::MISSING_ATTRIBUTE, "type");
1121
1122
0
                    ArgumentChecks::MinSize::Type type;
1123
0
                    if (strcmp(typeattr,"strlen")==0)
1124
0
                        type = ArgumentChecks::MinSize::Type::STRLEN;
1125
0
                    else if (strcmp(typeattr,"argvalue")==0)
1126
0
                        type = ArgumentChecks::MinSize::Type::ARGVALUE;
1127
0
                    else if (strcmp(typeattr,"sizeof")==0)
1128
0
                        type = ArgumentChecks::MinSize::Type::SIZEOF;
1129
0
                    else if (strcmp(typeattr,"mul")==0)
1130
0
                        type = ArgumentChecks::MinSize::Type::MUL;
1131
0
                    else if (strcmp(typeattr,"value")==0)
1132
0
                        type = ArgumentChecks::MinSize::Type::VALUE;
1133
0
                    else
1134
0
                        return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, typeattr);
1135
1136
0
                    if (type == ArgumentChecks::MinSize::Type::VALUE) {
1137
0
                        const char *valueattr = argnode->Attribute("value");
1138
0
                        if (!valueattr)
1139
0
                            return Error(ErrorCode::MISSING_ATTRIBUTE, "value");
1140
0
                        long long minsizevalue = 0;
1141
0
                        try {
1142
0
                            minsizevalue = strToInt<long long>(valueattr);
1143
0
                        } catch (const std::runtime_error&) {
1144
0
                            return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, valueattr);
1145
0
                        }
1146
0
                        if (minsizevalue <= 0)
1147
0
                            return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, valueattr);
1148
0
                        ac.minsizes.emplace_back(type, 0);
1149
0
                        ac.minsizes.back().value = minsizevalue;
1150
0
                    } else {
1151
0
                        const char *argattr = argnode->Attribute("arg");
1152
0
                        if (!argattr)
1153
0
                            return Error(ErrorCode::MISSING_ATTRIBUTE, "arg");
1154
0
                        if (strlen(argattr) != 1 || argattr[0]<'0' || argattr[0]>'9')
1155
0
                            return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, argattr);
1156
1157
0
                        ac.minsizes.reserve(type == ArgumentChecks::MinSize::Type::MUL ? 2 : 1);
1158
0
                        ac.minsizes.emplace_back(type, argattr[0] - '0');
1159
0
                        if (type == ArgumentChecks::MinSize::Type::MUL) {
1160
0
                            const char *arg2attr = argnode->Attribute("arg2");
1161
0
                            if (!arg2attr)
1162
0
                                return Error(ErrorCode::MISSING_ATTRIBUTE, "arg2");
1163
0
                            if (strlen(arg2attr) != 1 || arg2attr[0]<'0' || arg2attr[0]>'9')
1164
0
                                return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, arg2attr);
1165
0
                            ac.minsizes.back().arg2 = arg2attr[0] - '0';
1166
0
                        }
1167
0
                    }
1168
0
                    const char* baseTypeAttr = argnode->Attribute("baseType"); // used by VALUE, ARGVALUE
1169
0
                    if (baseTypeAttr)
1170
0
                        ac.minsizes.back().baseType = baseTypeAttr;
1171
0
                }
1172
1173
0
                else if (argnodename == MatchCompiler::makeConstString("iterator")) {
1174
0
                    ac.iteratorInfo.it = true;
1175
0
                    const char* str = argnode->Attribute("type");
1176
0
                    ac.iteratorInfo.first = (str && std::strcmp(str, "first") == 0);
1177
0
                    ac.iteratorInfo.last = (str && std::strcmp(str, "last") == 0);
1178
0
                    ac.iteratorInfo.container = argnode->IntAttribute("container", 0);
1179
0
                }
1180
1181
0
                else
1182
0
                    unknown_elements.insert(argnodename);
1183
0
            }
1184
0
            if (ac.notuninit == 0)
1185
0
                ac.notuninit = ac.notnull ? 1 : 0;
1186
0
        } else if (functionnodename == MatchCompiler::makeConstString("ignorefunction")) {
1187
0
            func.ignore = true;
1188
0
        } else if (functionnodename == MatchCompiler::makeConstString("formatstr")) {
1189
0
            func.formatstr = true;
1190
0
            const tinyxml2::XMLAttribute* scan = functionnode->FindAttribute("scan");
1191
0
            const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure");
1192
0
            func.formatstr_scan = scan && scan->BoolValue();
1193
0
            func.formatstr_secure = secure && secure->BoolValue();
1194
0
        } else if (functionnodename == MatchCompiler::makeConstString("warn")) {
1195
0
            WarnInfo wi;
1196
0
            const char* const severity = functionnode->Attribute("severity");
1197
0
            if (severity == nullptr)
1198
0
                return Error(ErrorCode::MISSING_ATTRIBUTE, "severity");
1199
0
            wi.severity = severityFromString(severity);
1200
1201
0
            const char* const cstd = functionnode->Attribute("cstd");
1202
0
            if (cstd) {
1203
0
                if (!wi.standards.setC(cstd))
1204
0
                    return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, cstd);
1205
0
            } else
1206
0
                wi.standards.c = Standards::C89;
1207
1208
0
            const char* const cppstd = functionnode->Attribute("cppstd");
1209
0
            if (cppstd) {
1210
0
                if (!wi.standards.setCPP(cppstd))
1211
0
                    return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, cppstd);
1212
0
            } else
1213
0
                wi.standards.cpp = Standards::CPP03;
1214
1215
0
            const char* const reason = functionnode->Attribute("reason");
1216
0
            const char* const alternatives = functionnode->Attribute("alternatives");
1217
0
            if (reason && alternatives) {
1218
                // Construct message
1219
0
                wi.message = std::string(reason) + " function '" + name + "' called. It is recommended to use ";
1220
0
                std::vector<std::string> alt = getnames(alternatives);
1221
0
                for (std::size_t i = 0; i < alt.size(); ++i) {
1222
0
                    wi.message += "'" + alt[i] + "'";
1223
0
                    if (i == alt.size() - 1)
1224
0
                        wi.message += " instead.";
1225
0
                    else if (i == alt.size() - 2)
1226
0
                        wi.message += " or ";
1227
0
                    else
1228
0
                        wi.message += ", ";
1229
0
                }
1230
0
            } else {
1231
0
                const char * const message = functionnode->GetText();
1232
0
                if (!message)
1233
0
                    return Error(ErrorCode::MISSING_ATTRIBUTE, "\"reason\" and \"alternatives\" or some text.");
1234
1235
0
                wi.message = message;
1236
0
            }
1237
1238
0
            mData->mFunctionwarn[name] = std::move(wi);
1239
0
        } else if (functionnodename == MatchCompiler::makeConstString("container")) {
1240
0
            const char* const action_ptr = functionnode->Attribute("action");
1241
0
            Container::Action action = Container::Action::NO_ACTION;
1242
0
            if (action_ptr) {
1243
0
                std::string actionName = action_ptr;
1244
0
                action = Container::actionFrom(actionName);
1245
0
                if (action == Container::Action::NO_ACTION)
1246
0
                    return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, actionName);
1247
0
            }
1248
0
            func.containerAction = action;
1249
1250
0
            const char* const yield_ptr = functionnode->Attribute("yields");
1251
0
            Container::Yield yield = Container::Yield::NO_YIELD;
1252
0
            if (yield_ptr) {
1253
0
                std::string yieldName = yield_ptr;
1254
0
                yield = Container::yieldFrom(yieldName);
1255
0
                if (yield == Container::Yield::NO_YIELD)
1256
0
                    return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, yieldName);
1257
0
            }
1258
0
            func.containerYield = yield;
1259
1260
0
            const char* const returnType = functionnode->Attribute("returnType");
1261
0
            if (returnType)
1262
0
                func.returnType = returnType;
1263
0
        } else
1264
0
            unknown_elements.insert(functionnodename);
1265
0
    }
1266
0
    return Error(ErrorCode::OK);
1267
0
}
1268
1269
bool Library::isIntArgValid(const Token *ftok, int argnr, const MathLib::bigint argvalue) const
1270
1.15k
{
1271
1.15k
    const ArgumentChecks *ac = getarg(ftok, argnr);
1272
1.15k
    if (!ac || ac->valid.empty())
1273
1.15k
        return true;
1274
0
    if (ac->valid.find('.') != std::string::npos)
1275
0
        return isFloatArgValid(ftok, argnr, static_cast<double>(argvalue));
1276
0
    TokenList tokenList(nullptr);
1277
0
    gettokenlistfromvalid(ac->valid, ftok->isCpp(), tokenList);
1278
0
    for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
1279
0
        if (tok->isNumber() && argvalue == MathLib::toBigNumber(tok))
1280
0
            return true;
1281
0
        if (match2(tok) && argvalue >= MathLib::toBigNumber(tok) && argvalue <= MathLib::toBigNumber(tok->tokAt(2)))
1282
0
            return true;
1283
0
        if (match3(tok) && argvalue >= MathLib::toBigNumber(tok))
1284
0
            return true;
1285
0
        if ((!tok->previous() || tok->strAt(-1) == MatchCompiler::makeConstString(",")) && match4(tok) && argvalue <= MathLib::toBigNumber(tok->tokAt(1)))
1286
0
            return true;
1287
0
    }
1288
0
    return false;
1289
0
}
1290
1291
bool Library::isFloatArgValid(const Token *ftok, int argnr, double argvalue) const
1292
0
{
1293
0
    const ArgumentChecks *ac = getarg(ftok, argnr);
1294
0
    if (!ac || ac->valid.empty())
1295
0
        return true;
1296
0
    TokenList tokenList(nullptr);
1297
0
    gettokenlistfromvalid(ac->valid, ftok->isCpp(), tokenList);
1298
0
    for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
1299
0
        if (match2(tok) && argvalue >= MathLib::toDoubleNumber(tok) && argvalue <= MathLib::toDoubleNumber(tok->tokAt(2)))
1300
0
            return true;
1301
0
        if (match3(tok) && argvalue >= MathLib::toDoubleNumber(tok))
1302
0
            return true;
1303
0
        if ((!tok->previous() || tok->strAt(-1) == MatchCompiler::makeConstString(",")) && match4(tok) && argvalue <= MathLib::toDoubleNumber(tok->tokAt(1)))
1304
0
            return true;
1305
0
        if (match5(tok) && MathLib::isFloat(tok->str()) && MathLib::isEqual(tok->str(), MathLib::toString(argvalue)))
1306
0
            return true;
1307
0
        if (match6(tok) && MathLib::isFloat(tok->strAt(1)))
1308
0
            return MathLib::isNotEqual(tok->strAt(1), MathLib::toString(argvalue));
1309
0
    }
1310
0
    return false;
1311
0
}
1312
1313
std::string Library::getFunctionName(const Token *ftok, bool &error) const
1314
2.34k
{
1315
2.34k
    if (!ftok) {
1316
1
        error = true;
1317
1
        return "";
1318
1
    }
1319
2.34k
    if (ftok->isName()) {
1320
2.34k
        if (match7(ftok->astParent()))
1321
0
            return ftok->str();
1322
7.92k
        for (const Scope *scope = ftok->scope(); scope; scope = scope->nestedIn) {
1323
5.57k
            if (!scope->isClassOrStruct())
1324
5.57k
                continue;
1325
0
            const std::vector<Type::BaseInfo> &derivedFrom = scope->definedType->derivedFrom;
1326
0
            for (const Type::BaseInfo & baseInfo : derivedFrom) {
1327
0
                std::string name;
1328
0
                const Token* tok = baseInfo.nameTok; // baseInfo.name still contains template parameters, but is missing namespaces
1329
0
                if (tok->str() == MatchCompiler::makeConstString("::"))
1330
0
                    tok = tok->next();
1331
0
                while (match8(tok)) {
1332
0
                    name += tok->str();
1333
0
                    tok = tok->next();
1334
0
                }
1335
0
                name += "::" + ftok->str();
1336
0
                if (mData->mFunctions.find(name) != mData->mFunctions.end() && matchArguments(ftok, name))
1337
0
                    return name;
1338
0
            }
1339
0
        }
1340
2.34k
        return ftok->str();
1341
2.34k
    }
1342
0
    if (ftok->str() == MatchCompiler::makeConstString("::")) {
1343
0
        if (!ftok->astOperand2())
1344
0
            return getFunctionName(ftok->astOperand1(), error);
1345
0
        return getFunctionName(ftok->astOperand1(),error) + "::" + getFunctionName(ftok->astOperand2(),error);
1346
0
    }
1347
0
    if (ftok->str() == MatchCompiler::makeConstString(".") && ftok->astOperand1()) {
1348
0
        const std::string type = astCanonicalType(ftok->astOperand1(), ftok->originalName() == MatchCompiler::makeConstString("->"));
1349
0
        if (type.empty()) {
1350
0
            error = true;
1351
0
            return "";
1352
0
        }
1353
1354
0
        return type + "::" + getFunctionName(ftok->astOperand2(),error);
1355
0
    }
1356
0
    error = true;
1357
0
    return "";
1358
0
}
1359
1360
std::string Library::getFunctionName(const Token *ftok) const
1361
29.2k
{
1362
29.2k
    if (!match9(ftok) && (ftok->strAt(-1) != MatchCompiler::makeConstString("&") || ftok->previous()->astOperand2()))
1363
24.3k
        return "";
1364
1365
    // Lookup function name using AST..
1366
4.92k
    if (ftok->astParent()) {
1367
2.34k
        bool error = false;
1368
2.34k
        const Token * tok = ftok->astParent()->isUnaryOp("&") ? ftok->astParent()->astOperand1() : ftok->next()->astOperand1();
1369
2.34k
        std::string ret = getFunctionName(tok, error);
1370
2.34k
        if (error)
1371
1
            return {};
1372
2.34k
        if (startsWith(ret, "::"))
1373
0
            ret.erase(0, 2);
1374
2.34k
        return ret;
1375
2.34k
    }
1376
1377
    // Lookup function name without using AST..
1378
2.58k
    if (match10(ftok->previous()))
1379
0
        return "";
1380
2.58k
    if (!match11(ftok->tokAt(-2)))
1381
2.58k
        return ftok->str();
1382
0
    std::string ret(ftok->str());
1383
0
    ftok = ftok->tokAt(-2);
1384
0
    while (match11(ftok)) {
1385
0
        ret = ftok->str() + "::" + ret;
1386
0
        ftok = ftok->tokAt(-2);
1387
0
    }
1388
0
    return ret;
1389
2.58k
}
1390
1391
bool Library::isnullargbad(const Token *ftok, int argnr) const
1392
652
{
1393
652
    const ArgumentChecks *arg = getarg(ftok, argnr);
1394
652
    if (!arg) {
1395
        // scan format string argument should not be null
1396
652
        const std::string funcname = getFunctionName(ftok);
1397
652
        const auto it = utils::as_const(mData->mFunctions).find(funcname);
1398
652
        if (it != mData->mFunctions.cend() && it->second.formatstr && it->second.formatstr_scan)
1399
0
            return true;
1400
652
    }
1401
652
    return arg && arg->notnull;
1402
652
}
1403
1404
bool Library::isuninitargbad(const Token *ftok, int argnr, int indirect, bool *hasIndirect) const
1405
0
{
1406
0
    const ArgumentChecks *arg = getarg(ftok, argnr);
1407
0
    if (!arg) {
1408
        // non-scan format string argument should not be uninitialized
1409
0
        const std::string funcname = getFunctionName(ftok);
1410
0
        const auto it = utils::as_const(mData->mFunctions).find(funcname);
1411
0
        if (it != mData->mFunctions.cend() && it->second.formatstr && !it->second.formatstr_scan)
1412
0
            return true;
1413
0
    }
1414
0
    if (hasIndirect && arg && arg->notuninit >= 1)
1415
0
        *hasIndirect = true;
1416
0
    return arg && arg->notuninit >= indirect;
1417
0
}
1418
1419
1420
/** get allocation info for function */
1421
const Library::AllocFunc* Library::getAllocFuncInfo(const Token *tok) const
1422
1.12k
{
1423
1.12k
    while (match7(tok))
1424
0
        tok = tok->astOperand2() ? tok->astOperand2() : tok->astOperand1();
1425
1.12k
    if (!tok)
1426
0
        return nullptr;
1427
1.12k
    const std::string funcname = getFunctionName(tok);
1428
1.12k
    return isNotLibraryFunction(tok) && mData->mFunctions.find(funcname) != mData->mFunctions.end() ? nullptr : getAllocDealloc(mData->mAlloc, funcname);
1429
1.12k
}
1430
1431
/** get deallocation info for function */
1432
const Library::AllocFunc* Library::getDeallocFuncInfo(const Token *tok) const
1433
32
{
1434
32
    while (match7(tok))
1435
0
        tok = tok->astOperand2() ? tok->astOperand2() : tok->astOperand1();
1436
32
    if (!tok)
1437
0
        return nullptr;
1438
32
    const std::string funcname = getFunctionName(tok);
1439
32
    return isNotLibraryFunction(tok) && mData->mFunctions.find(funcname) != mData->mFunctions.end() ? nullptr : getAllocDealloc(mData->mDealloc, funcname);
1440
32
}
1441
1442
/** get reallocation info for function */
1443
const Library::AllocFunc* Library::getReallocFuncInfo(const Token *tok) const
1444
840
{
1445
840
    while (match7(tok))
1446
0
        tok = tok->astOperand2() ? tok->astOperand2() : tok->astOperand1();
1447
840
    if (!tok)
1448
0
        return nullptr;
1449
840
    const std::string funcname = getFunctionName(tok);
1450
840
    return isNotLibraryFunction(tok) && mData->mFunctions.find(funcname) != mData->mFunctions.end() ? nullptr : getAllocDealloc(mData->mRealloc, funcname);
1451
840
}
1452
1453
/** get allocation id for function */
1454
int Library::getAllocId(const Token *tok, int arg) const
1455
722
{
1456
722
    const Library::AllocFunc* af = getAllocFuncInfo(tok);
1457
722
    return (af && af->arg == arg) ? af->groupId : 0;
1458
722
}
1459
1460
/** get deallocation id for function */
1461
int Library::getDeallocId(const Token *tok, int arg) const
1462
0
{
1463
0
    const Library::AllocFunc* af = getDeallocFuncInfo(tok);
1464
0
    return (af && af->arg == arg) ? af->groupId : 0;
1465
0
}
1466
1467
/** get reallocation id for function */
1468
int Library::getReallocId(const Token *tok, int arg) const
1469
0
{
1470
0
    const Library::AllocFunc* af = getReallocFuncInfo(tok);
1471
0
    return (af && af->arg == arg) ? af->groupId : 0;
1472
0
}
1473
1474
1475
const Library::ArgumentChecks * Library::getarg(const Token *ftok, int argnr) const
1476
3.61k
{
1477
3.61k
    const Function* func = nullptr;
1478
3.61k
    if (isNotLibraryFunction(ftok, &func))
1479
3.61k
        return nullptr;
1480
0
    const auto it2 = utils::as_const(func->argumentChecks).find(argnr);
1481
0
    if (it2 != func->argumentChecks.cend())
1482
0
        return &it2->second;
1483
0
    const auto it3 = utils::as_const(func->argumentChecks).find(-1);
1484
0
    if (it3 != func->argumentChecks.cend())
1485
0
        return &it3->second;
1486
0
    return nullptr;
1487
0
}
1488
1489
bool Library::isScopeNoReturn(const Token *end, std::string *unknownFunc) const
1490
29
{
1491
29
    if (unknownFunc)
1492
29
        unknownFunc->clear();
1493
1494
29
    if (match12(end->tokAt(-2))) {
1495
0
        const Token *lastTop = end->tokAt(-2)->astTop();
1496
0
        if (match13(lastTop) &&
1497
0
            match14(lastTop->astOperand1()) &&
1498
0
            match15(lastTop->astOperand1()->previous()))
1499
0
            return isnoreturn(lastTop->astOperand1()->previous());
1500
0
    }
1501
1502
29
    if (!match16(end->tokAt(-2)))
1503
29
        return false;
1504
1505
0
    const Token *funcname = end->linkAt(-2)->previous();
1506
0
    if (funcname->isCpp() && funcname->astTop()->str() == MatchCompiler::makeConstString("throw"))
1507
0
        return true;
1508
0
    const Token *start = funcname;
1509
0
    if (match17(funcname->tokAt(-3))) {
1510
0
        funcname = funcname->previous();
1511
0
        start = funcname->tokAt(-3);
1512
0
    } else if (funcname->isName()) {
1513
0
        while (match18(start))
1514
0
            start = start->previous();
1515
0
    } else {
1516
0
        return false;
1517
0
    }
1518
0
    if (match19(start) && match9(funcname)) {
1519
0
        if (funcname->isKeyword())
1520
0
            return false;
1521
0
        if (funcname->str() == MatchCompiler::makeConstString("exit"))
1522
0
            return true;
1523
0
        if (!isnotnoreturn(funcname)) {
1524
0
            if (unknownFunc && !isnoreturn(funcname))
1525
0
                *unknownFunc = funcname->str();
1526
0
            return true;
1527
0
        }
1528
0
    }
1529
0
    return false;
1530
0
}
1531
1532
// cppcheck-suppress unusedFunction - used in tests only
1533
const std::unordered_map<std::string, Library::Container>& Library::containers() const
1534
0
{
1535
0
    return mData->mContainers;
1536
0
}
1537
1538
const Library::Container* Library::detectContainerInternal(const Token* const typeStart, DetectContainer detect, bool* isIterator, bool withoutStd) const
1539
69.9k
{
1540
69.9k
    if (!typeStart)
1541
0
        return nullptr;
1542
69.9k
    const Token* firstLinkedTok = nullptr;
1543
148k
    for (const Token* tok = typeStart; tok && !tok->varId(); tok = tok->next()) {
1544
94.5k
        if (!tok->link())
1545
79.0k
            continue;
1546
1547
15.4k
        firstLinkedTok = tok;
1548
15.4k
        break;
1549
94.5k
    }
1550
1551
69.9k
    for (const std::pair<const std::string, Library::Container> & c : mData->mContainers) {
1552
0
        const Container& container = c.second;
1553
0
        if (container.startPattern.empty())
1554
0
            continue;
1555
1556
0
        const int offset = (withoutStd && startsWith(container.startPattern2, "std :: ")) ? 7 : 0;
1557
1558
        // If endPattern is undefined, it will always match, but itEndPattern has to be defined.
1559
0
        if (detect != IteratorOnly && container.endPattern.empty()) {
1560
0
            if (!Token::Match(typeStart, container.startPattern2.c_str() + offset))
1561
0
                continue;
1562
1563
0
            if (isIterator)
1564
0
                *isIterator = false;
1565
0
            return &container;
1566
0
        }
1567
1568
0
        if (!firstLinkedTok)
1569
0
            continue;
1570
1571
0
        const bool matchedStartPattern = Token::Match(typeStart, container.startPattern2.c_str() + offset);
1572
0
        if (!matchedStartPattern)
1573
0
            continue;
1574
1575
0
        if (detect != ContainerOnly && Token::Match(firstLinkedTok->link(), container.itEndPattern.c_str())) {
1576
0
            if (isIterator)
1577
0
                *isIterator = true;
1578
0
            return &container;
1579
0
        }
1580
0
        if (detect != IteratorOnly && Token::Match(firstLinkedTok->link(), container.endPattern.c_str())) {
1581
0
            if (isIterator)
1582
0
                *isIterator = false;
1583
0
            return &container;
1584
0
        }
1585
0
    }
1586
69.9k
    return nullptr;
1587
69.9k
}
1588
1589
const Library::Container* Library::detectContainer(const Token* typeStart) const
1590
3.82k
{
1591
3.82k
    return detectContainerInternal(typeStart, ContainerOnly);
1592
3.82k
}
1593
1594
const Library::Container* Library::detectIterator(const Token* typeStart) const
1595
0
{
1596
0
    return detectContainerInternal(typeStart, IteratorOnly);
1597
0
}
1598
1599
const Library::Container* Library::detectContainerOrIterator(const Token* typeStart, bool* isIterator, bool withoutStd) const
1600
66.0k
{
1601
66.0k
    bool res;
1602
66.0k
    const Library::Container* c = detectContainerInternal(typeStart, Both, &res, withoutStd);
1603
66.0k
    if (c && isIterator)
1604
0
        *isIterator = res;
1605
66.0k
    return c;
1606
66.0k
}
1607
1608
bool Library::isContainerYield(const Token * const cond, Library::Container::Yield y, const std::string& fallback)
1609
126
{
1610
126
    if (!cond)
1611
0
        return false;
1612
126
    if (cond->str() == MatchCompiler::makeConstString("(")) {
1613
0
        const Token* tok = cond->astOperand1();
1614
0
        if (tok && tok->str() == MatchCompiler::makeConstString(".")) {
1615
0
            if (tok->astOperand1() && tok->astOperand1()->valueType()) {
1616
0
                if (const Library::Container *container = tok->astOperand1()->valueType()->container) {
1617
0
                    return tok->astOperand2() && y == container->getYield(tok->astOperand2()->str());
1618
0
                }
1619
0
            } else if (!fallback.empty()) {
1620
0
                return match20(cond) && cond->strAt(-1) == fallback;
1621
0
            }
1622
0
        }
1623
0
    }
1624
126
    return false;
1625
126
}
1626
1627
Library::Container::Yield Library::getContainerYield(const Token* const cond)
1628
0
{
1629
0
    if (match14(cond)) {
1630
0
        const Token* tok = cond->astOperand1();
1631
0
        if (tok && tok->str() == MatchCompiler::makeConstString(".")) {
1632
0
            if (tok->astOperand1() && tok->astOperand1()->valueType()) {
1633
0
                if (const Library::Container *container = tok->astOperand1()->valueType()->container) {
1634
0
                    if (tok->astOperand2())
1635
0
                        return container->getYield(tok->astOperand2()->str());
1636
0
                }
1637
0
            }
1638
0
        }
1639
0
    }
1640
0
    return Library::Container::Yield::NO_YIELD;
1641
0
}
1642
1643
// returns true if ftok is not a library function
1644
bool Library::isNotLibraryFunction(const Token *ftok, const Function **func) const
1645
54.3k
{
1646
54.3k
    if (ftok->isKeyword() || ftok->isStandardType())
1647
19.3k
        return true;
1648
1649
35.0k
    if (ftok->function() && ftok->function()->nestedIn && ftok->function()->nestedIn->type != Scope::eGlobal)
1650
0
        return true;
1651
1652
    // variables are not library functions.
1653
35.0k
    if (ftok->varId())
1654
8.39k
        return true;
1655
1656
26.6k
    return !matchArguments(ftok, getFunctionName(ftok), func);
1657
35.0k
}
1658
1659
bool Library::matchArguments(const Token *ftok, const std::string &functionName, const Function **func) const
1660
26.6k
{
1661
26.6k
    if (functionName.empty())
1662
24.2k
        return false;
1663
2.39k
    const auto it = utils::as_const(mData->mFunctions).find(functionName);
1664
2.39k
    if (it == mData->mFunctions.cend())
1665
2.39k
        return false;
1666
0
    const int callargs = numberOfArgumentsWithoutAst(ftok);
1667
0
    int args = 0;
1668
0
    int firstOptionalArg = -1;
1669
0
    for (const std::pair<const int, Library::ArgumentChecks> & argCheck : it->second.argumentChecks) {
1670
0
        args = std::max(argCheck.first, args);
1671
0
        if (argCheck.second.optional && (firstOptionalArg == -1 || firstOptionalArg > argCheck.first))
1672
0
            firstOptionalArg = argCheck.first;
1673
1674
0
        if (argCheck.second.formatstr || argCheck.second.variadic) {
1675
0
            const bool b = args <= callargs;
1676
0
            if (b && func)
1677
0
                *func = &it->second;
1678
0
            return b;
1679
0
        }
1680
0
    }
1681
0
    const bool b = (firstOptionalArg < 0) ? args == callargs : (callargs >= firstOptionalArg-1 && callargs <= args);
1682
0
    if (b && func)
1683
0
        *func = &it->second;
1684
0
    return b;
1685
0
}
1686
1687
const std::map<std::string, Library::WarnInfo>& Library::functionwarn() const
1688
0
{
1689
0
    return mData->mFunctionwarn;
1690
0
}
1691
1692
const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
1693
4.77k
{
1694
4.77k
    if (isNotLibraryFunction(ftok))
1695
4.77k
        return nullptr;
1696
0
    const auto i = utils::as_const(mData->mFunctionwarn).find(getFunctionName(ftok));
1697
0
    if (i ==  mData->mFunctionwarn.cend())
1698
0
        return nullptr;
1699
0
    return &i->second;
1700
0
}
1701
1702
bool Library::isCompliantValidationExpression(const char* p)
1703
0
{
1704
0
    if (!p || !*p)
1705
0
        return false;
1706
1707
0
    bool error = false;
1708
0
    bool range = false;
1709
0
    bool has_dot = false;
1710
0
    bool has_E = false;
1711
1712
0
    error = *p == '.';
1713
0
    for (; *p; p++) {
1714
0
        if (std::isdigit(*p)) {
1715
0
            error |= (*(p + 1) == '-');
1716
0
        }
1717
0
        else if (*p == ':') {
1718
            // cppcheck-suppress bitwiseOnBoolean - TODO: fix this
1719
0
            error |= range | (*(p + 1) == '.');
1720
0
            range = true;
1721
0
            has_dot = false;
1722
0
            has_E = false;
1723
0
        }
1724
0
        else if ((*p == '-') || (*p == '+')) {
1725
0
            error |= (!std::isdigit(*(p + 1)));
1726
0
        }
1727
0
        else if (*p == ',') {
1728
0
            range = false;
1729
0
            error |= *(p + 1) == '.';
1730
0
            has_dot = false;
1731
0
            has_E = false;
1732
0
        } else if (*p == '.') {
1733
            // cppcheck-suppress bitwiseOnBoolean - TODO: fix this
1734
0
            error |= has_dot | (!std::isdigit(*(p + 1)));
1735
0
            has_dot = true;
1736
0
        } else if (*p == 'E' || *p == 'e') {
1737
0
            error |= has_E;
1738
0
            has_E = true;
1739
0
        } else if (*p == '!') {
1740
0
            error |= !((*(p+1) == '-') || (*(p+1) == '+') || (std::isdigit(*(p + 1))));
1741
0
        } else
1742
0
            return false;
1743
0
    }
1744
0
    return !error;
1745
0
}
1746
1747
bool Library::formatstr_function(const Token* ftok) const
1748
1.72k
{
1749
1.72k
    if (isNotLibraryFunction(ftok))
1750
1.72k
        return false;
1751
1752
0
    const auto it = utils::as_const(mData->mFunctions).find(getFunctionName(ftok));
1753
0
    if (it != mData->mFunctions.cend())
1754
0
        return it->second.formatstr;
1755
0
    return false;
1756
0
}
1757
1758
int Library::formatstr_argno(const Token* ftok) const
1759
0
{
1760
0
    const std::map<int, Library::ArgumentChecks>& argumentChecksFunc = mData->mFunctions.at(getFunctionName(ftok)).argumentChecks;
1761
0
    auto it = std::find_if(argumentChecksFunc.cbegin(), argumentChecksFunc.cend(), [](const std::pair<const int, Library::ArgumentChecks>& a) {
1762
0
        return a.second.formatstr;
1763
0
    });
1764
0
    return it == argumentChecksFunc.cend() ? -1 : it->first - 1;
1765
0
}
1766
1767
bool Library::formatstr_scan(const Token* ftok) const
1768
0
{
1769
0
    return mData->mFunctions.at(getFunctionName(ftok)).formatstr_scan;
1770
0
}
1771
1772
bool Library::formatstr_secure(const Token* ftok) const
1773
0
{
1774
0
    return mData->mFunctions.at(getFunctionName(ftok)).formatstr_secure;
1775
0
}
1776
1777
const Library::NonOverlappingData* Library::getNonOverlappingData(const Token *ftok) const
1778
722
{
1779
722
    if (isNotLibraryFunction(ftok))
1780
722
        return nullptr;
1781
0
    const auto it = utils::as_const(mData->mNonOverlappingData).find(getFunctionName(ftok));
1782
0
    return (it != mData->mNonOverlappingData.cend()) ? &it->second : nullptr;
1783
722
}
1784
1785
Library::UseRetValType Library::getUseRetValType(const Token *ftok) const
1786
0
{
1787
0
    if (isNotLibraryFunction(ftok)) {
1788
0
        if (match10(ftok->astParent())) {
1789
0
            const Token* contTok = ftok->astParent()->astOperand1();
1790
0
            using Yield = Library::Container::Yield;
1791
0
            const Yield yield = astContainerYield(contTok);
1792
0
            if (yield == Yield::START_ITERATOR || yield == Yield::END_ITERATOR || yield == Yield::AT_INDEX ||
1793
0
                yield == Yield::SIZE || yield == Yield::EMPTY || yield == Yield::BUFFER || yield == Yield::BUFFER_NT ||
1794
0
                ((yield == Yield::ITEM || yield == Yield::ITERATOR) && astContainerAction(contTok) == Library::Container::Action::NO_ACTION))
1795
0
                return Library::UseRetValType::DEFAULT;
1796
0
        }
1797
0
        return Library::UseRetValType::NONE;
1798
0
    }
1799
0
    const auto it = utils::as_const(mData->mFunctions).find(getFunctionName(ftok));
1800
0
    if (it != mData->mFunctions.cend())
1801
0
        return it->second.useretval;
1802
0
    return Library::UseRetValType::NONE;
1803
0
}
1804
1805
const std::string& Library::returnValue(const Token *ftok) const
1806
0
{
1807
0
    if (isNotLibraryFunction(ftok))
1808
0
        return emptyString;
1809
0
    const auto it = utils::as_const(mData->mReturnValue).find(getFunctionName(ftok));
1810
0
    return it != mData->mReturnValue.cend() ? it->second : emptyString;
1811
0
}
1812
1813
const std::string& Library::returnValueType(const Token *ftok) const
1814
13.1k
{
1815
13.1k
    if (isNotLibraryFunction(ftok)) {
1816
13.1k
        if (match10(ftok->astParent()) && ftok->astParent()->astOperand1()) {
1817
0
            const Token* contTok = ftok->astParent()->astOperand1();
1818
0
            if (contTok->valueType() && contTok->valueType()->container)
1819
0
                return contTok->valueType()->container->getReturnType(ftok->str());
1820
0
        }
1821
13.1k
        return emptyString;
1822
13.1k
    }
1823
0
    const auto it = utils::as_const(mData->mReturnValueType).find(getFunctionName(ftok));
1824
0
    return it != mData->mReturnValueType.cend() ? it->second : emptyString;
1825
13.1k
}
1826
1827
int Library::returnValueContainer(const Token *ftok) const
1828
187
{
1829
187
    if (isNotLibraryFunction(ftok))
1830
187
        return -1;
1831
0
    const auto it = utils::as_const(mData->mReturnValueContainer).find(getFunctionName(ftok));
1832
0
    return it != mData->mReturnValueContainer.cend() ? it->second : -1;
1833
187
}
1834
1835
std::vector<MathLib::bigint> Library::unknownReturnValues(const Token *ftok) const
1836
0
{
1837
0
    if (isNotLibraryFunction(ftok))
1838
0
        return std::vector<MathLib::bigint>();
1839
0
    const auto it = utils::as_const(mData->mUnknownReturnValues).find(getFunctionName(ftok));
1840
0
    return (it == mData->mUnknownReturnValues.cend()) ? std::vector<MathLib::bigint>() : it->second;
1841
0
}
1842
1843
const Library::Function *Library::getFunction(const Token *ftok) const
1844
6.16k
{
1845
6.16k
    if (isNotLibraryFunction(ftok))
1846
6.16k
        return nullptr;
1847
0
    const auto it1 = utils::as_const(mData->mFunctions).find(getFunctionName(ftok));
1848
0
    if (it1 == mData->mFunctions.cend())
1849
0
        return nullptr;
1850
0
    return &it1->second;
1851
0
}
1852
1853
1854
bool Library::hasminsize(const Token *ftok) const
1855
722
{
1856
722
    if (isNotLibraryFunction(ftok))
1857
722
        return false;
1858
0
    const auto it = utils::as_const(mData->mFunctions).find(getFunctionName(ftok));
1859
0
    if (it == mData->mFunctions.cend())
1860
0
        return false;
1861
0
    return std::any_of(it->second.argumentChecks.cbegin(), it->second.argumentChecks.cend(), [](const std::pair<const int, Library::ArgumentChecks>& a) {
1862
0
        return !a.second.minsizes.empty();
1863
0
    });
1864
0
}
1865
1866
Library::ArgumentChecks::Direction Library::getArgDirection(const Token* ftok, int argnr, int indirect) const
1867
0
{
1868
0
    const ArgumentChecks* arg = getarg(ftok, argnr);
1869
0
    if (arg) {
1870
0
        if (indirect < 0 || indirect >= arg->direction.size())
1871
0
            return ArgumentChecks::Direction::DIR_UNKNOWN; // TODO: don't generate bad indirect values
1872
0
        return arg->direction[indirect];
1873
0
    }
1874
0
    if (formatstr_function(ftok)) {
1875
0
        const int fs_argno = formatstr_argno(ftok);
1876
0
        if (fs_argno >= 0 && argnr >= fs_argno) {
1877
0
            if (formatstr_scan(ftok))
1878
0
                return ArgumentChecks::Direction::DIR_OUT;
1879
0
            return ArgumentChecks::Direction::DIR_IN;
1880
0
        }
1881
0
    }
1882
0
    return ArgumentChecks::Direction::DIR_UNKNOWN;
1883
0
}
1884
1885
bool Library::ignorefunction(const std::string& functionName) const
1886
0
{
1887
0
    const auto it = utils::as_const(mData->mFunctions).find(functionName);
1888
0
    if (it != mData->mFunctions.cend())
1889
0
        return it->second.ignore;
1890
0
    return false;
1891
0
}
1892
const std::unordered_map<std::string, Library::Function>& Library::functions() const
1893
5.60k
{
1894
5.60k
    return mData->mFunctions;
1895
5.60k
}
1896
bool Library::isUse(const std::string& functionName) const
1897
0
{
1898
0
    const auto it = utils::as_const(mData->mFunctions).find(functionName);
1899
0
    if (it != mData->mFunctions.cend())
1900
0
        return it->second.use;
1901
0
    return false;
1902
0
}
1903
bool Library::isLeakIgnore(const std::string& functionName) const
1904
0
{
1905
0
    const auto it = utils::as_const(mData->mFunctions).find(functionName);
1906
0
    if (it != mData->mFunctions.cend())
1907
0
        return it->second.leakignore;
1908
0
    return false;
1909
0
}
1910
bool Library::isFunctionConst(const std::string& functionName, bool pure) const
1911
722
{
1912
722
    const auto it = utils::as_const(mData->mFunctions).find(functionName);
1913
722
    if (it != mData->mFunctions.cend())
1914
0
        return pure ? it->second.ispure : it->second.isconst;
1915
722
    return false;
1916
722
}
1917
bool Library::isFunctionConst(const Token *ftok) const
1918
16
{
1919
16
    if (ftok->function() && ftok->function()->isConst())
1920
0
        return true;
1921
16
    if (isNotLibraryFunction(ftok)) {
1922
16
        if (match10(ftok->astParent())) {
1923
0
            using Yield = Library::Container::Yield;
1924
0
            const Yield yield = astContainerYield(ftok->astParent()->astOperand1());
1925
0
            if (yield == Yield::EMPTY || yield == Yield::SIZE || yield == Yield::BUFFER_NT)
1926
0
                return true;
1927
0
        }
1928
16
        return false;
1929
16
    }
1930
0
    const auto it = utils::as_const(mData->mFunctions).find(getFunctionName(ftok));
1931
0
    return (it != mData->mFunctions.cend() && it->second.isconst);
1932
16
}
1933
1934
bool Library::isnoreturn(const Token *ftok) const
1935
19.9k
{
1936
19.9k
    if (ftok->function() && ftok->function()->isAttributeNoreturn())
1937
0
        return true;
1938
19.9k
    if (ftok->variable() && ftok->variable()->nameToken()->isAttributeNoreturn())
1939
0
        return true;
1940
19.9k
    if (isNotLibraryFunction(ftok)) {
1941
19.9k
        if (match10(ftok->astParent())) {
1942
0
            const Token* contTok = ftok->astParent()->astOperand1();
1943
0
            if (astContainerAction(contTok) != Library::Container::Action::NO_ACTION ||
1944
0
                astContainerYield(contTok) != Library::Container::Yield::NO_YIELD)
1945
0
                return false;
1946
0
        }
1947
19.9k
        return false;
1948
19.9k
    }
1949
0
    const auto it = utils::as_const(mData->mNoReturn).find(getFunctionName(ftok));
1950
0
    if (it == mData->mNoReturn.end())
1951
0
        return false;
1952
0
    if (it->second == LibraryData::FalseTrueMaybe::Maybe)
1953
0
        return true;
1954
0
    return it->second == LibraryData::FalseTrueMaybe::True;
1955
0
}
1956
1957
bool Library::isnotnoreturn(const Token *ftok) const
1958
0
{
1959
0
    if (ftok->function() && ftok->function()->isAttributeNoreturn())
1960
0
        return false;
1961
0
    if (isNotLibraryFunction(ftok))
1962
0
        return hasAnyTypeCheck(getFunctionName(ftok));
1963
0
    const auto it = utils::as_const(mData->mNoReturn).find(getFunctionName(ftok));
1964
0
    if (it == mData->mNoReturn.end())
1965
0
        return false;
1966
0
    if (it->second == LibraryData::FalseTrueMaybe::Maybe)
1967
0
        return false;
1968
0
    return it->second == LibraryData::FalseTrueMaybe::False;
1969
0
}
1970
1971
bool Library::markupFile(const std::string &path) const
1972
2.54k
{
1973
2.54k
    return mData->mMarkupExtensions.find(Path::getFilenameExtensionInLowerCase(path)) != mData->mMarkupExtensions.end();
1974
2.54k
}
1975
1976
bool Library::processMarkupAfterCode(const std::string &path) const
1977
0
{
1978
0
    const auto it = utils::as_const(mData->mProcessAfterCode).find(Path::getFilenameExtensionInLowerCase(path));
1979
0
    return (it == mData->mProcessAfterCode.cend() || it->second);
1980
0
}
1981
1982
bool Library::reportErrors(const std::string &path) const
1983
961
{
1984
961
    const auto it = utils::as_const(mData->mReportErrors).find(Path::getFilenameExtensionInLowerCase(path));
1985
961
    return (it == mData->mReportErrors.cend() || it->second);
1986
961
}
1987
1988
bool Library::isexecutableblock(const std::string &file, const std::string &token) const
1989
54.8k
{
1990
54.8k
    const auto it = utils::as_const(mData->mExecutableBlocks).find(Path::getFilenameExtensionInLowerCase(file));
1991
54.8k
    return (it != mData->mExecutableBlocks.cend() && it->second.isBlock(token));
1992
54.8k
}
1993
1994
int Library::blockstartoffset(const std::string &file) const
1995
0
{
1996
0
    int offset = -1;
1997
0
    const auto map_it
1998
0
        = utils::as_const(mData->mExecutableBlocks).find(Path::getFilenameExtensionInLowerCase(file));
1999
2000
0
    if (map_it != mData->mExecutableBlocks.end()) {
2001
0
        offset = map_it->second.offset();
2002
0
    }
2003
0
    return offset;
2004
0
}
2005
2006
const std::string& Library::blockstart(const std::string &file) const
2007
0
{
2008
0
    const auto map_it
2009
0
        = utils::as_const(mData->mExecutableBlocks).find(Path::getFilenameExtensionInLowerCase(file));
2010
2011
0
    if (map_it != mData->mExecutableBlocks.end()) {
2012
0
        return map_it->second.start();
2013
0
    }
2014
0
    return emptyString;
2015
0
}
2016
2017
const std::string& Library::blockend(const std::string &file) const
2018
0
{
2019
0
    const auto map_it
2020
0
        = utils::as_const(mData->mExecutableBlocks).find(Path::getFilenameExtensionInLowerCase(file));
2021
2022
0
    if (map_it != mData->mExecutableBlocks.end()) {
2023
0
        return map_it->second.end();
2024
0
    }
2025
0
    return emptyString;
2026
0
}
2027
2028
bool Library::iskeyword(const std::string &file, const std::string &keyword) const
2029
0
{
2030
0
    const auto it =
2031
0
        utils::as_const(mData->mKeywords).find(Path::getFilenameExtensionInLowerCase(file));
2032
0
    return (it != mData->mKeywords.end() && it->second.count(keyword));
2033
0
}
2034
2035
bool Library::isimporter(const std::string& file, const std::string &importer) const
2036
0
{
2037
0
    const auto it =
2038
0
        utils::as_const(mData->mImporters).find(Path::getFilenameExtensionInLowerCase(file));
2039
0
    return (it != mData->mImporters.end() && it->second.count(importer) > 0);
2040
0
}
2041
2042
const Token* Library::getContainerFromYield(const Token* tok, Library::Container::Yield yield) const
2043
2.85k
{
2044
2.85k
    if (!tok)
2045
0
        return nullptr;
2046
2.85k
    if (match21(tok->tokAt(-2))) {
2047
0
        const Token* containerTok = tok->tokAt(-2)->astOperand1();
2048
0
        if (!astIsContainer(containerTok))
2049
0
            return nullptr;
2050
0
        if (containerTok->valueType()->container &&
2051
0
            containerTok->valueType()->container->getYield(tok->strAt(-1)) == yield)
2052
0
            return containerTok;
2053
0
        if (yield == Library::Container::Yield::EMPTY && match22(tok->tokAt(-1)))
2054
0
            return containerTok;
2055
0
        if (yield == Library::Container::Yield::SIZE && match23(tok->tokAt(-1)))
2056
0
            return containerTok;
2057
2.85k
    } else if (match15(tok->previous())) {
2058
2.46k
        if (const Library::Function* f = this->getFunction(tok->previous())) {
2059
0
            if (f->containerYield == yield) {
2060
0
                return tok->astOperand2();
2061
0
            }
2062
0
        }
2063
2.46k
    }
2064
2.85k
    return nullptr;
2065
2.85k
}
2066
2067
// cppcheck-suppress unusedFunction
2068
const Token* Library::getContainerFromAction(const Token* tok, Library::Container::Action action) const
2069
0
{
2070
0
    if (!tok)
2071
0
        return nullptr;
2072
0
    if (match21(tok->tokAt(-2))) {
2073
0
        const Token* containerTok = tok->tokAt(-2)->astOperand1();
2074
0
        if (!astIsContainer(containerTok))
2075
0
            return nullptr;
2076
0
        if (containerTok->valueType()->container &&
2077
0
            containerTok->valueType()->container->getAction(tok->strAt(-1)) == action)
2078
0
            return containerTok;
2079
0
        if (match22(tok->tokAt(-1)))
2080
0
            return containerTok;
2081
0
    } else if (match15(tok->previous())) {
2082
0
        if (const Library::Function* f = this->getFunction(tok->previous())) {
2083
0
            if (f->containerAction == action) {
2084
0
                return tok->astOperand2();
2085
0
            }
2086
0
        }
2087
0
    }
2088
0
    return nullptr;
2089
0
}
2090
2091
const std::unordered_map<std::string, Library::SmartPointer>& Library::smartPointers() const
2092
0
{
2093
0
    return mData->mSmartPointers;
2094
0
}
2095
2096
bool Library::isSmartPointer(const Token* tok) const
2097
6.42k
{
2098
6.42k
    return detectSmartPointer(tok);
2099
6.42k
}
2100
2101
const Library::SmartPointer* Library::detectSmartPointer(const Token* tok, bool withoutStd) const
2102
72.5k
{
2103
72.5k
    std::string typestr = withoutStd ? "std::" : "";
2104
208k
    while (match8(tok)) {
2105
136k
        typestr += tok->str();
2106
136k
        tok = tok->next();
2107
136k
    }
2108
72.5k
    auto it = mData->mSmartPointers.find(typestr);
2109
72.5k
    if (it == mData->mSmartPointers.end())
2110
72.5k
        return nullptr;
2111
0
    return &it->second;
2112
72.5k
}
2113
2114
const Library::Container * getLibraryContainer(const Token * tok)
2115
246k
{
2116
246k
    if (!tok)
2117
0
        return nullptr;
2118
    // TODO: Support dereferencing iterators
2119
    // TODO: Support dereferencing with ->
2120
246k
    if (tok->isUnaryOp("*") && astIsPointer(tok->astOperand1())) {
2121
0
        for (const ValueFlow::Value& v:tok->astOperand1()->values()) {
2122
0
            if (!v.isLocalLifetimeValue())
2123
0
                continue;
2124
0
            if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
2125
0
                continue;
2126
0
            return getLibraryContainer(v.tokvalue);
2127
0
        }
2128
0
    }
2129
246k
    if (!tok->valueType())
2130
156k
        return nullptr;
2131
89.0k
    return tok->valueType()->container;
2132
246k
}
2133
2134
Library::TypeCheck Library::getTypeCheck(std::string check,  std::string typeName) const
2135
0
{
2136
0
    auto it = mData->mTypeChecks.find(std::pair<std::string, std::string>(std::move(check), std::move(typeName)));
2137
0
    return it == mData->mTypeChecks.end() ? TypeCheck::def : it->second;
2138
0
}
2139
2140
bool Library::hasAnyTypeCheck(const std::string& typeName) const
2141
0
{
2142
0
    return std::any_of(mData->mTypeChecks.begin(), mData->mTypeChecks.end(), [&](const std::pair<std::pair<std::string, std::string>, Library::TypeCheck>& tc) {
2143
0
        return tc.first.second == typeName;
2144
0
    });
2145
0
}
2146
2147
const Library::AllocFunc* Library::getAllocFuncInfo(const char name[]) const
2148
0
{
2149
0
    return getAllocDealloc(mData->mAlloc, name);
2150
0
}
2151
2152
const Library::AllocFunc* Library::getDeallocFuncInfo(const char name[]) const
2153
0
{
2154
0
    return getAllocDealloc(mData->mDealloc, name);
2155
0
}
2156
2157
// cppcheck-suppress unusedFunction
2158
int Library::allocId(const char name[]) const
2159
0
{
2160
0
    const AllocFunc* af = getAllocDealloc(mData->mAlloc, name);
2161
0
    return af ? af->groupId : 0;
2162
0
}
2163
2164
int Library::deallocId(const char name[]) const
2165
0
{
2166
0
    const AllocFunc* af = getAllocDealloc(mData->mDealloc, name);
2167
0
    return af ? af->groupId : 0;
2168
0
}
2169
2170
const std::set<std::string> &Library::markupExtensions() const
2171
0
{
2172
0
    return mData->mMarkupExtensions;
2173
0
}
2174
2175
bool Library::isexporter(const std::string &prefix) const
2176
54.8k
{
2177
54.8k
    return mData->mExporters.find(prefix) != mData->mExporters.end();
2178
54.8k
}
2179
2180
bool Library::isexportedprefix(const std::string &prefix, const std::string &token) const
2181
0
{
2182
0
    const auto it = utils::as_const(mData->mExporters).find(prefix);
2183
0
    return (it != mData->mExporters.end() && it->second.isPrefix(token));
2184
0
}
2185
2186
bool Library::isexportedsuffix(const std::string &prefix, const std::string &token) const
2187
0
{
2188
0
    const auto it = utils::as_const(mData->mExporters).find(prefix);
2189
0
    return (it != mData->mExporters.end() && it->second.isSuffix(token));
2190
0
}
2191
2192
bool Library::isreflection(const std::string &token) const
2193
54.8k
{
2194
54.8k
    return mData->mReflection.find(token) != mData->mReflection.end();
2195
54.8k
}
2196
2197
int Library::reflectionArgument(const std::string &token) const
2198
0
{
2199
0
    const auto it = utils::as_const(mData->mReflection).find(token);
2200
0
    if (it != mData->mReflection.end())
2201
0
        return it->second;
2202
0
    return -1;
2203
0
}
2204
2205
bool Library::isentrypoint(const std::string &func) const
2206
1.10k
{
2207
1.10k
    return func == MatchCompiler::makeConstString("main") || mData->mEntrypoints.find(func) != mData->mEntrypoints.end();
2208
1.10k
}
2209
2210
const std::set<std::string>& Library::defines() const
2211
1.73k
{
2212
1.73k
    return mData->mDefines;
2213
1.73k
}
2214
2215
const Library::PodType *Library::podtype(const std::string &name) const
2216
21.5k
{
2217
21.5k
    const auto it = utils::as_const(mData->mPodTypes).find(name);
2218
21.5k
    return (it != mData->mPodTypes.end()) ? &(it->second) : nullptr;
2219
21.5k
}
2220
2221
const Library::PlatformType *Library::platform_type(const std::string &name, const std::string & platform) const
2222
27.5k
{
2223
27.5k
    const auto it = utils::as_const(mData->mPlatforms).find(platform);
2224
27.5k
    if (it != mData->mPlatforms.end()) {
2225
0
        const PlatformType * const type = it->second.platform_type(name);
2226
0
        if (type)
2227
0
            return type;
2228
0
    }
2229
2230
27.5k
    const auto it2 = utils::as_const(mData->mPlatformTypes).find(name);
2231
27.5k
    return (it2 != mData->mPlatformTypes.end()) ? &(it2->second) : nullptr;
2232
27.5k
}