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: strategy:
matrix: 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: include:
- build_gui: false - build_gui: false
- image: "ubuntu:23.10" - image: "ubuntu:23.10"
@ -39,13 +39,6 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - 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 - name: Install missing software on ubuntu
if: contains(matrix.image, 'ubuntu') if: contains(matrix.image, 'ubuntu')
run: | run: |
@ -62,22 +55,12 @@ jobs:
# - it doesn't support centos # - it doesn't support centos
- name: ccache - name: ccache
uses: hendrikmuhs/ccache-action@v1.2 uses: hendrikmuhs/ccache-action@v1.2
if: matrix.image != 'ubuntu:14.04' # no support for --set-config
with: with:
key: ${{ github.workflow }}-${{ matrix.image }} 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 # tests require CMake 3.9 - ccache available
- name: CMake build (no tests) - name: CMake build (no tests)
if: matrix.image == 'centos:7' || matrix.image == 'ubuntu:16.04' if: matrix.image == 'ubuntu:16.04'
run: | run: |
mkdir cmake.output mkdir cmake.output
cd cmake.output cd cmake.output
@ -85,7 +68,7 @@ jobs:
cmake --build . -- -j$(nproc) cmake --build . -- -j$(nproc)
- name: CMake build - 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: | run: |
mkdir cmake.output mkdir cmake.output
cd cmake.output cd cmake.output
@ -99,7 +82,7 @@ jobs:
cmake --build cmake.output -- -j$(nproc) cmake --build cmake.output -- -j$(nproc)
- name: Run CMake test - 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: | run: |
cmake --build cmake.output --target check -- -j$(nproc) cmake --build cmake.output --target check -- -j$(nproc)
@ -107,7 +90,7 @@ jobs:
strategy: strategy:
matrix: 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 fail-fast: false # Prefer quick result
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
@ -118,13 +101,6 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - 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 - name: Install missing software on ubuntu
if: contains(matrix.image, 'ubuntu') if: contains(matrix.image, 'ubuntu')
run: | run: |
@ -136,7 +112,6 @@ jobs:
# - it doesn't support centos # - it doesn't support centos
- name: ccache - name: ccache
uses: hendrikmuhs/ccache-action@v1.2 uses: hendrikmuhs/ccache-action@v1.2
if: matrix.image != 'ubuntu:14.04' # no support for --set-config
with: with:
key: ${{ github.workflow }}-${{ matrix.image }} 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 python3 ../naming.py --var='[a-z].*' --function='[a-z].*' naming_test.c.dump
../../cppcheck --dump naming_test.cpp ../../cppcheck --dump naming_test.cpp
python3 ../naming.py --var='[a-z].*' --function='[a-z].*' naming_test.cpp.dump 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 - name: Build democlient
if: matrix.os == 'ubuntu-22.04' 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! 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! ..\..\cppcheck --dump naming_test.cpp || exit /b !errorlevel!
python3 ..\naming.py --var='[a-z].*' --function='[a-z].*' naming_test.cpp.dump || 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 runs-on: ubuntu-22.04 # run on the latest image only
env: env:
PREMIUM_VERSION: devdrop-20231105 PREMIUM_VERSION: 23.12.0
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Download cppcheckpremium - name: Download cppcheckpremium
run: | 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 tar xzf cppcheckpremium-${{ env.PREMIUM_VERSION }}-amd64.tar.gz
- name: Generate a license file - name: Generate a license file
run: | run: |
echo cppcheck > cppcheck.lic echo cppcheck > cppcheck.lic
echo 231231 >> cppcheck.lic echo 241231 >> cppcheck.lic
echo 80000 >> cppcheck.lic echo 80000 >> cppcheck.lic
echo 57e08c39523ab54d >> cppcheck.lic echo 53b72a908d7aeeee >> cppcheck.lic
echo path:lib >> cppcheck.lic echo path:lib >> cppcheck.lic
- name: Check - name: Check

View File

@ -63,7 +63,7 @@ jobs:
# TODO: switch to Qt 6 after we enabled the Qt mappings again # TODO: switch to Qt 6 after we enabled the Qt mappings again
- name: Prepare CMake - name: Prepare CMake
run: | 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 - name: Prepare CMake dependencies
run: | run: |
@ -140,7 +140,7 @@ jobs:
- name: Prepare CMake - name: Prepare CMake
run: | 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: env:
CC: clang-17 CC: clang-17
CXX: clang++-17 CXX: clang++-17

View File

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

View File

