Coverage Report

Created: 2025-01-24 06:31

/src/cppcheck/oss-fuzz/build/clangimport.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: &|*|%name%
7
0
static inline bool match1(const Token* tok) {
8
0
    if (!tok || !(((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || tok->isName()))
9
0
        return false;
10
0
    return true;
11
0
}
12
// pattern: if|for|while (
13
0
static inline bool match2(const Token* tok) {
14
0
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while"))))
15
0
        return false;
16
0
    tok = tok->next();
17
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
18
0
        return false;
19
0
    return true;
20
0
}
21
// pattern: [;{}]
22
0
static inline bool match3(const Token* tok) {
23
0
    if (!tok || tok->str().size() != 1U || !strchr(";{}", tok->str()[0]))
24
0
        return false;
25
0
    return true;
26
0
}
27
// pattern: , }
28
0
static inline bool match4(const Token* tok) {
29
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")))
30
0
        return false;
31
0
    tok = tok->next();
32
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
33
0
        return false;
34
0
    return true;
35
0
}
36
// pattern: sizeof (
37
0
static inline bool match5(const Token* tok) {
38
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("sizeof")))
39
0
        return false;
40
0
    tok = tok->next();
41
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
42
0
        return false;
43
0
    return true;
44
0
}
45
// pattern: (|)|[|]|{|}
46
0
static inline bool match6(const Token* tok) {
47
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))))
48
0
        return false;
49
0
    return true;
50
0
}
51
/*
52
 * Cppcheck - A tool for static C/C++ code analysis
53
 * Copyright (C) 2007-2024 Cppcheck team.
54
 *
55
 * This program is free software: you can redistribute it and/or modify
56
 * it under the terms of the GNU General Public License as published by
57
 * the Free Software Foundation, either version 3 of the License, or
58
 * (at your option) any later version.
59
 *
60
 * This program is distributed in the hope that it will be useful,
61
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
62
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
63
 * GNU General Public License for more details.
64
 *
65
 * You should have received a copy of the GNU General Public License
66
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
67
 */
