1 /* 2 * Cppcheck - A tool for static C/C++ code analysis 3 * Copyright (C) 2007-2021 Cppcheck team. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 //--------------------------------------------------------------------------- 20 #ifndef tokenH 21 #define tokenH 22 //--------------------------------------------------------------------------- 23 24 #include "config.h" 25 #include "mathlib.h" 26 #include "valueflow.h" 27 #include "templatesimplifier.h" 28 #include "utils.h" 29 30 #include <cstddef> 31 #include <functional> 32 #include <list> 33 #include <memory> 34 #include <ostream> 35 #include <string> 36 #include <vector> 37 38 class Enumerator; 39 class Function; 40 class Scope; 41 class Settings; 42 class Type; 43 class ValueType; 44 class Variable; 45 class TokenList; 46 47 class ConstTokenRange; 48 49 /** 50 * @brief This struct stores pointers to the front and back tokens of the list this token is in. 51 */ 52 struct TokensFrontBack { 53 Token *front; 54 Token *back; 55 const TokenList* list; 56 }; 57 58 struct ScopeInfo2 { nameScopeInfo259 ScopeInfo2(const std::string &name_, const Token *bodyEnd_, const std::set<std::string> &usingNamespaces_ = std::set<std::string>()) : name(name_), bodyEnd(bodyEnd_), usingNamespaces(usingNamespaces_) {} 60 std::string name; 61 const Token * const bodyEnd; 62 std::set<std::string> usingNamespaces; 63 }; 64 65 struct TokenImpl { 66 nonneg int mVarId; 67 nonneg int mFileIndex; 68 nonneg int mLineNumber; 69 nonneg int mColumn; 70 nonneg int mExprId; 71 72 // AST.. 73 Token *mAstOperand1; 74 Token *mAstOperand2; 75 Token *mAstParent; 76 77 // symbol database information 78 const Scope *mScope; 79 union { 80 const Function *mFunction; 81 const Variable *mVariable; 82 const ::Type* mType; 83 const Enumerator *mEnumerator; 84 }; 85 86 /** 87 * A value from 0-100 that provides a rough idea about where in the token 88 * list this token is located. 89 */ 90 nonneg int mProgressValue; 91 92 /** 93 * Token index. Position in token list 94 */ 95 nonneg int mIndex; 96 97 // original name like size_t 98 std::string* mOriginalName; 99 100 // ValueType 101 ValueType *mValueType; 102 103 // ValueFlow 104 std::list<ValueFlow::Value>* mValues; 105 static const std::list<ValueFlow::Value> mEmptyValueList; 106 107 // Pointer to a template in the template simplifier 108 std::set<TemplateSimplifier::TokenAndName*>* mTemplateSimplifierPointers; 109 110 // Pointer to the object representing this token's scope 111 std::shared_ptr<ScopeInfo2> mScopeInfo; 112 113 // __cppcheck_in_range__ 114 struct CppcheckAttributes { 115 enum Type {LOW,HIGH} type; 116 MathLib::bigint value; 117 struct CppcheckAttributes *next; 118 }; 119 struct CppcheckAttributes *mCppcheckAttributes; 120 121 // For memoization, to speed up parsing of huge arrays #8897 122 enum class Cpp11init {UNKNOWN, CPP11INIT, NOINIT} mCpp11init; 123 124 /** Bitfield bit count. */ 125 unsigned char mBits; 126 127 void setCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint value); 128 bool getCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint *value) const; 129 TokenImplTokenImpl130 TokenImpl() 131 : mVarId(0) 132 , mFileIndex(0) 133 , mLineNumber(0) 134 , mColumn(0) 135 , mExprId(0) 136 , mAstOperand1(nullptr) 137 , mAstOperand2(nullptr) 138 , mAstParent(nullptr) 139 , mScope(nullptr) 140 , mFunction(nullptr) // Initialize whole union 141 , mProgressValue(0) 142 , mIndex(0) 143 , mOriginalName(nullptr) 144 , mValueType(nullptr) 145 , mValues(nullptr) 146 , mTemplateSimplifierPointers(nullptr) 147 , mScopeInfo(nullptr) 148 , mCppcheckAttributes(nullptr) 149 , mCpp11init(Cpp11init::UNKNOWN) 150 , mBits(0) 151 {} 152 153 ~TokenImpl(); 154 }; 155 156 /// @addtogroup Core 157 /// @{ 158 159 /** 160 * @brief The token list that the TokenList generates is a linked-list of this class. 161 * 162 * Tokens are stored as strings. The "if", "while", etc are stored in plain text. 163 * The reason the Token class is needed (instead of using the string class) is that some extra functionality is also needed for tokens: 164 * - location of the token is stored (fileIndex, linenr, column) 165 * - functions for classifying the token (isName, isNumber, isBoolean, isStandardType) 166 * 167 * The Token class also has other functions for management of token list, matching tokens, etc. 168 */ 169 class CPPCHECKLIB Token { 170 private: 171 TokensFrontBack* mTokensFrontBack; 172 173 // Not implemented.. 174 Token(const Token &); 175 Token operator=(const Token &); 176 177 public: 178 enum Type { 179 eVariable, eType, eFunction, eKeyword, eName, // Names: Variable (varId), Type (typeId, later), Function (FuncId, later), Language keyword, Name (unknown identifier) 180 eNumber, eString, eChar, eBoolean, eLiteral, eEnumerator, // Literals: Number, String, Character, Boolean, User defined literal (C++11), Enumerator 181 eArithmeticalOp, eComparisonOp, eAssignmentOp, eLogicalOp, eBitOp, eIncDecOp, eExtendedOp, // Operators: Arithmetical, Comparison, Assignment, Logical, Bitwise, ++/--, Extended 182 eBracket, // {, }, <, >: < and > only if link() is set. Otherwise they are comparison operators. 183 eLambda, // A function without a name 184 eEllipsis, // "..." 185 eOther, 186 eNone 187 }; 188 189 explicit Token(TokensFrontBack *tokensFrontBack = nullptr); 190 ~Token(); 191 192 ConstTokenRange until(const Token * t) const; 193 194 template<typename T> str(T && s)195 void str(T&& s) { 196 mStr = s; 197 mImpl->mVarId = 0; 198 199 update_property_info(); 200 } 201 202 /** 203 * Concatenate two (quoted) strings. Automatically cuts of the last/first character. 204 * Example: "hello ""world" -> "hello world". Used by the token simplifier. 205 */ 206 void concatStr(std::string const& b); 207 str()208 const std::string &str() const { 209 return mStr; 210 } 211 212 /** 213 * Unlink and delete the next 'count' tokens. 214 */ 215 void deleteNext(nonneg int count = 1); 216 217 /** 218 * Unlink and delete the previous 'count' tokens. 219 */ 220 void deletePrevious(nonneg int count = 1); 221 222 /** 223 * Swap the contents of this token with the next token. 224 */ 225 void swapWithNext(); 226 227 /** 228 * @return token in given index, related to this token. 229 * For example index 1 would return next token, and 2 230 * would return next from that one. 231 */ 232 const Token *tokAt(int index) const; tokAt(int index)233 Token *tokAt(int index) { 234 return const_cast<Token *>(const_cast<const Token *>(this)->tokAt(index)); 235 } 236 237 /** 238 * @return the link to the token in given index, related to this token. 239 * For example index 1 would return the link to next token. 240 */ 241 const Token *linkAt(int index) const; linkAt(int index)242 Token *linkAt(int index) { 243 return const_cast<Token *>(const_cast<const Token *>(this)->linkAt(index)); 244 } 245 246 /** 247 * @return String of the token in given index, related to this token. 248 * If that token does not exist, an empty string is being returned. 249 */ 250 const std::string &strAt(int index) const; 251 252 /** 253 * Match given token (or list of tokens) to a pattern list. 254 * 255 * Possible patterns 256 * "someRandomText" If token contains "someRandomText". 257 * @note Use Match() if you want to use flags in patterns 258 * 259 * The patterns can be also combined to compare to multiple tokens at once 260 * by separating tokens with a space, e.g. 261 * ") void {" will return true if first token is ')' next token 262 * is "void" and token after that is '{'. If even one of the tokens does 263 * not match its pattern, false is returned. 264 * 265 * @param tok List of tokens to be compared to the pattern 266 * @param pattern The pattern against which the tokens are compared, 267 * e.g. "const" or ") void {". 268 * @return true if given token matches with given pattern 269 * false if given token does not match with given pattern 270 */ 271 template<size_t count> simpleMatch(const Token * tok,const char (& pattern)[count])272 static bool simpleMatch(const Token *tok, const char (&pattern)[count]) { 273 return simpleMatch(tok, pattern, count-1); 274 } 275 276 static bool simpleMatch(const Token *tok, const char pattern[], size_t pattern_len); 277 278 /** 279 * Match given token (or list of tokens) to a pattern list. 280 * 281 * Possible patterns 282 * - "%any%" any token 283 * - "%assign%" a assignment operand 284 * - "%bool%" true or false 285 * - "%char%" Any token enclosed in '-character. 286 * - "%comp%" Any token such that isComparisonOp() returns true. 287 * - "%cop%" Any token such that isConstOp() returns true. 288 * - "%name%" any token which is a name, variable or type e.g. "hello" or "int" 289 * - "%num%" Any numeric token, e.g. "23" 290 * - "%op%" Any token such that isOp() returns true. 291 * - "%or%" A bitwise-or operator '|' 292 * - "%oror%" A logical-or operator '||' 293 * - "%type%" Anything that can be a variable type, e.g. "int", but not "delete". 294 * - "%str%" Any token starting with "-character (C-string). 295 * - "%var%" Match with token with varId > 0 296 * - "%varid%" Match with parameter varid 297 * - "[abc]" Any of the characters 'a' or 'b' or 'c' 298 * - "int|void|char" Any of the strings, int, void or char 299 * - "int|void|char|" Any of the strings, int, void or char or empty string 300 * - "!!else" No tokens or any token that is not "else". 301 * - "someRandomText" If token contains "someRandomText". 302 * 303 * multi-compare patterns such as "int|void|char" can contain %%or%, %%oror% and %%op% 304 * it is recommended to put such an %%cmd% as the first pattern. 305 * For example: "%var%|%num%|)" means yes to a variable, a number or ')'. 306 * 307 * The patterns can be also combined to compare to multiple tokens at once 308 * by separating tokens with a space, e.g. 309 * ") const|void {" will return true if first token is ')' next token is either 310 * "const" or "void" and token after that is '{'. If even one of the tokens does not 311 * match its pattern, false is returned. 312 * 313 * @param tok List of tokens to be compared to the pattern 314 * @param pattern The pattern against which the tokens are compared, 315 * e.g. "const" or ") const|volatile| {". 316 * @param varid if %%varid% is given in the pattern the Token::varId 317 * will be matched against this argument 318 * @return true if given token matches with given pattern 319 * false if given token does not match with given pattern 320 */ 321 static bool Match(const Token *tok, const char pattern[], nonneg int varid = 0); 322 323 /** 324 * @return length of C-string. 325 * 326 * Should be called for %%str%% tokens only. 327 * 328 * @param tok token with C-string 329 **/ 330 static nonneg int getStrLength(const Token *tok); 331 332 /** 333 * @return array length of C-string. 334 * 335 * Should be called for %%str%% tokens only. 336 * 337 * @param tok token with C-string 338 **/ 339 static nonneg int getStrArraySize(const Token *tok); 340 341 /** 342 * @return sizeof of C-string. 343 * 344 * Should be called for %%str%% tokens only. 345 * 346 * @param tok token with C-string 347 * @param settings Settings 348 **/ 349 static nonneg int getStrSize(const Token *tok, const Settings *const settings); 350 351 /** 352 * @return char of C-string at index (possible escaped "\\n") 353 * 354 * Should be called for %%str%% tokens only. 355 * 356 * @param tok token with C-string 357 * @param index position of character 358 **/ 359 static std::string getCharAt(const Token *tok, MathLib::bigint index); 360 valueType()361 const ValueType *valueType() const { 362 return mImpl->mValueType; 363 } 364 void setValueType(ValueType *vt); 365 argumentType()366 const ValueType *argumentType() const { 367 const Token *top = this; 368 while (top && !Token::Match(top->astParent(), ",|(")) 369 top = top->astParent(); 370 return top ? top->mImpl->mValueType : nullptr; 371 } 372 tokType()373 Token::Type tokType() const { 374 return mTokType; 375 } tokType(Token::Type t)376 void tokType(Token::Type t) { 377 mTokType = t; 378 379 const bool memoizedIsName = (mTokType == eName || mTokType == eType || mTokType == eVariable || 380 mTokType == eFunction || mTokType == eKeyword || mTokType == eBoolean || 381 mTokType == eEnumerator); // TODO: "true"/"false" aren't really a name... 382 setFlag(fIsName, memoizedIsName); 383 384 const bool memoizedIsLiteral = (mTokType == eNumber || mTokType == eString || mTokType == eChar || 385 mTokType == eBoolean || mTokType == eLiteral || mTokType == eEnumerator); 386 setFlag(fIsLiteral, memoizedIsLiteral); 387 } isKeyword()388 bool isKeyword() const { 389 return mTokType == eKeyword; 390 } isName()391 bool isName() const { 392 return getFlag(fIsName); 393 } isNameOnly()394 bool isNameOnly() const { 395 return mFlags == fIsName && mTokType == eName; 396 } 397 bool isUpperCaseName() const; isLiteral()398 bool isLiteral() const { 399 return getFlag(fIsLiteral); 400 } isNumber()401 bool isNumber() const { 402 return mTokType == eNumber; 403 } isEnumerator()404 bool isEnumerator() const { 405 return mTokType == eEnumerator; 406 } isOp()407 bool isOp() const { 408 return (isConstOp() || 409 isAssignmentOp() || 410 mTokType == eIncDecOp); 411 } isConstOp()412 bool isConstOp() const { 413 return (isArithmeticalOp() || 414 mTokType == eLogicalOp || 415 mTokType == eComparisonOp || 416 mTokType == eBitOp); 417 } isExtendedOp()418 bool isExtendedOp() const { 419 return isConstOp() || 420 mTokType == eExtendedOp; 421 } isArithmeticalOp()422 bool isArithmeticalOp() const { 423 return mTokType == eArithmeticalOp; 424 } isComparisonOp()425 bool isComparisonOp() const { 426 return mTokType == eComparisonOp; 427 } isAssignmentOp()428 bool isAssignmentOp() const { 429 return mTokType == eAssignmentOp; 430 } isBoolean()431 bool isBoolean() const { 432 return mTokType == eBoolean; 433 } isIncDecOp()434 bool isIncDecOp() const { 435 return mTokType == eIncDecOp; 436 } isBinaryOp()437 bool isBinaryOp() const { 438 return astOperand1() != nullptr && astOperand2() != nullptr; 439 } isUnaryOp(const std::string & s)440 bool isUnaryOp(const std::string &s) const { 441 return s == mStr && astOperand1() != nullptr && astOperand2() == nullptr; 442 } 443 bool isUnaryPreOp() const; 444 flags()445 unsigned int flags() const { 446 return mFlags; 447 } flags(const unsigned int flags_)448 void flags(const unsigned int flags_) { 449 mFlags = flags_; 450 } isUnsigned()451 bool isUnsigned() const { 452 return getFlag(fIsUnsigned); 453 } isUnsigned(const bool sign)454 void isUnsigned(const bool sign) { 455 setFlag(fIsUnsigned, sign); 456 } isSigned()457 bool isSigned() const { 458 return getFlag(fIsSigned); 459 } isSigned(const bool sign)460 void isSigned(const bool sign) { 461 setFlag(fIsSigned, sign); 462 } isPointerCompare()463 bool isPointerCompare() const { 464 return getFlag(fIsPointerCompare); 465 } isPointerCompare(const bool b)466 void isPointerCompare(const bool b) { 467 setFlag(fIsPointerCompare, b); 468 } isLong()469 bool isLong() const { 470 return getFlag(fIsLong); 471 } isLong(bool size)472 void isLong(bool size) { 473 setFlag(fIsLong, size); 474 } isStandardType()475 bool isStandardType() const { 476 return getFlag(fIsStandardType); 477 } isStandardType(const bool b)478 void isStandardType(const bool b) { 479 setFlag(fIsStandardType, b); 480 } isExpandedMacro()481 bool isExpandedMacro() const { 482 return getFlag(fIsExpandedMacro); 483 } isExpandedMacro(const bool m)484 void isExpandedMacro(const bool m) { 485 setFlag(fIsExpandedMacro, m); 486 } isCast()487 bool isCast() const { 488 return getFlag(fIsCast); 489 } isCast(bool c)490 void isCast(bool c) { 491 setFlag(fIsCast, c); 492 } isAttributeConstructor()493 bool isAttributeConstructor() const { 494 return getFlag(fIsAttributeConstructor); 495 } isAttributeConstructor(const bool ac)496 void isAttributeConstructor(const bool ac) { 497 setFlag(fIsAttributeConstructor, ac); 498 } isAttributeDestructor()499 bool isAttributeDestructor() const { 500 return getFlag(fIsAttributeDestructor); 501 } isAttributeDestructor(const bool value)502 void isAttributeDestructor(const bool value) { 503 setFlag(fIsAttributeDestructor, value); 504 } isAttributeUnused()505 bool isAttributeUnused() const { 506 return getFlag(fIsAttributeUnused); 507 } isAttributeUnused(bool unused)508 void isAttributeUnused(bool unused) { 509 setFlag(fIsAttributeUnused, unused); 510 } isAttributeUsed()511 bool isAttributeUsed() const { 512 return getFlag(fIsAttributeUsed); 513 } isAttributeUsed(const bool unused)514 void isAttributeUsed(const bool unused) { 515 setFlag(fIsAttributeUsed, unused); 516 } isAttributePure()517 bool isAttributePure() const { 518 return getFlag(fIsAttributePure); 519 } isAttributePure(const bool value)520 void isAttributePure(const bool value) { 521 setFlag(fIsAttributePure, value); 522 } isAttributeConst()523 bool isAttributeConst() const { 524 return getFlag(fIsAttributeConst); 525 } isAttributeConst(bool value)526 void isAttributeConst(bool value) { 527 setFlag(fIsAttributeConst, value); 528 } isAttributeNoreturn()529 bool isAttributeNoreturn() const { 530 return getFlag(fIsAttributeNoreturn); 531 } isAttributeNoreturn(const bool value)532 void isAttributeNoreturn(const bool value) { 533 setFlag(fIsAttributeNoreturn, value); 534 } isAttributeNothrow()535 bool isAttributeNothrow() const { 536 return getFlag(fIsAttributeNothrow); 537 } isAttributeNothrow(const bool value)538 void isAttributeNothrow(const bool value) { 539 setFlag(fIsAttributeNothrow, value); 540 } isAttributePacked()541 bool isAttributePacked() const { 542 return getFlag(fIsAttributePacked); 543 } isAttributePacked(const bool value)544 void isAttributePacked(const bool value) { 545 setFlag(fIsAttributePacked, value); 546 } isAttributeNodiscard()547 bool isAttributeNodiscard() const { 548 return getFlag(fIsAttributeNodiscard); 549 } isAttributeNodiscard(const bool value)550 void isAttributeNodiscard(const bool value) { 551 setFlag(fIsAttributeNodiscard, value); 552 } isAttributeMaybeUnused()553 bool isAttributeMaybeUnused() const { 554 return getFlag(fIsAttributeMaybeUnused); 555 } isAttributeMaybeUnused(const bool value)556 void isAttributeMaybeUnused(const bool value) { 557 setFlag(fIsAttributeMaybeUnused, value); 558 } setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type,MathLib::bigint value)559 void setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint value) { 560 mImpl->setCppcheckAttribute(type, value); 561 } getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type,MathLib::bigint * value)562 bool getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint *value) const { 563 return mImpl->getCppcheckAttribute(type, value); 564 } hasCppcheckAttributes()565 bool hasCppcheckAttributes() const { 566 return nullptr != mImpl->mCppcheckAttributes; 567 } isControlFlowKeyword()568 bool isControlFlowKeyword() const { 569 return getFlag(fIsControlFlowKeyword); 570 } isOperatorKeyword()571 bool isOperatorKeyword() const { 572 return getFlag(fIsOperatorKeyword); 573 } isOperatorKeyword(const bool value)574 void isOperatorKeyword(const bool value) { 575 setFlag(fIsOperatorKeyword, value); 576 } isComplex()577 bool isComplex() const { 578 return getFlag(fIsComplex); 579 } isComplex(const bool value)580 void isComplex(const bool value) { 581 setFlag(fIsComplex, value); 582 } isEnumType()583 bool isEnumType() const { 584 return getFlag(fIsEnumType); 585 } isEnumType(const bool value)586 void isEnumType(const bool value) { 587 setFlag(fIsEnumType, value); 588 } isAtAddress()589 bool isAtAddress() const { 590 return getFlag(fAtAddress); 591 } isAtAddress(bool b)592 void isAtAddress(bool b) { 593 setFlag(fAtAddress, b); 594 } isIncompleteVar()595 bool isIncompleteVar() const { 596 return getFlag(fIncompleteVar); 597 } isIncompleteVar(bool b)598 void isIncompleteVar(bool b) { 599 setFlag(fIncompleteVar, b); 600 } 601 isConstexpr()602 bool isConstexpr() const { 603 return getFlag(fConstexpr); 604 } isConstexpr(bool b)605 void isConstexpr(bool b) { 606 setFlag(fConstexpr, b); 607 } 608 isExternC()609 bool isExternC() const { 610 return getFlag(fExternC); 611 } isExternC(bool b)612 void isExternC(bool b) { 613 setFlag(fExternC, b); 614 } 615 isSplittedVarDeclComma()616 bool isSplittedVarDeclComma() const { 617 return getFlag(fIsSplitVarDeclComma); 618 } isSplittedVarDeclComma(bool b)619 void isSplittedVarDeclComma(bool b) { 620 setFlag(fIsSplitVarDeclComma, b); 621 } 622 isSplittedVarDeclEq()623 bool isSplittedVarDeclEq() const { 624 return getFlag(fIsSplitVarDeclEq); 625 } isSplittedVarDeclEq(bool b)626 void isSplittedVarDeclEq(bool b) { 627 setFlag(fIsSplitVarDeclEq, b); 628 } 629 isImplicitInt()630 bool isImplicitInt() const { 631 return getFlag(fIsImplicitInt); 632 } isImplicitInt(bool b)633 void isImplicitInt(bool b) { 634 setFlag(fIsImplicitInt, b); 635 } 636 isInline()637 bool isInline() const { 638 return getFlag(fIsInline); 639 } isInline(bool b)640 void isInline(bool b) { 641 setFlag(fIsInline, b); 642 } 643 isTemplate()644 bool isTemplate() const { 645 return getFlag(fIsTemplate); 646 } isTemplate(bool b)647 void isTemplate(bool b) { 648 setFlag(fIsTemplate, b); 649 } 650 isBitfield()651 bool isBitfield() const { 652 return mImpl->mBits > 0; 653 } bits()654 unsigned char bits() const { 655 return mImpl->mBits; 656 } templateSimplifierPointers()657 std::set<TemplateSimplifier::TokenAndName*>* templateSimplifierPointers() const { 658 return mImpl->mTemplateSimplifierPointers; 659 } templateSimplifierPointer(TemplateSimplifier::TokenAndName * tokenAndName)660 void templateSimplifierPointer(TemplateSimplifier::TokenAndName* tokenAndName) { 661 if (!mImpl->mTemplateSimplifierPointers) 662 mImpl->mTemplateSimplifierPointers = new std::set<TemplateSimplifier::TokenAndName*>; 663 mImpl->mTemplateSimplifierPointers->insert(tokenAndName); 664 } setBits(const unsigned char b)665 void setBits(const unsigned char b) { 666 mImpl->mBits = b; 667 } 668 isUtf8()669 bool isUtf8() const { 670 return (((mTokType == eString) && isPrefixStringCharLiteral(mStr, '"', "u8")) || 671 ((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', "u8"))); 672 } 673 isUtf16()674 bool isUtf16() const { 675 return (((mTokType == eString) && isPrefixStringCharLiteral(mStr, '"', "u")) || 676 ((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', "u"))); 677 } 678 isUtf32()679 bool isUtf32() const { 680 return (((mTokType == eString) && isPrefixStringCharLiteral(mStr, '"', "U")) || 681 ((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', "U"))); 682 } 683 isCChar()684 bool isCChar() const { 685 return (((mTokType == eString) && isPrefixStringCharLiteral(mStr, '"', "")) || 686 ((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', "") && mStr.length() == 3)); 687 } 688 isCMultiChar()689 bool isCMultiChar() const { 690 return (((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', "")) && 691 (mStr.length() > 3)); 692 } 693 /** 694 * @brief Is current token a template argument? 695 * 696 * Original code: 697 * 698 * template<class C> struct S { 699 * C x; 700 * }; 701 * S<int> s; 702 * 703 * Resulting code: 704 * 705 * struct S<int> { 706 * int x ; // <- "int" is a template argument 707 * } 708 * S<int> s; 709 */ isTemplateArg()710 bool isTemplateArg() const { 711 return getFlag(fIsTemplateArg); 712 } isTemplateArg(const bool value)713 void isTemplateArg(const bool value) { 714 setFlag(fIsTemplateArg, value); 715 } 716 717 template<size_t count> findsimplematch(const Token * const startTok,const char (& pattern)[count])718 static const Token *findsimplematch(const Token * const startTok, const char (&pattern)[count]) { 719 return findsimplematch(startTok, pattern, count-1); 720 } 721 static const Token *findsimplematch(const Token * const startTok, const char pattern[], size_t pattern_len); 722 723 template<size_t count> findsimplematch(const Token * const startTok,const char (& pattern)[count],const Token * const end)724 static const Token *findsimplematch(const Token * const startTok, const char (&pattern)[count], const Token * const end) { 725 return findsimplematch(startTok, pattern, count-1, end); 726 } 727 static const Token *findsimplematch(const Token * const startTok, const char pattern[], size_t pattern_len, const Token * const end); 728 729 static const Token *findmatch(const Token * const startTok, const char pattern[], const nonneg int varId = 0); 730 static const Token *findmatch(const Token * const startTok, const char pattern[], const Token * const end, const nonneg int varId = 0); 731 732 template<size_t count> findsimplematch(Token * const startTok,const char (& pattern)[count])733 static Token *findsimplematch(Token * const startTok, const char (&pattern)[count]) { 734 return findsimplematch(startTok, pattern, count-1); 735 } findsimplematch(Token * const startTok,const char pattern[],size_t pattern_len)736 static Token *findsimplematch(Token * const startTok, const char pattern[], size_t pattern_len) { 737 return const_cast<Token *>(findsimplematch(const_cast<const Token *>(startTok), pattern, pattern_len)); 738 } 739 template<size_t count> findsimplematch(Token * const startTok,const char (& pattern)[count],const Token * const end)740 static Token *findsimplematch(Token * const startTok, const char (&pattern)[count], const Token * const end) { 741 return findsimplematch(startTok, pattern, count-1, end); 742 } findsimplematch(Token * const startTok,const char pattern[],size_t pattern_len,const Token * const end)743 static Token *findsimplematch(Token * const startTok, const char pattern[], size_t pattern_len, const Token * const end) { 744 return const_cast<Token *>(findsimplematch(const_cast<const Token *>(startTok), pattern, pattern_len, end)); 745 } 746 747 static Token *findmatch(Token * const startTok, const char pattern[], const nonneg int varId = 0) { 748 return const_cast<Token *>(findmatch(const_cast<const Token *>(startTok), pattern, varId)); 749 } 750 static Token *findmatch(Token * const startTok, const char pattern[], const Token * const end, const nonneg int varId = 0) { 751 return const_cast<Token *>(findmatch(const_cast<const Token *>(startTok), pattern, end, varId)); 752 } 753 754 /** 755 * Needle is build from multiple alternatives. If one of 756 * them is equal to haystack, return value is 1. If there 757 * are no matches, but one alternative to needle is empty 758 * string, return value is 0. If needle was not found, return 759 * value is -1. 760 * 761 * @param tok Current token (needle) 762 * @param haystack e.g. "one|two" or "|one|two" 763 * @param varid optional varid of token 764 * @return 1 if needle is found from the haystack 765 * 0 if needle was empty string 766 * -1 if needle was not found 767 */ 768 static int multiCompare(const Token *tok, const char *haystack, nonneg int varid); 769 fileIndex()770 nonneg int fileIndex() const { 771 return mImpl->mFileIndex; 772 } fileIndex(nonneg int indexOfFile)773 void fileIndex(nonneg int indexOfFile) { 774 mImpl->mFileIndex = indexOfFile; 775 } 776 linenr()777 nonneg int linenr() const { 778 return mImpl->mLineNumber; 779 } linenr(nonneg int lineNumber)780 void linenr(nonneg int lineNumber) { 781 mImpl->mLineNumber = lineNumber; 782 } 783 column()784 nonneg int column() const { 785 return mImpl->mColumn; 786 } column(nonneg int c)787 void column(nonneg int c) { 788 mImpl->mColumn = c; 789 } 790 next()791 Token *next() const { 792 return mNext; 793 } 794 795 796 /** 797 * Delete tokens between begin and end. E.g. if begin = 1 798 * and end = 5, tokens 2,3 and 4 would be erased. 799 * 800 * @param begin Tokens after this will be erased. 801 * @param end Tokens before this will be erased. 802 */ 803 static void eraseTokens(Token *begin, const Token *end); 804 805 /** 806 * Insert new token after this token. This function will handle 807 * relations between next and previous token also. 808 * @param tokenStr String for the new token. 809 * @param originalNameStr String used for Token::originalName(). 810 * @param prepend Insert the new token before this token when it's not 811 * the first one on the tokens list. 812 */ 813 void insertToken(const std::string &tokenStr, const std::string &originalNameStr=emptyString, bool prepend=false); 814 previous()815 Token *previous() const { 816 return mPrevious; 817 } 818 819 varId()820 nonneg int varId() const { 821 return mImpl->mVarId; 822 } varId(nonneg int id)823 void varId(nonneg int id) { 824 mImpl->mVarId = id; 825 if (id != 0) { 826 tokType(eVariable); 827 isStandardType(false); 828 } else { 829 update_property_info(); 830 } 831 } 832 exprId()833 nonneg int exprId() const { 834 if (mImpl->mExprId) 835 return mImpl->mExprId; 836 return mImpl->mVarId; 837 } exprId(nonneg int id)838 void exprId(nonneg int id) { 839 mImpl->mExprId = id; 840 } 841 842 /** 843 * For debugging purposes, prints token and all tokens 844 * followed by it. 845 * @param title Title for the printout or use default parameter or 0 846 * for no title. 847 */ 848 void printOut(const char *title = nullptr) const; 849 850 /** 851 * For debugging purposes, prints token and all tokens 852 * followed by it. 853 * @param title Title for the printout or use default parameter or 0 854 * for no title. 855 * @param fileNames Prints out file name instead of file index. 856 * File index should match the index of the string in this vector. 857 */ 858 void printOut(const char *title, const std::vector<std::string> &fileNames) const; 859 860 /** 861 * print out tokens 862 */ 863 void printLines(int lines=5) const; 864 865 /** 866 * Replace token replaceThis with tokens between start and end, 867 * including start and end. The replaceThis token is deleted. 868 * @param replaceThis This token will be deleted. 869 * @param start This will be in the place of replaceThis 870 * @param end This is also in the place of replaceThis 871 */ 872 static void replace(Token *replaceThis, Token *start, Token *end); 873 874 struct stringifyOptions { 875 bool varid = false; 876 bool exprid = false; 877 bool idtype = false; // distinguish varid / exprid 878 bool attributes = false; 879 bool macro = false; 880 bool linenumbers = false; 881 bool linebreaks = false; 882 bool files = false; forDebugstringifyOptions883 static stringifyOptions forDebug() { 884 stringifyOptions options; 885 options.attributes = true; 886 options.macro = true; 887 options.linenumbers = true; 888 options.linebreaks = true; 889 options.files = true; 890 return options; 891 } forDebugVarIdstringifyOptions892 static stringifyOptions forDebugVarId() { 893 stringifyOptions options = forDebug(); 894 options.varid = true; 895 return options; 896 } forDebugExprIdstringifyOptions897 static stringifyOptions forDebugExprId() { 898 stringifyOptions options = forDebug(); 899 options.exprid = true; 900 return options; 901 } forPrintOutstringifyOptions902 static stringifyOptions forPrintOut() { 903 stringifyOptions options = forDebug(); 904 options.exprid = true; 905 options.varid = true; 906 options.idtype = true; 907 return options; 908 } 909 }; 910 911 std::string stringify(const stringifyOptions& options) const; 912 913 /** 914 * Stringify a token 915 * @param varid Print varids. (Style: "varname\@id") 916 * @param attributes Print attributes of tokens like "unsigned" in front of it. 917 * @param macro Prints $ in front of the token if it was expanded from a macro. 918 */ 919 std::string stringify(bool varid, bool attributes, bool macro) const; 920 921 std::string stringifyList(const stringifyOptions& options, const std::vector<std::string>* fileNames = nullptr, const Token* end = nullptr) const; 922 std::string stringifyList(const Token* end, bool attributes = true) const; 923 std::string stringifyList(bool varid = false) const; 924 925 /** 926 * Stringify a list of token, from current instance on. 927 * @param varid Print varids. (Style: "varname\@id") 928 * @param attributes Print attributes of tokens like "unsigned" in front of it. 929 * @param linenumbers Print line number in front of each line 930 * @param linebreaks Insert "\\n" into string when line number changes 931 * @param files print Files as numbers or as names (if fileNames is given) 932 * @param fileNames Vector of filenames. Used (if given) to print filenames as strings instead of numbers. 933 * @param end Stringification ends before this token is reached. 0 to stringify until end of list. 934 * @return Stringified token list as a string 935 */ 936 std::string stringifyList(bool varid, bool attributes, bool linenumbers, bool linebreaks, bool files, const std::vector<std::string>* fileNames = nullptr, const Token* end = nullptr) const; 937 938 /** 939 * Remove the contents for this token from the token list. 940 * 941 * The contents are replaced with the contents of the next token and 942 * the next token is unlinked and deleted from the token list. 943 * 944 * So this token will still be valid after the 'deleteThis()'. 945 */ 946 void deleteThis(); 947 948 /** 949 * Create link to given token 950 * @param linkToToken The token where this token should link 951 * to. 952 */ link(Token * linkToToken)953 void link(Token *linkToToken) { 954 mLink = linkToToken; 955 if (mStr == "<" || mStr == ">") 956 update_property_info(); 957 } 958 959 /** 960 * Return token where this token links to. 961 * Supported links are: 962 * "{" <-> "}" 963 * "(" <-> ")" 964 * "[" <-> "]" 965 * 966 * @return The token where this token links to. 967 */ link()968 Token *link() const { 969 return mLink; 970 } 971 972 /** 973 * Associate this token with given scope 974 * @param s Scope to be associated 975 */ scope(const Scope * s)976 void scope(const Scope *s) { 977 mImpl->mScope = s; 978 } 979 980 /** 981 * @return a pointer to the scope containing this token. 982 */ scope()983 const Scope *scope() const { 984 return mImpl->mScope; 985 } 986 987 /** 988 * Associate this token with given function 989 * @param f Function to be associated 990 */ 991 void function(const Function *f); 992 993 /** 994 * @return a pointer to the Function associated with this token. 995 */ function()996 const Function *function() const { 997 return mTokType == eFunction || mTokType == eLambda ? mImpl->mFunction : nullptr; 998 } 999 1000 /** 1001 * Associate this token with given variable 1002 * @param v Variable to be associated 1003 */ variable(const Variable * v)1004 void variable(const Variable *v) { 1005 mImpl->mVariable = v; 1006 if (v || mImpl->mVarId) 1007 tokType(eVariable); 1008 else if (mTokType == eVariable) 1009 tokType(eName); 1010 } 1011 1012 /** 1013 * @return a pointer to the variable associated with this token. 1014 */ variable()1015 const Variable *variable() const { 1016 return mTokType == eVariable ? mImpl->mVariable : nullptr; 1017 } 1018 1019 /** 1020 * Associate this token with given type 1021 * @param t Type to be associated 1022 */ 1023 void type(const ::Type *t); 1024 1025 /** 1026 * @return a pointer to the type associated with this token. 1027 */ type()1028 const ::Type *type() const { 1029 return mTokType == eType ? mImpl->mType : nullptr; 1030 } 1031 1032 static const ::Type* typeOf(const Token* tok, const Token** typeTok = nullptr); 1033 1034 static std::pair<const Token*, const Token*> typeDecl(const Token * tok); 1035 1036 static std::string typeStr(const Token* tok); 1037 1038 /** 1039 * @return a pointer to the Enumerator associated with this token. 1040 */ enumerator()1041 const Enumerator *enumerator() const { 1042 return mTokType == eEnumerator ? mImpl->mEnumerator : nullptr; 1043 } 1044 1045 /** 1046 * Associate this token with given enumerator 1047 * @param e Enumerator to be associated 1048 */ enumerator(const Enumerator * e)1049 void enumerator(const Enumerator *e) { 1050 mImpl->mEnumerator = e; 1051 if (e) 1052 tokType(eEnumerator); 1053 else if (mTokType == eEnumerator) 1054 tokType(eName); 1055 } 1056 1057 /** 1058 * Links two elements against each other. 1059 **/ 1060 static void createMutualLinks(Token *begin, Token *end); 1061 1062 /** 1063 * This can be called only for tokens that are strings, else 1064 * the assert() is called. If Token is e.g. '"hello"', this will return 1065 * 'hello' (removing the double quotes). 1066 * @return String value 1067 */ 1068 std::string strValue() const; 1069 1070 /** 1071 * Move srcStart and srcEnd tokens and all tokens between them 1072 * into new a location. Only links between tokens are changed. 1073 * @param srcStart This is the first token to be moved 1074 * @param srcEnd The last token to be moved 1075 * @param newLocation srcStart will be placed after this token. 1076 */ 1077 static void move(Token *srcStart, Token *srcEnd, Token *newLocation); 1078 1079 /** Get progressValue (0 - 100) */ progressValue()1080 nonneg int progressValue() const { 1081 return mImpl->mProgressValue; 1082 } 1083 1084 /** Calculate progress values for all tokens */ 1085 static void assignProgressValues(Token *tok); 1086 1087 /** 1088 * @return the first token of the next argument. Does only work on argument 1089 * lists. Requires that Tokenizer::createLinks2() has been called before. 1090 * Returns 0, if there is no next argument. 1091 */ 1092 Token* nextArgument() const; 1093 1094 /** 1095 * @return the first token of the next argument. Does only work on argument 1096 * lists. Should be used only before Tokenizer::createLinks2() was called. 1097 * Returns 0, if there is no next argument. 1098 */ 1099 Token* nextArgumentBeforeCreateLinks2() const; 1100 1101 /** 1102 * @return the first token of the next template argument. Does only work on template argument 1103 * lists. Requires that Tokenizer::createLinks2() has been called before. 1104 * Returns 0, if there is no next argument. 1105 */ 1106 Token* nextTemplateArgument() const; 1107 1108 /** 1109 * Returns the closing bracket of opening '<'. Should only be used if link() 1110 * is unavailable. 1111 * @return closing '>', ')', ']' or '}'. if no closing bracket is found, NULL is returned 1112 */ 1113 const Token* findClosingBracket() const; 1114 Token* findClosingBracket(); 1115 1116 const Token* findOpeningBracket() const; 1117 Token* findOpeningBracket(); 1118 1119 /** 1120 * @return the original name. 1121 */ originalName()1122 const std::string & originalName() const { 1123 return mImpl->mOriginalName ? *mImpl->mOriginalName : emptyString; 1124 } 1125 values()1126 const std::list<ValueFlow::Value>& values() const { 1127 return mImpl->mValues ? *mImpl->mValues : TokenImpl::mEmptyValueList; 1128 } 1129 1130 /** 1131 * Sets the original name. 1132 */ 1133 template<typename T> originalName(T && name)1134 void originalName(T&& name) { 1135 if (!mImpl->mOriginalName) 1136 mImpl->mOriginalName = new std::string(name); 1137 else 1138 *mImpl->mOriginalName = name; 1139 } 1140 1141 bool hasKnownIntValue() const; 1142 bool hasKnownValue() const; 1143 bool hasKnownValue(ValueFlow::Value::ValueType t) const; 1144 bool hasKnownSymbolicValue(const Token* tok) const; 1145 1146 const ValueFlow::Value* getKnownValue(ValueFlow::Value::ValueType t) const; getKnownIntValue()1147 MathLib::bigint getKnownIntValue() const { 1148 return mImpl->mValues->front().intvalue; 1149 } 1150 1151 bool isImpossibleIntValue(const MathLib::bigint val) const; 1152 1153 const ValueFlow::Value* getValue(const MathLib::bigint val) const; 1154 1155 const ValueFlow::Value* getMaxValue(bool condition, MathLib::bigint path = 0) const; 1156 1157 const ValueFlow::Value* getMovedValue() const; 1158 1159 const ValueFlow::Value * getValueLE(const MathLib::bigint val, const Settings *settings) const; 1160 const ValueFlow::Value * getValueGE(const MathLib::bigint val, const Settings *settings) const; 1161 1162 const ValueFlow::Value * getInvalidValue(const Token *ftok, nonneg int argnr, const Settings *settings) const; 1163 1164 const ValueFlow::Value* getContainerSizeValue(const MathLib::bigint val) const; 1165 1166 const Token *getValueTokenMaxStrLength() const; 1167 const Token *getValueTokenMinStrSize(const Settings *settings) const; 1168 1169 const Token *getValueTokenDeadPointer() const; 1170 1171 /** Add token value. Return true if value is added. */ 1172 bool addValue(const ValueFlow::Value &value); 1173 removeValues(std::function<bool (const ValueFlow::Value &)> pred)1174 void removeValues(std::function<bool(const ValueFlow::Value &)> pred) { 1175 if (mImpl->mValues) 1176 mImpl->mValues->remove_if(pred); 1177 } 1178 index()1179 nonneg int index() const { 1180 return mImpl->mIndex; 1181 } 1182 1183 void assignIndexes(); 1184 1185 private: 1186 next(Token * nextToken)1187 void next(Token *nextToken) { 1188 mNext = nextToken; 1189 } previous(Token * previousToken)1190 void previous(Token *previousToken) { 1191 mPrevious = previousToken; 1192 } 1193 1194 /** used by deleteThis() to take data from token to delete */ 1195 void takeData(Token *fromToken); 1196 1197 /** 1198 * Works almost like strcmp() except returns only true or false and 1199 * if str has empty space ' ' character, that character is handled 1200 * as if it were '\\0' 1201 */ 1202 static bool firstWordEquals(const char *str, const char *word); 1203 1204 /** 1205 * Works almost like strchr() except 1206 * if str has empty space ' ' character, that character is handled 1207 * as if it were '\\0' 1208 */ 1209 static const char *chrInFirstWord(const char *str, char c); 1210 1211 std::string mStr; 1212 1213 Token *mNext; 1214 Token *mPrevious; 1215 Token *mLink; 1216 1217 enum : uint64_t { 1218 fIsUnsigned = (1 << 0), 1219 fIsSigned = (1 << 1), 1220 fIsPointerCompare = (1 << 2), 1221 fIsLong = (1 << 3), 1222 fIsStandardType = (1 << 4), 1223 fIsExpandedMacro = (1 << 5), 1224 fIsCast = (1 << 6), 1225 fIsAttributeConstructor = (1 << 7), // __attribute__((constructor)) __attribute__((constructor(priority))) 1226 fIsAttributeDestructor = (1 << 8), // __attribute__((destructor)) __attribute__((destructor(priority))) 1227 fIsAttributeUnused = (1 << 9), // __attribute__((unused)) 1228 fIsAttributePure = (1 << 10), // __attribute__((pure)) 1229 fIsAttributeConst = (1 << 11), // __attribute__((const)) 1230 fIsAttributeNoreturn = (1 << 12), // __attribute__((noreturn)), __declspec(noreturn) 1231 fIsAttributeNothrow = (1 << 13), // __attribute__((nothrow)), __declspec(nothrow) 1232 fIsAttributeUsed = (1 << 14), // __attribute__((used)) 1233 fIsAttributePacked = (1 << 15), // __attribute__((packed)) 1234 fIsAttributeMaybeUnused = (1 << 16), // [[maybe_unsed]] 1235 fIsControlFlowKeyword = (1 << 17), // if/switch/while/... 1236 fIsOperatorKeyword = (1 << 18), // operator=, etc 1237 fIsComplex = (1 << 19), // complex/_Complex type 1238 fIsEnumType = (1 << 20), // enumeration type 1239 fIsName = (1 << 21), 1240 fIsLiteral = (1 << 22), 1241 fIsTemplateArg = (1 << 23), 1242 fIsAttributeNodiscard = (1 << 24), // __attribute__ ((warn_unused_result)), [[nodiscard]] 1243 fAtAddress = (1 << 25), // @ 0x4000 1244 fIncompleteVar = (1 << 26), 1245 fConstexpr = (1 << 27), 1246 fExternC = (1 << 28), 1247 fIsSplitVarDeclComma = (1 << 29), // set to true when variable declarations are split up ('int a,b;' => 'int a; int b;') 1248 fIsSplitVarDeclEq = (1 << 30), // set to true when variable declaration with initialization is split up ('int a=5;' => 'int a; a=5;') 1249 fIsImplicitInt = (1U << 31), // Is "int" token implicitly added? 1250 fIsInline = (1ULL << 32), // Is this a inline type 1251 fIsTemplate = (1ULL << 33) 1252 }; 1253 1254 Token::Type mTokType; 1255 1256 uint64_t mFlags; 1257 1258 TokenImpl *mImpl; 1259 1260 /** 1261 * Get specified flag state. 1262 * @param flag_ flag to get state of 1263 * @return true if flag set or false in flag not set 1264 */ getFlag(uint64_t flag_)1265 bool getFlag(uint64_t flag_) const { 1266 return ((mFlags & flag_) != 0); 1267 } 1268 1269 /** 1270 * Set specified flag state. 1271 * @param flag_ flag to set state 1272 * @param state_ new state of flag 1273 */ setFlag(uint64_t flag_,bool state_)1274 void setFlag(uint64_t flag_, bool state_) { 1275 mFlags = state_ ? mFlags | flag_ : mFlags & ~flag_; 1276 } 1277 1278 /** Updates internal property cache like _isName or _isBoolean. 1279 Called after any mStr() modification. */ 1280 void update_property_info(); 1281 1282 /** Update internal property cache about isStandardType() */ 1283 void update_property_isStandardType(); 1284 1285 /** Update internal property cache about string and char literals */ 1286 void update_property_char_string_literal(); 1287 1288 /** Internal helper function to avoid excessive string allocations */ 1289 void astStringVerboseRecursive(std::string& ret, const nonneg int indent1 = 0, const nonneg int indent2 = 0) const; 1290 1291 public: 1292 void astOperand1(Token *tok); 1293 void astOperand2(Token *tok); 1294 void astParent(Token* tok); 1295 astOperand1()1296 Token * astOperand1() { 1297 return mImpl->mAstOperand1; 1298 } astOperand1()1299 const Token * astOperand1() const { 1300 return mImpl->mAstOperand1; 1301 } astOperand2()1302 Token * astOperand2() { 1303 return mImpl->mAstOperand2; 1304 } astOperand2()1305 const Token * astOperand2() const { 1306 return mImpl->mAstOperand2; 1307 } astParent()1308 Token * astParent() { 1309 return mImpl->mAstParent; 1310 } astParent()1311 const Token * astParent() const { 1312 return mImpl->mAstParent; 1313 } astSibling()1314 Token * astSibling() { 1315 if (!astParent()) 1316 return nullptr; 1317 if (this == astParent()->astOperand1()) 1318 return astParent()->astOperand2(); 1319 else if (this == astParent()->astOperand2()) 1320 return astParent()->astOperand1(); 1321 return nullptr; 1322 1323 } astSibling()1324 const Token * astSibling() const { 1325 if (!astParent()) 1326 return nullptr; 1327 if (this == astParent()->astOperand1()) 1328 return astParent()->astOperand2(); 1329 else if (this == astParent()->astOperand2()) 1330 return astParent()->astOperand1(); 1331 return nullptr; 1332 1333 } astTop()1334 Token *astTop() { 1335 Token *ret = this; 1336 while (ret->mImpl->mAstParent) 1337 ret = ret->mImpl->mAstParent; 1338 return ret; 1339 } 1340 astTop()1341 const Token *astTop() const { 1342 const Token *ret = this; 1343 while (ret->mImpl->mAstParent) 1344 ret = ret->mImpl->mAstParent; 1345 return ret; 1346 } 1347 1348 std::pair<const Token *, const Token *> findExpressionStartEndTokens() const; 1349 1350 /** 1351 * Is current token a calculation? Only true for operands. 1352 * For '*' and '&' tokens it is looked up if this is a 1353 * dereference or address-of. A dereference or address-of is not 1354 * counted as a calculation. 1355 * @return returns true if current token is a calculation 1356 */ 1357 bool isCalculation() const; 1358 clearAst()1359 void clearAst() { 1360 mImpl->mAstOperand1 = mImpl->mAstOperand2 = mImpl->mAstParent = nullptr; 1361 } 1362 clearValueFlow()1363 void clearValueFlow() { 1364 delete mImpl->mValues; 1365 mImpl->mValues = nullptr; 1366 } 1367 1368 std::string astString(const char *sep = "") const { 1369 std::string ret; 1370 if (mImpl->mAstOperand1) 1371 ret = mImpl->mAstOperand1->astString(sep); 1372 if (mImpl->mAstOperand2) 1373 ret += mImpl->mAstOperand2->astString(sep); 1374 return ret + sep + mStr; 1375 } 1376 1377 std::string astStringVerbose() const; 1378 1379 std::string astStringZ3() const; 1380 1381 std::string expressionString() const; 1382 1383 void printAst(bool verbose, bool xml, const std::vector<std::string> &fileNames, std::ostream &out) const; 1384 1385 void printValueFlow(bool xml, std::ostream &out) const; 1386 1387 void scopeInfo(std::shared_ptr<ScopeInfo2> newScopeInfo); 1388 std::shared_ptr<ScopeInfo2> scopeInfo() const; 1389 setCpp11init(bool cpp11init)1390 void setCpp11init(bool cpp11init) const { 1391 mImpl->mCpp11init=cpp11init ? TokenImpl::Cpp11init::CPP11INIT : TokenImpl::Cpp11init::NOINIT; 1392 } isCpp11init()1393 TokenImpl::Cpp11init isCpp11init() const { 1394 return mImpl->mCpp11init; 1395 } 1396 }; 1397 1398 Token* findTypeEnd(Token* tok); 1399 const Token* findTypeEnd(const Token* tok); 1400 Token* findLambdaEndScope(Token* tok); 1401 const Token* findLambdaEndScope(const Token* tok); 1402 1403 /// @} 1404 //--------------------------------------------------------------------------- 1405 #endif // tokenH 1406