Codebase list cppcheck / 4796a9e
Import upstream version 2.8+git20220524.1.1ed280f Debian Janitor 1 year, 11 months ago
31 changed file(s) with 676 addition(s) and 494 deletion(s). Raw diff Collapse all Expand all
00 ---
1 Checks: '*,-abseil-*,-altera-*,-android-*,-cert-*,-cppcoreguidelines-*,-fuchsia-*,-google-*,-hicpp-*,-linuxkernel-*,-llvm-*,-llvmlibc-*,-mpi-*,-objc-*,-openmp-*,-zircon-*,-readability-braces-around-statements,-readability-magic-numbers,-bugprone-macro-parentheses,-readability-isolate-declaration,-readability-function-size,-modernize-use-trailing-return-type,-readability-implicit-bool-conversion,-readability-uppercase-literal-suffix,-modernize-use-auto,-readability-else-after-return,-modernize-use-default-member-init,-readability-named-parameter,-readability-redundant-member-init,-performance-faster-string-find,-modernize-avoid-c-arrays,-modernize-use-equals-default,-readability-container-size-empty,-readability-simplify-boolean-expr,-modernize-use-override,-modernize-pass-by-value,-bugprone-branch-clone,-bugprone-narrowing-conversions,-modernize-raw-string-literal,-readability-convert-member-functions-to-static,-modernize-loop-convert,-misc-unused-using-decls,-modernize-use-emplace,-readability-const-return-type,-performance-unnecessary-value-param,-modernize-return-braced-init-list,-performance-inefficient-string-concatenation,-misc-throw-by-value-catch-by-reference,-readability-avoid-const-params-in-decls,-readability-non-const-parameter,-misc-non-private-member-variables-in-classes,-bugprone-suspicious-string-compare,-clang-analyzer-*,-bugprone-signed-char-misuse,-readability-make-member-function-const,-misc-no-recursion,-readability-use-anyofallof,-performance-no-automatic-move,-bugprone-suspicious-include,-modernize-replace-random-shuffle,-readability-function-cognitive-complexity,-readability-redundant-access-specifiers,-modernize-use-equals-delete,-performance-noexcept-move-constructor,-concurrency-mt-unsafe,-bugprone-easily-swappable-parameters,-readability-suspicious-call-argument'
1 Checks: '*,-abseil-*,-altera-*,-android-*,-cert-*,-cppcoreguidelines-*,-fuchsia-*,-google-*,-hicpp-*,-linuxkernel-*,-llvm-*,-llvmlibc-*,-mpi-*,-objc-*,-openmp-*,-zircon-*,-readability-braces-around-statements,-readability-magic-numbers,-bugprone-macro-parentheses,-readability-isolate-declaration,-readability-function-size,-modernize-use-trailing-return-type,-readability-implicit-bool-conversion,-readability-uppercase-literal-suffix,-modernize-use-auto,-readability-else-after-return,-modernize-use-default-member-init,-readability-named-parameter,-readability-redundant-member-init,-performance-faster-string-find,-modernize-avoid-c-arrays,-modernize-use-equals-default,-readability-container-size-empty,-readability-simplify-boolean-expr,-modernize-use-override,-modernize-pass-by-value,-bugprone-branch-clone,-bugprone-narrowing-conversions,-modernize-raw-string-literal,-readability-convert-member-functions-to-static,-modernize-loop-convert,-misc-unused-using-decls,-modernize-use-emplace,-readability-const-return-type,-performance-unnecessary-value-param,-modernize-return-braced-init-list,-performance-inefficient-string-concatenation,-misc-throw-by-value-catch-by-reference,-readability-avoid-const-params-in-decls,-readability-non-const-parameter,-misc-non-private-member-variables-in-classes,-bugprone-suspicious-string-compare,-clang-analyzer-*,-bugprone-signed-char-misuse,-readability-make-member-function-const,-misc-no-recursion,-readability-use-anyofallof,-performance-no-automatic-move,-bugprone-suspicious-include,-modernize-replace-random-shuffle,-readability-function-cognitive-complexity,-readability-redundant-access-specifiers,-modernize-use-equals-delete,-performance-noexcept-move-constructor,-concurrency-mt-unsafe,-bugprone-easily-swappable-parameters,-readability-suspicious-call-argument,-readability-identifier-length,-readability-container-data-pointer'
22 WarningsAsErrors: '*'
33 CheckOptions:
44 - key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
88
99 strategy:
1010 matrix:
11 image: ["centos:7", "ubuntu:14.04", "ubuntu:16.04", "ubuntu:21.10"]
11 image: ["centos:7", "ubuntu:14.04", "ubuntu:16.04", "ubuntu:22.04"]
1212 fail-fast: false # Prefer quick result
1313
1414 runs-on: ubuntu-20.04
2222 - name: Install missing software on CentOS 7
2323 if: matrix.image == 'centos:7'
2424 run: |
25 yum install -y cmake gcc-c++ make
25 yum install -y cmake gcc-c++ make which python3
2626 yum install -y pcre-devel
2727
2828 - name: Install missing software on ubuntu
2929 if: matrix.image != 'centos:7'
3030 run: |
3131 apt-get update
32 apt-get install -y cmake g++ make python libxml2-utils
32 apt-get install -y cmake g++ make python3 libxml2-utils
3333 apt-get install -y libpcre3-dev
3434
3535 # tests require CMake 3.4
3636 - name: Test CMake build (no tests)
37 if: matrix.image != 'ubuntu:21.10'
37 if: matrix.image != 'ubuntu:22.04'
3838 run: |
3939 mkdir cmake.output
4040 cd cmake.output
4343 cd ..
4444
4545 - name: Test CMake build
46 if: matrix.image == 'ubuntu:21.10'
46 if: matrix.image == 'ubuntu:22.04'
4747 run: |
4848 mkdir cmake.output
4949 cd cmake.output
99 runs-on: ubuntu-20.04
1010
1111 container:
12 image: "ubuntu:21.10"
12 image: "ubuntu:22.04"
1313
1414 env:
1515 ASAN_OPTIONS: detect_stack_use_after_return=1
2626 run: |
2727 apt-get update
2828 apt-get install -y make libpcre3-dev
29 apt-get install -y clang-13
29 apt-get install -y clang-14
3030
3131 - name: Build
3232 run: make -j$(nproc) cppcheck testrunner HAVE_RULES=yes MATCHCOMPILER=yes VERIFY=1
3333 env:
34 CC: clang-13
35 CXX: clang++-13
34 CC: clang-14
35 CXX: clang++-14
3636 CXXFLAGS: "-fsanitize=address -O2 -g3 -DCPPCHK_GLIBCXX_DEBUG"
3737 CPPFLAGS: "-DCHECK_INTERNAL"
3838
99 runs-on: ubuntu-20.04
1010
1111 container:
12 image: "ubuntu:21.10"
12 image: "ubuntu:22.04"
1313
1414 env:
1515 QT_VERSION: 5.15.2
2020 - name: Install missing software
2121 run: |
2222 apt-get update
23 apt-get install -y cmake clang-13 make
23 apt-get install -y cmake clang-14 make
2424 apt-get install -y libpcre3-dev
2525 apt-get install -y libffi7 # work around missing dependency for Qt install step
26 apt-get install -y clang-tidy-13
26 apt-get install -y clang-tidy-14
2727
2828 - name: Cache Qt ${{ env.QT_VERSION }}
2929 id: cache-qt
4747 cmake -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCPPCHK_GLIBCXX_DEBUG=Off ..
4848 cd ..
4949 env:
50 CC: clang-13
51 CXX: clang++-13
50 CC: clang-14
51 CXX: clang++-14
5252
5353 - name: Prepare CMake dependencies
5454 run: |
99 runs-on: ubuntu-20.04
1010
1111 container:
12 image: "ubuntu:21.10"
12 image: "ubuntu:22.04"
1313
1414 env:
1515 UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
2626 run: |
2727 apt-get update
2828 apt-get install -y make libpcre3-dev
29 apt-get install -y clang-13
29 apt-get install -y clang-14
3030
3131 - name: Build
3232 run: make -j$(nproc) cppcheck testrunner HAVE_RULES=yes MATCHCOMPILER=yes VERIFY=1
3333 env:
34 CC: clang-13
35 CXX: clang++-13
34 CC: clang-14
35 CXX: clang++-14
3636 CXXFLAGS: "-fsanitize=undefined -fsanitize=nullability -fno-sanitize=signed-integer-overflow -O2 -g3 -DCPPCHK_GLIBCXX_DEBUG"
3737 CPPFLAGS: "-DCHECK_INTERNAL"
3838
1111 endif
1212 ifeq ($(MATCHCOMPILER),yes)
1313 # Find available Python interpreter
14 ifndef PYTHON_INTERPRETER
14 ifeq ($(PYTHON_INTERPRETER),)
1515 PYTHON_INTERPRETER := $(shell which python3)
1616 endif
17 ifndef PYTHON_INTERPRETER
17 ifeq ($(PYTHON_INTERPRETER),)
1818 PYTHON_INTERPRETER := $(shell which python)
1919 endif
20 ifndef PYTHON_INTERPRETER
20 ifeq ($(PYTHON_INTERPRETER),)
2121 $(error Did not find a Python interpreter)
2222 endif
2323 ifdef VERIFY
9595 CPPCHK_GLIBCXX_DEBUG=
9696 endif
9797 ifndef CXXFLAGS
98 CXXFLAGS=-std=c++0x -O2 -DNDEBUG -Wall -Wno-sign-compare
98 CXXFLAGS=-pedantic -Wall -Wextra -Wcast-qual -Wno-deprecated-declarations -Wfloat-equal -Wmissing-declarations -Wmissing-format-attribute -Wno-long-long -Wpacked -Wredundant-decls -Wundef -Wno-shadow -Wno-missing-field-initializers -Wno-missing-braces -Wno-sign-compare -Wno-multichar $(CPPCHK_GLIBCXX_DEBUG) -g
9999 endif
100100
101101 ifeq (g++, $(findstring g++,$(CXX)))
303303 ./dmake
304304
305305 clean:
306 rm -f build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/*/*.o testrunner dmake cppcheck cppcheck.exe cppcheck.1
306 rm -f build/*.cpp build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/*/*.o testrunner dmake cppcheck cppcheck.exe cppcheck.1
307307
308308 man: man/cppcheck.1
309309
382382 xmllint --noout --relaxng cppcheck-errors.rng /tmp/example.xml
383383
384384 checkCWEEntries: /tmp/errorlist.xml
385 ./tools/listErrorsWithoutCWE.py -F /tmp/errorlist.xml
385 $(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(shell which python3)))
386 $(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(shell which python)))
387 $(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(error Did not find a Python interpreter)))
388 $(PYTHON_INTERPRETER) tools/listErrorsWithoutCWE.py -F /tmp/errorlist.xml
386389 .PHONY: validateRules
387390 validateRules:
388391 xmllint --noout rules/*.xml
34893489 <not-uninit/>
34903490 <not-bool/>
34913491 </arg>
3492 </function>
3493 <!-- https://man7.org/linux/man-pages/man3/lsearch.3.html -->
3494 <!-- void *lfind(const void *key, const void *base, size_t *nmemb, size_t size, int(*compar)(const void *, const void *)); -->
3495 <function name="lfind">
3496 <returnValue type="void *"/>
3497 <noreturn>false</noreturn>
3498 <arg nr="1" direction="in">
3499 <not-uninit/>
3500 <not-null/>
3501 </arg>
3502 <arg nr="2" direction="in">
3503 <not-uninit/>
3504 <not-null/>
3505 </arg>
3506 <arg nr="3" direction="in">
3507 <not-uninit/>
3508 <not-null/>
3509 <minsize type="argvalue" arg="4"/>
3510 </arg>
3511 <arg nr="4" direction="in">
3512 <not-uninit/>
3513 <not-bool/>
3514 <valid>1:</valid>
3515 </arg>
3516 <arg nr="5" direction="in">
3517 <not-uninit/>
3518 <not-null/>
3519 </arg>
3520 </function>
3521 <!-- https://man7.org/linux/man-pages/man3/lsearch.3.html -->
3522 <!-- void *lsearch(const void *key, void *base, size_t *nmemb, size_t size, int(*compar)(const void *, const void *)); -->
3523 <function name="lsearch">
3524 <returnValue type="void *"/>
3525 <noreturn>false</noreturn>
3526 <arg nr="1" direction="in">
3527 <not-uninit/>
3528 <not-null/>
3529 </arg>
3530 <arg nr="2" direction="in">
3531 <not-null/>
3532 </arg>
3533 <arg nr="3" direction="in">
3534 <not-uninit/>
3535 <not-null/>
3536 <minsize type="argvalue" arg="4"/>
3537 </arg>
3538 <arg nr="4" direction="in">
3539 <not-uninit/>
3540 <not-bool/>
3541 <valid>1:</valid>
3542 </arg>
3543 <arg nr="5" direction="in">
3544 <not-uninit/>
3545 <not-null/>
3546 </arg>
3547 </function>
3548 <!-- https://man7.org/linux/man-pages/man3/mbsnrtowcs.3.html -->
3549 <!-- size_t mbsnrtowcs(wchar_t *restrict dest, const char **restrict src, size_t nms, size_t len, mbstate_t *restrict ps) -->
3550 <function name="mbsnrtowcs">
3551 <returnValue type="size_t"/>
3552 <use-retval/>
3553 <noreturn>false</noreturn>
3554 <!-- If dest is NULL, len is ignored, and the conversion proceeds as
3555 above, except that the converted wide characters are not written
3556 out to memory, and that no length limit exists. -->
3557 <arg nr="1" direction="out"/>
3558 <arg nr="2" direction="in">
3559 <not-uninit/>
3560 <not-null/>
3561 <minsize type="argvalue" arg="3"/>
3562 </arg>
3563 <arg nr="3" direction="in">
3564 <not-uninit/>
3565 <not-null/>
3566 <valid>0:</valid>
3567 </arg>
3568 <arg nr="4" direction="in">
3569 <not-uninit/>
3570 <not-bool/>
3571 <valid>0:</valid>
3572 </arg>
3573 <!-- In both of the above cases, if ps is NULL, a static anonymous
3574 state known only to the mbsrtowcs() function is used instead. -->
3575 <arg nr="5" direction="in"/>
34923576 </function>
34933577 <!-- https://pubs.opengroup.org/onlinepubs/9699919799/functions/regcomp.html -->
34943578 <!-- int regcomp(regex_t *restrict preg, const char *restrict pattern, int cflags); -->
73127312 </arg>
73137313 <arg nr="3" direction="in" default="">
73147314 <not-uninit/>
7315 </arg>
7316 </function>
7317 <!-- template< class ForwardIt > std::pair<ForwardIt,ForwardIt> std::minmax_element( ForwardIt first, ForwardIt last ) -->
7318 <!-- template< class ForwardIt > std::pair<ForwardIt,ForwardIt> std::minmax( ForwardIt first, ForwardIt last ) -->
7319 <function name="std::minmax_element,std::minmax">
7320 <use-retval/>
7321 <noreturn>false</noreturn>
7322 <arg nr="1" direction="in">
7323 <not-uninit/>
7324 <iterator container="1" type="first"/>
7325 </arg>
7326 <arg nr="2" direction="in">
7327 <not-uninit/>
7328 <iterator container="1" type="last"/>
73157329 </arg>
73167330 </function>
73177331 <!-- template<class InputIterator> typename iterator_traits<InputIterator>::difference_type std::distance (InputIterator first, InputIterator last); -->
1919 /**
2020 *
2121 * @mainpage Cppcheck
22 * @version 2.8
22 * @version 2.7
2323 *
2424 * @section overview_sec Overview
2525 * Cppcheck is a simple tool for static analysis of C/C++ code.
66 endif()
77 message(STATUS "NPROC=${NPROC}")
88
9 find_program(RUN_CLANG_TIDY NAMES run-clang-tidy run-clang-tidy-13 run-clang-tidy-12 run-clang-tidy-11 run-clang-tidy-10 run-clang-tidy-9 run-clang-tidy-8)
9 find_program(RUN_CLANG_TIDY NAMES run-clang-tidy run-clang-tidy-14 run-clang-tidy-13 run-clang-tidy-12 run-clang-tidy-11 run-clang-tidy-10 run-clang-tidy-9 run-clang-tidy-8)
1010 message(STATUS "RUN_CLANG_TIDY=${RUN_CLANG_TIDY}")
1111 if (RUN_CLANG_TIDY)
1212 # disable all compiler warnings since we are just interested in the tidy ones
5050 add_compile_options(-Wsuggest-attribute=noreturn)
5151 add_compile_options(-Wno-shadow) # whenever a local variable or type declaration shadows another one
5252 elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
53 if (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 14)
54 if (CMAKE_BUILD_TYPE MATCHES "Release" OR CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
55 # work around performance regression - see https://github.com/llvm/llvm-project/issues/53555
56 add_compile_options(-mllvm -inline-deferral)
57 endif()
58
59 # use force DWARF 4 debug format since not all tools might be able to handle DWARF 5 yet - e.g. valgrind on ubuntu 20.04
60 add_compile_options(-gdwarf-4)
61 endif()
5362
5463 add_compile_options_safe(-Wno-documentation-unknown-command)
5564
8594 add_compile_options_safe(-Wno-tautological-type-limit-compare)
8695 add_compile_options_safe(-Wno-unused-member-function)
8796 add_compile_options(-Wno-disabled-macro-expansion)
97 add_compile_options_safe(-Wno-bitwise-instead-of-logical) # TODO: fix these
8898
8999 # warnings we are not interested in
90100 add_compile_options(-Wno-four-char-constants)
00 # Version for libraries CPP
1 SET(VERSION "2.8")
1 SET(VERSION "2.7")
22 STRING(REGEX MATCHALL "[0-9]" VERSION_PARTS "${VERSION}")
33 LIST(GET VERSION_PARTS 0 VERSION_MAJOR)
44 LIST(GET VERSION_PARTS 1 VERSION_MINOR)
724724
725725 const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
726726 for (const Variable* var : symbolDatabase->variableList()) {
727 if (!var || !var->isLocal() || var->isStatic() || var->isReference())
727 if (!var || (!var->isLocal() && !(var->isArgument() && var->scope())) || var->isStatic() || var->isReference())
728728 continue;
729729 if (var->typeEndToken()->isStandardType())
730730 continue;
788788 return deallocated;
789789 };
790790
791 for (const Token *tok2 = variable->nameToken(); tok2 && tok2 != variable->scope()->bodyEnd; tok2 = tok2->next()) {
791 // return { memberTok, rhsTok }
792 auto isMemberAssignment = [](const Token* varTok, int varId) -> std::pair<const Token*, const Token*> {
793 if (varTok->varId() != varId)
794 return {};
795 const Token* top = varTok;
796 while (top->astParent()) {
797 if (top->astParent()->str() == "(")
798 return {};
799 top = top->astParent();
800 }
801 if (!Token::simpleMatch(top, "=") || !precedes(varTok, top))
802 return {};
803 const Token* dot = top->astOperand1();
804 while (dot && dot->str() != ".")
805 dot = dot->astOperand1();
806 if (!dot)
807 return {};
808 return { dot->astOperand2(), top->next() };
809 };
810 std::pair<const Token*, const Token*> assignToks;
811
812 const Token* tokStart = variable->nameToken();
813 if (variable->isArgument() && variable->scope())
814 tokStart = variable->scope()->bodyStart->next();
815 for (const Token *tok2 = tokStart; tok2 && tok2 != variable->scope()->bodyEnd; tok2 = tok2->next()) {
792816 if (tok2->str() == "{")
793817 ++indentlevel2;
794818
804828 break;
805829
806830 // Struct member is allocated => check if it is also properly deallocated..
807 else if (Token::Match(tok2->previous(), "[;{}] %varid% . %var% =", variable->declarationId())) {
808 if (getAllocationType(tok2->tokAt(4), tok2->tokAt(2)->varId()) == AllocType::No)
831 else if ((assignToks = isMemberAssignment(tok2, variable->declarationId())).first && assignToks.first->varId()) {
832 if (getAllocationType(assignToks.second, assignToks.first->varId()) == AllocType::No)
809833 continue;
810834
811835 const int structid(variable->declarationId());
812 const int structmemberid(tok2->tokAt(2)->varId());
836 const int structmemberid(assignToks.first->varId());
813837
814838 // This struct member is allocated.. check that it is deallocated
815839 int indentlevel3 = indentlevel2;
11771177 size = settings->sizeof_pointer;
11781178 else if (var.type() && var.type()->classScope)
11791179 size = estimateSize(var.type(), settings, symbolDatabase, recursionDepth+1);
1180 else if (var.valueType()->type == ValueType::Type::CONTAINER)
1180 else if (var.valueType() && var.valueType()->type == ValueType::Type::CONTAINER)
11811181 size = 3 * settings->sizeof_pointer; // Just guess
11821182 else
11831183 size = symbolDatabase->sizeOfType(var.typeStartToken());
15991599 const int indirect = p->isArray() ? p->dimensions().size() : 1;
16001600 if (isVariableChanged(start, p->scope()->bodyEnd, indirect, p->declarationId(), false, mSettings, mTokenizer->isCPP()))
16011601 continue;
1602 if (p->isArgument() && p->typeStartToken() && p->typeStartToken()->isSimplifiedTypedef() && !(Token::simpleMatch(p->typeEndToken(), "*") && !p->typeEndToken()->isSimplifiedTypedef()))
1603 continue;
16021604 constVariableError(p, nullptr);
16031605 }
16041606 }
16141616
16151617 const std::string vartype(var->isArgument() ? "Parameter" : "Variable");
16161618 const std::string varname(var->name());
1619 const std::string ptrRefArray = var->isArray() ? "const array" : (var->isPointer() ? "pointer to const" : "reference to const");
16171620
16181621 ErrorPath errorPath;
16191622 std::string id = "const" + vartype;
1620 std::string message = "$symbol:" + varname + "\n" + vartype + " '$symbol' can be declared with const";
1623 std::string message = "$symbol:" + varname + "\n" + vartype + " '$symbol' can be declared as " + ptrRefArray;
16211624 errorPath.push_back(ErrorPathItem(var ? var->nameToken() : nullptr, message));
16221625 if (var && var->isArgument() && function && function->functionPointerUsage) {
16231626 errorPath.push_front(ErrorPathItem(function->functionPointerUsage, "You might need to cast the function pointer here"));
601601 setFlag(fIncompleteVar, b);
602602 }
603603
604 bool isSimplifiedTypedef() const {
605 return getFlag(fIsSimplifiedTypedef);
606 }
607 void isSimplifiedTypedef(bool b) {
608 setFlag(fIsSimplifiedTypedef, b);
609 }
610
604611 bool isIncompleteConstant() const {
605612 return getFlag(fIsIncompleteConstant);
606613 }
648655 }
649656 void isInline(bool b) {
650657 setFlag(fIsInline, b);
658 }
659
660 bool isRestrict() const {
661 return getFlag(fIsRestrict);
662 }
663 void isRestrict(bool b) {
664 setFlag(fIsRestrict, b);
651665 }
652666
653667 bool isRemovedVoidParameter() const {
12761290 fIsSimplifedScope = (1ULL << 34), // scope added when simplifying e.g. if (int i = ...; ...)
12771291 fIsRemovedVoidParameter = (1ULL << 35), // A void function parameter has been removed
12781292 fIsIncompleteConstant = (1ULL << 36),
1293 fIsRestrict = (1ULL << 37), // Is this a restrict pointer type
1294 fIsSimplifiedTypedef = (1ULL << 38),
12791295 };
12801296
12811297 Token::Type mTokType;
13771377 typeEnd = typeStart;
13781378
13791379 // start substituting at the typedef name by replacing it with the type
1380 Token* replStart = tok2; // track first replaced token
1381 for (Token* tok3 = typeStart; tok3->str() != ";"; tok3 = tok3->next())
1382 tok3->isSimplifiedTypedef(true);
13801383 tok2->str(typeStart->str());
13811384
13821385 // restore qualification if it was removed
13851388 tok2 = tok2->previous();
13861389
13871390 if (globalScope) {
1388 tok2->insertToken("::");
1391 replStart = tok2->insertToken("::");
13891392 tok2 = tok2->next();
13901393 }
13911394
14141417 startIdx = spaceIdx + 1;
14151418 }
14161419 tok2->previous()->insertToken(removed1.substr(startIdx));
1417 tok2->previous()->insertToken("::");
1420 replStart = tok2->previous()->insertToken("::");
14181421 break;
14191422 }
14201423 idx = removed1.rfind(" ::");
14241427 removed1.resize(idx);
14251428 }
14261429 }
1430 replStart->isSimplifiedTypedef(true);
1431 Token* constTok = Token::simpleMatch(tok2->previous(), "const") ? tok2->previous() : nullptr;
14271432 // add remainder of type
14281433 tok2 = TokenList::copyTokens(tok2, typeStart->next(), typeEnd);
14291434
14301435 if (!pointers.empty()) {
14311436 for (const std::string &p : pointers) {
14321437 tok2->insertToken(p);
1438 tok2->isSimplifiedTypedef(true);
1439 tok2 = tok2->next();
1440 }
1441 if (constTok) {
1442 constTok->deleteThis();
1443 tok2->insertToken("const");
1444 tok2->isSimplifiedTypedef(true);
14331445 tok2 = tok2->next();
14341446 }
14351447 }
37493761 for (Token *tok = list.front(); tok; tok = tok->next()) {
37503762 if (tok->isOp())
37513763 continue;
3764 if (isCPP() && Token::simpleMatch(tok, "template <")) {
3765 Token* closingBracket = tok->next()->findClosingBracket();
3766 if (closingBracket)
3767 tok = closingBracket;
3768 continue;
3769 }
3770
37523771 if (tok == functionDeclEndToken) {
37533772 functionDeclEndStack.pop();
37543773 functionDeclEndToken = functionDeclEndStack.empty() ? nullptr : functionDeclEndStack.top();
54905509 out << " isImplicitInt=\"true\"";
54915510 if (tok->isComplex())
54925511 out << " isComplex=\"true\"";
5512 if (tok->isRestrict())
5513 out << " isRestrict=\"true\"";
54935514 if (tok->link())
54945515 out << " link=\"" << tok->link() << '\"';
54955516 if (tok->varId() > 0)
1124111262 if (keywords.find(tok->str()) != keywords.end()) {
1124211263 // Don't remove struct members
1124311264 if (!Token::simpleMatch(tok->previous(), ".")) {
11244 if (tok->str().find("inline") != std::string::npos) {
11245 Token *temp = tok->next();
11246 while (temp != nullptr && Token::Match(temp, "%name%")) {
11247 temp->isInline(true);
11248 temp = temp->next();
11265 const bool isinline = (tok->str().find("inline") != std::string::npos);
11266 const bool isrestrict = (tok->str().find("restrict") != std::string::npos);
11267 if (isinline || isrestrict) {
11268 for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
11269 if (isinline)
11270 temp->isInline(true);
11271 if (isrestrict)
11272 temp->isRestrict(true);
1124911273 }
1125011274 }
1125111275 tok->deleteThis(); // Simplify..
1126311287 tok->deleteNext();
1126411288
1126511289 if (c99) {
11266 while (tok->str() == "restrict")
11290 if (tok->str() == "restrict") {
11291 for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
11292 temp->isRestrict(true);
11293 }
1126711294 tok->deleteThis();
11295 }
1126811296
1126911297 if (mSettings->standards.c >= Standards::C11) {
1127011298 while (tok->str() == "_Atomic")
936936 }
937937 }
938938
939 // Array element
940 else if (parent->str() == "[" && parent->isBinaryOp()) {
941 for (const ValueFlow::Value &value1 : parent->astOperand1()->values()) {
942 if (!value1.isTokValue())
943 continue;
944 for (const ValueFlow::Value &value2 : parent->astOperand2()->values()) {
945 if (!value2.isIntValue())
946 continue;
947 if (value1.varId == 0 || value2.varId == 0 ||
948 (value1.varId == value2.varId && value1.varvalue == value2.varvalue)) {
949 ValueFlow::Value result(0);
950 result.condition = value1.condition ? value1.condition : value2.condition;
951 result.setInconclusive(value1.isInconclusive() | value2.isInconclusive());
952 result.varId = (value1.varId != 0) ? value1.varId : value2.varId;
953 result.varvalue = (result.varId == value1.varId) ? value1.intvalue : value2.intvalue;
954 if (value1.valueKind == value2.valueKind)
955 result.valueKind = value1.valueKind;
956 if (value1.tokvalue->tokType() == Token::eString) {
957 const std::string s = value1.tokvalue->strValue();
958 const MathLib::bigint index = value2.intvalue;
959 if (index == s.size()) {
960 result.intvalue = 0;
961 setTokenValue(parent, result, settings);
962 } else if (index >= 0 && index < s.size()) {
963 result.intvalue = s[index];
964 setTokenValue(parent, result, settings);
965 }
966 } else if (value1.tokvalue->str() == "{") {
967 MathLib::bigint index = value2.intvalue;
968 const Token *element = value1.tokvalue->next();
969 while (index > 0 && element->str() != "}") {
970 if (element->str() == ",")
971 --index;
972 if (Token::Match(element, "[{}()[]]"))
973 break;
974 element = element->next();
975 }
976 if (Token::Match(element, "%num% [,}]")) {
977 result.intvalue = MathLib::toLongNumber(element->str());
978 setTokenValue(parent, result, settings);
979 }
980 }
981 }
982 }
983 }
984 }
985
986939 else if (Token::Match(parent, ":: %name%") && parent->astOperand2() == tok) {
987940 setTokenValue(parent, value, settings);
988941 }
14041357 }
14051358 }
14061359
1360 static void valueFlowArrayElement(TokenList* tokenlist, const Settings* settings)
1361 {
1362 for (Token* tok = tokenlist->front(); tok; tok = tok->next()) {
1363 if (!Token::simpleMatch(tok, "["))
1364 continue;
1365 if (!tok->isBinaryOp())
1366 continue;
1367 if (tok->hasKnownIntValue())
1368 continue;
1369 const Token* indexTok = tok->astOperand2();
1370 const Token* arrayTok = tok->astOperand1();
1371
1372 for (const ValueFlow::Value& arrayValue : arrayTok->values()) {
1373 if (!arrayValue.isTokValue())
1374 continue;
1375 for (const ValueFlow::Value& indexValue : indexTok->values()) {
1376 if (!indexValue.isIntValue())
1377 continue;
1378 if (arrayValue.varId != 0 && indexValue.varId != 0 &&
1379 !(arrayValue.varId == indexValue.varId && arrayValue.varvalue == indexValue.varvalue))
1380 continue;
1381
1382 ValueFlow::Value result(0);
1383 result.condition = arrayValue.condition ? arrayValue.condition : indexValue.condition;
1384 result.setInconclusive(arrayValue.isInconclusive() | indexValue.isInconclusive());
1385 result.varId = (arrayValue.varId != 0) ? arrayValue.varId : indexValue.varId;
1386 result.varvalue = (result.varId == arrayValue.varId) ? arrayValue.intvalue : indexValue.intvalue;
1387 if (arrayValue.valueKind == indexValue.valueKind)
1388 result.valueKind = arrayValue.valueKind;
1389
1390 result.errorPath.insert(result.errorPath.end(), arrayValue.errorPath.begin(), arrayValue.errorPath.end());
1391 result.errorPath.insert(result.errorPath.end(), indexValue.errorPath.begin(), indexValue.errorPath.end());
1392
1393 const MathLib::bigint index = indexValue.intvalue;
1394
1395 if (arrayValue.tokvalue->tokType() == Token::eString) {
1396 const std::string s = arrayValue.tokvalue->strValue();
1397 if (index == s.size()) {
1398 result.intvalue = 0;
1399 setTokenValue(tok, result, settings);
1400 } else if (index >= 0 && index < s.size()) {
1401 result.intvalue = s[index];
1402 setTokenValue(tok, result, settings);
1403 }
1404 } else if (Token::simpleMatch(arrayValue.tokvalue, "{")) {
1405 std::vector<const Token*> args = getArguments(arrayValue.tokvalue);
1406 if (index < 0 || index >= args.size())
1407 continue;
1408 const Token* arg = args[index];
1409 if (!arg->hasKnownIntValue())
1410 continue;
1411 const ValueFlow::Value& v = arg->values().front();
1412 result.intvalue = v.intvalue;
1413 result.errorPath.insert(result.errorPath.end(), v.errorPath.begin(), v.errorPath.end());
1414 setTokenValue(tok, result, settings);
1415 }
1416 }
1417 }
1418 }
1419 }
1420
14071421 static void valueFlowPointerAlias(TokenList *tokenlist)
14081422 {
14091423 for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
18121826 }
18131827 }
18141828
1829 ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist);
1830 ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist);
1831
1832 static Analyzer::Result valueFlowForward(Token* startToken,
1833 const Token* endToken,
1834 const Token* exprTok,
1835 const ValueFlow::Value& value,
1836 TokenList* const tokenlist)
1837 {
1838 return valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, value, tokenlist), tokenlist->getSettings());
1839 }
1840
18151841 static Analyzer::Result valueFlowForward(Token* startToken,
18161842 const Token* endToken,
18171843 const Token* exprTok,
18181844 const std::list<ValueFlow::Value>& values,
1819 TokenList* const tokenlist,
1820 const Settings* settings);
1821
1845 TokenList* const tokenlist)
1846 {
1847 Analyzer::Result result{};
1848 for (const ValueFlow::Value& v : values) {
1849 result.update(valueFlowForward(startToken, endToken, exprTok, v, tokenlist));
1850 }
1851 return result;
1852 }
1853
1854 template<class ValueOrValues>
1855 static Analyzer::Result valueFlowForward(Token* startToken, const Token* exprTok, const ValueOrValues& v, TokenList* tokenlist)
1856 {
1857 const Token* endToken = nullptr;
1858 const Function* f = Scope::nestedInFunction(startToken->scope());
1859 if (f && f->functionScope)
1860 endToken = f->functionScope->bodyEnd;
1861 return valueFlowForward(startToken, endToken, exprTok, v, tokenlist);
1862 }
1863
1864 static Analyzer::Result valueFlowForwardRecursive(Token* top,
1865 const Token* exprTok,
1866 const std::list<ValueFlow::Value>& values,
1867 TokenList* const tokenlist)
1868 {
1869 Analyzer::Result result{};
1870 for (const ValueFlow::Value& v : values) {
1871 result.update(valueFlowGenericForward(top, makeAnalyzer(exprTok, v, tokenlist), tokenlist->getSettings()));
1872 }
1873 return result;
1874 }
1875
1876 static void valueFlowReverse(Token* tok,
1877 const Token* const endToken,
1878 const Token* const varToken,
1879 const std::list<ValueFlow::Value>& values,
1880 TokenList* tokenlist)
1881 {
1882 for (const ValueFlow::Value& v : values) {
1883 valueFlowGenericReverse(tok, endToken, makeReverseAnalyzer(varToken, v, tokenlist), tokenlist->getSettings());
1884 }
1885 }
1886
1887 // Deprecated
18221888 static void valueFlowReverse(TokenList* tokenlist,
18231889 Token* tok,
18241890 const Token* const varToken,
18251891 ValueFlow::Value val,
18261892 const ValueFlow::Value& val2,
1827 ErrorLogger* errorLogger,
1828 const Settings* settings);
1893 ErrorLogger* /*errorLogger*/,
1894 const Settings* = nullptr)
1895 {
1896 std::list<ValueFlow::Value> values = {val};
1897 if (val2.varId != 0)
1898 values.push_back(val2);
1899 valueFlowReverse(tok, nullptr, varToken, values, tokenlist);
1900 }
18291901
18301902 static bool isConditionKnown(const Token* tok, bool then)
18311903 {
26322704 }
26332705 };
26342706
2635 ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist);
2636
26372707 struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
26382708 std::unordered_map<nonneg int, const Variable*> varids;
26392709 std::unordered_map<nonneg int, const Variable*> aliases;
29282998 return tok->next()->str() == varname;
29292999 }
29303000 };
2931
2932 static Analyzer::Result valueFlowForwardExpression(Token* startToken,
2933 const Token* endToken,
2934 const Token* exprTok,
2935 const std::list<ValueFlow::Value>& values,
2936 const TokenList* const tokenlist,
2937 const Settings* settings)
2938 {
2939 Analyzer::Result result{};
2940 for (const ValueFlow::Value& v : values) {
2941 ExpressionAnalyzer a(exprTok, v, tokenlist);
2942 result.update(valueFlowGenericForward(startToken, endToken, a, settings));
2943 }
2944 return result;
2945 }
2946
2947 static const Token* parseBinaryIntOp(const Token* expr,
2948 const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
2949 MathLib::bigint& known)
2950 {
2951 if (!expr)
2952 return nullptr;
2953 if (!expr->astOperand1() || !expr->astOperand2())
2954 return nullptr;
2955 if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0)
2956 return nullptr;
2957 std::vector<MathLib::bigint> x1 = eval(expr->astOperand1());
2958 std::vector<MathLib::bigint> x2 = eval(expr->astOperand2());
2959 if (expr->astOperand1()->exprId() == 0 && x1.empty())
2960 return nullptr;
2961 if (expr->astOperand2()->exprId() == 0 && x2.empty())
2962 return nullptr;
2963 const Token* varTok = nullptr;
2964 if (!x1.empty() && x2.empty()) {
2965 varTok = expr->astOperand2();
2966 known = x1.front();
2967 } else if (x1.empty() && !x2.empty()) {
2968 varTok = expr->astOperand1();
2969 known = x2.front();
2970 }
2971 return varTok;
2972 }
2973
2974 const Token* solveExprValue(const Token* expr,
2975 const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
2976 ValueFlow::Value& value)
2977 {
2978 if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
2979 return expr;
2980 if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
2981 return expr;
2982 MathLib::bigint intval;
2983 const Token* binaryTok = parseBinaryIntOp(expr, eval, intval);
2984 bool rhs = astIsRHS(binaryTok);
2985 // If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values
2986 if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-"))
2987 return expr;
2988 if (binaryTok && expr->str().size() == 1) {
2989 switch (expr->str()[0]) {
2990 case '+': {
2991 value.intvalue -= intval;
2992 return solveExprValue(binaryTok, eval, value);
2993 }
2994 case '-': {
2995 if (rhs)
2996 value.intvalue = intval - value.intvalue;
2997 else
2998 value.intvalue += intval;
2999 return solveExprValue(binaryTok, eval, value);
3000 }
3001 case '*': {
3002 if (intval == 0)
3003 break;
3004 value.intvalue /= intval;
3005 return solveExprValue(binaryTok, eval, value);
3006 }
3007 case '^': {
3008 value.intvalue ^= intval;
3009 return solveExprValue(binaryTok, eval, value);
3010 }
3011 }
3012 }
3013 return expr;
3014 }
3015
3016 static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
3017 {
3018 return solveExprValue(
3019 expr,
3020 [](const Token* tok) -> std::vector<MathLib::bigint> {
3021 if (tok->hasKnownIntValue())
3022 return {tok->values().front().intvalue};
3023 return {};
3024 },
3025 value);
3026 }
3027
3028 ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
3029 {
3030 const Token* expr = solveExprValue(exprTok, value);
3031 return ExpressionAnalyzer(expr, value, tokenlist);
3032 }
3033
3034 static Analyzer::Result valueFlowForward(Token* startToken,
3035 const Token* endToken,
3036 const Token* exprTok,
3037 const std::list<ValueFlow::Value>& values,
3038 TokenList* const tokenlist,
3039 const Settings* settings)
3040 {
3041 Analyzer::Result result{};
3042 for (const ValueFlow::Value& v : values) {
3043 result.update(valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, v, tokenlist), settings));
3044 }
3045 return result;
3046 }
3047
3048 static Analyzer::Result valueFlowForward(Token* top,
3049 const Token* exprTok,
3050 const std::list<ValueFlow::Value>& values,
3051 TokenList* const tokenlist,
3052 const Settings* settings)
3053 {
3054 Analyzer::Result result{};
3055 for (const ValueFlow::Value& v : values) {
3056 result.update(valueFlowGenericForward(top, makeAnalyzer(exprTok, v, tokenlist), settings));
3057 }
3058 return result;
3059 }
3060
3061 static void valueFlowReverse(Token* tok,
3062 const Token* const endToken,
3063 const Token* const varToken,
3064 const std::list<ValueFlow::Value>& values,
3065 TokenList* tokenlist,
3066 const Settings* settings)
3067 {
3068 for (const ValueFlow::Value& v : values) {
3069 ExpressionAnalyzer a(varToken, v, tokenlist);
3070 valueFlowGenericReverse(tok, endToken, a, settings);
3071 }
3072 }
3073
3074 static void valueFlowReverse(TokenList* tokenlist,
3075 Token* tok,
3076 const Token* const varToken,
3077 ValueFlow::Value val,
3078 const ValueFlow::Value& val2,
3079 ErrorLogger* /*errorLogger*/,
3080 const Settings* settings)
3081 {
3082 std::list<ValueFlow::Value> values = {val};
3083 if (val2.varId != 0)
3084 values.push_back(val2);
3085 valueFlowReverse(tok, nullptr, varToken, values, tokenlist, settings);
3086 }
30873001
30883002 enum class LifetimeCapture { Undefined, ByValue, ByReference };
30893003
35763490 if (Token::Match(tok->previous(), "%var% {|(") && isVariableDecl(tok->previous())) {
35773491 std::list<ValueFlow::Value> values = tok->values();
35783492 values.remove_if(&isNotLifetimeValue);
3579 valueFlowForward(nextAfterAstRightmostLeaf(tok), getEndOfExprScope(tok), tok->previous(), values, tokenlist, settings);
3493 valueFlowForward(nextAfterAstRightmostLeaf(tok), getEndOfExprScope(tok), tok->previous(), values, tokenlist);
35803494 return;
35813495 }
35823496 Token *parent = tok->astParent();
36163530 const Token *nextExpression = nextAfterAstRightmostLeaf(parent);
36173531
36183532 if (expr->exprId() > 0) {
3619 valueFlowForwardExpression(const_cast<Token*>(nextExpression),
3620 endOfVarScope->next(),
3621 expr,
3622 values,
3623 tokenlist,
3624 settings);
3533 valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope->next(), expr, values, tokenlist);
36253534
36263535 for (ValueFlow::Value& val : values) {
36273536 if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address)
36323541 const Token* parentLifetime =
36333542 getParentLifetime(tokenlist->isCPP(), parent->astOperand1()->astOperand2(), &settings->library);
36343543 if (parentLifetime && parentLifetime->exprId() > 0) {
3635 valueFlowForward(const_cast<Token*>(nextExpression),
3636 endOfVarScope,
3637 parentLifetime,
3638 values,
3639 tokenlist,
3640 settings);
3544 valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, parentLifetime, values, tokenlist);
36413545 }
36423546 }
36433547 }
36583562 const Token *nextExpression = nextAfterAstRightmostLeaf(parent);
36593563 // Only forward lifetime values
36603564 values.remove_if(&isNotLifetimeValue);
3661 valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, tok, values, tokenlist, settings);
3565 valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, tok, values, tokenlist);
36623566 // Cast
36633567 } else if (parent->isCast()) {
36643568 std::list<ValueFlow::Value> values = tok->values();
47094613 continue;
47104614 const Token * const endOfVarScope = var->scope()->bodyEnd;
47114615 setTokenValue(varTok, value, settings);
4712 valueFlowForward(varTok->next(), endOfVarScope, varTok, values, tokenlist, settings);
4616 valueFlowForward(varTok->next(), endOfVarScope, varTok, values, tokenlist);
47134617 continue;
47144618 }
47154619 ValueFlow::Value::MoveKind moveKind;
47454649 const Token * openParentesisOfMove = findOpenParentesisOfMove(varTok);
47464650 const Token * endOfFunctionCall = findEndOfFunctionCallForParameter(openParentesisOfMove);
47474651 if (endOfFunctionCall)
4748 valueFlowForward(
4749 const_cast<Token*>(endOfFunctionCall), endOfVarScope, varTok, values, tokenlist, settings);
4652 valueFlowForward(const_cast<Token*>(endOfFunctionCall), endOfVarScope, varTok, values, tokenlist);
47504653 }
47514654 }
47524655 }
49664869 rhs.errorPath.emplace_back(tok,
49674870 tok->astOperand1()->expressionString() + " is assigned '" +
49684871 tok->astOperand2()->expressionString() + "' here.");
4969 valueFlowForward(start, end, tok->astOperand1(), {rhs}, tokenlist, tokenlist->getSettings());
4872 valueFlowForward(start, end, tok->astOperand1(), rhs, tokenlist);
49704873
49714874 ValueFlow::Value lhs = makeSymbolic(tok->astOperand1());
49724875 lhs.errorPath.emplace_back(tok,
49734876 tok->astOperand1()->expressionString() + " is assigned '" +
49744877 tok->astOperand2()->expressionString() + "' here.");
4975 valueFlowForward(start, end, tok->astOperand2(), {lhs}, tokenlist, tokenlist->getSettings());
4878 valueFlowForward(start, end, tok->astOperand2(), lhs, tokenlist);
49764879 }
49774880 }
49784881 }
52525155 constValues.splice(constValues.end(), values, it, values.end());
52535156 valueFlowForwardConst(const_cast<Token*>(nextExpression), endOfVarScope, expr->variable(), constValues, settings);
52545157 }
5255 valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, expr, values, tokenlist, settings);
5158 valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, expr, values, tokenlist);
52565159 }
52575160
52585161 static void valueFlowForwardAssign(Token* const tok,
54245327 value.errorPath.emplace_back(tok,
54255328 tok->astOperand1()->expressionString() + " is assigned '" +
54265329 tok->astOperand2()->expressionString() + "' here.");
5427 valueFlowForward(start, end, expr, {value}, tokenlist, settings);
5330 valueFlowForward(start, end, expr, value, tokenlist);
54285331 }
54295332 }
54305333 }
55305433 Condition() : vartok(nullptr), true_values(), false_values(), inverted(false), impossible(true) {}
55315434 };
55325435
5436 virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const = 0;
5437
55335438 virtual Analyzer::Result forward(Token* start,
55345439 const Token* stop,
55355440 const Token* exprTok,
55365441 const std::list<ValueFlow::Value>& values,
5537 TokenList* tokenlist,
5538 const Settings* settings) const = 0;
5442 TokenList* tokenlist) const
5443 {
5444 return valueFlowForward(start->next(), stop, exprTok, values, tokenlist);
5445 }
55395446
55405447 virtual Analyzer::Result forward(Token* top,
55415448 const Token* exprTok,
55425449 const std::list<ValueFlow::Value>& values,
5543 TokenList* tokenlist,
5544 const Settings* settings) const = 0;
5450 TokenList* tokenlist) const
5451 {
5452 return valueFlowForwardRecursive(top, exprTok, values, tokenlist);
5453 }
55455454
55465455 virtual void reverse(Token* start,
55475456 const Token* endToken,
55485457 const Token* exprTok,
55495458 const std::list<ValueFlow::Value>& values,
5550 TokenList* tokenlist,
5551 const Settings* settings) const = 0;
5552
5553 virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const = 0;
5459 TokenList* tokenlist) const
5460 {
5461 return valueFlowReverse(start, endToken, exprTok, values, tokenlist);
5462 }
55545463
55555464 void traverseCondition(TokenList* tokenlist,
55565465 SymbolDatabase* symboldatabase,
56715580 })) {
56725581 // Start at the end of the loop body
56735582 Token* bodyTok = top->link()->next();
5674 reverse(bodyTok->link(), bodyTok, cond.vartok, values, tokenlist, settings);
5583 reverse(bodyTok->link(), bodyTok, cond.vartok, values, tokenlist);
56755584 }
56765585 if (settings->debugwarnings)
56775586 bailout(tokenlist,
56905599 if (!startTok)
56915600 startTok = tok->previous();
56925601
5693 reverse(startTok, nullptr, cond.vartok, values, tokenlist, settings);
5602 reverse(startTok, nullptr, cond.vartok, values, tokenlist);
56945603 });
56955604 }
56965605
57775686 return v.isImpossible();
57785687 });
57795688 for (Token* start:nextExprs) {
5780 Analyzer::Result r = forward(start, cond.vartok, values, tokenlist, settings);
5689 Analyzer::Result r = forward(start, cond.vartok, values, tokenlist);
57815690 if (r.terminate != Analyzer::Terminate::None)
57825691 return;
57835692 }
58375746
58385747 if (Token::simpleMatch(condTop, "?")) {
58395748 Token* colon = condTop->astOperand2();
5840 forward(colon->astOperand1(), cond.vartok, thenValues, tokenlist, settings);
5841 forward(colon->astOperand2(), cond.vartok, elseValues, tokenlist, settings);
5749 forward(colon->astOperand1(), cond.vartok, thenValues, tokenlist);
5750 forward(colon->astOperand2(), cond.vartok, elseValues, tokenlist);
58425751 // TODO: Handle after condition
58435752 return;
58445753 }
59225831 std::list<ValueFlow::Value>& values = (i == 0 ? thenValues : elseValues);
59235832 valueFlowSetConditionToKnown(condTok, values, i == 0);
59245833
5925 Analyzer::Result r =
5926 forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, tokenlist, settings);
5834 Analyzer::Result r = forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, tokenlist);
59275835 deadBranch[i] = r.terminate == Analyzer::Terminate::Escape;
59285836 if (r.action.isModified() && !deadBranch[i])
59295837 changeBlock = i;
60255933 }
60265934 if (values.empty())
60275935 return;
6028 forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist, settings);
5936 forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist);
60295937 }
60305938 });
60315939 }
60435951 }
60445952
60455953 struct SimpleConditionHandler : ConditionHandler {
6046 virtual Analyzer::Result forward(Token* start,
6047 const Token* stop,
6048 const Token* exprTok,
6049 const std::list<ValueFlow::Value>& values,
6050 TokenList* tokenlist,
6051 const Settings* settings) const override {
6052 return valueFlowForward(start->next(), stop, exprTok, values, tokenlist, settings);
6053 }
6054
6055 virtual Analyzer::Result forward(Token* top,
6056 const Token* exprTok,
6057 const std::list<ValueFlow::Value>& values,
6058 TokenList* tokenlist,
6059 const Settings* settings) const override {
6060 return valueFlowForward(top, exprTok, values, tokenlist, settings);
6061 }
6062
6063 virtual void reverse(Token* start,
6064 const Token* endToken,
6065 const Token* exprTok,
6066 const std::list<ValueFlow::Value>& values,
6067 TokenList* tokenlist,
6068 const Settings* settings) const override {
6069 return valueFlowReverse(start, endToken, exprTok, values, tokenlist, settings);
6070 }
6071
60725954 virtual std::vector<Condition> parse(const Token* tok, const Settings*) const override {
60735955 Condition cond;
60745956 ValueFlow::Value true_value;
64386320 }
64396321 }
64406322
6441 static void valueFlowForLoopSimplifyAfter(Token* fortok,
6442 nonneg int varid,
6443 const MathLib::bigint num,
6444 TokenList* tokenlist,
6445 const Settings* settings)
6323 static void valueFlowForLoopSimplifyAfter(Token* fortok, nonneg int varid, const MathLib::bigint num, TokenList* tokenlist)
64466324 {
64476325 const Token *vartok = nullptr;
64486326 for (const Token *tok = fortok; tok; tok = tok->next()) {
64676345 values.back().errorPath.emplace_back(fortok,"After for loop, " + var->name() + " has value " + values.back().infoString());
64686346
64696347 if (blockTok != endToken) {
6470 valueFlowForward(blockTok->next(), endToken, vartok, values, tokenlist, settings);
6348 valueFlowForward(blockTok->next(), endToken, vartok, values, tokenlist);
64716349 }
64726350 }
64736351
64956373 std::list<ValueFlow::Value> initValues;
64966374 initValues.emplace_back(initValue, ValueFlow::Value::Bound::Lower);
64976375 initValues.push_back(asImpossible(initValues.back()));
6498 Analyzer::Result result =
6499 valueFlowForward(bodyStart, bodyStart->link(), vartok, initValues, tokenlist, settings);
6376 Analyzer::Result result = valueFlowForward(bodyStart, bodyStart->link(), vartok, initValues, tokenlist);
65006377
65016378 if (!result.action.isModified()) {
65026379 std::list<ValueFlow::Value> lastValues;
65056382 lastValues.push_back(asImpossible(lastValues.back()));
65066383 if (stepValue != 1)
65076384 lastValues.pop_front();
6508 valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist, settings);
6385 valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist);
65096386 }
65106387 }
65116388 const MathLib::bigint afterValue = executeBody ? lastValue + stepValue : initValue;
6512 valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist, settings);
6389 valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist);
65136390 } else {
65146391 ProgramMemory mem1, mem2, memAfter;
65156392 if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter)) {
65326409 continue;
65336410 if (p.first.tok->varId() == 0)
65346411 continue;
6535 valueFlowForLoopSimplifyAfter(tok, p.first.getExpressionId(), p.second.intvalue, tokenlist, settings);
6412 valueFlowForLoopSimplifyAfter(tok, p.first.getExpressionId(), p.second.intvalue, tokenlist);
65366413 }
65376414 }
65386415 }
67896666 }
67906667
67916668 static void valueFlowInjectParameter(TokenList* tokenlist,
6792 const Settings* settings,
67936669 const Variable* arg,
67946670 const Scope* functionScope,
67956671 const std::list<ValueFlow::Value>& argvalues)
68076683 functionScope->bodyEnd,
68086684 arg->nameToken(),
68096685 argvalues,
6810 tokenlist,
6811 settings);
6686 tokenlist);
68126687 }
68136688
68146689 static void valueFlowSwitchVariable(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
70316906 }
70326907 }
70336908
7034 static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
6909 static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDatabase* symboldatabase)
70356910 {
70366911 if (!tokenlist->isCPP())
70376912 return;
70536928 argvalues.push_back(v);
70546929 }
70556930 if (!argvalues.empty())
7056 valueFlowInjectParameter(tokenlist, settings, var, scope, argvalues);
6931 valueFlowInjectParameter(tokenlist, var, scope, argvalues);
70576932 }
70586933 }
70596934 }
72497124 if (partial)
72507125 continue;
72517126
7252 valueFlowForward(tok->next(), tok->scope()->bodyEnd, var->nameToken(), {uninitValue}, tokenlist, settings);
7127 valueFlowForward(tok->next(), tok->scope()->bodyEnd, var->nameToken(), uninitValue, tokenlist);
72537128 }
72547129 }
72557130
74077282 }
74087283 };
74097284
7410 static Analyzer::Result valueFlowContainerForward(Token* startToken,
7411 const Token* endToken,
7412 const Token* exprTok,
7413 const ValueFlow::Value& value,
7414 TokenList* tokenlist)
7415 {
7416 ContainerExpressionAnalyzer a(exprTok, value, tokenlist);
7417 return valueFlowGenericForward(startToken, endToken, a, tokenlist->getSettings());
7418 }
7419
7420 static Analyzer::Result valueFlowContainerForwardRecursive(Token* top,
7421 const Token* exprTok,
7422 const ValueFlow::Value& value,
7423 TokenList* tokenlist)
7424 {
7425 ContainerExpressionAnalyzer a(exprTok, value, tokenlist);
7426 return valueFlowGenericForward(top, a, tokenlist->getSettings());
7427 }
7428
7429 static Analyzer::Result valueFlowContainerForward(Token* startToken,
7430 const Token* exprTok,
7431 const ValueFlow::Value& value,
7432 TokenList* tokenlist)
7433 {
7434 const Token* endToken = nullptr;
7435 const Function* f = Scope::nestedInFunction(startToken->scope());
7436 if (f && f->functionScope)
7437 endToken = f->functionScope->bodyEnd;
7438 return valueFlowContainerForward(startToken, endToken, exprTok, value, tokenlist);
7439 }
7440
7441 static void valueFlowContainerReverse(Token* tok,
7442 const Token* const endToken,
7443 const Token* const varToken,
7444 const std::list<ValueFlow::Value>& values,
7445 TokenList* tokenlist,
7446 const Settings* settings)
7447 {
7448 for (const ValueFlow::Value& value : values) {
7449 ContainerExpressionAnalyzer a(varToken, value, tokenlist);
7450 valueFlowGenericReverse(tok, endToken, a, settings);
7451 }
7285 static const Token* parseBinaryIntOp(const Token* expr,
7286 const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
7287 MathLib::bigint& known)
7288 {
7289 if (!expr)
7290 return nullptr;
7291 if (!expr->astOperand1() || !expr->astOperand2())
7292 return nullptr;
7293 if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0)
7294 return nullptr;
7295 std::vector<MathLib::bigint> x1 = eval(expr->astOperand1());
7296 std::vector<MathLib::bigint> x2 = eval(expr->astOperand2());
7297 if (expr->astOperand1()->exprId() == 0 && x1.empty())
7298 return nullptr;
7299 if (expr->astOperand2()->exprId() == 0 && x2.empty())
7300 return nullptr;
7301 const Token* varTok = nullptr;
7302 if (!x1.empty() && x2.empty()) {
7303 varTok = expr->astOperand2();
7304 known = x1.front();
7305 } else if (x1.empty() && !x2.empty()) {
7306 varTok = expr->astOperand1();
7307 known = x2.front();
7308 }
7309 return varTok;
7310 }
7311
7312 const Token* solveExprValue(const Token* expr,
7313 const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
7314 ValueFlow::Value& value)
7315 {
7316 if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
7317 return expr;
7318 if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
7319 return expr;
7320 MathLib::bigint intval;
7321 const Token* binaryTok = parseBinaryIntOp(expr, eval, intval);
7322 bool rhs = astIsRHS(binaryTok);
7323 // If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values
7324 if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-"))
7325 return expr;
7326 if (binaryTok && expr->str().size() == 1) {
7327 switch (expr->str()[0]) {
7328 case '+': {
7329 value.intvalue -= intval;
7330 return solveExprValue(binaryTok, eval, value);
7331 }
7332 case '-': {
7333 if (rhs)
7334 value.intvalue = intval - value.intvalue;
7335 else
7336 value.intvalue += intval;
7337 return solveExprValue(binaryTok, eval, value);
7338 }
7339 case '*': {
7340 if (intval == 0)
7341 break;
7342 value.intvalue /= intval;
7343 return solveExprValue(binaryTok, eval, value);
7344 }
7345 case '^': {
7346 value.intvalue ^= intval;
7347 return solveExprValue(binaryTok, eval, value);
7348 }
7349 }
7350 }
7351 return expr;
7352 }
7353
7354 static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
7355 {
7356 return solveExprValue(
7357 expr,
7358 [](const Token* tok) -> std::vector<MathLib::bigint> {
7359 if (tok->hasKnownIntValue())
7360 return {tok->values().front().intvalue};
7361 return {};
7362 },
7363 value);
7364 }
7365
7366 ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
7367 {
7368 if (value.isContainerSizeValue())
7369 return ContainerExpressionAnalyzer(exprTok, value, tokenlist);
7370 const Token* expr = solveExprValue(exprTok, value);
7371 return ExpressionAnalyzer(expr, value, tokenlist);
7372 }
7373
7374 ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist)
7375 {
7376 if (value.isContainerSizeValue())
7377 return ContainerExpressionAnalyzer(exprTok, value, tokenlist);
7378 return ExpressionAnalyzer(exprTok, value, tokenlist);
74527379 }
74537380
74547381 bool isContainerSizeChanged(const Token* tok, const Settings* settings, int depth)
78647791 if (constSize)
78657792 valueFlowForwardConst(var->nameToken()->next(), var->scope()->bodyEnd, var, values, settings);
78667793 else
7867 valueFlowContainerForward(var->nameToken()->next(), var->nameToken(), value, tokenlist);
7794 valueFlowForward(var->nameToken()->next(), var->nameToken(), value, tokenlist);
78687795 }
78697796 }
78707797
78797806 ValueFlow::Value value(Token::getStrLength(containerTok->tokAt(2)));
78807807 value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
78817808 value.setKnown();
7882 valueFlowContainerForward(containerTok->next(), containerTok, value, tokenlist);
7809 valueFlowForward(containerTok->next(), containerTok, value, tokenlist);
78837810 }
78847811 } else if (Token::Match(tok, "%name%|;|{|}|> %var% = {") && Token::simpleMatch(tok->linkAt(3), "} ;")) {
78857812 const Token* containerTok = tok->next();
78897816 std::vector<ValueFlow::Value> values =
78907817 getInitListSize(tok->tokAt(3), containerTok->valueType(), settings);
78917818 for (const ValueFlow::Value& value : values)
7892 valueFlowContainerForward(containerTok->next(), containerTok, value, tokenlist);
7819 valueFlowForward(containerTok->next(), containerTok, value, tokenlist);
78937820 }
78947821 } else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() &&
78957822 tok->astOperand1()->valueType()->container) {
79017828 ValueFlow::Value value(0);
79027829 value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
79037830 value.setKnown();
7904 valueFlowContainerForward(tok->next(), containerTok, value, tokenlist);
7831 valueFlowForward(tok->next(), containerTok, value, tokenlist);
79057832 } else if (action == Library::Container::Action::RESIZE && tok->tokAt(2)->astOperand2() &&
79067833 tok->tokAt(2)->astOperand2()->hasKnownIntValue()) {
79077834 ValueFlow::Value value(tok->tokAt(2)->astOperand2()->values().front());
79087835 value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
79097836 value.setKnown();
7910 valueFlowContainerForward(tok->next(), containerTok, value, tokenlist);
7837 valueFlowForward(tok->next(), containerTok, value, tokenlist);
79117838 }
79127839 }
79137840 }
79157842 }
79167843
79177844 struct ContainerConditionHandler : ConditionHandler {
7918 virtual Analyzer::Result forward(Token* start,
7919 const Token* stop,
7920 const Token* exprTok,
7921 const std::list<ValueFlow::Value>& values,
7922 TokenList* tokenlist,
7923 const Settings*) const override {
7924 Analyzer::Result result{};
7925 for (const ValueFlow::Value& value : values)
7926 result.update(valueFlowContainerForward(start->next(), stop, exprTok, value, tokenlist));
7927 return result;
7928 }
7929
7930 virtual Analyzer::Result forward(Token* top,
7931 const Token* exprTok,
7932 const std::list<ValueFlow::Value>& values,
7933 TokenList* tokenlist,
7934 const Settings*) const override {
7935 Analyzer::Result result{};
7936 for (const ValueFlow::Value& value : values)
7937 result.update(valueFlowContainerForwardRecursive(top, exprTok, value, tokenlist));
7938 return result;
7939 }
7940
7941 virtual void reverse(Token* start,
7942 const Token* endTok,
7943 const Token* exprTok,
7944 const std::list<ValueFlow::Value>& values,
7945 TokenList* tokenlist,
7946 const Settings* settings) const override {
7947 return valueFlowContainerReverse(start, endTok, exprTok, values, tokenlist, settings);
7948 }
7949
79507845 virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const override
79517846 {
79527847 Condition cond;
81128007 value.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE;
81138008 value.setKnown();
81148009 const std::list<ValueFlow::Value> values{value};
8115 valueFlowForward(const_cast<Token*>(rhs), functionScope->bodyEnd, tok->next(), values, tokenlist, settings);
8010 valueFlowForward(const_cast<Token*>(rhs), functionScope->bodyEnd, tok->next(), values, tokenlist);
81168011 }
81178012 }
81188013 }
82138108 argValues.back().errorPath.emplace_back(arg.nameToken(), "Assuming " + arg.name() + " size is 1000000");
82148109 argValues.back().safe = true;
82158110 for (const ValueFlow::Value &value : argValues)
8216 valueFlowContainerForward(
8217 const_cast<Token*>(functionScope->bodyStart), arg.nameToken(), value, tokenlist);
8111 valueFlowForward(const_cast<Token*>(functionScope->bodyStart), arg.nameToken(), value, tokenlist);
82188112 continue;
82198113 }
82208114
82528146 functionScope->bodyEnd,
82538147 arg.nameToken(),
82548148 argValues,
8255 tokenlist,
8256 settings);
8149 tokenlist);
82578150 continue;
82588151 }
82598152 }
82758168 functionScope->bodyEnd,
82768169 arg.nameToken(),
82778170 argValues,
8278 tokenlist,
8279 settings);
8171 tokenlist);
82808172 }
82818173 }
82828174 }
84938385 valueFlowCondition(SymbolicConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
84948386 valueFlowSymbolicInfer(tokenlist, symboldatabase);
84958387 valueFlowArrayBool(tokenlist);
8388 valueFlowArrayElement(tokenlist, settings);
84968389 valueFlowRightShift(tokenlist, settings);
84978390 valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings);
84988391 valueFlowAfterSwap(tokenlist, symboldatabase, errorLogger, settings);
85038396 valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings);
85048397 valueFlowFunctionReturn(tokenlist, errorLogger);
85058398 valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings);
8506 valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, settings);
8399 valueFlowFunctionDefaultParameter(tokenlist, symboldatabase);
85078400 valueFlowUninit(tokenlist, symboldatabase, settings);
85088401 if (tokenlist->isCPP()) {
85098402 valueFlowAfterMove(tokenlist, symboldatabase, settings);
11 // After a release the DEVMINOR is incremented. MAJOR=x MINOR=y, DEVMINOR=y+1
22
33 #define CPPCHECK_MAJOR 2
4 #define CPPCHECK_MINOR 8
5 #define CPPCHECK_DEVMINOR 8
4 #define CPPCHECK_MINOR 7
5 #define CPPCHECK_DEVMINOR 7
66
77 #define STRINGIFY(x) STRING(x)
88 #define STRING(VER) #VER
00 ---
11 title: Cppcheck manual
2 subtitle: Version 2.8
2 subtitle: Version 2.7
33 author: Cppcheck team
44 lang: en
55 documentclass: report
0 release notes for cppcheck-2.8
0 release notes for cppcheck-2.9
11
2 - Lifetime analysis can now track lifetime across user-defined constructors when they are inline and using member initializer list.
3 - SymbolDatabase can now deduce iterator types from how they are specified in the library files.
4 - ValueFlow can evaluate class member functions that return known values.
5 - Improve duplicateValueTenary to not warn when used as an lvalue or when one branch has side effects
6 - Fix variableScope to not warn when variables are used in lambda functions
7 - Fix unassignedVariable warnings when using structured bindings
8 - Fix redundantInitialization warning when variable is used in a lambda
9 - Fix variableScope warnings when using if/while init-statement
10 - Improve lifetime analysis when returning variadic template expressions
11 - Detect more statements with constStatement
12 - Detect variableScope for more types
13 - Improvements to unreadVariable
14 - Detect more instances of C style casts
15 - Warn if the return value of new is discarded
16 - The pre-ValueFlow uninitialized checker now uses a different ID as legacyUninitvar
17 - Extended library format to exclude specific function argument values
16411641 }
16421642
16431643 void secondAlwaysTrueFalseWhenFirstTrueError() {
1644 check("void f(void) {\n" // #8892
1645 " const char c[1] = { \'x\' }; \n"
1646 " if(c[0] == \'x\'){;}\n"
1647 "}");
1648 ASSERT_EQUALS("[test.cpp:3]: (style) Condition 'c[0]=='x'' is always true\n", errout.str());
1649
16441650 check("void f(int x) {\n"
16451651 " if (x > 5 && x != 1)\n"
16461652 " a++;\n"
17071707 TEST_CASE(assign1);
17081708 TEST_CASE(assign2);
17091709 TEST_CASE(assign3);
1710 TEST_CASE(assign4); // #11019
17101711
17111712 // Failed allocation
17121713 TEST_CASE(failedAllocation);
18831884 " f2.a = malloc(100);\n"
18841885 " *f1 = f2;\n"
18851886 "}", false);
1887 ASSERT_EQUALS("", errout.str());
1888 }
1889
1890 void assign4() {
1891 check("struct S { int a, b, c; };\n" // #11019
1892 "void f() {\n"
1893 " struct S s;\n"
1894 " *&s.a = open(\"xx.log\", O_RDONLY);\n"
1895 " ((s).b) = open(\"xx.log\", O_RDONLY);\n"
1896 " (&s)->c = open(\"xx.log\", O_RDONLY);\n"
1897 "}\n", false);
1898 ASSERT_EQUALS("[test.c:7]: (error) Memory leak: s.a\n"
1899 "[test.c:7]: (error) Memory leak: s.b\n"
1900 "[test.c:7]: (error) Memory leak: s.c\n",
1901 errout.str());
1902
1903 check("struct S { int *p, *q; };\n" // #7705
1904 "void f(S s) {\n"
1905 " s.p = new int[10];\n"
1906 " s.q = malloc(40);\n"
1907 "}\n");
1908 ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: s.p\n"
1909 "[test.cpp:5]: (error) Memory leak: s.q\n",
1910 errout.str());
1911
1912 check("struct S** f(struct S** s) {\n" // don't throw
1913 " struct S** ret = malloc(sizeof(*ret));\n"
1914 " ret[0] = malloc(sizeof(**s));\n"
1915 " ret[0]->g = strdup(s[0]->g);\n"
1916 " return ret;\n"
1917 "}\n");
1918 ASSERT_EQUALS("", errout.str());
1919
1920 check("void run_rcmd(enum rcommand rcmd, rsh_session *sess, char *cmd) {\n"
1921 " sess->fp = popen(cmd, rcmd == RSH_PIPE_READ ? \"r\" : \"w\");\n"
1922 "}\n", false);
18861923 ASSERT_EQUALS("", errout.str());
18871924 }
18881925
21362173 " ((f)->realm) = strdup(realm);\n"
21372174 " if(f->realm == NULL) {}\n"
21382175 "}", false);
2139 TODO_ASSERT_EQUALS("[test.c:6]: (error) Memory leak: f.realm\n", "", errout.str());
2176 ASSERT_EQUALS("[test.c:6]: (error) Memory leak: f.realm\n", errout.str());
21402177 }
21412178
21422179 void customAllocation() { // #4770
18151815 "void f(S s) {}\n");
18161816 ASSERT_EQUALS("[test.cpp:2]: (performance) Function parameter 's' should be passed by const reference.\n", errout.str());
18171817
1818 check("union U {\n" // don't crash
1819 " int a;\n"
1820 " decltype(nullptr) b;\n"
1821 "};\n"
1822 "int* f(U u) { return u.b; }\n");
1823 ASSERT_EQUALS("", errout.str());
1824
18181825 Settings settings1;
18191826 settings1.platform(Settings::Win64);
18201827 check("using ui64 = unsigned __int64;\n"
18501857 check("void f(std::string str) {\n"
18511858 " std::string& s2 = str;\n"
18521859 "}");
1853 ASSERT_EQUALS("[test.cpp:2]: (style) Variable 's2' can be declared with const\n", errout.str());
1860 ASSERT_EQUALS("[test.cpp:2]: (style) Variable 's2' can be declared as reference to const\n", errout.str());
18541861
18551862 check("void f(std::string str) {\n"
18561863 " const std::string& s2 = str;\n"
20052012 " int& i = x[0];\n"
20062013 " return i;\n"
20072014 "}");
2008 ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared with const\n", errout.str());
2015 ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared as reference to const\n", errout.str());
20092016
20102017 check("int f(std::vector<int>& x) {\n"
20112018 " return x[0];\n"
20122019 "}");
2013 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared with const\n", errout.str());
2020 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
20142021
20152022 check("int f(std::vector<int> x) {\n"
20162023 " const int& i = x[0];\n"
20512058 check("const int& f(std::vector<int>& x) {\n"
20522059 " return x[0];\n"
20532060 "}");
2054 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared with const\n", errout.str());
2061 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
20552062
20562063 check("int f(std::vector<int>& x) {\n"
20572064 " x[0]++;\n"
21682175 " for(auto x:v)\n"
21692176 " x = 1;\n"
21702177 "}");
2171 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared with const\n", errout.str());
2178 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str());
21722179
21732180 check("void f(std::vector<int>& v) {\n"
21742181 " for(auto& x:v) {}\n"
21752182 "}");
2176 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared with const\n", errout.str());
2183 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str());
21772184
21782185 check("void f(std::vector<int>& v) {\n"
21792186 " for(const auto& x:v) {}\n"
21802187 "}");
2181 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared with const\n", errout.str());
2188 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str());
21822189
21832190 check("void f(int& i) {\n"
21842191 " int& j = i;\n"
22822289 " a x;\n"
22832290 " x(i);\n"
22842291 "}\n");
2285 ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'i' can be declared with const\n", errout.str());
2292 ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'i' can be declared as reference to const\n", errout.str());
22862293
22872294 //cast or assignment to a non-const reference should prevent the warning
22882295 check("struct T { void dostuff() const {}};\n"
22892296 "void a(T& x) {\n"
22902297 " x.dostuff();\n"
22912298 "}");
2292 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
2299 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
22932300 check("struct T : public U { void dostuff() const {}};\n"
22942301 "void a(T& x) {\n"
22952302 " x.dostuff();\n"
23032310 " x.dostuff();\n"
23042311 " const U& y = x\n"
23052312 "}");
2306 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
2313 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
23072314 check("struct T : public U { void dostuff() const {}};\n"
23082315 "void a(T& x) {\n"
23092316 " x.dostuff();\n"
23242331 " const U& y = static_cast<const U&>(x)\n"
23252332 " y.mutate();\n" //to avoid warnings that y can be const
23262333 "}");
2327 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
2334 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
23282335 check("struct T : public U { void dostuff() const {}};\n"
23292336 "void a(T& x) {\n"
23302337 " x.dostuff();\n"
23372344 " x.dostuff();\n"
23382345 " const U& y = dynamic_cast<const U&>(x)\n"
23392346 "}");
2340 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
2347 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
23412348 check(
23422349 "struct T : public U { void dostuff() const {}};\n"
23432350 "void a(T& x) {\n"
23452352 " const U& y = dynamic_cast<U const &>(x)\n"
23462353 "}"
23472354 );
2348 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
2355 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
23492356 check("struct T : public U { void dostuff() const {}};\n"
23502357 "void a(T& x) {\n"
23512358 " x.dostuff();\n"
23522359 " const U& y = dynamic_cast<U & const>(x)\n"
23532360 "}");
2354 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
2361 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
23552362 check("struct T : public U { void dostuff() const {}};\n"
23562363 "void a(T& x) {\n"
23572364 " x.dostuff();\n"
23642371 " x.dostuff();\n"
23652372 " const U& y = dynamic_cast<typename const U&>(x)\n"
23662373 "}");
2367 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
2374 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
23682375 check("struct T : public U { void dostuff() const {}};\n"
23692376 "void a(T& x) {\n"
23702377 " x.dostuff();\n"
24352442 " x.dostuff();\n"
24362443 " const U& y = (const U&)(x)\n"
24372444 "}");
2438 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
2445 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
24392446 check("struct T : public U { void dostuff() const {}};\n"
24402447 "void a(T& x) {\n"
24412448 " x.dostuff();\n"
24482455 " x.dostuff();\n"
24492456 " const U& y = (typename const U&)(x)\n"
24502457 "}");
2451 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
2458 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
24522459 check("struct T : public U { void dostuff() const {}};\n"
24532460 "void a(T& x) {\n"
24542461 " x.dostuff();\n"
24872494 "void f(int& i) {\n"
24882495 " a()(i);\n"
24892496 "}\n");
2490 ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'i' can be declared with const\n", errout.str());
2497 ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'i' can be declared as reference to const\n", errout.str());
24912498
24922499 // #9767
24932500 check("void fct1(MyClass& object) {\n"
27362743 " : c(i)\n"
27372744 "{\n"
27382745 "}");
2739 TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared with const\n", "", errout.str());
2746 TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared as reference to const\n", "", errout.str());
27402747
27412748 check("class C\n"
27422749 "{\n"
27572764 " : c(i)\n"
27582765 "{\n"
27592766 "}");
2760 TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared with const\n", "", errout.str());
2767 TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared as reference to const\n", "", errout.str());
27612768
27622769 check("class C\n"
27632770 "{\n"
27782785 " : c(0, i)\n"
27792786 "{\n"
27802787 "}");
2781 TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared with const\n", "", errout.str());
2788 TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared as reference to const\n", "", errout.str());
27822789
27832790 check("void f(std::map<int, std::vector<int>> &map) {\n" // #10266
27842791 " for (auto &[slave, panels] : map)\n"
28312838 void constParameterCallback() {
28322839 check("int callback(std::vector<int>& x) { return x[0]; }\n"
28332840 "void f() { dostuff(callback); }");
2834 ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Parameter 'x' can be declared with const. However it seems that 'callback' is a callback function, if 'x' is declared with const you might also need to cast function pointer(s).\n", errout.str());
2841 ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:1]: (style) Parameter 'x' can be declared as reference to const. However it seems that 'callback' is a callback function, if 'x' is declared with const you might also need to cast function pointer(s).\n", errout.str());
28352842
28362843 // #9906
28372844 check("class EventEngine : public IEventEngine {\n"
28492856 "void EventEngine::signalEvent(ev::sig& signal, int revents) {\n"
28502857 " switch (signal.signum) {}\n"
28512858 "}");
2852 ASSERT_EQUALS("[test.cpp:10] -> [test.cpp:13]: (style) Parameter 'signal' can be declared with const. However it seems that 'signalEvent' is a callback function, if 'signal' is declared with const you might also need to cast function pointer(s).\n", errout.str());
2859 ASSERT_EQUALS("[test.cpp:10] -> [test.cpp:13]: (style) Parameter 'signal' can be declared as reference to const. However it seems that 'signalEvent' is a callback function, if 'signal' is declared with const you might also need to cast function pointer(s).\n", errout.str());
28532860 }
28542861
28552862 void constPointer() {
28562863 check("void foo(int *p) { return *p; }");
2857 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2864 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28582865
28592866 check("void foo(int *p) { x = *p; }");
2860 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2867 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28612868
28622869 check("void foo(int *p) { int &ref = *p; ref = 12; }");
28632870 ASSERT_EQUALS("", errout.str());
28642871
28652872 check("void foo(int *p) { x = *p + 10; }");
2866 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2873 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28672874
28682875 check("void foo(int *p) { return p[10]; }");
2869 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2876 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28702877
28712878 check("void foo(int *p) { int &ref = p[0]; ref = 12; }");
28722879 ASSERT_EQUALS("", errout.str());
28732880
28742881 check("void foo(int *p) { x[*p] = 12; }");
2875 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2882 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28762883
28772884 check("void foo(int *p) { if (p) {} }");
2878 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2885 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28792886
28802887 check("void foo(int *p) { if (p || x) {} }");
2881 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2888 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28822889
28832890 check("void foo(int *p) { if (p == 0) {} }");
2884 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2891 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28852892
28862893 check("void foo(int *p) { if (!p) {} }");
2887 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2894 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28882895
28892896 check("void foo(int *p) { if (*p > 123) {} }");
2890 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2897 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28912898
28922899 check("void foo(int *p) { return *p + 1; }");
2893 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2900 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28942901
28952902 check("void foo(int *p) { return *p > 1; }");
2896 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
2903 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
28972904
28982905 check("void foo(const int* c) { if (c == 0) {}; }");
28992906 ASSERT_EQUALS("", errout.str());
29943001 " static int i[1] = {};\n"
29953002 " return i[0];\n"
29963003 "}\n");
2997 ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared with const\n", errout.str());
3004 ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared as const array\n", errout.str());
29983005
29993006 check("int f() {\n"
30003007 " static int i[] = { 0 };\n"
30013008 " int j = i[0] + 1;\n"
30023009 " return j;\n"
30033010 "}\n");
3004 ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared with const\n", errout.str());
3011 ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared as const array\n", errout.str());
30053012
30063013 // #10471
30073014 check("void f(std::array<int, 1> const& i) {\n"
30243031 " for (const auto* p : v)\n"
30253032 " if (p == nullptr) {}\n"
30263033 "}\n");
3027 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared with const\n", errout.str());
3034 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str());
30283035
30293036 check("void f(std::vector<const int*>& v) {\n"
30303037 " for (const auto& p : v)\n"
30323039 " for (const auto* p : v)\n"
30333040 " if (p == nullptr) {}\n"
30343041 "}\n");
3035 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared with const\n", errout.str());
3042 ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str());
30363043
30373044 check("void f(const std::vector<const int*>& v) {\n"
30383045 " for (const auto& p : v)\n"
30703077 " tmp = b[i];\n"
30713078 " printf(\"%s\", tmp);\n"
30723079 "}\n");
3073 ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' can be declared with const\n"
3074 "[test.cpp:4]: (style) Variable 'b' can be declared with const\n",
3080 ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' can be declared as const array\n"
3081 "[test.cpp:4]: (style) Variable 'b' can be declared as const array\n",
30753082 errout.str());
3083
3084 check("typedef void* HWND;\n"
3085 "void f(const HWND h) {\n"
3086 " if (h == nullptr) {}\n"
3087 "}\n");
3088 ASSERT_EQUALS("", errout.str());
3089
3090 check("using HWND = void*;\n"
3091 "void f(const HWND h) {\n"
3092 " if (h == nullptr) {}\n"
3093 "}\n");
3094 ASSERT_EQUALS("", errout.str());
3095
3096 check("typedef int A;\n"
3097 "void f(A* x) {\n"
3098 " if (x == nullptr) {}\n"
3099 "}\n");
3100 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str());
3101
3102 check("using A = int;\n"
3103 "void f(A* x) {\n"
3104 " if (x == nullptr) {}\n"
3105 "}\n");
3106 ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str());
30763107 }
30773108
30783109 void switchRedundantAssignmentTest() {
52465277
52475278 // #5535: Reference named like its type
52485279 check("void foo() { UMSConfig& UMSConfig = GetUMSConfiguration(); }");
5249 ASSERT_EQUALS("[test.cpp:1]: (style) Variable 'UMSConfig' can be declared with const\n", errout.str());
5280 ASSERT_EQUALS("[test.cpp:1]: (style) Variable 'UMSConfig' can be declared as reference to const\n", errout.str());
52505281
52515282 // #3868 - false positive (same expression on both sides of |)
52525283 check("void f(int x) {\n"
92729303 " int local_argc = 0;\n"
92739304 " local_argv[local_argc++] = argv[0];\n"
92749305 "}\n", "test.c");
9275 ASSERT_EQUALS("[test.c:1]: (style) Parameter 'argv' can be declared with const\n", errout.str());
9306 ASSERT_EQUALS("[test.c:1]: (style) Parameter 'argv' can be declared as const array\n", errout.str());
92769307
92779308 check("void f() {\n"
92789309 " int x = 0;\n"
77437743 ASSERT_EQUALS("const signed int", typeOf("; const auto x = 3;", "x"));
77447744 ASSERT_EQUALS("const signed int", typeOf("; constexpr auto x = 3;", "x"));
77457745 ASSERT_EQUALS("const signed int", typeOf("; const constexpr auto x = 3;", "x"));
7746 ASSERT_EQUALS("void * const", typeOf("typedef void* HWND; const HWND x = 0;", "x"));
77467747
77477748 // Variable declaration
77487749 ASSERT_EQUALS("char *", typeOf("; char abc[] = \"abc\";", "["));
150150 TEST_CASE(localvaralias17); // ticket #8911
151151 TEST_CASE(localvaralias18); // ticket #9234 - iterator
152152 TEST_CASE(localvaralias19); // ticket #9828
153 TEST_CASE(localvaralias20); // ticket #10966
153154 TEST_CASE(localvarasm);
154155 TEST_CASE(localvarstatic);
155156 TEST_CASE(localvarextern);
46734674 ASSERT_EQUALS("", errout.str());
46744675 }
46754676
4677 void localvaralias20() { // #10966
4678 functionVariableUsage("struct A {};\n"
4679 "A g();\n"
4680 "void f() {\n"
4681 " const auto& a = g();\n"
4682 " const auto& b = a;\n"
4683 " const auto&& c = g();\n"
4684 " auto&& d = c;\n"
4685 "}\n");
4686 TODO_ASSERT_EQUALS("[test.cpp:5]: (style) Variable 'b' is assigned a value that is never used.\n"
4687 "[test.cpp:7]: (style) Variable 'd' is assigned a value that is never used.\n",
4688 "[test.cpp:7]: (style) Variable 'd' is assigned a value that is never used.\n",
4689 errout.str());
4690 }
4691
46764692 void localvarasm() {
46774693
46784694 functionVariableUsage("void foo(int &b)\n"
753753 " return x[0];\n"
754754 "}";
755755 ASSERT_EQUALS(0, valueOfTok(code, "[").intvalue);
756
757 code = "int g() { return 3; }\n"
758 "void f() {\n"
759 " const int x[2] = { g(), g() };\n"
760 " return x[0];\n"
761 "}\n";
762 ASSERT_EQUALS(3, valueOfTok(code, "[ 0").intvalue);
763
764 code = "int g() { return 3; }\n"
765 "void f() {\n"
766 " const int x[2] = { g(), g() };\n"
767 " return x[1];\n"
768 "}\n";
769 ASSERT_EQUALS(3, valueOfTok(code, "[ 1").intvalue);
756770 }
757771
758772 void valueFlowMove() {
152152 TEST_CASE(varid_templateNamespaceFuncPtr); // #4172
153153 TEST_CASE(varid_templateArray);
154154 TEST_CASE(varid_templateParameter); // #7046 set varid for "X": std::array<int,X> Y;
155 TEST_CASE(varid_templateParameterFunctionPointer); // #11050
155156 TEST_CASE(varid_templateUsing); // #5781 #7273
156157 TEST_CASE(varid_not_template_in_condition); // #7988
157158 TEST_CASE(varid_cppcast); // #6190
23532354 const char code[] = "std::optional<N::Foo<A>> Foo;\n"; // #11003
23542355
23552356 ASSERT_EQUALS("1: std :: optional < N :: Foo < A > > Foo@1 ;\n",
2357 tokenize(code));
2358 }
2359 }
2360
2361 void varid_templateParameterFunctionPointer() {
2362 {
2363 const char code[] = "template <class, void (*F)()>\n"
2364 "struct a;\n";
2365
2366 ASSERT_EQUALS("1: template < class , void ( * F ) ( ) >\n"
2367 "2: struct a ;\n",
23562368 tokenize(code));
23572369 }
23582370 }
241241 << " $(warning Usage of SRCDIR to activate match compiler is deprecated. Use MATCHCOMPILER=yes instead.)\n"
242242 << " MATCHCOMPILER:=yes\n"
243243 << "endif\n";
244 // TODO: bail out when matchcompiler.py fails (i.e. invalid PYTHON_INTERPRETER specified)
245 // TODO: handle "PYTHON_INTERPRETER="
244246 fout << "ifeq ($(MATCHCOMPILER),yes)\n"
245247 << " # Find available Python interpreter\n"
246 << " ifndef PYTHON_INTERPRETER\n"
248 << " ifeq ($(PYTHON_INTERPRETER),)\n"
247249 << " PYTHON_INTERPRETER := $(shell which python3)\n"
248250 << " endif\n"
249 << " ifndef PYTHON_INTERPRETER\n"
251 << " ifeq ($(PYTHON_INTERPRETER),)\n"
250252 << " PYTHON_INTERPRETER := $(shell which python)\n"
251253 << " endif\n"
252 << " ifndef PYTHON_INTERPRETER\n"
254 << " ifeq ($(PYTHON_INTERPRETER),)\n"
253255 << " $(error Did not find a Python interpreter)\n"
254256 << " endif\n"
255257 << " ifdef VERIFY\n"
423425 fout << "run-dmake: dmake\n";
424426 fout << "\t./dmake\n\n";
425427 fout << "clean:\n";
426 fout << "\trm -f build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/*/*.o testrunner dmake cppcheck cppcheck.exe cppcheck.1\n\n";
428 fout << "\trm -f build/*.cpp build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/*/*.o testrunner dmake cppcheck cppcheck.exe cppcheck.1\n\n";
427429 fout << "man:\tman/cppcheck.1\n\n";
428430 fout << "man/cppcheck.1:\t$(MAN_SOURCE)\n\n";
429431 fout << "\t$(XP) $(DB2MAN) $(MAN_SOURCE)\n\n";
493495 fout << "\txmllint --noout --relaxng cppcheck-errors.rng /tmp/errorlist.xml\n";
494496 fout << "\txmllint --noout --relaxng cppcheck-errors.rng /tmp/example.xml\n";
495497 fout << "\ncheckCWEEntries: /tmp/errorlist.xml\n";
496 fout << "\t./tools/listErrorsWithoutCWE.py -F /tmp/errorlist.xml\n";
498 // TODO: handle "PYTHON_INTERPRETER="
499 fout << "\t$(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(shell which python3)))\n";
500 fout << "\t$(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(shell which python)))\n";
501 fout << "\t$(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(error Did not find a Python interpreter)))\n";
502 fout << "\t$(PYTHON_INTERPRETER) tools/listErrorsWithoutCWE.py -F /tmp/errorlist.xml\n";
497503 fout << ".PHONY: validateRules\n";
498504 fout << "validateRules:\n";
499505 fout << "\txmllint --noout rules/*.xml\n";
2424 # Version scheme (MAJOR.MINOR.PATCH) should orientate on "Semantic Versioning" https://semver.org/
2525 # Every change in this script should result in increasing the version number accordingly (exceptions may be cosmetic
2626 # changes)
27 SERVER_VERSION = "1.3.24"
28
29 OLD_VERSION = '2.7'
27 SERVER_VERSION = "1.3.25"
28
29 OLD_VERSION = '2.8'
3030
3131
3232 # Set up logging
1010 CPPCHECK=$(pwd)/bin/cppcheck
1111 fi
1212
13 python $DIR/extracttests.py --code=$(pwd)/test1 $1
13 python3 $DIR/extracttests.py --code=$(pwd)/test1 $1
1414
1515 cd test1
1616
262262 const QStringList lines = item->text().split("\n");
263263 if (lines.size() < 2)
264264 return;
265 const QString url = lines[0];
265 const QString &url = lines[0];
266266 QString msg = lines[1];
267267 const QRegularExpressionMatch matchRes = mVersionRe.match(msg);
268268 if (matchRes.hasMatch())