68
69
#include "clangimport.h"
70
71
#include "errortypes.h"
72
#include "mathlib.h"
73
#include "settings.h"
74
#include "standards.h"
75
#include "symboldatabase.h"
76
#include "token.h"
77
#include "tokenize.h"
78
#include "tokenlist.h"
79
#include "utils.h"
80
#include "vfvalue.h"
81
82
#include <algorithm>
83
#include <cctype>
84
#include <cstring>
85
#include <iostream>
86
#include <iterator>
87
#include <list>
88
#include <map>
89
#include <memory>
90
#include <set>
91
#include <sstream>
92
#include <stack>
93
#include <string>
94
#include <utility>
95
#include <vector>
96
#include <numeric>
97
98
static const std::string AccessSpecDecl = "AccessSpecDecl";
99
static const std::string ArraySubscriptExpr = "ArraySubscriptExpr";
100
static const std::string BinaryOperator = "BinaryOperator";
101
static const std::string BreakStmt = "BreakStmt";
102
static const std::string CallExpr = "CallExpr";
103
static const std::string CaseStmt = "CaseStmt";
104
static const std::string CharacterLiteral = "CharacterLiteral";
105
static const std::string ClassTemplateDecl = "ClassTemplateDecl";
106
static const std::string ClassTemplateSpecializationDecl = "ClassTemplateSpecializationDecl";
107
static const std::string ConditionalOperator = "ConditionalOperator";
108
static const std::string ConstantExpr = "ConstantExpr";
109
static const std::string CompoundAssignOperator = "CompoundAssignOperator";
110
static const std::string CompoundStmt = "CompoundStmt";
111
static const std::string ContinueStmt = "ContinueStmt";
112
static const std::string CStyleCastExpr = "CStyleCastExpr";
113
static const std::string CXXBindTemporaryExpr = "CXXBindTemporaryExpr";
114
static const std::string CXXBoolLiteralExpr = "CXXBoolLiteralExpr";
115
static const std::string CXXConstructorDecl = "CXXConstructorDecl";
116
static const std::string CXXConstructExpr = "CXXConstructExpr";
117
static const std::string CXXDefaultArgExpr = "CXXDefaultArgExpr";
118
static const std::string CXXDeleteExpr = "CXXDeleteExpr";
119
static const std::string CXXDestructorDecl = "CXXDestructorDecl";
120
static const std::string CXXForRangeStmt = "CXXForRangeStmt";
121
static const std::string CXXFunctionalCastExpr = "CXXFunctionalCastExpr";
122
static const std::string CXXMemberCallExpr = "CXXMemberCallExpr";
123
static const std::string CXXMethodDecl = "CXXMethodDecl";
124
static const std::string CXXNewExpr = "CXXNewExpr";
125
static const std::string CXXNullPtrLiteralExpr = "CXXNullPtrLiteralExpr";
126
static const std::string CXXOperatorCallExpr = "CXXOperatorCallExpr";
127
static const std::string CXXRecordDecl = "CXXRecordDecl";
128
static const std::string CXXStaticCastExpr = "CXXStaticCastExpr";
129
static const std::string CXXStdInitializerListExpr = "CXXStdInitializerListExpr";
130
static const std::string CXXTemporaryObjectExpr = "CXXTemporaryObjectExpr";
131
static const std::string CXXThisExpr = "CXXThisExpr";
132
static const std::string CXXThrowExpr = "CXXThrowExpr";
133
static const std::string DeclRefExpr = "DeclRefExpr";
134
static const std::string DeclStmt = "DeclStmt";
135
static const std::string DefaultStmt = "DefaultStmt";
136
static const std::string DoStmt = "DoStmt";
137
static const std::string EnumConstantDecl = "EnumConstantDecl";
138
static const std::string EnumDecl = "EnumDecl";
139
static const std::string ExprWithCleanups = "ExprWithCleanups";
140
static const std::string FieldDecl = "FieldDecl";
141
static const std::string FloatingLiteral = "FloatingLiteral";
142
static const std::string ForStmt = "ForStmt";
143
static const std::string FunctionDecl = "FunctionDecl";
144
static const std::string FunctionTemplateDecl = "FunctionTemplateDecl";
145
static const std::string GotoStmt = "GotoStmt";
146
static const std::string IfStmt = "IfStmt";
147
static const std::string ImplicitCastExpr = "ImplicitCastExpr";
148
static const std::string InitListExpr = "InitListExpr";
149
static const std::string IntegerLiteral = "IntegerLiteral";
150
static const std::string LabelStmt = "LabelStmt";
151
static const std::string LinkageSpecDecl = "LinkageSpecDecl";
152
static const std::string MaterializeTemporaryExpr = "MaterializeTemporaryExpr";
153
static const std::string MemberExpr = "MemberExpr";
154
static const std::string NamespaceDecl = "NamespaceDecl";
155
static const std::string NullStmt = "NullStmt";
156
static const std::string ParenExpr = "ParenExpr";
157
static const std::string ParmVarDecl = "ParmVarDecl";
158
static const std::string RecordDecl = "RecordDecl";
159
static const std::string ReturnStmt = "ReturnStmt";
160
static const std::string StringLiteral = "StringLiteral";
161
static const std::string SwitchStmt = "SwitchStmt";
162
static const std::string TemplateArgument = "TemplateArgument";
163
static const std::string TypedefDecl = "TypedefDecl";
164
static const std::string UnaryOperator = "UnaryOperator";
165
static const std::string UnaryExprOrTypeTraitExpr = "UnaryExprOrTypeTraitExpr";
166
static const std::string VarDecl = "VarDecl";
167
static const std::string WhileStmt = "WhileStmt";
168
169
static std::string unquote(const std::string &s)
170
0
{
171
0
    return (s[0] == '\'') ? s.substr(1, s.size() - 2) : s;
172
0
}
173
174
175
static std::vector<std::string> splitString(const std::string &line)
176
0
{
177
0
    std::vector<std::string> ret;
178
0
    std::string::size_type pos1 = line.find_first_not_of(' ');
179
0
    while (pos1 < line.size()) {
180
0
        std::string::size_type pos2;
181
0
        if (std::strchr("*()", line[pos1])) {
182
0
            ret.push_back(line.substr(pos1,1));
183
0
            pos1 = line.find_first_not_of(' ', pos1 + 1);
184
0
            continue;
185
0
        }
186
0
        if (line[pos1] == '<')
187
0
            pos2 = line.find('>', pos1);
188
0
        else if (line[pos1] == '\"')
189
0
            pos2 = line.find('\"', pos1+1);
190
0
        else if (line[pos1] == '\'') {
191
0
            pos2 = line.find('\'', pos1+1);
192
0
            if (pos2 < (int)line.size() - 3 && line.compare(pos2, 3, "\':\'", 0, 3) == 0)
193
0
                pos2 = line.find('\'', pos2 + 3);
194
0
        } else {
195
0
            pos2 = pos1;
196
0
            while (pos2 < line.size() && (line[pos2] == '_' || line[pos2] == ':' || std::isalnum((unsigned char)line[pos2])))
197
0
                ++pos2;
198
0
            if (pos2 > pos1 && pos2 < line.size() && line[pos2] == '<' && std::isalpha(line[pos1])) {
199
0
                int tlevel = 1;
200
0
                while (++pos2 < line.size() && tlevel > 0) {
201
0
                    if (line[pos2] == '<')
202
0
                        ++tlevel;
203
0
                    else if (line[pos2] == '>')
204
0
                        --tlevel;
205
0
                }
206
0
                if (tlevel == 0 && pos2 < line.size() && line[pos2] == ' ') {
207
0
                    ret.push_back(line.substr(pos1, pos2-pos1));
208
0
                    pos1 = pos2 + 1;
209
0
                    continue;
210
0
                }
211
0
            }
212
213
0
            pos2 = line.find(' ', pos1) - 1;
214
0
            if ((std::isalpha(line[pos1]) || line[pos1] == '_') &&
215
0
                line.find("::", pos1) < pos2 &&
216
0
                line.find("::", pos1) < line.find('<', pos1)) {
217
0
                pos2 = line.find("::", pos1);
218
0
                ret.push_back(line.substr(pos1, pos2-pos1));
219
0
                ret.emplace_back("::");
220
0
                pos1 = pos2 + 2;
221
0
                continue;
222
0
            }
223
0
            if ((std::isalpha(line[pos1]) || line[pos1] == '_') &&
224
0
                line.find('<', pos1) < pos2 &&
225
0
                line.find("<<",pos1) != line.find('<',pos1) &&
226
0
                line.find('>', pos1) != std::string::npos &&
227
0
                line.find('>', pos1) > pos2) {
228
0
                int level = 0;
229
0
                for (pos2 = pos1; pos2 < line.size(); ++pos2) {
230
0
                    if (line[pos2] == '<')
231
0
                        ++level;
232
0
                    else if (line[pos2] == '>') {
233
0
                        if (level <= 1)
234
0
                            break;
235
0
                        --level;
236
0
                    }
237
0
                }
238
0
                if (level > 1 && pos2 + 1 >= line.size())
239
0
                    return std::vector<std::string> {};
240
0
                pos2 = line.find(' ', pos2);
241
0
                if (pos2 != std::string::npos)
242
0
                    --pos2;
243
0
            }
244
0
        }
245
0
        if (pos2 == std::string::npos) {
246
0
            ret.push_back(line.substr(pos1));
247
0
            break;
248
0
        }
249
0
        ret.push_back(line.substr(pos1, pos2+1-pos1));
250
0
        pos1 = line.find_first_not_of(' ', pos2 + 1);
251
0
    }
252
0
    return ret;
253
0
}
254
255
256
namespace clangimport {
257
    struct Data {
258
        struct Decl {
259
0
            explicit Decl(Scope *scope) : scope(scope) {}
260
0
            Decl(Token *def, Variable *var) : def(def), var(var) {}
261
0
            Decl(Token *def, Function *function) : def(def), function(function) {}
262
0
            Decl(Token *def, Enumerator *enumerator) : def(def), enumerator(enumerator) {}
263
0
            void ref(Token *tok) const {
264
0
                if (enumerator)
265
0
                    tok->enumerator(enumerator);
266
0
                if (function)
267
0
                    tok->function(function);
268
0
                if (var) {
269
0
                    tok->variable(var);
270
0
                    tok->varId(var->declarationId());
271
0
                }
272
0
            }
273
            Token* def{};
274
            Enumerator* enumerator{};
275
            Function* function{};
276
            Scope* scope{};
277
            Variable* var{};
278
        };
279
280
        const Settings *mSettings = nullptr;
281
        SymbolDatabase *mSymbolDatabase = nullptr;
282
283
        int enumValue = 0;
284
285
0
        void enumDecl(const std::string &addr, Token *nameToken, Enumerator *enumerator) {
286
0
            Decl decl(nameToken, enumerator);
287
0
            mDeclMap.emplace(addr, decl);
288
0
            nameToken->enumerator(enumerator);
289
0
            notFound(addr);
290
0
        }
291
292
0
        void funcDecl(const std::string &addr, Token *nameToken, Function *function) {
293
0
            Decl decl(nameToken, function);
294
0
            mDeclMap.emplace(addr, decl);
295
0
            nameToken->function(function);
296
0
            notFound(addr);
297
0
        }
298
299
0
        void scopeDecl(const std::string &addr, Scope *scope) {
300
0
            Decl decl(scope);
301
0
            mDeclMap.emplace(addr, decl);
302
0
        }
303
304
0
        void varDecl(const std::string &addr, Token *def, Variable *var) {
305
0
            Decl decl(def, var);
306
0
            mDeclMap.emplace(addr, decl);
307
0
            def->varId(++mVarId);
308
0
            def->variable(var);
309
0
            if (def->valueType())
310
0
                var->setValueType(*def->valueType());
311
0
            notFound(addr);
312
0
        }
313
314
0
        void replaceVarDecl(const Variable *from, Variable *to) {
315
0
            for (auto &it: mDeclMap) {
316
0
                Decl &decl = it.second;
317
0
                if (decl.var == from)
318
0
                    decl.var = to;
319
0
            }
320
0
        }
321
322
0
        void ref(const std::string &addr, Token *tok) {
323
0
            auto it = mDeclMap.find(addr);
324
0
            if (it != mDeclMap.end())
325
0
                it->second.ref(tok);
326
0
            else
327
0
                mNotFound[addr].push_back(tok);
328
0
        }
329
330
0
        std::vector<const Variable *> getVariableList() const {
331
0
            std::vector<const Variable *> ret;
332
0
            ret.resize(mVarId + 1, nullptr);
333
0
            for (const auto& it: mDeclMap) {
334
0
                if (it.second.var)
335
0
                    ret[it.second.var->declarationId()] = it.second.var;
336
0
            }
337
0
            return ret;
338
0
        }
339
340
0
        bool hasDecl(const std::string &addr) const {
341
0
            return mDeclMap.find(addr) != mDeclMap.end();
342
0
        }
343
344
0
        const Scope *getScope(const std::string &addr) {
345
0
            auto it = mDeclMap.find(addr);
346
0
            return (it == mDeclMap.end() ? nullptr : it->second.scope);
347
0
        }
348
349
        // "}" tokens that are not end-of-scope
350
        std::set<Token *> mNotScope;
351
352
        std::map<const Scope *, AccessControl> scopeAccessControl;
353
    private:
354
0
        void notFound(const std::string &addr) {
355
0
            auto it = mNotFound.find(addr);
356
0
            if (it != mNotFound.end()) {
357
0
                for (Token *reftok: it->second)
358
0
                    ref(addr, reftok);
359
0
                mNotFound.erase(it);
360
0
            }
361
0
        }
362
363
        std::map<std::string, Decl> mDeclMap;
364
        std::map<std::string, std::vector<Token *>> mNotFound;
365
        int mVarId = 0;
366
    };
367
368
    class AstNode;
369
    using AstNodePtr = std::shared_ptr<AstNode>;
370
371
    class AstNode {
372
    public:
373
        AstNode(std::string nodeType, const std::string &ext, Data *data)
374
0
            : nodeType(std::move(nodeType)), mExtTokens(splitString(ext)), mData(data)
375
0
        {}
376
        std::string nodeType;
377
        std::vector<AstNodePtr> children;
378
379
        bool isPrologueTypedefDecl() const;
380
        void setLocations(TokenList &tokenList, int file, int line, int col);
381
382
        void dumpAst(int num = 0, int indent = 0) const;
383
0
        void createTokens1(TokenList &tokenList) {
384
            //dumpAst(); // TODO: reactivate or remove
385
0
            if (isPrologueTypedefDecl())
386
0
                return;
387
0
            if (!tokenList.back()) {
388
0
                setLocations(tokenList, 0, 1, 1);
389
0
            }
390
0
            else
391
0
                setLocations(tokenList, tokenList.back()->fileIndex(), tokenList.back()->linenr(), 1);
392
0
            createTokens(tokenList);
393
0
            if (nodeType == VarDecl || nodeType == RecordDecl || nodeType == TypedefDecl)
394
0
                addtoken(tokenList, ";");
395
0
            mData->mNotScope.clear();
396
0
        }
397
398
0
        AstNodePtr getChild(int c) {
399
0
            if (c >= children.size()) {
400
0
                std::ostringstream err;
401
0
                err << "ClangImport: AstNodePtr::getChild(" << c << ") out of bounds. children.size=" << children.size() << " " << nodeType;
402
0
                for (const std::string &s: mExtTokens)
403
0
                    err << " " << s;
404
0
                throw InternalError(nullptr, err.str());
405
0
            }
406
0
            return children[c];
407
0
        }
408
    private:
409
        Token *createTokens(TokenList &tokenList);
410
        Token *addtoken(TokenList &tokenList, const std::string &str, bool valueType=true);
411
        const ::Type *addTypeTokens(TokenList &tokenList, const std::string &str, const Scope *scope = nullptr);
412
        void addFullScopeNameTokens(TokenList &tokenList, const Scope *recordScope);
413
        Scope *createScope(TokenList &tokenList, Scope::ScopeType scopeType, AstNodePtr astNode, const Token *def);
414
        Scope *createScope(TokenList &tokenList, Scope::ScopeType scopeType, const std::vector<AstNodePtr> &children2, const Token *def);
415
        RET_NONNULL Token *createTokensCall(TokenList &tokenList);
416
        void createTokensFunctionDecl(TokenList &tokenList);
417
        void createTokensForCXXRecord(TokenList &tokenList);
418
        Token *createTokensVarDecl(TokenList &tokenList);
419
        std::string getSpelling() const;
420
        std::string getType(int index = 0) const;
421
        std::string getFullType(int index = 0) const;
422
        bool isDefinition() const;
423
        std::string getTemplateParameters() const;
424
        const Scope *getNestedInScope(TokenList &tokenList);
425
        void setValueType(Token *tok);
426
427
        int mFile  = 0;
428
        int mLine  = 1;
429
        int mCol   = 1;
430
        std::vector<std::string> mExtTokens;
431
        Data *mData;
432
    };
433
}
434
435
std::string clangimport::AstNode::getSpelling() const
436
0
{
437
0
    if (nodeType == CompoundAssignOperator) {
438
0
        std::size_t typeIndex = 1;
439
0
        while (typeIndex < mExtTokens.size() && mExtTokens[typeIndex][0] != '\'')
440
0
            typeIndex++;
441
        // name is next quoted token
442
0
        std::size_t nameIndex = typeIndex + 1;
443
0
        while (nameIndex < mExtTokens.size() && mExtTokens[nameIndex][0] != '\'')
444
0
            nameIndex++;
445
0
        return (nameIndex < mExtTokens.size()) ? unquote(mExtTokens[nameIndex]) : "";
446
0
    }
447
448
0
    if (nodeType == UnaryExprOrTypeTraitExpr) {
449
0
        std::size_t typeIndex = 1;
450
0
        while (typeIndex < mExtTokens.size() && mExtTokens[typeIndex][0] != '\'')
451
0
            typeIndex++;
452
0
        const std::size_t nameIndex = typeIndex + 1;
453
0
        return (nameIndex < mExtTokens.size()) ? unquote(mExtTokens[nameIndex]) : "";
454
0
    }
455
456
0
    int typeIndex = mExtTokens.size() - 1;
457
0
    if (nodeType == FunctionDecl || nodeType == CXXConstructorDecl || nodeType == CXXMethodDecl) {
458
0
        while (typeIndex >= 0 && mExtTokens[typeIndex][0] != '\'')
459
0
            typeIndex--;
460
0
        if (typeIndex <= 0)
461
0
            return "";
462
0
    }
463
0
    if (nodeType == DeclRefExpr) {
464
0
        while (typeIndex > 0 && std::isalpha(mExtTokens[typeIndex][0]))
465
0
            typeIndex--;
466
0
        if (typeIndex <= 0)
467
0
            return "";
468
0
    }
469
0
    const std::string &str = mExtTokens[typeIndex - 1];
470
0
    if (startsWith(str,"col:"))
471
0
        return "";
472
0
    if (startsWith(str,"<invalid"))
473
0
        return "";
474
0
    if (nodeType == RecordDecl && str == MatchCompiler::makeConstString("struct"))
475
0
        return "";
476
0
    return str;
477
0
}
478
479
std::string clangimport::AstNode::getType(int index) const
480
0
{
481
0
    std::string type = getFullType(index);
482
0
    if (type.find(" (") != std::string::npos) {
483
0
        const std::string::size_type pos = type.find(" (");
484
0
        type[pos] = '\'';
485
0
        type.erase(pos+1);
486
0
    }
487
0
    if (type.find(" *(") != std::string::npos) {
488
0
        const std::string::size_type pos = type.find(" *(") + 2;
489
0
        type[pos] = '\'';
490
0
        type.erase(pos+1);
491
0
    }
492
0
    if (type.find(" &(") != std::string::npos) {
493
0
        const std::string::size_type pos = type.find(" &(") + 2;
494
0
        type[pos] = '\'';
495
0
        type.erase(pos+1);
496
0
    }
497
0
    return unquote(type);
498
0
}
499
500
std::string clangimport::AstNode::getFullType(int index) const
501
0
{
502
0
    std::size_t typeIndex = 1;
503
0
    while (typeIndex < mExtTokens.size() && mExtTokens[typeIndex][0] != '\'')
504
0
        typeIndex++;
505
0
    if (typeIndex >= mExtTokens.size())
506
0
        return "";
507
0
    std::string type = mExtTokens[typeIndex];
508
0
    if (type.find("\':\'") != std::string::npos) {
509
0
        if (index == 0)
510
0
            type.erase(type.find("\':\'") + 1);
511
0
        else
512
0
            type.erase(0, type.find("\':\'") + 2);
513
0
    }
514
0
    return type;
515
0
}
516
517
bool clangimport::AstNode::isDefinition() const
518
0
{
519
0
    return contains(mExtTokens, "definition");
520
0
}
521
522
std::string clangimport::AstNode::getTemplateParameters() const
523
0
{
524
0
    if (children.empty() || children[0]->nodeType != TemplateArgument)
525
0
        return "";
526
0
    std::string templateParameters;
527
0
    for (const AstNodePtr& child: children) {
528
0
        if (child->nodeType == TemplateArgument) {
529
0
            if (templateParameters.empty())
530
0
                templateParameters = "<";
531
0
            else
532
0
                templateParameters += ",";
533
0
            templateParameters += unquote(child->mExtTokens.back());
534
0
        }
535
0
    }
536
0
    return templateParameters + ">";
537
0
}
538
539
// cppcheck-suppress unusedFunction // only used in comment
540
void clangimport::AstNode::dumpAst(int num, int indent) const
541
0
{
542
0
    (void)num;
543
0
    std::cout << std::string(indent, ' ') << nodeType;
544
0
    for (const auto& tok: mExtTokens)
545
0
        std::cout << " " << tok;
546
0
    std::cout << std::endl;
547
0
    for (int c = 0; c < children.size(); ++c) {
548
0
        if (children[c])
549
0
            children[c]->dumpAst(c, indent + 2);
550
0
        else
551
0
            std::cout << std::string(indent + 2, ' ') << "<<<<NULL>>>>>" << std::endl;
552
0
    }
553
0
}
554
555
bool clangimport::AstNode::isPrologueTypedefDecl() const
556
0
{
557
    // these TypedefDecl are included in *any* AST dump and we should ignore them as they should not be of interest to us
558
    // see https://github.com/llvm/llvm-project/issues/120228#issuecomment-2549212109 for an explanation
559
0
    if (nodeType != TypedefDecl)
560
0
        return false;
561
562
    // TODO: use different values to indicate "<invalid sloc>"?
563
0
    if (mFile != 0 || mLine != 1 || mCol != 1)
564
0
        return false;
565
566
    // TODO: match without using children
567
0
    if (children.empty())
568
0
        return false;
569
570
0
    if (children[0].get()->mExtTokens.size() < 2)
571
0
        return false;
572
573
0
    const auto& type = children[0].get()->mExtTokens[1];
574
0
    if (type == MatchCompiler::makeConstString("'__int128'") ||
575
0
        type == MatchCompiler::makeConstString("'unsigned __int128'") ||
576
0
        type == MatchCompiler::makeConstString("'struct __NSConstantString_tag'") ||
577
0
        type == MatchCompiler::makeConstString("'char *'") ||
578
0
        type == MatchCompiler::makeConstString("'struct __va_list_tag[1]'"))
579
0
    {
580
        // NOLINTNEXTLINE(readability-simplify-boolean-expr)
581
0
        return true;
582
0
    }
583
584
0
    return false;
585
0
}
586
587
void clangimport::AstNode::setLocations(TokenList &tokenList, int file, int line, int col)
588
0
{
589
0
    if (mExtTokens.size() >= 2)
590
0
    {
591
0
        const std::string &ext = mExtTokens[1];
592
0
        if (startsWith(ext, "<col:"))
593
0
            col = strToInt<int>(ext.substr(5, ext.find_first_of(",>", 5) - 5));
594
0
        else if (startsWith(ext, "<line:")) {
595
0
            line = strToInt<int>(ext.substr(6, ext.find_first_of(":,>", 6) - 6));
596
0
            const auto pos = ext.find(", col:");
597
0
            if (pos != std::string::npos)
598
0
                col = strToInt<int>(ext.substr(pos+6, ext.find_first_of(":,>", pos+6) - (pos+6)));
599
0
        } else if (ext[0] == '<') {
600
0
            const std::string::size_type colon = ext.find(':');
601
0
            if (colon != std::string::npos) {
602
0
                const bool windowsPath = colon == 2 && ext.size() > 3 && ext[2] == ':';
603
0
                const std::string::size_type sep1 = windowsPath ? ext.find(':', 4) : colon;
604
0
                const std::string::size_type sep2 = ext.find(':', sep1 + 1);
605
0
                file = tokenList.appendFileIfNew(ext.substr(1, sep1 - 1));
606
0
                line = strToInt<int>(ext.substr(sep1 + 1, sep2 - sep1 - 1));
607
0
            }
608
0
            else {
609
                // "<invalid sloc>" are encountered in every AST dump by some built-in TypedefDecl
610
                // an completely empty location block was encountered with a CompoundStmt
611
0
                if (ext != MatchCompiler::makeConstString("<<invalid sloc>") && ext != MatchCompiler::makeConstString("<>"))
612
0
                    throw InternalError(nullptr, "invalid AST location: " + ext, InternalError::AST);
613
0
            }
614
0
        }
615
0
    }
616
0
    mFile = file;
617
0
    mLine = line;
618
0
    mCol = col;
619
0
    for (const auto& child: children) {
620
0
        if (child)
621
0
            child->setLocations(tokenList, file, line, col);
622
0
    }
623
0
}
624
625
Token *clangimport::AstNode::addtoken(TokenList &tokenList, const std::string &str, bool valueType)
626
0
{
627
0
    const Scope *scope = getNestedInScope(tokenList);
628
0
    tokenList.addtoken(str, mLine, mCol, mFile);
629
0
    tokenList.back()->scope(scope);
630
0
    if (valueType)
631
0
        setValueType(tokenList.back());
632
0
    return tokenList.back();
633
0
}
634
635
const ::Type * clangimport::AstNode::addTypeTokens(TokenList &tokenList, const std::string &str, const Scope *scope)
636
0
{
637
0
    if (str.find("\':\'") != std::string::npos) {
638
0
        return addTypeTokens(tokenList, str.substr(0, str.find("\':\'") + 1), scope);
639
0
    }
640
641
0
    if (startsWith(str, "'enum (anonymous"))
642
0
        return nullptr;
643
644
0
    std::string type;
645
0
    if (str.find(" (") != std::string::npos) {
646
0
        if (str.find('<') != std::string::npos)
647
0
            type = str.substr(1, str.find('<')) + "...>";
648
0
        else
649
0
            type = str.substr(1,str.find(" (")-1);
650
0
    } else
651
0
        type = unquote(str);
652
653
0
    if (type.find("(*)(") != std::string::npos) {
654
0
        type.erase(type.find("(*)("));
655
0
        type += "*";
656
0
    }
657
0
    if (type.find('(') != std::string::npos)
658
0
        type.erase(type.find('('));
659
660
    // TODO: put in a helper?
661
0
    std::stack<Token *> lpar;
662
0
    for (const std::string &s: splitString(type)) {
663
0
        Token *tok = addtoken(tokenList, s, false);
664
0
        if (tok->str() == MatchCompiler::makeConstString("("))
665
0
            lpar.push(tok);
666
0
        else if (tok->str() == MatchCompiler::makeConstString(")")) {
667
0
            Token::createMutualLinks(tok, lpar.top());
668
0
            lpar.pop();
669
0
        }
670
0
    }
671
672
    // Set Type
673
0
    if (!scope) {
674
0
        scope = tokenList.back() ? tokenList.back()->scope() : nullptr;
675
0
        if (!scope)
676
0
            return nullptr;
677
0
    }
678
0
    for (const Token *typeToken = tokenList.back(); match1(typeToken); typeToken = typeToken->previous()) {
679
0
        if (!typeToken->isName())
680
0
            continue;
681
0
        const ::Type *recordType = scope->check->findVariableType(scope, typeToken);
682
0
        if (recordType) {
683
0
            const_cast<Token*>(typeToken)->type(recordType);
684
0
            return recordType;
685
0
        }
686
0
    }
687
0
    return nullptr;
688
0
}
689
690
void clangimport::AstNode::addFullScopeNameTokens(TokenList &tokenList, const Scope *recordScope)
691
0
{
692
0
    if (!recordScope)
693
0
        return;
694
0
    std::list<const Scope *> scopes;
695
0
    while (recordScope && recordScope != tokenList.back()->scope() && !recordScope->isExecutable()) {
696
0
        scopes.push_front(recordScope);
697
0
        recordScope = recordScope->nestedIn;
698
0
    }
699
0
    for (const Scope *s: scopes) {
700
0
        if (!s->className.empty()) {
701
0
            addtoken(tokenList, s->className);
702
0
            addtoken(tokenList, "::");
703
0
        }
704
0
    }
705
0
}
706
707
const Scope *clangimport::AstNode::getNestedInScope(TokenList &tokenList)
708
0
{
709
0
    if (!tokenList.back())
710
0
        return &mData->mSymbolDatabase->scopeList.front();
711
0
    if (tokenList.back()->str() == MatchCompiler::makeConstString("}") && mData->mNotScope.find(tokenList.back()) == mData->mNotScope.end())
712
0
        return tokenList.back()->scope()->nestedIn;
713
0
    return tokenList.back()->scope();
714
0
}
715
716
void clangimport::AstNode::setValueType(Token *tok)
717
0
{
718
0
    for (int i = 0; i < 2; i++) {
719
0
        const std::string &type = getType(i);
720
721
0
        if (type.find('<') != std::string::npos)
722
            // TODO
723
0
            continue;
724
725
0
        TokenList decl(nullptr);
726
0
        decl.setLang(tok->isCpp() ? Standards::Language::CPP : Standards::Language::C);
727
0
        addTypeTokens(decl, type, tok->scope());
728
0
        if (!decl.front())
729
0
            break;
730
731
0
        const ValueType valueType = ValueType::parseDecl(decl.front(), *mData->mSettings);
732
0
        if (valueType.type != ValueType::Type::UNKNOWN_TYPE) {
733
0
            tok->setValueType(new ValueType(valueType));
734
0
            break;
735
0
        }
736
0
    }
737
0
}
738
739
Scope *clangimport::AstNode::createScope(TokenList &tokenList, Scope::ScopeType scopeType, AstNodePtr astNode, const Token *def)
740
0
{
741
0
    std::vector<AstNodePtr> children2{std::move(astNode)};
742
0
    return createScope(tokenList, scopeType, children2, def);
743
0
}
744
745
Scope *clangimport::AstNode::createScope(TokenList &tokenList, Scope::ScopeType scopeType, const std::vector<AstNodePtr> & children2, const Token *def)
746
0
{
747
0
    SymbolDatabase *symbolDatabase = mData->mSymbolDatabase;
748
749
0
    auto *nestedIn = const_cast<Scope *>(getNestedInScope(tokenList));
750
751
0
    symbolDatabase->scopeList.emplace_back(nullptr, nullptr, nestedIn);
752
0
    Scope *scope = &symbolDatabase->scopeList.back();
753
0
    if (scopeType == Scope::ScopeType::eEnum)
754
0
        scope->enumeratorList.reserve(children2.size());
755
0
    nestedIn->nestedList.push_back(scope);
756
0
    scope->type = scopeType;
757
0
    scope->classDef = def;
758
0
    scope->check = nestedIn->check;
759
0
    if (match2(def)) {
760
0
        std::map<const Variable *, const Variable *> replaceVar;
761
0
        for (const Token *vartok = def->tokAt(2); vartok; vartok = vartok->next()) {
762
0
            if (!vartok->variable())
763
0
                continue;
764
0
            if (vartok->variable()->nameToken() == vartok) {
765
0
                const Variable *from = vartok->variable();
766
0
                scope->varlist.emplace_back(*from, scope);
767
0
                Variable *to = &scope->varlist.back();
768
0
                replaceVar[from] = to;
769
0
                mData->replaceVarDecl(from, to);
770
0
            }
771
0
            if (replaceVar.find(vartok->variable()) != replaceVar.end())
772
0
                const_cast<Token *>(vartok)->variable(replaceVar[vartok->variable()]);
773
0
        }
774
0
        std::list<Variable> &varlist = const_cast<Scope *>(def->scope())->varlist;
775
0
        for (auto var = varlist.cbegin(); var != varlist.cend();) {
776
0
            if (replaceVar.find(&(*var)) != replaceVar.end())
777
0
                var = varlist.erase(var);
778
0
            else
779
0
                ++var;
780
0
        }
781
0
    }
782
0
    scope->bodyStart = addtoken(tokenList, "{");
783
0
    tokenList.back()->scope(scope);
784
0
    mData->scopeAccessControl[scope] = scope->defaultAccess();
785
0
    if (!children2.empty()) {
786
0
        for (const AstNodePtr &astNode: children2) {
787
0
            if (astNode->nodeType == MatchCompiler::makeConstString("VisibilityAttr"))
788
0
                continue;
789
0
            if (astNode->nodeType == AccessSpecDecl) {
790
0
                if (contains(astNode->mExtTokens, "private"))
791
0
                    mData->scopeAccessControl[scope] = AccessControl::Private;
792
0
                else if (contains(astNode->mExtTokens, "protected"))
793
0
                    mData->scopeAccessControl[scope] = AccessControl::Protected;
794
0
                else if (contains(astNode->mExtTokens, "public"))
795
0
                    mData->scopeAccessControl[scope] = AccessControl::Public;
796
0
                continue;
797
0
            }
798
0
            astNode->createTokens(tokenList);
799
0
            if (scopeType == Scope::ScopeType::eEnum)
800
0
                astNode->addtoken(tokenList, ",");
801
0
            else if (!match3(tokenList.back()))
802
0
                astNode->addtoken(tokenList, ";");
803
0
        }
804
0
    }
805
0
    scope->bodyEnd = addtoken(tokenList, "}");
806
0
    Token::createMutualLinks(const_cast<Token*>(scope->bodyStart), const_cast<Token*>(scope->bodyEnd));
807
0
    mData->scopeAccessControl.erase(scope);
808
0
    return scope;
809
0
}
810
811
Token *clangimport::AstNode::createTokens(TokenList &tokenList)
812
0
{
813
0
    if (nodeType == ArraySubscriptExpr) {
814
0
        Token *array = getChild(0)->createTokens(tokenList);
815
0
        Token *bracket1 = addtoken(tokenList, "[");
816
0
        Token *index = children[1]->createTokens(tokenList);
817
0
        Token *bracket2 = addtoken(tokenList, "]");
818
0
        bracket1->astOperand1(array);
819
0
        bracket1->astOperand2(index);
820
0
        bracket1->link(bracket2);
821
0
        bracket2->link(bracket1);
822
0
        return bracket1;
823
0
    }
824
0
    if (nodeType == BinaryOperator) {
825
0
        Token *tok1 = getChild(0)->createTokens(tokenList);
826
0
        Token *binop = addtoken(tokenList, unquote(mExtTokens.back()));
827
0
        Token *tok2 = children[1]->createTokens(tokenList);
828
0
        binop->astOperand1(tok1);
829
0
        binop->astOperand2(tok2);
830
0
        return binop;
831
0
    }
832
0
    if (nodeType == BreakStmt)
833
0
        return addtoken(tokenList, "break");
834
0
    if (nodeType == CharacterLiteral) {
835
0
        const int c = MathLib::toBigNumber(mExtTokens.back());
836
0
        if (c == 0)
837
0
            return addtoken(tokenList, "\'\\0\'");
838
0
        if (c == '\r')
839
0
            return addtoken(tokenList, "\'\\r\'");
840
0
        if (c == '\n')
841
0
            return addtoken(tokenList, "\'\\n\'");
842
0
        if (c == '\t')
843
0
            return addtoken(tokenList, "\'\\t\'");
844
0
        if (c == '\\')
845
0
            return addtoken(tokenList, "\'\\\\\'");
846
0
        if (c < ' ' || c >= 0x80) {
847
0
            std::ostringstream hex;
848
0
            hex << std::hex << ((c>>4) & 0xf) << (c&0xf);
849
0
            return addtoken(tokenList, "\'\\x" + hex.str() + "\'");
850
0
        }
851
0
        return addtoken(tokenList, std::string("\'") + char(c) + std::string("\'"));
852
0
    }
853
0
    if (nodeType == CallExpr)
854
0
        return createTokensCall(tokenList);
855
0
    if (nodeType == CaseStmt) {
856
0
        Token *caseToken = addtoken(tokenList, "case");
857
0
        Token *exprToken = getChild(0)->createTokens(tokenList);
858
0
        caseToken->astOperand1(exprToken);
859
0
        addtoken(tokenList, ":");
860
0
        children.back()->createTokens(tokenList);
861
0
        return nullptr;
862
0
    }
863
0
    if (nodeType == ClassTemplateDecl) {
864
0
        for (const AstNodePtr& child: children) {
865
0
            if (child->nodeType == ClassTemplateSpecializationDecl)
866
0
                child->createTokens(tokenList);
867
0
        }
868
0
        return nullptr;
869
0
    }
870
0
    if (nodeType == ClassTemplateSpecializationDecl) {
871
0
        createTokensForCXXRecord(tokenList);
872
0
        return nullptr;
873
0
    }
874
0
    if (nodeType == ConditionalOperator) {
875
0
        Token *expr1 = getChild(0)->createTokens(tokenList);
876
0
        Token *tok1 = addtoken(tokenList, "?");
877
0
        Token *expr2 = children[1]->createTokens(tokenList);
878
0
        Token *tok2 = addtoken(tokenList, ":");
879
0
        Token *expr3 = children[2]->createTokens(tokenList);
880
0
        tok2->astOperand1(expr2);
881
0
        tok2->astOperand2(expr3);
882
0
        tok1->astOperand1(expr1);
883
0
        tok1->astOperand2(tok2);
884
0
        return tok1;
885
0
    }
886
0
    if (nodeType == CompoundAssignOperator) {
887
0
        Token *lhs = getChild(0)->createTokens(tokenList);
888
0
        Token *assign = addtoken(tokenList, getSpelling());
889
0
        Token *rhs = children[1]->createTokens(tokenList);
890
0
        assign->astOperand1(lhs);
891
0
        assign->astOperand2(rhs);
892
0
        return assign;
893
0
    }
894
0
    if (nodeType == CompoundStmt) {
895
0
        for (const AstNodePtr& child: children) {
896
0
            child->createTokens(tokenList);
897
0
            if (!match3(tokenList.back()))
898
0
                child->addtoken(tokenList, ";");
899
0
        }
900
0
        return nullptr;
901
0
    }
902
0
    if (nodeType == ConstantExpr)
903
0
        return children.back()->createTokens(tokenList);
904
0
    if (nodeType == ContinueStmt)
905
0
        return addtoken(tokenList, "continue");
906
0
    if (nodeType == CStyleCastExpr) {
907
0
        Token *par1 = addtoken(tokenList, "(");
908
0
        addTypeTokens(tokenList, '\'' + getType() + '\'');
909
0
        Token *par2 = addtoken(tokenList, ")");
910
0
        par1->link(par2);
911
0
        par2->link(par1);
912
0
        par1->astOperand1(getChild(0)->createTokens(tokenList));
913
0
        return par1;
914
0
    }
915
0
    if (nodeType == CXXBindTemporaryExpr)
916
0
        return getChild(0)->createTokens(tokenList);
917
0
    if (nodeType == CXXBoolLiteralExpr) {
918
0
        addtoken(tokenList, mExtTokens.back());
919
0
        tokenList.back()->setValueType(new ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0));
920
0
        return tokenList.back();
921
0
    }
