[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/cppcheck-opensource/cppcheck/main/test/testtoken.cpp [Back]  [Original]

/*
 * Cppcheck - A tool for static C/C++ code analysis
 * Copyright (C) 2007-2026 Cppcheck team.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */

#include "fixture.h"
#include "helpers.h"
#include "settings.h"
#include "standards.h"
#include "token.h"
#include "tokenlist.h"
#include "vfvalue.h"

#include 
#include 
#include 
#include 
#include 


class TestToken : public TestFixture {
public:
    TestToken() : TestFixture("TestToken") {}

private:
    class TokenTest final : public Token
    {
        friend class TestToken;
    };

    const TokenList list{settingsDefault, Standards::Language::C};

    std::vector arithmeticalOps;
    std::vector logicalOps;
    std::vector bitOps;
    std::vector comparisonOps;
    std::vector extendedOps;
    std::vector assignmentOps;

    void run() override {
        arithmeticalOps = { "+", "-", "*", "/", "%", "" };
        logicalOps = { "&&", "||", "!" };
        comparisonOps = { "==", "!=", "=" };
        bitOps = { "&", "|", "^", "~" };
        extendedOps = { ",", "[", "]", "(", ")", "?", ":" };
        assignmentOps = { "=", "+=", "-=", "*=", "/=", "%=", "&=", "^=", "|=", "=" };

        TEST_CASE(nextprevious);
        TEST_CASE(multiCompare);
        TEST_CASE(multiCompare2);                   // #3294 - false negative multi compare between "=" and "=="
        TEST_CASE(multiCompare3);                   // false positive for %or% on code using "|="
        TEST_CASE(multiCompare4);
        TEST_CASE(multiCompare5);
        TEST_CASE(multiCompare6);
        TEST_CASE(charTypes);
        TEST_CASE(stringTypes);
        TEST_CASE(getStrLength);
        TEST_CASE(getStrSize);
        TEST_CASE(strValue);
        TEST_CASE(concatStr);

        TEST_CASE(deleteLast);
        TEST_CASE(deleteFirst);
        TEST_CASE(nextArgument);
        TEST_CASE(eraseTokens);

        TEST_CASE(matchAny);
        TEST_CASE(matchSingleChar);
        TEST_CASE(matchNothingOrAnyNotElse);
        TEST_CASE(matchType);
        TEST_CASE(matchChar);
        TEST_CASE(matchCompOp);
        TEST_CASE(matchStr);
        TEST_CASE(matchVarid);
        TEST_CASE(matchNumeric);
        TEST_CASE(matchBoolean);
        TEST_CASE(matchOr);
        TEST_CASE(matchOp);
        TEST_CASE(matchConstOp);

        TEST_CASE(isArithmeticalOp);
        TEST_CASE(isOp);
        TEST_CASE(isConstOp);
        TEST_CASE(isExtendedOp);
        TEST_CASE(isAssignmentOp);
        TEST_CASE(isStandardType);
        TEST_CASE(literals);
        TEST_CASE(operators);

        TEST_CASE(updateProperties);
        TEST_CASE(isNameGuarantees1);
        TEST_CASE(isNameGuarantees2);
        TEST_CASE(isNameGuarantees3);
        TEST_CASE(isNameGuarantees4);
        TEST_CASE(isNameGuarantees5);
        TEST_CASE(isNameGuarantees6);

        TEST_CASE(canFindMatchingBracketsNeedsOpen);
        TEST_CASE(canFindMatchingBracketsInnerPair);
        TEST_CASE(canFindMatchingBracketsOuterPair);
        TEST_CASE(canFindMatchingBracketsWithTooManyClosing);
        TEST_CASE(canFindMatchingBracketsWithTooManyOpening);
        TEST_CASE(findClosingBracket);
        TEST_CASE(findClosingBracket2);
        TEST_CASE(findClosingBracket3);
        TEST_CASE(findClosingBracket4);

        TEST_CASE(expressionString);

        TEST_CASE(hasKnownIntValue);

        TEST_CASE(update_property_info);
        TEST_CASE(update_property_info_evariable);
        TEST_CASE(update_property_info_ekeyword_c);
        TEST_CASE(update_property_info_ekeyword_cpp);
        TEST_CASE(update_property_info_ebracket_link);
        TEST_CASE(update_property_info_ecomparisonop_link);
        TEST_CASE(update_property_info_etype_c);
        TEST_CASE(update_property_info_etype_cpp);
        TEST_CASE(update_property_info_replace); // #13743

        TEST_CASE(varid_reset);
    }

    void nextprevious() const {
        auto tokensFrontBack = std::make_shared();
        auto *token = new Token(list, std::move(tokensFrontBack));
        token->str("1");
        (void)token->insertToken("2");
        (void)token->next()->insertToken("3");
        Token *last = token->tokAt(2);
        ASSERT_EQUALS(token->str(), "1");
        ASSERT_EQUALS(token->strAt(1), "2");
        ASSERT_EQUALS(token->tokAt(2)->str(), "3");
        ASSERT_EQUALS_MSG(true, last->next() == nullptr, "Null was expected");

        ASSERT_EQUALS(last->str(), "3");
        ASSERT_EQUALS(last->strAt(-1), "2");
        ASSERT_EQUALS(last->tokAt(-2)->str(), "1");
        ASSERT_EQUALS_MSG(true, token->previous() == nullptr, "Null was expected");

        TokenList::deleteTokens(token);
    }

#define MatchCheck(...) MatchCheck_(__FILE__, __LINE__, __VA_ARGS__)
    bool MatchCheck_(const char* file, int line, const std::string& code, const std::string& pattern) {
        SimpleTokenizer tokenizer(settingsDefault, *this);
        const std::string code2 = ";" + code + ";";
        try {
            ASSERT_LOC(tokenizer.tokenize(code2), file, line);
        } catch (...) {}
        return Token::Match(tokenizer.tokens()->next(), pattern.c_str());
    }

    void multiCompare() const {
        // Test for found
        {
            auto tokensFrontBack = std::make_shared();
            Token one(list, std::move(tokensFrontBack));
            one.str("one");
            ASSERT_EQUALS(1, TokenTest::multiCompare(&one, "one|two", 0));
        }

        {
            auto tokensFrontBack = std::make_shared();
            Token two(list, std::move(tokensFrontBack));
            two.str("two");
            ASSERT_EQUALS(1, TokenTest::multiCompare(&two, "one|two", 0));
            ASSERT_EQUALS(1, TokenTest::multiCompare(&two, "verybig|two|", 0));
        }

        // Test for empty string found
        {
            auto tokensFrontBack = std::make_shared();
            Token notfound(list, std::move(tokensFrontBack));
            notfound.str("notfound");
            ASSERT_EQUALS(0, TokenTest::multiCompare(¬found, "one|two|", 0));

            // Test for not found
            ASSERT_EQUALS(-1, TokenTest::multiCompare(¬found, "one|two", 0));
        }

        {
            auto tokensFrontBack = std::make_shared();
            Token s(list, std::move(tokensFrontBack));
            s.str("s");
            ASSERT_EQUALS(-1, TokenTest::multiCompare(&s, "verybig|two", 0));
        }

        {
            auto tokensFrontBack = std::make_shared();
            Token ne(list, std::move(tokensFrontBack));
            ne.str("ne");
            ASSERT_EQUALS(-1, TokenTest::multiCompare(&ne, "one|two", 0));
        }

        {
            auto tokensFrontBack = std::make_shared();
            Token a(list, std::move(tokensFrontBack));
            a.str("a");
            ASSERT_EQUALS(-1, TokenTest::multiCompare(&a, "abc|def", 0));
        }

        {
            auto tokensFrontBack = std::make_shared();
            Token abcd(list, std::move(tokensFrontBack));
            abcd.str("abcd");
            ASSERT_EQUALS(-1, TokenTest::multiCompare(&abcd, "abc|def", 0));
        }

        {
            auto tokensFrontBack = std::make_shared();
            Token def(list, std::move(tokensFrontBack));
            def.str("default");
            ASSERT_EQUALS(-1, TokenTest::multiCompare(&def, "abc|def", 0));
        }

        // %op%
        {
            auto tokensFrontBack = std::make_shared();
            Token plus(list, std::move(tokensFrontBack));
            plus.str("+");
            ASSERT_EQUALS(1, TokenTest::multiCompare(&plus, "one|%op%", 0));
            ASSERT_EQUALS(1, TokenTest::multiCompare(&plus, "%op%|two", 0));
        }
        {
            auto tokensFrontBack = std::make_shared();
            Token x(list, std::move(tokensFrontBack));
            x.str("x");
            ASSERT_EQUALS(-1, TokenTest::multiCompare(&x, "one|%op%", 0));
            ASSERT_EQUALS(-1, TokenTest::multiCompare(&x, "%op%|two", 0));
        }

    }

    void multiCompare2() const { // #3294
        // Original pattern that failed: [[,(=+-*|&^] %num% [+-*/] %num% ]|,|)|;|=|%op%
        const SimpleTokenList toks("a == 1");
        ASSERT_EQUALS(true, Token::Match(toks.front(), "a =|%op%"));
    }

    void multiCompare3() const {
        // Original pattern that failed: "return|(|&&|%oror% %name% &&|%oror%|==|!=|=||-|%or% %name% )|&&|%oror%|;"
        // Code snippet that failed: "return lv@86 |= rv@87 ;"

        // Note: Also test "reverse" alternative pattern, two different code paths to handle it
        const SimpleTokenList toks("return a |= b ;");
        ASSERT_EQUALS(false, Token::Match(toks.front(), "return %name% xyz|%or% %name% ;"));
        ASSERT_EQUALS(false, Token::Match(toks.front(), "return %name% %or%|xyz %name% ;"));

        const SimpleTokenList toks2("return a | b ;");
        ASSERT_EQUALS(true, Token::Match(toks2.front(), "return %name% xyz|%or% %name% ;"));
        ASSERT_EQUALS(true, Token::Match(toks2.front(), "return %name% %or%|xyz %name% ;"));

        const SimpleTokenList toks3("return a || b ;");
        ASSERT_EQUALS(false, Token::Match(toks3.front(), "return %name% xyz|%or% %name% ;"));
        ASSERT_EQUALS(false, Token::Match(toks3.front(), "return %name% %or%|xyz %name% ;"));

        ASSERT_EQUALS(true, Token::Match(toks3.front(), "return %name% xyz|%oror% %name% ;"));
        ASSERT_EQUALS(true, Token::Match(toks3.front(), "return %name% %oror%|xyz %name% ;"));

        const SimpleTokenList toks4("a % b ;");
        ASSERT_EQUALS(true, Token::Match(toks4.front(), "%name% >>|||findClosingBracket();
        ASSERT(t == nullptr);
    }

    void canFindMatchingBracketsInnerPair() {
        SimpleTokenizer var(*this);
        ASSERT(var.tokenize("std::deque intsets;"));

        const Token * const t = var.tokens()->tokAt(7)->findClosingBracket();
        ASSERT_EQUALS(">", t->str());
        ASSERT(var.tokens()->tokAt(9) == t);
    }

    void canFindMatchingBracketsOuterPair() {
        SimpleTokenizer var(*this);
        ASSERT(var.tokenize("std::deque intsets;"));

        const Token* const t = var.tokens()->tokAt(3)->findClosingBracket();
        ASSERT_EQUALS(">", t->str());
        ASSERT(var.tokens()->tokAt(10) == t);
    }

    void canFindMatchingBracketsWithTooManyClosing() {
        SimpleTokenizer var(*this);
        ASSERT(var.tokenize("X< 1>2 > x1;"));

        const Token* const t = var.tokens()->next()->findClosingBracket();
        ASSERT_EQUALS(">", t->str());
        ASSERT(var.tokens()->tokAt(3) == t);
    }

    void canFindMatchingBracketsWithTooManyOpening() {
        SimpleTokenizer var(*this);
        ASSERT(var.tokenize("X < (2 < 1) > x1;"));

        const Token* t = var.tokens()->next()->findClosingBracket();
        ASSERT(t != nullptr && t->str() == ">");

        t = var.tokens()->tokAt(4)->findClosingBracket();
        ASSERT(t == nullptr);
    }

    void findClosingBracket() {
        SimpleTokenizer var(*this);
        ASSERT(var.tokenize("template struct S : public Fred {}"));

        const Token* const t = var.tokens()->next()->findClosingBracket();
        ASSERT(Token::simpleMatch(t, "> struct"));
    }

    void findClosingBracket2() {
        SimpleTokenizer var(*this); // #11275
        ASSERT(var.tokenize("const auto g = []() {};\n"));

        const Token* const t = Token::findsimplematch(var.tokens(), ""));
    }

    void findClosingBracket3() {
        SimpleTokenizer var(*this); // #12789
        ASSERT(var.tokenize("template \n"
                            "void f();\n"));
        const Token* const t = Token::findsimplematch(var.tokens(), ""));
    }

    void findClosingBracket4() {
        SimpleTokenizer var(*this); // #12923
        ASSERT(var.tokenize("template\n"
                            "class C;\n"));
        const Token *const t = Token::findsimplematch(var.tokens(), "

Web Proxy Viewer  |  New URL  |  Original Page