diff --git a/.clang-tidy b/.clang-tidy
index 960abc5..4e769db 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,5 +1,5 @@
 ---
-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'
+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'
 WarningsAsErrors: '*'
 CheckOptions:
   - key:             misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
diff --git a/.github/workflows/CI-unixish-docker.yml b/.github/workflows/CI-unixish-docker.yml
index eda91e3..b177d5d 100644
--- a/.github/workflows/CI-unixish-docker.yml
+++ b/.github/workflows/CI-unixish-docker.yml
@@ -9,7 +9,7 @@ jobs:
 
     strategy:
       matrix:
-        image: ["centos:7", "ubuntu:14.04", "ubuntu:16.04", "ubuntu:21.10"]
+        image: ["centos:7", "ubuntu:14.04", "ubuntu:16.04", "ubuntu:22.04"]
       fail-fast: false # Prefer quick result
 
     runs-on: ubuntu-20.04
@@ -23,19 +23,19 @@ jobs:
       - name: Install missing software on CentOS 7
         if: matrix.image == 'centos:7'
         run: |
-          yum install -y cmake gcc-c++ make
+          yum install -y cmake gcc-c++ make which python3
           yum install -y pcre-devel
 
       - name: Install missing software on ubuntu
         if: matrix.image != 'centos:7'
         run: |
           apt-get update
-          apt-get install -y cmake g++ make python libxml2-utils
+          apt-get install -y cmake g++ make python3 libxml2-utils
           apt-get install -y libpcre3-dev
 
       # tests require CMake 3.4
       - name: Test CMake build (no tests)
-        if: matrix.image != 'ubuntu:21.10'
+        if: matrix.image != 'ubuntu:22.04'
         run: |
           mkdir cmake.output
           cd cmake.output
@@ -44,7 +44,7 @@ jobs:
           cd ..
 
       - name: Test CMake build
-        if: matrix.image == 'ubuntu:21.10'
+        if: matrix.image == 'ubuntu:22.04'
         run: |
           mkdir cmake.output
           cd cmake.output
diff --git a/.github/workflows/asan.yml b/.github/workflows/asan.yml
index 3d8caab..34a322f 100644
--- a/.github/workflows/asan.yml
+++ b/.github/workflows/asan.yml
@@ -10,7 +10,7 @@ jobs:
     runs-on: ubuntu-20.04
 
     container:
-      image: "ubuntu:21.10"
+      image: "ubuntu:22.04"
 
     env:
       ASAN_OPTIONS: detect_stack_use_after_return=1
@@ -27,13 +27,13 @@ jobs:
         run: |
           apt-get update
           apt-get install -y make libpcre3-dev
-          apt-get install -y clang-13
+          apt-get install -y clang-14
 
       - name: Build
         run: make -j$(nproc) cppcheck testrunner HAVE_RULES=yes MATCHCOMPILER=yes VERIFY=1
         env:
-          CC: clang-13
-          CXX: clang++-13
+          CC: clang-14
+          CXX: clang++-14
           CXXFLAGS: "-fsanitize=address -O2 -g3 -DCPPCHK_GLIBCXX_DEBUG"
           CPPFLAGS: "-DCHECK_INTERNAL"
 
diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml
index 484eed2..1222aa2 100644
--- a/.github/workflows/clang-tidy.yml
+++ b/.github/workflows/clang-tidy.yml
@@ -10,7 +10,7 @@ jobs:
     runs-on: ubuntu-20.04
 
     container:
-      image: "ubuntu:21.10"
+      image: "ubuntu:22.04"
 
     env:
       QT_VERSION: 5.15.2
@@ -21,10 +21,10 @@ jobs:
       - name: Install missing software
         run: |
           apt-get update
-          apt-get install -y cmake clang-13 make
+          apt-get install -y cmake clang-14 make
           apt-get install -y libpcre3-dev
           apt-get install -y libffi7 # work around missing dependency for Qt install step
-          apt-get install -y clang-tidy-13
+          apt-get install -y clang-tidy-14
 
       - name: Cache Qt ${{ env.QT_VERSION }}
         id: cache-qt
@@ -48,8 +48,8 @@ jobs:
           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 ..
           cd ..
         env:
-          CC: clang-13
-          CXX: clang++-13
+          CC: clang-14
+          CXX: clang++-14
 
       - name: Prepare CMake dependencies
         run: |
diff --git a/.github/workflows/ubsan.yml b/.github/workflows/ubsan.yml
index 65ec763..6480cfe 100644
--- a/.github/workflows/ubsan.yml
+++ b/.github/workflows/ubsan.yml
@@ -10,7 +10,7 @@ jobs:
     runs-on: ubuntu-20.04
 
     container:
-      image: "ubuntu:21.10"
+      image: "ubuntu:22.04"
 
     env:
       UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
@@ -27,13 +27,13 @@ jobs:
         run: |
           apt-get update
           apt-get install -y make libpcre3-dev
-          apt-get install -y clang-13
+          apt-get install -y clang-14
 
       - name: Build
         run: make -j$(nproc) cppcheck testrunner HAVE_RULES=yes MATCHCOMPILER=yes VERIFY=1
         env:
-          CC: clang-13
-          CXX: clang++-13
+          CC: clang-14
+          CXX: clang++-14
           CXXFLAGS: "-fsanitize=undefined -fsanitize=nullability -fno-sanitize=signed-integer-overflow -O2 -g3 -DCPPCHK_GLIBCXX_DEBUG"
           CPPFLAGS: "-DCHECK_INTERNAL"
 
diff --git a/Makefile b/Makefile
index 70a73e1..9e6face 100644
--- a/Makefile
+++ b/Makefile
@@ -12,13 +12,13 @@ ifeq ($(SRCDIR),build)
 endif
 ifeq ($(MATCHCOMPILER),yes)
     # Find available Python interpreter
-    ifndef PYTHON_INTERPRETER
+    ifeq ($(PYTHON_INTERPRETER),)
         PYTHON_INTERPRETER := $(shell which python3)
     endif
-    ifndef PYTHON_INTERPRETER
+    ifeq ($(PYTHON_INTERPRETER),)
         PYTHON_INTERPRETER := $(shell which python)
     endif
-    ifndef PYTHON_INTERPRETER
+    ifeq ($(PYTHON_INTERPRETER),)
         $(error Did not find a Python interpreter)
     endif
     ifdef VERIFY
@@ -96,7 +96,7 @@ ifeq (clang++, $(findstring clang++,$(CXX)))
     CPPCHK_GLIBCXX_DEBUG=
 endif
 ifndef CXXFLAGS
-    CXXFLAGS=-std=c++0x -O2 -DNDEBUG -Wall -Wno-sign-compare
+    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
 endif
 
 ifeq (g++, $(findstring g++,$(CXX)))
@@ -304,7 +304,7 @@ run-dmake: dmake
 	./dmake
 
 clean:
-	rm -f build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/*/*.o testrunner dmake cppcheck cppcheck.exe cppcheck.1
+	rm -f build/*.cpp build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/*/*.o testrunner dmake cppcheck cppcheck.exe cppcheck.1
 
 man:	man/cppcheck.1
 
@@ -383,7 +383,10 @@ validateXML: createXMLExamples
 	xmllint --noout --relaxng cppcheck-errors.rng /tmp/example.xml
 
 checkCWEEntries: /tmp/errorlist.xml