922
0
    if (nodeType == CXXConstructExpr) {
923
0
        if (!children.empty())
924
0
            return getChild(0)->createTokens(tokenList);
925
0
        addTypeTokens(tokenList, '\'' + getType() + '\'');
926
0
        Token *type = tokenList.back();
927
0
        Token *par1 = addtoken(tokenList, "(");
928
0
        Token *par2 = addtoken(tokenList, ")");
929
0
        par1->link(par2);
930
0
        par2->link(par1);
931
0
        par1->astOperand1(type);
932
0
        return par1;
933
0
    }
934
0
    if (nodeType == CXXConstructorDecl) {
935
0
        createTokensFunctionDecl(tokenList);
936
0
        return nullptr;
937
0
    }
938
0
    if (nodeType == CXXDeleteExpr) {
939
0
        addtoken(tokenList, "delete");
940
0
        getChild(0)->createTokens(tokenList);
941
0
        return nullptr;
942
0
    }
943
0
    if (nodeType == CXXDestructorDecl) {
944
0
        createTokensFunctionDecl(tokenList);
945
0
        return nullptr;
946
0
    }
947
0
    if (nodeType == CXXForRangeStmt) {
948
0
        Token *forToken = addtoken(tokenList, "for");
949
0
        Token *par1 = addtoken(tokenList, "(");
950
0
        AstNodePtr varDecl;
951
0
        if (children[6]->nodeType == DeclStmt)
952
0
            varDecl = getChild(6)->getChild(0);
953
0
        else
954
0
            varDecl = getChild(5)->getChild(0);
955
0
        varDecl->mExtTokens.pop_back();
956
0
        varDecl->children.clear();
957
0
        Token *expr1 = varDecl->createTokens(tokenList);
958
0
        Token *colon = addtoken(tokenList, ":");
959
0
        AstNodePtr range;
960
0
        for (std::size_t i = 0; i < 2; i++) {
961
0
            if (children[i] && children[i]->nodeType == DeclStmt && children[i]->getChild(0)->nodeType == VarDecl) {
962
0
                range = children[i]->getChild(0)->getChild(0);
963
0
                break;
964
0
            }
965
0
        }
966
0
        if (!range)
967
0
            throw InternalError(tokenList.back(), "Failed to import CXXForRangeStmt. Range?");
968
0
        Token *expr2 = range->createTokens(tokenList);
969
0
        Token *par2 = addtoken(tokenList, ")");
970
971
0
        par1->link(par2);
972
0
        par2->link(par1);
973
974
0
        colon->astOperand1(expr1);
975
0
        colon->astOperand2(expr2);
976
0
        par1->astOperand1(forToken);
977
0
        par1->astOperand2(colon);
978
979
0
        createScope(tokenList, Scope::ScopeType::eFor, children.back(), forToken);
980
0
        return nullptr;
981
0
    }