@ -1,14 +1,18 @@
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 3.5)
project(Cppcheck) 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) include(cmake/cxx11.cmake)
use_cxx11() use_cxx11()
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include(GNUInstallDirs) include(GNUInstallDirs)
include(cmake/ccache.cmake)
include(cmake/compilerCheck.cmake) include(cmake/compilerCheck.cmake)
include(cmake/versions.cmake) include(cmake/versions.cmake)
include(cmake/options.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 $(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 $(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 $(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 $(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. Helper class for reading Cppcheck dump files within an addon.
- misra_9.py - misra_9.py
Implementation of the MISRA 9.x rules used by `misra` addon. Implementation of the MISRA 9.x rules used by `misra` addon.
- naming.json - namingng.config.json
Example configuration for `namingng` addon. 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 - ROS_naming.json
Example configuration for the `namingng` addon enforcing the [ROS naming convention for C++ ](http://wiki.ros.org/CppStyleGuide#Files). Example configuration for the `namingng` addon enforcing the [ROS naming convention for C++ ](http://wiki.ros.org/CppStyleGuide#Files).
- runaddon.py - 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"], "RE_NAMESPACE": {".*[A-Z]": [true, "under_scored"],
".*\\_$": [true, "under_scored"]}, ".*\\_$": [true, "under_scored"]},
"RE_FUNCTIONNAME": {".*\\_": [true, "camelCase"], "RE_FUNCTIONNAME": {".*\\_": [true, "camelCase"],

View File

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

View File

@ -311,8 +311,7 @@ class InitializerParser:
if self.ed and self.ed.isValue: if self.ed and self.ed.isValue:
if not isDesignated and len(self.rootStack) > 0 and self.rootStack[-1][1] == self.root: if not isDesignated and len(self.rootStack) > 0 and self.rootStack[-1][1] == self.root:
self.rootStack[-1][0].markStuctureViolation(self.token) self.rootStack[-1][0].markStuctureViolation(self.token)
if isFirstElement and self.token.isInt and self.token.getKnownIntValue() == 0 and self.token.next.str == '}':
if isFirstElement and self.token.str == '0' and self.token.next.str == '}':
# Zero initializer causes recursive initialization # Zero initializer causes recursive initialization
self.root.initializeChildren() self.root.initializeChildren()
elif self.token.isString and self.ed.valueType and self.ed.valueType.pointer > 0: 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_VARNAME": ["[a-z]*[a-zA-Z0-9_]*\\Z"],
"RE_PRIVATE_MEMBER_VARIABLE": null, "RE_PRIVATE_MEMBER_VARIABLE": null,
"RE_FUNCTIONNAME": ["[a-z0-9A-Z]*\\Z"], "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", "var_prefixes": {"uint32_t": "ui32",
"int*": "intp"}, "int*": "intp"},
"function_prefixes": {"uint16_t": "ui16", "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 # cppcheck addon for naming conventions
# An enhanced version. Configuration is taken from a json file # An enhanced version. Configuration is taken from a json file
# It supports to check for type-based prefixes in function or variable names. # 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): # Example usage (variable name must start with lowercase, function name must start with uppercase):
# $ cppcheck --dump path-to-src/ # $ cppcheck --dump path-to-src/
@ -11,9 +12,18 @@
# JSON format: # 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_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"}, # "var_prefixes": {"uint32_t": "ui32"},
# "function_prefixes": {"uint16_t": "ui16", # "function_prefixes": {"uint16_t": "ui16",
# "uint32_t": "ui32"} # "uint32_t": "ui32"}
@ -24,230 +34,386 @@
import cppcheckdata import cppcheckdata
import sys import sys
import os
import re import re
import argparse import argparse
import json import json
# Auxiliary class # Auxiliary class
class DataStruct: class DataStruct:
def __init__(self, file, linenr, string): def __init__(self, file, linenr, string, column=0):
self.file = file self.file = file
self.linenr = linenr self.linenr = linenr
self.str = string 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): def configError(error,fatal=True):
message = "[{filename}:{linenr}] ( {severity} ) naming.py: {msg}\n".format( print('config error: %s'%error)
filename=filename, if fatal:
linenr=linenr, sys.exit(1)
severity=severity,
msg=msg
)
sys.stderr.write(message)
return message
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): def loadConfig(configfile):
with open(configfile) as fh: if not os.path.exists(configfile):
data = json.load(fh) configError("cannot find config file '%s'"%configfile)
return data
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): def evalExpr(conf, exp, mockToken, msgType):
res = re.match(expr, data.str) report_as_error = False
if res: msg = msgType + ' ' + mockToken.str + ' violates naming convention'
errors.append(reportError(data.file, data.linenr, 'style', msg))
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 isinstance(conf, dict):
if conf[exp][0]: report_as_error = conf[exp][0]
msg = msgType + ' ' + mockToken.str + ' violates naming convention : ' + conf[exp][1] msg += ': ' + conf[exp][1]
checkTrueRegex(mockToken, exp, msg, errors)
elif ~conf[exp][0]: res = re.match(exp,mockToken.str)
msg = msgType + ' ' + mockToken.str + ' violates naming convention : ' + conf[exp][1] if bool(res) == report_as_error:
checkFalseRegex(mockToken, exp, msg, errors) reportNamingError(mockToken,msg)
else:
msg = msgType + ' ' + mockToken.str + ' violates naming convention : ' + conf[exp][0] def check_include_guard_name(conf,directive):
checkFalseRegex(mockToken, exp, msg, errors) 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: else:
msg = msgType + ' ' + mockToken.str + ' violates naming convention' print("invalid config value for 'case': '%s'"%use_case,file=sys.stderr)
checkFalseRegex(mockToken, exp, msg, errors) 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) 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: for afile in dumpfiles:
if not afile[-5:] == '.dump': if not afile[-5:] == '.dump':
continue continue
print('Checking ' + afile + '...') if not args.cli:
print('Checking ' + afile + '...')
data = cppcheckdata.CppcheckData(afile) data = cppcheckdata.CppcheckData(afile)
process_data(conf,data)
# Check File naming def check_file_naming(conf,data):
if "RE_FILE" in conf and conf["RE_FILE"]: for source_file in data.files:
mockToken = DataStruct(afile[:-5], "0", afile[afile.rfind('/') + 1:-5]) basename = os.path.basename(source_file)
msgType = 'File name' good = False
for exp in conf["RE_FILE"]: for exp in conf.file:
evalExpr(conf["RE_FILE"], exp, mockToken, msgType, errors) 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 def check_namespace_naming(conf,data):
if "RE_NAMESPACE" in conf and conf["RE_NAMESPACE"]: for tk in data.rawTokens:
for tk in data.rawTokens: if tk.str != 'namespace':
if tk.str == 'namespace': continue
mockToken = DataStruct(tk.next.file, tk.next.linenr, tk.next.str) mockToken = DataStruct(tk.next.file, tk.next.linenr, tk.next.str, tk.next.column)
msgType = 'Namespace' for exp in conf.namespace:
for exp in conf["RE_NAMESPACE"]: evalExpr(conf.namespace, exp, mockToken, 'Namespace')
evalExpr(conf["RE_NAMESPACE"], exp, mockToken, msgType, errors)
for cfg in data.configurations: def check_variable_naming(conf,cfg):
print('Checking %s, config %s...' % (afile, cfg.name)) for var in cfg.variables:
if "RE_VARNAME" in conf and conf["RE_VARNAME"]: if not var.nameToken:
for var in cfg.variables: continue
if var.nameToken and var.access != 'Global' and var.access != 'Public' and var.access != 'Private': if var.access in ('Global','Public','Private'):
prev = var.nameToken.previous continue
varType = prev.str prev = var.nameToken.previous
while "*" in varType and len(varType.replace("*", "")) == 0: varType = prev.str
prev = prev.previous while "*" in varType and len(varType.replace("*", "")) == 0:
varType = prev.str + varType prev = prev.previous
varType = prev.str + varType
if debugprint: if args.debugprint:
print("Variable Name: " + str(var.nameToken.str)) print("Variable Name: " + str(var.nameToken.str))
print("original Type Name: " + str(var.nameToken.valueType.originalTypeName)) print("original Type Name: " + str(var.nameToken.valueType.originalTypeName))
print("Type Name: " + var.nameToken.valueType.type) print("Type Name: " + var.nameToken.valueType.type)
print("Sign: " + str(var.nameToken.valueType.sign)) print("Sign: " + str(var.nameToken.valueType.sign))
print("variable type: " + varType) print("variable type: " + varType)
print("\n") print("\n")
print("\t-- {} {}".format(varType, str(var.nameToken.str))) print("\t-- {} {}".format(varType, str(var.nameToken.str)))
if conf["skip_one_char_variables"] and len(var.nameToken.str) == 1: if conf.skip_one_char_variables and len(var.nameToken.str) == 1:
continue continue
if varType in conf["var_prefixes"]: if varType in conf.variable_prefixes:
if not var.nameToken.str.startswith(conf["var_prefixes"][varType]): prefix = conf.variable_prefixes[varType]
errors.append(reportError( if not var.nameToken.str.startswith(prefix):
var.typeStartToken.file, reportNamingError(var.typeStartToken,
var.typeStartToken.linenr, 'Variable ' +
'style', var.nameToken.str +
'Variable ' + ' violates naming convention',
var.nameToken.str + column=var.nameToken.column)
' violates naming convention'))
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str) mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str, var.nameToken.column)
msgType = 'Variable' for exp in conf.variable:
for exp in conf["RE_VARNAME"]: evalExpr(conf.variable, exp, mockToken, 'Variable')
evalExpr(conf["RE_VARNAME"], exp, mockToken, msgType, errors)
# Check Private Variable naming # Naming check for Global, Private and Public member variables
if "RE_PRIVATE_MEMBER_VARIABLE" in conf and conf["RE_PRIVATE_MEMBER_VARIABLE"]: def check_gpp_naming(conf_list,cfg,access,message):
# TODO: Not converted yet for var in cfg.variables:
for var in cfg.variables: if var.access != access:
if (var.access is None) or var.access != 'Private': continue
continue mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str, var.nameToken.column)
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str) for exp in conf_list:
msgType = 'Private member variable' evalExpr(conf_list, exp, mockToken, message)
for exp in conf["RE_PRIVATE_MEMBER_VARIABLE"]:
evalExpr(conf["RE_PRIVATE_MEMBER_VARIABLE"], exp, mockToken, msgType, errors)
# Check Public Member Variable naming def check_function_naming(conf,cfg):
if "RE_PUBLIC_MEMBER_VARIABLE" in conf and conf["RE_PUBLIC_MEMBER_VARIABLE"]: for token in cfg.tokenlist:
for var in cfg.variables: if not token.function:
if (var.access is None) or var.access != 'Public': continue
continue if token.function.type in ('Constructor', 'Destructor', 'CopyConstructor', 'MoveConstructor'):
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str) continue
msgType = 'Public member variable' retval = token.previous.str
for exp in conf["RE_PUBLIC_MEMBER_VARIABLE"]: prev = token.previous
evalExpr(conf["RE_PUBLIC_MEMBER_VARIABLE"], exp, mockToken, msgType, errors) 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 retval and retval in conf.function_prefixes:
if "RE_GLOBAL_VARNAME" in conf and conf["RE_GLOBAL_VARNAME"]: if not token.function.name.startswith(conf.function_prefixes[retval]):
for var in cfg.variables: reportNamingError(token, 'Function ' + token.function.name + ' violates naming convention', column=token.column)
if (var.access is None) or var.access != 'Global': mockToken = DataStruct(token.file, token.linenr, token.function.name, token.column)
continue msgType = 'Function'
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str) for exp in conf.function_name:
msgType = 'Public member variable' evalExpr(conf.function_name, exp, mockToken, msgType)
for exp in conf["RE_GLOBAL_VARNAME"]:
evalExpr(conf["RE_GLOBAL_VARNAME"], exp, mockToken, msgType, errors)
# Check Functions naming def check_class_naming(conf,cfg):
if "RE_FUNCTIONNAME" in conf and conf["RE_FUNCTIONNAME"]: for fnc in cfg.functions:
for token in cfg.tokenlist: if fnc.type not in ('Constructor','Destructor'):
if token.function: continue
if token.function.type in ('Constructor', 'Destructor', 'CopyConstructor', 'MoveConstructor'): mockToken = DataStruct(fnc.tokenDef.file, fnc.tokenDef.linenr, fnc.name, fnc.tokenDef.column)
continue msgType = 'Class ' + fnc.type
retval = token.previous.str for exp in conf.class_name:
prev = token.previous evalExpr(conf.class_name, exp, mockToken, msgType)
while "*" in retval and len(retval.replace("*", "")) == 0:
prev = prev.previous
retval = prev.str + retval
if debugprint:
print("\t:: {} {}".format(retval, token.function.name))
if retval and retval in conf["function_prefixes"]: def process_data(conf,data):
if not token.function.name.startswith(conf["function_prefixes"][retval]): if conf.file:
errors.append(reportError( check_file_naming(conf,data)
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)
# Check Class naming if conf.namespace:
if "RE_CLASS_NAME" in conf and conf["RE_CLASS_NAME"]: check_namespace_naming(conf,data)
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
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__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Naming verification') parser = cppcheckdata.ArgumentParser()
parser.add_argument('dumpfiles', type=str, nargs='+',
help='A set of dumpfiles to process')
parser.add_argument("--debugprint", action="store_true", default=False, parser.add_argument("--debugprint", action="store_true", default=False,
help="Add debug prints") 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") 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() args = parser.parse_args()
errors = process(args.dumpfiles, args.configfile, args.debugprint) process(args.dumpfile, args.configfile)
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)
sys.exit(0) 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 e[2][2] = { { 1 , 2 }, {} }; // 9.2
int f[5] = { 0 }; int f[5] = { 0 };
int f1[5] = { 0u }; // no-warning #11298
int g[5][2] = { 0 }; int g[5][2] = { 0 };
int h[2][2] = { { 0 } }; // 9.3 int h[2][2] = { { 0 } }; // 9.3
int i[2][2] = { { 0 }, { 0 } }; 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"/> <define name="cairo_bool_t" value="int"/>
<!-- TODO: Configure cairo_status_t as an enum when this is implemented in Cppcheck --> <!-- TODO: Configure cairo_status_t as an enum when this is implemented in Cppcheck -->
<podtype name="cairo_status_t"/> <podtype name="cairo_status_t"/>
<define name="CAIRO_STATUS_READ_ERROR" value="10"/>
<!-- ########## cairo Macros / Defines ########## --> <!-- ########## cairo Macros / Defines ########## -->
<define name="CAIRO_HAS_MIME_SURFACE" value="1"/> <define name="CAIRO_HAS_MIME_SURFACE" value="1"/>
<define name="CAIRO_MIME_TYPE_CCITT_FAX" value="&quot;image/g3fax&quot;"/> <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 --> <!-- This file once has been generated automatically. See https://github.com/scriptum/cppcheck-libs -->
<!-- Now it is maintained and extended manually. --> <!-- Now it is maintained and extended manually. -->
<def format="2"> <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_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_val_if_fail(expr, val)" value="do{if(!(expr)){return val;}}while(0)"/>
<define name="g_return_if_reached()" value="do{return;}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(expr)" value="assert(expr)"/>
<define name="g_assert_not_reached()" value="assert(NULL)"/> <define name="g_assert_not_reached()" value="assert(NULL)"/>
<define name="g_assert_true(expr)" value="g_assert(expr)"/> <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_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_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_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_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_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(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_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)"/> <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> <valid>0:</valid>
</arg> </arg>
</function> </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 --> <!-- https://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html -->
<!-- char *asctime_r(const struct tm *tm, char *buf); --> <!-- char *asctime_r(const struct tm *tm, char *buf); -->
<function name="asctime_r"> <function name="asctime_r">

View File

@ -737,6 +737,7 @@
<not-uninit/> <not-uninit/>
</arg> </arg>
</function> </function>
<!-- https://en.cppreference.com/w/cpp/numeric/math/tgamma -->
<!-- double tgamma(double x); --> <!-- double tgamma(double x); -->
<function name="tgamma,std::tgamma"> <function name="tgamma,std::tgamma">
<use-retval/> <use-retval/>
@ -746,8 +747,11 @@
<leak-ignore/> <leak-ignore/>
<arg nr="1" direction="in"> <arg nr="1" direction="in">
<not-uninit/> <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> </arg>
</function> </function>
<!-- https://en.cppreference.com/w/cpp/numeric/math/tgamma -->
<!-- float tgammaf(float x); --> <!-- float tgammaf(float x); -->
<function name="tgammaf,std::tgammaf"> <function name="tgammaf,std::tgammaf">
<use-retval/> <use-retval/>
@ -757,8 +761,11 @@
<leak-ignore/> <leak-ignore/>
<arg nr="1" direction="in"> <arg nr="1" direction="in">
<not-uninit/> <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> </arg>
</function> </function>
<!-- https://en.cppreference.com/w/cpp/numeric/math/tgamma -->
<!-- long double tgammal(long double x); --> <!-- long double tgammal(long double x); -->
<function name="tgammal,std::tgammal"> <function name="tgammal,std::tgammal">
<use-retval/> <use-retval/>
@ -768,6 +775,8 @@
<leak-ignore/> <leak-ignore/>
<arg nr="1" direction="in"> <arg nr="1" direction="in">
<not-uninit/> <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> </arg>
</function> </function>
<!-- double trunc(double x); --> <!-- double trunc(double x); -->
@ -3035,6 +3044,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<not-uninit/> <not-uninit/>
</arg> </arg>
</function> </function>
<!-- https://cplusplus.com/reference/cmath/lgamma/ -->
<!-- double lgamma(double x); --> <!-- double lgamma(double x); -->
<function name="lgamma,std::lgamma"> <function name="lgamma,std::lgamma">
<use-retval/> <use-retval/>
@ -3044,8 +3054,11 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<leak-ignore/> <leak-ignore/>
<arg nr="1" direction="in"> <arg nr="1" direction="in">
<not-uninit/> <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> </arg>
</function> </function>
<!-- https://cplusplus.com/reference/cmath/lgamma/ -->
<!-- float lgammaf(float x); --> <!-- float lgammaf(float x); -->
<function name="lgammaf,std::lgammaf"> <function name="lgammaf,std::lgammaf">
<use-retval/> <use-retval/>
@ -3055,8 +3068,11 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<leak-ignore/> <leak-ignore/>
<arg nr="1" direction="in"> <arg nr="1" direction="in">
<not-uninit/> <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> </arg>
</function> </function>
<!-- https://cplusplus.com/reference/cmath/lgamma/ -->
<!-- long double lgammal(long double x); --> <!-- long double lgammal(long double x); -->
<function name="lgammal,std::lgammal"> <function name="lgammal,std::lgammal">
<use-retval/> <use-retval/>
@ -3066,6 +3082,8 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<leak-ignore/> <leak-ignore/>
<arg nr="1" direction="in"> <arg nr="1" direction="in">
<not-uninit/> <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> </arg>
</function> </function>
<!-- double rint(double x); --> <!-- double rint(double x); -->

View File

@ -6,11 +6,11 @@ list(REMOVE_ITEM srcs ${mainfile})
add_library(cli_objs OBJECT ${hdrs} ${srcs}) add_library(cli_objs OBJECT ${hdrs} ${srcs})
target_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/lib/) target_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/lib/)
if(USE_BUNDLED_TINYXML2) 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() else()
target_include_directories(cli_objs SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS}) target_include_directories(cli_objs SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS})
endif() 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) if (NOT CMAKE_DISABLE_PRECOMPILE_HEADERS)
target_precompile_headers(cli_objs PRIVATE precompiled.h) target_precompile_headers(cli_objs PRIVATE precompiled.h)
endif() endif()
@ -38,11 +38,11 @@ endif()
add_executable(cppcheck ${cppcheck_SOURCES}) add_executable(cppcheck ${cppcheck_SOURCES})
target_include_directories(cppcheck PRIVATE ${PROJECT_SOURCE_DIR}/lib/) target_include_directories(cppcheck PRIVATE ${PROJECT_SOURCE_DIR}/lib/)
if(USE_BUNDLED_TINYXML2) 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() else()
target_include_directories(cppcheck SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS}) target_include_directories(cppcheck SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS})
endif() 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) if (HAVE_RULES)
target_link_libraries(cppcheck ${PCRE_LIBRARY}) target_link_libraries(cppcheck ${PCRE_LIBRARY})
endif() endif()