-	./tools/listErrorsWithoutCWE.py -F /tmp/errorlist.xml
+	$(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(shell which python3)))
+	$(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(shell which python)))
+	$(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(error Did not find a Python interpreter)))
+	$(PYTHON_INTERPRETER) tools/listErrorsWithoutCWE.py -F /tmp/errorlist.xml
 .PHONY: validateRules
 validateRules:
 	xmllint --noout rules/*.xml
diff --git a/cfg/posix.cfg b/cfg/posix.cfg
index 92fb67b..39bfad6 100644
--- a/cfg/posix.cfg
+++ b/cfg/posix.cfg
@@ -3491,6 +3491,90 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s
       <not-bool/>
     </arg>
   </function>
+  <!-- https://man7.org/linux/man-pages/man3/lsearch.3.html -->
+  <!-- void *lfind(const void *key, const void *base, size_t *nmemb, size_t size, int(*compar)(const void *, const void *)); -->
+  <function name="lfind">
+    <returnValue type="void *"/>
+    <noreturn>false</noreturn>
+    <arg nr="1" direction="in">
+      <not-uninit/>
+      <not-null/>
+    </arg>
+    <arg nr="2" direction="in">
+      <not-uninit/>
+      <not-null/>
+    </arg>
+    <arg nr="3" direction="in">
+      <not-uninit/>
+      <not-null/>
+      <minsize type="argvalue" arg="4"/>
+    </arg>
+    <arg nr="4" direction="in">
+      <not-uninit/>
+      <not-bool/>
+      <valid>1:</valid>
+    </arg>
+    <arg nr="5" direction="in">
+      <not-uninit/>
+      <not-null/>
+    </arg>
+  </function>
+  <!-- https://man7.org/linux/man-pages/man3/lsearch.3.html -->
+  <!-- void *lsearch(const void *key, void *base, size_t *nmemb, size_t size, int(*compar)(const void *, const void *)); -->
+  <function name="lsearch">
+    <returnValue type="void *"/>
+    <noreturn>false</noreturn>
+    <arg nr="1" direction="in">
+      <not-uninit/>
+      <not-null/>
+    </arg>
+    <arg nr="2" direction="in">
+      <not-null/>
+    </arg>
+    <arg nr="3" direction="in">
+      <not-uninit/>
+      <not-null/>
+      <minsize type="argvalue" arg="4"/>
+    </arg>
+    <arg nr="4" direction="in">
+      <not-uninit/>
+      <not-bool/>
+      <valid>1:</valid>
+    </arg>
+    <arg nr="5" direction="in">
+      <not-uninit/>
+      <not-null/>
+    </arg>
+  </function>
+  <!-- https://man7.org/linux/man-pages/man3/mbsnrtowcs.3.html -->
+  <!-- size_t mbsnrtowcs(wchar_t *restrict dest, const char **restrict src, size_t nms, size_t len, mbstate_t *restrict ps) -->
+  <function name="mbsnrtowcs">
+    <returnValue type="size_t"/>
+    <use-retval/>
+    <noreturn>false</noreturn>
+    <!-- If dest is NULL, len is ignored, and the conversion proceeds as
+       above, except that the converted wide characters are not written
+       out to memory, and that no length limit exists. -->
+    <arg nr="1" direction="out"/>
+    <arg nr="2" direction="in">
+      <not-uninit/>
+      <not-null/>
+      <minsize type="argvalue" arg="3"/>
+    </arg>
+    <arg nr="3" direction="in">
+      <not-uninit/>
+      <not-null/>
+      <valid>0:</valid>
+    </arg>
+    <arg nr="4" direction="in">
+      <not-uninit/>
+      <not-bool/>
+      <valid>0:</valid>
+    </arg>
+    <!-- In both of the above cases, if ps is NULL, a static anonymous
+       state known only to the mbsrtowcs() function is used instead. -->
+    <arg nr="5" direction="in"/>
+  </function>
   <!-- https://pubs.opengroup.org/onlinepubs/9699919799/functions/regcomp.html -->
   <!-- int regcomp(regex_t *restrict preg, const char *restrict pattern, int cflags); -->
   <function name="regcomp">
diff --git a/cfg/std.cfg b/cfg/std.cfg
index 9356803..e3e73f1 100644
--- a/cfg/std.cfg
+++ b/cfg/std.cfg
@@ -7315,6 +7315,20 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init
       <not-uninit/>
     </arg>
   </function>
+  <!-- template< class ForwardIt > std::pair<ForwardIt,ForwardIt> std::minmax_element( ForwardIt first, ForwardIt last ) -->
+  <!-- template< class ForwardIt > std::pair<ForwardIt,ForwardIt> std::minmax( ForwardIt first, ForwardIt last ) -->
+  <function name="std::minmax_element,std::minmax">
+    <use-retval/>
+    <noreturn>false</noreturn>
+    <arg nr="1" direction="in">
+      <not-uninit/>
+      <iterator container="1" type="first"/>
+    </arg>
+    <arg nr="2" direction="in">
+      <not-uninit/>
+      <iterator container="1" type="last"/>
+    </arg>
+  </function>
   <!-- template<class InputIterator> typename iterator_traits<InputIterator>::difference_type std::distance (InputIterator first, InputIterator last); -->
   <function name="std::distance">
     <use-retval/>
diff --git a/cli/main.cpp b/cli/main.cpp
index 0aa46c5..dae782c 100644
--- a/cli/main.cpp
+++ b/cli/main.cpp
@@ -20,7 +20,7 @@
 /**
  *
  * @mainpage Cppcheck
- * @version 2.8
+ * @version 2.7
  *
  * @section overview_sec Overview
  * Cppcheck is a simple tool for static analysis of C/C++ code.
diff --git a/cmake/clang_tidy.cmake b/cmake/clang_tidy.cmake
index d2c1617..73c1203 100644
--- a/cmake/clang_tidy.cmake
+++ b/cmake/clang_tidy.cmake
@@ -7,7 +7,7 @@ if (NOT NPROC)
 endif()
 message(STATUS "NPROC=${NPROC}")
 
-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)
+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)
 message(STATUS "RUN_CLANG_TIDY=${RUN_CLANG_TIDY}")
 if (RUN_CLANG_TIDY)
     # disable all compiler warnings since we are just interested in the tidy ones
diff --git a/cmake/compileroptions.cmake b/cmake/compileroptions.cmake
index 684c93c..f5d4281 100644
--- a/cmake/compileroptions.cmake
+++ b/cmake/compileroptions.cmake
@@ -51,6 +51,15 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
     add_compile_options(-Wsuggest-attribute=noreturn)
     add_compile_options(-Wno-shadow)                # whenever a local variable or type declaration shadows another one
 elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+    if (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 14)
+        if (CMAKE_BUILD_TYPE MATCHES "Release" OR CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
+            # work around performance regression - see https://github.com/llvm/llvm-project/issues/53555
+            add_compile_options(-mllvm -inline-deferral)
+        endif()
+
+        # 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
+        add_compile_options(-gdwarf-4)
+    endif()
 
    add_compile_options_safe(-Wno-documentation-unknown-command)
 
@@ -86,6 +95,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    add_compile_options_safe(-Wno-tautological-type-limit-compare)
    add_compile_options_safe(-Wno-unused-member-function)
    add_compile_options(-Wno-disabled-macro-expansion)
+   add_compile_options_safe(-Wno-bitwise-instead-of-logical) # TODO: fix these
 
    # warnings we are not interested in
    add_compile_options(-Wno-four-char-constants)
diff --git a/cmake/versions.cmake b/cmake/versions.cmake
index 9be86e2..0ed0729 100644
--- a/cmake/versions.cmake
+++ b/cmake/versions.cmake
@@ -1,5 +1,5 @@
 # Version for libraries CPP
-SET(VERSION "2.8")
+SET(VERSION "2.7")
 STRING(REGEX MATCHALL "[0-9]" VERSION_PARTS "${VERSION}")
 LIST(GET VERSION_PARTS 0 VERSION_MAJOR)
 LIST(GET VERSION_PARTS 1 VERSION_MINOR)
diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp
index 348c938..240dd82 100644
--- a/lib/checkmemoryleak.cpp
+++ b/lib/checkmemoryleak.cpp
@@ -725,7 +725,7 @@ void CheckMemoryLeakStructMember::check()
 
     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Variable* var : symbolDatabase->variableList()) {
-        if (!var || !var->isLocal() || var->isStatic() || var->isReference())
+        if (!var || (!var->isLocal() && !(var->isArgument() && var->scope())) || var->isStatic() || var->isReference())
             continue;
         if (var->typeEndToken()->isStandardType())
             continue;
@@ -789,7 +789,31 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
         return deallocated;
     };
 
-    for (const Token *tok2 = variable->nameToken(); tok2 && tok2 != variable->scope()->bodyEnd; tok2 = tok2->next()) {
+    // return { memberTok, rhsTok }
+    auto isMemberAssignment = [](const Token* varTok, int varId) -> std::pair<const Token*, const Token*> {
+        if (varTok->varId() != varId)
+            return {};
+        const Token* top = varTok;
+        while (top->astParent()) {
+            if (top->astParent()->str() == "(")
+                return {};
+            top = top->astParent();
+        }
+        if (!Token::simpleMatch(top, "=") || !precedes(varTok, top))
+            return {};
+        const Token* dot = top->astOperand1();
+        while (dot && dot->str() != ".")
+            dot = dot->astOperand1();
+        if (!dot)
+            return {};
+        return { dot->astOperand2(), top->next() };
+    };
+    std::pair<const Token*, const Token*> assignToks;
+
+    const Token* tokStart = variable->nameToken();
+    if (variable->isArgument() && variable->scope())
+        tokStart = variable->scope()->bodyStart->next();
+    for (const Token *tok2 = tokStart; tok2 && tok2 != variable->scope()->bodyEnd; tok2 = tok2->next()) {
         if (tok2->str() == "{")
             ++indentlevel2;
 
@@ -805,12 +829,12 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
             break;
 
         // Struct member is allocated => check if it is also properly deallocated..
-        else if (Token::Match(tok2->previous(), "[;{}] %varid% . %var% =", variable->declarationId())) {
-            if (getAllocationType(tok2->tokAt(4), tok2->tokAt(2)->varId()) == AllocType::No)
+        else if ((assignToks = isMemberAssignment(tok2, variable->declarationId())).first && assignToks.first->varId()) {
+            if (getAllocationType(assignToks.second, assignToks.first->varId()) == AllocType::No)
                 continue;
 
             const int structid(variable->declarationId());
-            const int structmemberid(tok2->tokAt(2)->varId());
+            const int structmemberid(assignToks.first->varId());
 
             // This struct member is allocated.. check that it is deallocated
             int indentlevel3 = indentlevel2;
diff --git a/lib/checkother.cpp b/lib/checkother.cpp
index 25cba3e..03c617a 100644
--- a/lib/checkother.cpp
+++ b/lib/checkother.cpp
@@ -1178,7 +1178,7 @@ static int estimateSize(const Type* type, const Settings* settings, const Symbol
             size = settings->sizeof_pointer;
         else if (var.type() && var.type()->classScope)
             size = estimateSize(var.type(), settings, symbolDatabase, recursionDepth+1);
-        else if (var.valueType()->type == ValueType::Type::CONTAINER)
+        else if (var.valueType() && var.valueType()->type == ValueType::Type::CONTAINER)
             size = 3 * settings->sizeof_pointer; // Just guess
         else
             size = symbolDatabase->sizeOfType(var.typeStartToken());
@@ -1600,6 +1600,8 @@ void CheckOther::checkConstPointer()
             const int indirect = p->isArray() ? p->dimensions().size() : 1;
             if (isVariableChanged(start, p->scope()->bodyEnd, indirect, p->declarationId(), false, mSettings, mTokenizer->isCPP()))
                 continue;
+            if (p->isArgument() && p->typeStartToken() && p->typeStartToken()->isSimplifiedTypedef() && !(Token::simpleMatch(p->typeEndToken(), "*") && !p->typeEndToken()->isSimplifiedTypedef()))
+                continue;
             constVariableError(p, nullptr);
         }
     }
@@ -1615,10 +1617,11 @@ void CheckOther::constVariableError(const Variable *var, const Function *functio
 
     const std::string vartype(var->isArgument() ? "Parameter" : "Variable");
     const std::string varname(var->name());
+    const std::string ptrRefArray = var->isArray() ? "const array" : (var->isPointer() ? "pointer to const" : "reference to const");
 
     ErrorPath errorPath;
     std::string id = "const" + vartype;
-    std::string message = "$symbol:" + varname + "\n" + vartype + " '$symbol' can be declared with const";
+    std::string message = "$symbol:" + varname + "\n" + vartype + " '$symbol' can be declared as " + ptrRefArray;
     errorPath.push_back(ErrorPathItem(var ? var->nameToken() : nullptr, message));
     if (var && var->isArgument() && function && function->functionPointerUsage) {
         errorPath.push_front(ErrorPathItem(function->functionPointerUsage, "You might need to cast the function pointer here"));
diff --git a/lib/token.h b/lib/token.h
index 8377a43..8edf527 100644
--- a/lib/token.h
+++ b/lib/token.h
@@ -602,6 +602,13 @@ public:
         setFlag(fIncompleteVar, b);
     }
 
+    bool isSimplifiedTypedef() const {
+        return getFlag(fIsSimplifiedTypedef);
+    }
+    void isSimplifiedTypedef(bool b) {
+        setFlag(fIsSimplifiedTypedef, b);
+    }
+
     bool isIncompleteConstant() const {
         return getFlag(fIsIncompleteConstant);
     }
@@ -651,6 +658,13 @@ public:
         setFlag(fIsInline, b);
     }
 
+    bool isRestrict() const {
+        return getFlag(fIsRestrict);
+    }
+    void isRestrict(bool b) {
+        setFlag(fIsRestrict, b);
+    }
+
     bool isRemovedVoidParameter() const {
         return getFlag(fIsRemovedVoidParameter);
     }
@@ -1277,6 +1291,8 @@ private:
         fIsSimplifedScope       = (1ULL << 34), // scope added when simplifying e.g. if (int i = ...; ...)
         fIsRemovedVoidParameter = (1ULL << 35), // A void function parameter has been removed
         fIsIncompleteConstant   = (1ULL << 36),
+        fIsRestrict             = (1ULL << 37), // Is this a restrict pointer type
+        fIsSimplifiedTypedef    = (1ULL << 38),
     };
 
     Token::Type mTokType;
diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp
index 94bca1f..13546a0 100644
--- a/lib/tokenize.cpp
+++ b/lib/tokenize.cpp
@@ -1378,6 +1378,9 @@ void Tokenizer::simplifyTypedef()
                         typeEnd = typeStart;
 
                     // start substituting at the typedef name by replacing it with the type
+                    Token* replStart = tok2; // track first replaced token
+                    for (Token* tok3 = typeStart; tok3->str() != ";"; tok3 = tok3->next())
+                        tok3->isSimplifiedTypedef(true);
                     tok2->str(typeStart->str());
 
                     // restore qualification if it was removed
@@ -1386,7 +1389,7 @@ void Tokenizer::simplifyTypedef()
                             tok2 = tok2->previous();
 
                         if (globalScope) {
-                            tok2->insertToken("::");
+                            replStart = tok2->insertToken("::");
                             tok2 = tok2->next();
                         }
 
@@ -1415,7 +1418,7 @@ void Tokenizer::simplifyTypedef()
                                     startIdx = spaceIdx + 1;
                                 }
                                 tok2->previous()->insertToken(removed1.substr(startIdx));
-                                tok2->previous()->insertToken("::");
+                                replStart = tok2->previous()->insertToken("::");
                                 break;
                             }
                             idx = removed1.rfind(" ::");
@@ -1425,12 +1428,21 @@ void Tokenizer::simplifyTypedef()
                             removed1.resize(idx);
                         }
                     }
+                    replStart->isSimplifiedTypedef(true);
+                    Token* constTok = Token::simpleMatch(tok2->previous(), "const") ? tok2->previous() : nullptr;
                     // add remainder of type
                     tok2 = TokenList::copyTokens(tok2, typeStart->next(), typeEnd);
 
                     if (!pointers.empty()) {
                         for (const std::string &p : pointers) {
                             tok2->insertToken(p);
+                            tok2->isSimplifiedTypedef(true);
+                            tok2 = tok2->next();
+                        }
+                        if (constTok) {
+                            constTok->deleteThis();
+                            tok2->insertToken("const");
+                            tok2->isSimplifiedTypedef(true);
                             tok2 = tok2->next();
                         }
                     }
@@ -3750,6 +3762,13 @@ void Tokenizer::setVarIdPass1()
     for (Token *tok = list.front(); tok; tok = tok->next()) {
         if (tok->isOp())
             continue;
+        if (isCPP() && Token::simpleMatch(tok, "template <")) {
+            Token* closingBracket = tok->next()->findClosingBracket();
+            if (closingBracket)
+                tok = closingBracket;
+            continue;
+        }
+
         if (tok == functionDeclEndToken) {
             functionDeclEndStack.pop();
             functionDeclEndToken = functionDeclEndStack.empty() ? nullptr : functionDeclEndStack.top();
@@ -5491,6 +5510,8 @@ void Tokenizer::dump(std::ostream &out) const
             out << " isImplicitInt=\"true\"";
         if (tok->isComplex())
             out << " isComplex=\"true\"";
+        if (tok->isRestrict())
+            out << " isRestrict=\"true\"";
         if (tok->link())
             out << " link=\"" << tok->link() << '\"';
         if (tok->varId() > 0)
@@ -11242,11 +11263,14 @@ void Tokenizer::simplifyKeyword()
         if (keywords.find(tok->str()) != keywords.end()) {
             // Don't remove struct members
             if (!Token::simpleMatch(tok->previous(), ".")) {
-                if (tok->str().find("inline") != std::string::npos) {
-                    Token *temp = tok->next();
-                    while (temp != nullptr && Token::Match(temp, "%name%")) {
-                        temp->isInline(true);
-                        temp = temp->next();
+                const bool isinline = (tok->str().find("inline") != std::string::npos);
+                const bool isrestrict = (tok->str().find("restrict") != std::string::npos);
+                if (isinline || isrestrict) {
+                    for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
+                        if (isinline)
+                            temp->isInline(true);
+                        if (isrestrict)
+                            temp->isRestrict(true);
                     }
                 }
                 tok->deleteThis(); // Simplify..
@@ -11264,8 +11288,12 @@ void Tokenizer::simplifyKeyword()
             tok->deleteNext();
 
         if (c99) {
-            while (tok->str() == "restrict")
+            if (tok->str() == "restrict") {
+                for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
+                    temp->isRestrict(true);
+                }
                 tok->deleteThis();
+            }
 
             if (mSettings->standards.c >= Standards::C11) {
                 while (tok->str() == "_Atomic")
diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp
index f208001..508f230 100644
--- a/lib/valueflow.cpp
+++ b/lib/valueflow.cpp
@@ -937,53 +937,6 @@ static void setTokenValue(Token* tok, ValueFlow::Value value, const Settings* se
         }
     }
 
-    // Array element
-    else if (parent->str() == "[" && parent->isBinaryOp()) {
-        for (const ValueFlow::Value &value1 : parent->astOperand1()->values()) {
-            if (!value1.isTokValue())
-                continue;
-            for (const ValueFlow::Value &value2 : parent->astOperand2()->values()) {
-                if (!value2.isIntValue())
-                    continue;
-                if (value1.varId == 0 || value2.varId == 0 ||
-                    (value1.varId == value2.varId && value1.varvalue == value2.varvalue)) {
-                    ValueFlow::Value result(0);
-                    result.condition = value1.condition ? value1.condition : value2.condition;
-                    result.setInconclusive(value1.isInconclusive() | value2.isInconclusive());
-                    result.varId = (value1.varId != 0) ? value1.varId : value2.varId;
-                    result.varvalue = (result.varId == value1.varId) ? value1.intvalue : value2.intvalue;
-                    if (value1.valueKind == value2.valueKind)
-                        result.valueKind = value1.valueKind;
-                    if (value1.tokvalue->tokType() == Token::eString) {
-                        const std::string s = value1.tokvalue->strValue();
-                        const MathLib::bigint index = value2.intvalue;
-                        if (index == s.size()) {
-                            result.intvalue = 0;
-                            setTokenValue(parent, result, settings);
-                        } else if (index >= 0 && index < s.size()) {
-                            result.intvalue = s[index];
-                            setTokenValue(parent, result, settings);
-                        }
-                    } else if (value1.tokvalue->str() == "{") {
-                        MathLib::bigint index = value2.intvalue;
-                        const Token *element = value1.tokvalue->next();
-                        while (index > 0 && element->str() != "}") {
-                            if (element->str() == ",")
-                                --index;
-                            if (Token::Match(element, "[{}()[]]"))
-                                break;
-                            element = element->next();
-                        }
-                        if (Token::Match(element, "%num% [,}]")) {
-                            result.intvalue = MathLib::toLongNumber(element->str());
-                            setTokenValue(parent, result, settings);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     else if (Token::Match(parent, ":: %name%") && parent->astOperand2() == tok) {
         setTokenValue(parent, value, settings);
     }
@@ -1405,6 +1358,67 @@ static void valueFlowArrayBool(TokenList *tokenlist)
     }
 }
 
+static void valueFlowArrayElement(TokenList* tokenlist, const Settings* settings)
+{
+    for (Token* tok = tokenlist->front(); tok; tok = tok->next()) {
+        if (!Token::simpleMatch(tok, "["))
+            continue;
+        if (!tok->isBinaryOp())
+            continue;
+        if (tok->hasKnownIntValue())
+            continue;
+        const Token* indexTok = tok->astOperand2();
+        const Token* arrayTok = tok->astOperand1();
+
+        for (const ValueFlow::Value& arrayValue : arrayTok->values()) {
+            if (!arrayValue.isTokValue())
+                continue;
+            for (const ValueFlow::Value& indexValue : indexTok->values()) {
+                if (!indexValue.isIntValue())
+                    continue;
+                if (arrayValue.varId != 0 && indexValue.varId != 0 &&
+                    !(arrayValue.varId == indexValue.varId && arrayValue.varvalue == indexValue.varvalue))
+                    continue;
+
+                ValueFlow::Value result(0);
+                result.condition = arrayValue.condition ? arrayValue.condition : indexValue.condition;
+                result.setInconclusive(arrayValue.isInconclusive() | indexValue.isInconclusive());
+                result.varId = (arrayValue.varId != 0) ? arrayValue.varId : indexValue.varId;
+                result.varvalue = (result.varId == arrayValue.varId) ? arrayValue.intvalue : indexValue.intvalue;
+                if (arrayValue.valueKind == indexValue.valueKind)
+                    result.valueKind = arrayValue.valueKind;
+
+                result.errorPath.insert(result.errorPath.end(), arrayValue.errorPath.begin(), arrayValue.errorPath.end());
+                result.errorPath.insert(result.errorPath.end(), indexValue.errorPath.begin(), indexValue.errorPath.end());
+
+                const MathLib::bigint index = indexValue.intvalue;
+
+                if (arrayValue.tokvalue->tokType() == Token::eString) {
+                    const std::string s = arrayValue.tokvalue->strValue();
+                    if (index == s.size()) {
+                        result.intvalue = 0;
+                        setTokenValue(tok, result, settings);
+                    } else if (index >= 0 && index < s.size()) {
+                        result.intvalue = s[index];
+                        setTokenValue(tok, result, settings);
+                    }
+                } else if (Token::simpleMatch(arrayValue.tokvalue, "{")) {
+                    std::vector<const Token*> args = getArguments(arrayValue.tokvalue);
+                    if (index < 0 || index >= args.size())
+                        continue;
+                    const Token* arg = args[index];
+                    if (!arg->hasKnownIntValue())
+                        continue;
+                    const ValueFlow::Value& v = arg->values().front();
+                    result.intvalue = v.intvalue;
+                    result.errorPath.insert(result.errorPath.end(), v.errorPath.begin(), v.errorPath.end());
+                    setTokenValue(tok, result, settings);
+                }
+            }
+        }
+    }
+}
+
 static void valueFlowPointerAlias(TokenList *tokenlist)
 {
     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
@@ -1813,20 +1827,78 @@ static void valueFlowGlobalStaticVar(TokenList *tokenList, const Settings *setti
     }
 }
 
+ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist);
+ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist);
+
+static Analyzer::Result valueFlowForward(Token* startToken,
+                                         const Token* endToken,
+                                         const Token* exprTok,
+                                         const ValueFlow::Value& value,
+                                         TokenList* const tokenlist)
+{
+    return valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, value, tokenlist), tokenlist->getSettings());
+}
+
 static Analyzer::Result valueFlowForward(Token* startToken,
                                          const Token* endToken,
                                          const Token* exprTok,
                                          const std::list<ValueFlow::Value>& values,
-                                         TokenList* const tokenlist,
-                                         const Settings* settings);
+                                         TokenList* const tokenlist)
+{
+    Analyzer::Result result{};
+    for (const ValueFlow::Value& v : values) {
+        result.update(valueFlowForward(startToken, endToken, exprTok, v, tokenlist));
+    }
+    return result;
+}
+
+template<class ValueOrValues>
+static Analyzer::Result valueFlowForward(Token* startToken, const Token* exprTok, const ValueOrValues& v, TokenList* tokenlist)
+{
+    const Token* endToken = nullptr;
+    const Function* f = Scope::nestedInFunction(startToken->scope());
+    if (f && f->functionScope)
+        endToken = f->functionScope->bodyEnd;
+    return valueFlowForward(startToken, endToken, exprTok, v, tokenlist);
+}
+
+static Analyzer::Result valueFlowForwardRecursive(Token* top,
+                                                  const Token* exprTok,
+                                                  const std::list<ValueFlow::Value>& values,
+                                                  TokenList* const tokenlist)
+{
+    Analyzer::Result result{};
+    for (const ValueFlow::Value& v : values) {
+        result.update(valueFlowGenericForward(top, makeAnalyzer(exprTok, v, tokenlist), tokenlist->getSettings()));
+    }
+    return result;
+}
+
+static void valueFlowReverse(Token* tok,
+                             const Token* const endToken,
+                             const Token* const varToken,
+                             const std::list<ValueFlow::Value>& values,
+                             TokenList* tokenlist)
+{
+    for (const ValueFlow::Value& v : values) {
+        valueFlowGenericReverse(tok, endToken, makeReverseAnalyzer(varToken, v, tokenlist), tokenlist->getSettings());
+    }
+}
 
+// Deprecated
 static void valueFlowReverse(TokenList* tokenlist,
                              Token* tok,
                              const Token* const varToken,
                              ValueFlow::Value val,
                              const ValueFlow::Value& val2,
-                             ErrorLogger* errorLogger,
-                             const Settings* settings);
+                             ErrorLogger* /*errorLogger*/,
+                             const Settings* = nullptr)
+{
+    std::list<ValueFlow::Value> values = {val};
+    if (val2.varId != 0)
+        values.push_back(val2);
+    valueFlowReverse(tok, nullptr, varToken, values, tokenlist);
+}
 
 static bool isConditionKnown(const Token* tok, bool then)
 {
@@ -2633,8 +2705,6 @@ struct ValueFlowAnalyzer : Analyzer {
     }
 };
 
-ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist);
-
 struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
     std::unordered_map<nonneg int, const Variable*> varids;
     std::unordered_map<nonneg int, const Variable*> aliases;
@@ -2930,162 +3000,6 @@ struct MemberExpressionAnalyzer : SubExpressionAnalyzer {
     }
 };
 
-static Analyzer::Result valueFlowForwardExpression(Token* startToken,
-                                                   const Token* endToken,
-                                                   const Token* exprTok,
-                                                   const std::list<ValueFlow::Value>& values,
-                                                   const TokenList* const tokenlist,
-                                                   const Settings* settings)
-{
-    Analyzer::Result result{};
-    for (const ValueFlow::Value& v : values) {
-        ExpressionAnalyzer a(exprTok, v, tokenlist);
-        result.update(valueFlowGenericForward(startToken, endToken, a, settings));
-    }
-    return result;
-}
-
-static const Token* parseBinaryIntOp(const Token* expr,
-                                     const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
-                                     MathLib::bigint& known)
-{
-    if (!expr)
-        return nullptr;
-    if (!expr->astOperand1() || !expr->astOperand2())
-        return nullptr;
-    if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0)
-        return nullptr;
-    std::vector<MathLib::bigint> x1 = eval(expr->astOperand1());
-    std::vector<MathLib::bigint> x2 = eval(expr->astOperand2());
-    if (expr->astOperand1()->exprId() == 0 && x1.empty())
-        return nullptr;
-    if (expr->astOperand2()->exprId() == 0 && x2.empty())
-        return nullptr;
-    const Token* varTok = nullptr;
-    if (!x1.empty() && x2.empty()) {
-        varTok = expr->astOperand2();
-        known = x1.front();
-    } else if (x1.empty() && !x2.empty()) {
-        varTok = expr->astOperand1();
-        known = x2.front();
-    }
-    return varTok;
-}
-
-const Token* solveExprValue(const Token* expr,
-                            const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
-                            ValueFlow::Value& value)
-{
-    if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
-        return expr;
-    if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
-        return expr;
-    MathLib::bigint intval;
-    const Token* binaryTok = parseBinaryIntOp(expr, eval, intval);
-    bool rhs = astIsRHS(binaryTok);
-    // If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values
-    if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-"))
-        return expr;
-    if (binaryTok && expr->str().size() == 1) {
-        switch (expr->str()[0]) {
-        case '+': {
-            value.intvalue -= intval;
-            return solveExprValue(binaryTok, eval, value);
-        }
-        case '-': {
-            if (rhs)
-                value.intvalue = intval - value.intvalue;
-            else
-                value.intvalue += intval;
-            return solveExprValue(binaryTok, eval, value);
-        }
-        case '*': {
-            if (intval == 0)
-                break;
-            value.intvalue /= intval;
-            return solveExprValue(binaryTok, eval, value);
-        }
-        case '^': {
-            value.intvalue ^= intval;
-            return solveExprValue(binaryTok, eval, value);
-        }
-        }
-    }
-    return expr;
-}
-
-static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
-{
-    return solveExprValue(
-        expr,
-        [](const Token* tok) -> std::vector<MathLib::bigint> {
-        if (tok->hasKnownIntValue())
-            return {tok->values().front().intvalue};
-        return {};
-    },
-        value);
-}
-
-ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
-{
-    const Token* expr = solveExprValue(exprTok, value);
-    return ExpressionAnalyzer(expr, value, tokenlist);
-}
-
-static Analyzer::Result valueFlowForward(Token* startToken,
-                                         const Token* endToken,
-                                         const Token* exprTok,
-                                         const std::list<ValueFlow::Value>& values,
-                                         TokenList* const tokenlist,
-                                         const Settings* settings)
-{
-    Analyzer::Result result{};
-    for (const ValueFlow::Value& v : values) {
-        result.update(valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, v, tokenlist), settings));
-    }
-    return result;
-}
-
-static Analyzer::Result valueFlowForward(Token* top,
-                                         const Token* exprTok,
-                                         const std::list<ValueFlow::Value>& values,
-                                         TokenList* const tokenlist,
-                                         const Settings* settings)
-{
-    Analyzer::Result result{};
-    for (const ValueFlow::Value& v : values) {
-        result.update(valueFlowGenericForward(top, makeAnalyzer(exprTok, v, tokenlist), settings));
-    }
-    return result;
-}
-
-static void valueFlowReverse(Token* tok,
-                             const Token* const endToken,
-                             const Token* const varToken,
-                             const std::list<ValueFlow::Value>& values,
-                             TokenList* tokenlist,
-                             const Settings* settings)
-{
-    for (const ValueFlow::Value& v : values) {
-        ExpressionAnalyzer a(varToken, v, tokenlist);
-        valueFlowGenericReverse(tok, endToken, a, settings);
-    }
-}
-
-static void valueFlowReverse(TokenList* tokenlist,
-                             Token* tok,
-                             const Token* const varToken,
-                             ValueFlow::Value val,
-                             const ValueFlow::Value& val2,
-                             ErrorLogger* /*errorLogger*/,
-                             const Settings* settings)
-{
-    std::list<ValueFlow::Value> values = {val};
-    if (val2.varId != 0)
-        values.push_back(val2);
-    valueFlowReverse(tok, nullptr, varToken, values, tokenlist, settings);
-}
-
 enum class LifetimeCapture { Undefined, ByValue, ByReference };
 
 std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