982
0
    if (nodeType == CXXMethodDecl) {
983
0
        for (std::size_t i = 0; i+1 < mExtTokens.size(); ++i) {
984
0
            if (mExtTokens[i] == MatchCompiler::makeConstString("prev") && !mData->hasDecl(mExtTokens[i+1]))
985
0
                return nullptr;
986
0
        }
987
0
        createTokensFunctionDecl(tokenList);
988
0
        return nullptr;
989
0
    }
990
0
    if (nodeType == CXXMemberCallExpr)
991
0
        return createTokensCall(tokenList);
992
0
    if (nodeType == CXXNewExpr) {
993
0
        Token *newtok = addtoken(tokenList, "new");
994
0
        if (children.size() == 1 && getChild(0)->nodeType == CXXConstructExpr) {
995
0
            newtok->astOperand1(getChild(0)->createTokens(tokenList));
996
0
            return newtok;
997
0
        }
998
0
        std::string type = getType();
999
0
        if (type.find('*') != std::string::npos)
1000
0
            type = type.erase(type.rfind('*'));
1001
0
        addTypeTokens(tokenList, type);
1002
0
        if (!children.empty()) {
1003
0
            Token *bracket1 = addtoken(tokenList, "[");
1004
0
            getChild(0)->createTokens(tokenList);
1005
0
            Token *bracket2 = addtoken(tokenList, "]");
1006
0
            bracket1->link(bracket2);
1007
0
            bracket2->link(bracket1);
1008
0
        }
1009
0
        return newtok;
1010
0
    }
