/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 | } |