@@ -3577,7 +3491,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
     if (Token::Match(tok->previous(), "%var% {|(") && isVariableDecl(tok->previous())) {
         std::list<ValueFlow::Value> values = tok->values();
         values.remove_if(&isNotLifetimeValue);
-        valueFlowForward(nextAfterAstRightmostLeaf(tok), getEndOfExprScope(tok), tok->previous(), values, tokenlist, settings);
+        valueFlowForward(nextAfterAstRightmostLeaf(tok), getEndOfExprScope(tok), tok->previous(), values, tokenlist);
         return;
     }
     Token *parent = tok->astParent();
@@ -3617,12 +3531,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
         const Token *nextExpression = nextAfterAstRightmostLeaf(parent);
 
         if (expr->exprId() > 0) {
-            valueFlowForwardExpression(const_cast<Token*>(nextExpression),
-                                       endOfVarScope->next(),
-                                       expr,
-                                       values,
-                                       tokenlist,
-                                       settings);
+            valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope->next(), expr, values, tokenlist);
 
             for (ValueFlow::Value& val : values) {
                 if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address)
@@ -3633,12 +3542,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
                 const Token* parentLifetime =
                     getParentLifetime(tokenlist->isCPP(), parent->astOperand1()->astOperand2(), &settings->library);
                 if (parentLifetime && parentLifetime->exprId() > 0) {
-                    valueFlowForward(const_cast<Token*>(nextExpression),
-                                     endOfVarScope,
-                                     parentLifetime,
-                                     values,
-                                     tokenlist,
-                                     settings);
+                    valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, parentLifetime, values, tokenlist);
                 }
             }
         }
@@ -3659,7 +3563,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
         const Token *nextExpression = nextAfterAstRightmostLeaf(parent);
         // Only forward lifetime values
         values.remove_if(&isNotLifetimeValue);
-        valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, tok, values, tokenlist, settings);
+        valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, tok, values, tokenlist);
         // Cast
     } else if (parent->isCast()) {
         std::list<ValueFlow::Value> values = tok->values();
@@ -4710,7 +4614,7 @@ static void valueFlowAfterMove(TokenList* tokenlist, SymbolDatabase* symboldatab
                     continue;
                 const Token * const endOfVarScope = var->scope()->bodyEnd;
                 setTokenValue(varTok, value, settings);
-                valueFlowForward(varTok->next(), endOfVarScope, varTok, values, tokenlist, settings);
+                valueFlowForward(varTok->next(), endOfVarScope, varTok, values, tokenlist);
                 continue;
             }
             ValueFlow::Value::MoveKind moveKind;
@@ -4746,8 +4650,7 @@ static void valueFlowAfterMove(TokenList* tokenlist, SymbolDatabase* symboldatab
             const Token * openParentesisOfMove = findOpenParentesisOfMove(varTok);
             const Token * endOfFunctionCall = findEndOfFunctionCallForParameter(openParentesisOfMove);
             if (endOfFunctionCall)
-                valueFlowForward(
-                    const_cast<Token*>(endOfFunctionCall), endOfVarScope, varTok, values, tokenlist, settings);
+                valueFlowForward(const_cast<Token*>(endOfFunctionCall), endOfVarScope, varTok, values, tokenlist);
         }
     }
 }
@@ -4967,13 +4870,13 @@ static void valueFlowSymbolic(TokenList* tokenlist, SymbolDatabase* symboldataba
             rhs.errorPath.emplace_back(tok,
                                        tok->astOperand1()->expressionString() + " is assigned '" +
                                        tok->astOperand2()->expressionString() + "' here.");
-            valueFlowForward(start, end, tok->astOperand1(), {rhs}, tokenlist, tokenlist->getSettings());
+            valueFlowForward(start, end, tok->astOperand1(), rhs, tokenlist);
 
             ValueFlow::Value lhs = makeSymbolic(tok->astOperand1());
             lhs.errorPath.emplace_back(tok,
                                        tok->astOperand1()->expressionString() + " is assigned '" +
                                        tok->astOperand2()->expressionString() + "' here.");
-            valueFlowForward(start, end, tok->astOperand2(), {lhs}, tokenlist, tokenlist->getSettings());
+            valueFlowForward(start, end, tok->astOperand2(), lhs, tokenlist);
         }
     }
 }
@@ -5253,7 +5156,7 @@ static void valueFlowForwardAssign(Token* const tok,
         constValues.splice(constValues.end(), values, it, values.end());
         valueFlowForwardConst(const_cast<Token*>(nextExpression), endOfVarScope, expr->variable(), constValues, settings);
     }
-    valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, expr, values, tokenlist, settings);
+    valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, expr, values, tokenlist);
 }
 
 static void valueFlowForwardAssign(Token* const tok,
@@ -5425,7 +5328,7 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat
                     value.errorPath.emplace_back(tok,
                                                  tok->astOperand1()->expressionString() + " is assigned '" +
                                                  tok->astOperand2()->expressionString() + "' here.");
-                    valueFlowForward(start, end, expr, {value}, tokenlist, settings);
+                    valueFlowForward(start, end, expr, value, tokenlist);
                 }
             }
         }
@@ -5531,27 +5434,33 @@ struct ConditionHandler {
         Condition() : vartok(nullptr), true_values(), false_values(), inverted(false), impossible(true) {}
     };
 