1011
0
    if (nodeType == CXXNullPtrLiteralExpr)
1012
0
        return addtoken(tokenList, "nullptr");
1013
0
    if (nodeType == CXXOperatorCallExpr)
1014
0
        return createTokensCall(tokenList);
1015
0
    if (nodeType == CXXRecordDecl) {
1016
0
        createTokensForCXXRecord(tokenList);
1017
0
        return nullptr;
1018
0
    }
1019
0
    if (nodeType == CXXStaticCastExpr || nodeType == CXXFunctionalCastExpr) {
1020
0
        Token *cast = addtoken(tokenList, getSpelling());
1021
0
        Token *par1 = addtoken(tokenList, "(");
1022
0
        Token *expr = getChild(0)->createTokens(tokenList);
1023
0
        Token *par2 = addtoken(tokenList, ")");
1024
0
        par1->link(par2);
1025
0
        par2->link(par1);
1026
0
        par1->astOperand1(cast);
1027
0
        par1->astOperand2(expr);
1028
0
        setValueType(par1);
1029
0
        return par1;
1030
0
    }
1031
0
    if (nodeType == CXXStdInitializerListExpr)
1032
0
        return getChild(0)->createTokens(tokenList);
1033
0
    if (nodeType == CXXTemporaryObjectExpr && !children.empty())
1034
0
        return getChild(0)->createTokens(tokenList);
1035
0
    if (nodeType == CXXThisExpr)
1036
0
        return addtoken(tokenList, "this");
1037
0
    if (nodeType == CXXThrowExpr) {
1038
0
        Token *t = addtoken(tokenList, "throw");
1039
0
        t->astOperand1(getChild(0)->createTokens(tokenList));
1040
0
        return t;
1041
0
    }
1042
0
    if (nodeType == DeclRefExpr) {
1043
0
        int addrIndex = mExtTokens.size() - 1;
1044
0
        while (addrIndex > 1 && !startsWith(mExtTokens[addrIndex],"0x"))
1045
0
            --addrIndex;
1046
0
        const std::string addr = mExtTokens[addrIndex];
1047
0
        std::string name = unquote(getSpelling());
1048
0
        Token *reftok = addtoken(tokenList, name.empty() ? "<NoName>" : std::move(name));
1049
0
        mData->ref(addr, reftok);
1050
0
        return reftok;
1051
0
    }
1052
0
    if (nodeType == DeclStmt)
1053
0
        return getChild(0)->createTokens(tokenList);
1054
0
    if (nodeType == DefaultStmt) {
1055
0
        addtoken(tokenList, "default");
1056
0
        addtoken(tokenList, ":");
1057
0
        children.back()->createTokens(tokenList);
1058
0
        return nullptr;
1059
0
    }
1060
0
    if (nodeType == DoStmt) {
1061
0
        addtoken(tokenList, "do");
1062
0
        createScope(tokenList, Scope::ScopeType::eDo, getChild(0), tokenList.back());
1063
0
        Token *tok1 = addtoken(tokenList, "while");
1064
0
        Token *par1 = addtoken(tokenList, "(");
1065
0
        Token *expr = children[1]->createTokens(tokenList);
1066
0
        Token *par2 = addtoken(tokenList, ")");
1067
0
        par1->link(par2);
1068
0
        par2->link(par1);
1069
0
        par1->astOperand1(tok1);
1070
0
        par1->astOperand2(expr);
1071
0
        return nullptr;
1072
0
    }
1073
0
    if (nodeType == EnumConstantDecl) {
1074
0
        Token *nameToken = addtoken(tokenList, getSpelling());
1075
0
        auto *scope = const_cast<Scope *>(nameToken->scope());
1076
0
        scope->enumeratorList.emplace_back(nameToken->scope());
1077
0
        Enumerator *e = &scope->enumeratorList.back();
1078
0
        e->name = nameToken;
1079
0
        e->value = mData->enumValue++;
1080
0
        e->value_known = true;
1081
0
        mData->enumDecl(mExtTokens.front(), nameToken, e);
1082
0
        return nameToken;
1083
0
    }
1084
0
    if (nodeType == EnumDecl) {
1085
0
        int colIndex = mExtTokens.size() - 1;
1086
0
        while (colIndex > 0 && !startsWith(mExtTokens[colIndex],"col:") && !startsWith(mExtTokens[colIndex],"line:"))
1087
0
            --colIndex;
1088
0
        if (colIndex == 0)
1089
0
            return nullptr;
1090
1091
0
        mData->enumValue = 0;
1092
0
        Token *enumtok = addtoken(tokenList, "enum");
1093
0
        const Token *nametok = nullptr;
1094
0
        {
1095
0
            int nameIndex = mExtTokens.size() - 1;
1096
0
            while (nameIndex > colIndex && mExtTokens[nameIndex][0] == '\'')
1097
0
                --nameIndex;
1098
0
            if (nameIndex > colIndex)
1099
0
                nametok = addtoken(tokenList, mExtTokens[nameIndex]);
1100
0
            if (mExtTokens.back()[0] == '\'') {
1101
0
                addtoken(tokenList, ":");
1102
0
                addTypeTokens(tokenList, mExtTokens.back());
1103
0
            }
1104
0
        }
1105
0
        Scope *enumscope = createScope(tokenList, Scope::ScopeType::eEnum, children, enumtok);
1106
0
        if (nametok)
1107
0
            enumscope->className = nametok->str();
1108
0
        if (enumscope->bodyEnd && match4(enumscope->bodyEnd->previous()))
1109
0
            const_cast<Token *>(enumscope->bodyEnd)->deletePrevious();
1110
1111
        // Create enum type
1112
0
        mData->mSymbolDatabase->typeList.emplace_back(enumtok, enumscope, enumtok->scope());
1113
0
        enumscope->definedType = &mData->mSymbolDatabase->typeList.back();
1114
0
        if (nametok)
1115
0
            const_cast<Scope *>(enumtok->scope())->definedTypesMap[nametok->str()] = enumscope->definedType;
1116
1117
0
        return nullptr;
1118
0
    }