View File

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

View File

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

View File

@ -31,6 +31,7 @@
class CppCheck; class CppCheck;
class Settings; class Settings;
class ErrorLogger; class ErrorLogger;
class Suppressions;
/** /**
* This class works as an example of how CppCheck can be used in external * This class works as an example of how CppCheck can be used in external
@ -48,7 +49,7 @@ public:
*/ */
CppCheckExecutor() = default; CppCheckExecutor() = default;
CppCheckExecutor(const CppCheckExecutor &) = delete; CppCheckExecutor(const CppCheckExecutor &) = delete;
void operator=(const CppCheckExecutor&) = delete; CppCheckExecutor& operator=(const CppCheckExecutor&) = delete;
/** /**
* Starts the checking. * Starts the checking.
@ -81,7 +82,7 @@ private:
protected: 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 * Wrapper around check_internal

View File

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

View File

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

View File

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

View File

@ -20,7 +20,7 @@
/** /**
* *
* @mainpage Cppcheck * @mainpage Cppcheck
* @version 2.12.99 * @version 2.13.99
* *
* @section overview_sec Overview * @section overview_sec Overview
* Cppcheck is a simple tool for static analysis of C/C++ code. * 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 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); 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); static constexpr std::size_t l_size = sizeof(unsigned int);
writeToPipeInternal(type, &len, l_size); writeToPipeInternal(type, &len, l_size);

View File

@ -43,7 +43,7 @@ class ProcessExecutor : public Executor {
public: 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 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; ProcessExecutor(const ProcessExecutor &) = delete;
void operator=(const ProcessExecutor &) = delete; ProcessExecutor& operator=(const ProcessExecutor &) = delete;
unsigned int check() override; unsigned int check() override;

View File

@ -37,7 +37,7 @@ class SingleExecutor : public Executor
public: 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(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; SingleExecutor(const SingleExecutor &) = delete;
void operator=(const SingleExecutor &) = delete; SingleExecutor& operator=(const SingleExecutor &) = delete;
unsigned int check() override; unsigned int check() override;

View File

@ -45,7 +45,7 @@ class ThreadExecutor : public Executor {
public: 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 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; ThreadExecutor(const ThreadExecutor &) = delete;
void operator=(const ThreadExecutor &) = delete; ThreadExecutor& operator=(const ThreadExecutor &) = delete;
unsigned int check() override; 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_ID STREQUAL "GNU")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
message(ERROR "GCC >= 4.8 required - detected ${CMAKE_CXX_COMPILER_VERSION} not supported") message(ERROR "GCC >= 5.1 required - detected ${CMAKE_CXX_COMPILER_VERSION} not supported")
endif () endif ()
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# TODO: verify this if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2.9) message(ERROR "Clang >= 3.5 required - detected ${CMAKE_CXX_COMPILER_VERSION} not supported")
message(ERROR "Clang >= 2.9 required - detected ${CMAKE_CXX_COMPILER_VERSION} not supported")
endif () endif ()
elseif(MSVC) elseif(MSVC)
if (MSVC_VERSION VERSION_LESS 1800) if (MSVC_VERSION VERSION_LESS 1900)
message(ERROR "Visual Studio >= 2013 (1800) required - detected ${MSVC_VERSION} not supported") message(ERROR "Visual Studio >= 2015 (19.0) required - detected ${MSVC_VERSION} not supported")
endif () endif ()
endif() endif()

View File

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

View File

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

View File

@ -1,20 +1,9 @@
macro(use_cxx11) macro(use_cxx11)
if (CMAKE_VERSION VERSION_LESS "3.1") # some GitHub Action Windows runners randomly fail with a complaint that Qt6 requires a C++17 compiler
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if (MSVC AND USE_QT6)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") # CMAKE_CXX_STANDARD 17 was added in CMake 3.8
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set (CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to use")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif ()
else () else ()
# some GitHub Action windows runners randomly fail with a complaint that Qt6 requires a C++17 compiler set (CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to use")
if (MSVC) endif()
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 ()
endmacro(use_cxx11) 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_THREAD "Clang dynamic analyzer: tool that detects data races. " OFF)
option(ANALYZE_UNDEFINED "Clang dynamic analyzer: undefined behavior checker. " OFF) option(ANALYZE_UNDEFINED "Clang dynamic analyzer: undefined behavior checker. " OFF)
option(ANALYZE_DATAFLOW "Clang dynamic analyzer: general dynamic dataflow analysis." OFF) option(ANALYZE_DATAFLOW "Clang dynamic analyzer: general dynamic dataflow analysis." OFF)
option(WARNINGS_ARE_ERRORS "Treat warnings as errors" 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(USE_MATCHCOMPILER "Auto" CACHE STRING "Usage of match compiler")
set_property(CACHE USE_MATCHCOMPILER PROPERTY STRINGS Auto Off On Verify) 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") set(CMAKE_DISABLE_PRECOMPILE_HEADERS On CACHE BOOL "Disable precompiled headers")
endif() 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_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") 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 )
message( STATUS "CMake Version = ${CMAKE_VERSION}") message( STATUS "CMake Version = ${CMAKE_VERSION}")
message( STATUS "CMake Generator = ${CMAKE_GENERATOR}") 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_THREAD = ${ANALYZE_THREAD}" )
message( STATUS "ANALYZE_UNDEFINED = ${ANALYZE_UNDEFINED}" ) message( STATUS "ANALYZE_UNDEFINED = ${ANALYZE_UNDEFINED}" )
message( STATUS "ANALYZE_DATAFLOW = ${ANALYZE_DATAFLOW}" ) message( STATUS "ANALYZE_DATAFLOW = ${ANALYZE_DATAFLOW}" )
message( STATUS )
message( STATUS "WARNINGS_ARE_ERRORS = ${WARNINGS_ARE_ERRORS}" ) message( STATUS "WARNINGS_ARE_ERRORS = ${WARNINGS_ARE_ERRORS}" )
message( STATUS "EXTERNALS_AS_SYSTEM = ${EXTERNALS_AS_SYSTEM}" )
message( STATUS ) message( STATUS )
message( STATUS "USE_MATCHCOMPILER = ${USE_MATCHCOMPILER}" ) message( STATUS "USE_MATCHCOMPILER = ${USE_MATCHCOMPILER}" )
message( STATUS "USE_MATCHCOMPILER_OPT = ${USE_MATCHCOMPILER_OPT}" ) message( STATUS "USE_MATCHCOMPILER_OPT = ${USE_MATCHCOMPILER_OPT}" )

View File

@ -1,11 +1,6 @@
# Version for libraries CPP # Version for libraries CPP
# Version string must have 3 "parts". https://sourceforge.net/p/cppcheck/discussion/development/thread/e57efb2b62/ # Version string must have 3 "parts". https://sourceforge.net/p/cppcheck/discussion/development/thread/e57efb2b62/
SET(VERSION "2.12.99") SET(SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
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}")
# Postfix of so's: # Postfix of so's:
SET(DLLVERSION "") SET(DLLVERSION "")

View File

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

View File

@ -38,7 +38,7 @@ CheckOptions:
set_target_properties(cppcheck-gui PROPERTIES WIN32_EXECUTABLE ON) set_target_properties(cppcheck-gui PROPERTIES WIN32_EXECUTABLE ON)
target_include_directories(cppcheck-gui PRIVATE ${PROJECT_SOURCE_DIR}/lib/) target_include_directories(cppcheck-gui PRIVATE ${PROJECT_SOURCE_DIR}/lib/)
if(USE_BUNDLED_TINYXML2) 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() else()
target_include_directories(cppcheck-gui SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS}) target_include_directories(cppcheck-gui SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS})
endif() endif()

View File

@ -112,7 +112,7 @@ of the GNU General Public License version 3</string>
<item> <item>
<widget class="QLabel" name="mUsedLibs"> <widget class="QLabel" name="mUsedLibs">
<property name="text"> <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> </property>
</widget> </widget>
</item> </item>

View File

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

View File

@ -72,10 +72,10 @@ StyleEditDialog::StyleEditDialog(const CodeEditorStyle& newStyle,
mStyleIncoming(newStyle), mStyleIncoming(newStyle),
mStyleOutgoing(newStyle) mStyleOutgoing(newStyle)
{ {
QVBoxLayout *vboxMain = new QVBoxLayout(this); auto *vboxMain = new QVBoxLayout(this);
QHBoxLayout *hboxEdit = new QHBoxLayout(); auto *hboxEdit = new QHBoxLayout();
// Color/Weight controls // Color/Weight controls
QFormLayout *flEditControls = new QFormLayout(); auto *flEditControls = new QFormLayout();
mBtnWidgetColorFG = new SelectColorButton(this); mBtnWidgetColorFG = new SelectColorButton(this);
flEditControls->addRow(QObject::tr("Editor Foreground Color"), flEditControls->addRow(QObject::tr("Editor Foreground Color"),
mBtnWidgetColorFG); mBtnWidgetColorFG);
@ -141,7 +141,7 @@ StyleEditDialog::StyleEditDialog(const CodeEditorStyle& newStyle,
vboxMain->addLayout(hboxEdit); vboxMain->addLayout(hboxEdit);
// Default Controls // Default Controls
QHBoxLayout *hboxDefaultControls = new QHBoxLayout(); auto *hboxDefaultControls = new QHBoxLayout();
mBtnDefaultLight = new QPushButton(QObject::tr("Set to Default Light"), mBtnDefaultLight = new QPushButton(QObject::tr("Set to Default Light"),
this); this);
mBtnDefaultDark = new QPushButton(QObject::tr("Set to Default Dark"), mBtnDefaultDark = new QPushButton(QObject::tr("Set to Default Dark"),
@ -153,7 +153,7 @@ StyleEditDialog::StyleEditDialog(const CodeEditorStyle& newStyle,
vboxMain->addLayout(hboxDefaultControls); vboxMain->addLayout(hboxDefaultControls);
vboxMain->addStretch(2); vboxMain->addStretch(2);
// dialog controls // dialog controls
QDialogButtonBox *dBtnBox = new QDialogButtonBox( auto *dBtnBox = new QDialogButtonBox(
QDialogButtonBox::Cancel | QDialogButtonBox::Cancel |
QDialogButtonBox::Ok | QDialogButtonBox::Ok |
QDialogButtonBox::Reset); 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 // name patterns are our values. The generated filter string list will
// thus be sorted alphabetically over the descriptions. // thus be sorted alphabetically over the descriptions.
for (const auto& k: filters.keys()) { 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(";;"); return entries.join(";;");

View File

@ -37,6 +37,7 @@
#include <QCheckBox> #include <QCheckBox>
#include <QComboBox> #include <QComboBox>
#include <QCoreApplication> #include <QCoreApplication>
#include <QCryptographicHash>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
@ -52,7 +53,6 @@
#include <QStringList> #include <QStringList>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QTextStream> #include <QTextStream>
#include <QtCore>
static void addHeaders(const QString& file1, QSet<QString> &allFiles) { static void addHeaders(const QString& file1, QSet<QString> &allFiles) {
if (allFiles.contains(file1)) if (allFiles.contains(file1))
@ -170,7 +170,7 @@ void ComplianceReportDialog::save()
} catch (InternalError &e) { } catch (InternalError &e) {
QMessageBox msg(QMessageBox::Critical, QMessageBox msg(QMessageBox::Critical,
tr("Save compliance report"), 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, QMessageBox::Ok,
this); this);
msg.exec(); msg.exec();

View File

@ -176,7 +176,7 @@ Parameters: -l(line) (file)</translation>
<message> <message>
<location filename="compliancereportdialog.cpp" line="173"/> <location filename="compliancereportdialog.cpp" line="173"/>
<source>Failed to import &apos;%1&apos; (%2), can not show files in compliance report</source> <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>
<message> <message>
<source>Failed to import &apos;%1&apos;, can not show files in compliance report</source> <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> <message>
<location filename="mainwindow.cpp" line="961"/> <location filename="mainwindow.cpp" line="961"/>
<source>Failed to load %1 - %2</source> <source>Failed to load %1 - %2</source>
<translation type="unfinished"></translation> <translation>%1 - %2 </translation>
</message> </message>
<message> <message>
<location filename="mainwindow.cpp" line="1313"/> <location filename="mainwindow.cpp" line="1313"/>
@ -1233,7 +1233,7 @@ Analysis is stopped.</source>
<message> <message>
<location filename="mainwindow.cpp" line="1799"/> <location filename="mainwindow.cpp" line="1799"/>
<source>Failed to import &apos;%1&apos; (%2), analysis is stopped</source> <source>Failed to import &apos;%1&apos; (%2), analysis is stopped</source>
<translation type="unfinished"></translation> <translation>&apos;%1&apos; (%2) </translation>
</message> </message>
<message> <message>
<location filename="mainwindow.cpp" line="2099"/> <location filename="mainwindow.cpp" line="2099"/>
@ -2213,7 +2213,7 @@ Options:
<message> <message>
<location filename="resultstree.cpp" line="347"/> <location filename="resultstree.cpp" line="347"/>
<source>internal</source> <source>internal</source>
<translation type="unfinished"></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="resultstree.cpp" line="692"/> <location filename="resultstree.cpp" line="692"/>
@ -2435,7 +2435,7 @@ To toggle what kind of errors are shown, open view menu.</source>
<message> <message>
<location filename="resultsview.cpp" line="575"/> <location filename="resultsview.cpp" line="575"/>
<source>when checking a file</source> <source>when checking a file</source>
<translation type="unfinished"></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="resultsview.cpp" line="576"/> <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'") throw std::runtime_error(QObject::tr("line %1: Mandatory attribute '%2' missing in '%3'")
.arg(xmlReader.lineNumber()) .arg(xmlReader.lineNumber())
.arg(attributeName) .arg(attributeName, xmlReader.name().toString())
.arg(xmlReader.name().toString()).toStdString()); .toStdString());
} }
static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader) 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); const QString file = QDir::toNativeSeparators(error.errorPath.back().file);
QString line = QString("%1,%2,").arg(file).arg(error.errorPath.back().line); QString line = QString("%1,%2,").arg(file, error.errorPath.back().line);
line += QString("%1,%2,%3").arg(GuiSeverity::toString(error.severity)).arg(error.errorId).arg(error.summary); line += QString("%1,%2,%3").arg(GuiSeverity::toString(error.severity), error.errorId, error.summary);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
mTxtWriter << line << Qt::endl; mTxtWriter << line << Qt::endl;
#else #else

View File

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

View File

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

View File

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

View File

@ -55,7 +55,6 @@
#include <QSize> #include <QSize>
#include <QSpinBox> #include <QSpinBox>
#include <QVariant> #include <QVariant>
#include <QtCore>
static constexpr char ADDON_MISRA[] = "misra"; static constexpr char ADDON_MISRA[] = "misra";
static constexpr char CODING_STANDARD_MISRA_C_2023[] = "misra-c-2023"; static constexpr char CODING_STANDARD_MISRA_C_2023[] = "misra-c-2023";
@ -183,7 +182,7 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, bool premium, QWi
libs.sort(); libs.sort();
mUI->mLibraries->clear(); mUI->mLibraries->clear();
for (const QString &lib : libs) { 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->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag
item->setCheckState(Qt::Unchecked); // AND initialize check state item->setCheckState(Qt::Unchecked); // AND initialize check state
} }
@ -605,7 +604,7 @@ void ProjectFileDialog::setProjectConfigurations(const QStringList &configs)
mUI->mListVsConfigs->clear(); mUI->mListVsConfigs->clear();
mUI->mListVsConfigs->setEnabled(!configs.isEmpty() && !mUI->mChkAllVsConfigs->isChecked()); mUI->mListVsConfigs->setEnabled(!configs.isEmpty() && !mUI->mChkAllVsConfigs->isChecked());
for (const QString &cfg : configs) { 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->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag
item->setCheckState(Qt::Unchecked); item->setCheckState(Qt::Unchecked);
} }
@ -622,7 +621,7 @@ void ProjectFileDialog::addIncludeDir(const QString &dir)
return; return;
const QString newdir = QDir::toNativeSeparators(dir); const QString newdir = QDir::toNativeSeparators(dir);
QListWidgetItem *item = new QListWidgetItem(newdir); auto *item = new QListWidgetItem(newdir);
item->setFlags(item->flags() | Qt::ItemIsEditable); item->setFlags(item->flags() | Qt::ItemIsEditable);
mUI->mListIncludeDirs->addItem(item); mUI->mListIncludeDirs->addItem(item);
} }
@ -633,7 +632,7 @@ void ProjectFileDialog::addCheckPath(const QString &path)
return; return;
const QString newpath = QDir::toNativeSeparators(path); const QString newpath = QDir::toNativeSeparators(path);
QListWidgetItem *item = new QListWidgetItem(newpath); auto *item = new QListWidgetItem(newpath);
item->setFlags(item->flags() | Qt::ItemIsEditable); item->setFlags(item->flags() | Qt::ItemIsEditable);
mUI->mListCheckPaths->addItem(item); mUI->mListCheckPaths->addItem(item);
} }
@ -644,7 +643,7 @@ void ProjectFileDialog::addExcludePath(const QString &path)
return; return;
const QString newpath = QDir::toNativeSeparators(path); const QString newpath = QDir::toNativeSeparators(path);
QListWidgetItem *item = new QListWidgetItem(newpath); auto *item = new QListWidgetItem(newpath);
item->setFlags(item->flags() | Qt::ItemIsEditable); item->setFlags(item->flags() | Qt::ItemIsEditable);
mUI->mListExcludedPaths->addItem(item); 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 *ResultsTree::createNormalItem(const QString &name)
{ {
QStandardItem *item = new QStandardItem(name); auto *item = new QStandardItem(name);
item->setData(name, Qt::ToolTipRole); item->setData(name, Qt::ToolTipRole);
item->setEditable(false); item->setEditable(false);
return item; return item;
@ -118,7 +118,7 @@ QStandardItem *ResultsTree::createNormalItem(const QString &name)
QStandardItem *ResultsTree::createCheckboxItem(bool checked) QStandardItem *ResultsTree::createCheckboxItem(bool checked)
{ {
QStandardItem *item = new QStandardItem; auto *item = new QStandardItem;
item->setCheckable(true); item->setCheckable(true);
item->setCheckState(checked ? Qt::Checked : Qt::Unchecked); item->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
item->setEnabled(false); item->setEnabled(false);
@ -127,7 +127,7 @@ QStandardItem *ResultsTree::createCheckboxItem(bool checked)
QStandardItem *ResultsTree::createLineNumberItem(const QString &linenumber) QStandardItem *ResultsTree::createLineNumberItem(const QString &linenumber)
{ {
QStandardItem *item = new QStandardItem(); auto *item = new QStandardItem();
item->setData(QVariant(linenumber.toInt()), Qt::DisplayRole); item->setData(QVariant(linenumber.toInt()), Qt::DisplayRole);
item->setToolTip(linenumber); item->setToolTip(linenumber);
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); 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 //Create a signal mapper so we don't have to store data to class
//member variables //member variables
QSignalMapper *signalMapper = new QSignalMapper(this); auto *signalMapper = new QSignalMapper(this);
if (mContextItem && mApplications->getApplicationCount() > 0 && mContextItem->parent()) { if (mContextItem && mApplications->getApplicationCount() > 0 && mContextItem->parent()) {
//Create an action for the application //Create an action for the application
@ -619,7 +619,7 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e)
if (defaultApplicationIndex < 0) if (defaultApplicationIndex < 0)
defaultApplicationIndex = 0; defaultApplicationIndex = 0;
const Application& app = mApplications->getApplication(defaultApplicationIndex); const Application& app = mApplications->getApplication(defaultApplicationIndex);
QAction *start = new QAction(app.getName(), &menu); auto *start = new QAction(app.getName(), &menu);
if (multipleSelection) if (multipleSelection)
start->setDisabled(true); start->setDisabled(true);
@ -646,11 +646,11 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e)
} }
//Create an action for the application //Create an action for the application
QAction *recheckAction = new QAction(tr("Recheck"), &menu); auto *recheckAction = new QAction(tr("Recheck"), &menu);
QAction *copyAction = new QAction(tr("Copy"), &menu); auto *copyAction = new QAction(tr("Copy"), &menu);
QAction *hide = new QAction(tr("Hide"), &menu); auto *hide = new QAction(tr("Hide"), &menu);
QAction *hideallid = new QAction(tr("Hide all with id"), &menu); auto *hideallid = new QAction(tr("Hide all with id"), &menu);
QAction *opencontainingfolder = new QAction(tr("Open containing folder"), &menu); auto *opencontainingfolder = new QAction(tr("Open containing folder"), &menu);
if (multipleSelection) { if (multipleSelection) {
hideallid->setDisabled(true); hideallid->setDisabled(true);
@ -668,7 +668,7 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e)
menu.addAction(hide); menu.addAction(hide);
menu.addAction(hideallid); 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(); QVariantMap data = mContextItem->data().toMap();
const QString messageId = data[ERRORID].toString(); const QString messageId = data[ERRORID].toString();
@ -691,7 +691,7 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e)
menu.addSeparator(); menu.addSeparator();
QMenu *tagMenu = menu.addMenu(tr("Tag")); 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); tagMenu->addAction(action);
connect(action, &QAction::triggered, [=]() { connect(action, &QAction::triggered, [=]() {
tagSelectedItems(QString()); tagSelectedItems(QString());
@ -699,7 +699,7 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e)
} }
for (const QString& tagstr : currentProject->getTags()) { for (const QString& tagstr : currentProject->getTags()) {
QAction *action = new QAction(tagstr, tagMenu); auto *action = new QAction(tagstr, tagMenu);
tagMenu->addAction(action); tagMenu->addAction(action);
connect(action, &QAction::triggered, [=]() { connect(action, &QAction::triggered, [=]() {
tagSelectedItems(tagstr); tagSelectedItems(tagstr);
@ -816,7 +816,7 @@ void ResultsTree::startApplication(const QStandardItem *target, int application)
} }
#endif // Q_OS_WIN #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 // 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)) #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) 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); QStandardItem *item = model->itemFromIndex(index);
if (!item) { if (!item) {
@ -463,7 +463,7 @@ void ResultsView::updateDetails(const QModelIndex &index)
const QString file0 = data["file0"].toString(); const QString file0 = data["file0"].toString();
if (!file0.isEmpty() && Path::isHeader(data["file"].toString().toStdString())) 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) if (data["cwe"].toInt() > 0)
formattedMsg.prepend("CWE: " + QString::number(data["cwe"].toInt()) + "\n"); formattedMsg.prepend("CWE: " + QString::number(data["cwe"].toInt()) + "\n");

View File

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

View File

@ -10,7 +10,8 @@ add_executable(test-filelist
${CMAKE_SOURCE_DIR}/lib/utils.cpp ${CMAKE_SOURCE_DIR}/lib/utils.cpp
$<TARGET_OBJECTS:simplecpp_objs> $<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_compile_definitions(test-filelist PRIVATE SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(test-filelist ${QT_CORE_LIB} ${QT_TEST_LIB}) target_link_libraries(test-filelist ${QT_CORE_LIB} ${QT_TEST_LIB})

View File

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

View File

@ -43,14 +43,14 @@ if (BUILD_CORE_DLL)
else() else()
add_library(cppcheck-core OBJECT ${srcs_lib} ${hdrs}) add_library(cppcheck-core OBJECT ${srcs_lib} ${hdrs})
endif() 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) 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() else()
target_include_directories(cppcheck-core SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS}) target_include_directories(cppcheck-core SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS})
endif() endif()
target_include_directories(cppcheck-core PRIVATE ${PROJECT_SOURCE_DIR}/externals/picojson/) target_externals_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/simplecpp/)
if (HAVE_RULES) if (HAVE_RULES)
target_include_directories(cppcheck-core SYSTEM PRIVATE ${PCRE_INCLUDE}) target_include_directories(cppcheck-core SYSTEM PRIVATE ${PCRE_INCLUDE})
endif() endif()

View File

@ -52,42 +52,73 @@ static std::string parseAddonInfo(AddonInfo& addoninfo, const picojson::value &j
return "Loading " + fileName + " failed. " + json_error; return "Loading " + fileName + " failed. " + json_error;
} }
if (!json.is<picojson::object>()) if (!json.is<picojson::object>())
return "Loading " + fileName + " failed. Bad json."; return "Loading " + fileName + " failed. JSON is not an object.";
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>();
}
if (obj.count("ctu")) { // TODO: remove/complete default value handling for missing fields
// ctu is specified in the config file const picojson::object& obj = json.get<picojson::object>();
if (!obj["ctu"].is<bool>()) {
return "Loading " + fileName + " failed. ctu must be boolean."; const auto it = obj.find("args");
addoninfo.ctu = obj["ctu"].get<bool>(); if (it != obj.cend()) {
} else { const auto& val = it->second;
addoninfo.ctu = false; if (!val.is<picojson::array>())
} return "Loading " + fileName + " failed. 'args' must be an array.";
for (const picojson::value &v : val.get<picojson::array>()) {
if (obj.count("python")) { if (!v.is<std::string>())
// Python was defined in the config file return "Loading " + fileName + " failed. 'args' entry is not a string.";
if (obj["python"].is<picojson::array>()) { addoninfo.args += " " + v.get<std::string>();
return "Loading " + fileName +" failed. python must not be an array."; }
} }
addoninfo.python = obj["python"].get<std::string>();
} else {
addoninfo.python = "";
} }
if (obj.count("executable")) { {
if (!obj["executable"].is<std::string>()) const auto it = obj.find("ctu");
return "Loading " + fileName + " failed. executable must be a string."; if (it != obj.cend()) {
addoninfo.executable = getFullPath(obj["executable"].get<std::string>(), fileName); const auto& val = it->second;
return ""; // 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) { 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; virtual bool stopOnCondition(const Token* condTok) const = 0;
/// The condition that will be assumed during analysis /// The condition that will be assumed during analysis
virtual void assume(const Token* tok, bool state, unsigned int flags = 0) = 0; 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 /// Return analyzer for expression at token
virtual ValuePtr<Analyzer> reanalyze(Token* tok, const std::string& msg = emptyString) const = 0; virtual ValuePtr<Analyzer> reanalyze(Token* tok, const std::string& msg = emptyString) const = 0;
virtual bool invalid() const { 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 (val.isLocalLifetimeValue() || (pointer && val.isSymbolicValue() && val.intvalue == 0)) {
if (findAstNode(val.tokvalue, if (findAstNode(val.tokvalue,
[&](const Token* aliasTok) { [&](const Token* aliasTok) {
return aliasTok->exprId() == childTok->exprId(); return aliasTok != childTok && aliasTok->exprId() == childTok->exprId();
})) { })) {
if (val.isInconclusive() && inconclusive != nullptr) { if (val.isInconclusive() && inconclusive != nullptr) {
value = &val; value = &val;
@ -2651,8 +2651,11 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings *settings,
const Token * ptok = tok2; const Token * ptok = tok2;
while (Token::Match(ptok->astParent(), ".|::|[")) while (Token::Match(ptok->astParent(), ".|::|["))
ptok = 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 inconclusive = false;
bool isChanged = isVariableChangedByFunctionCall(ptok, indirect, settings, &inconclusive); bool isChanged = isVariableChangedByFunctionCall(ptok, pindirect, settings, &inconclusive);
isChanged |= inconclusive; isChanged |= inconclusive;
if (isChanged) if (isChanged)
return true; return true;
@ -3257,6 +3260,8 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings
continue; continue;
if (arg->isReference()) if (arg->isReference())
return ExprUsage::PassedByReference; return ExprUsage::PassedByReference;
if (arg->isPointer() && indirect == 1)
return ExprUsage::PassedByReference;
} }
if (!args.empty() && indirect == 0 && !addressOf) if (!args.empty() && indirect == 0 && !addressOf)
return ExprUsage::Used; return ExprUsage::Used;
@ -3301,6 +3306,8 @@ ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings,
parent = parent->astParent(); parent = parent->astParent();
if (Token::Match(parent, "%assign%") && (astIsRHS(tok) || astIsLHS(parent->astOperand1()))) if (Token::Match(parent, "%assign%") && (astIsRHS(tok) || astIsLHS(parent->astOperand1())))
return ExprUsage::NotUsed; return ExprUsage::NotUsed;
if (Token::Match(parent, "++|--"))
return ExprUsage::NotUsed;
if (parent->isConstOp()) if (parent->isConstOp())
return ExprUsage::NotUsed; return ExprUsage::NotUsed;
if (parent->isCast()) if (parent->isCast())

View File

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

View File

@ -2633,6 +2633,7 @@ namespace { // avoid one-definition-rule violation
const Variable *var; const Variable *var;
const Token *tok; const Token *tok;
std::vector<const Variable*> initArgs;
}; };
} }
@ -2663,25 +2664,44 @@ void CheckClass::initializerListOrder()
tok = tok->next(); tok = tok->next();
// find all variable initializations in list // 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% (|{")) { if (Token::Match(tok, "%name% (|{")) {
const Variable *var = scope->getVariable(tok->str()); const Variable *var = scope->getVariable(tok->str());
if (var) if (var)
vars.emplace_back(var, tok); vars.emplace_back(var, tok);
else
continue;
if (Token::Match(tok->tokAt(2), "%name% =")) { const Token* const end = tok->next()->link();
var = scope->getVariable(tok->strAt(2)); for (; tok != end; tok = tok->next()) {
if (const Variable* argVar = scope->getVariable(tok->str())) {
if (var) if (scope != argVar->scope())
vars.emplace_back(var, tok->tokAt(2)); 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 = 0; j < vars.size(); j++) {
for (int j = 1; 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 // check for out of order initialization
if (vars[j].var->index() < vars[j - 1].var->index()) if (vars[j].var->index() < vars[j - 1].var->index())
initializerListError(vars[j].tok,vars[j].var->nameToken(), scope->className, vars[j].var->name()); 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 }; 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", reportError(toks, Severity::style, "initializerList",
"$symbol:" + classname + "::" + varname +"\n" "$symbol:" + classname + "::" + varname + '\n' +
"Member variable '$symbol' is in the wrong place in the initializer list.\n" msg + '\n' +
"Member variable '$symbol' is in the wrong place in the initializer list. " msg + ' ' +
"Members are initialized in the order they are declared, not in the " "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 " "in the same order that the members were declared prevents order dependent "
"initialization errors.", CWE398, Certainty::inconclusive); "initialization errors.", CWE398, Certainty::inconclusive);
} }
@ -2988,7 +3011,8 @@ static std::vector<DuplMemberFuncInfo> getDuplInheritedMemberFunctionsRecursive(
if (classFuncIt.name() == parentClassFuncIt.name() && if (classFuncIt.name() == parentClassFuncIt.name() &&
(parentClassFuncIt.access != AccessControl::Private || !skipPrivate) && (parentClassFuncIt.access != AccessControl::Private || !skipPrivate) &&
!classFuncIt.isConstructor() && !classFuncIt.isDestructor() && !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); results.emplace_back(&classFuncIt, &parentClassFuncIt, &parentClassIt);
} }
} }
@ -3509,14 +3533,14 @@ Check::FileInfo *CheckClass::getFileInfo(const Tokenizer *tokenizer, const Setti
if (classDefinitions.empty()) if (classDefinitions.empty())
return nullptr; return nullptr;
MyFileInfo *fileInfo = new MyFileInfo; auto *fileInfo = new MyFileInfo;
fileInfo->classDefinitions.swap(classDefinitions); fileInfo->classDefinitions.swap(classDefinitions);
return fileInfo; return fileInfo;
} }
Check::FileInfo * CheckClass::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const 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()) { for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (std::strcmp(e->Name(), "class") != 0) if (std::strcmp(e->Name(), "class") != 0)
continue; continue;

View File

@ -199,7 +199,7 @@ private:
void operatorEqToSelfError(const Token *tok); void operatorEqToSelfError(const Token *tok);
void checkConstError(const Token *tok, const std::string &classname, const std::string &funcname, bool suggestStatic); 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 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 suggestInitializationList(const Token *tok, const std::string& varname);
void selfInitializationError(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); 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) 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; std::ostringstream expression;
expression << std::hex << "(X " << bitop << " 0x" << value1 << ") " << op << " 0x" << value2; 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 // 5 => testvalue is larger than both value1 and value2
bool result1, result2; bool result1, result2;
if (isfloat) { if (isfloat) {
const double testvalue = getvalue<double>(test, d1, d2); const auto testvalue = getvalue<double>(test, d1, d2);
result1 = checkFloatRelation(op1, testvalue, d1); result1 = checkFloatRelation(op1, testvalue, d1);
result2 = checkFloatRelation(op2, testvalue, d2); result2 = checkFloatRelation(op2, testvalue, d2);
} else if (useUnsignedInt) { } 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); result1 = checkIntRelation(op1, testvalue, u1);
result2 = checkIntRelation(op2, testvalue, u2); result2 = checkIntRelation(op2, testvalue, u2);
} else { } 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); result1 = checkIntRelation(op1, testvalue, i1);
result2 = checkIntRelation(op2, testvalue, i2); result2 = checkIntRelation(op2, testvalue, i2);
} }

View File

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

View File

@ -135,7 +135,7 @@ private:
* @param varInfo Variable info * @param varInfo Variable info
* @return next token to process (if no other checks needed for this token). NULL if other checks could be performed. * @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 */ /** parse function call */
void functionCall(const Token *tokName, const Token *tokOpeningPar, VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af); 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: public:
CheckMemoryLeak() = delete; CheckMemoryLeak() = delete;
CheckMemoryLeak(const 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) CheckMemoryLeak(const Tokenizer *t, ErrorLogger *e, const Settings *s)
: mTokenizer_(t), mErrorLogger_(e), mSettings_(s) {} : mTokenizer_(t), mErrorLogger_(e), mSettings_(s) {}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -188,13 +188,13 @@ static void createDumpFile(const Settings& settings,
std::string language; std::string language;
switch (settings.enforcedLang) { switch (settings.enforcedLang) {
case Settings::Language::C: case Standards::Language::C:
language = " language=\"c\""; language = " language=\"c\"";
break; break;
case Settings::Language::CPP: case Standards::Language::CPP:
language = " language=\"cpp\""; language = " language=\"cpp\"";
break; break;
case Settings::Language::None: case Standards::Language::None:
if (Path::isCPP(filename)) if (Path::isCPP(filename))
language = " language=\"cpp\""; language = " language=\"cpp\"";
else if (Path::isC(filename)) else if (Path::isC(filename))
@ -423,120 +423,127 @@ static bool reportClangErrors(std::istream &is, const std::function<void(const E
return false; return false;
} }
unsigned int CppCheck::check(const std::string &path) unsigned int CppCheck::checkClang(const std::string &path)
{ {
if (mSettings.clang) { if (!mSettings.quiet)
if (!mSettings.quiet) mErrorLogger.reportOut(std::string("Checking ") + path + " ...", Color::FgGreen);
mErrorLogger.reportOut(std::string("Checking ") + path + " ...", Color::FgGreen);
const std::string lang = Path::isCPP(path) ? "-x c++" : "-x c"; // TODO: this ignores the configured language
const std::string analyzerInfo = mSettings.buildDir.empty() ? std::string() : AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, path, emptyString); const std::string lang = Path::isCPP(path) ? "-x c++" : "-x c";
const std::string clangcmd = analyzerInfo + ".clang-cmd"; const std::string analyzerInfo = mSettings.buildDir.empty() ? std::string() : AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, path, emptyString);
const std::string clangStderr = analyzerInfo + ".clang-stderr"; const std::string clangcmd = analyzerInfo + ".clang-cmd";
const std::string clangAst = analyzerInfo + ".clang-ast"; const std::string clangStderr = analyzerInfo + ".clang-stderr";
std::string exe = mSettings.clangExecutable; const std::string clangAst = analyzerInfo + ".clang-ast";
std::string exe = mSettings.clangExecutable;
#ifdef _WIN32 #ifdef _WIN32
// append .exe if it is not a path // append .exe if it is not a path
if (Path::fromNativeSeparators(mSettings.clangExecutable).find('/') == std::string::npos) { if (Path::fromNativeSeparators(mSettings.clangExecutable).find('/') == std::string::npos) {
exe += ".exe"; exe += ".exe";
} }
#endif #endif
std::string flags(lang + " "); std::string flags(lang + " ");
if (Path::isCPP(path) && !mSettings.standards.stdValue.empty()) // TODO: does not apply C standard
flags += "-std=" + mSettings.standards.stdValue + " "; if (Path::isCPP(path) && !mSettings.standards.stdValue.empty())
flags += "-std=" + mSettings.standards.stdValue + " ";
for (const std::string &i: mSettings.includePaths) for (const std::string &i: mSettings.includePaths)
flags += "-I" + i + " "; 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 args2 = "-fsyntax-only -Xclang -ast-dump -fno-color-diagnostics " + flags + path;
const std::string redirect2 = analyzerInfo.empty() ? std::string("2>&1") : ("2> " + clangStderr); const std::string redirect2 = analyzerInfo.empty() ? std::string("2>&1") : ("2> " + clangStderr);
if (!mSettings.buildDir.empty()) { if (!mSettings.buildDir.empty()) {
std::ofstream fout(clangcmd); std::ofstream fout(clangcmd);
fout << exe << " " << args2 << " " << redirect2 << std::endl; fout << exe << " " << args2 << " " << redirect2 << std::endl;
} else if (mSettings.verbose && !mSettings.quiet) { } else if (mSettings.verbose && !mSettings.quiet) {
mErrorLogger.reportOut(exe + " " + args2); 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;
} }
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); return checkFile(Path::simplifyPath(path), emptyString);
} }
@ -1347,8 +1354,8 @@ void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &token
} }
break; break;
} }
const unsigned int pos1 = (unsigned int)ovector[0]; const auto pos1 = (unsigned int)ovector[0];
const unsigned int pos2 = (unsigned int)ovector[1]; const auto pos2 = (unsigned int)ovector[1];
// jump to the end of the match for the next pcre_exec // jump to the end of the match for the next pcre_exec
pos = (int)pos2; pos = (int)pos2;
@ -1751,7 +1758,7 @@ bool CppCheck::analyseWholeProgram()
// Analyse the tokens // Analyse the tokens
CTU::FileInfo ctu; CTU::FileInfo ctu;
for (const Check::FileInfo *fi : mFileInfo) { 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) { if (fi2) {
ctu.functionCalls.insert(ctu.functionCalls.end(), fi2->functionCalls.cbegin(), fi2->functionCalls.cend()); ctu.functionCalls.insert(ctu.functionCalls.end(), fi2->functionCalls.cbegin(), fi2->functionCalls.cend());
ctu.nestedCalls.insert(ctu.nestedCalls.end(), fi2->nestedCalls.cbegin(), fi2->nestedCalls.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); void executeRules(const std::string &tokenlist, const Tokenizer &tokenizer);
#endif #endif
unsigned int checkClang(const std::string &path);
/** /**
* @brief Errors and warnings are directed here. * @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(); const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase();
FileInfo *fileInfo = new FileInfo; auto *fileInfo = new FileInfo;
// Parse all functions in TU // Parse all functions in TU
for (const Scope &scope : symbolDatabase->scopeList) { for (const Scope &scope : symbolDatabase->scopeList) {
@ -513,7 +513,7 @@ static bool findPath(const std::string &callId,
if (c->callArgNr != callArgNr) if (c->callArgNr != callArgNr)
continue; 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 (functionCall) {
if (!warning && functionCall->warning) if (!warning && functionCall->warning)
continue; continue;
@ -537,7 +537,7 @@ static bool findPath(const std::string &callId,
return true; 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) if (!nestedCall)
continue; continue;
@ -570,7 +570,7 @@ std::list<ErrorMessage::FileLocation> CTU::FileInfo::getErrorPath(InvalidValueTy
if (!path[index]) if (!path[index])
continue; 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 (functionCall) {
if (functionCallPtr) if (functionCallPtr)

View File

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

View File

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

View File

@ -34,14 +34,13 @@
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <functional> #include <functional>
#include <iterator>
#include <list> #include <list>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <iostream>
ExprIdToken::ExprIdToken(const Token* tok) : tok(tok), exprid(tok ? tok->exprId() : 0) {} ExprIdToken::ExprIdToken(const Token* tok) : tok(tok), exprid(tok ? tok->exprId() : 0) {}
nonneg int ExprIdToken::getExpressionId() const { nonneg int ExprIdToken::getExpressionId() const {
@ -1640,6 +1639,14 @@ namespace {
return *it; 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) ValueFlow::Value execute(const Token* expr)
{ {
depth--; depth--;
@ -1648,13 +1655,29 @@ namespace {
}}; }};
if (depth < 0) if (depth < 0)
return unknown(); return unknown();
ValueFlow::Value v = executeImpl(expr); ValueFlow::Value v = unknown();
if (!v.isUninitValue()) if (updateValue(v, executeImpl(expr)))
return v; return v;
if (!expr) if (!expr)
return v; return v;
if (expr->exprId() > 0 && pm->hasValue(expr->exprId())) if (expr->exprId() > 0 && pm->hasValue(expr->exprId())) {
return pm->at(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)) if (const ValueFlow::Value* value = getImpossibleValue(expr))
return *value; return *value;
return v; return v;

View File

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

View File

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

View File

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

View File

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

View File

@ -42,6 +42,7 @@
#include <set> #include <set>
#include <sstream> // IWYU pragma: keep #include <sstream> // IWYU pragma: keep
#include <stack> #include <stack>
#include <type_traits>
#include <unordered_set> #include <unordered_set>
#include <utility> #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* const tok3 = insertTokens(tok2, mRangeTypeQualifiers);
Token *after = tok3; Token *after = tok3;
@ -3354,10 +3361,10 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration)
if (mTimerResults) { if (mTimerResults) {
Timer t("Tokenizer::simplifyTokens1::createAst", mSettings->showtime, mTimerResults); Timer t("Tokenizer::simplifyTokens1::createAst", mSettings->showtime, mTimerResults);
list.createAst(); list.createAst();
list.validateAst(); list.validateAst(mSettings->debugnormal);
} else { } else {
list.createAst(); list.createAst();
list.validateAst(); list.validateAst(mSettings->debugnormal);
} }
if (mTimerResults) { if (mTimerResults) {
@ -3915,7 +3922,7 @@ void Tokenizer::simplifyLabelsCaseDefault()
int indentLevel = 0; int indentLevel = 0;
for (Token *tok = list.front(); tok; tok = tok->next()) { for (Token *tok = list.front(); tok; tok = tok->next()) {
// Simplify labels in the executable scope.. // Simplify labels in the executable scope..
Token *start = const_cast<Token *>(startOfExecutableScope(tok)); auto *start = const_cast<Token *>(startOfExecutableScope(tok));
if (start) { if (start) {
tok = start; tok = start;
executablescope = true; executablescope = true;

View File

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

View File

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

View File

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

View File

@ -5,15 +5,15 @@
#define versionH #define versionH
#define CPPCHECK_MAJOR_VERSION 2 #define CPPCHECK_MAJOR_VERSION 2
#define CPPCHECK_MINOR_VERSION 12 #define CPPCHECK_MINOR_VERSION 13
#define CPPCHECK_DEVMINOR_VERSION 13 #define CPPCHECK_DEVMINOR_VERSION 14
#define CPPCHECK_FIX_VERSION 0 #define CPPCHECK_BUGFIX_VERSION 99
#define STRINGIFY(x) STRING(x) #define STRINGIFY(x) STRING(x)
#define STRING(VER) #VER #define STRING(VER) #VER
#if CPPCHECK_MINOR_VERSION == CPPCHECK_DEVMINOR_VERSION #if CPPCHECK_BUGFIX_VERSION < 99
#define CPPCHECK_VERSION_STRING STRINGIFY(CPPCHECK_MAJOR_VERSION) "." STRINGIFY(CPPCHECK_MINOR_VERSION) "." STRINGIFY(CPPCHECK_FIX_VERSION) #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_FIX_VERSION,0 #define CPPCHECK_VERSION CPPCHECK_MAJOR_VERSION,CPPCHECK_MINOR_VERSION,CPPCHECK_BUGFIX_VERSION,0
#else #else
#define CPPCHECK_VERSION_STRING STRINGIFY(CPPCHECK_MAJOR_VERSION) "." STRINGIFY(CPPCHECK_DEVMINOR_VERSION) " dev" #define CPPCHECK_VERSION_STRING STRINGIFY(CPPCHECK_MAJOR_VERSION) "." STRINGIFY(CPPCHECK_DEVMINOR_VERSION) " dev"
#define CPPCHECK_VERSION CPPCHECK_MAJOR_VERSION,CPPCHECK_MINOR_VERSION,99,0 #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-override")
SUPPRESS_WARNING_CLANG_PUSH("-Wsuggest-destructor-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
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: 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 # Preprocessor Settings
@ -450,10 +450,10 @@ The format for an error suppression is one of:
[error id]:[filename2] [error id]:[filename2]
[error id] [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. 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. 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. For instance, if the warning contains a relative path, then the suppression must match that relative path.
## Command line suppression ## 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. 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 # 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. 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 title: Cppcheck manual
subtitle: Version 2.12.99 subtitle: Version 2.13.99
author: Cppcheck team author: Cppcheck team
lang: en lang: en
documentclass: report documentclass: report

View File

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

View File

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

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