+    virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const = 0;
+
     virtual Analyzer::Result forward(Token* start,
                                      const Token* stop,
                                      const Token* exprTok,
                                      const std::list<ValueFlow::Value>& values,
-                                     TokenList* tokenlist,
-                                     const Settings* settings) const = 0;
+                                     TokenList* tokenlist) const
+    {
+        return valueFlowForward(start->next(), stop, exprTok, values, tokenlist);
+    }
 
     virtual Analyzer::Result forward(Token* top,
                                      const Token* exprTok,
                                      const std::list<ValueFlow::Value>& values,
-                                     TokenList* tokenlist,
-                                     const Settings* settings) const = 0;
+                                     TokenList* tokenlist) const
+    {
+        return valueFlowForwardRecursive(top, exprTok, values, tokenlist);
+    }
 
     virtual void reverse(Token* start,
                          const Token* endToken,
                          const Token* exprTok,
                          const std::list<ValueFlow::Value>& values,
-                         TokenList* tokenlist,
-                         const Settings* settings) const = 0;
-
-    virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const = 0;
+                         TokenList* tokenlist) const
+    {
+        return valueFlowReverse(start, endToken, exprTok, values, tokenlist);
+    }
 
     void traverseCondition(TokenList* tokenlist,
                            SymbolDatabase* symboldatabase,
@@ -5672,7 +5581,7 @@ struct ConditionHandler {
                     })) {
                         // Start at the end of the loop body
                         Token* bodyTok = top->link()->next();
-                        reverse(bodyTok->link(), bodyTok, cond.vartok, values, tokenlist, settings);
+                        reverse(bodyTok->link(), bodyTok, cond.vartok, values, tokenlist);
                     }
                     if (settings->debugwarnings)
                         bailout(tokenlist,
@@ -5691,7 +5600,7 @@ struct ConditionHandler {
             if (!startTok)
                 startTok = tok->previous();
 
-            reverse(startTok, nullptr, cond.vartok, values, tokenlist, settings);
+            reverse(startTok, nullptr, cond.vartok, values, tokenlist);
         });
     }
 
@@ -5778,7 +5687,7 @@ struct ConditionHandler {
                             return v.isImpossible();
                         });
                     for (Token* start:nextExprs) {
-                        Analyzer::Result r = forward(start, cond.vartok, values, tokenlist, settings);
+                        Analyzer::Result r = forward(start, cond.vartok, values, tokenlist);
                         if (r.terminate != Analyzer::Terminate::None)
                             return;
                     }
@@ -5838,8 +5747,8 @@ struct ConditionHandler {
 
             if (Token::simpleMatch(condTop, "?")) {
                 Token* colon = condTop->astOperand2();
-                forward(colon->astOperand1(), cond.vartok, thenValues, tokenlist, settings);
-                forward(colon->astOperand2(), cond.vartok, elseValues, tokenlist, settings);
+                forward(colon->astOperand1(), cond.vartok, thenValues, tokenlist);
+                forward(colon->astOperand2(), cond.vartok, elseValues, tokenlist);
                 // TODO: Handle after condition
                 return;
             }
@@ -5923,8 +5832,7 @@ struct ConditionHandler {
                 std::list<ValueFlow::Value>& values = (i == 0 ? thenValues : elseValues);
                 valueFlowSetConditionToKnown(condTok, values, i == 0);
 
-                Analyzer::Result r =
-                    forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, tokenlist, settings);
+                Analyzer::Result r = forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, tokenlist);
                 deadBranch[i] = r.terminate == Analyzer::Terminate::Escape;
                 if (r.action.isModified() && !deadBranch[i])
                     changeBlock = i;
@@ -6026,7 +5934,7 @@ struct ConditionHandler {
                 }
                 if (values.empty())
                     return;
-                forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist, settings);
+                forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist);
             }
         });
     }
@@ -6044,32 +5952,6 @@ static void valueFlowCondition(const ValuePtr<ConditionHandler>& handler,
 }
 
 struct SimpleConditionHandler : ConditionHandler {
-    virtual Analyzer::Result forward(Token* start,
-                                     const Token* stop,
-                                     const Token* exprTok,
-                                     const std::list<ValueFlow::Value>& values,
-                                     TokenList* tokenlist,
-                                     const Settings* settings) const override {
-        return valueFlowForward(start->next(), stop, exprTok, values, tokenlist, settings);
-    }
-
-    virtual Analyzer::Result forward(Token* top,
-                                     const Token* exprTok,
-                                     const std::list<ValueFlow::Value>& values,
-                                     TokenList* tokenlist,
-                                     const Settings* settings) const override {
-        return valueFlowForward(top, exprTok, values, tokenlist, settings);
-    }
-
-    virtual void reverse(Token* start,
-                         const Token* endToken,
-                         const Token* exprTok,
-                         const std::list<ValueFlow::Value>& values,
-                         TokenList* tokenlist,
-                         const Settings* settings) const override {
-        return valueFlowReverse(start, endToken, exprTok, values, tokenlist, settings);
-    }
-
     virtual std::vector<Condition> parse(const Token* tok, const Settings*) const override {
         Condition cond;
         ValueFlow::Value true_value;
@@ -6439,11 +6321,7 @@ static void valueFlowForLoopSimplify(Token* const bodyStart,
     }
 }
 
-static void valueFlowForLoopSimplifyAfter(Token* fortok,
-                                          nonneg int varid,
-                                          const MathLib::bigint num,
-                                          TokenList* tokenlist,
-                                          const Settings* settings)
+static void valueFlowForLoopSimplifyAfter(Token* fortok, nonneg int varid, const MathLib::bigint num, TokenList* tokenlist)
 {
     const Token *vartok = nullptr;
     for (const Token *tok = fortok; tok; tok = tok->next()) {
@@ -6468,7 +6346,7 @@ static void valueFlowForLoopSimplifyAfter(Token* fortok,
     values.back().errorPath.emplace_back(fortok,"After for loop, " + var->name() + " has value " + values.back().infoString());
 
     if (blockTok != endToken) {
-        valueFlowForward(blockTok->next(), endToken, vartok, values, tokenlist, settings);
+        valueFlowForward(blockTok->next(), endToken, vartok, values, tokenlist);
     }
 }
 
@@ -6496,8 +6374,7 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas
                 std::list<ValueFlow::Value> initValues;
                 initValues.emplace_back(initValue, ValueFlow::Value::Bound::Lower);
                 initValues.push_back(asImpossible(initValues.back()));
-                Analyzer::Result result =
-                    valueFlowForward(bodyStart, bodyStart->link(), vartok, initValues, tokenlist, settings);
+                Analyzer::Result result = valueFlowForward(bodyStart, bodyStart->link(), vartok, initValues, tokenlist);
 
                 if (!result.action.isModified()) {
                     std::list<ValueFlow::Value> lastValues;
@@ -6506,11 +6383,11 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas
                     lastValues.push_back(asImpossible(lastValues.back()));
                     if (stepValue != 1)
                         lastValues.pop_front();
-                    valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist, settings);
+                    valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist);
                 }
             }
             const MathLib::bigint afterValue = executeBody ? lastValue + stepValue : initValue;
-            valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist, settings);
+            valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist);
         } else {
             ProgramMemory mem1, mem2, memAfter;
             if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter)) {
@@ -6533,7 +6410,7 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas
                         continue;
                     if (p.first.tok->varId() == 0)
                         continue;
-                    valueFlowForLoopSimplifyAfter(tok, p.first.getExpressionId(), p.second.intvalue, tokenlist, settings);
+                    valueFlowForLoopSimplifyAfter(tok, p.first.getExpressionId(), p.second.intvalue, tokenlist);
                 }
             }
         }
@@ -6790,7 +6667,6 @@ static void valueFlowInjectParameter(TokenList* tokenlist,
 }
 
 static void valueFlowInjectParameter(TokenList* tokenlist,
-                                     const Settings* settings,
                                      const Variable* arg,
                                      const Scope* functionScope,
                                      const std::list<ValueFlow::Value>& argvalues)
@@ -6808,8 +6684,7 @@ static void valueFlowInjectParameter(TokenList* tokenlist,
                      functionScope->bodyEnd,
                      arg->nameToken(),
                      argvalues,
-                     tokenlist,
-                     settings);
+                     tokenlist);
 }
 
 static void valueFlowSwitchVariable(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
@@ -7032,7 +6907,7 @@ static void valueFlowSubFunction(TokenList* tokenlist, SymbolDatabase* symboldat
     }
 }
 
-static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
+static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDatabase* symboldatabase)
 {
     if (!tokenlist->isCPP())
         return;
@@ -7054,7 +6929,7 @@ static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDataba
                         argvalues.push_back(v);
                 }
                 if (!argvalues.empty())
-                    valueFlowInjectParameter(tokenlist, settings, var, scope, argvalues);
+                    valueFlowInjectParameter(tokenlist, var, scope, argvalues);
             }
         }
     }