1119
0
    if (nodeType == ExprWithCleanups)
1120
0
        return getChild(0)->createTokens(tokenList);
1121
0
    if (nodeType == FieldDecl)
1122
0
        return createTokensVarDecl(tokenList);
1123
0
    if (nodeType == FloatingLiteral)
1124
0
        return addtoken(tokenList, mExtTokens.back());
1125
0
    if (nodeType == ForStmt) {
1126
0
        Token *forToken = addtoken(tokenList, "for");
1127
0
        Token *par1 = addtoken(tokenList, "(");
1128
0
        Token *expr1 = getChild(0) ? children[0]->createTokens(tokenList) : nullptr;
1129
0
        Token *sep1 = addtoken(tokenList, ";");
1130
0
        Token *expr2 = children[2] ? children[2]->createTokens(tokenList) : nullptr;
1131
0
        Token *sep2 = addtoken(tokenList, ";");
1132
0
        Token *expr3 = children[3] ? children[3]->createTokens(tokenList) : nullptr;
1133
0
        Token *par2 = addtoken(tokenList, ")");
1134
0
        par1->link(par2);
1135
0
        par2->link(par1);
1136
0
        par1->astOperand1(forToken);
1137
0
        par1->astOperand2(sep1);
1138
0
        sep1->astOperand1(expr1);
1139
0
        sep1->astOperand2(sep2);
1140
0
        sep2->astOperand1(expr2);
1141
0
        sep2->astOperand2(expr3);
1142
0
        createScope(tokenList, Scope::ScopeType::eFor, children[4], forToken);
1143
0
        return nullptr;
1144
0
    }
1145
0
    if (nodeType == FunctionDecl) {
1146
0
        createTokensFunctionDecl(tokenList);
1147
0
        return nullptr;
1148
0
    }
1149
0
    if (nodeType == FunctionTemplateDecl) {
1150
0
        bool first = true;
1151
0
        for (const AstNodePtr& child: children) {
1152
0
            if (child->nodeType == FunctionDecl) {
1153
0
                if (!first)
1154
0
                    child->createTokens(tokenList);
1155
0
                first = false;
1156
0
            }
1157
0
        }
1158
0
        return nullptr;
1159
0
    }
1160
0
    if (nodeType == GotoStmt) {
1161
0
        addtoken(tokenList, "goto");
1162
0
        addtoken(tokenList, unquote(mExtTokens[mExtTokens.size() - 2]));
1163
0
        addtoken(tokenList, ";");
1164
0
        return nullptr;
1165
0
    }
1166
0
    if (nodeType == IfStmt) {
1167
0
        AstNodePtr cond;
1168
0
        AstNodePtr thenCode;
1169
0
        AstNodePtr elseCode;
1170
0
        if (children.size() == 2) {
1171
0
            cond = children[children.size() - 2];
1172
0
            thenCode = children[children.size() - 1];
1173
0
        } else {
1174
0
            cond = children[children.size() - 3];
1175
0
            thenCode = children[children.size() - 2];
1176
0
            elseCode = children[children.size() - 1];
1177
0
        }
1178
1179
0
        Token *iftok = addtoken(tokenList, "if");
1180
0
        Token *par1 = addtoken(tokenList, "(");
1181
0
        par1->astOperand1(iftok);
1182
0
        par1->astOperand2(cond->createTokens(tokenList));
1183
0
        Token *par2 = addtoken(tokenList, ")");
1184
0
        par1->link(par2);
1185
0
        par2->link(par1);
1186
0
        createScope(tokenList, Scope::ScopeType::eIf, std::move(thenCode), iftok);
1187
0
        if (elseCode) {
1188
0
            elseCode->addtoken(tokenList, "else");
1189
0
            createScope(tokenList, Scope::ScopeType::eElse, std::move(elseCode), tokenList.back());
1190
0
        }
1191
0
        return nullptr;
1192
0
    }
1193
0
    if (nodeType == ImplicitCastExpr) {
1194
0
        Token *expr = getChild(0)->createTokens(tokenList);
1195
0
        if (!expr->valueType() || contains(mExtTokens, "<ArrayToPointerDecay>"))
1196
0
            setValueType(expr);
1197
0
        return expr;
1198
0
    }
1199
0
    if (nodeType == InitListExpr) {
1200
0
        const Scope *scope = tokenList.back()->scope();
1201
0
        Token *start = addtoken(tokenList, "{");
1202
0
        start->scope(scope);
1203
0
        for (const AstNodePtr& child: children) {
1204
0
            if (tokenList.back()->str() != MatchCompiler::makeConstString("{"))
1205
0
                addtoken(tokenList, ",");
1206
0
            child->createTokens(tokenList);
1207
0
        }
1208
0
        Token *end = addtoken(tokenList, "}");
1209
0
        end->scope(scope);
1210
0
        start->link(end);
1211
0
        end->link(start);
1212
0
        mData->mNotScope.insert(end);
1213
0
        return start;
1214
0
    }
1215
0
    if (nodeType == IntegerLiteral)
1216
0
        return addtoken(tokenList, mExtTokens.back());
1217
0
    if (nodeType == LabelStmt) {
1218
0
        addtoken(tokenList, unquote(mExtTokens.back()));
1219
0
        addtoken(tokenList, ":");
1220
0
        for (const auto& child: children)
1221
0
            child->createTokens(tokenList);
1222
0
        return nullptr;
1223
0
    }
1224
0
    if (nodeType == LinkageSpecDecl)
1225
0
        return nullptr;
1226
0
    if (nodeType == MaterializeTemporaryExpr)
1227
0
        return getChild(0)->createTokens(tokenList);
1228
0
    if (nodeType == MemberExpr) {
1229
0
        Token *s = getChild(0)->createTokens(tokenList);
1230
0
        Token *dot = addtoken(tokenList, ".");
1231
0
        std::string memberName = getSpelling();
1232
0
        if (startsWith(memberName, "->")) {
1233
0
            dot->originalName("->");
1234
0
            memberName = memberName.substr(2);
1235
0
        } else if (startsWith(memberName, ".")) {
1236
0
            memberName = memberName.substr(1);
1237
0
        }
1238
0
        if (memberName.empty())
1239
0
            memberName = "<unknown>";
1240
0
        Token *member = addtoken(tokenList, memberName);
1241
0
        mData->ref(mExtTokens.back(), member);
1242
0
        dot->astOperand1(s);
1243
0
        dot->astOperand2(member);
1244
0
        return dot;
1245
0
    }
1246
0
    if (nodeType == NamespaceDecl) {
1247
0
        if (children.empty())
1248
0
            return nullptr;
1249
0
        const Token *defToken = addtoken(tokenList, "namespace");
1250
0
        const std::string &s = mExtTokens[mExtTokens.size() - 2];
1251
0
        const Token* nameToken = (startsWith(s, "col:") || startsWith(s, "line:")) ?
1252
0
                                 addtoken(tokenList, mExtTokens.back()) : nullptr;
1253
0
        Scope *scope = createScope(tokenList, Scope::ScopeType::eNamespace, children, defToken);
1254
0
        if (nameToken)
1255
0
            scope->className = nameToken->str();
1256
0
        return nullptr;
1257
0
    }
1258
0
    if (nodeType == NullStmt)
1259
0
        return addtoken(tokenList, ";");
1260
0
    if (nodeType == ParenExpr) {
1261
0
        Token *par1 = addtoken(tokenList, "(");
1262
0
        Token *expr = getChild(0)->createTokens(tokenList);
1263
0
        Token *par2 = addtoken(tokenList, ")");
1264
0
        par1->link(par2);
1265
0
        par2->link(par1);
1266
0
        return expr;
1267
0
    }
1268
0
    if (nodeType == RecordDecl) {
1269
0
        const Token *classDef = addtoken(tokenList, "struct");
1270
0
        const std::string &recordName = getSpelling();
1271
0
        if (!recordName.empty())
1272
0
            addtoken(tokenList, getSpelling());
1273
0
        if (!isDefinition()) {
1274
0
            addtoken(tokenList, ";");
1275
0
            return nullptr;
1276
0
        }
1277
1278
0
        Scope *recordScope = createScope(tokenList, Scope::ScopeType::eStruct, children, classDef);
1279
0
        mData->mSymbolDatabase->typeList.emplace_back(classDef, recordScope, classDef->scope());
1280
0
        recordScope->definedType = &mData->mSymbolDatabase->typeList.back();
1281
0
        if (!recordName.empty()) {
1282
0
            recordScope->className = recordName;
1283
0
            const_cast<Scope *>(classDef->scope())->definedTypesMap[recordName] = recordScope->definedType;
1284
0
        }
1285
1286
0
        return nullptr;
1287
0
    }
1288
0
    if (nodeType == ReturnStmt) {
1289
0
        Token *tok1 = addtoken(tokenList, "return");
1290
0
        if (!children.empty()) {
1291
0
            getChild(0)->setValueType(tok1);
1292
0
            tok1->astOperand1(getChild(0)->createTokens(tokenList));
1293
0
        }
1294
0
        return tok1;
1295
0
    }
1296
0
    if (nodeType == StringLiteral)
1297
0
        return addtoken(tokenList, mExtTokens.back());
1298
0
    if (nodeType == SwitchStmt) {
1299
0
        Token *tok1 = addtoken(tokenList, "switch");
1300
0
        Token *par1 = addtoken(tokenList, "(");
1301
0
        Token *expr = children[children.size() - 2]->createTokens(tokenList);
1302
0
        Token *par2 = addtoken(tokenList, ")");
1303
0
        par1->link(par2);
1304
0
        par2->link(par1);
1305
0
        par1->astOperand1(tok1);
1306
0
        par1->astOperand2(expr);
1307
0
        createScope(tokenList, Scope::ScopeType::eSwitch, children.back(), tok1);
1308
0
        return nullptr;
1309
0
    }
1310
0
    if (nodeType == TypedefDecl) {
1311
0
        addtoken(tokenList, "typedef");
1312
0
        addTypeTokens(tokenList, getType());
1313
0
        return addtoken(tokenList, getSpelling());
1314
0
    }
1315
0
    if (nodeType == UnaryOperator) {
1316
0
        int index = (int)mExtTokens.size() - 1;
1317
0
        while (index > 0 && mExtTokens[index][0] != '\'')
1318
0
            --index;
1319
0
        Token *unop = addtoken(tokenList, unquote(mExtTokens[index]));
1320
0
        unop->astOperand1(getChild(0)->createTokens(tokenList));
1321
0
        return unop;
1322
0
    }
