Compare commits

...

69 Commits

Author SHA1 Message Date
chrchr-github 30397f0d53
Fix FP initializerList with static member (#5864) 2024-01-09 19:42:23 +01:00
chrchr-github 9fceba4fbc
Fix FP initializerList with base member (#5862) 2024-01-09 14:52:32 +01:00
chrchr-github c21166565f
Fix #12322 detect usage of partially-initialized object in constructor (#5851) 2024-01-09 12:28:22 +01:00
Daniel Marjamäki 8903f0e4b1
daca: Add compare-normal-exhaustive.py script to compare normal and exhaustive check level (#5860) 2024-01-09 11:45:44 +01:00
Oliver Stöneberg 08d754d536
ClangImport: avoid unchecked pointer dereferences (#5856)
The `Tokenizer` and `TokenList` objects which are passed around always
need to exist so pass them by reference.
2024-01-08 19:46:12 +01:00
Oliver Stöneberg 30ca8e11b5
moved `Language` from `settings.h` to `standards.h` (#5854) 2024-01-07 22:53:39 +01:00
Oliver Stöneberg bbd2b2aa83
cleaned up includes based on `include-what-you-use` (#5855) 2024-01-07 11:07:51 +01:00
Oliver Stöneberg 81700b481d
some `TokenList` cleanups (#5848) 2024-01-06 23:49:25 +01:00
Maarten van der Schrieck 328f98b35a
test/cli/test-other.py: Fix test_showtime_top5_file. (#5847)
test_showtime_top5_file() assumes that all reported elements, of which
the "top 5" are validated, end with the string "- 1 result(s))".

This is clearly not the case when viewing the entire list:

```bash
$ cppcheck --showtime=summary --quiet empty.c  |grep "2 result"
valueFlowLifetime(tokenlist, errorLogger, settings): 3.4e-05s (avg. 1.7e-05s - 2 result(s))
valueFlowEnumValue(symboldatabase, settings): 3e-06s (avg. 1.5e-06s - 2 result(s))
```

As the order of items is non-deterministic, this test makes CI workflows
randomly fail.

This patch addresses the issue by adjusting the expected string to the
reported item.
2024-01-06 22:50:40 +01:00
Oliver Stöneberg e3b3048d00
test/helpers:h: fixed initialization order in `givenACodeSampleToTokenize` (#5849) 2024-01-06 18:36:34 +01:00
orbitcowboy 71212c7d66
std.cfg: Added support for invalidFunctionArg check to tgamma(). (#5850)
Reference: https://en.cppreference.com/w/cpp/numeric/math/tgamma
2024-01-06 14:59:43 +01:00
orbitcowboy 32cabecca9
Add support for InvalidFunctionArg lgamma() (#5845)
Reference: https://en.cppreference.com/w/cpp/numeric/math/lgamma
2024-01-05 23:34:08 +01:00
chrchr-github fde7ea6d17
Fix #12321 FP doubleFree within lambda (#5844) 2024-01-05 22:20:21 +01:00
Oliver Stöneberg 44ed53319e
CppCheck: extracted clang-specific code from `check(const std::string&)` into separate method (#5842) 2024-01-05 22:02:37 +01:00
Oliver Stöneberg bd9700b848
fixed cfg tests (#5843) 2024-01-05 18:08:00 +01:00
Oliver Stöneberg 028596f100
enabled and mitigated debug warnings in cfg tests (#5840) 2024-01-05 17:00:51 +01:00
orbitcowboy 950b285608
posix.cfg: Added support for strxfrm_l (#5839)
Reference: 
-
https://pubs.opengroup.org/onlinepubs/9699919799/functions/strxfrm_l.html
2024-01-05 16:41:28 +01:00
Oliver Stöneberg 42c3aebda9
AddonInfo: const-ified loading and improved errorhandling (#5834) 2024-01-05 15:01:02 +01:00
chrchr-github c7cd091a93
Fix #12141 debug: simplifyUsing: unmatched body end (#5620) 2024-01-05 14:11:41 +01:00
chrchr-github f9134a69d2
CheckLeakAutoVar: fix crash on unknown macro (#5836) 2024-01-05 13:24:01 +01:00
Oliver Stöneberg 02f474bc19
about.ui: added Boost to list of libraries and correct capitalization for existing ones (#5832)
Boost is only optional - but so is the PCRE-based rules support which is
also mentioned in the list.
2024-01-05 13:22:52 +01:00
Oliver Stöneberg 957096417e
fixed some `modernize-use-auto` clean-tidy warnings (#4663) 2024-01-05 13:22:37 +01:00
orbitcowboy 3241cf5966
Ticket 6306: Added regression test and mention suppression in comment (#5835) 2024-01-05 12:58:27 +01:00
Philip Chimento 8ca93c983b
gtk.cfg: Add more definitions for assert macros (#5830)
In particular, the missing definition of `g_assert_nonnull()` can cause
false positives because it's not recognized as `assert(expr != NULL)` by
cppcheck.
2024-01-05 12:32:05 +01:00
Oliver Stöneberg 6ef3224bd4
fixed signatures of deleted `operator=` (#5831) 2024-01-05 11:12:30 +01:00
Oliver Stöneberg 93a53af168
modernized and cleaned up CMake files / explicitly check for CMake 3.13 with Visual Studio (#5825) 2024-01-05 11:07:16 +01:00
Daniel Marjamäki fc1d4d6f7d
runformat: improve instructions [ci skip] (#5833) 2024-01-05 10:06:10 +01:00
chrchr-github 1eee68f039
Fix FN deallocuse with function call (refs #11409) (#5822) 2024-01-04 22:10:24 +01:00
chrchr-github efa8a08407
Set main version to 2.13.99 (#5818) 2024-01-04 22:00:30 +01:00
Oliver Stöneberg 87540e6ca6
testrunner: do not suppress duplicated error messages (#5736) 2024-01-04 21:46:42 +01:00
Oliver Stöneberg b2e0b3b425
refs #12171 - start generating unmatched suppressions with `FileSettings` / improved TestSuppressions / some cleanups (#5827) 2024-01-04 21:32:21 +01:00
Oliver Stöneberg 615e4c01c4
bumped minimum requirements to GCC 5.1 / Clang 3.5 / Visual Studio 2015 / CMake 3.5 (#5398)
The current versions only have partial C++11 support which fortunately
has caused us only few issues so far but it would be good to finally
have fully working C++11 support. This also gets rid of several CI
builds on very outdated platforms.

The outdated platforms were used to also test CMake 2.8 but as future
versions of CMake will drop combability with CMake < 3.5 this is a good
time to also drop that requirement on our part.

This PR does not remove or update any outdated code.
2024-01-04 21:31:08 +01:00
chrchr-github f24c7fdae9
Fix #12311 FP duplInheritedMember for const overload (#5829) 2024-01-04 20:59:09 +01:00
chrchr-github 73187e6e12
Fix #11998 FN (regression): comparisonError (#5826) 2024-01-04 20:58:39 +01:00
Daniel Marjamäki 9aae9aeb25
AUTHORS: Add thingsconnected [ci skip] (#5828) 2024-01-04 16:29:31 +01:00
Maarten van der Schrieck 21a9de7d42
addons/namingng.py: Reinstate dict-with-regexps, cosmetic overhaul. (#5824)
`namingng.py` somewhat supported specifying a dict instead of a list for
regular expressions, until the feature was broken by a patch of mine
recently. This PR contains a patch rewriting the feature and expanding
relevant unit tests.

To improve maintainability, a second patch is added that refactors the
code for better readability and structure.
2024-01-04 16:26:54 +01:00
chrchr-github 481d4578ab
Fix #12301 FP doubleFree with GTK functions (#5823) 2024-01-04 11:02:59 +01:00
thingsconnected 8261ded475
addons/namingng.py: Improve output and unit test. (#5820)
For naming issues reported, column was always set to `0`, which is now
fixed.

Global variable naming errors were reported as "Public member" issues,
which is also fixed.

The unit test now covers namespaces, class names, public and private
member variables.
2024-01-03 14:00:47 +01:00
chrchr-github 5e59652fd3
Add tests for #1644, #3929, #6109 (#5821) 2024-01-03 11:50:28 +01:00
Oliver Stöneberg dd869cf808
added CMake option `EXTERNALS_AS_SYSTEM` to treat external includes as `SYSTEM` ones (#5386)
Although these files are part of our repo changes are being done via
their original projects so it might make sense to treat these as system
includes for some people instead of local ones.

Co-authored-by: Daniel Marjamäki <daniel.marjamaki@gmail.com>
2024-01-03 11:05:32 +01:00
chrchr-github 8d64d12e5d
Fix #12252 Regression: constParameterPointer (#5819) 2024-01-02 20:07:35 +01:00
chrchr-github 14627ca6d2
Add tests for #2199, #11207, #11464 (#5817) 2024-01-02 15:49:47 +01:00
thingsconnected 98b9244bcb
addons/namingng.py: Add tests for include guards, config file validation. (#5815)
Include guard naming can be validated against various patterns:
- prefixes/suffixes (`_FILE_H`, `PROJECT_FILE_H`, `FILE_H_`)
- basename/full path (`FILE_H`, `SUB_DIR_INC_FILE_H`)
- upper- or lowercase (`FILE_H`, `file_h`)
- any combination of the above (`project_sub_dir_inc_file_h_`)

A regexp can be specified to match header filenames. The example matches
any filename not starting with / and ending with `.h`, intended to match
C header files while exluding system files.

The test is not limited to naming only; validity and presence of include
guards can also be tested by setting `"required":true` in the config
file.

Enabling this feature requires adding the key `"include_guard"` to the
namingng config file used.

The namingng unit test is extended to test various features of the
include guard test.

Also, config handling is improved, adding (superficial) validation and a
unit test.
2024-01-02 15:01:02 +01:00
chrchr-github d9d23d979d
Partial fix for #12302 internalAstError using lambda (#5816) 2024-01-02 13:33:22 +01:00
Daniel Marjamäki 0c8ee7895d
manual-premium.md: copy changes from manual.md (#5813) 2023-12-30 21:39:39 +01:00
thingsconnected 24133d4a59
addons/namingng.py: Fix commandline use. (#5793)
namingng.py was only usable in standalone mode, but now supports CLI
mode, i.e. with cppcheck --addon=namingng. It uses the generic reporting
provided by cppcheckdata.reportError(). All output other than reported
errors is suppressed.

A local function reportNamingError() is implemented to call through to
cppcheckdata.reportError(), filling in common defaults.

The collection of errors and the --verify feature are removed, including
related workflow and a test file. These are replaced by a unit test.
2023-12-30 20:54:03 +01:00
Daniel Marjamäki b7c5505550
CI: Update Cppcheck Premium version and license (#5814) 2023-12-30 20:47:30 +01:00
Swasti Shrivastava 681b15f5c9
Fix #12298: false positive: misra-c2012-9.3 (#5812) 2023-12-30 13:05:25 +01:00
thingsconnected 4c7aae3a16
addons/namingng.py: Improve file name checking feature. (#5802)
(note: comment updated after force push; initial PR was incomplete)

namingng.py attempted to derive the source filename from the name of the
dumpfile. However, the dumpfile is not necessarily named according to
this pattern, e.g. cppcheck will add the pid to the filename, making
RE_FILE rules
fail. Taking the first item of data.files seem to be more robust.

To get the basename of the file, `os.path.basename()` is used. This
solves (theoretical) issues on platforms with a different path
separator.

With this patch, all filenames are checked, not just those provided on
the cppcheck command line. This is useful as header files will now also
be part of this check, even if not explicitly specified on the command
line.

The "RE_FILE" key of the configuration JSON may contain a list of
regular expressions, where any match will lead to acceptance of the
filename.

Both the full path and the basename of the files are tested.

One use case for this combination of features is:

```
"RE_FILE":[
    "/.*\\.h\\Z",
    "[a-z][a-z0-9_]*[a-z0-9]\\.[ch]\\Z"
]
```
This will accept any file naming convention of the platform used
(assuming platform files are all referenced using an absolute path),
while enforcing a particular naming scheme for project files.
2023-12-27 18:56:29 +01:00
Paul Fultz II 4d9e69e42c
Fix 11985: False positive: uninitvar (valueflow) (#5781) 2023-12-27 18:11:57 +01:00
Daniel Marjamäki b6e157408c
triage: fix broken signal-slot when double-clicking result (#5810) 2023-12-27 12:25:40 +01:00
Christoph Grüninger 4a9b921ccf
Fix two types of Clazy warnings (#5807)
Chained QString::arg, replace inclusion of QtCore
2023-12-27 10:36:18 +01:00
thingsconnected 403e7f1f7d
lib/addoninfo.cpp: When loading a JSON addon, test 'script' key. (#5797)
In case a user accidentally uses a wrong JSON file (e.g. naming.json,
which is the config file for namingng.py), the code could give a
confusing exception. This happens when the key 'script' is not defined
as a string.

This is solved by testing the key for existence and type. In case
'script' is not a key or refers to a type other than a string, a clear
error is given, stating for example: 'Loading naming.json failed. script
must be set to a string value.'

The message is kept in line with other messages. Maybe it can be
clarified further, e.g. 'Loading naming.json failed. A key "script" must
be set with a string value referring to a Python script.' - in which
case the errors relating to other keys may also be clarified.
2023-12-25 05:49:17 +01:00
chrchr-github a7baf88d4f
Fix #12289 FN (regression): memory leak not shown when strcpy is used (#5809) 2023-12-24 14:42:07 +01:00
olabetskyi e553940e23
#12158: improve check: variableScope is not reported when there is el… (#5758)
variableScope is not reported when there is else if
2023-12-24 14:01:01 +01:00
Tomo Dote c02d0786ad
Add Japanese translation for 2.13.0 (#5806)
This is just adding Japanese translation only.

Happy holidays
2023-12-24 13:00:15 +01:00
thingsconnected d506e7e937
addons/namingng.py: allow function/variable name test without prefixes (#5801)
This patch allows a config file to have RE_VARNAME and RE_FUNCTIONNAME
without the corresponding var_prefixes and function_prefixes keys. The
namingng.py processing function would otherwise raise an exception
trying to get these keys, while they are not strictly necessary, if no
prefixes are required.
2023-12-23 22:33:36 +01:00
chrchr-github 9118d330d3
Fix test failure on 32bit platform (#5803) 2023-12-23 20:59:59 +01:00
orbitcowboy 06e6c3eba4
cppcheck-htmlreport: Added clear button inside 'File' and 'Filter' text box (#5805)
This is a cosmetic change. When the user enters text to either the
"File" or "Filter" option, a clear button is shown now.
2023-12-23 19:32:13 +01:00
chrchr-github 17ee4093fa
Fix #10905, #11665 FN deallocuse (#5751) 2023-12-23 11:31:27 +01:00
Paul Fultz II 7f0234e7d5
Fix 12032: False positive: uninitialized variable, flags with same value (#5754) 2023-12-23 10:57:40 +01:00
Paul Fultz II 77157a678a
Fix 12033: false negative: uninitialized data passed as const data to function (#5747) 2023-12-23 10:55:39 +01:00
Daniel Marjamäki 2af3b7bf44
createrelease: nothing new, tweak instructions [ci skip] (#5800) 2023-12-23 09:23:53 +01:00
Daniel Marjamäki c9401a576d
daca@home: use cppcheck-2.13.0 as old version [ci skip] (#5799) 2023-12-23 09:18:41 +01:00
Daniel Marjamäki 0fec74d867
createrelease: use -j12 to build faster, build with -O2 (#5798) 2023-12-23 08:18:34 +01:00
Daniel Marjamäki 79fb57e756
dmake: in run-dmake target run dmake with --release in a release Makefile (#5792) 2023-12-22 23:21:02 +01:00
Daniel Marjamäki 5a222b80a1
CI: fix --version tests (#5790) 2023-12-22 19:57:55 +01:00
Daniel Marjamäki 36b8e54b71
createrelease: update sed commands for writing cppcheck version (#5789) 2023-12-22 18:03:27 +01:00
Daniel Marjamäki d81c69682c
releasenotes.txt: new notes for 2.14 [ci skip] (#5787) 2023-12-20 22:19:37 +01:00
153 changed files with 3051 additions and 1152 deletions

View File

@ -19,7 +19,7 @@ jobs:
strategy:
matrix:
image: ["centos:7", "ubuntu:14.04", "ubuntu:16.04", "ubuntu:18.04", "ubuntu:23.10"]
image: ["ubuntu:16.04", "ubuntu:18.04", "ubuntu:23.10"]
include:
- build_gui: false
- image: "ubuntu:23.10"
@ -39,13 +39,6 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Install missing software on CentOS 7
if: matrix.image == 'centos:7'
run: |
yum install -y cmake gcc-c++ make pcre-devel
yum --enablerepo=extras install -y epel-release
yum install -y ccache
- name: Install missing software on ubuntu
if: contains(matrix.image, 'ubuntu')
run: |
@ -62,22 +55,12 @@ jobs:
# - it doesn't support centos
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
if: matrix.image != 'ubuntu:14.04' # no support for --set-config
with:
key: ${{ github.workflow }}-${{ matrix.image }}
# tests require CMake 3.9 - no ccache available
- name: CMake build (no tests / no ccache)
if: matrix.image == 'ubuntu:14.04'
run: |
mkdir cmake.output
cd cmake.output
cmake -G "Unix Makefiles" -DHAVE_RULES=On ..
cmake --build . -- -j$(nproc)
# tests require CMake 3.9 - ccache available
- name: CMake build (no tests)
if: matrix.image == 'centos:7' || matrix.image == 'ubuntu:16.04'
if: matrix.image == 'ubuntu:16.04'
run: |
mkdir cmake.output
cd cmake.output
@ -85,7 +68,7 @@ jobs:
cmake --build . -- -j$(nproc)
- name: CMake build
if: ${{ !matrix.build_gui && matrix.image != 'centos:7' && matrix.image != 'ubuntu:14.04' && matrix.image != 'ubuntu:16.04' }}
if: ${{ !matrix.build_gui && matrix.image != 'ubuntu:16.04' }}
run: |
mkdir cmake.output
cd cmake.output
@ -99,7 +82,7 @@ jobs:
cmake --build cmake.output -- -j$(nproc)
- name: Run CMake test
if: matrix.image != 'centos:7' && matrix.image != 'ubuntu:14.04' && matrix.image != 'ubuntu:16.04'
if: matrix.image != 'ubuntu:16.04'
run: |
cmake --build cmake.output --target check -- -j$(nproc)
@ -107,7 +90,7 @@ jobs:
strategy:
matrix:
image: ["centos:7", "ubuntu:14.04", "ubuntu:16.04", "ubuntu:18.04", "ubuntu:23.10"]
image: ["ubuntu:16.04", "ubuntu:18.04", "ubuntu:23.10"]
fail-fast: false # Prefer quick result
runs-on: ubuntu-22.04
@ -118,13 +101,6 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Install missing software on CentOS 7
if: matrix.image == 'centos:7'
run: |
yum install -y gcc-c++ make which python3 pcre-devel
yum --enablerepo=extras install -y epel-release
yum install -y ccache
- name: Install missing software on ubuntu
if: contains(matrix.image, 'ubuntu')
run: |
@ -136,7 +112,6 @@ jobs:
# - it doesn't support centos
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
if: matrix.image != 'ubuntu:14.04' # no support for --set-config
with:
key: ${{ github.workflow }}-${{ matrix.image }}

View File

@ -446,8 +446,6 @@ jobs:
python3 ../naming.py --var='[a-z].*' --function='[a-z].*' naming_test.c.dump
../../cppcheck --dump naming_test.cpp
python3 ../naming.py --var='[a-z].*' --function='[a-z].*' naming_test.cpp.dump
../../cppcheck --dump namingng_test.c
python3 ../namingng.py --configfile ../naming.json --verify namingng_test.c.dump
- name: Build democlient
if: matrix.os == 'ubuntu-22.04'

View File

@ -202,6 +202,4 @@ jobs:
rem python3 ..\naming.py --var='[a-z].*' --function='[a-z].*' naming_test.c.dump || exit /b !errorlevel!
..\..\cppcheck --dump naming_test.cpp || exit /b !errorlevel!
python3 ..\naming.py --var='[a-z].*' --function='[a-z].*' naming_test.cpp.dump || exit /b !errorlevel!
..\..\cppcheck --dump namingng_test.c || exit /b !errorlevel!
python3 ..\namingng.py --configfile ..\naming.json --verify namingng_test.c.dump || exit /b !errorlevel!

View File

@ -19,22 +19,23 @@ jobs:
runs-on: ubuntu-22.04 # run on the latest image only
env:
PREMIUM_VERSION: devdrop-20231105
PREMIUM_VERSION: 23.12.0
steps:
- uses: actions/checkout@v3
- name: Download cppcheckpremium
run: |
wget https://files.cppchecksolutions.com/cppcheckpremium-${{ env.PREMIUM_VERSION }}-amd64.tar.gz
wget https://files.cppchecksolutions.com/${{ env.PREMIUM_VERSION }}/ubuntu-22.04/cppcheckpremium-${{ env.PREMIUM_VERSION }}-amd64.tar.gz
#wget https://files.cppchecksolutions.com/cppcheckpremium-${{ env.PREMIUM_VERSION }}-amd64.tar.gz
tar xzf cppcheckpremium-${{ env.PREMIUM_VERSION }}-amd64.tar.gz
- name: Generate a license file
run: |
echo cppcheck > cppcheck.lic
echo 231231 >> cppcheck.lic
echo 241231 >> cppcheck.lic
echo 80000 >> cppcheck.lic
echo 57e08c39523ab54d >> cppcheck.lic
echo 53b72a908d7aeeee >> cppcheck.lic
echo path:lib >> cppcheck.lic
- name: Check

View File

@ -63,7 +63,7 @@ jobs:
# TODO: switch to Qt 6 after we enabled the Qt mappings again
- name: Prepare CMake
run: |
cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off
cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On
- name: Prepare CMake dependencies
run: |
@ -140,7 +140,7 @@ jobs:
- name: Prepare CMake
run: |
cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off
cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On
env:
CC: clang-17
CXX: clang++-17

View File

@ -221,6 +221,7 @@ Lukas Grützmacher
Lukasz Czajczyk
Łukasz Jankowski
Luxon Jean-Pierre
Maarten van der Schrieck
Maksim Derbasov
Malcolm Parsons
Marc-Antoine Perennou

View File

@ -1,14 +1,18 @@
cmake_minimum_required(VERSION 2.8.12)
project(Cppcheck)
cmake_minimum_required(VERSION 3.5)
if (MSVC)
cmake_minimum_required(VERSION 3.13)
endif()
cmake_policy(SET CMP0048 NEW) # allow VERSION in project()
project(Cppcheck VERSION 2.13.99 LANGUAGES CXX)
include(cmake/cxx11.cmake)
use_cxx11()
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include(GNUInstallDirs)
include(cmake/ccache.cmake)
include(cmake/compilerCheck.cmake)
include(cmake/versions.cmake)
include(cmake/options.cmake)

View File

@ -626,7 +626,7 @@ $(libcppdir)/settings.o: lib/settings.cpp externals/picojson/picojson.h lib/addo
$(libcppdir)/summaries.o: lib/summaries.cpp lib/addoninfo.h lib/analyzerinfo.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/summaries.cpp
$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/mathlib.h lib/path.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/mathlib.h lib/path.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp
$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/addoninfo.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h

View File

@ -33,8 +33,10 @@ Addons are scripts that analyses Cppcheck dump files to check compatibility with
Helper class for reading Cppcheck dump files within an addon.
- misra_9.py
Implementation of the MISRA 9.x rules used by `misra` addon.
- naming.json
- namingng.config.json
Example configuration for `namingng` addon.
- namingng.json
Example JSON file that can be used using --addon=namingng.json, referring to namingng.py and namingng.config.json
- ROS_naming.json
Example configuration for the `namingng` addon enforcing the [ROS naming convention for C++ ](http://wiki.ros.org/CppStyleGuide#Files).
- runaddon.py

View File

@ -1,5 +1,5 @@
{
"RE_FILE": {".*[A-Z]": [true, "under_scored"]},
"RE_FILE": [".*[A-Z]"],
"RE_NAMESPACE": {".*[A-Z]": [true, "under_scored"],
".*\\_$": [true, "under_scored"]},
"RE_FUNCTIONNAME": {".*\\_": [true, "camelCase"],

View File

@ -1619,11 +1619,11 @@ def is_suppressed(location, message, errorId):
return True
return False
def reportError(location, severity, message, addon, errorId, extra=''):
def reportError(location, severity, message, addon, errorId, extra='', columnOverride=None):
if '--cli' in sys.argv:
msg = { 'file': location.file,
'linenr': location.linenr,
'column': location.column,
'column': location.column if columnOverride is None else columnOverride,
'severity': severity,
'message': message,
'addon': addon,

View File

@ -311,8 +311,7 @@ class InitializerParser:
if self.ed and self.ed.isValue:
if not isDesignated and len(self.rootStack) > 0 and self.rootStack[-1][1] == self.root:
self.rootStack[-1][0].markStuctureViolation(self.token)
if isFirstElement and self.token.str == '0' and self.token.next.str == '}':
if isFirstElement and self.token.isInt and self.token.getKnownIntValue() == 0 and self.token.next.str == '}':
# Zero initializer causes recursive initialization
self.root.initializeChildren()
elif self.token.isString and self.ed.valueType and self.ed.valueType.pointer > 0:

View File

@ -2,6 +2,15 @@
"RE_VARNAME": ["[a-z]*[a-zA-Z0-9_]*\\Z"],
"RE_PRIVATE_MEMBER_VARIABLE": null,
"RE_FUNCTIONNAME": ["[a-z0-9A-Z]*\\Z"],
"include_guard": {
"input": "path",
"prefix": "",
"suffix": "",
"case": "upper",
"max_linenr": 5,
"RE_HEADERFILE": "[^/].*\\.h\\Z",
"required": true
},
"var_prefixes": {"uint32_t": "ui32",
"int*": "intp"},
"function_prefixes": {"uint16_t": "ui16",

6
addons/namingng.json Normal file
View File

@ -0,0 +1,6 @@
{
"script":"namingng.py",
"args":[
"--configfile=namingng.config.json"
]
}

View File

@ -3,6 +3,7 @@
# cppcheck addon for naming conventions
# An enhanced version. Configuration is taken from a json file
# It supports to check for type-based prefixes in function or variable names.
# Aside from include guard naming, include guard presence can also be tested.
#
# Example usage (variable name must start with lowercase, function name must start with uppercase):
# $ cppcheck --dump path-to-src/
@ -11,9 +12,18 @@
# JSON format:
#
# {
# "RE_VARNAME": "[a-z]*[a-zA-Z0-9_]*\\Z",
# "RE_VARNAME": ["[a-z]*[a-zA-Z0-9_]*\\Z"],
# "RE_PRIVATE_MEMBER_VARIABLE": null,
# "RE_FUNCTIONNAME": "[a-z0-9A-Z]*\\Z",
# "RE_FUNCTIONNAME": ["[a-z0-9A-Z]*\\Z"],
# "_comment": "comments can be added to the config with underscore-prefixed keys",
# "include_guard": {
# "input": "path",
# "prefix": "GUARD_",
# "case": "upper",
# "max_linenr": 5,
# "RE_HEADERFILE": "[^/].*\\.h\\Z",
# "required": true
# },
# "var_prefixes": {"uint32_t": "ui32"},
# "function_prefixes": {"uint16_t": "ui16",
# "uint32_t": "ui32"}
@ -24,230 +34,386 @@
import cppcheckdata
import sys
import os
import re
import argparse
import json
# Auxiliary class
class DataStruct:
def __init__(self, file, linenr, string):
def __init__(self, file, linenr, string, column=0):
self.file = file
self.linenr = linenr
self.str = string
self.column = column
def reportNamingError(location,message,errorId='namingConvention',severity='style',extra='',column=None):
cppcheckdata.reportError(location,severity,message,'namingng',errorId,extra,columnOverride=column)
def reportError(filename, linenr, severity, msg):
message = "[{filename}:{linenr}] ( {severity} ) naming.py: {msg}\n".format(
filename=filename,
linenr=linenr,
severity=severity,
msg=msg
)
sys.stderr.write(message)
return message
def configError(error,fatal=True):
print('config error: %s'%error)
if fatal:
sys.exit(1)
def validateConfigREs(list_or_dict,json_key):
have_error = False
for item in list_or_dict:
try:
re.compile(item)
except re.error as err:
configError("item '%s' of '%s' is not a valid regular expression: %s"%(item,json_key,err),fatal=False)
have_error = True
continue
if not isinstance(list_or_dict,dict):
continue
# item is actually a dict key; check value
value = list_or_dict[item]
if (not isinstance(value,list) or len(value) != 2
or not isinstance(value[0],bool) or not isinstance(value[1],str)):
configError("item '%s' of '%s' must be an array [bool,string]"%(item,json_key),fatal=False)
have_error = True
return have_error
def loadConfig(configfile):
with open(configfile) as fh:
data = json.load(fh)
return data
if not os.path.exists(configfile):
configError("cannot find config file '%s'"%configfile)
try:
with open(configfile) as fh:
data = json.load(fh)
except json.JSONDecodeError as e:
configError("error parsing config file as JSON at line %d: %s"%(e.lineno,e.msg))
except Exception as e:
configError("error opening config file '%s': %s"%(configfile,e))
if not isinstance(data, dict):
configError('config file must contain a JSON object at the top level')
# All errors are emitted before bailing out, to make the unit test more
# effective.
have_error = False
# Put config items in a class, so that settings can be accessed using
# config.feature
class Config:
pass
config = Config()
mapping = {
'file': ('RE_FILE', (list,)),
'namespace': ('RE_NAMESPACE', (list,dict)),
'include_guard': ('include_guard', (dict,)),
'variable': ('RE_VARNAME', (list,dict)),
'variable_prefixes': ('var_prefixes', (dict,), {}),
'private_member': ('RE_PRIVATE_MEMBER_VARIABLE', (list,dict)),
'public_member': ('RE_PUBLIC_MEMBER_VARIABLE', (list,dict)),
'global_variable': ('RE_GLOBAL_VARNAME', (list,dict)),
'function_name': ('RE_FUNCTIONNAME', (list,dict)),
'function_prefixes': ('function_prefixes', (dict,), {}),
'class_name': ('RE_CLASS_NAME', (list,dict)),
'skip_one_char_variables': ('skip_one_char_variables', (bool,)),
}
# parse defined keys and store as members of config object
for key,opts in mapping.items():
json_key = opts[0]
req_type = opts[1]
default = None if len(opts)<3 else opts[2]
value = data.pop(json_key,default)
if value is not None and type(value) not in req_type:
req_typename = ' or '.join([tp.__name__ for tp in req_type])
got_typename = type(value).__name__
configError('%s must be %s (not %s), or not set'%(json_key,req_typename,got_typename),fatal=False)
have_error = True
continue
# type list implies that this is either a list of REs or a dict with RE keys
if list in req_type and value is not None:
re_error = validateConfigREs(value,json_key)
if re_error:
have_error = True
setattr(config,key,value)
# check remaining keys, only accept underscore-prefixed comments
for key,value in data.items():
if key == '' or key[0] != '_':
configError("unknown config key '%s'"%key,fatal=False)
have_error = True
if have_error:
sys.exit(1)
return config
def checkTrueRegex(data, expr, msg, errors):
res = re.match(expr, data.str)
if res:
errors.append(reportError(data.file, data.linenr, 'style', msg))
def evalExpr(conf, exp, mockToken, msgType):
report_as_error = False
msg = msgType + ' ' + mockToken.str + ' violates naming convention'
def checkFalseRegex(data, expr, msg, errors):
res = re.match(expr, data.str)
if not res:
errors.append(reportError(data.file, data.linenr, 'style', msg))
def evalExpr(conf, exp, mockToken, msgType, errors):
if isinstance(conf, dict):
if conf[exp][0]:
msg = msgType + ' ' + mockToken.str + ' violates naming convention : ' + conf[exp][1]
checkTrueRegex(mockToken, exp, msg, errors)
elif ~conf[exp][0]:
msg = msgType + ' ' + mockToken.str + ' violates naming convention : ' + conf[exp][1]
checkFalseRegex(mockToken, exp, msg, errors)
else:
msg = msgType + ' ' + mockToken.str + ' violates naming convention : ' + conf[exp][0]
checkFalseRegex(mockToken, exp, msg, errors)
report_as_error = conf[exp][0]
msg += ': ' + conf[exp][1]
res = re.match(exp,mockToken.str)
if bool(res) == report_as_error:
reportNamingError(mockToken,msg)
def check_include_guard_name(conf,directive):
parts = directive.str.split()
if len(parts) != 2:
msg = 'syntax error'
reportNamingError(directive,msg,'syntax')
return None,None
guard_name = parts[1]
guard_column = 1+directive.str.find(guard_name)
filename = directive.file
if conf.include_guard.get('input','path') == 'basename':
filename = os.path.basename(filename)
use_case = conf.include_guard.get('case','upper')
if use_case == 'upper':
filename = filename.upper()
elif use_case == 'lower':
filename = filename.lower()
elif use_case == 'keep':
pass # keep filename case as-is
else:
msg = msgType + ' ' + mockToken.str + ' violates naming convention'
checkFalseRegex(mockToken, exp, msg, errors)
print("invalid config value for 'case': '%s'"%use_case,file=sys.stderr)
sys.exit(1)
barename = re.sub('[^A-Za-z0-9]','_',filename).strip('_')
expect_guard_name = conf.include_guard.get('prefix','') + barename + conf.include_guard.get('suffix','')
if expect_guard_name != guard_name:
msg = 'include guard naming violation; %s != %s'%(guard_name,expect_guard_name)
reportNamingError(directive,msg,'includeGuardName',column=guard_column)
def process(dumpfiles, configfile, debugprint=False):
return guard_name,guard_column
errors = []
def check_include_guards(conf,cfg,unguarded_include_files):
# Scan for '#ifndef FILE_H' as the first directive, in the first N lines.
# Then test whether the next directive #defines the found name.
# Various tests are done:
# - check include guards for their naming and consistency
# - test whether include guards are in place
max_linenr = conf.include_guard.get('max_linenr', 5)
def report(directive,msg,errorId,column=0):
reportNamingError(directive,msg,errorId,column=column)
def report_pending_ifndef(directive,column):
report(directive,'include guard #ifndef is not followed by #define','includeGuardIncomplete',column=column)
last_fn = None
pending_ifndef = None
phase = 0
for directive in cfg.directives:
if last_fn != directive.file:
if pending_ifndef:
report_pending_ifndef(pending_ifndef,guard_column)
pending_ifndef = None
last_fn = directive.file
phase = 0
if phase == -1:
# ignore (the remainder of) this file
continue
if not re.match(include_guard_header_re,directive.file):
phase = -1
continue
if directive.linenr > max_linenr:
if phase == 0 and conf.include_guard.get('required',1):
report(directive,'include guard not found before line %d'%max_linenr,'includeGuardMissing')
phase = -1
continue
if phase == 0:
# looking for '#ifndef FILE_H'
if not directive.str.startswith('#ifndef'):
if conf.include_guard.get('required',1):
report(directive,'first preprocessor directive should be include guard #ifndef','includeGuardMissing')
phase = -1
continue
guard_name,guard_column = check_include_guard_name(conf,directive)
if guard_name == None:
phase = -1
continue
pending_ifndef = directive
phase = 1
elif phase == 1:
pending_ifndef = None
# looking for '#define FILE_H'
if not directive.str.startswith('#define'):
report(directive,'second preprocessor directive should be include guard #define','includeGuardIncomplete')
phase = -1
continue
parts = directive.str.split()
if len(parts) == 1:
report(directive,'syntax error','syntax')
phase = -1
continue
if guard_name != parts[1]:
report(directive,'include guard does not guard; %s != %s'%(guard_name,parts[1]),'includeGuardAwayFromDuty',severity='warning',column=guard_column)
unguarded_include_files.remove(directive.file)
phase = -1
if pending_ifndef:
report_pending_ifndef(pending_ifndef,guard_column)
def process(dumpfiles, configfile):
conf = loadConfig(configfile)
if conf.include_guard:
global include_guard_header_re
include_guard_header_re = conf.include_guard.get('RE_HEADERFILE',"[^/].*\\.h\\Z")
for afile in dumpfiles:
if not afile[-5:] == '.dump':
continue
print('Checking ' + afile + '...')
if not args.cli:
print('Checking ' + afile + '...')
data = cppcheckdata.CppcheckData(afile)
process_data(conf,data)
# Check File naming
if "RE_FILE" in conf and conf["RE_FILE"]:
mockToken = DataStruct(afile[:-5], "0", afile[afile.rfind('/') + 1:-5])
msgType = 'File name'
for exp in conf["RE_FILE"]:
evalExpr(conf["RE_FILE"], exp, mockToken, msgType, errors)
def check_file_naming(conf,data):
for source_file in data.files:
basename = os.path.basename(source_file)
good = False
for exp in conf.file:
good |= bool(re.match(exp, source_file))
good |= bool(re.match(exp, basename))
if not good:
mockToken = DataStruct(source_file, 0, basename)
reportNamingError(mockToken, 'File name ' + basename + ' violates naming convention')
# Check Namespace naming
if "RE_NAMESPACE" in conf and conf["RE_NAMESPACE"]:
for tk in data.rawTokens:
if tk.str == 'namespace':
mockToken = DataStruct(tk.next.file, tk.next.linenr, tk.next.str)
msgType = 'Namespace'
for exp in conf["RE_NAMESPACE"]:
evalExpr(conf["RE_NAMESPACE"], exp, mockToken, msgType, errors)
def check_namespace_naming(conf,data):
for tk in data.rawTokens:
if tk.str != 'namespace':
continue
mockToken = DataStruct(tk.next.file, tk.next.linenr, tk.next.str, tk.next.column)
for exp in conf.namespace:
evalExpr(conf.namespace, exp, mockToken, 'Namespace')
for cfg in data.configurations:
print('Checking %s, config %s...' % (afile, cfg.name))
if "RE_VARNAME" in conf and conf["RE_VARNAME"]:
for var in cfg.variables:
if var.nameToken and var.access != 'Global' and var.access != 'Public' and var.access != 'Private':
prev = var.nameToken.previous
varType = prev.str
while "*" in varType and len(varType.replace("*", "")) == 0:
prev = prev.previous
varType = prev.str + varType
def check_variable_naming(conf,cfg):
for var in cfg.variables:
if not var.nameToken:
continue
if var.access in ('Global','Public','Private'):
continue
prev = var.nameToken.previous
varType = prev.str
while "*" in varType and len(varType.replace("*", "")) == 0:
prev = prev.previous
varType = prev.str + varType
if debugprint:
print("Variable Name: " + str(var.nameToken.str))
print("original Type Name: " + str(var.nameToken.valueType.originalTypeName))
print("Type Name: " + var.nameToken.valueType.type)
print("Sign: " + str(var.nameToken.valueType.sign))
print("variable type: " + varType)
print("\n")
print("\t-- {} {}".format(varType, str(var.nameToken.str)))
if args.debugprint:
print("Variable Name: " + str(var.nameToken.str))
print("original Type Name: " + str(var.nameToken.valueType.originalTypeName))
print("Type Name: " + var.nameToken.valueType.type)
print("Sign: " + str(var.nameToken.valueType.sign))
print("variable type: " + varType)
print("\n")
print("\t-- {} {}".format(varType, str(var.nameToken.str)))
if conf["skip_one_char_variables"] and len(var.nameToken.str) == 1:
continue
if varType in conf["var_prefixes"]:
if not var.nameToken.str.startswith(conf["var_prefixes"][varType]):
errors.append(reportError(
var.typeStartToken.file,
var.typeStartToken.linenr,
'style',
'Variable ' +
var.nameToken.str +
' violates naming convention'))
if conf.skip_one_char_variables and len(var.nameToken.str) == 1:
continue
if varType in conf.variable_prefixes:
prefix = conf.variable_prefixes[varType]
if not var.nameToken.str.startswith(prefix):
reportNamingError(var.typeStartToken,
'Variable ' +
var.nameToken.str +
' violates naming convention',
column=var.nameToken.column)
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str)
msgType = 'Variable'
for exp in conf["RE_VARNAME"]:
evalExpr(conf["RE_VARNAME"], exp, mockToken, msgType, errors)
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str, var.nameToken.column)
for exp in conf.variable:
evalExpr(conf.variable, exp, mockToken, 'Variable')
# Check Private Variable naming
if "RE_PRIVATE_MEMBER_VARIABLE" in conf and conf["RE_PRIVATE_MEMBER_VARIABLE"]:
# TODO: Not converted yet
for var in cfg.variables:
if (var.access is None) or var.access != 'Private':
continue
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str)
msgType = 'Private member variable'
for exp in conf["RE_PRIVATE_MEMBER_VARIABLE"]:
evalExpr(conf["RE_PRIVATE_MEMBER_VARIABLE"], exp, mockToken, msgType, errors)
# Naming check for Global, Private and Public member variables
def check_gpp_naming(conf_list,cfg,access,message):
for var in cfg.variables:
if var.access != access:
continue
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str, var.nameToken.column)
for exp in conf_list:
evalExpr(conf_list, exp, mockToken, message)
# Check Public Member Variable naming
if "RE_PUBLIC_MEMBER_VARIABLE" in conf and conf["RE_PUBLIC_MEMBER_VARIABLE"]:
for var in cfg.variables:
if (var.access is None) or var.access != 'Public':
continue
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str)
msgType = 'Public member variable'
for exp in conf["RE_PUBLIC_MEMBER_VARIABLE"]:
evalExpr(conf["RE_PUBLIC_MEMBER_VARIABLE"], exp, mockToken, msgType, errors)
def check_function_naming(conf,cfg):
for token in cfg.tokenlist:
if not token.function:
continue
if token.function.type in ('Constructor', 'Destructor', 'CopyConstructor', 'MoveConstructor'):
continue
retval = token.previous.str
prev = token.previous
while "*" in retval and len(retval.replace("*", "")) == 0:
prev = prev.previous
retval = prev.str + retval
if args.debugprint:
print("\t:: {} {}".format(retval, token.function.name))
# Check Global Variable naming
if "RE_GLOBAL_VARNAME" in conf and conf["RE_GLOBAL_VARNAME"]:
for var in cfg.variables:
if (var.access is None) or var.access != 'Global':
continue
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str)
msgType = 'Public member variable'
for exp in conf["RE_GLOBAL_VARNAME"]:
evalExpr(conf["RE_GLOBAL_VARNAME"], exp, mockToken, msgType, errors)
if retval and retval in conf.function_prefixes:
if not token.function.name.startswith(conf.function_prefixes[retval]):
reportNamingError(token, 'Function ' + token.function.name + ' violates naming convention', column=token.column)
mockToken = DataStruct(token.file, token.linenr, token.function.name, token.column)
msgType = 'Function'
for exp in conf.function_name:
evalExpr(conf.function_name, exp, mockToken, msgType)
# Check Functions naming
if "RE_FUNCTIONNAME" in conf and conf["RE_FUNCTIONNAME"]:
for token in cfg.tokenlist:
if token.function:
if token.function.type in ('Constructor', 'Destructor', 'CopyConstructor', 'MoveConstructor'):
continue
retval = token.previous.str
prev = token.previous
while "*" in retval and len(retval.replace("*", "")) == 0:
prev = prev.previous
retval = prev.str + retval
if debugprint:
print("\t:: {} {}".format(retval, token.function.name))
def check_class_naming(conf,cfg):
for fnc in cfg.functions:
if fnc.type not in ('Constructor','Destructor'):
continue
mockToken = DataStruct(fnc.tokenDef.file, fnc.tokenDef.linenr, fnc.name, fnc.tokenDef.column)
msgType = 'Class ' + fnc.type
for exp in conf.class_name:
evalExpr(conf.class_name, exp, mockToken, msgType)
if retval and retval in conf["function_prefixes"]:
if not token.function.name.startswith(conf["function_prefixes"][retval]):
errors.append(reportError(
token.file, token.linenr, 'style', 'Function ' + token.function.name + ' violates naming convention'))
mockToken = DataStruct(token.file, token.linenr, token.function.name)
msgType = 'Function'
for exp in conf["RE_FUNCTIONNAME"]:
evalExpr(conf["RE_FUNCTIONNAME"], exp, mockToken, msgType, errors)
def process_data(conf,data):
if conf.file:
check_file_naming(conf,data)
# Check Class naming
if "RE_CLASS_NAME" in conf and conf["RE_CLASS_NAME"]:
for fnc in cfg.functions:
# Check if it is Constructor/Destructor
if fnc.type == 'Constructor' or fnc.type == 'Destructor':
mockToken = DataStruct(fnc.tokenDef.file, fnc.tokenDef.linenr, fnc.name)
msgType = 'Class ' + fnc.type
for exp in conf["RE_CLASS_NAME"]:
evalExpr(conf["RE_CLASS_NAME"], exp, mockToken, msgType, errors)
return errors
if conf.namespace:
check_namespace_naming(conf,data)
unguarded_include_files = []
if conf.include_guard and conf.include_guard.get('required',1):
unguarded_include_files = [fn for fn in data.files if re.match(include_guard_header_re,fn)]
for cfg in data.configurations:
if not args.cli:
print('Checking config %s...' % cfg.name)
if conf.variable:
check_variable_naming(conf,cfg)
if conf.private_member:
check_gpp_naming(conf.private_member,cfg,'Private','Private member variable')
if conf.public_member:
check_gpp_naming(conf.public_member,cfg,'Public','Public member variable')
if conf.global_variable:
check_gpp_naming(conf.global_variable,cfg,'Global','Global variable')
if conf.function_name:
check_function_naming(conf,cfg)
if conf.class_name:
check_class_naming(conf,cfg)
if conf.include_guard:
check_include_guards(conf,cfg,unguarded_include_files)
for fn in unguarded_include_files:
mockToken = DataStruct(fn,0,os.path.basename(fn))
reportNamingError(mockToken,'Missing include guard','includeGuardMissing')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Naming verification')
parser.add_argument('dumpfiles', type=str, nargs='+',
help='A set of dumpfiles to process')
parser = cppcheckdata.ArgumentParser()
parser.add_argument("--debugprint", action="store_true", default=False,
help="Add debug prints")
parser.add_argument("--configfile", type=str, default="naming.json",
parser.add_argument("--configfile", type=str, default="namingng.config.json",
help="Naming check config file")
parser.add_argument("--verify", action="store_true", default=False,
help="verify this script. Must be executed in test folder !")
args = parser.parse_args()
errors = process(args.dumpfiles, args.configfile, args.debugprint)
if args.verify:
print(errors)
if len(errors) < 6:
print("Not enough errors found")
sys.exit(1)
target = [
'[namingng_test.c:8] ( style ) naming.py: Variable badui32 violates naming convention\n',
'[namingng_test.c:11] ( style ) naming.py: Variable a violates naming convention\n',
'[namingng_test.c:29] ( style ) naming.py: Variable badui32 violates naming convention\n',
'[namingng_test.c:20] ( style ) naming.py: Function ui16bad_underscore violates naming convention\n',
'[namingng_test.c:25] ( style ) naming.py: Function u32Bad violates naming convention\n',
'[namingng_test.c:37] ( style ) naming.py: Function Badui16 violates naming convention\n']
diff = set(errors) - set(target)
if len(diff):
print("Not the right errors found {}".format(str(diff)))
sys.exit(1)
print("Verification done\n")
sys.exit(0)
if len(errors):
print('Found errors: {}'.format(len(errors)))
sys.exit(1)
process(args.dumpfile, args.configfile)
sys.exit(0)

View File

@ -441,6 +441,7 @@ static void misra_9_empty_or_zero_initializers(void) {
int e[2][2] = { { 1 , 2 }, {} }; // 9.2
int f[5] = { 0 };
int f1[5] = { 0u }; // no-warning #11298
int g[5][2] = { 0 };
int h[2][2] = { { 0 } }; // 9.3
int i[2][2] = { { 0 }, { 0 } };

View File

@ -1,50 +0,0 @@
#include <stddef.h>
#include <stdint.h>
uint32_t ui32Good (int abc)
{
uint32_t ui32good;
int32_t i32good;
uint32_t badui32;
int32_t badi32;
uint32_t a; // Short
return 5;
}
uint16_t ui16Good (int a)
{
return 5;
}
uint16_t ui16bad_underscore (int a)
{
return 5;
}
uint32_t u32Bad (int a)
{
uint32_t ui32good;
int32_t i32good;
uint32_t badui32;
int32_t badi32;
int * intpointer=NULL;
int ** intppointer=NULL;
int *** intpppointer=NULL;
return 5;
}
uint16_t Badui16 (int a)
{
return 5;
}
void * Pointer()
{
return NULL;
}
void ** PPointer()
{
return NULL;
}

View File

@ -6,6 +6,7 @@
<define name="cairo_bool_t" value="int"/>
<!-- TODO: Configure cairo_status_t as an enum when this is implemented in Cppcheck -->
<podtype name="cairo_status_t"/>
<define name="CAIRO_STATUS_READ_ERROR" value="10"/>
<!-- ########## cairo Macros / Defines ########## -->
<define name="CAIRO_HAS_MIME_SURFACE" value="1"/>
<define name="CAIRO_MIME_TYPE_CCITT_FAX" value="&quot;image/g3fax&quot;"/>

View File

@ -2,6 +2,8 @@
<!-- This file once has been generated automatically. See https://github.com/scriptum/cppcheck-libs -->
<!-- Now it is maintained and extended manually. -->
<def format="2">
<define name="TRUE" value="(!FALSE)"/>
<define name="FALSE" value="(0)"/>
<define name="g_return_if_fail(expr)" value="do{if(!(expr)){return;}}while(0)"/>
<define name="g_return_val_if_fail(expr, val)" value="do{if(!(expr)){return val;}}while(0)"/>
<define name="g_return_if_reached()" value="do{return;}while(0)"/>
@ -178,11 +180,14 @@
<define name="g_assert(expr)" value="assert(expr)"/>
<define name="g_assert_not_reached()" value="assert(NULL)"/>
<define name="g_assert_true(expr)" value="g_assert(expr)"/>
<define name="g_assert_false(expr)" value="g_assert(!(expr))"/>
<define name="g_assert_cmpstr(s1, cmp, s2)" value="g_assert_true(g_strcmp0 ((s1), (s2)) cmp 0)"/>
<define name="g_assert_cmpint(n1, cmp, n2)" value="g_assert_true((n1) cmp (n2))"/>
<define name="g_assert_cmpuint(n1, cmp, n2)" value="g_assert_true((n1) cmp (n2))"/>
<define name="g_assert_cmphex(n1, cmp, n2)" value="g_assert_true((n1) cmp (n2))"/>
<define name="g_assert_cmpfloat(n1, cmp, n2)" value="g_assert_true((n1) cmp (n2))"/>
<define name="g_assert_null(expr)" value="g_assert_true((expr) == NULL)"/>
<define name="g_assert_nonnull(expr)" value="g_assert_true((expr) != NULL)"/>
<define name="g_signal_connect(instance, detailed_signal, c_handler, data)" value="g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0)"/>
<define name="g_signal_connect_after(instance, detailed_signal, c_handler, data)" value="g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, G_CONNECT_AFTER)"/>
<define name="g_signal_connect_swapped(instance, detailed_signal, c_handler, data)" value="g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, G_CONNECT_SWAPPED)"/>

View File

@ -4179,6 +4179,30 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s
<valid>0:</valid>
</arg>
</function>
<!-- https://pubs.opengroup.org/onlinepubs/9699919799/functions/strxfrm_l.html -->
<!-- size_t strxfrm_l(char *restrict s1, const char *restrict s2, size_t n, locale_t locale) -->
<function name="strxfrm_l">
<returnValue type="size_t"/>
<noreturn>false</noreturn>
<leak-ignore/>
<!-- In case the 3rd argument is 0, the 1st argument is permitted to be a null pointer. (#6306) -->
<arg nr="1" direction="out">
<minsize type="argvalue" arg="3"/>
</arg>
<arg nr="2" direction="in">
<not-null/>
<not-uninit/>
<strz/>
<minsize type="argvalue" arg="3"/>
</arg>
<arg nr="3" direction="in">
<not-uninit/>
<valid>0:</valid>
</arg>
<arg nr="4" direction="in">
<not-uninit/>
</arg>
</function>
<!-- https://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html -->
<!-- char *asctime_r(const struct tm *tm, char *buf); -->
<function name="asctime_r">

View File

@ -737,6 +737,7 @@
<not-uninit/>
</arg>
</function>
<!-- https://en.cppreference.com/w/cpp/numeric/math/tgamma -->
<!-- double tgamma(double x); -->
<function name="tgamma,std::tgamma">
<use-retval/>
@ -746,8 +747,11 @@
<leak-ignore/>
<arg nr="1" direction="in">
<not-uninit/>
<!-- If x is zero or a negative integer for which the function is asymptotic, it may cause a pole error (depending on implementation).-->
<valid>!0.0:</valid>
</arg>
</function>
<!-- https://en.cppreference.com/w/cpp/numeric/math/tgamma -->
<!-- float tgammaf(float x); -->
<function name="tgammaf,std::tgammaf">
<use-retval/>
@ -757,8 +761,11 @@
<leak-ignore/>
<arg nr="1" direction="in">
<not-uninit/>
<!-- If x is zero or a negative integer for which the function is asymptotic, it may cause a pole error (depending on implementation).-->
<valid>!0.0:</valid>
</arg>
</function>
<!-- https://en.cppreference.com/w/cpp/numeric/math/tgamma -->
<!-- long double tgammal(long double x); -->
<function name="tgammal,std::tgammal">
<use-retval/>
@ -768,6 +775,8 @@
<leak-ignore/>
<arg nr="1" direction="in">
<not-uninit/>
<!-- If x is zero or a negative integer for which the function is asymptotic, it may cause a pole error (depending on implementation).-->
<valid>!0.0:</valid>
</arg>
</function>
<!-- double trunc(double x); -->
@ -3035,6 +3044,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<not-uninit/>
</arg>
</function>
<!-- https://cplusplus.com/reference/cmath/lgamma/ -->
<!-- double lgamma(double x); -->
<function name="lgamma,std::lgamma">
<use-retval/>
@ -3044,8 +3054,11 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<leak-ignore/>
<arg nr="1" direction="in">
<not-uninit/>
<!-- If x is zero or a negative integer for which the function is asymptotic, it may cause a pole error (depending on implementation).-->
<valid>!0.0:</valid>
</arg>
</function>
<!-- https://cplusplus.com/reference/cmath/lgamma/ -->
<!-- float lgammaf(float x); -->
<function name="lgammaf,std::lgammaf">
<use-retval/>
@ -3055,8 +3068,11 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<leak-ignore/>
<arg nr="1" direction="in">
<not-uninit/>
<!-- If x is zero or a negative integer for which the function is asymptotic, it may cause a pole error (depending on implementation).-->
<valid>!0.0:</valid>
</arg>
</function>
<!-- https://cplusplus.com/reference/cmath/lgamma/ -->
<!-- long double lgammal(long double x); -->
<function name="lgammal,std::lgammal">
<use-retval/>
@ -3066,6 +3082,8 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<leak-ignore/>
<arg nr="1" direction="in">
<not-uninit/>
<!-- If x is zero or a negative integer for which the function is asymptotic, it may cause a pole error (depending on implementation).-->
<valid>!0.0:</valid>
</arg>
</function>
<!-- double rint(double x); -->

View File

@ -6,11 +6,11 @@ list(REMOVE_ITEM srcs ${mainfile})
add_library(cli_objs OBJECT ${hdrs} ${srcs})
target_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/lib/)
if(USE_BUNDLED_TINYXML2)
target_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/externals/tinyxml2/)
target_externals_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/externals/tinyxml2/)
else()
target_include_directories(cli_objs SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS})
endif()
target_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/externals/simplecpp/)
target_externals_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/externals/simplecpp/)
if (NOT CMAKE_DISABLE_PRECOMPILE_HEADERS)
target_precompile_headers(cli_objs PRIVATE precompiled.h)
endif()
@ -38,11 +38,11 @@ endif()
add_executable(cppcheck ${cppcheck_SOURCES})
target_include_directories(cppcheck PRIVATE ${PROJECT_SOURCE_DIR}/lib/)
if(USE_BUNDLED_TINYXML2)
target_include_directories(cppcheck PRIVATE ${PROJECT_SOURCE_DIR}/externals/tinyxml2/)
target_externals_include_directories(cppcheck PRIVATE ${PROJECT_SOURCE_DIR}/externals/tinyxml2/)
else()
target_include_directories(cppcheck SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS})
endif()
target_include_directories(cppcheck PRIVATE ${PROJECT_SOURCE_DIR}/externals/simplecpp/)
target_externals_include_directories(cppcheck PRIVATE ${PROJECT_SOURCE_DIR}/externals/simplecpp/)
if (HAVE_RULES)
target_link_libraries(cppcheck ${PCRE_LIBRARY})
endif()

View File

@ -42,6 +42,7 @@
#include <algorithm>
#include <cassert>
#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstdlib> // EXIT_FAILURE
#include <cstring>
@ -797,9 +798,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
}
if (str == "c")
mSettings.enforcedLang = Settings::Language::C;
mSettings.enforcedLang = Standards::Language::C;
else if (str == "c++")
mSettings.enforcedLang = Settings::Language::CPP;
mSettings.enforcedLang = Standards::Language::CPP;
else {
mLogger.printError("unknown language '" + str + "' enforced.");
return Result::Fail;

View File

@ -42,6 +42,7 @@
#endif
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib> // EXIT_SUCCESS and EXIT_FAILURE
#include <ctime>
@ -49,6 +50,7 @@
#include <list>
#include <set>
#include <sstream> // IWYU pragma: keep
#include <unordered_set>
#include <utility>
#include <vector>
@ -217,21 +219,29 @@ int CppCheckExecutor::check_wrapper(CppCheck& cppcheck)
return check_internal(cppcheck);
}
bool CppCheckExecutor::reportSuppressions(const Settings &settings, bool unusedFunctionCheckEnabled, const std::list<std::pair<std::string, std::size_t>> &files, ErrorLogger& errorLogger) {
const auto& suppressions = settings.nomsg.getSuppressions();
if (std::any_of(suppressions.begin(), suppressions.end(), [](const Suppressions::Suppression& s) {
bool CppCheckExecutor::reportSuppressions(const Settings &settings, const Suppressions& suppressions, bool unusedFunctionCheckEnabled, const std::list<std::pair<std::string, std::size_t>> &files, const std::list<FileSettings>& fileSettings, ErrorLogger& errorLogger) {
const auto& suppr = suppressions.getSuppressions();
if (std::any_of(suppr.begin(), suppr.end(), [](const Suppressions::Suppression& s) {
return s.errorId == "unmatchedSuppression" && s.fileName.empty() && s.lineNumber == Suppressions::Suppression::NO_LINE;
}))
return false;
bool err = false;
if (settings.useSingleJob()) {
// the two inputs may only be used exclusively
assert(!(!files.empty() && !fileSettings.empty()));
for (std::list<std::pair<std::string, std::size_t>>::const_iterator i = files.cbegin(); i != files.cend(); ++i) {
err |= Suppressions::reportUnmatchedSuppressions(
settings.nomsg.getUnmatchedLocalSuppressions(i->first, unusedFunctionCheckEnabled), errorLogger);
suppressions.getUnmatchedLocalSuppressions(i->first, unusedFunctionCheckEnabled), errorLogger);
}
for (std::list<FileSettings>::const_iterator i = fileSettings.cbegin(); i != fileSettings.cend(); ++i) {
err |= Suppressions::reportUnmatchedSuppressions(
suppressions.getUnmatchedLocalSuppressions(i->filename, unusedFunctionCheckEnabled), errorLogger);
}
}
err |= Suppressions::reportUnmatchedSuppressions(settings.nomsg.getUnmatchedGlobalSuppressions(unusedFunctionCheckEnabled), errorLogger);
err |= Suppressions::reportUnmatchedSuppressions(suppressions.getUnmatchedGlobalSuppressions(unusedFunctionCheckEnabled), errorLogger);
return err;
}
@ -277,7 +287,7 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck) const
cppcheck.analyseWholeProgram(settings.buildDir, mFiles, mFileSettings);
if (settings.severity.isEnabled(Severity::information) || settings.checkConfiguration) {
const bool err = reportSuppressions(settings, cppcheck.isUnusedFunctionCheckEnabled(), mFiles, *mStdLogger);
const bool err = reportSuppressions(settings, settings.nomsg, cppcheck.isUnusedFunctionCheckEnabled(), mFiles, mFileSettings, *mStdLogger);
if (err && returnValue == 0)
returnValue = settings.exitCode;
}

View File

@ -31,6 +31,7 @@
class CppCheck;
class Settings;
class ErrorLogger;
class Suppressions;
/**
* This class works as an example of how CppCheck can be used in external
@ -48,7 +49,7 @@ public:
*/
CppCheckExecutor() = default;
CppCheckExecutor(const CppCheckExecutor &) = delete;
void operator=(const CppCheckExecutor&) = delete;
CppCheckExecutor& operator=(const CppCheckExecutor&) = delete;
/**
* Starts the checking.
@ -81,7 +82,7 @@ private:
protected:
static bool reportSuppressions(const Settings &settings, bool unusedFunctionCheckEnabled, const std::list<std::pair<std::string, std::size_t>> &files, ErrorLogger& errorLogger);
static bool reportSuppressions(const Settings &settings, const Suppressions& suppressions, bool unusedFunctionCheckEnabled, const std::list<std::pair<std::string, std::size_t>> &files, const std::list<FileSettings>& fileSettings, ErrorLogger& errorLogger);
/**
* Wrapper around check_internal

View File

@ -109,7 +109,7 @@ static void CppcheckSignalHandler(int signo, siginfo_t * info, void * context)
pid_t killid;
// TODO: separate these two defines
#if defined(__linux__) && defined(REG_ERR)
const ucontext_t* const uc = reinterpret_cast<const ucontext_t*>(context);
const auto* const uc = reinterpret_cast<const ucontext_t*>(context);
killid = (pid_t) syscall(SYS_gettid);
if (uc) {
type = (int)uc->uc_mcontext.gregs[REG_ERR] & 2;

View File

@ -20,10 +20,10 @@
#include "color.h"
#include "errorlogger.h"
#include "library.h"
#include "settings.h"
#include "suppressions.h"
#include <algorithm>
#include <cassert>
#include <sstream> // IWYU pragma: keep
#include <utility>

View File

@ -45,7 +45,7 @@ public:
virtual ~Executor() = default;
Executor(const Executor &) = delete;
void operator=(const Executor &) = delete;
Executor& operator=(const Executor &) = delete;
virtual unsigned int check() = 0;

View File

@ -20,7 +20,7 @@
/**
*
* @mainpage Cppcheck
* @version 2.12.99
* @version 2.13.99
*
* @section overview_sec Overview
* Cppcheck is a simple tool for static analysis of C/C++ code.

View File

@ -107,11 +107,11 @@ namespace {
void writeToPipe(PipeSignal type, const std::string &data) const
{
{
const char t = static_cast<char>(type);
const auto t = static_cast<char>(type);
writeToPipeInternal(type, &t, 1);
}
const unsigned int len = static_cast<unsigned int>(data.length());
const auto len = static_cast<unsigned int>(data.length());
{
static constexpr std::size_t l_size = sizeof(unsigned int);
writeToPipeInternal(type, &len, l_size);

View File

@ -43,7 +43,7 @@ class ProcessExecutor : public Executor {
public:
ProcessExecutor(const std::list<std::pair<std::string, std::size_t>> &files, const std::list<FileSettings>& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand);
ProcessExecutor(const ProcessExecutor &) = delete;
void operator=(const ProcessExecutor &) = delete;
ProcessExecutor& operator=(const ProcessExecutor &) = delete;
unsigned int check() override;

View File

@ -37,7 +37,7 @@ class SingleExecutor : public Executor
public:
SingleExecutor(CppCheck &cppcheck, const std::list<std::pair<std::string, std::size_t>> &files, const std::list<FileSettings>& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger);
SingleExecutor(const SingleExecutor &) = delete;
void operator=(const SingleExecutor &) = delete;
SingleExecutor& operator=(const SingleExecutor &) = delete;
unsigned int check() override;

View File

@ -45,7 +45,7 @@ class ThreadExecutor : public Executor {
public:
ThreadExecutor(const std::list<std::pair<std::string, std::size_t>> &files, const std::list<FileSettings>& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand);
ThreadExecutor(const ThreadExecutor &) = delete;
void operator=(const ThreadExecutor &) = delete;
ThreadExecutor& operator=(const ThreadExecutor &) = delete;
unsigned int check() override;

View File

@ -1,7 +0,0 @@
if (CMAKE_VERSION VERSION_LESS "3.0")
if (CMAKE_CXX_COMPILER_LAUNCHER)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_CXX_COMPILER_LAUNCHER}")
elseif (CMAKE_C_COMPILER_LAUNCHER)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_C_COMPILER_LAUNCHER}")
endif()
endif()

View File

@ -1,14 +1,13 @@
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
message(ERROR "GCC >= 4.8 required - detected ${CMAKE_CXX_COMPILER_VERSION} not supported")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
message(ERROR "GCC >= 5.1 required - detected ${CMAKE_CXX_COMPILER_VERSION} not supported")
endif ()
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# TODO: verify this
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2.9)
message(ERROR "Clang >= 2.9 required - detected ${CMAKE_CXX_COMPILER_VERSION} not supported")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)
message(ERROR "Clang >= 3.5 required - detected ${CMAKE_CXX_COMPILER_VERSION} not supported")
endif ()
elseif(MSVC)
if (MSVC_VERSION VERSION_LESS 1800)
message(ERROR "Visual Studio >= 2013 (1800) required - detected ${MSVC_VERSION} not supported")
if (MSVC_VERSION VERSION_LESS 1900)
message(ERROR "Visual Studio >= 2015 (19.0) required - detected ${MSVC_VERSION} not supported")
endif ()
endif()

View File

@ -1,4 +1,6 @@
if (MSVC)
# add_compile_definitions() requires CMake 3.12
# Visual Studio only sets _DEBUG
add_compile_definitions($<$<CONFIG:Debug>:DEBUG>)

View File

@ -16,6 +16,14 @@ function(target_compile_options_safe TARGET FLAG)
endif()
endfunction()
function(target_externals_include_directories TARGET)
if (EXTERNALS_AS_SYSTEM)
target_include_directories(${TARGET} SYSTEM ${ARGN})
else()
target_include_directories(${TARGET} ${ARGN})
endif()
endfunction()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Weverything)
endif()
@ -77,7 +85,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if (USE_LIBCXX)
add_compile_options(-stdlib=libc++)
add_link_options(-lc++)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lc++")
endif()
# TODO: fix and enable these warnings - or move to suppression list below
@ -125,6 +133,8 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
endif()
if (MSVC)
# add_link_options() requires CMake 3.13
# General
add_compile_options(/W4) # Warning Level
add_compile_options(/Zi) # Debug Information Format - Program Database

View File

@ -1,20 +1,9 @@
macro(use_cxx11)
if (CMAKE_VERSION VERSION_LESS "3.1")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif ()
# some GitHub Action Windows runners randomly fail with a complaint that Qt6 requires a C++17 compiler
if (MSVC AND USE_QT6)
# CMAKE_CXX_STANDARD 17 was added in CMake 3.8
set (CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to use")
else ()
# some GitHub Action windows runners randomly fail with a complaint that Qt6 requires a C++17 compiler
if (MSVC)
set (CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to use")
else ()
set (CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to use")
endif()
set (CMAKE_CXX_STANDARD_REQUIRED ON)
if (POLICY CMP0025)
cmake_policy(SET CMP0025 NEW)
endif ()
endif ()
set (CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to use")
endif()
endmacro(use_cxx11)

View File

@ -17,7 +17,9 @@ option(ANALYZE_ADDRESS "Clang dynamic analyzer: fast memory error detector.
option(ANALYZE_THREAD "Clang dynamic analyzer: tool that detects data races. " OFF)
option(ANALYZE_UNDEFINED "Clang dynamic analyzer: undefined behavior checker. " OFF)
option(ANALYZE_DATAFLOW "Clang dynamic analyzer: general dynamic dataflow analysis." OFF)
option(WARNINGS_ARE_ERRORS "Treat warnings as errors" OFF)
option(EXTERNALS_AS_SYSTEM "Treat externals as system includes" OFF)
set(USE_MATCHCOMPILER "Auto" CACHE STRING "Usage of match compiler")
set_property(CACHE USE_MATCHCOMPILER PROPERTY STRINGS Auto Off On Verify)
@ -70,6 +72,10 @@ else()
set(CMAKE_DISABLE_PRECOMPILE_HEADERS On CACHE BOOL "Disable precompiled headers")
endif()
if (BUILD_TESTS AND REGISTER_TESTS AND CMAKE_VERSION VERSION_LESS "3.9")
message(FATAL_ERROR "Registering tests with CTest requires at least CMake 3.9. Use REGISTER_TESTS=OFF to disable this.")
endif()
set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE ${CMAKE_INSTALL_PREFIX}/include CACHE PATH "Output directory for headers")
set(CMAKE_LIB_DIRS_CONFIGCMAKE ${CMAKE_INSTALL_PREFIX}/lib CACHE PATH "Output directory for libraries")

View File

@ -1,4 +1,4 @@
message( STATUS "------------------ General configuration for ${PROJECT_NAME} ${VERSION} -----------------")
message( STATUS "------------------ General configuration for ${PROJECT_NAME} ${PROJECT_VERSION} -----------------")
message( STATUS )
message( STATUS "CMake Version = ${CMAKE_VERSION}")
message( STATUS "CMake Generator = ${CMAKE_GENERATOR}")
@ -25,7 +25,9 @@ message( STATUS "ANALYZE_ADDRESS = ${ANALYZE_ADDRESS}" )
message( STATUS "ANALYZE_THREAD = ${ANALYZE_THREAD}" )
message( STATUS "ANALYZE_UNDEFINED = ${ANALYZE_UNDEFINED}" )
message( STATUS "ANALYZE_DATAFLOW = ${ANALYZE_DATAFLOW}" )
message( STATUS )
message( STATUS "WARNINGS_ARE_ERRORS = ${WARNINGS_ARE_ERRORS}" )
message( STATUS "EXTERNALS_AS_SYSTEM = ${EXTERNALS_AS_SYSTEM}" )
message( STATUS )
message( STATUS "USE_MATCHCOMPILER = ${USE_MATCHCOMPILER}" )
message( STATUS "USE_MATCHCOMPILER_OPT = ${USE_MATCHCOMPILER_OPT}" )

View File

@ -1,11 +1,6 @@
# Version for libraries CPP
# Version string must have 3 "parts". https://sourceforge.net/p/cppcheck/discussion/development/thread/e57efb2b62/
SET(VERSION "2.12.99")
STRING(REGEX MATCHALL "[0-9]+" VERSION_PARTS "${VERSION}")
LIST(GET VERSION_PARTS 0 VERSION_MAJOR)
LIST(GET VERSION_PARTS 1 VERSION_MINOR)
LIST(GET VERSION_PARTS 2 VERSION_PATCH)
SET(SOVERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
SET(SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
# Postfix of so's:
SET(DLLVERSION "")

View File

@ -37,11 +37,11 @@
# - empty the releasenotes.txt in main branch
#
# Update version numbers in:
# sed -i -r "s/version 2[.][0-9]+([.]99)*/version 2.9/" cli/main.cpp
# sed -i -r "s|2[.][0-9]+([.]99)*|2.9.0|" cmake/versions.cmake # version must have 3 parts.
# sed -i -r "s/MINOR [0-9]+/MINOR 9/" lib/version.h
# sed -i -r "s/2[.][0-9]+([.]99)*/2.9/" win_installer/productInfo.wxi
# sed -i -r "s/subtitle: Version 2\.[0-9]+/subtitle: Version 2.9/" man/*.md
# sed -i -r "s/version 2[.][0-9]+([.]99)*/version 2.13.0/" cli/main.cpp
# sed -i -r "s|2[.][0-9]+([.]99)*|2.13.0|" cmake/versions.cmake # version must have 3 parts.
# sed -i -r "s/CPPCHECK_MINOR_VERSION [0-9]+/CPPCHECK_MINOR_VERSION 13/" lib/version.h
# sed -i -r "s/2[.][0-9]+([.]99)*( dev)*/2.13.0/" win_installer/productInfo.wxi
# sed -i -r "s/subtitle: Version 2\.[0-9]+.*/subtitle: Version 2.13/" man/*.md
# Ensure that "-rc1" is added in productInfo.wxi and lib/version.h
# Verify:
# grep '\.99' */*.[ch]* && grep '[0-9][0-9] dev' */*.[ch]*
@ -72,7 +72,7 @@
# git tag 2.8 ; git push --tags
# ./createrelease 2.8
#
# copy msi from release-windows
# copy msi from release-windows, install and test cppcheck
# copy manual from build-manual
#
# Update download link on index.php main page
@ -96,13 +96,14 @@
# ./build-cppcheck.sh
#
# run daca with new release
# 1. edit tools/donate-cpu-server.py. Update OLD_VERSION and VERSION
# 2. scp -i ../.ssh/osuosl_id_rsa tools/donate-cpu-server.py danielmarjamaki@cppcheck1.osuosl.org:/var/daca@home/
# 1. edit tools/donate-cpu-server.py. Update OLD_VERSION and SERVER_VERSION
# 2. scp -i ~/.ssh/osuosl_id_rsa tools/donate-cpu-server.py danielmarjamaki@cppcheck1.osuosl.org:/var/daca@home/
#
# Backup:
# * trac: cd /var && nice tar -zcf /home/danielmarjamaki/trac.tar.gz trac-cppcheck
# * git: git checkout -f && git checkout main && git pull && tar -zcf ~/cppchecksolutions/backups/2.12.0-git.tar.gz .git
# * trac: cd /var && nice tar -cJf trac.tar.xz trac-cppcheck
# * git: git checkout -f && git checkout main && git pull && tar -cJf git.tar.xz .git
# * Changelog
# * ci status: screenshot(s) showing that all tests pass for tagged commit
# Folder/tag to use
folder=$1
@ -132,8 +133,8 @@ rm $releasename.*
cd ..
# Generate version.txt
make -j4
rm cppcheck.cfg
make -j12
rm -f cppcheck.cfg
./cppcheck --version > upload/version.txt
cd ~/cppcheck/upload
@ -149,7 +150,7 @@ cp -R ~/cppcheck/cfg .
cp -R ~/cppcheck/addons .
cp -R ~/cppcheck/platforms .
cd ~/cppcheck
make clean ; make -j4 FILESDIR=~/.cppcheck/$tag MATCHCOMPILER=yes
make clean ; make -j12 FILESDIR=~/.cppcheck/$tag MATCHCOMPILER=yes CXXFLAGS=-O2
mv cppcheck ~/.cppcheck/cppcheck-$tag
git checkout main

View File

@ -38,7 +38,7 @@ CheckOptions:
set_target_properties(cppcheck-gui PROPERTIES WIN32_EXECUTABLE ON)
target_include_directories(cppcheck-gui PRIVATE ${PROJECT_SOURCE_DIR}/lib/)
if(USE_BUNDLED_TINYXML2)
target_include_directories(cppcheck-gui PRIVATE ${PROJECT_SOURCE_DIR}/externals/tinyxml2/)
target_externals_include_directories(cppcheck-gui PRIVATE ${PROJECT_SOURCE_DIR}/externals/tinyxml2/)
else()
target_include_directories(cppcheck-gui SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS})
endif()

View File

@ -112,7 +112,7 @@ of the GNU General Public License version 3</string>
<item>
<widget class="QLabel" name="mUsedLibs">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Many thanks to these libraries that we use:&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;pcre&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;picojson&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;qt&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;tinyxml2&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Many thanks to these libraries that we use:&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;PCRE&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;PicoJSON&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Qt&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;TinyXML2&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Boost&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>

View File

@ -22,6 +22,7 @@
#include <QChar>
#include <QColor>
#include <QCryptographicHash>
#include <QFont>
#include <QFontMetrics>
#include <QKeySequence>
@ -37,7 +38,6 @@
#include <QTextCursor>
#include <QTextEdit>
#include <QTextFormat>
#include <QtCore>
class QTextDocument;
@ -287,11 +287,11 @@ CodeEditor::CodeEditor(QWidget *parent) :
setStyleSheet(generateStyleString());
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QShortcut *copyText = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_C),this);
QShortcut *allText = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_A),this);
auto *copyText = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_C),this);
auto *allText = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_A),this);
#else
const QShortcut *copyText = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_C),this);
const QShortcut *allText = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_A),this);
const auto *copyText = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_C),this);
const auto *allText = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_A),this);
#endif
connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));
@ -448,15 +448,14 @@ void CodeEditor::lineNumberAreaPaintEvent(const QPaintEvent *event)
QString CodeEditor::generateStyleString()
{
QString bgcolor = QString("background:rgb(%1,%2,%3);")
.arg(mWidgetStyle->widgetBGColor.red())
.arg(mWidgetStyle->widgetBGColor.green())
.arg(mWidgetStyle->widgetBGColor.blue());
.arg(mWidgetStyle->widgetBGColor.red(),
mWidgetStyle->widgetBGColor.green(),
mWidgetStyle->widgetBGColor.blue());
QString fgcolor = QString("color:rgb(%1,%2,%3);")
.arg(mWidgetStyle->widgetFGColor.red())
.arg(mWidgetStyle->widgetFGColor.green())
.arg(mWidgetStyle->widgetFGColor.blue());
.arg(mWidgetStyle->widgetFGColor.red(),
mWidgetStyle->widgetFGColor.green(),
mWidgetStyle->widgetFGColor.blue());
QString style = QString("%1 %2")
.arg(bgcolor)
.arg(fgcolor);
.arg(bgcolor, fgcolor);
return style;
}

View File

@ -72,10 +72,10 @@ StyleEditDialog::StyleEditDialog(const CodeEditorStyle& newStyle,
mStyleIncoming(newStyle),
mStyleOutgoing(newStyle)
{
QVBoxLayout *vboxMain = new QVBoxLayout(this);
QHBoxLayout *hboxEdit = new QHBoxLayout();
auto *vboxMain = new QVBoxLayout(this);
auto *hboxEdit = new QHBoxLayout();
// Color/Weight controls
QFormLayout *flEditControls = new QFormLayout();
auto *flEditControls = new QFormLayout();
mBtnWidgetColorFG = new SelectColorButton(this);
flEditControls->addRow(QObject::tr("Editor Foreground Color"),
mBtnWidgetColorFG);
@ -141,7 +141,7 @@ StyleEditDialog::StyleEditDialog(const CodeEditorStyle& newStyle,
vboxMain->addLayout(hboxEdit);
// Default Controls
QHBoxLayout *hboxDefaultControls = new QHBoxLayout();
auto *hboxDefaultControls = new QHBoxLayout();
mBtnDefaultLight = new QPushButton(QObject::tr("Set to Default Light"),
this);
mBtnDefaultDark = new QPushButton(QObject::tr("Set to Default Dark"),
@ -153,7 +153,7 @@ StyleEditDialog::StyleEditDialog(const CodeEditorStyle& newStyle,
vboxMain->addLayout(hboxDefaultControls);
vboxMain->addStretch(2);
// dialog controls
QDialogButtonBox *dBtnBox = new QDialogButtonBox(
auto *dBtnBox = new QDialogButtonBox(
QDialogButtonBox::Cancel |
QDialogButtonBox::Ok |
QDialogButtonBox::Reset);

View File

@ -66,7 +66,7 @@ QString toFilterString(const QMap<QString,QString>& filters, bool addAllSupporte
// name patterns are our values. The generated filter string list will
// thus be sorted alphabetically over the descriptions.
for (const auto& k: filters.keys()) {
entries << QString("%1 (%2)").arg(k).arg(filters.value(k));
entries << QString("%1 (%2)").arg(k, filters.value(k));
}
return entries.join(";;");

View File

@ -37,6 +37,7 @@
#include <QCheckBox>
#include <QComboBox>
#include <QCoreApplication>
#include <QCryptographicHash>
#include <QDialogButtonBox>
#include <QDir>
#include <QFile>
@ -52,7 +53,6 @@
#include <QStringList>
#include <QTemporaryFile>
#include <QTextStream>
#include <QtCore>
static void addHeaders(const QString& file1, QSet<QString> &allFiles) {
if (allFiles.contains(file1))
@ -170,7 +170,7 @@ void ComplianceReportDialog::save()
} catch (InternalError &e) {
QMessageBox msg(QMessageBox::Critical,
tr("Save compliance report"),
tr("Failed to import '%1' (%2), can not show files in compliance report").arg(prjfile).arg(QString::fromStdString(e.errorMessage)),
tr("Failed to import '%1' (%2), can not show files in compliance report").arg(prjfile, QString::fromStdString(e.errorMessage)),
QMessageBox::Ok,
this);
msg.exec();

View File

@ -176,7 +176,7 @@ Parameters: -l(line) (file)</translation>
<message>
<location filename="compliancereportdialog.cpp" line="173"/>
<source>Failed to import &apos;%1&apos; (%2), can not show files in compliance report</source>
<translation type="unfinished"></translation>
<translation>&apos;%1&apos; (%2)</translation>
</message>
<message>
<source>Failed to import &apos;%1&apos;, can not show files in compliance report</source>
@ -1153,7 +1153,7 @@ Do you want to load this project file instead?</source>
<message>
<location filename="mainwindow.cpp" line="961"/>
<source>Failed to load %1 - %2</source>
<translation type="unfinished"></translation>
<translation>%1 - %2 </translation>
</message>
<message>
<location filename="mainwindow.cpp" line="1313"/>
@ -1233,7 +1233,7 @@ Analysis is stopped.</source>
<message>
<location filename="mainwindow.cpp" line="1799"/>
<source>Failed to import &apos;%1&apos; (%2), analysis is stopped</source>
<translation type="unfinished"></translation>
<translation>&apos;%1&apos; (%2) </translation>
</message>
<message>
<location filename="mainwindow.cpp" line="2099"/>
@ -2213,7 +2213,7 @@ Options:
<message>
<location filename="resultstree.cpp" line="347"/>
<source>internal</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<location filename="resultstree.cpp" line="692"/>
@ -2435,7 +2435,7 @@ To toggle what kind of errors are shown, open view menu.</source>
<message>
<location filename="resultsview.cpp" line="575"/>
<source>when checking a file</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<location filename="resultsview.cpp" line="576"/>

View File

@ -46,8 +46,8 @@ static std::string mandatoryAttibuteMissing(const QXmlStreamReader &xmlReader, c
{
throw std::runtime_error(QObject::tr("line %1: Mandatory attribute '%2' missing in '%3'")
.arg(xmlReader.lineNumber())
.arg(attributeName)
.arg(xmlReader.name().toString()).toStdString());
.arg(attributeName, xmlReader.name().toString())
.toStdString());
}
static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader)

View File

@ -62,8 +62,8 @@ void CsvReport::writeError(const ErrorItem &error)
*/
const QString file = QDir::toNativeSeparators(error.errorPath.back().file);
QString line = QString("%1,%2,").arg(file).arg(error.errorPath.back().line);
line += QString("%1,%2,%3").arg(GuiSeverity::toString(error.severity)).arg(error.errorId).arg(error.summary);
QString line = QString("%1,%2,").arg(file, error.errorPath.back().line);
line += QString("%1,%2,%3").arg(GuiSeverity::toString(error.severity), error.errorId, error.summary);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
mTxtWriter << line << Qt::endl;
#else

View File

@ -121,7 +121,7 @@ void LibraryDialog::openCfg()
if (!errmsg.isNull()) {
QMessageBox msg(QMessageBox::Critical,
tr("Cppcheck"),
tr("Failed to load %1. %2.").arg(selectedFile).arg(errmsg),
tr("Failed to load %1. %2.").arg(selectedFile, errmsg),
QMessageBox::Ok,
this);
msg.exec();
@ -185,7 +185,7 @@ void LibraryDialog::saveCfgAs()
void LibraryDialog::addFunction()
{
LibraryAddFunctionDialog *d = new LibraryAddFunctionDialog;
auto *d = new LibraryAddFunctionDialog;
if (d->exec() == QDialog::Accepted && !d->functionName().isEmpty()) {
CppcheckLibraryData::Function f;

View File

@ -39,7 +39,6 @@
#include <QString>
#include <QStringList>
#include <QVariant>
#include <QtCore>
static void ShowUsage();
@ -59,7 +58,7 @@ int main(int argc, char *argv[])
QCoreApplication::setOrganizationName("Cppcheck");
QCoreApplication::setApplicationName("Cppcheck-GUI");
QSettings* settings = new QSettings("Cppcheck", "Cppcheck-GUI", &app);
auto* settings = new QSettings("Cppcheck", "Cppcheck-GUI", &app);
// Set data dir..
const QStringList args = QApplication::arguments();
@ -71,7 +70,7 @@ int main(int argc, char *argv[])
return 0;
}
TranslationHandler* th = new TranslationHandler(&app);
auto* th = new TranslationHandler(&app);
th->setLanguage(settings->value(SETTINGS_LANGUAGE, th->suggestLanguage()).toString());
if (!CheckArgs(QApplication::arguments()))

View File

@ -247,7 +247,7 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) :
for (int i = 0; i < mPlatforms.getCount(); i++) {
PlatformData platform = mPlatforms.mPlatforms[i];
QAction *action = new QAction(this);
auto *action = new QAction(this);
platform.mActMainWindow = action;
mPlatforms.mPlatforms[i] = platform;
action->setText(platform.mTitle);
@ -392,10 +392,10 @@ void MainWindow::loadSettings()
mUI->mActionToolBarFilter->setChecked(showFilterToolbar);
mUI->mToolBarFilter->setVisible(showFilterToolbar);
const Settings::Language enforcedLanguage = (Settings::Language)mSettings->value(SETTINGS_ENFORCED_LANGUAGE, 0).toInt();
if (enforcedLanguage == Settings::CPP)
const Standards::Language enforcedLanguage = (Standards::Language)mSettings->value(SETTINGS_ENFORCED_LANGUAGE, 0).toInt();
if (enforcedLanguage == Standards::Language::CPP)
mUI->mActionEnforceCpp->setChecked(true);
else if (enforcedLanguage == Settings::C)
else if (enforcedLanguage == Standards::Language::C)
mUI->mActionEnforceC->setChecked(true);
else
mUI->mActionAutoDetectLanguage->setChecked(true);
@ -469,11 +469,11 @@ void MainWindow::saveSettings() const
mSettings->setValue(SETTINGS_TOOLBARS_FILTER_SHOW, mUI->mToolBarFilter->isVisible());
if (mUI->mActionEnforceCpp->isChecked())
mSettings->setValue(SETTINGS_ENFORCED_LANGUAGE, Settings::CPP);
mSettings->setValue(SETTINGS_ENFORCED_LANGUAGE, Standards::Language::CPP);
else if (mUI->mActionEnforceC->isChecked())
mSettings->setValue(SETTINGS_ENFORCED_LANGUAGE, Settings::C);
mSettings->setValue(SETTINGS_ENFORCED_LANGUAGE, Standards::Language::C);
else
mSettings->setValue(SETTINGS_ENFORCED_LANGUAGE, Settings::None);
mSettings->setValue(SETTINGS_ENFORCED_LANGUAGE, Standards::Language::None);
mApplications->saveSettings();
@ -861,7 +861,7 @@ bool MainWindow::tryLoadLibrary(Library *library, const QString& filename)
const Library::Error error = loadLibrary(library, filename);
if (error.errorcode != Library::ErrorCode::OK) {
if (error.errorcode == Library::ErrorCode::UNKNOWN_ELEMENT) {
QMessageBox::information(this, tr("Information"), tr("The library '%1' contains unknown elements:\n%2").arg(filename).arg(error.reason.c_str()));
QMessageBox::information(this, tr("Information"), tr("The library '%1' contains unknown elements:\n%2").arg(filename, error.reason.c_str()));
return true;
}
@ -899,7 +899,7 @@ bool MainWindow::tryLoadLibrary(Library *library, const QString& filename)
}
if (!error.reason.empty())
errmsg += " '" + QString::fromStdString(error.reason) + "'";
QMessageBox::information(this, tr("Information"), tr("Failed to load the selected library '%1'.\n%2").arg(filename).arg(errmsg));
QMessageBox::information(this, tr("Information"), tr("Failed to load the selected library '%1'.\n%2").arg(filename, errmsg));
return false;
}
return true;
@ -958,7 +958,7 @@ Settings MainWindow::getCppcheckSettings()
{
const QString cfgErr = QString::fromStdString(result.loadCppcheckCfg());
if (!cfgErr.isEmpty())
QMessageBox::critical(this, tr("Error"), tr("Failed to load %1 - %2").arg("cppcheck.cfg").arg(cfgErr));
QMessageBox::critical(this, tr("Error"), tr("Failed to load %1 - %2").arg("cppcheck.cfg", cfgErr));
const auto cfgAddons = result.addons;
result.addons.clear();
@ -1021,7 +1021,7 @@ Settings MainWindow::getCppcheckSettings()
result.platform.loadFromFile(applicationFilePath.toStdString().c_str(), platform.toStdString());
} else {
for (int i = Platform::Type::Native; i <= Platform::Type::Unix64; i++) {
const Platform::Type p = (Platform::Type)i;
const auto p = (Platform::Type)i;
if (platform == Platform::toString(p)) {
result.platform.set(p);
break;
@ -1091,7 +1091,7 @@ Settings MainWindow::getCppcheckSettings()
result.platform.set((Platform::Type) mSettings->value(SETTINGS_CHECKED_PLATFORM, 0).toInt());
result.standards.setCPP(mSettings->value(SETTINGS_STD_CPP, QString()).toString().toStdString());
result.standards.setC(mSettings->value(SETTINGS_STD_C, QString()).toString().toStdString());
result.enforcedLang = (Settings::Language)mSettings->value(SETTINGS_ENFORCED_LANGUAGE, 0).toInt();
result.enforcedLang = (Standards::Language)mSettings->value(SETTINGS_ENFORCED_LANGUAGE, 0).toInt();
if (result.jobs <= 1) {
result.jobs = 1;
@ -1468,21 +1468,21 @@ void MainWindow::about()
msg.exec();
}
else {
AboutDialog *dlg = new AboutDialog(CppCheck::version(), CppCheck::extraVersion(), this);
auto *dlg = new AboutDialog(CppCheck::version(), CppCheck::extraVersion(), this);
dlg->exec();
}
}
void MainWindow::showLicense()
{
FileViewDialog *dlg = new FileViewDialog(":COPYING", tr("License"), this);
auto *dlg = new FileViewDialog(":COPYING", tr("License"), this);
dlg->resize(570, 400);
dlg->exec();
}
void MainWindow::showAuthors()
{
FileViewDialog *dlg = new FileViewDialog(":AUTHORS", tr("Authors"), this);
auto *dlg = new FileViewDialog(":AUTHORS", tr("Authors"), this);
dlg->resize(350, 400);
dlg->exec();
}
@ -1634,7 +1634,7 @@ void MainWindow::openHelpContents()
void MainWindow::openOnlineHelp()
{
HelpDialog *helpDialog = new HelpDialog;
auto *helpDialog = new HelpDialog;
helpDialog->showMaximized();
}
@ -1787,7 +1787,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const bool check
if (!errorMessage.isEmpty()) {
QMessageBox msg(QMessageBox::Critical,
tr("Cppcheck"),
tr("Failed to import '%1': %2\n\nAnalysis is stopped.").arg(prjfile).arg(errorMessage),
tr("Failed to import '%1': %2\n\nAnalysis is stopped.").arg(prjfile, errorMessage),
QMessageBox::Ok,
this);
msg.exec();
@ -1796,7 +1796,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const bool check
} catch (InternalError &e) {
QMessageBox msg(QMessageBox::Critical,
tr("Cppcheck"),
tr("Failed to import '%1' (%2), analysis is stopped").arg(prjfile).arg(QString::fromStdString(e.errorMessage)),
tr("Failed to import '%1' (%2), analysis is stopped").arg(prjfile, QString::fromStdString(e.errorMessage)),
QMessageBox::Ok,
this);
msg.exec();
@ -1923,7 +1923,7 @@ void MainWindow::enableProjectOpenActions(bool enable)
void MainWindow::openRecentProject()
{
QAction *action = qobject_cast<QAction *>(sender());
auto *action = qobject_cast<QAction *>(sender());
if (!action)
return;
const QString project = action->data().toString();
@ -2012,7 +2012,7 @@ void MainWindow::removeProjectMRU(const QString &project)
void MainWindow::selectPlatform()
{
QAction *action = qobject_cast<QAction *>(sender());
auto *action = qobject_cast<QAction *>(sender());
if (action) {
const Platform::Type platform = (Platform::Type) action->data().toInt();
mSettings->setValue(SETTINGS_CHECKED_PLATFORM, platform);
@ -2100,7 +2100,7 @@ void MainWindow::replyFinished(QNetworkReply *reply) {
}
mUI->mButtonHideInformation->setVisible(true);
mUI->mLabelInformation->setVisible(true);
mUI->mLabelInformation->setText(tr("New version available: %1. %2").arg(str.trimmed()).arg(install));
mUI->mLabelInformation->setText(tr("New version available: %1. %2").arg(str.trimmed(), install));
}
}
}

View File

@ -46,7 +46,7 @@ void PrintableReport::writeError(const ErrorItem &error)
{
const QString file = QDir::toNativeSeparators(error.errorPath.back().file);
QString line = QString("%1,%2,").arg(file).arg(error.errorPath.back().line);
line += QString("%1,%2").arg(GuiSeverity::toString(error.severity)).arg(error.summary);
line += QString("%1,%2").arg(GuiSeverity::toString(error.severity), error.summary);
mFormattedReport += line;
mFormattedReport += "\n";

View File

@ -55,7 +55,6 @@
#include <QSize>
#include <QSpinBox>
#include <QVariant>
#include <QtCore>
static constexpr char ADDON_MISRA[] = "misra";
static constexpr char CODING_STANDARD_MISRA_C_2023[] = "misra-c-2023";
@ -183,7 +182,7 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, bool premium, QWi
libs.sort();
mUI->mLibraries->clear();
for (const QString &lib : libs) {
QListWidgetItem* item = new QListWidgetItem(lib, mUI->mLibraries);
auto* item = new QListWidgetItem(lib, mUI->mLibraries);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag
item->setCheckState(Qt::Unchecked); // AND initialize check state
}
@ -605,7 +604,7 @@ void ProjectFileDialog::setProjectConfigurations(const QStringList &configs)
mUI->mListVsConfigs->clear();
mUI->mListVsConfigs->setEnabled(!configs.isEmpty() && !mUI->mChkAllVsConfigs->isChecked());
for (const QString &cfg : configs) {
QListWidgetItem* item = new QListWidgetItem(cfg, mUI->mListVsConfigs);
auto* item = new QListWidgetItem(cfg, mUI->mListVsConfigs);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag
item->setCheckState(Qt::Unchecked);
}
@ -622,7 +621,7 @@ void ProjectFileDialog::addIncludeDir(const QString &dir)
return;
const QString newdir = QDir::toNativeSeparators(dir);
QListWidgetItem *item = new QListWidgetItem(newdir);
auto *item = new QListWidgetItem(newdir);
item->setFlags(item->flags() | Qt::ItemIsEditable);
mUI->mListIncludeDirs->addItem(item);
}
@ -633,7 +632,7 @@ void ProjectFileDialog::addCheckPath(const QString &path)
return;
const QString newpath = QDir::toNativeSeparators(path);
QListWidgetItem *item = new QListWidgetItem(newpath);
auto *item = new QListWidgetItem(newpath);
item->setFlags(item->flags() | Qt::ItemIsEditable);
mUI->mListCheckPaths->addItem(item);
}
@ -644,7 +643,7 @@ void ProjectFileDialog::addExcludePath(const QString &path)
return;
const QString newpath = QDir::toNativeSeparators(path);
QListWidgetItem *item = new QListWidgetItem(newpath);
auto *item = new QListWidgetItem(newpath);
item->setFlags(item->flags() | Qt::ItemIsEditable);
mUI->mListExcludedPaths->addItem(item);
}

View File

@ -110,7 +110,7 @@ void ResultsTree::initialize(QSettings *settings, ApplicationList *list, ThreadH
QStandardItem *ResultsTree::createNormalItem(const QString &name)
{
QStandardItem *item = new QStandardItem(name);
auto *item = new QStandardItem(name);
item->setData(name, Qt::ToolTipRole);
item->setEditable(false);
return item;
@ -118,7 +118,7 @@ QStandardItem *ResultsTree::createNormalItem(const QString &name)
QStandardItem *ResultsTree::createCheckboxItem(bool checked)
{
QStandardItem *item = new QStandardItem;
auto *item = new QStandardItem;
item->setCheckable(true);
item->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
item->setEnabled(false);
@ -127,7 +127,7 @@ QStandardItem *ResultsTree::createCheckboxItem(bool checked)
QStandardItem *ResultsTree::createLineNumberItem(const QString &linenumber)
{
QStandardItem *item = new QStandardItem();
auto *item = new QStandardItem();
item->setData(QVariant(linenumber.toInt()), Qt::DisplayRole);
item->setToolTip(linenumber);
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
@ -611,7 +611,7 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e)
//Create a signal mapper so we don't have to store data to class
//member variables
QSignalMapper *signalMapper = new QSignalMapper(this);
auto *signalMapper = new QSignalMapper(this);
if (mContextItem && mApplications->getApplicationCount() > 0 && mContextItem->parent()) {
//Create an action for the application
@ -619,7 +619,7 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e)
if (defaultApplicationIndex < 0)
defaultApplicationIndex = 0;
const Application& app = mApplications->getApplication(defaultApplicationIndex);
QAction *start = new QAction(app.getName(), &menu);
auto *start = new QAction(app.getName(), &menu);
if (multipleSelection)
start->setDisabled(true);
@ -646,11 +646,11 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e)
}
//Create an action for the application
QAction *recheckAction = new QAction(tr("Recheck"), &menu);
QAction *copyAction = new QAction(tr("Copy"), &menu);
QAction *hide = new QAction(tr("Hide"), &menu);
QAction *hideallid = new QAction(tr("Hide all with id"), &menu);
QAction *opencontainingfolder = new QAction(tr("Open containing folder"), &menu);
auto *recheckAction = new QAction(tr("Recheck"), &menu);
auto *copyAction = new QAction(tr("Copy"), &menu);
auto *hide = new QAction(tr("Hide"), &menu);
auto *hideallid = new QAction(tr("Hide all with id"), &menu);
auto *opencontainingfolder = new QAction(tr("Open containing folder"), &menu);
if (multipleSelection) {
hideallid->setDisabled(true);
@ -668,7 +668,7 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e)
menu.addAction(hide);
menu.addAction(hideallid);
QAction *suppress = new QAction(tr("Suppress selected id(s)"), &menu);
auto *suppress = new QAction(tr("Suppress selected id(s)"), &menu);
{
QVariantMap data = mContextItem->data().toMap();
const QString messageId = data[ERRORID].toString();
@ -691,7 +691,7 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e)
menu.addSeparator();
QMenu *tagMenu = menu.addMenu(tr("Tag"));
{
QAction *action = new QAction(tr("No tag"), tagMenu);
auto *action = new QAction(tr("No tag"), tagMenu);
tagMenu->addAction(action);
connect(action, &QAction::triggered, [=]() {
tagSelectedItems(QString());
@ -699,7 +699,7 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e)
}
for (const QString& tagstr : currentProject->getTags()) {
QAction *action = new QAction(tagstr, tagMenu);
auto *action = new QAction(tagstr, tagMenu);
tagMenu->addAction(action);
connect(action, &QAction::triggered, [=]() {
tagSelectedItems(tagstr);
@ -816,7 +816,7 @@ void ResultsTree::startApplication(const QStandardItem *target, int application)
}
#endif // Q_OS_WIN
const QString cmdLine = QString("%1 %2").arg(program).arg(params);
const QString cmdLine = QString("%1 %2").arg(program, params);
// this is reported as deprecated in Qt 5.15.2 but no longer in Qt 6
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))

View File

@ -436,7 +436,7 @@ void ResultsView::readErrorsXml(const QString &filename)
void ResultsView::updateDetails(const QModelIndex &index)
{
const QStandardItemModel *model = qobject_cast<const QStandardItemModel*>(mUI->mTree->model());
const auto *model = qobject_cast<const QStandardItemModel*>(mUI->mTree->model());
QStandardItem *item = model->itemFromIndex(index);
if (!item) {
@ -463,7 +463,7 @@ void ResultsView::updateDetails(const QModelIndex &index)
const QString file0 = data["file0"].toString();
if (!file0.isEmpty() && Path::isHeader(data["file"].toString().toStdString()))
formattedMsg += QString("\n\n%1: %2").arg(tr("First included by")).arg(QDir::toNativeSeparators(file0));
formattedMsg += QString("\n\n%1: %2").arg(tr("First included by"), QDir::toNativeSeparators(file0));
if (data["cwe"].toInt() > 0)
formattedMsg.prepend("CWE: " + QString::number(data["cwe"].toInt()) + "\n");

View File

@ -140,7 +140,7 @@ void SettingsDialog::initTranslationsList()
{
const QString current = mTranslator->getCurrentLanguage();
for (const TranslationInfo& translation : mTranslator->getTranslations()) {
QListWidgetItem *item = new QListWidgetItem;
auto *item = new QListWidgetItem;
item->setText(translation.mName);
item->setData(mLangCodeRole, QVariant(translation.mCode));
mUI->mListLanguages->addItem(item);

View File

@ -182,9 +182,9 @@ void StatsDialog::pdfExport()
"<font color=\"blue\"><h3>%9 : %10</h3></font>\n"
"<font color=\"blue\"><h3>%11 : %12</h3></font>\n"
"<font color=\"purple\"><h3>%13 : %14</h3></font>\n")
.arg(tr("Statistics"))
.arg(QDate::currentDate().toString("dd.MM.yyyy"))
.arg(tr("Errors"))
.arg(tr("Statistics"),
QDate::currentDate().toString("dd.MM.yyyy"),
tr("Errors"))
.arg(mStatistics->getCount(CPPCHECK,ShowTypes::ShowErrors))
.arg(tr("Warnings"))
.arg(mStatistics->getCount(CPPCHECK,ShowTypes::ShowWarnings))
@ -246,17 +246,17 @@ void StatsDialog::copyToClipboard()
"\t%8:\t%9\n"
"\t%10:\t%11\n"
)
.arg(projSettings)
.arg(project)
.arg(mUI->mProject->text())
.arg(paths)
.arg(mUI->mPaths->text())
.arg(incPaths)
.arg(mUI->mIncludePaths->text())
.arg(defines)
.arg(mUI->mDefines->text())
.arg(undefines)
.arg(mUI->mUndefines->text());
.arg(projSettings,
project,
mUI->mProject->text(),
paths,
mUI->mPaths->text(),
incPaths,
mUI->mIncludePaths->text(),
defines)
.arg(mUI->mDefines->text(),
undefines,
mUI->mUndefines->text());
const QString previous = QString(
"%1\n"
@ -264,13 +264,13 @@ void StatsDialog::copyToClipboard()
"\t%4:\t%5\n"
"\t%6:\t%7\n"
)
.arg(prevScan)
.arg(selPath)
.arg(mUI->mPath->text())
.arg(numFiles)
.arg(mUI->mNumberOfFilesScanned->text())
.arg(duration)
.arg(mUI->mScanDuration->text());
.arg(prevScan,
selPath,
mUI->mPath->text(),
numFiles,
mUI->mNumberOfFilesScanned->text(),
duration,
mUI->mScanDuration->text());
const QString statistics = QString(
"%1\n"
@ -281,8 +281,8 @@ void StatsDialog::copyToClipboard()
"\t%10:\t%11\n"
"\t%12:\t%13\n"
)
.arg(stats)
.arg(errors)
.arg(stats,
errors)
.arg(mStatistics->getCount(CPPCHECK,ShowTypes::ShowErrors))
.arg(warnings)
.arg(mStatistics->getCount(CPPCHECK,ShowTypes::ShowWarnings))
@ -308,17 +308,17 @@ void StatsDialog::copyToClipboard()
" <tr><th>%10:</th><td>%11</td></tr>\n"
"</table>\n"
)
.arg(projSettings)
.arg(project)
.arg(mUI->mProject->text())
.arg(paths)
.arg(mUI->mPaths->text())
.arg(incPaths)
.arg(mUI->mIncludePaths->text())
.arg(defines)
.arg(mUI->mDefines->text())
.arg(undefines)
.arg(mUI->mUndefines->text());
.arg(projSettings,
project,
mUI->mProject->text(),
paths,
mUI->mPaths->text(),
incPaths,
mUI->mIncludePaths->text(),
defines)
.arg(mUI->mDefines->text(),
undefines,
mUI->mUndefines->text());
const QString htmlPrevious = QString(
"<h3>%1</h3>\n"
@ -328,13 +328,13 @@ void StatsDialog::copyToClipboard()
" <tr><th>%6:</th><td>%7</td></tr>\n"
"</table>\n"
)
.arg(prevScan)
.arg(selPath)
.arg(mUI->mPath->text())
.arg(numFiles)
.arg(mUI->mNumberOfFilesScanned->text())
.arg(duration)
.arg(mUI->mScanDuration->text());
.arg(prevScan,
selPath,
mUI->mPath->text(),
numFiles,
mUI->mNumberOfFilesScanned->text(),
duration,
mUI->mScanDuration->text());
const QString htmlStatistics = QString(
"<h3>%1</h3>\n"
@ -346,8 +346,8 @@ void StatsDialog::copyToClipboard()
" <tr><th>%12:</th><td>%13</td></tr>\n"
"</table>\n"
)
.arg(stats)
.arg(errors)
.arg(stats,
errors)
.arg(mStatistics->getCount(CPPCHECK,ShowTypes::ShowErrors))
.arg(warnings)
.arg(mStatistics->getCount(CPPCHECK,ShowTypes::ShowWarnings))
@ -362,7 +362,7 @@ void StatsDialog::copyToClipboard()
const QString htmlSummary = htmlSettings + htmlPrevious + htmlStatistics;
QMimeData *mimeData = new QMimeData();
auto *mimeData = new QMimeData();
mimeData->setText(textSummary);
mimeData->setHtml(htmlSummary);
clipboard->setMimeData(mimeData);
@ -384,14 +384,14 @@ void StatsDialog::setStatistics(const CheckStatistics *stats)
#ifdef QT_CHARTS_LIB
QChartView *createChart(const QString &statsFile, const QString &tool)
{
QChart *chart = new QChart;
auto *chart = new QChart;
chart->addSeries(numberOfReports(statsFile, tool + "-error"));
chart->addSeries(numberOfReports(statsFile, tool + "-warning"));
chart->addSeries(numberOfReports(statsFile, tool + "-style"));
chart->addSeries(numberOfReports(statsFile, tool + "-performance"));
chart->addSeries(numberOfReports(statsFile, tool + "-portability"));
QDateTimeAxis *axisX = new QDateTimeAxis;
auto *axisX = new QDateTimeAxis;
axisX->setTitleText("Date");
chart->addAxis(axisX, Qt::AlignBottom);
@ -399,7 +399,7 @@ QChartView *createChart(const QString &statsFile, const QString &tool)
s->attachAxis(axisX);
}
QValueAxis *axisY = new QValueAxis;
auto *axisY = new QValueAxis;
axisY->setLabelFormat("%i");
axisY->setTitleText("Count");
chart->addAxis(axisY, Qt::AlignLeft);
@ -407,7 +407,7 @@ QChartView *createChart(const QString &statsFile, const QString &tool)
qreal maxY = 0;
for (QAbstractSeries *s : chart->series()) {
s->attachAxis(axisY);
if (const QLineSeries *ls = dynamic_cast<const QLineSeries*>(s)) {
if (const auto *ls = dynamic_cast<const QLineSeries*>(s)) {
for (QPointF p : ls->points()) {
if (p.y() > maxY)
maxY = p.y();
@ -419,14 +419,14 @@ QChartView *createChart(const QString &statsFile, const QString &tool)
//chart->createDefaultAxes();
chart->setTitle(tool);
QChartView *chartView = new QChartView(chart);
auto *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
return chartView;
}
QLineSeries *numberOfReports(const QString &fileName, const QString &severity)
{
QLineSeries *series = new QLineSeries();
auto *series = new QLineSeries();
series->setName(severity);
QFile f(fileName);
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {

View File

@ -10,7 +10,8 @@ add_executable(test-filelist
${CMAKE_SOURCE_DIR}/lib/utils.cpp
$<TARGET_OBJECTS:simplecpp_objs>
)
target_include_directories(test-filelist PRIVATE ${CMAKE_SOURCE_DIR}/gui ${CMAKE_SOURCE_DIR}/lib ${CMAKE_SOURCE_DIR}/externals/simplecpp)
target_include_directories(test-filelist PRIVATE ${CMAKE_SOURCE_DIR}/gui ${CMAKE_SOURCE_DIR}/lib)
target_externals_include_directories(test-filelist PRIVATE ${CMAKE_SOURCE_DIR}/externals/simplecpp)
target_compile_definitions(test-filelist PRIVATE SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(test-filelist ${QT_CORE_LIB} ${QT_TEST_LIB})

View File

@ -408,8 +408,8 @@ def filter_bar(enabled):
,'\n | '
,''.join([filter_button(enabled, tool, 'toggleTool') for tool in ['cppcheck', 'clang-tidy']])
,'\n | '
,'\n <label class="severityHeader">File: <input type="text" oninput="filterFile(this.value)"/></label>'
,'\n <label class="severityHeader">Filter: <input type="text" oninput="filterText(this.value)"/></label>'
,'\n <label class="severityHeader">File: <input type="search" oninput="filterFile(this.value)"/></label>'
,'\n <label class="severityHeader">Filter: <input type="search" oninput="filterText(this.value)"/></label>'
,'\n </div>\n'])
def git_blame(errors, path, file, blame_options):

View File

@ -43,14 +43,14 @@ if (BUILD_CORE_DLL)
else()
add_library(cppcheck-core OBJECT ${srcs_lib} ${hdrs})
endif()
target_include_directories(cppcheck-core PRIVATE ${PROJECT_SOURCE_DIR}/externals/)
target_externals_include_directories(cppcheck-core PRIVATE ${PROJECT_SOURCE_DIR}/externals/)
if(USE_BUNDLED_TINYXML2)
target_include_directories(cppcheck-core PRIVATE ${PROJECT_SOURCE_DIR}/externals/tinyxml2/)
target_externals_include_directories(cppcheck-core PRIVATE ${PROJECT_SOURCE_DIR}/externals/tinyxml2/)
else()
target_include_directories(cppcheck-core SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS})
endif()
target_include_directories(cppcheck-core PRIVATE ${PROJECT_SOURCE_DIR}/externals/picojson/)
target_include_directories(cppcheck-core PRIVATE ${PROJECT_SOURCE_DIR}/externals/simplecpp/)
target_externals_include_directories(cppcheck-core PRIVATE ${PROJECT_SOURCE_DIR}/externals/picojson/)
target_externals_include_directories(cppcheck-core PRIVATE ${PROJECT_SOURCE_DIR}/externals/simplecpp/)
if (HAVE_RULES)
target_include_directories(cppcheck-core SYSTEM PRIVATE ${PCRE_INCLUDE})
endif()

View File

@ -52,42 +52,73 @@ static std::string parseAddonInfo(AddonInfo& addoninfo, const picojson::value &j
return "Loading " + fileName + " failed. " + json_error;
}
if (!json.is<picojson::object>())
return "Loading " + fileName + " failed. Bad json.";
picojson::object obj = json.get<picojson::object>();
if (obj.count("args")) {
if (!obj["args"].is<picojson::array>())
return "Loading " + fileName + " failed. args must be array.";
for (const picojson::value &v : obj["args"].get<picojson::array>())
addoninfo.args += " " + v.get<std::string>();
}
return "Loading " + fileName + " failed. JSON is not an object.";
if (obj.count("ctu")) {
// ctu is specified in the config file
if (!obj["ctu"].is<bool>())
return "Loading " + fileName + " failed. ctu must be boolean.";
addoninfo.ctu = obj["ctu"].get<bool>();
} else {
addoninfo.ctu = false;
}
if (obj.count("python")) {
// Python was defined in the config file
if (obj["python"].is<picojson::array>()) {
return "Loading " + fileName +" failed. python must not be an array.";
// TODO: remove/complete default value handling for missing fields
const picojson::object& obj = json.get<picojson::object>();
{
const auto it = obj.find("args");
if (it != obj.cend()) {
const auto& val = it->second;
if (!val.is<picojson::array>())
return "Loading " + fileName + " failed. 'args' must be an array.";
for (const picojson::value &v : val.get<picojson::array>()) {
if (!v.is<std::string>())
return "Loading " + fileName + " failed. 'args' entry is not a string.";
addoninfo.args += " " + v.get<std::string>();
}
}
addoninfo.python = obj["python"].get<std::string>();
} else {
addoninfo.python = "";
}
if (obj.count("executable")) {
if (!obj["executable"].is<std::string>())
return "Loading " + fileName + " failed. executable must be a string.";
addoninfo.executable = getFullPath(obj["executable"].get<std::string>(), fileName);
return "";
{
const auto it = obj.find("ctu");
if (it != obj.cend()) {
const auto& val = it->second;
// ctu is specified in the config file
if (!val.is<bool>())
return "Loading " + fileName + " failed. 'ctu' must be a boolean.";
addoninfo.ctu = val.get<bool>();
}
else {
addoninfo.ctu = false;
}
}
return addoninfo.getAddonInfo(obj["script"].get<std::string>(), exename);
{
const auto it = obj.find("python");
if (it != obj.cend()) {
const auto& val = it->second;
// Python was defined in the config file
if (!val.is<std::string>()) {
return "Loading " + fileName +" failed. 'python' must be a string.";
}
addoninfo.python = val.get<std::string>();
}
else {
addoninfo.python = "";
}
}
{
const auto it = obj.find("executable");
if (it != obj.cend()) {
const auto& val = it->second;
if (!val.is<std::string>())
return "Loading " + fileName + " failed. 'executable' must be a string.";
addoninfo.executable = getFullPath(val.get<std::string>(), fileName);
return ""; // TODO: why bail out?
}
}
const auto it = obj.find("script");
if (it == obj.cend())
return "Loading " + fileName + " failed. 'script' is missing.";
const auto& val = it->second;
if (!val.is<std::string>())
return "Loading " + fileName + " failed. 'script' must be a string.";
return addoninfo.getAddonInfo(val.get<std::string>(), exename);
}
std::string AddonInfo::getAddonInfo(const std::string &fileName, const std::string &exename) {

View File

@ -181,6 +181,8 @@ struct Analyzer {
virtual bool stopOnCondition(const Token* condTok) const = 0;
/// The condition that will be assumed during analysis
virtual void assume(const Token* tok, bool state, unsigned int flags = 0) = 0;
/// Update the state of the program at the token
virtual void updateState(const Token* tok) = 0;
/// Return analyzer for expression at token
virtual ValuePtr<Analyzer> reanalyze(Token* tok, const std::string& msg = emptyString) const = 0;
virtual bool invalid() const {

View File

@ -1020,7 +1020,7 @@ bool isAliasOf(const Token* tok, const Token* expr, int* indirect, bool* inconcl
if (val.isLocalLifetimeValue() || (pointer && val.isSymbolicValue() && val.intvalue == 0)) {
if (findAstNode(val.tokvalue,
[&](const Token* aliasTok) {
return aliasTok->exprId() == childTok->exprId();
return aliasTok != childTok && aliasTok->exprId() == childTok->exprId();
})) {
if (val.isInconclusive() && inconclusive != nullptr) {
value = &val;
@ -2651,8 +2651,11 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings *settings,
const Token * ptok = tok2;
while (Token::Match(ptok->astParent(), ".|::|["))
ptok = ptok->astParent();
int pindirect = indirect;
if (indirect == 0 && astIsLHS(tok2) && Token::Match(ptok, ". %var%") && astIsPointer(ptok->next()))
pindirect = 1;
bool inconclusive = false;
bool isChanged = isVariableChangedByFunctionCall(ptok, indirect, settings, &inconclusive);
bool isChanged = isVariableChangedByFunctionCall(ptok, pindirect, settings, &inconclusive);
isChanged |= inconclusive;
if (isChanged)
return true;
@ -3257,6 +3260,8 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings
continue;
if (arg->isReference())
return ExprUsage::PassedByReference;
if (arg->isPointer() && indirect == 1)
return ExprUsage::PassedByReference;
}
if (!args.empty() && indirect == 0 && !addressOf)
return ExprUsage::Used;
@ -3301,6 +3306,8 @@ ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings,
parent = parent->astParent();
if (Token::Match(parent, "%assign%") && (astIsRHS(tok) || astIsLHS(parent->astOperand1())))
return ExprUsage::NotUsed;
if (Token::Match(parent, "++|--"))
return ExprUsage::NotUsed;
if (parent->isConstOp())
return ExprUsage::NotUsed;
if (parent->isCast())

View File

@ -948,7 +948,7 @@ bool CheckBufferOverrun::isCtuUnsafePointerArith(const Settings *settings, const
/** @brief Parse current TU and extract file info */
Check::FileInfo *CheckBufferOverrun::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const
{
MyFileInfo *fileInfo = new MyFileInfo;
auto *fileInfo = new MyFileInfo;
fileInfo->unsafeArrayIndex = CTU::getUnsafeUsage(tokenizer, settings, isCtuUnsafeArrayIndex);
fileInfo->unsafePointerArith = CTU::getUnsafeUsage(tokenizer, settings, isCtuUnsafePointerArith);
if (fileInfo->unsafeArrayIndex.empty() && fileInfo->unsafePointerArith.empty()) {
@ -964,7 +964,7 @@ Check::FileInfo * CheckBufferOverrun::loadFileInfoFromXml(const tinyxml2::XMLEle
const std::string arrayIndex("array-index");
const std::string pointerArith("pointer-arith");
MyFileInfo *fileInfo = new MyFileInfo;
auto *fileInfo = new MyFileInfo;
for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (e->Name() == arrayIndex)
fileInfo->unsafeArrayIndex = CTU::loadUnsafeUsageListFromXml(e);

View File

@ -2633,6 +2633,7 @@ namespace { // avoid one-definition-rule violation
const Variable *var;
const Token *tok;
std::vector<const Variable*> initArgs;
};
}
@ -2663,25 +2664,44 @@ void CheckClass::initializerListOrder()
tok = tok->next();
// find all variable initializations in list
while (tok && tok != func->functionScope->bodyStart) {
for (; tok && tok != func->functionScope->bodyStart; tok = tok->next()) {
if (Token::Match(tok, "%name% (|{")) {
const Variable *var = scope->getVariable(tok->str());
if (var)
vars.emplace_back(var, tok);
else
continue;
if (Token::Match(tok->tokAt(2), "%name% =")) {
var = scope->getVariable(tok->strAt(2));
if (var)
vars.emplace_back(var, tok->tokAt(2));
const Token* const end = tok->next()->link();
for (; tok != end; tok = tok->next()) {
if (const Variable* argVar = scope->getVariable(tok->str())) {
if (scope != argVar->scope())
continue;
if (argVar->isStatic())
continue;
if (tok->variable() && tok->variable()->isArgument())
continue;
if (var->isPointer() && (argVar->isArray() || Token::simpleMatch(tok->astParent(), "&")))
continue;
if (var->isReference())
continue;
if (Token::simpleMatch(tok->astParent(), "="))
continue;
vars.back().initArgs.emplace_back(argVar);
}
}
tok = tok->next()->link()->next();
} else
tok = tok->next();
}
}
// need at least 2 members to have out of order initialization
for (int j = 1; j < vars.size(); j++) {
for (int j = 0; j < vars.size(); j++) {
// check for use of uninitialized arguments
for (const auto& arg : vars[j].initArgs)
if (vars[j].var->index() < arg->index())
initializerListError(vars[j].tok, vars[j].var->nameToken(), scope->className, vars[j].var->name(), /*isArgument*/ true);
// need at least 2 members to have out of order initialization
if (j == 0)
continue;
// check for out of order initialization
if (vars[j].var->index() < vars[j - 1].var->index())
initializerListError(vars[j].tok,vars[j].var->nameToken(), scope->className, vars[j].var->name());
@ -2692,15 +2712,18 @@ void CheckClass::initializerListOrder()
}
}
void CheckClass::initializerListError(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &varname)
void CheckClass::initializerListError(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &varname, bool isArgument)
{
std::list<const Token *> toks = { tok1, tok2 };
const std::string msg = isArgument ?
"Member variable '$symbol' uses an uninitialized argument due to the order of declarations." :
"Member variable '$symbol' is in the wrong place in the initializer list.";
reportError(toks, Severity::style, "initializerList",
"$symbol:" + classname + "::" + varname +"\n"
"Member variable '$symbol' is in the wrong place in the initializer list.\n"
"Member variable '$symbol' is in the wrong place in the initializer list. "
"$symbol:" + classname + "::" + varname + '\n' +
msg + '\n' +
msg + ' ' +
"Members are initialized in the order they are declared, not in the "
"order they are in the initializer list. Keeping the initializer list "
"order they are in the initializer list. Keeping the initializer list "
"in the same order that the members were declared prevents order dependent "
"initialization errors.", CWE398, Certainty::inconclusive);
}
@ -2988,7 +3011,8 @@ static std::vector<DuplMemberFuncInfo> getDuplInheritedMemberFunctionsRecursive(
if (classFuncIt.name() == parentClassFuncIt.name() &&
(parentClassFuncIt.access != AccessControl::Private || !skipPrivate) &&
!classFuncIt.isConstructor() && !classFuncIt.isDestructor() &&
classFuncIt.argsMatch(parentClassIt.type->classScope, parentClassFuncIt.argDef, classFuncIt.argDef, emptyString, 0))
classFuncIt.argsMatch(parentClassIt.type->classScope, parentClassFuncIt.argDef, classFuncIt.argDef, emptyString, 0) &&
(classFuncIt.isConst() == parentClassFuncIt.isConst() || Function::returnsConst(&classFuncIt) == Function::returnsConst(&parentClassFuncIt)))
results.emplace_back(&classFuncIt, &parentClassFuncIt, &parentClassIt);
}
}
@ -3509,14 +3533,14 @@ Check::FileInfo *CheckClass::getFileInfo(const Tokenizer *tokenizer, const Setti
if (classDefinitions.empty())
return nullptr;
MyFileInfo *fileInfo = new MyFileInfo;
auto *fileInfo = new MyFileInfo;
fileInfo->classDefinitions.swap(classDefinitions);
return fileInfo;
}
Check::FileInfo * CheckClass::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const
{
MyFileInfo *fileInfo = new MyFileInfo;
auto *fileInfo = new MyFileInfo;
for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (std::strcmp(e->Name(), "class") != 0)
continue;

View File

@ -199,7 +199,7 @@ private:
void operatorEqToSelfError(const Token *tok);
void checkConstError(const Token *tok, const std::string &classname, const std::string &funcname, bool suggestStatic);
void checkConstError2(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &funcname, bool suggestStatic);
void initializerListError(const Token *tok1,const Token *tok2, const std::string & classname, const std::string &varname);
void initializerListError(const Token *tok1,const Token *tok2, const std::string & classname, const std::string &varname, bool isArgument = false);
void suggestInitializationList(const Token *tok, const std::string& varname);
void selfInitializationError(const Token* tok, const std::string& varname);
void pureVirtualFunctionCallInConstructorError(const Function * scopeFunction, const std::list<const Token *> & tokStack, const std::string &purefuncname);

View File

@ -417,8 +417,6 @@ void CheckCondition::comparison()
void CheckCondition::comparisonError(const Token *tok, const std::string &bitop, MathLib::bigint value1, const std::string &op, MathLib::bigint value2, bool result)
{
if (tok && (diag(tok) | diag(tok->astParent())))
return;
std::ostringstream expression;
expression << std::hex << "(X " << bitop << " 0x" << value1 << ") " << op << " 0x" << value2;
@ -1287,15 +1285,15 @@ void CheckCondition::checkIncorrectLogicOperator()
// 5 => testvalue is larger than both value1 and value2
bool result1, result2;
if (isfloat) {
const double testvalue = getvalue<double>(test, d1, d2);
const auto testvalue = getvalue<double>(test, d1, d2);
result1 = checkFloatRelation(op1, testvalue, d1);
result2 = checkFloatRelation(op2, testvalue, d2);
} else if (useUnsignedInt) {
const MathLib::biguint testvalue = getvalue<MathLib::biguint>(test, u1, u2);
const auto testvalue = getvalue<MathLib::biguint>(test, u1, u2);
result1 = checkIntRelation(op1, testvalue, u1);
result2 = checkIntRelation(op2, testvalue, u2);
} else {
const MathLib::bigint testvalue = getvalue<MathLib::bigint>(test, i1, i2);
const auto testvalue = getvalue<MathLib::bigint>(test, i1, i2);
result1 = checkIntRelation(op1, testvalue, i1);
result2 = checkIntRelation(op2, testvalue, i2);
}

View File

@ -32,6 +32,7 @@
#include "symboldatabase.h"
#include "token.h"
#include "tokenize.h"
#include "tokenlist.h"
#include "utils.h"
#include "vfvalue.h"
@ -466,6 +467,9 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken,
const Token * closingParenthesis = tok->linkAt(1);
for (const Token *innerTok = tok->tokAt(2); innerTok && innerTok != closingParenthesis; innerTok = innerTok->next()) {
// TODO: replace with checkTokenInsideExpression()
const Token* const openingPar = isFunctionCall(innerTok);
if (!openingPar)
checkTokenInsideExpression(innerTok, varInfo);
if (!isLocalVarNoAutoDealloc(innerTok, mTokenizer->isCPP()))
continue;
@ -502,7 +506,6 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken,
}
// check for function call
const Token * const openingPar = isFunctionCall(innerTok);
if (openingPar) {
const Library::AllocFunc* allocFunc = mSettings->library.getDeallocFuncInfo(innerTok);
// innerTok is a function name
@ -805,14 +808,15 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken,
const Token * vtok = typeEndTok->tokAt(3);
const VarInfo::AllocInfo allocation(af ? af->groupId : (arrayDelete ? NEW_ARRAY : NEW), VarInfo::OWNED, ftok);
changeAllocStatus(varInfo, allocation, vtok, vtok);
}
} else if (Token::Match(tok, "%var% ."))
checkTokenInsideExpression(tok, varInfo);
}
ret(endToken, varInfo, true);
return true;
}
const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const tok, VarInfo &varInfo)
const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const tok, VarInfo &varInfo, bool inFuncCall)
{
// Deallocation and then dereferencing pointer..
if (tok->varId() > 0) {
@ -838,7 +842,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t
if (rhs->varId() == tok->varId()) {
// simple assignment
varInfo.erase(tok->varId());
} else if (rhs->str() == "(" && !mSettings->library.returnValue(rhs->astOperand1()).empty()) {
} else if (rhs->astParent() && rhs->str() == "(" && !mSettings->library.returnValue(rhs->astOperand1()).empty()) {
// #9298, assignment through return value of a function
const std::string &returnValue = mSettings->library.returnValue(rhs->astOperand1());
if (startsWith(returnValue, "arg")) {
@ -859,7 +863,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t
}
// check for function call
const Token * const openingPar = isFunctionCall(tok);
const Token * const openingPar = inFuncCall ? nullptr : isFunctionCall(tok);
if (openingPar) {
const Library::AllocFunc* allocFunc = mSettings->library.getDeallocFuncInfo(tok);
VarInfo::AllocInfo alloc(allocFunc ? allocFunc->groupId : 0, VarInfo::DEALLOC, tok);
@ -930,8 +934,7 @@ void CheckLeakAutoVar::changeAllocStatus(VarInfo &varInfo, const VarInfo::AllocI
void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpeningPar, VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af)
{
// Ignore function call?
if (mSettings->library.isLeakIgnore(mSettings->library.getFunctionName(tokName)))
return;
const bool isLeakIgnore = mSettings->library.isLeakIgnore(mSettings->library.getFunctionName(tokName));
if (mSettings->library.getReallocFuncInfo(tokName))
return;
@ -990,6 +993,8 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin
varAlloc.allocTok = arg;
}
}
else if (isLeakIgnore)
checkTokenInsideExpression(arg, varInfo);
else
changeAllocStatus(varInfo, dealloc.type == 0 ? allocation : dealloc, tokName, arg);
}
@ -1041,7 +1046,14 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin
const VarInfo::AllocInfo sp_allocation(sp_af ? sp_af->groupId : (arrayDelete ? NEW_ARRAY : NEW), VarInfo::OWNED, allocTok);
changeAllocStatus(varInfo, sp_allocation, vtok, vtok);
} else {
checkTokenInsideExpression(arg, varInfo);
const Token* const nextArg = funcArg->nextArgument();
while (arg && ((nextArg && arg != nextArg) || (!nextArg && arg != tokOpeningPar->link()))) {
checkTokenInsideExpression(arg, varInfo, /*inFuncCall*/ isLeakIgnore);
if (isLambdaCaptureList(arg))
break;
arg = arg->next();
}
}
// TODO: check each token in argument expression (could contain multiple variables)
argNr++;
@ -1107,7 +1119,7 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO
for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) {
if (tok2->str() == ";")
break;
if (!Token::Match(tok2, "return|(|{|,"))
if (!Token::Match(tok2, "return|(|{|,|*"))
continue;
const Token* tok3 = tok2->next();

View File

@ -135,7 +135,7 @@ private:
* @param varInfo Variable info
* @return next token to process (if no other checks needed for this token). NULL if other checks could be performed.
*/
const Token * checkTokenInsideExpression(const Token * const tok, VarInfo &varInfo);
const Token * checkTokenInsideExpression(const Token * const tok, VarInfo &varInfo, bool inFuncCall = false);
/** parse function call */
void functionCall(const Token *tokName, const Token *tokOpeningPar, VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af);

View File

@ -86,7 +86,7 @@ private:
public:
CheckMemoryLeak() = delete;
CheckMemoryLeak(const CheckMemoryLeak &) = delete;
void operator=(const CheckMemoryLeak &) = delete;
CheckMemoryLeak& operator=(const CheckMemoryLeak &) = delete;
CheckMemoryLeak(const Tokenizer *t, ErrorLogger *e, const Settings *s)
: mTokenizer_(t), mErrorLogger_(e), mSettings_(s) {}

View File

@ -586,7 +586,7 @@ Check::FileInfo *CheckNullPointer::getFileInfo(const Tokenizer *tokenizer, const
if (unsafeUsage.empty())
return nullptr;
MyFileInfo *fileInfo = new MyFileInfo;
auto *fileInfo = new MyFileInfo;
fileInfo->unsafeUsage = unsafeUsage;
return fileInfo;
}
@ -597,7 +597,7 @@ Check::FileInfo * CheckNullPointer::loadFileInfoFromXml(const tinyxml2::XMLEleme
if (unsafeUsage.empty())
return nullptr;
MyFileInfo *fileInfo = new MyFileInfo;
auto *fileInfo = new MyFileInfo;
fileInfo->unsafeUsage = unsafeUsage;
return fileInfo;
}

View File

@ -995,16 +995,7 @@ void CheckOther::checkVariableScope()
// parse else if blocks..
} else if (Token::simpleMatch(tok, "else { if (") && Token::simpleMatch(tok->linkAt(3), ") {")) {
const Token *endif = tok->linkAt(3)->linkAt(1);
bool elseif = false;
if (Token::simpleMatch(endif, "} }"))
elseif = true;
else if (Token::simpleMatch(endif, "} else {") && Token::simpleMatch(endif->linkAt(2),"} }"))
elseif = true;
if (elseif && Token::findmatch(tok->next(), "%varid%", tok->linkAt(1), var->declarationId())) {
reduce = false;
break;
}
tok = tok->next();
} else if (tok->varId() == var->declarationId() || tok->str() == "goto") {
reduce = false;
break;

View File

@ -1642,12 +1642,7 @@ void CheckUninitVar::valueFlowUninit()
const bool isarray = tok->variable()->isArray();
if (isarray && tok->variable()->isMember())
continue; // Todo: this is a bailout
const bool ispointer = astIsPointer(tok) && !isarray;
const bool deref = CheckNullPointer::isPointerDeRef(tok, unknown, mSettings);
if (ispointer && v->indirect == 1 && !deref)
continue;
if (isarray && !deref)
continue;
uninitderef = deref && v->indirect == 0;
const bool isleaf = isLeafDot(tok) || uninitderef;
if (!isleaf && Token::Match(tok->astParent(), ". %name%") && (tok->astParent()->next()->varId() || tok->astParent()->next()->isEnumerator()))
@ -1710,7 +1705,7 @@ Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer *tokenizer, const S
if (unsafeUsage.empty())
return nullptr;
MyFileInfo *fileInfo = new MyFileInfo;
auto *fileInfo = new MyFileInfo;
fileInfo->unsafeUsage = unsafeUsage;
return fileInfo;
}
@ -1721,7 +1716,7 @@ Check::FileInfo * CheckUninitVar::loadFileInfoFromXml(const tinyxml2::XMLElement
if (unsafeUsage.empty())
return nullptr;
MyFileInfo *fileInfo = new MyFileInfo;
auto *fileInfo = new MyFileInfo;
fileInfo->unsafeUsage = unsafeUsage;
return fileInfo;
}

View File

@ -325,15 +325,15 @@ namespace clangimport {
std::string nodeType;
std::vector<AstNodePtr> children;
void setLocations(TokenList *tokenList, int file, int line, int col);
void setLocations(TokenList &tokenList, int file, int line, int col);
void dumpAst(int num = 0, int indent = 0) const;
void createTokens1(TokenList *tokenList) {
void createTokens1(TokenList &tokenList) {
//dumpAst();
if (!tokenList->back())
if (!tokenList.back())
setLocations(tokenList, 0, 1, 1);
else
setLocations(tokenList, tokenList->back()->fileIndex(), tokenList->back()->linenr(), 1);
setLocations(tokenList, tokenList.back()->fileIndex(), tokenList.back()->linenr(), 1);
createTokens(tokenList);
if (nodeType == VarDecl || nodeType == RecordDecl || nodeType == TypedefDecl)
addtoken(tokenList, ";");
@ -351,22 +351,22 @@ namespace clangimport {
return children[c];
}
private:
Token *createTokens(TokenList *tokenList);
Token *addtoken(TokenList *tokenList, const std::string &str, bool valueType=true);
const ::Type *addTypeTokens(TokenList *tokenList, const std::string &str, const Scope *scope = nullptr);
void addFullScopeNameTokens(TokenList *tokenList, const Scope *recordScope);
Scope *createScope(TokenList *tokenList, Scope::ScopeType scopeType, AstNodePtr astNode, const Token *def);
Scope *createScope(TokenList *tokenList, Scope::ScopeType scopeType, const std::vector<AstNodePtr> &children2, const Token *def);
Token *createTokensCall(TokenList *tokenList);
void createTokensFunctionDecl(TokenList *tokenList);
void createTokensForCXXRecord(TokenList *tokenList);
Token *createTokensVarDecl(TokenList *tokenList);
Token *createTokens(TokenList &tokenList);
Token *addtoken(TokenList &tokenList, const std::string &str, bool valueType=true);
const ::Type *addTypeTokens(TokenList &tokenList, const std::string &str, const Scope *scope = nullptr);
void addFullScopeNameTokens(TokenList &tokenList, const Scope *recordScope);
Scope *createScope(TokenList &tokenList, Scope::ScopeType scopeType, AstNodePtr astNode, const Token *def);
Scope *createScope(TokenList &tokenList, Scope::ScopeType scopeType, const std::vector<AstNodePtr> &children2, const Token *def);
Token *createTokensCall(TokenList &tokenList);
void createTokensFunctionDecl(TokenList &tokenList);
void createTokensForCXXRecord(TokenList &tokenList);
Token *createTokensVarDecl(TokenList &tokenList);
std::string getSpelling() const;
std::string getType(int index = 0) const;
std::string getFullType(int index = 0) const;
bool isDefinition() const;
std::string getTemplateParameters() const;
const Scope *getNestedInScope(TokenList *tokenList);
const Scope *getNestedInScope(TokenList &tokenList);
void setValueType(Token *tok);
int mFile = 0;
@ -496,7 +496,7 @@ void clangimport::AstNode::dumpAst(int num, int indent) const
}
}
void clangimport::AstNode::setLocations(TokenList *tokenList, int file, int line, int col)
void clangimport::AstNode::setLocations(TokenList &tokenList, int file, int line, int col)
{
for (const std::string &ext: mExtTokens) {
if (startsWith(ext, "<col:"))
@ -512,7 +512,7 @@ void clangimport::AstNode::setLocations(TokenList *tokenList, int file, int line
const bool windowsPath = colon == 2 && ext.size() > 3 && ext[2] == ':';
const std::string::size_type sep1 = windowsPath ? ext.find(':', 4) : colon;
const std::string::size_type sep2 = ext.find(':', sep1 + 1);
file = tokenList->appendFileIfNew(ext.substr(1, sep1 - 1));
file = tokenList.appendFileIfNew(ext.substr(1, sep1 - 1));
line = strToInt<int>(ext.substr(sep1 + 1, sep2 - sep1 - 1));
}
}
@ -526,17 +526,17 @@ void clangimport::AstNode::setLocations(TokenList *tokenList, int file, int line
}
}
Token *clangimport::AstNode::addtoken(TokenList *tokenList, const std::string &str, bool valueType)
Token *clangimport::AstNode::addtoken(TokenList &tokenList, const std::string &str, bool valueType)
{
const Scope *scope = getNestedInScope(tokenList);
tokenList->addtoken(str, mLine, mCol, mFile);
tokenList->back()->scope(scope);
tokenList.addtoken(str, mLine, mCol, mFile);
tokenList.back()->scope(scope);
if (valueType)
setValueType(tokenList->back());
return tokenList->back();
setValueType(tokenList.back());
return tokenList.back();
}
const ::Type * clangimport::AstNode::addTypeTokens(TokenList *tokenList, const std::string &str, const Scope *scope)
const ::Type * clangimport::AstNode::addTypeTokens(TokenList &tokenList, const std::string &str, const Scope *scope)
{
if (str.find("\':\'") != std::string::npos) {
return addTypeTokens(tokenList, str.substr(0, str.find("\':\'") + 1), scope);
@ -574,11 +574,11 @@ const ::Type * clangimport::AstNode::addTypeTokens(TokenList *tokenList, const s
// Set Type
if (!scope) {
scope = tokenList->back() ? tokenList->back()->scope() : nullptr;
scope = tokenList.back() ? tokenList.back()->scope() : nullptr;
if (!scope)
return nullptr;
}
for (const Token *typeToken = tokenList->back(); Token::Match(typeToken, "&|*|%name%"); typeToken = typeToken->previous()) {
for (const Token *typeToken = tokenList.back(); Token::Match(typeToken, "&|*|%name%"); typeToken = typeToken->previous()) {
if (!typeToken->isName())
continue;
const ::Type *recordType = scope->check->findVariableType(scope, typeToken);
@ -590,12 +590,12 @@ const ::Type * clangimport::AstNode::addTypeTokens(TokenList *tokenList, const s
return nullptr;
}
void clangimport::AstNode::addFullScopeNameTokens(TokenList *tokenList, const Scope *recordScope)
void clangimport::AstNode::addFullScopeNameTokens(TokenList &tokenList, const Scope *recordScope)
{
if (!recordScope)
return;
std::list<const Scope *> scopes;
while (recordScope && recordScope != tokenList->back()->scope() && !recordScope->isExecutable()) {
while (recordScope && recordScope != tokenList.back()->scope() && !recordScope->isExecutable()) {
scopes.push_front(recordScope);
recordScope = recordScope->nestedIn;
}
@ -607,13 +607,13 @@ void clangimport::AstNode::addFullScopeNameTokens(TokenList *tokenList, const Sc
}
}
const Scope *clangimport::AstNode::getNestedInScope(TokenList *tokenList)
const Scope *clangimport::AstNode::getNestedInScope(TokenList &tokenList)
{
if (!tokenList->back())
if (!tokenList.back())
return &mData->mSymbolDatabase->scopeList.front();
if (tokenList->back()->str() == "}" && mData->mNotScope.find(tokenList->back()) == mData->mNotScope.end())
return tokenList->back()->scope()->nestedIn;
return tokenList->back()->scope();
if (tokenList.back()->str() == "}" && mData->mNotScope.find(tokenList.back()) == mData->mNotScope.end())
return tokenList.back()->scope()->nestedIn;
return tokenList.back()->scope();
}
void clangimport::AstNode::setValueType(Token *tok)
@ -626,7 +626,7 @@ void clangimport::AstNode::setValueType(Token *tok)
continue;
TokenList decl(nullptr);
addTypeTokens(&decl, type, tok->scope());
addTypeTokens(decl, type, tok->scope());
if (!decl.front())
break;
@ -638,17 +638,17 @@ void clangimport::AstNode::setValueType(Token *tok)
}
}
Scope *clangimport::AstNode::createScope(TokenList *tokenList, Scope::ScopeType scopeType, AstNodePtr astNode, const Token *def)
Scope *clangimport::AstNode::createScope(TokenList &tokenList, Scope::ScopeType scopeType, AstNodePtr astNode, const Token *def)
{
std::vector<AstNodePtr> children2{std::move(astNode)};
return createScope(tokenList, scopeType, children2, def);
}
Scope *clangimport::AstNode::createScope(TokenList *tokenList, Scope::ScopeType scopeType, const std::vector<AstNodePtr> & children2, const Token *def)
Scope *clangimport::AstNode::createScope(TokenList &tokenList, Scope::ScopeType scopeType, const std::vector<AstNodePtr> & children2, const Token *def)
{
SymbolDatabase *symbolDatabase = mData->mSymbolDatabase;
Scope *nestedIn = const_cast<Scope *>(getNestedInScope(tokenList));
auto *nestedIn = const_cast<Scope *>(getNestedInScope(tokenList));
symbolDatabase->scopeList.emplace_back(nullptr, nullptr, nestedIn);
Scope *scope = &symbolDatabase->scopeList.back();
@ -682,7 +682,7 @@ Scope *clangimport::AstNode::createScope(TokenList *tokenList, Scope::ScopeType
}
}
scope->bodyStart = addtoken(tokenList, "{");
tokenList->back()->scope(scope);
tokenList.back()->scope(scope);
mData->scopeAccessControl[scope] = scope->defaultAccess();
if (!children2.empty()) {
for (const AstNodePtr &astNode: children2) {
@ -700,7 +700,7 @@ Scope *clangimport::AstNode::createScope(TokenList *tokenList, Scope::ScopeType
astNode->createTokens(tokenList);
if (scopeType == Scope::ScopeType::eEnum)
astNode->addtoken(tokenList, ",");
else if (!Token::Match(tokenList->back(), "[;{}]"))
else if (!Token::Match(tokenList.back(), "[;{}]"))
astNode->addtoken(tokenList, ";");
}
}
@ -710,7 +710,7 @@ Scope *clangimport::AstNode::createScope(TokenList *tokenList, Scope::ScopeType
return scope;
}
Token *clangimport::AstNode::createTokens(TokenList *tokenList)
Token *clangimport::AstNode::createTokens(TokenList &tokenList)
{
if (nodeType == ArraySubscriptExpr) {
Token *array = getChild(0)->createTokens(tokenList);
@ -796,7 +796,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
if (nodeType == CompoundStmt) {
for (const AstNodePtr& child: children) {
child->createTokens(tokenList);
if (!Token::Match(tokenList->back(), "[;{}]"))
if (!Token::Match(tokenList.back(), "[;{}]"))
child->addtoken(tokenList, ";");
}
return nullptr;
@ -818,14 +818,14 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
return getChild(0)->createTokens(tokenList);
if (nodeType == CXXBoolLiteralExpr) {
addtoken(tokenList, mExtTokens.back());
tokenList->back()->setValueType(new ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0));
return tokenList->back();
tokenList.back()->setValueType(new ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0));
return tokenList.back();
}
if (nodeType == CXXConstructExpr) {
if (!children.empty())
return getChild(0)->createTokens(tokenList);
addTypeTokens(tokenList, '\'' + getType() + '\'');
Token *type = tokenList->back();
Token *type = tokenList.back();
Token *par1 = addtoken(tokenList, "(");
Token *par2 = addtoken(tokenList, ")");
par1->link(par2);
@ -866,7 +866,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
}
}
if (!range)
throw InternalError(tokenList->back(), "Failed to import CXXForRangeStmt. Range?");
throw InternalError(tokenList.back(), "Failed to import CXXForRangeStmt. Range?");
Token *expr2 = range->createTokens(tokenList);
Token *par2 = addtoken(tokenList, ")");
@ -961,7 +961,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
}
if (nodeType == DoStmt) {
addtoken(tokenList, "do");
createScope(tokenList, Scope::ScopeType::eDo, getChild(0), tokenList->back());
createScope(tokenList, Scope::ScopeType::eDo, getChild(0), tokenList.back());
Token *tok1 = addtoken(tokenList, "while");
Token *par1 = addtoken(tokenList, "(");
Token *expr = children[1]->createTokens(tokenList);
@ -974,7 +974,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
}
if (nodeType == EnumConstantDecl) {
Token *nameToken = addtoken(tokenList, getSpelling());
Scope *scope = const_cast<Scope *>(nameToken->scope());
auto *scope = const_cast<Scope *>(nameToken->scope());
scope->enumeratorList.emplace_back(nameToken->scope());
Enumerator *e = &scope->enumeratorList.back();
e->name = nameToken;
@ -1088,7 +1088,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
createScope(tokenList, Scope::ScopeType::eIf, thenCode, iftok);
if (elseCode) {
elseCode->addtoken(tokenList, "else");
createScope(tokenList, Scope::ScopeType::eElse, elseCode, tokenList->back());
createScope(tokenList, Scope::ScopeType::eElse, elseCode, tokenList.back());
}
return nullptr;
}
@ -1099,11 +1099,11 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
return expr;
}
if (nodeType == InitListExpr) {
const Scope *scope = tokenList->back()->scope();
const Scope *scope = tokenList.back()->scope();
Token *start = addtoken(tokenList, "{");
start->scope(scope);
for (const AstNodePtr& child: children) {
if (tokenList->back()->str() != "{")
if (tokenList.back()->str() != "{")
addtoken(tokenList, ",");
child->createTokens(tokenList);
}
@ -1261,7 +1261,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
return addtoken(tokenList, "?" + nodeType + "?");
}
Token * clangimport::AstNode::createTokensCall(TokenList *tokenList)
Token * clangimport::AstNode::createTokensCall(TokenList &tokenList)
{
int firstParam;
Token *f;
@ -1302,7 +1302,7 @@ Token * clangimport::AstNode::createTokensCall(TokenList *tokenList)
return par1;
}
void clangimport::AstNode::createTokensFunctionDecl(TokenList *tokenList)
void clangimport::AstNode::createTokensFunctionDecl(TokenList &tokenList)
{
const bool prev = contains(mExtTokens, "prev");
const bool hasBody = !children.empty() && children.back()->nodeType == CompoundStmt;
@ -1317,16 +1317,16 @@ void clangimport::AstNode::createTokensFunctionDecl(TokenList *tokenList)
addtoken(tokenList, "static");
if (isInline)
addtoken(tokenList, "inline");
const Token * const before = tokenList->back();
const Token * const before = tokenList.back();
addTypeTokens(tokenList, '\'' + getType() + '\'');
startToken = before ? before->next() : tokenList->front();
startToken = before ? before->next() : tokenList.front();
}
if (mExtTokens.size() > 4 && mExtTokens[1] == "parent")
addFullScopeNameTokens(tokenList, mData->getScope(mExtTokens[2]));
Token *nameToken = addtoken(tokenList, getSpelling() + getTemplateParameters());
Scope *nestedIn = const_cast<Scope *>(nameToken->scope());
auto *nestedIn = const_cast<Scope *>(nameToken->scope());
if (prev) {
const std::string addr = *(std::find(mExtTokens.cbegin(), mExtTokens.cend(), "prev") + 1);
@ -1343,10 +1343,10 @@ void clangimport::AstNode::createTokensFunctionDecl(TokenList *tokenList)
nestedIn->functionList.back().retDef = startToken;
}
Function * const function = const_cast<Function*>(nameToken->function());
auto * const function = const_cast<Function*>(nameToken->function());
if (!prev) {
auto accessControl = mData->scopeAccessControl.find(tokenList->back()->scope());
auto accessControl = mData->scopeAccessControl.find(tokenList.back()->scope());
if (accessControl != mData->scopeAccessControl.end())
function->access = accessControl->second;
}
@ -1377,10 +1377,10 @@ void clangimport::AstNode::createTokensFunctionDecl(TokenList *tokenList)
AstNodePtr child = children[i];
if (child->nodeType != ParmVarDecl)
continue;
if (tokenList->back() != par1)
if (tokenList.back() != par1)
addtoken(tokenList, ",");
const Type *recordType = addTypeTokens(tokenList, child->mExtTokens.back(), nestedIn);
const Token *typeEndToken = tokenList->back();
const Token *typeEndToken = tokenList.back();
const std::string spelling = child->getSpelling();
Token *vartok = nullptr;
if (!spelling.empty())
@ -1424,7 +1424,7 @@ void clangimport::AstNode::createTokensFunctionDecl(TokenList *tokenList)
}
}
void clangimport::AstNode::createTokensForCXXRecord(TokenList *tokenList)
void clangimport::AstNode::createTokensForCXXRecord(TokenList &tokenList)
{
const bool isStruct = contains(mExtTokens, "struct");
Token * const classToken = addtoken(tokenList, isStruct ? "struct" : "class");
@ -1466,10 +1466,10 @@ void clangimport::AstNode::createTokensForCXXRecord(TokenList *tokenList)
const_cast<Scope *>(classToken->scope())->definedTypesMap[className] = scope->definedType;
}
addtoken(tokenList, ";");
const_cast<Token *>(tokenList->back())->scope(classToken->scope());
const_cast<Token *>(tokenList.back())->scope(classToken->scope());
}
Token * clangimport::AstNode::createTokensVarDecl(TokenList *tokenList)
Token * clangimport::AstNode::createTokensVarDecl(TokenList &tokenList)
{
const std::string addr = mExtTokens.front();
if (contains(mExtTokens, "static"))
@ -1479,14 +1479,14 @@ Token * clangimport::AstNode::createTokensVarDecl(TokenList *tokenList)
typeIndex--;
const std::string type = mExtTokens[typeIndex];
const std::string name = mExtTokens[typeIndex - 1];
const Token *startToken = tokenList->back();
const Token *startToken = tokenList.back();
const ::Type *recordType = addTypeTokens(tokenList, type);
if (!startToken)
startToken = tokenList->front();
startToken = tokenList.front();
else if (startToken->str() != "static")
startToken = startToken->next();
Token *vartok1 = addtoken(tokenList, name);
Scope *scope = const_cast<Scope *>(tokenList->back()->scope());
auto *scope = const_cast<Scope *>(tokenList.back()->scope());
scope->varlist.emplace_back(vartok1, unquote(type), startToken, vartok1->previous(), 0, scope->defaultAccess(), recordType, scope);
mData->varDecl(addr, vartok1, &scope->varlist.back());
if (mExtTokens.back() == "cinit" && !children.empty()) {
@ -1510,9 +1510,9 @@ Token * clangimport::AstNode::createTokensVarDecl(TokenList *tokenList)
return vartok1;
}
static void setTypes(TokenList *tokenList)
static void setTypes(TokenList &tokenList)
{
for (Token *tok = tokenList->front(); tok; tok = tok->next()) {
for (Token *tok = tokenList.front(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "sizeof (")) {
for (Token *typeToken = tok->tokAt(2); typeToken->str() != ")"; typeToken = typeToken->next()) {
if (typeToken->type())
@ -1523,9 +1523,9 @@ static void setTypes(TokenList *tokenList)
}
}
static void setValues(const Tokenizer *tokenizer, const SymbolDatabase *symbolDatabase)
static void setValues(const Tokenizer &tokenizer, const SymbolDatabase *symbolDatabase)
{
const Settings * const settings = tokenizer->getSettings();
const Settings * const settings = tokenizer.getSettings();
for (const Scope& scope : symbolDatabase->scopeList) {
if (!scope.definedType)
@ -1542,7 +1542,7 @@ static void setValues(const Tokenizer *tokenizer, const SymbolDatabase *symbolDa
scope.definedType->sizeOf = typeSize;
}
for (Token *tok = const_cast<Token*>(tokenizer->tokens()); tok; tok = tok->next()) {
for (auto *tok = const_cast<Token*>(tokenizer.tokens()); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "sizeof (")) {
ValueType vt = ValueType::parseDecl(tok->tokAt(2), *settings);
const int sz = vt.typeSize(settings->platform, true);
@ -1563,18 +1563,18 @@ static void setValues(const Tokenizer *tokenizer, const SymbolDatabase *symbolDa
}
}
void clangimport::parseClangAstDump(Tokenizer *tokenizer, std::istream &f)
void clangimport::parseClangAstDump(Tokenizer &tokenizer, std::istream &f)
{
TokenList *tokenList = &tokenizer->list;
TokenList &tokenList = tokenizer.list;
tokenizer->createSymbolDatabase();
SymbolDatabase *symbolDatabase = const_cast<SymbolDatabase *>(tokenizer->getSymbolDatabase());
tokenizer.createSymbolDatabase();
auto *symbolDatabase = const_cast<SymbolDatabase *>(tokenizer.getSymbolDatabase());
symbolDatabase->scopeList.emplace_back(nullptr, nullptr, nullptr);
symbolDatabase->scopeList.back().type = Scope::ScopeType::eGlobal;
symbolDatabase->scopeList.back().check = symbolDatabase;
clangimport::Data data;
data.mSettings = tokenizer->getSettings();
data.mSettings = tokenizer.getSettings();
data.mSymbolDatabase = symbolDatabase;
std::string line;
std::vector<AstNodePtr> tree;
@ -1617,16 +1617,16 @@ void clangimport::parseClangAstDump(Tokenizer *tokenizer, std::istream &f)
tree[0]->createTokens1(tokenList);
// Validation
for (const Token *tok = tokenList->front(); tok; tok = tok->next()) {
for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "(|)|[|]|{|}") && !tok->link())
throw InternalError(tok, "Token::link() is not set properly");
}
if (tokenList->front())
tokenList->front()->assignIndexes();
if (tokenList.front())
tokenList.front()->assignIndexes();
symbolDatabase->clangSetVariables(data.getVariableList());
symbolDatabase->createSymbolDatabaseExprIds();
tokenList->clangSetOrigFiles();
tokenList.clangSetOrigFiles();
setTypes(tokenList);
setValues(tokenizer, symbolDatabase);
}

View File

@ -29,7 +29,7 @@
class Tokenizer;
namespace clangimport {
void CPPCHECKLIB parseClangAstDump(Tokenizer *tokenizer, std::istream &f);
void CPPCHECKLIB parseClangAstDump(Tokenizer &tokenizer, std::istream &f);
}
#endif

View File

@ -188,13 +188,13 @@ static void createDumpFile(const Settings& settings,
std::string language;
switch (settings.enforcedLang) {
case Settings::Language::C:
case Standards::Language::C:
language = " language=\"c\"";
break;
case Settings::Language::CPP:
case Standards::Language::CPP:
language = " language=\"cpp\"";
break;
case Settings::Language::None:
case Standards::Language::None:
if (Path::isCPP(filename))
language = " language=\"cpp\"";
else if (Path::isC(filename))
@ -423,120 +423,127 @@ static bool reportClangErrors(std::istream &is, const std::function<void(const E
return false;
}
unsigned int CppCheck::check(const std::string &path)
unsigned int CppCheck::checkClang(const std::string &path)
{
if (mSettings.clang) {
if (!mSettings.quiet)
mErrorLogger.reportOut(std::string("Checking ") + path + " ...", Color::FgGreen);
if (!mSettings.quiet)
mErrorLogger.reportOut(std::string("Checking ") + path + " ...", Color::FgGreen);
const std::string lang = Path::isCPP(path) ? "-x c++" : "-x c";
const std::string analyzerInfo = mSettings.buildDir.empty() ? std::string() : AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, path, emptyString);
const std::string clangcmd = analyzerInfo + ".clang-cmd";
const std::string clangStderr = analyzerInfo + ".clang-stderr";
const std::string clangAst = analyzerInfo + ".clang-ast";
std::string exe = mSettings.clangExecutable;
// TODO: this ignores the configured language
const std::string lang = Path::isCPP(path) ? "-x c++" : "-x c";
const std::string analyzerInfo = mSettings.buildDir.empty() ? std::string() : AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, path, emptyString);
const std::string clangcmd = analyzerInfo + ".clang-cmd";
const std::string clangStderr = analyzerInfo + ".clang-stderr";
const std::string clangAst = analyzerInfo + ".clang-ast";
std::string exe = mSettings.clangExecutable;
#ifdef _WIN32
// append .exe if it is not a path
if (Path::fromNativeSeparators(mSettings.clangExecutable).find('/') == std::string::npos) {
exe += ".exe";
}
// append .exe if it is not a path
if (Path::fromNativeSeparators(mSettings.clangExecutable).find('/') == std::string::npos) {
exe += ".exe";
}
#endif
std::string flags(lang + " ");
if (Path::isCPP(path) && !mSettings.standards.stdValue.empty())
flags += "-std=" + mSettings.standards.stdValue + " ";
std::string flags(lang + " ");
// TODO: does not apply C standard
if (Path::isCPP(path) && !mSettings.standards.stdValue.empty())
flags += "-std=" + mSettings.standards.stdValue + " ";
for (const std::string &i: mSettings.includePaths)
flags += "-I" + i + " ";
for (const std::string &i: mSettings.includePaths)
flags += "-I" + i + " ";
flags += getDefinesFlags(mSettings.userDefines);
flags += getDefinesFlags(mSettings.userDefines);
const std::string args2 = "-fsyntax-only -Xclang -ast-dump -fno-color-diagnostics " + flags + path;
const std::string redirect2 = analyzerInfo.empty() ? std::string("2>&1") : ("2> " + clangStderr);
if (!mSettings.buildDir.empty()) {
std::ofstream fout(clangcmd);
fout << exe << " " << args2 << " " << redirect2 << std::endl;
} else if (mSettings.verbose && !mSettings.quiet) {
mErrorLogger.reportOut(exe + " " + args2);
}
std::string output2;
if (mExecuteCommand(exe,split(args2),redirect2,output2) != EXIT_SUCCESS || output2.find("TranslationUnitDecl") == std::string::npos) {
std::cerr << "Failed to execute '" << exe << " " << args2 << " " << redirect2 << "'" << std::endl;
return 0;
}
// Ensure there are not syntax errors...
std::vector<ErrorMessage> compilerWarnings;
if (!mSettings.buildDir.empty()) {
std::ifstream fin(clangStderr);
auto reportError = [this](const ErrorMessage& errorMessage) {
reportErr(errorMessage);
};
if (reportClangErrors(fin, reportError, compilerWarnings))
return 0;
} else {
std::istringstream istr(output2);
auto reportError = [this](const ErrorMessage& errorMessage) {
reportErr(errorMessage);
};
if (reportClangErrors(istr, reportError, compilerWarnings))
return 0;
}
if (!mSettings.buildDir.empty()) {
std::ofstream fout(clangAst);
fout << output2 << std::endl;
}
try {
std::istringstream ast(output2);
Tokenizer tokenizer(&mSettings, this);
tokenizer.list.appendFileIfNew(path);
clangimport::parseClangAstDump(&tokenizer, ast);
ValueFlow::setValues(tokenizer.list,
const_cast<SymbolDatabase&>(*tokenizer.getSymbolDatabase()),
this,
&mSettings,
&s_timerResults);
if (mSettings.debugnormal)
tokenizer.printDebugOutput(1);
checkNormalTokens(tokenizer);
// create dumpfile
std::ofstream fdump;
std::string dumpFile;
createDumpFile(mSettings, path, fdump, dumpFile);
if (fdump.is_open()) {
fdump << "<dump cfg=\"\">\n";
for (const ErrorMessage& errmsg: compilerWarnings)
fdump << " <clang-warning file=\"" << toxml(errmsg.callStack.front().getfile()) << "\" line=\"" << errmsg.callStack.front().line << "\" column=\"" << errmsg.callStack.front().column << "\" message=\"" << toxml(errmsg.shortMessage()) << "\"/>\n";
fdump << " <standards>\n";
fdump << " <c version=\"" << mSettings.standards.getC() << "\"/>\n";
fdump << " <cpp version=\"" << mSettings.standards.getCPP() << "\"/>\n";
fdump << " </standards>\n";
tokenizer.dump(fdump);
fdump << "</dump>\n";
fdump << "</dumps>\n";
fdump.close();
}
// run addons
executeAddons(dumpFile, path);
} catch (const InternalError &e) {
const ErrorMessage errmsg = ErrorMessage::fromInternalError(e, nullptr, path, "Bailing out from analysis: Processing Clang AST dump failed");
reportErr(errmsg);
} catch (const TerminateException &) {
// Analysis is terminated
return mExitCode;
} catch (const std::exception &e) {
internalError(path, std::string("Processing Clang AST dump failed: ") + e.what());
}
return mExitCode;
const std::string args2 = "-fsyntax-only -Xclang -ast-dump -fno-color-diagnostics " + flags + path;
const std::string redirect2 = analyzerInfo.empty() ? std::string("2>&1") : ("2> " + clangStderr);
if (!mSettings.buildDir.empty()) {
std::ofstream fout(clangcmd);
fout << exe << " " << args2 << " " << redirect2 << std::endl;
} else if (mSettings.verbose && !mSettings.quiet) {
mErrorLogger.reportOut(exe + " " + args2);
}
std::string output2;
if (mExecuteCommand(exe,split(args2),redirect2,output2) != EXIT_SUCCESS || output2.find("TranslationUnitDecl") == std::string::npos) {
std::cerr << "Failed to execute '" << exe << " " << args2 << " " << redirect2 << "'" << std::endl;
return 0;
}
// Ensure there are not syntax errors...
std::vector<ErrorMessage> compilerWarnings;
if (!mSettings.buildDir.empty()) {
std::ifstream fin(clangStderr);
auto reportError = [this](const ErrorMessage& errorMessage) {
reportErr(errorMessage);
};
if (reportClangErrors(fin, reportError, compilerWarnings))
return 0;
} else {
std::istringstream istr(output2);
auto reportError = [this](const ErrorMessage& errorMessage) {
reportErr(errorMessage);
};
if (reportClangErrors(istr, reportError, compilerWarnings))
return 0;
}
if (!mSettings.buildDir.empty()) {
std::ofstream fout(clangAst);
fout << output2 << std::endl;
}
try {
std::istringstream ast(output2);
Tokenizer tokenizer(&mSettings, this);
tokenizer.list.appendFileIfNew(path);
clangimport::parseClangAstDump(tokenizer, ast);
ValueFlow::setValues(tokenizer.list,
const_cast<SymbolDatabase&>(*tokenizer.getSymbolDatabase()),
this,
&mSettings,
&s_timerResults);
if (mSettings.debugnormal)
tokenizer.printDebugOutput(1);
checkNormalTokens(tokenizer);
// create dumpfile
std::ofstream fdump;
std::string dumpFile;
createDumpFile(mSettings, path, fdump, dumpFile);
if (fdump.is_open()) {
// TODO: use tinyxml2 to create XML
fdump << "<dump cfg=\"\">\n";
for (const ErrorMessage& errmsg: compilerWarnings)
fdump << " <clang-warning file=\"" << toxml(errmsg.callStack.front().getfile()) << "\" line=\"" << errmsg.callStack.front().line << "\" column=\"" << errmsg.callStack.front().column << "\" message=\"" << toxml(errmsg.shortMessage()) << "\"/>\n";
fdump << " <standards>\n";
fdump << " <c version=\"" << mSettings.standards.getC() << "\"/>\n";
fdump << " <cpp version=\"" << mSettings.standards.getCPP() << "\"/>\n";
fdump << " </standards>\n";
tokenizer.dump(fdump);
fdump << "</dump>\n";
fdump << "</dumps>\n";
fdump.close();
}
// run addons
executeAddons(dumpFile, path);
} catch (const InternalError &e) {
const ErrorMessage errmsg = ErrorMessage::fromInternalError(e, nullptr, path, "Bailing out from analysis: Processing Clang AST dump failed");
reportErr(errmsg);
} catch (const TerminateException &) {
// Analysis is terminated
return mExitCode;
} catch (const std::exception &e) {
internalError(path, std::string("Processing Clang AST dump failed: ") + e.what());
}
return mExitCode;
}
unsigned int CppCheck::check(const std::string &path)
{
if (mSettings.clang)
return checkClang(path);
return checkFile(Path::simplifyPath(path), emptyString);
}
@ -1347,8 +1354,8 @@ void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &token
}
break;
}
const unsigned int pos1 = (unsigned int)ovector[0];
const unsigned int pos2 = (unsigned int)ovector[1];
const auto pos1 = (unsigned int)ovector[0];
const auto pos2 = (unsigned int)ovector[1];
// jump to the end of the match for the next pcre_exec
pos = (int)pos2;
@ -1751,7 +1758,7 @@ bool CppCheck::analyseWholeProgram()
// Analyse the tokens
CTU::FileInfo ctu;
for (const Check::FileInfo *fi : mFileInfo) {
const CTU::FileInfo *fi2 = dynamic_cast<const CTU::FileInfo *>(fi);
const auto *fi2 = dynamic_cast<const CTU::FileInfo *>(fi);
if (fi2) {
ctu.functionCalls.insert(ctu.functionCalls.end(), fi2->functionCalls.cbegin(), fi2->functionCalls.cend());
ctu.nestedCalls.insert(ctu.nestedCalls.end(), fi2->nestedCalls.cbegin(), fi2->nestedCalls.cend());

View File

@ -200,6 +200,8 @@ private:
void executeRules(const std::string &tokenlist, const Tokenizer &tokenizer);
#endif
unsigned int checkClang(const std::string &path);
/**
* @brief Errors and warnings are directed here.
*

View File

@ -309,7 +309,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
{
const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase();
FileInfo *fileInfo = new FileInfo;
auto *fileInfo = new FileInfo;
// Parse all functions in TU
for (const Scope &scope : symbolDatabase->scopeList) {
@ -513,7 +513,7 @@ static bool findPath(const std::string &callId,
if (c->callArgNr != callArgNr)
continue;
const CTU::FileInfo::FunctionCall *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(c);
const auto *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(c);
if (functionCall) {
if (!warning && functionCall->warning)
continue;
@ -537,7 +537,7 @@ static bool findPath(const std::string &callId,
return true;
}
const CTU::FileInfo::NestedCall *nestedCall = dynamic_cast<const CTU::FileInfo::NestedCall *>(c);
const auto *nestedCall = dynamic_cast<const CTU::FileInfo::NestedCall *>(c);
if (!nestedCall)
continue;
@ -570,7 +570,7 @@ std::list<ErrorMessage::FileLocation> CTU::FileInfo::getErrorPath(InvalidValueTy
if (!path[index])
continue;
const CTU::FileInfo::FunctionCall *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(path[index]);
const auto *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(path[index]);
if (functionCall) {
if (functionCallPtr)

View File

@ -31,14 +31,17 @@ struct CPPCHECKLIB FileSettings {
std::string cfg;
std::string filename;
std::string defines;
// TODO: handle differently
std::string cppcheckDefines() const {
return defines + (msc ? ";_MSC_VER=1900" : "") + (useMfc ? ";__AFXWIN_H__=1" : "");
}
std::set<std::string> undefs;
std::list<std::string> includePaths;
// only used by clang mode
std::list<std::string> systemIncludePaths;
std::string standard;
Platform::Type platformType = Platform::Type::Unspecified;
// TODO: get rid of these
bool msc{};
bool useMfc{};
};

View File

@ -26,10 +26,12 @@
#include "settings.h"
#include "symboldatabase.h"
#include "token.h"
#include "utils.h"
#include "valueptr.h"
#include "vfvalue.h"
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <functional>
#include <list>
@ -443,7 +445,7 @@ namespace {
if (checkElse && isDoWhile &&
(condTok->hasKnownIntValue() ||
(!bodyAnalysis.isModified() && !condAnalysis.isModified() && condAnalysis.isRead()))) {
if (updateRange(endBlock->link(), endBlock) == Progress::Break)
if (updateScope(endBlock) == Progress::Break)
return Break();
return updateRecursive(condTok);
}
@ -519,8 +521,17 @@ namespace {
return updateLoop(endToken, endBlock, condTok, initTok, stepTok, true);
}
Progress updateScope(Token* endBlock) {
return updateRange(endBlock->link(), endBlock);
Progress updateScope(Token* endBlock, int depth = 20)
{
if (!endBlock)
return Break();
assert(endBlock->link());
Token* ctx = endBlock->link()->previous();
if (Token::simpleMatch(ctx, ")"))
ctx = ctx->link()->previous();
if (ctx)
analyzer->updateState(ctx);
return updateRange(endBlock->link(), endBlock, depth);
}
Progress updateRange(Token* start, const Token* end, int depth = 20) {
@ -682,7 +693,7 @@ namespace {
thenBranch.escape = isEscapeScope(endBlock, thenBranch.escapeUnknown);
if (thenBranch.check) {
thenBranch.active = true;
if (updateRange(endCond->next(), endBlock, depth - 1) == Progress::Break)
if (updateScope(endBlock, depth - 1) == Progress::Break)
return Break();
} else if (!elseBranch.check) {
thenBranch.active = true;
@ -694,7 +705,7 @@ namespace {
elseBranch.escape = isEscapeScope(endBlock->linkAt(2), elseBranch.escapeUnknown);
if (elseBranch.check) {
elseBranch.active = true;
const Progress result = updateRange(endBlock->tokAt(2), endBlock->linkAt(2), depth - 1);
const Progress result = updateScope(endBlock->linkAt(2), depth - 1);
if (result == Progress::Break)
return Break();
} else if (!thenBranch.check) {
@ -746,7 +757,7 @@ namespace {
} else if (Token::simpleMatch(tok, "try {")) {
Token* endBlock = tok->next()->link();
ForwardTraversal tryTraversal = fork();
tryTraversal.updateRange(tok->next(), endBlock, depth - 1);
tryTraversal.updateScope(endBlock, depth - 1);
bool bail = tryTraversal.actions.isModified();
if (bail) {
actions = tryTraversal.actions;
@ -760,7 +771,7 @@ namespace {
return Break();
endBlock = endCatch->linkAt(1);
ForwardTraversal ft = fork();
ft.updateRange(endBlock->link(), endBlock, depth - 1);
ft.updateScope(endBlock, depth - 1);
bail |= ft.terminate != Analyzer::Terminate::None || ft.actions.isModified();
}
if (bail)
@ -880,6 +891,8 @@ Analyzer::Result valueFlowGenericForward(Token* start, const Token* end, const V
if (a->invalid())
return Analyzer::Result{Analyzer::Action::None, Analyzer::Terminate::Bail};
ForwardTraversal ft{a, settings};
if (start)
ft.analyzer->updateState(start);
ft.updateRange(start, end);
return Analyzer::Result{ ft.actions, ft.terminate };
}

View File

@ -757,6 +757,7 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
FileSettings fs;
fs.filename = cfilename;
fs.cfg = p.name;
// TODO: detect actual MSC version
fs.msc = true;
fs.useMfc = useOfMfc;
fs.defines = "_WIN32=1";

View File

@ -34,14 +34,13 @@
#include <cassert>
#include <cmath>
#include <functional>
#include <iterator>
#include <list>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <iostream>
ExprIdToken::ExprIdToken(const Token* tok) : tok(tok), exprid(tok ? tok->exprId() : 0) {}
nonneg int ExprIdToken::getExpressionId() const {
@ -1640,6 +1639,14 @@ namespace {
return *it;
}
static bool updateValue(ValueFlow::Value& v, ValueFlow::Value x)
{
const bool returnValue = !x.isUninitValue() && !x.isImpossible();
if (v.isUninitValue() || returnValue)
v = std::move(x);
return returnValue;
}
ValueFlow::Value execute(const Token* expr)
{
depth--;
@ -1648,13 +1655,29 @@ namespace {
}};
if (depth < 0)
return unknown();
ValueFlow::Value v = executeImpl(expr);
if (!v.isUninitValue())
ValueFlow::Value v = unknown();
if (updateValue(v, executeImpl(expr)))
return v;
if (!expr)
return v;
if (expr->exprId() > 0 && pm->hasValue(expr->exprId()))
return pm->at(expr->exprId());
if (expr->exprId() > 0 && pm->hasValue(expr->exprId())) {
if (updateValue(v, pm->at(expr->exprId())))
return v;
}
// Find symbolic values
for (const ValueFlow::Value& value : expr->values()) {
if (!value.isSymbolicValue())
continue;
if (!value.isKnown())
continue;
if (value.tokvalue->exprId() > 0 && !pm->hasValue(value.tokvalue->exprId()))
continue;
ValueFlow::Value v2 = pm->at(value.tokvalue->exprId());
if (!v2.isIntValue() && value.intvalue != 0)
continue;
v2.intvalue += value.intvalue;
return v2;
}
if (const ValueFlow::Value* value = getImpossibleValue(expr))
return *value;
return v;

View File

@ -182,12 +182,8 @@ public:
bool dump{};
std::string dumpFile;
enum Language {
None, C, CPP
};
/** @brief Name of the language that is enforced. Empty per default. */
Language enforcedLang{};
Standards::Language enforcedLang{};
#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING)
/** @brief Is --exception-handling given */

View File

@ -34,6 +34,8 @@
* This struct contains all possible standards that cppcheck recognize.
*/
struct Standards {
enum Language { None, C, CPP };
/** C code standard */
enum cstd_t { C89, C99, C11, CLatest = C11 } c = CLatest;

View File

@ -43,11 +43,11 @@
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits>
#include <sstream> // IWYU pragma: keep
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
//---------------------------------------------------------------------------
@ -1052,7 +1052,7 @@ void SymbolDatabase::createSymbolDatabaseSetScopePointers()
const_cast<Token *>(bodyEnd)->scope(&scope);
for (Token* tok = const_cast<Token *>(bodyStart); tok != bodyEnd; tok = tok->next()) {
for (auto* tok = const_cast<Token *>(bodyStart); tok != bodyEnd; tok = tok->next()) {
if (bodyStart != bodyEnd && tok->str() == "{") {
bool isEndOfScope = false;
for (Scope* innerScope: scope.nestedList) {
@ -1702,7 +1702,7 @@ void SymbolDatabase::createSymbolDatabaseExprIds()
std::unordered_map<std::string, nonneg int> unknownIds;
// Assign IDs to incomplete vars which are part of an expression
// Such variables should be assumed global
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
if (!tok->isIncompleteVar())
continue;
if (!isExpression(tok->astParent()))
@ -1725,7 +1725,7 @@ void SymbolDatabase::createSymbolDatabaseExprIds()
// Assign IDs
ExprIdMap exprIdMap;
std::map<std::string, nonneg int> baseIds;
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
if (tok->varId() > 0) {
tok->exprId(tok->varId());
if (tok->astParent() && tok->astParent()->exprId() == 0)
@ -1794,7 +1794,7 @@ void SymbolDatabase::setArrayDimensionsUsingValueFlow()
continue;
// check each array dimension
for (const Dimension &const_dimension : var->dimensions()) {
Dimension &dimension = const_cast<Dimension &>(const_dimension);
auto &dimension = const_cast<Dimension &>(const_dimension);
if (dimension.num != 0 || !dimension.tok)
continue;
@ -3383,7 +3383,7 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To
if (match) {
auto range = scope1->functionMap.equal_range((*tok)->str());
for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
Function * func = const_cast<Function *>(it->second);
auto * func = const_cast<Function *>(it->second);
if (!func->hasBody()) {
if (func->argsMatch(scope1, func->argDef, (*tok)->next(), path, path_length)) {
const Token *closeParen = (*tok)->next()->link();
@ -6502,7 +6502,7 @@ static bool isContainerYieldPointer(Library::Container::Yield yield)
void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, SourceLocation loc)
{
ValueType* valuetypePtr = new ValueType(valuetype);
auto* valuetypePtr = new ValueType(valuetype);
if (mSettings.debugnormal || mSettings.debugwarnings)
valuetypePtr->setDebugPath(tok, loc);
tok->setValueType(valuetypePtr);
@ -6584,7 +6584,7 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, Source
setValueType(var1Tok, vt);
if (var1Tok != parent->previous())
setValueType(parent->previous(), vt);
Variable *var = const_cast<Variable *>(parent->previous()->variable());
auto *var = const_cast<Variable *>(parent->previous()->variable());
if (var) {
ValueType vt2_(*vt2);
if (vt2_.pointer == 0 && autoTok->strAt(1) == "*")
@ -6737,7 +6737,7 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, Source
varvt.constness |= 1;
}
setValueType(parent->previous(), varvt);
Variable *var = const_cast<Variable *>(parent->previous()->variable());
auto *var = const_cast<Variable *>(parent->previous()->variable());
if (var) {
var->setValueType(varvt);
if (vt2->typeScope && vt2->typeScope->definedType) {
@ -6803,7 +6803,7 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, Source
if (isconst)
varvt.constness |= (1 << autovt.pointer);
setValueType(parent->previous(), varvt);
Variable * var = const_cast<Variable *>(parent->previous()->variable());
auto * var = const_cast<Variable *>(parent->previous()->variable());
if (var) {
var->setValueType(varvt);
if (templateArgType && templateArgType->classScope && templateArgType->classScope->definedType) {

View File

@ -34,6 +34,7 @@
#include <map>
#include <memory>
#include <stack>
#include <type_traits>
#include <utility>
static Token *skipRequires(Token *tok)
@ -1376,7 +1377,7 @@ void TemplateSimplifier::simplifyTemplateAliases()
}
if (found) {
Token *end = const_cast<Token *>(aliasDeclaration.aliasEndToken());
auto *end = const_cast<Token *>(aliasDeclaration.aliasEndToken());
// remove declaration tokens
if (aliasDeclaration.token()->previous())
@ -3227,7 +3228,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
// process uninstantiated templates
// TODO: remove the specialized check and handle all uninstantiated templates someday.
if (!instantiated && specialized) {
Token * tok2 = const_cast<Token *>(templateDeclaration.nameToken());
auto * tok2 = const_cast<Token *>(templateDeclaration.nameToken());
if (mErrorLogger && !mTokenList.getFiles().empty())
mErrorLogger->reportProgress(mTokenList.getFiles()[0], "TemplateSimplifier::simplifyTemplateInstantiations()", tok2->progressValue());

View File

@ -42,6 +42,7 @@
#include <set>
#include <sstream> // IWYU pragma: keep
#include <stack>
#include <type_traits>
#include <unordered_set>
#include <utility>

View File

@ -821,7 +821,14 @@ namespace {
}
}
Token* const tok2 = insertTokens(tok, mRangeType);
// don't add class|struct|union in inheritance list
auto rangeType = mRangeType;
if (Token::Match(tok->previous(), "public|private|protected")) {
while (Token::Match(rangeType.first, "const|class|struct|union"))
rangeType.first = rangeType.first->next();
}
Token* const tok2 = insertTokens(tok, rangeType);
Token* const tok3 = insertTokens(tok2, mRangeTypeQualifiers);
Token *after = tok3;
@ -3354,10 +3361,10 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration)
if (mTimerResults) {
Timer t("Tokenizer::simplifyTokens1::createAst", mSettings->showtime, mTimerResults);
list.createAst();
list.validateAst();
list.validateAst(mSettings->debugnormal);
} else {
list.createAst();
list.validateAst();
list.validateAst(mSettings->debugnormal);
}
if (mTimerResults) {
@ -3915,7 +3922,7 @@ void Tokenizer::simplifyLabelsCaseDefault()
int indentLevel = 0;
for (Token *tok = list.front(); tok; tok = tok->next()) {
// Simplify labels in the executable scope..
Token *start = const_cast<Token *>(startOfExecutableScope(tok));
auto *start = const_cast<Token *>(startOfExecutableScope(tok));
if (start) {
tok = start;
executablescope = true;

View File

@ -50,6 +50,9 @@ TokenList::TokenList(const Settings* settings) :
mSettings(settings)
{
mTokensFrontBack.list = this;
if (mSettings && (mSettings->enforcedLang != Standards::Language::None)) {
mLang = mSettings->enforcedLang;
}
}
TokenList::~TokenList()
@ -80,12 +83,12 @@ void TokenList::deallocateTokens()
void TokenList::determineCppC()
{
if (!mSettings) {
mIsC = Path::isC(getSourceFilePath());
mIsCpp = Path::isCPP(getSourceFilePath());
} else {
mIsC = mSettings->enforcedLang == Settings::Language::C || (mSettings->enforcedLang == Settings::Language::None && Path::isC(getSourceFilePath()));
mIsCpp = mSettings->enforcedLang == Settings::Language::CPP || (mSettings->enforcedLang == Settings::Language::None && Path::isCPP(getSourceFilePath()));
// only try to determine it if it wasn't enforced
if (mLang == Standards::Language::None) {
if (Path::isC(getSourceFilePath()))
mLang = Standards::Language::C;
else if (Path::isCPP(getSourceFilePath()))
mLang = Standards::Language::CPP;
}
}
@ -573,8 +576,12 @@ static bool iscpp11init_impl(const Token * const tok)
}
auto isCaseStmt = [](const Token* colonTok) {
if (!Token::Match(colonTok->tokAt(-1), "%name%|%num%|%char% :"))
if (!Token::Match(colonTok->tokAt(-1), "%name%|%num%|%char%|) :"))
return false;
if (const Token* castTok = colonTok->linkAt(-1)) {
if (Token::simpleMatch(castTok->astParent(), "case"))
return true;
}
const Token* caseTok = colonTok->tokAt(-2);
while (caseTok && Token::Match(caseTok->tokAt(-1), "::|%name%"))
caseTok = caseTok->tokAt(-1);
@ -1718,10 +1725,10 @@ namespace {
};
}
void TokenList::validateAst() const
void TokenList::validateAst(bool print) const
{
OnException oe{[&] {
if (mSettings && mSettings->debugnormal)
if (print)
mTokensFrontBack.front->printOut();
}};
// Check for some known issues in AST to avoid crash/hang later on
@ -1850,7 +1857,7 @@ void TokenList::simplifyPlatformTypes()
if (!mSettings)
return;
const bool isCPP11 = mSettings->standards.cpp >= Standards::CPP11;
const bool isCPP11 = isCPP() && (mSettings->standards.cpp >= Standards::CPP11);
enum { isLongLong, isLong, isInt } type;
@ -1992,7 +1999,7 @@ void TokenList::simplifyStdType()
continue;
}
if (Token::Match(tok, "char|short|int|long|unsigned|signed|double|float") || (mSettings->standards.c >= Standards::C99 && Token::Match(tok, "complex|_Complex"))) {
if (Token::Match(tok, "char|short|int|long|unsigned|signed|double|float") || (isC() && (!mSettings || (mSettings->standards.c >= Standards::C99)) && Token::Match(tok, "complex|_Complex"))) {
bool isFloat= false;
bool isSigned = false;
bool isUnsigned = false;
@ -2015,7 +2022,7 @@ void TokenList::simplifyStdType()
else if (Token::Match(tok2, "float|double")) {
isFloat = true;
typeSpec = tok2;
} else if (mSettings->standards.c >= Standards::C99 && Token::Match(tok2, "complex|_Complex"))
} else if (isC() && (!mSettings || (mSettings->standards.c >= Standards::C99)) && Token::Match(tok2, "complex|_Complex"))
isComplex = !isFloat || tok2->str() == "_Complex" || Token::Match(tok2->next(), "*|&|%name%"); // Ensure that "complex" is not the variables name
else if (Token::Match(tok2, "char|int")) {
if (!typeSpec)
@ -2053,7 +2060,7 @@ void TokenList::simplifyStdType()
bool TokenList::isKeyword(const std::string &str) const
{
if (mIsCpp) {
if (isCPP()) {
// TODO: integrate into keywords?
// types and literals are not handled as keywords
static const std::unordered_set<std::string> cpp_types = {"bool", "false", "true"};

View File

@ -22,15 +22,16 @@
//---------------------------------------------------------------------------
#include "config.h"
#include "standards.h"
#include <cstddef>
#include <iosfwd>
#include <string>
#include <vector>
class Settings;
class Token;
class TokenList;
class Settings;
namespace simplecpp {
class TokenList;
@ -61,12 +62,12 @@ public:
/** Is the code C. Used for bailouts */
bool isC() const {
return mIsC;
return mLang == Standards::Language::C;
}
/** Is the code CPP. Used for bailouts */
bool isCPP() const {
return mIsCpp;
return mLang == Standards::Language::CPP;
}
/**
@ -171,7 +172,7 @@ public:
* Check abstract syntax tree.
* Throws InternalError on failure
*/
void validateAst() const;
void validateAst(bool print) const;
/**
* Verify that the given token is an element of the tokenlist.
@ -214,8 +215,7 @@ private:
const Settings* const mSettings{};
/** File is known to be C/C++ code */
bool mIsC{};
bool mIsCpp{};
Standards::Language mLang{Standards::Language::None};
};
/// @}

View File

@ -2969,6 +2969,13 @@ struct ValueFlowAnalyzer : Analyzer {
makeConditional();
}
void updateState(const Token* tok) override
{
// Update program state
pms.removeModifiedVars(tok);
pms.addState(tok, getProgramState());
}
virtual void internalUpdate(Token* /*tok*/, const ValueFlow::Value& /*v*/, Direction /*d*/)
{
assert(false && "Internal update unimplemented.");
@ -5113,7 +5120,7 @@ static void valueFlowAfterMove(TokenList& tokenlist, const SymbolDatabase& symbo
start = memberInitializationTok;
}
for (Token* tok = const_cast<Token*>(start); tok != scope->bodyEnd; tok = tok->next()) {
for (auto* tok = const_cast<Token*>(start); tok != scope->bodyEnd; tok = tok->next()) {
Token * varTok;
if (Token::Match(tok, "%var% . reset|clear (") && tok->next()->originalName().empty()) {
varTok = tok;
@ -5369,7 +5376,7 @@ static std::set<nonneg int> getVarIds(const Token* tok)
static void valueFlowSymbolic(const TokenList& tokenlist, const SymbolDatabase& symboldatabase, const Settings* settings)
{
for (const Scope* scope : symboldatabase.functionScopes) {
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
if (!Token::simpleMatch(tok, "="))
continue;
if (tok->astParent())
@ -5462,7 +5469,7 @@ static ValueFlow::Value inferCondition(const std::string& op, const Token* varTo
static void valueFlowSymbolicOperators(const SymbolDatabase& symboldatabase, const Settings* settings)
{
for (const Scope* scope : symboldatabase.functionScopes) {
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
if (tok->hasKnownIntValue())
continue;
@ -5575,7 +5582,7 @@ struct SymbolicInferModel : InferModel {
static void valueFlowSymbolicInfer(const SymbolDatabase& symboldatabase, const Settings* settings)
{
for (const Scope* scope : symboldatabase.functionScopes) {
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
if (!Token::Match(tok, "-|%comp%"))
continue;
if (tok->hasKnownIntValue())
@ -5923,7 +5930,7 @@ static void valueFlowAfterAssign(TokenList &tokenlist,
if (skippedFunctions.count(scope))
continue;
std::unordered_map<nonneg int, std::unordered_set<nonneg int>> backAssigns;
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
// Assignment
bool isInit = false;
if (tok->str() != "=" && !(isInit = isVariableInit(tok)))
@ -6056,7 +6063,7 @@ static void valueFlowAfterSwap(TokenList& tokenlist,
const Settings* settings)
{
for (const Scope* scope : symboldatabase.functionScopes) {
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
if (!Token::simpleMatch(tok, "swap ("))
continue;
if (!Token::simpleMatch(tok->next()->astOperand2(), ","))
@ -6231,7 +6238,7 @@ struct ConditionHandler {
for (const Scope *scope : symboldatabase.functionScopes) {
if (skippedFunctions.count(scope))
continue;
for (Token *tok = const_cast<Token *>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
for (auto *tok = const_cast<Token *>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
if (Token::Match(tok, "if|while|for ("))
continue;
if (Token::Match(tok, ":|;|,"))
@ -6720,7 +6727,7 @@ struct ConditionHandler {
return;
if (r.action.isModified())
return;
Token* start = const_cast<Token*>(loopScope->bodyEnd);
auto* start = const_cast<Token*>(loopScope->bodyEnd);
if (Token::simpleMatch(start, "} while (")) {
start = start->tokAt(2);
forward(start, start->link(), cond.vartok, values, tokenlist, settings);
@ -7173,8 +7180,8 @@ static void valueFlowForLoop(TokenList &tokenlist, const SymbolDatabase& symbold
if (scope.type != Scope::eFor)
continue;
Token* tok = const_cast<Token*>(scope.classDef);
Token* const bodyStart = const_cast<Token*>(scope.bodyStart);
auto* tok = const_cast<Token*>(scope.classDef);
auto* const bodyStart = const_cast<Token*>(scope.bodyStart);
if (!Token::simpleMatch(tok->next()->astOperand2(), ";") ||
!Token::simpleMatch(tok->next()->astOperand2()->astOperand2(), ";"))
@ -8772,7 +8779,7 @@ static void valueFlowContainerSize(TokenList& tokenlist,
// after assignment
for (const Scope *functionScope : symboldatabase.functionScopes) {
for (Token* tok = const_cast<Token*>(functionScope->bodyStart); tok != functionScope->bodyEnd; tok = tok->next()) {
for (auto* tok = const_cast<Token*>(functionScope->bodyStart); tok != functionScope->bodyEnd; tok = tok->next()) {
if (Token::Match(tok, "%name%|;|{|} %var% = %str% ;")) {
Token* containerTok = tok->next();
if (containerTok->exprId() == 0)

View File

@ -5,15 +5,15 @@
#define versionH
#define CPPCHECK_MAJOR_VERSION 2
#define CPPCHECK_MINOR_VERSION 12
#define CPPCHECK_DEVMINOR_VERSION 13
#define CPPCHECK_FIX_VERSION 0
#define CPPCHECK_MINOR_VERSION 13
#define CPPCHECK_DEVMINOR_VERSION 14
#define CPPCHECK_BUGFIX_VERSION 99
#define STRINGIFY(x) STRING(x)
#define STRING(VER) #VER
#if CPPCHECK_MINOR_VERSION == CPPCHECK_DEVMINOR_VERSION
#define CPPCHECK_VERSION_STRING STRINGIFY(CPPCHECK_MAJOR_VERSION) "." STRINGIFY(CPPCHECK_MINOR_VERSION) "." STRINGIFY(CPPCHECK_FIX_VERSION)
#define CPPCHECK_VERSION CPPCHECK_MAJOR_VERSION,CPPCHECK_MINOR_VERSION,CPPCHECK_FIX_VERSION,0
#if CPPCHECK_BUGFIX_VERSION < 99
#define CPPCHECK_VERSION_STRING STRINGIFY(CPPCHECK_MAJOR_VERSION) "." STRINGIFY(CPPCHECK_MINOR_VERSION) "." STRINGIFY(CPPCHECK_BUGFIX_VERSION)
#define CPPCHECK_VERSION CPPCHECK_MAJOR_VERSION,CPPCHECK_MINOR_VERSION,CPPCHECK_BUGFIX_VERSION,0
#else
#define CPPCHECK_VERSION_STRING STRINGIFY(CPPCHECK_MAJOR_VERSION) "." STRINGIFY(CPPCHECK_DEVMINOR_VERSION) " dev"
#define CPPCHECK_VERSION CPPCHECK_MAJOR_VERSION,CPPCHECK_MINOR_VERSION,99,0

View File

@ -26,7 +26,7 @@ SUPPRESS_WARNING_CLANG_PUSH("-Wextra-semi-stmt")
SUPPRESS_WARNING_CLANG_PUSH("-Wsuggest-override")
SUPPRESS_WARNING_CLANG_PUSH("-Wsuggest-destructor-override")
#include <tinyxml2.h>
#include <tinyxml2.h> // IWYU pragma: export
SUPPRESS_WARNING_CLANG_POP
SUPPRESS_WARNING_CLANG_POP

View File

@ -320,7 +320,7 @@ If you can generate a compile database, then it is possible to import that in Cp
In Linux you can use for instance the `bear` (build ear) utility to generate a compile database from arbitrary build tools:
bear make
bear -- make
# Preprocessor Settings
@ -450,10 +450,10 @@ The format for an error suppression is one of:
[error id]:[filename2]
[error id]
The `error id` is the id that you want to suppress. The easiest way to get it is to use the --template=gcc command line flag. The id is shown in brackets.
The `error id` is the id that you want to suppress. The id of a warning is shown in brackets in the normal cppcheck text output. The suppression `error id` may contain \* to match any sequence of tokens.
The filename may include the wildcard characters \* or ?, which matches any sequence of characters or any single character respectively.
It is recommended to use "/" as path separator on all operating systems. The filename must match the filename in the reported warning exactly.
The filename may include the wildcard characters \* or ?, which matches any sequence of characters or any single character respectively.
It is recommended to use forward-slash `/` as path separator on all operating systems. The filename must match the filename in the reported warning exactly.
For instance, if the warning contains a relative path, then the suppression must match that relative path.
## Command line suppression
@ -929,13 +929,87 @@ Addons could be run through Cppcheck command line utility as follows:
This will launch all Cppcheck checks and additionally calls specific checks provided by selected addon.
Some addons need extra arguments. You can configure how you want to execute an addon in a json file. For example put this in misra.json:
{
"script": "misra.py",
"args": [
"--rule-texts=misra.txt"
]
}
And then the configuration can be executed on the Cppcheck command line:
cppcheck --addon=misra.json somefile.c
By default Cppcheck would search addon at the standard path which was specified
during the installation process. You also can set this path directly, for example:
cppcheck --addon=/opt/cppcheck/configurations/my_misra.json somefile.c
This allows you to create and manage multiple configuration files for different projects.
# Library configuration
When external libraries are used, such as WinAPI, POSIX, gtk, Qt, etc, Cppcheck doesn't know how the external functions behave. Cppcheck then fails to detect various problems such as memory leaks, buffer overflows, possible null pointer dereferences, etc. But this can be fixed with configuration files.
When external libraries are used, such as WinAPI, POSIX, gtk, Qt, etc, Cppcheck has no information about functions, types, or macros contained in those libraries. Cppcheck then fails to detect various problems in the code, or might even abort the analysis. But this can be fixed by using the appropriate configuration files.
Cppcheck already contains configurations for several libraries. They can be loaded as described below. Note that the configuration for the standard libraries of C and C++, std.cfg, is always loaded by cppcheck. If you create or update a configuration file for a popular library, we would appreciate if you upload it to us.
Cppcheck already contains configurations for several libraries. They can be loaded as described below. Note that the configuration for the standard libraries of C and C++, std.cfg, is always loaded by cppcheck. If you create or update a configuration file for a popular library, we would appreciate if you supplied it to the cppcheck project.
## Using your own custom .cfg file
## Using a .cfg file
To use a .cfg file shipped with cppcheck, pass the `--library=<lib>` option. The table below shows the currently existing libraries:
| .cfg file | Library | Comment |
| ------------- | ------------- | ------------- |
| avr.cfg | |
| bento4.cfg | [Bento4](http://www.bento4.com/) |
| boost.cfg | [Boost](http://www.boost.org/)|
| bsd.cfg | [BSD](https://www.freebsd.org/) |
| cairo.cfg | [cairo](https://www.cairographics.org/) |
| cppcheck-lib.cfg | [Cppcheck](http://cppcheck.net/) | Used in selfcheck of the Cppcheck code base
| cppunit.cfg | [CppUnit](https://sourceforge.net/projects/cppunit/) |
| dpdk.cfg | |
| embedded_sql.cfg | |
| emscripten.cfg | |
| ginac.cfg | |
| gnu.cfg | [GNU](https://www.gnu.org/) |
| googletest.cfg | [GoogleTest](https://github.com/google/googletest) |
| gtk.cfg | [GTK](https://www.gtk.org/) |
| icu.cfg | |
| kde.cfg | [KDE](https://kde.org/) |
| libcerror.cfg | [libcerror](https://github.com/libyal/libcerror) |
| libcurl.cfg | [libcurl](https://curl.se/libcurl/) |
| libsigc++.cfg | [libsigc++](https://github.com/libsigcplusplus/libsigcplusplus) |
| lua.cfg | |
| mfc.cfg | [MFC](https://learn.microsoft.com/en-us/cpp/mfc/mfc-desktop-applications) |
| microsoft_atl.cfg | [ATL](https://learn.microsoft.com/en-us/cpp/atl/active-template-library-atl-concepts) |
| microsoft_sal.cfg | [SAL annotations](https://learn.microsoft.com/en-us/cpp/c-runtime-library/sal-annotations) |
| microsoft_unittest.cfg | [CppUnitTest](https://learn.microsoft.com/en-us/visualstudio/test/microsoft-visualstudio-testtools-cppunittestframework-api-reference) |
| motif.cfg | |
| nspr.cfg | |
| ntl.cfg | |
| opencv2.cfg | [OpenCV](https://opencv.org/) |
| opengl.cfg | [OpenGL](https://opengl.org/) |
| openmp.cfg | [OpenMP](https://www.openmp.org/) |
| openssl.cfg | [OpenSSL](https://www.openssl.org/) |
| pcre.cfg | [PCRE](https://pcre.org/) |
| posix.cfg | [POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/) |
| python.cfg | |
| qt.cfg | [Qt](https://doc.qt.io/qt.html) |
| ruby.cfg | |
| sdl.cfg | |
| sfml.cfg | |
| sqlite3.cfg | [SQLite](https://www.sqlite.org/) |
| std.cfg | C/C++ standard library | Loaded by default
| tinyxml2.cfg | [TinyXML-2](https://github.com/leethomason/tinyxml2) |
| vcl.cfg | |
| windows.cfg | [Win32 API](https://learn.microsoft.com/en-us/windows/win32/) |
| wxsqlite3.cfg | |
| wxsvg.cfg | |
| wxwidgets.cfg | [wxWidgets](https://www.wxwidgets.org/) |
| zephyr.cfg | |
| zlib.cfg | [zlib](https://www.zlib.net) |
## Creating a custom .cfg file
You can create and use your own .cfg files for your projects. Use `--check-library` to get hints about what you should configure.

View File

@ -1,6 +1,6 @@
---
title: Cppcheck manual
subtitle: Version 2.12.99
subtitle: Version 2.13.99
author: Cppcheck team
lang: en
documentclass: report

View File

@ -1,6 +1,6 @@
---
title: Cppcheck .cfg format
subtitle: Version 2.12.99
subtitle: Version 2.13.99
author: Cppcheck team
lang: en
documentclass: report

View File

@ -1,6 +1,6 @@
---
title: Writing addons
subtitle: Version 2.12.99
subtitle: Version 2.13.99
author: Cppcheck team
lang: en
documentclass: report

Some files were not shown because too many files have changed in this diff Show More