@@ -7250,7 +7125,7 @@ static void valueFlowUninit(TokenList* tokenlist, SymbolDatabase* /*symbolDataba
         if (partial)
             continue;
 
-        valueFlowForward(tok->next(), tok->scope()->bodyEnd, var->nameToken(), {uninitValue}, tokenlist, settings);
+        valueFlowForward(tok->next(), tok->scope()->bodyEnd, var->nameToken(), uninitValue, tokenlist);
     }
 }
 
@@ -7408,48 +7283,100 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
     }
 };
 
-static Analyzer::Result valueFlowContainerForward(Token* startToken,
-                                                  const Token* endToken,
-                                                  const Token* exprTok,
-                                                  const ValueFlow::Value& value,
-                                                  TokenList* tokenlist)
+static const Token* parseBinaryIntOp(const Token* expr,
+                                     const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
+                                     MathLib::bigint& known)
 {
-    ContainerExpressionAnalyzer a(exprTok, value, tokenlist);
-    return valueFlowGenericForward(startToken, endToken, a, tokenlist->getSettings());
+    if (!expr)
+        return nullptr;
+    if (!expr->astOperand1() || !expr->astOperand2())
+        return nullptr;
+    if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0)
+        return nullptr;
+    std::vector<MathLib::bigint> x1 = eval(expr->astOperand1());
+    std::vector<MathLib::bigint> x2 = eval(expr->astOperand2());
+    if (expr->astOperand1()->exprId() == 0 && x1.empty())
+        return nullptr;
+    if (expr->astOperand2()->exprId() == 0 && x2.empty())
+        return nullptr;
+    const Token* varTok = nullptr;
+    if (!x1.empty() && x2.empty()) {
+        varTok = expr->astOperand2();
+        known = x1.front();
+    } else if (x1.empty() && !x2.empty()) {
+        varTok = expr->astOperand1();
+        known = x2.front();
+    }
+    return varTok;
+}
+
+const Token* solveExprValue(const Token* expr,
+                            const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
+                            ValueFlow::Value& value)
+{
+    if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
+        return expr;
+    if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
+        return expr;
+    MathLib::bigint intval;
+    const Token* binaryTok = parseBinaryIntOp(expr, eval, intval);
+    bool rhs = astIsRHS(binaryTok);
+    // If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values
+    if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-"))
+        return expr;
+    if (binaryTok && expr->str().size() == 1) {
+        switch (expr->str()[0]) {
+        case '+': {
+            value.intvalue -= intval;
+            return solveExprValue(binaryTok, eval, value);
+        }
+        case '-': {
+            if (rhs)
+                value.intvalue = intval - value.intvalue;
+            else
+                value.intvalue += intval;
+            return solveExprValue(binaryTok, eval, value);
+        }
+        case '*': {
+            if (intval == 0)
+                break;
+            value.intvalue /= intval;
+            return solveExprValue(binaryTok, eval, value);
+        }
+        case '^': {
+            value.intvalue ^= intval;
+            return solveExprValue(binaryTok, eval, value);
+        }
+        }
+    }
+    return expr;
 }
 
-static Analyzer::Result valueFlowContainerForwardRecursive(Token* top,
-                                                           const Token* exprTok,
-                                                           const ValueFlow::Value& value,
-                                                           TokenList* tokenlist)
+static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
 {
-    ContainerExpressionAnalyzer a(exprTok, value, tokenlist);
-    return valueFlowGenericForward(top, a, tokenlist->getSettings());
+    return solveExprValue(
+        expr,
+        [](const Token* tok) -> std::vector<MathLib::bigint> {
+        if (tok->hasKnownIntValue())
+            return {tok->values().front().intvalue};
+        return {};
+    },
+        value);
 }
 
-static Analyzer::Result valueFlowContainerForward(Token* startToken,
-                                                  const Token* exprTok,
-                                                  const ValueFlow::Value& value,
-                                                  TokenList* tokenlist)
+ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
 {
-    const Token* endToken = nullptr;
-    const Function* f = Scope::nestedInFunction(startToken->scope());
-    if (f && f->functionScope)
-        endToken = f->functionScope->bodyEnd;
-    return valueFlowContainerForward(startToken, endToken, exprTok, value, tokenlist);
+    if (value.isContainerSizeValue())
+        return ContainerExpressionAnalyzer(exprTok, value, tokenlist);
+    const Token* expr = solveExprValue(exprTok, value);
+    return ExpressionAnalyzer(expr, value, tokenlist);
 }
 
-static void valueFlowContainerReverse(Token* tok,
-                                      const Token* const endToken,
-                                      const Token* const varToken,
-                                      const std::list<ValueFlow::Value>& values,
-                                      TokenList* tokenlist,
-                                      const Settings* settings)
+ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist)
 {
-    for (const ValueFlow::Value& value : values) {
-        ContainerExpressionAnalyzer a(varToken, value, tokenlist);
-        valueFlowGenericReverse(tok, endToken, a, settings);
-    }
+    if (value.isContainerSizeValue())
+        return ContainerExpressionAnalyzer(exprTok, value, tokenlist);
+    return ExpressionAnalyzer(exprTok, value, tokenlist);
 }
 
 bool isContainerSizeChanged(const Token* tok, const Settings* settings, int depth)
@@ -7865,7 +7792,7 @@ static void valueFlowContainerSize(TokenList* tokenlist,
             if (constSize)
                 valueFlowForwardConst(var->nameToken()->next(), var->scope()->bodyEnd, var, values, settings);
             else
-                valueFlowContainerForward(var->nameToken()->next(), var->nameToken(), value, tokenlist);
+                valueFlowForward(var->nameToken()->next(), var->nameToken(), value, tokenlist);
         }
     }
 
@@ -7880,7 +7807,7 @@ static void valueFlowContainerSize(TokenList* tokenlist,
                     ValueFlow::Value value(Token::getStrLength(containerTok->tokAt(2)));
                     value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
                     value.setKnown();
-                    valueFlowContainerForward(containerTok->next(), containerTok, value, tokenlist);
+                    valueFlowForward(containerTok->next(), containerTok, value, tokenlist);
                 }
             } else if (Token::Match(tok, "%name%|;|{|}|> %var% = {") && Token::simpleMatch(tok->linkAt(3), "} ;")) {
                 const Token* containerTok = tok->next();
@@ -7890,7 +7817,7 @@ static void valueFlowContainerSize(TokenList* tokenlist,
                     std::vector<ValueFlow::Value> values =
                         getInitListSize(tok->tokAt(3), containerTok->valueType(), settings);
                     for (const ValueFlow::Value& value : values)
-                        valueFlowContainerForward(containerTok->next(), containerTok, value, tokenlist);
+                        valueFlowForward(containerTok->next(), containerTok, value, tokenlist);
                 }
             } else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() &&
                        tok->astOperand1()->valueType()->container) {
@@ -7902,13 +7829,13 @@ static void valueFlowContainerSize(TokenList* tokenlist,
                     ValueFlow::Value value(0);
                     value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
                     value.setKnown();
-                    valueFlowContainerForward(tok->next(), containerTok, value, tokenlist);
+                    valueFlowForward(tok->next(), containerTok, value, tokenlist);
                 } else if (action == Library::Container::Action::RESIZE && tok->tokAt(2)->astOperand2() &&
                            tok->tokAt(2)->astOperand2()->hasKnownIntValue()) {
                     ValueFlow::Value value(tok->tokAt(2)->astOperand2()->values().front());
                     value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
                     value.setKnown();
-                    valueFlowContainerForward(tok->next(), containerTok, value, tokenlist);
+                    valueFlowForward(tok->next(), containerTok, value, tokenlist);
                 }
             }
         }
@@ -7916,38 +7843,6 @@ static void valueFlowContainerSize(TokenList* tokenlist,
 }
 
 struct ContainerConditionHandler : ConditionHandler {
-    virtual Analyzer::Result forward(Token* start,
-                                     const Token* stop,
-                                     const Token* exprTok,
-                                     const std::list<ValueFlow::Value>& values,
-                                     TokenList* tokenlist,
-                                     const Settings*) const override {
-        Analyzer::Result result{};
-        for (const ValueFlow::Value& value : values)
-            result.update(valueFlowContainerForward(start->next(), stop, exprTok, value, tokenlist));
-        return result;
-    }
-
-    virtual Analyzer::Result forward(Token* top,
-                                     const Token* exprTok,
-                                     const std::list<ValueFlow::Value>& values,
-                                     TokenList* tokenlist,
-                                     const Settings*) const override {
-        Analyzer::Result result{};
-        for (const ValueFlow::Value& value : values)
-            result.update(valueFlowContainerForwardRecursive(top, exprTok, value, tokenlist));
-        return result;
-    }
-
-    virtual void reverse(Token* start,
-                         const Token* endTok,
-                         const Token* exprTok,
-                         const std::list<ValueFlow::Value>& values,
-                         TokenList* tokenlist,
-                         const Settings* settings) const override {
-        return valueFlowContainerReverse(start, endTok, exprTok, values, tokenlist, settings);
-    }
-
     virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const override
     {
         Condition cond;
@@ -8113,7 +8008,7 @@ static void valueFlowDynamicBufferSize(TokenList* tokenlist, SymbolDatabase* sym
             value.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE;
             value.setKnown();
             const std::list<ValueFlow::Value> values{value};
-            valueFlowForward(const_cast<Token*>(rhs), functionScope->bodyEnd, tok->next(), values, tokenlist, settings);
+            valueFlowForward(const_cast<Token*>(rhs), functionScope->bodyEnd, tok->next(), values, tokenlist);
         }
     }
 }
@@ -8214,8 +8109,7 @@ static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symbold
                 argValues.back().errorPath.emplace_back(arg.nameToken(), "Assuming " + arg.name() + " size is 1000000");
                 argValues.back().safe = true;
                 for (const ValueFlow::Value &value : argValues)
-                    valueFlowContainerForward(
-                        const_cast<Token*>(functionScope->bodyStart), arg.nameToken(), value, tokenlist);
+                    valueFlowForward(const_cast<Token*>(functionScope->bodyStart), arg.nameToken(), value, tokenlist);
                 continue;
             }
 
@@ -8253,8 +8147,7 @@ static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symbold
                                      functionScope->bodyEnd,
                                      arg.nameToken(),
                                      argValues,
-                                     tokenlist,
-                                     settings);
+                                     tokenlist);
                     continue;
                 }
             }
@@ -8276,8 +8169,7 @@ static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symbold
                                  functionScope->bodyEnd,
                                  arg.nameToken(),
                                  argValues,
-                                 tokenlist,
-                                 settings);
+                                 tokenlist);
         }
     }
 }
@@ -8494,6 +8386,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
         valueFlowCondition(SymbolicConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
         valueFlowSymbolicInfer(tokenlist, symboldatabase);
         valueFlowArrayBool(tokenlist);
+        valueFlowArrayElement(tokenlist, settings);
         valueFlowRightShift(tokenlist, settings);
         valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings);
         valueFlowAfterSwap(tokenlist, symboldatabase, errorLogger, settings);
@@ -8504,7 +8397,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
         valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings);
         valueFlowFunctionReturn(tokenlist, errorLogger);
         valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings);
-        valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, settings);
+        valueFlowFunctionDefaultParameter(tokenlist, symboldatabase);
         valueFlowUninit(tokenlist, symboldatabase, settings);
         if (tokenlist->isCPP()) {
             valueFlowAfterMove(tokenlist, symboldatabase, settings);
diff --git a/lib/version.h b/lib/version.h
index 32e055a..f958b5e 100644
--- a/lib/version.h
+++ b/lib/version.h
@@ -2,8 +2,8 @@
 // After a release the DEVMINOR is incremented. MAJOR=x MINOR=y, DEVMINOR=y+1
 
 #define CPPCHECK_MAJOR 2
-#define CPPCHECK_MINOR 8
-#define CPPCHECK_DEVMINOR 8
+#define CPPCHECK_MINOR 7
+#define CPPCHECK_DEVMINOR 7
 
 #define STRINGIFY(x) STRING(x)
 #define STRING(VER) #VER
diff --git a/man/manual.md b/man/manual.md
index 023e018..1a6ad2c 100644
--- a/man/manual.md
+++ b/man/manual.md
@@ -1,6 +1,6 @@
 ---
 title: Cppcheck manual
-subtitle: Version 2.8
+subtitle: Version 2.7
 author: Cppcheck team
 lang: en
 documentclass: report
diff --git a/releasenotes.txt b/releasenotes.txt
index 0c7f2c3..807afe9 100644
--- a/releasenotes.txt
+++ b/releasenotes.txt
@@ -1,18 +1,2 @@
-release notes for cppcheck-2.8
+release notes for cppcheck-2.9
 
-- Lifetime analysis can now track lifetime across user-defined constructors when they are inline and using member initializer list.
-- SymbolDatabase can now deduce iterator types from how they are specified in the library files.
-- ValueFlow can evaluate class member functions that return known values.
-- Improve duplicateValueTenary to not warn when used as an lvalue or when one branch has side effects
-- Fix variableScope to not warn when variables are used in lambda functions
-- Fix unassignedVariable warnings when using structured bindings
-- Fix redundantInitialization warning when variable is used in a lambda
-- Fix variableScope warnings when using if/while init-statement
-- Improve lifetime analysis when returning variadic template expressions
-- Detect more statements with constStatement
-- Detect variableScope for more types
-- Improvements to unreadVariable
-- Detect more instances of C style casts
-- Warn if the return value of new is discarded
-- The pre-ValueFlow uninitialized checker now uses a different ID as legacyUninitvar
-- Extended library format to exclude specific function argument values 
diff --git a/test/testcondition.cpp b/test/testcondition.cpp
index ee09454..aea3f33 100644
--- a/test/testcondition.cpp
+++ b/test/testcondition.cpp
@@ -1642,6 +1642,12 @@ private:
     }
 
     void secondAlwaysTrueFalseWhenFirstTrueError() {
+        check("void f(void) {\n" // #8892
+              "    const char c[1] = { \'x\' }; \n"
+              "    if(c[0] == \'x\'){;}\n"
+              "}");
+        ASSERT_EQUALS("[test.cpp:3]: (style) Condition 'c[0]=='x'' is always true\n", errout.str());
+
         check("void f(int x) {\n"
               "    if (x > 5 && x != 1)\n"
               "        a++;\n"
diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp
index 4fe96c9..b5ea3cb 100644
--- a/test/testmemleak.cpp
+++ b/test/testmemleak.cpp
@@ -1708,6 +1708,7 @@ private:
         TEST_CASE(assign1);
         TEST_CASE(assign2);
         TEST_CASE(assign3);
+        TEST_CASE(assign4); // #11019
 
         // Failed allocation
         TEST_CASE(failedAllocation);
@@ -1887,6 +1888,42 @@ private:
         ASSERT_EQUALS("", errout.str());
     }
 
+    void assign4() {
+        check("struct S { int a, b, c; };\n" // #11019
+              "void f() {\n"
+              "    struct S s;\n"
+              "    *&s.a = open(\"xx.log\", O_RDONLY);\n"
+              "    ((s).b) = open(\"xx.log\", O_RDONLY);\n"
+              "    (&s)->c = open(\"xx.log\", O_RDONLY);\n"
+              "}\n", false);
+        ASSERT_EQUALS("[test.c:7]: (error) Memory leak: s.a\n"
+                      "[test.c:7]: (error) Memory leak: s.b\n"
+                      "[test.c:7]: (error) Memory leak: s.c\n",
+                      errout.str());
+
+        check("struct S { int *p, *q; };\n" // #7705
+              "void f(S s) {\n"
+              "    s.p = new int[10];\n"
+              "    s.q = malloc(40);\n"
+              "}\n");
+        ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: s.p\n"
+                      "[test.cpp:5]: (error) Memory leak: s.q\n",
+                      errout.str());
+
+        check("struct S** f(struct S** s) {\n" // don't throw
+              "    struct S** ret = malloc(sizeof(*ret));\n"
+              "    ret[0] = malloc(sizeof(**s));\n"
+              "    ret[0]->g = strdup(s[0]->g);\n"
+              "    return ret;\n"
+              "}\n");
+        ASSERT_EQUALS("", errout.str());
+
+        check("void run_rcmd(enum rcommand rcmd, rsh_session *sess, char *cmd) {\n"
+              "    sess->fp = popen(cmd, rcmd == RSH_PIPE_READ ? \"r\" : \"w\");\n"
+              "}\n", false);
+        ASSERT_EQUALS("", errout.str());
+    }
+
     void failedAllocation() {
         check("static struct ABC * foo()\n"
               "{\n"
@@ -2137,7 +2174,7 @@ private:
               "  ((f)->realm) = strdup(realm);\n"
               "  if(f->realm == NULL) {}\n"
               "}", false);
-        TODO_ASSERT_EQUALS("[test.c:6]: (error) Memory leak: f.realm\n", "", errout.str());
+        ASSERT_EQUALS("[test.c:6]: (error) Memory leak: f.realm\n", errout.str());
     }
 
     void customAllocation() { // #4770
diff --git a/test/testother.cpp b/test/testother.cpp
index a5fef18..7f81727 100644
--- a/test/testother.cpp
+++ b/test/testother.cpp
@@ -1816,6 +1816,13 @@ private:
               "void f(S s) {}\n");
         ASSERT_EQUALS("[test.cpp:2]: (performance) Function parameter 's' should be passed by const reference.\n", errout.str());
 
+        check("union U {\n" // don't crash
+              "    int a;\n"
+              "    decltype(nullptr) b;\n"
+              "};\n"
+              "int* f(U u) { return u.b; }\n");
+        ASSERT_EQUALS("", errout.str());
+
         Settings settings1;
         settings1.platform(Settings::Win64);
         check("using ui64 = unsigned __int64;\n"
@@ -1851,7 +1858,7 @@ private:
         check("void f(std::string str) {\n"
               "    std::string& s2 = str;\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Variable 's2' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Variable 's2' can be declared as reference to const\n", errout.str());
 
         check("void f(std::string str) {\n"
               "    const std::string& s2 = str;\n"
@@ -2006,12 +2013,12 @@ private:
               "    int& i = x[0];\n"
               "    return i;\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared as reference to const\n", errout.str());
 
         check("int f(std::vector<int>& x) {\n"
               "    return x[0];\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
 
         check("int f(std::vector<int> x) {\n"
               "    const int& i = x[0];\n"
@@ -2052,7 +2059,7 @@ private:
         check("const int& f(std::vector<int>& x) {\n"
               "    return x[0];\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
 
         check("int f(std::vector<int>& x) {\n"
               "    x[0]++;\n"
@@ -2169,17 +2176,17 @@ private:
               "    for(auto x:v)\n"
               "        x = 1;\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str());
 
         check("void f(std::vector<int>& v) {\n"
               "    for(auto& x:v) {}\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str());
 
         check("void f(std::vector<int>& v) {\n"
               "    for(const auto& x:v) {}\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str());
 
         check("void f(int& i) {\n"
               "    int& j = i;\n"
@@ -2283,14 +2290,14 @@ private:
               "    a x;\n"
               "    x(i);\n"
               "}\n");
-        ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'i' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'i' can be declared as reference to const\n", errout.str());
 
         //cast or assignment to a non-const reference should prevent the warning
         check("struct T { void dostuff() const {}};\n"
               "void a(T& x) {\n"
               "    x.dostuff();\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
         check("struct T : public U  { void dostuff() const {}};\n"
               "void a(T& x) {\n"
               "    x.dostuff();\n"
@@ -2304,7 +2311,7 @@ private:
               "    x.dostuff();\n"
               "    const U& y = x\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
         check("struct T : public U  { void dostuff() const {}};\n"
               "void a(T& x) {\n"
               "    x.dostuff();\n"
@@ -2325,7 +2332,7 @@ private:
               "    const U& y = static_cast<const U&>(x)\n"
               "    y.mutate();\n" //to avoid warnings that y can be const
               "}");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
         check("struct T : public U  { void dostuff() const {}};\n"
               "void a(T& x) {\n"
               "    x.dostuff();\n"
@@ -2338,7 +2345,7 @@ private:
               "    x.dostuff();\n"
               "    const U& y = dynamic_cast<const U&>(x)\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
         check(
             "struct T : public U { void dostuff() const {}};\n"
             "void a(T& x) {\n"
@@ -2346,13 +2353,13 @@ private:
             "    const U& y = dynamic_cast<U const &>(x)\n"
             "}"
             );
-        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
         check("struct T : public U { void dostuff() const {}};\n"
               "void a(T& x) {\n"
               "    x.dostuff();\n"
               "    const U& y = dynamic_cast<U & const>(x)\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
         check("struct T : public U { void dostuff() const {}};\n"
               "void a(T& x) {\n"
               "    x.dostuff();\n"
@@ -2365,7 +2372,7 @@ private:
               "    x.dostuff();\n"
               "    const U& y = dynamic_cast<typename const U&>(x)\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
         check("struct T : public U { void dostuff() const {}};\n"
               "void a(T& x) {\n"
               "    x.dostuff();\n"
@@ -2436,7 +2443,7 @@ private:
               "    x.dostuff();\n"
               "    const U& y = (const U&)(x)\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
         check("struct T : public U { void dostuff() const {}};\n"
               "void a(T& x) {\n"
               "    x.dostuff();\n"
@@ -2449,7 +2456,7 @@ private:
               "    x.dostuff();\n"
               "    const U& y = (typename const U&)(x)\n"
               "}");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str());
         check("struct T : public U { void dostuff() const {}};\n"
               "void a(T& x) {\n"
               "    x.dostuff();\n"
@@ -2488,7 +2495,7 @@ private:
               "void f(int& i) {\n"
               "    a()(i);\n"
               "}\n");
-        ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'i' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'i' can be declared as reference to const\n", errout.str());
 
         // #9767
         check("void fct1(MyClass& object) {\n"
@@ -2737,7 +2744,7 @@ private:
               "  : c(i)\n"
               "{\n"
               "}");
-        TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared with const\n", "", errout.str());
+        TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared as reference to const\n", "", errout.str());
 
         check("class C\n"
               "{\n"
@@ -2758,7 +2765,7 @@ private:
               "  : c(i)\n"
               "{\n"
               "}");
-        TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared with const\n", "", errout.str());
+        TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared as reference to const\n", "", errout.str());
 
         check("class C\n"
               "{\n"
@@ -2779,7 +2786,7 @@ private:
               "  : c(0, i)\n"
               "{\n"
               "}");
-        TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared with const\n", "", errout.str());
+        TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared as reference to const\n", "", errout.str());
 
         check("void f(std::map<int, std::vector<int>> &map) {\n" // #10266
               "  for (auto &[slave, panels] : map)\n"
@@ -2832,7 +2839,7 @@ private:
     void constParameterCallback() {
         check("int callback(std::vector<int>& x) { return x[0]; }\n"
               "void f() { dostuff(callback); }");
-        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());
+        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());
 
         // #9906
         check("class EventEngine : public IEventEngine {\n"
@@ -2850,51 +2857,51 @@ private:
               "void EventEngine::signalEvent(ev::sig& signal, int revents) {\n"
               "    switch (signal.signum) {}\n"
               "}");
-        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());
+        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());
     }
 
     void constPointer() {
         check("void foo(int *p) { return *p; }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(int *p) { x = *p; }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(int *p) { int &ref = *p; ref = 12; }");
         ASSERT_EQUALS("", errout.str());
 
         check("void foo(int *p) { x = *p + 10; }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(int *p) { return p[10]; }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(int *p) { int &ref = p[0]; ref = 12; }");
         ASSERT_EQUALS("", errout.str());
 
         check("void foo(int *p) { x[*p] = 12; }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(int *p) { if (p) {} }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(int *p) { if (p || x) {} }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(int *p) { if (p == 0) {} }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(int *p) { if (!p) {} }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(int *p) { if (*p > 123) {} }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(int *p) { return *p + 1; }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(int *p) { return *p > 1; }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n", errout.str());
 
         check("void foo(const int* c) { if (c == 0) {}; }");
         ASSERT_EQUALS("", errout.str());
@@ -2995,14 +3002,14 @@ private:
               "    static int i[1] = {};\n"
               "    return i[0];\n"
               "}\n");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared as const array\n", errout.str());
 
         check("int f() {\n"
               "    static int i[] = { 0 };\n"
               "    int j = i[0] + 1;\n"
               "    return j;\n"
               "}\n");
-        ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' can be declared as const array\n", errout.str());
 
         // #10471
         check("void f(std::array<int, 1> const& i) {\n"
@@ -3025,7 +3032,7 @@ private:
               "    for (const auto* p : v)\n"
               "        if (p == nullptr) {}\n"
               "}\n");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str());
 
         check("void f(std::vector<const int*>& v) {\n"
               "    for (const auto& p : v)\n"
@@ -3033,7 +3040,7 @@ private:
               "    for (const auto* p : v)\n"
               "        if (p == nullptr) {}\n"
               "}\n");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str());
 
         check("void f(const std::vector<const int*>& v) {\n"
               "    for (const auto& p : v)\n"
@@ -3071,9 +3078,33 @@ private:
               "    tmp = b[i];\n"
               "    printf(\"%s\", tmp);\n"
               "}\n");
-        ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' can be declared with const\n"
-                      "[test.cpp:4]: (style) Variable 'b' can be declared with const\n",
+        ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' can be declared as const array\n"
+                      "[test.cpp:4]: (style) Variable 'b' can be declared as const array\n",
                       errout.str());
+
+        check("typedef void* HWND;\n"
+              "void f(const HWND h) {\n"
+              "    if (h == nullptr) {}\n"
+              "}\n");
+        ASSERT_EQUALS("", errout.str());
+
+        check("using HWND = void*;\n"
+              "void f(const HWND h) {\n"
+              "    if (h == nullptr) {}\n"
+              "}\n");
+        ASSERT_EQUALS("", errout.str());
+
+        check("typedef int A;\n"
+              "void f(A* x) {\n"
+              "    if (x == nullptr) {}\n"
+              "}\n");
+        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str());
+
+        check("using A = int;\n"
+              "void f(A* x) {\n"
+              "    if (x == nullptr) {}\n"
+              "}\n");
+        ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str());
     }
 
     void switchRedundantAssignmentTest() {
@@ -5247,7 +5278,7 @@ private:
 
         // #5535: Reference named like its type
         check("void foo() { UMSConfig& UMSConfig = GetUMSConfiguration(); }");
-        ASSERT_EQUALS("[test.cpp:1]: (style) Variable 'UMSConfig' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.cpp:1]: (style) Variable 'UMSConfig' can be declared as reference to const\n", errout.str());
 
         // #3868 - false positive (same expression on both sides of |)
         check("void f(int x) {\n"
@@ -9273,7 +9304,7 @@ private:
               "    int local_argc = 0;\n"
               "    local_argv[local_argc++] = argv[0];\n"
               "}\n", "test.c");
-        ASSERT_EQUALS("[test.c:1]: (style) Parameter 'argv' can be declared with const\n", errout.str());
+        ASSERT_EQUALS("[test.c:1]: (style) Parameter 'argv' can be declared as const array\n", errout.str());
 
         check("void f() {\n"
               "  int x = 0;\n"
diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp
index 4f51f04..019b0e6 100644
--- a/test/testsymboldatabase.cpp
+++ b/test/testsymboldatabase.cpp
@@ -7744,6 +7744,7 @@ private:
         ASSERT_EQUALS("const signed int", typeOf("; const auto x = 3;", "x"));
         ASSERT_EQUALS("const signed int", typeOf("; constexpr auto x = 3;", "x"));
         ASSERT_EQUALS("const signed int", typeOf("; const constexpr auto x = 3;", "x"));
+        ASSERT_EQUALS("void * const", typeOf("typedef void* HWND; const HWND x = 0;", "x"));
 
         // Variable declaration
         ASSERT_EQUALS("char *", typeOf("; char abc[] = \"abc\";", "["));
diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp
index 666e85b..5ab4193 100644
--- a/test/testunusedvar.cpp
+++ b/test/testunusedvar.cpp
@@ -151,6 +151,7 @@ private:
         TEST_CASE(localvaralias17); // ticket #8911
         TEST_CASE(localvaralias18); // ticket #9234 - iterator
         TEST_CASE(localvaralias19); // ticket #9828
+        TEST_CASE(localvaralias20); // ticket #10966
         TEST_CASE(localvarasm);
         TEST_CASE(localvarstatic);
         TEST_CASE(localvarextern);
@@ -4674,6 +4675,21 @@ private:
         ASSERT_EQUALS("", errout.str());
     }
 
+    void localvaralias20() { // #10966
+        functionVariableUsage("struct A {};\n"
+                              "A g();\n"
+                              "void f() {\n"
+                              "    const auto& a = g();\n"
+                              "    const auto& b = a;\n"
+                              "    const auto&& c = g();\n"
+                              "    auto&& d = c;\n"
+                              "}\n");
+        TODO_ASSERT_EQUALS("[test.cpp:5]: (style) Variable 'b' is assigned a value that is never used.\n"
+                           "[test.cpp:7]: (style) Variable 'd' is assigned a value that is never used.\n",
+                           "[test.cpp:7]: (style) Variable 'd' is assigned a value that is never used.\n",
+                           errout.str());
+    }
+
     void localvarasm() {
 
         functionVariableUsage("void foo(int &b)\n"
diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp
index 648653f..2c8ad19 100644
--- a/test/testvalueflow.cpp
+++ b/test/testvalueflow.cpp
@@ -754,6 +754,20 @@ private:
                 "    return x[0];\n"
                 "}";
         ASSERT_EQUALS(0, valueOfTok(code, "[").intvalue);
+
+        code = "int g() { return 3; }\n"
+               "void f() {\n"
+               "    const int x[2] = { g(), g() };\n"
+               "    return x[0];\n"
+               "}\n";
+        ASSERT_EQUALS(3, valueOfTok(code, "[ 0").intvalue);
+
+        code = "int g() { return 3; }\n"
+               "void f() {\n"
+               "    const int x[2] = { g(), g() };\n"
+               "    return x[1];\n"
+               "}\n";
+        ASSERT_EQUALS(3, valueOfTok(code, "[ 1").intvalue);
     }
 
     void valueFlowMove() {
diff --git a/test/testvarid.cpp b/test/testvarid.cpp
index c572241..d977d4a 100644
--- a/test/testvarid.cpp
+++ b/test/testvarid.cpp
@@ -153,6 +153,7 @@ private:
         TEST_CASE(varid_templateNamespaceFuncPtr); // #4172
         TEST_CASE(varid_templateArray);
         TEST_CASE(varid_templateParameter); // #7046 set varid for "X":  std::array<int,X> Y;
+        TEST_CASE(varid_templateParameterFunctionPointer); // #11050
         TEST_CASE(varid_templateUsing); // #5781 #7273
         TEST_CASE(varid_not_template_in_condition); // #7988
         TEST_CASE(varid_cppcast); // #6190
@@ -2358,6 +2359,17 @@ private:
         }
     }
 
+    void varid_templateParameterFunctionPointer() {
+        {
+            const char code[] = "template <class, void (*F)()>\n"
+                                "struct a;\n";
+
+            ASSERT_EQUALS("1: template < class , void ( * F ) ( ) >\n"
+                          "2: struct a ;\n",
+                          tokenize(code));
+        }
+    }
+
     void varid_templateUsing() { // #5781 #7273
         const char code[] = "template<class T> using X = Y<T,4>;\n"
                             "X<int> x;";
diff --git a/tools/dmake.cpp b/tools/dmake.cpp
index cc17cc0..a7d0df3 100644
--- a/tools/dmake.cpp
+++ b/tools/dmake.cpp
@@ -242,15 +242,17 @@ int main(int argc, char **argv)
          << "    $(warning Usage of SRCDIR to activate match compiler is deprecated. Use MATCHCOMPILER=yes instead.)\n"
          << "    MATCHCOMPILER:=yes\n"
          << "endif\n";
+    // TODO: bail out when matchcompiler.py fails (i.e. invalid PYTHON_INTERPRETER specified)
+    // TODO: handle "PYTHON_INTERPRETER="
     fout << "ifeq ($(MATCHCOMPILER),yes)\n"
          << "    # Find available Python interpreter\n"
-         << "    ifndef PYTHON_INTERPRETER\n"
+         << "    ifeq ($(PYTHON_INTERPRETER),)\n"
          << "        PYTHON_INTERPRETER := $(shell which python3)\n"
          << "    endif\n"
-         << "    ifndef PYTHON_INTERPRETER\n"
+         << "    ifeq ($(PYTHON_INTERPRETER),)\n"
          << "        PYTHON_INTERPRETER := $(shell which python)\n"
          << "    endif\n"
-         << "    ifndef PYTHON_INTERPRETER\n"
+         << "    ifeq ($(PYTHON_INTERPRETER),)\n"
          << "        $(error Did not find a Python interpreter)\n"
          << "    endif\n"
          << "    ifdef VERIFY\n"
@@ -424,7 +426,7 @@ int main(int argc, char **argv)
     fout << "run-dmake: dmake\n";
     fout << "\t./dmake\n\n";
     fout << "clean:\n";
-    fout << "\trm -f build/*.o lib/*.o cli/*.o test/*.o tools/*.o externals/*/*.o testrunner dmake cppcheck cppcheck.exe cppcheck.1\n\n";
+    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";
     fout << "man:\tman/cppcheck.1\n\n";
     fout << "man/cppcheck.1:\t$(MAN_SOURCE)\n\n";
     fout << "\t$(XP) $(DB2MAN) $(MAN_SOURCE)\n\n";
@@ -494,7 +496,11 @@ int main(int argc, char **argv)
     fout << "\txmllint --noout --relaxng cppcheck-errors.rng /tmp/errorlist.xml\n";
     fout << "\txmllint --noout --relaxng cppcheck-errors.rng /tmp/example.xml\n";
     fout << "\ncheckCWEEntries: /tmp/errorlist.xml\n";
-    fout << "\t./tools/listErrorsWithoutCWE.py -F /tmp/errorlist.xml\n";
+    // TODO: handle "PYTHON_INTERPRETER="
+    fout << "\t$(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(shell which python3)))\n";
+    fout << "\t$(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(shell which python)))\n";
+    fout << "\t$(eval PYTHON_INTERPRETER := $(if $(PYTHON_INTERPRETER),$(PYTHON_INTERPRETER),$(error Did not find a Python interpreter)))\n";
+    fout << "\t$(PYTHON_INTERPRETER) tools/listErrorsWithoutCWE.py -F /tmp/errorlist.xml\n";
     fout << ".PHONY: validateRules\n";
     fout << "validateRules:\n";
     fout << "\txmllint --noout rules/*.xml\n";
diff --git a/tools/donate-cpu-server.py b/tools/donate-cpu-server.py
index c6269ae..2dbe5a8 100755
--- a/tools/donate-cpu-server.py
+++ b/tools/donate-cpu-server.py
@@ -25,9 +25,9 @@ import html as html_lib
 # Version scheme (MAJOR.MINOR.PATCH) should orientate on "Semantic Versioning" https://semver.org/
 # Every change in this script should result in increasing the version number accordingly (exceptions may be cosmetic
 # changes)
-SERVER_VERSION = "1.3.24"
+SERVER_VERSION = "1.3.25"
 
-OLD_VERSION = '2.7'
+OLD_VERSION = '2.8'
 
 
 # Set up logging
diff --git a/tools/run_more_tests.sh b/tools/run_more_tests.sh
index 2a5e17c..9bc3295 100755
--- a/tools/run_more_tests.sh
+++ b/tools/run_more_tests.sh
@@ -11,7 +11,7 @@ if test -f ./bin/cppcheck; then
     CPPCHECK=$(pwd)/bin/cppcheck
 fi
 
-python $DIR/extracttests.py --code=$(pwd)/test1 $1
+python3 $DIR/extracttests.py --code=$(pwd)/test1 $1
 
 cd test1
 
diff --git a/tools/triage/mainwindow.cpp b/tools/triage/mainwindow.cpp
index 48cf58f..f6ac966 100644
--- a/tools/triage/mainwindow.cpp
+++ b/tools/triage/mainwindow.cpp
@@ -263,7 +263,7 @@ void MainWindow::showResult(QListWidgetItem *item)
     const QStringList lines = item->text().split("\n");
     if (lines.size() < 2)
         return;
-    const QString url = lines[0];
+    const QString &url = lines[0];
     QString msg = lines[1];
     const QRegularExpressionMatch matchRes = mVersionRe.match(msg);
     if (matchRes.hasMatch())