1323
0
    if (nodeType == UnaryExprOrTypeTraitExpr) {
1324
0
        Token *tok1 = addtoken(tokenList, getSpelling());
1325
0
        Token *par1 = addtoken(tokenList, "(");
1326
0
        if (children.empty())
1327
0
            addTypeTokens(tokenList, mExtTokens.back());
1328
0
        else {
1329
0
            AstNodePtr child = getChild(0);
1330
0
            if (child && child->nodeType == ParenExpr)
1331
0
                child = child->getChild(0);
1332
0
            Token *expr = child->createTokens(tokenList);
1333
0
            child->setValueType(expr);
1334
0
            par1->astOperand2(expr);
1335
0
        }
1336
0
        Token *par2 = addtoken(tokenList, ")");
1337
0
        par1->link(par2);
1338
0
        par2->link(par1);
1339
0
        par1->astOperand1(tok1);
1340
0
        par1->astOperand2(par1->next());
1341
0
        setValueType(par1);
1342
0
        return par1;
1343
0
    }
1344
0
    if (nodeType == VarDecl)
1345
0
        return createTokensVarDecl(tokenList);
1346
0
    if (nodeType == WhileStmt) {
1347
0
        AstNodePtr cond = children[children.size() - 2];
1348
0
        AstNodePtr body = children.back();
1349
0
        Token *whiletok = addtoken(tokenList, "while");
1350
0
        Token *par1 = addtoken(tokenList, "(");
1351
0
        par1->astOperand1(whiletok);
1352
0
        par1->astOperand2(cond->createTokens(tokenList));
1353
0
        Token *par2 = addtoken(tokenList, ")");
1354
0
        par1->link(par2);
1355
0
        par2->link(par1);
1356
0
        createScope(tokenList, Scope::ScopeType::eWhile, std::move(body), whiletok);
1357
0
        return nullptr;
1358
0
    }
1359
0
    return addtoken(tokenList, "?" + nodeType + "?");
1360
0
}
1361
1362
Token * clangimport::AstNode::createTokensCall(TokenList &tokenList)
1363
0
{
1364
0
    int firstParam;
1365
0
    Token *f;
1366
0
    if (nodeType == CXXOperatorCallExpr) {
1367
0
        firstParam = 2;
1368
0
        Token *obj = getChild(1)->createTokens(tokenList);
1369
0
        Token *dot = addtoken(tokenList, ".");
1370
0
        Token *op = getChild(0)->createTokens(tokenList);
1371
0
        dot->astOperand1(obj);
1372
0
        dot->astOperand2(op);
1373
0
        f = dot;
1374
0
    } else {
1375
0
        firstParam = 1;
1376
0
        f = getChild(0)->createTokens(tokenList);
1377
0
    }
1378
0
    f->setValueType(nullptr);
1379
0
    Token *par1 = addtoken(tokenList, "(");
1380
0
    par1->astOperand1(f);
1381
0
    std::size_t args = 0;
1382
0
    while (args < children.size() && children[args]->nodeType != CXXDefaultArgExpr)
1383
0
        args++;
1384
0
    Token *child = nullptr;
1385
0
    for (std::size_t c = firstParam; c < args; ++c) {
1386
0
        if (child) {
1387
0
            Token *comma = addtoken(tokenList, ",");
1388
0
            comma->setValueType(nullptr);
1389
0
            comma->astOperand1(child);
1390
0
            comma->astOperand2(children[c]->createTokens(tokenList));
1391
0
            child = comma;
1392
0
        } else {
1393
0
            child = children[c]->createTokens(tokenList);
1394
0
        }
1395
0
    }
1396
0
    par1->astOperand2(child);
1397
0
    Token *par2 = addtoken(tokenList, ")");
1398
0
    par1->link(par2);
1399
0
    par2->link(par1);
1400
0
    return par1;
1401
0
}
1402
1403
void clangimport::AstNode::createTokensFunctionDecl(TokenList &tokenList)
1404
0
{
1405
0
    const bool prev = contains(mExtTokens, "prev");
1406
0
    const bool hasBody = !children.empty() && children.back()->nodeType == CompoundStmt;
1407
0
    const bool isStatic = contains(mExtTokens, "static");
1408
0
    const bool isInline = contains(mExtTokens, "inline");
1409
1410
0
    const Token *startToken = nullptr;
1411
1412
0
    SymbolDatabase *symbolDatabase = mData->mSymbolDatabase;
1413
0
    if (nodeType != CXXConstructorDecl && nodeType != CXXDestructorDecl) {
1414
0
        if (isStatic)
1415
0
            addtoken(tokenList, "static");
1416
0
        if (isInline)
1417
0
            addtoken(tokenList, "inline");
1418
0
        const Token * const before = tokenList.back();
1419
0
        addTypeTokens(tokenList, '\'' + getType() + '\'');
1420
0
        startToken = before ? before->next() : tokenList.front();
1421
0
    }
1422
1423
0
    if (mExtTokens.size() > 4 && mExtTokens[1] == MatchCompiler::makeConstString("parent"))
1424
0
        addFullScopeNameTokens(tokenList, mData->getScope(mExtTokens[2]));
1425
1426
0
    Token *nameToken = addtoken(tokenList, getSpelling() + getTemplateParameters());
1427
0
    auto *nestedIn = const_cast<Scope *>(nameToken->scope());
1428
1429
0
    if (prev) {
1430
0
        const std::string addr = *(std::find(mExtTokens.cbegin(), mExtTokens.cend(), "prev") + 1);
1431
0
        mData->ref(addr, nameToken);
1432
0
    }
1433
0
    if (!nameToken->function()) {
1434
0
        nestedIn->functionList.emplace_back(nameToken, unquote(getFullType()));
1435
0
        mData->funcDecl(mExtTokens.front(), nameToken, &nestedIn->functionList.back());
1436
0
        if (nodeType == CXXConstructorDecl)
1437
0
            nestedIn->functionList.back().type = Function::Type::eConstructor;
1438
0
        else if (nodeType == CXXDestructorDecl)
1439
0
            nestedIn->functionList.back().type = Function::Type::eDestructor;
1440
0
        else
1441
0
            nestedIn->functionList.back().retDef = startToken;
1442
0
    }
1443
1444
0
    auto * const function = const_cast<Function*>(nameToken->function());
1445
1446
0
    if (!prev) {
1447
0
        auto accessControl = mData->scopeAccessControl.find(tokenList.back()->scope());
1448
0
        if (accessControl != mData->scopeAccessControl.end())
1449
0
            function->access = accessControl->second;
1450
0
    }
1451
1452
0
    Scope *scope = nullptr;
1453
0
    if (hasBody) {
1454
0
        symbolDatabase->scopeList.emplace_back(nullptr, nullptr, nestedIn);
1455
0
        scope = &symbolDatabase->scopeList.back();
1456
0
        scope->check = symbolDatabase;
1457
0
        scope->function = function;
1458
0
        scope->classDef = nameToken;
1459
0
        scope->type = Scope::ScopeType::eFunction;
1460
0
        scope->className = nameToken->str();
1461
0
        nestedIn->nestedList.push_back(scope);
1462
0
        function->hasBody(true);
1463
0
        function->functionScope = scope;
1464
0
    }
1465
1466
0
    Token *par1 = addtoken(tokenList, "(");
1467
0
    if (!function->arg)
1468
0
        function->arg = par1;
1469
0
    function->token = nameToken;
1470
0
    if (!function->nestedIn)
1471
0
        function->nestedIn = nestedIn;
1472
0
    function->argDef = par1;
1473
    // Function arguments
1474
0
    for (int i = 0; i < children.size(); ++i) {
1475
0
        AstNodePtr child = children[i];
1476
0
        if (child->nodeType != ParmVarDecl)
1477
0
            continue;
1478
0
        if (tokenList.back() != par1)
1479
0
            addtoken(tokenList, ",");
1480
0
        const Type *recordType = addTypeTokens(tokenList, child->mExtTokens.back(), nestedIn);
1481
0
        const Token *typeEndToken = tokenList.back();
1482
0
        const std::string spelling = child->getSpelling();
1483
0
        Token *vartok = nullptr;
1484
0
        if (!spelling.empty())
1485
0
            vartok = child->addtoken(tokenList, spelling);
1486
0
        if (!prev) {
1487
0
            function->argumentList.emplace_back(vartok, child->getType(), nullptr, typeEndToken, i, AccessControl::Argument, recordType, scope);
1488
0
            if (vartok) {
1489
0
                const std::string addr = child->mExtTokens[0];
1490
0
                mData->varDecl(addr, vartok, &function->argumentList.back());
1491
0
            }
1492
0
        } else if (vartok) {
1493
0
            const std::string addr = child->mExtTokens[0];
1494
0
            mData->ref(addr, vartok);
1495
0
        }
1496
0
    }
1497
0
    Token *par2 = addtoken(tokenList, ")");
1498
0
    par1->link(par2);
1499
0
    par2->link(par1);
1500
1501
0
    if (function->isConst())
1502
0
        addtoken(tokenList, "const");
1503
1504
    // Function body
1505
0
    if (hasBody) {
1506
0
        symbolDatabase->functionScopes.push_back(scope);
1507
0
        Token *bodyStart = addtoken(tokenList, "{");
1508
0
        bodyStart->scope(scope);
1509
0
        children.back()->createTokens(tokenList);
1510
0
        Token *bodyEnd = addtoken(tokenList, "}");
1511
0
        scope->bodyStart = bodyStart;
1512
0
        scope->bodyEnd = bodyEnd;
1513
0
        bodyStart->link(bodyEnd);
1514
0
        bodyEnd->link(bodyStart);
1515
0
    } else {
1516
0
        if (nodeType == CXXConstructorDecl && contains(mExtTokens, "default")) {
1517
0
            addtoken(tokenList, "=");
1518
0
            addtoken(tokenList, "default");
1519
0
        }
1520
1521
0
        addtoken(tokenList, ";");
1522
0
    }
1523
0
}
1524
1525
void clangimport::AstNode::createTokensForCXXRecord(TokenList &tokenList)
1526
0
{
1527
0
    const bool isStruct = contains(mExtTokens, "struct");
1528
0
    Token * const classToken = addtoken(tokenList, isStruct ? "struct" : "class");
1529
0
    std::string className;
1530
0
    if (mExtTokens[mExtTokens.size() - 2] == (isStruct?"struct":"class"))
1531
0
        className = mExtTokens.back();
1532
0
    else
1533
0
        className = mExtTokens[mExtTokens.size() - 2];
1534
0
    className += getTemplateParameters();
1535
0
    /*Token *nameToken =*/ addtoken(tokenList, className);
1536
    // base classes
1537
0
    bool firstBase = true;
1538
0
    for (const AstNodePtr &child: children) {
1539
0
        if (child->nodeType == MatchCompiler::makeConstString("public") || child->nodeType == MatchCompiler::makeConstString("protected") || child->nodeType == MatchCompiler::makeConstString("private")) {
1540
0
            addtoken(tokenList, firstBase ? ":" : ",");
1541
0
            addtoken(tokenList, child->nodeType);
1542
0
            addtoken(tokenList, unquote(child->mExtTokens.back()));
1543
0
            firstBase = false;
1544
0
        }
1545
0
    }
1546
    // definition
1547
0
    if (isDefinition()) {
1548
0
        std::vector<AstNodePtr> children2;
1549
0
        std::copy_if(children.cbegin(), children.cend(), std::back_inserter(children2), [](const AstNodePtr& child) {
1550
0
            return child->nodeType == CXXConstructorDecl ||
1551
0
            child->nodeType == CXXDestructorDecl ||
1552
0
            child->nodeType == CXXMethodDecl ||
1553
0
            child->nodeType == FieldDecl ||
1554
0
            child->nodeType == VarDecl ||
1555
0
            child->nodeType == AccessSpecDecl ||
1556
0
            child->nodeType == TypedefDecl;
1557
0
        });
1558
0
        Scope *scope = createScope(tokenList, isStruct ? Scope::ScopeType::eStruct : Scope::ScopeType::eClass, children2, classToken);
1559
0
        const std::string addr = mExtTokens[0];
1560
0
        mData->scopeDecl(addr, scope);
1561
0
        scope->className = className;
1562
0
        mData->mSymbolDatabase->typeList.emplace_back(classToken, scope, classToken->scope());
1563
0
        scope->definedType = &mData->mSymbolDatabase->typeList.back();
1564
0
        const_cast<Scope *>(classToken->scope())->definedTypesMap[className] = scope->definedType;
1565
0
    }
1566
0
    addtoken(tokenList, ";");
1567
0
    tokenList.back()->scope(classToken->scope());
1568
0
}
1569
1570
Token * clangimport::AstNode::createTokensVarDecl(TokenList &tokenList)
1571
0
{
1572
0
    const std::string addr = mExtTokens.front();
1573
0
    if (contains(mExtTokens, "static"))
1574
0
        addtoken(tokenList, "static");
1575
0
    int typeIndex = mExtTokens.size() - 1;
1576
0
    while (typeIndex > 1 && std::isalpha(mExtTokens[typeIndex][0]))
1577
0
        typeIndex--;
1578
0
    const std::string type = mExtTokens[typeIndex];
1579
0
    const std::string name = mExtTokens[typeIndex - 1];
1580
0
    const Token *startToken = tokenList.back();
1581
0
    const ::Type *recordType = addTypeTokens(tokenList, type);
1582
0
    if (!startToken)
1583
0
        startToken = tokenList.front();
1584
0
    else if (startToken->str() != MatchCompiler::makeConstString("static"))
1585
0
        startToken = startToken->next();
1586
0
    Token *vartok1 = addtoken(tokenList, name);
1587
0
    auto *scope = const_cast<Scope *>(tokenList.back()->scope());
1588
0
    scope->varlist.emplace_back(vartok1, unquote(type), startToken, vartok1->previous(), 0, scope->defaultAccess(), recordType, scope);
1589
0
    mData->varDecl(addr, vartok1, &scope->varlist.back());
1590
0
    if (mExtTokens.back() == MatchCompiler::makeConstString("cinit") && !children.empty()) {
1591
0
        Token *eq = addtoken(tokenList, "=");
1592
0
        eq->astOperand1(vartok1);
1593
0
        eq->astOperand2(children.back()->createTokens(tokenList));
1594
0
        return eq;
1595
0
    }
1596
0
    if (mExtTokens.back() == MatchCompiler::makeConstString("callinit")) {
1597
0
        Token *par1 = addtoken(tokenList, "(");
1598
0
        par1->astOperand1(vartok1);
1599
0
        par1->astOperand2(getChild(0)->createTokens(tokenList));
1600
0
        Token *par2 = addtoken(tokenList, ")");
1601
0
        par1->link(par2);
1602
0
        par2->link(par1);
1603
0
        return par1;
1604
0
    }
1605
0
    if (mExtTokens.back() == MatchCompiler::makeConstString("listinit")) {
1606
0
        return getChild(0)->createTokens(tokenList);
1607
0
    }
1608
0
    return vartok1;
1609
0
}
1610
1611
static void setTypes(TokenList &tokenList)
1612
0
{
1613
0
    for (Token *tok = tokenList.front(); tok; tok = tok->next()) {
1614
0
        if (match5(tok)) {
1615
0
            for (Token *typeToken = tok->tokAt(2); typeToken->str() != MatchCompiler::makeConstString(")"); typeToken = typeToken->next()) {
1616
0
                if (typeToken->type())
1617
0
                    continue;
1618
0
                typeToken->type(typeToken->scope()->findType(typeToken->str()));
1619
0
            }
1620
0
        }
1621
0
    }
1622
0
}
1623
1624
static void setValues(const Tokenizer &tokenizer, const SymbolDatabase *symbolDatabase)
1625
0
{
1626
0
    const Settings & settings = tokenizer.getSettings();
1627
1628
0
    for (const Scope& scope : symbolDatabase->scopeList) {
1629
0
        if (!scope.definedType)
1630
0
            continue;
1631
1632
0
        MathLib::bigint typeSize = 0;
1633
0
        for (const Variable &var: scope.varlist) {
1634
0
            const int mul = std::accumulate(var.dimensions().cbegin(), var.dimensions().cend(), 1, [](int v, const Dimension& dim) {
1635
0
                return v * dim.num;
1636
0
            });
1637
0
            if (var.valueType())
1638
0
                typeSize += mul * var.valueType()->typeSize(settings.platform, true);
1639
0
        }
1640
0
        scope.definedType->sizeOf = typeSize;
1641
0
    }
1642
1643
0
    for (auto *tok = const_cast<Token*>(tokenizer.tokens()); tok; tok = tok->next()) {
1644
0
        if (match5(tok)) {
1645
0
            ValueType vt = ValueType::parseDecl(tok->tokAt(2), settings);
1646
0
            const MathLib::bigint sz = vt.typeSize(settings.platform, true);
1647
0
            if (sz <= 0)
1648
0
                continue;
1649
0
            long long mul = 1;
1650
0
            for (const Token *arrtok = tok->linkAt(1)->previous(); arrtok; arrtok = arrtok->previous()) {
1651
0
                const std::string &a = arrtok->str();
1652
0
                if (a.size() > 2 && a[0] == '[' && a.back() == ']')
1653
0
                    mul *= strToInt<long long>(a.substr(1));
1654
0
                else
1655
0
                    break;
1656
0
            }
1657
0
            ValueFlow::Value v(mul * sz);
1658
0
            v.setKnown();
1659
0
            tok->next()->addValue(v);
1660
0
        }
1661
0
    }
1662
0
}
1663
1664
void clangimport::parseClangAstDump(Tokenizer &tokenizer, std::istream &f)
1665
0
{
1666
0
    TokenList &tokenList = tokenizer.list;
1667
1668
0
    tokenizer.createSymbolDatabase();
1669
0
    auto *symbolDatabase = const_cast<SymbolDatabase *>(tokenizer.getSymbolDatabase());
1670
0
    symbolDatabase->scopeList.emplace_back(nullptr, nullptr, nullptr);
1671
0
    symbolDatabase->scopeList.back().type = Scope::ScopeType::eGlobal;
1672
0
    symbolDatabase->scopeList.back().check = symbolDatabase;
1673
1674
0
    clangimport::Data data;
1675
0
    data.mSettings = &tokenizer.getSettings();
1676
0
    data.mSymbolDatabase = symbolDatabase;
1677
0
    std::string line;
1678
0
    std::vector<AstNodePtr> tree;
1679
0
    while (std::getline(f,line)) {
1680
0
        const std::string::size_type pos1 = line.find('-');
1681
0
        if (pos1 == std::string::npos)
1682
0
            continue;
1683
0
        if (!tree.empty() && line.substr(pos1) == MatchCompiler::makeConstString("-<<<NULL>>>")) {
1684
0
            const int level = (pos1 - 1) / 2;
1685
0
            tree[level - 1]->children.push_back(nullptr);
1686
0
            continue;
1687
0
        }
1688
0
        const std::string::size_type pos2 = line.find(' ', pos1);
1689
0
        if (pos2 < pos1 + 4 || pos2 == std::string::npos)
1690
0
            continue;
1691
0
        const std::string nodeType = line.substr(pos1+1, pos2 - pos1 - 1);
1692
0
        const std::string ext = line.substr(pos2);
1693
1694
0
        if (pos1 == 1 && endsWith(nodeType, "Decl")) {
1695
0
            if (!tree.empty())
1696
0
                tree[0]->createTokens1(tokenList);
1697
0
            tree.clear();
1698
0
            tree.push_back(std::make_shared<AstNode>(nodeType, ext, &data));
1699
0
            continue;
1700
0
        }
1701
1702
0
        const int level = (pos1 - 1) / 2;
1703
0
        if (level == 0 || level > tree.size())
1704
0
            continue;
1705
1706
0
        AstNodePtr newNode = std::make_shared<AstNode>(nodeType, ext, &data);
1707
0
        tree[level - 1]->children.push_back(newNode);
1708
0
        if (level >= tree.size())
1709
0
            tree.push_back(std::move(newNode));
1710
0
        else
1711
0
            tree[level] = std::move(newNode);
1712
0
    }
1713
1714
0
    if (!tree.empty())
1715
0
        tree[0]->createTokens1(tokenList);
1716
1717
    // Validation
1718
0
    for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
1719
0
        if (match6(tok) && !tok->link())
1720
0
            throw InternalError(tok, "Token::link() is not set properly");
1721
0
    }
1722
1723
0
    if (tokenList.front())
1724
0
        tokenList.front()->assignIndexes();
1725
0
    symbolDatabase->clangSetVariables(data.getVariableList());
1726
0
    symbolDatabase->createSymbolDatabaseExprIds();
1727
0
    tokenList.clangSetOrigFiles();
1728
0
    setTypes(tokenList);
1729
0
    setValues(tokenizer, symbolDatabase);
1730
0
}
1731