diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 6cc6fe6a9d4..3f155114ab9 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -286,6 +286,9 @@ jobs: # FIXME: test_color_tty fails with xdist - os: macos-13 xdist_n: '1' + # FIXME: test_color_tty fails with xdist + - os: macos-15 + xdist_n: '1' fail-fast: false # Prefer quick result runs-on: ${{ matrix.os }} diff --git a/CMakeLists.txt b/CMakeLists.txt index a99ce95e6ae..73186b21ade 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.13) -project(Cppcheck VERSION 2.17.99 LANGUAGES CXX) +project(Cppcheck VERSION 2.18.3 LANGUAGES CXX) include(cmake/options.cmake) diff --git a/Makefile b/Makefile index 9ba42bb6bb1..cc031f1cea1 100644 --- a/Makefile +++ b/Makefile @@ -132,7 +132,7 @@ ifeq (clang++, $(findstring clang++,$(CXX))) CPPCHK_GLIBCXX_DEBUG= endif ifndef CXXFLAGS - CXXFLAGS=-pedantic -Wall -Wextra -Wcast-qual -Wfloat-equal -Wmissing-declarations -Wmissing-format-attribute -Wno-long-long -Wpacked -Wredundant-decls -Wundef -Wno-sign-compare -Wno-multichar -Woverloaded-virtual $(CPPCHK_GLIBCXX_DEBUG) -g + CXXFLAGS=-O2 -DNDEBUG -Wall -Wno-sign-compare -Wno-multichar endif ifeq (g++, $(findstring g++,$(CXX))) @@ -372,7 +372,7 @@ dmake: tools/dmake/dmake.o cli/filelister.o $(libcppdir)/pathmatch.o $(libcppdir $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) run-dmake: dmake - ./dmake + ./dmake --release clean: rm -f build/*.cpp build/*.o lib/*.o cli/*.o frontend/*.o test/*.o tools/dmake/*.o externals/*/*.o testrunner dmake cppcheck cppcheck.exe cppcheck.1 diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index ff4a37b629c..7aca02a20e4 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -1103,12 +1103,14 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mSettings.premiumArgs += " "; const std::string p(argv[i] + 10); const std::string p2(p.find('=') != std::string::npos ? p.substr(0, p.find('=')) : ""); - if (!valid.count(p) && !valid2.count(p2)) { + const bool isCodingStandard = startsWith(p, "autosar") || startsWith(p,"cert-") || startsWith(p,"misra-"); + const std::string p3(endsWith(p,":all") && isCodingStandard ? p.substr(0,p.rfind(':')) : p); + if (!valid.count(p3) && !valid2.count(p2)) { mLogger.printError("invalid --premium option '" + (p2.empty() ? p : p2) + "'."); return Result::Fail; } mSettings.premiumArgs += "--" + p; - if (startsWith(p, "autosar") || startsWith(p, "cert") || startsWith(p, "misra")) { + if (isCodingStandard) { // All checkers related to the coding standard should be enabled. The coding standards // do not all undefined behavior or portability issues. mSettings.addEnabled("warning"); @@ -1862,9 +1864,13 @@ void CmdLineParser::printHelp() const " * misra-c-2025 Misra C 2025\n" " * misra-c++-2008 Misra C++ 2008\n" " * misra-c++-2023 Misra C++ 2023\n" + " By default 'Misra/Cert C' only checks C files.\n" + " By default 'Autosar/Misra/Cert C++' only checks C++ files.\n" + " To check all files, append \":all\" i.e. --premium=misra-c++-2023:all.\n" " Other:\n" " * bughunting Soundy analysis\n" " * cert-c-int-precision=BITS Integer precision to use in Cert C analysis.\n" + " * metrics Calculate metrics. Metrics are only reported in xmlv3 output.\n" " * safety Turn on safety certified behavior (ON by default)\n" " * safety-off Turn off safety certified behavior\n"; } diff --git a/cli/main.cpp b/cli/main.cpp index d486b0c01ee..82b767ad914 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -20,7 +20,7 @@ /** * * @mainpage Cppcheck - * @version 2.17.99 + * @version 2.18.3 * * @section overview_sec Overview * Cppcheck is a simple tool for static analysis of C/C++ code. diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index ce900e4230a..127885cc22f 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -76,6 +76,7 @@ #include #include #include +#include #include #include #include @@ -193,6 +194,8 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) : // About menu connect(mUI->mActionAbout, &QAction::triggered, this, &MainWindow::about); connect(mUI->mActionLicense, &QAction::triggered, this, &MainWindow::showLicense); + mUI->mActionEULA->setVisible(isCppcheckPremium()); + connect(mUI->mActionEULA, &QAction::triggered, this, &MainWindow::showEULA); // View > Toolbar menu connect(mUI->mActionToolBarMain, SIGNAL(toggled(bool)), this, SLOT(toggleMainToolBar())); @@ -1643,6 +1646,11 @@ void MainWindow::showAuthors() dlg->exec(); } +void MainWindow::showEULA() +{ + QDesktopServices::openUrl(QUrl("https://www.cppcheck.com/EULA")); +} + void MainWindow::performSelectedFilesCheck(const QStringList &selectedFilesList) { reAnalyzeSelected(selectedFilesList); diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 4999f101f80..76fda4f0de6 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -170,6 +170,9 @@ public slots: /** @brief Slot to to show authors list */ void showAuthors(); + /** @brief Slot to to show EULA */ + void showEULA(); + /** @brief Slot to save results */ void save(); diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui index 6fb74bc0cb2..bf83b86a65e 100644 --- a/gui/mainwindow.ui +++ b/gui/mainwindow.ui @@ -124,7 +124,7 @@ 0 0 640 - 30 + 22 @@ -200,6 +200,7 @@ + @@ -1025,6 +1026,11 @@ Autosar + + + EULA... + + diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 181551e05f6..74bece05329 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -850,7 +850,7 @@ static simplecpp::TokenList createTokenList(const std::string& filename, std::ve return {filename, files, outputList}; } -std::size_t CppCheck::calculateHash(const Preprocessor& preprocessor, const simplecpp::TokenList& tokens) const +std::size_t CppCheck::calculateHash(const Preprocessor& preprocessor, const simplecpp::TokenList& tokens, const std::string& filePath) const { std::ostringstream toolinfo; toolinfo << (mSettings.cppcheckCfgProductName.empty() ? CPPCHECK_VERSION_STRING : mSettings.cppcheckCfgProductName); @@ -867,7 +867,7 @@ std::size_t CppCheck::calculateHash(const Preprocessor& preprocessor, const simp } toolinfo << mSettings.premiumArgs; // TODO: do we need to add more options? - mSuppressions.nomsg.dump(toolinfo); + mSuppressions.nomsg.dump(toolinfo, filePath); return preprocessor.calculateHash(tokens, toolinfo.str()); } @@ -1020,7 +1020,7 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string if (analyzerInformation) { // Calculate hash so it can be compared with old hash / future hashes - const std::size_t hash = calculateHash(preprocessor, tokens1); + const std::size_t hash = calculateHash(preprocessor, tokens1, file.spath()); std::list errors; if (!analyzerInformation->analyzeFile(mSettings.buildDir, file.spath(), cfgname, fileIndex, hash, errors)) { while (!errors.empty()) { diff --git a/lib/cppcheck.h b/lib/cppcheck.h index d56d7fa6b4f..57b75a32613 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -171,7 +171,7 @@ class CPPCHECKLIB CppCheck { * @param tokens Token list from preprocessed file. * @return hash */ - std::size_t calculateHash(const Preprocessor &preprocessor, const simplecpp::TokenList &tokens) const; + std::size_t calculateHash(const Preprocessor &preprocessor, const simplecpp::TokenList &tokens, const std::string& filePath = {}) const; /** * @brief Check a file using stream diff --git a/lib/pathmatch.cpp b/lib/pathmatch.cpp index 9dd4ce2b120..47856d82145 100644 --- a/lib/pathmatch.cpp +++ b/lib/pathmatch.cpp @@ -113,7 +113,7 @@ bool PathMatch::match(const std::string &pattern, const std::string &path, const /* No match, try to backtrack */ if (!b.empty()) { - const auto &bp = b.top(); + const auto bp = b.top(); b.pop(); s.setpos(bp.first); t.setpos(bp.second); diff --git a/lib/suppressions.cpp b/lib/suppressions.cpp index bf97bdb2b81..68bf90bfb14 100644 --- a/lib/suppressions.cpp +++ b/lib/suppressions.cpp @@ -512,12 +512,14 @@ bool SuppressionList::isSuppressed(const ::ErrorMessage &errmsg, const std::set< return isSuppressed(SuppressionList::ErrorMessage::fromErrorMessage(errmsg, macroNames)); } -void SuppressionList::dump(std::ostream & out) const +void SuppressionList::dump(std::ostream & out, const std::string& filePath) const { std::lock_guard lg(mSuppressionsSync); out << " " << std::endl; for (const Suppression &suppression : mSuppressions) { + if (suppression.isInline && !suppression.fileName.empty() && !filePath.empty() && filePath != suppression.fileName) + continue; out << " previous()->linenr(start->linenr()); dst->previous()->column(start->column()); Token *previous = dst->previous(); - previous->isTemplateArg(true); + previous->templateArgFrom(typetok); previous->isSigned(typetok->isSigned()); previous->isUnsigned(typetok->isUnsigned()); previous->isLong(typetok->isLong()); @@ -2016,7 +2016,7 @@ void TemplateSimplifier::expandTemplate( Token::createMutualLinks(brackets1.top(), back); brackets1.pop(); } - back->isTemplateArg(true); + back->templateArgFrom(typetok); back->isUnsigned(typetok->isUnsigned()); back->isSigned(typetok->isSigned()); back->isLong(typetok->isLong()); @@ -2120,7 +2120,7 @@ void TemplateSimplifier::expandTemplate( Token::createMutualLinks(par1, mTokenList.back()); mTokenList.addtoken(typetok, tok3); for (Token* t = par1; t; t = t->next()) - t->isTemplateArg(true); + t->templateArgFrom(typetok); continue; } } @@ -2174,7 +2174,7 @@ void TemplateSimplifier::expandTemplate( brackets1.pop(); } if (copy) - back->isTemplateArg(true); + back->templateArgFrom(typetok); } if (pointerType && Token::simpleMatch(beforeTypeToken, "const")) { mTokenList.addtoken(beforeTypeToken); diff --git a/lib/token.cpp b/lib/token.cpp index 98f79b4bb1d..66f7ee0992e 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -2720,3 +2720,10 @@ Token* findLambdaEndScope(Token* tok) const Token* findLambdaEndScope(const Token* tok) { return findLambdaEndScope(const_cast(tok)); } + +void Token::templateArgFrom(const Token* fromToken) { + setFlag(fIsTemplateArg, fromToken != nullptr); + mImpl->mTemplateArgFileIndex = fromToken ? fromToken->mImpl->mFileIndex : -1; + mImpl->mTemplateArgLineNumber = fromToken ? fromToken->mImpl->mLineNumber : -1; + mImpl->mTemplateArgColumn = fromToken ? fromToken->mImpl->mColumn : -1; +} diff --git a/lib/token.h b/lib/token.h index ecdba24007b..5fc7575c98d 100644 --- a/lib/token.h +++ b/lib/token.h @@ -70,6 +70,11 @@ struct TokenImpl { nonneg int mColumn{}; nonneg int mExprId{}; + // original template argument location + int mTemplateArgFileIndex{-1}; + int mTemplateArgLineNumber{-1}; + int mTemplateArgColumn{-1}; + /** * A value from 0-100 that provides a rough idea about where in the token * list this token is located. @@ -821,8 +826,15 @@ class CPPCHECKLIB Token { bool isTemplateArg() const { return getFlag(fIsTemplateArg); } - void isTemplateArg(const bool value) { - setFlag(fIsTemplateArg, value); + void templateArgFrom(const Token* fromToken); + int templateArgFileIndex() const { + return mImpl->mTemplateArgFileIndex; + } + int templateArgLineNumber() const { + return mImpl->mTemplateArgLineNumber; + } + int templateArgColumn() const { + return mImpl->mTemplateArgColumn; } const std::string& getMacroName() const { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index e1e91937d44..52f0007e86e 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6076,8 +6076,12 @@ void Tokenizer::dump(std::ostream &out) const outs += " externLang=\"C\""; if (tok->isExpandedMacro()) outs += " macroName=\"" + tok->getMacroName() + "\""; - if (tok->isTemplateArg()) + if (tok->isTemplateArg()) { outs += " isTemplateArg=\"true\""; + outs += " templateArgFileIndex=\"" + std::to_string(tok->templateArgFileIndex()) + "\""; + outs += " templateArgLineNumber=\"" + std::to_string(tok->templateArgLineNumber()) + "\""; + outs += " templateArgColumn=\"" + std::to_string(tok->templateArgColumn()) + "\""; + } if (tok->isRemovedVoidParameter()) outs += " isRemovedVoidParameter=\"true\""; if (tok->isSplittedVarDeclComma()) diff --git a/lib/version.h b/lib/version.h index fa70f05295f..bd80dc43fd8 100644 --- a/lib/version.h +++ b/lib/version.h @@ -23,18 +23,18 @@ #define versionH #define CPPCHECK_MAJOR_VERSION 2 -#define CPPCHECK_MINOR_VERSION 17 +#define CPPCHECK_MINOR_VERSION 18 #define CPPCHECK_DEVMINOR_VERSION 18 -#define CPPCHECK_BUGFIX_VERSION 99 +#define CPPCHECK_BUGFIX_VERSION 0 #define STRINGIFY(x) STRING(x) #define STRING(VER) #VER #if CPPCHECK_BUGFIX_VERSION < 99 -#define CPPCHECK_VERSION_STRING STRINGIFY(CPPCHECK_MAJOR_VERSION) "." STRINGIFY(CPPCHECK_MINOR_VERSION) "." STRINGIFY(CPPCHECK_BUGFIX_VERSION) -#define CPPCHECK_VERSION CPPCHECK_MAJOR_VERSION,CPPCHECK_MINOR_VERSION,CPPCHECK_BUGFIX_VERSION,0 +#define CPPCHECK_VERSION_STRING "2.18.3" +#define CPPCHECK_VERSION 2,18,3,0 #else -#define CPPCHECK_VERSION_STRING STRINGIFY(CPPCHECK_MAJOR_VERSION) "." STRINGIFY(CPPCHECK_DEVMINOR_VERSION) " dev" -#define CPPCHECK_VERSION CPPCHECK_MAJOR_VERSION,CPPCHECK_MINOR_VERSION,99,0 +#define CPPCHECK_VERSION_STRING "2.18.3" +#define CPPCHECK_VERSION 2,18,3,0 #endif #define LEGALCOPYRIGHT L"Copyright (C) 2007-2025 Cppcheck team." diff --git a/man/manual-premium.md b/man/manual-premium.md index 848de85f800..65550d7ec94 100644 --- a/man/manual-premium.md +++ b/man/manual-premium.md @@ -102,34 +102,46 @@ need to use both approaches. Later chapters will describe this in more detail. ### Check files matching a given file filter -With `--file-filter=` you can set a file filter and only those files matching the filter will be checked. +With `--file-filter=` you can configure file filter(s) and then only those files matching the filter will be checked. -For example: if you want to check only those files and folders starting from a subfolder src/ that start with "test" -you have to type: +For example, this command below means that `src/test1.cpp` and `src/test/file1.cpp` could be checked, but `src/file2.cpp` will not be checked: cppcheck src/ --file-filter=src/test* -Cppcheck first collects all files in src/ and will apply the filter after that. So the filter must start with the given -start folder. +You can use `**`, `*` and `?` in the file filter pattern. +`**`: matches zero or more characters, including path separators +`*`: matches zero or more characters, excluding path separators +`?`: matches any single character except path separators -### Excluding a file or folder from checking +A common use case for `--file-filter` is to check a project, but only check certain files: -To exclude a file or folder, there are two options. The first option is to only provide the paths and files you want to -check: + cppcheck --project=compile_commands.json --file-filter=src/*.c - cppcheck src/a src/b +Typically a `compile_commands.json` contains absolute paths. However no matter if `compile_commands.json` contains absolute paths or relative paths, the option `--file-filter=src/*.c` would mean that: + * a file with relative path `test1.c` is not checked. + * a file with relative path `src/test2.c` can be checked. + * a file with relative path `src/test3.cpp` is not checked. -All files under src/a and src/b are then checked. +### Excluding a file or folder from checking -The second option is to use -i, which specifies the files/paths to ignore. With this command no files in src/c are -checked: +The option `-i` specifies a pattern to files/folders to exclude. With this command no files in `src/c` are checked: cppcheck -isrc/c src -This option is only valid when supplying an input directory. To ignore multiple directories supply the -i flag for each -directory individually. The following command ignores both the src/b and src/c directories: +The `-i` option is not used during preprocessing, it can't be used to exclude headers that are included. + +You can use `**`, `*` and `?` in the pattern to specify excluded folders/files. +`**`: matches zero or more characters, including path separators +`*`: matches zero or more characters, excluding path separators +`?`: matches any single character except path separators + +A use case for `-i` is to check a project, but exclude certain files/folders: - cppcheck -isrc/b -isrc/c + cppcheck --project=compile_commands.json -itest + +Typically a `compile_commands.json` contains absolute paths. However no matter if `compile_commands.json` contains absolute paths or relative paths, the option `-itest` would mean that: + * a file with relative path `test1.cpp` can be checked. + * a file with relative path `test/somefile.cpp` is not checked ### Clang parser (experimental) @@ -474,19 +486,22 @@ The format for an error suppression is one of: [error id]:[filename2] [error id] -The `error id` is the id that you want to suppress. The 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 `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 `error id` and `filename` patterns may contain `**`, `*` or `?`. +`**`: matches zero or more characters, including path separators +`*`: matches zero or more characters, excluding path separators +`?`: matches any single character except path separators -The filename may include the wildcard characters \* or ?, which matches any sequence of characters or any single character respectively. -It is recommended to use forward-slash `/` as path separator on all operating systems. The filename must match the filename in the reported warning exactly. -For instance, if the warning contains a relative path, then the suppression must match that relative path. +It is recommended to use forward-slash `/` in the filename pattern as path separator on all operating systems. -## Command line suppression +### Command line suppression The `--suppress=` command line option is used to specify suppressions on the command line. Example: cppcheck --suppress=memleak:src/file1.cpp src/ -## Suppressions in a file +### Suppressions in a file You can create a suppressions file for example as follows: @@ -517,6 +532,11 @@ You can specify suppressions in a XML file, for example as follows: +The `id` and `fileName` patterns may contain `**`, `*` or `?`. +`**`: matches zero or more characters, including path separators +`*`: matches zero or more characters, excluding path separators +`?`: matches any single character except path separators + The XML format is extensible and may be extended with further attributes in the future. The usage of the suppressions file is as follows: @@ -1252,6 +1272,21 @@ Command to activate Misra C++ 2023 checkers: cppcheck --premium=misra-c++-2023 .... +### Checking all C and C++ files + +The `cert-c` and `misra-c-*` coding standards target C and therefore the checkers only check C files by default. + +The `autosar`, `cert-c++` and `misra-c++-*` coding standards target C++ and therefore the checkers only check C++ files by default. + +If you want to check all files you can append ":all" to the coding standard. Example: + + # Misra C checkers are executed on C files, not on C++ files + cppcheck --premium=misra-c-2025 path + + # Misra C checkers are executed on C and C++ files + cppcheck --premium=misra-c-2025:all path + + ## Compliance report ### Graphical user interface diff --git a/man/manual.md b/man/manual.md index cdc692552d0..7d45395614a 100644 --- a/man/manual.md +++ b/man/manual.md @@ -1,6 +1,6 @@ --- title: Cppcheck manual -subtitle: Version 2.17.99 +subtitle: Version 2.18.3 author: Cppcheck team lang: en documentclass: report @@ -103,34 +103,46 @@ need to use both approaches. Later chapters will describe this in more detail. ### Check files matching a given file filter -With `--file-filter=` you can set a file filter and only those files matching the filter will be checked. +With `--file-filter=` you can configure file filter(s) and then only those files matching the filter will be checked. -For example: if you want to check only those files and folders starting from a subfolder src/ that start with "test" -you have to type: +For example, this command below means that `src/test1.cpp` and `src/test/file1.cpp` could be checked, but `src/file2.cpp` will not be checked: cppcheck src/ --file-filter=src/test* -Cppcheck first collects all files in src/ and will apply the filter after that. So the filter must start with the given -start folder. +You can use `**`, `*` and `?` in the file filter pattern. +`**`: matches zero or more characters, including path separators +`*`: matches zero or more characters, excluding path separators +`?`: matches any single character except path separators -### Excluding a file or folder from checking +A common use case for `--file-filter` is to check a project, but only check certain files: -To exclude a file or folder, there are two options. The first option is to only provide the paths and files you want to -check: + cppcheck --project=compile_commands.json --file-filter=src/*.c - cppcheck src/a src/b +Typically a `compile_commands.json` contains absolute paths. However no matter if `compile_commands.json` contains absolute paths or relative paths, the option `--file-filter=src/*.c` would mean that: + * a file with relative path `test1.c` is not checked. + * a file with relative path `src/test2.c` can be checked. + * a file with relative path `src/test3.cpp` is not checked. -All files under src/a and src/b are then checked. +### Excluding a file or folder from checking -The second option is to use -i, which specifies the files/paths to ignore. With this command no files in src/c are -checked: +The option `-i` specifies a pattern to files/folders to exclude. With this command no files in `src/c` are checked: cppcheck -isrc/c src -This option is only valid when supplying an input directory. To ignore multiple directories supply the -i flag for each -directory individually. The following command ignores both the src/b and src/c directories: +The `-i` option is not used during preprocessing, it can't be used to exclude headers that are included. + +You can use `**`, `*` and `?` in the pattern to specify excluded folders/files. +`**`: matches zero or more characters, including path separators +`*`: matches zero or more characters, excluding path separators +`?`: matches any single character except path separators + +A use case for `-i` is to check a project, but exclude certain files/folders: - cppcheck -isrc/b -isrc/c + cppcheck --project=compile_commands.json -itest + +Typically a `compile_commands.json` contains absolute paths. However no matter if `compile_commands.json` contains absolute paths or relative paths, the option `-itest` would mean that: + * a file with relative path `test1.cpp` can be checked. + * a file with relative path `test/somefile.cpp` is not checked ### Clang parser (experimental) @@ -475,19 +487,22 @@ The format for an error suppression is one of: [error id]:[filename2] [error id] -The `error id` is the id that you want to suppress. The 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 `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 `error id` and `filename` patterns may contain `**`, `*` or `?`. +`**`: matches zero or more characters, including path separators +`*`: matches zero or more characters, excluding path separators +`?`: matches any single character except path separators -The filename may include the wildcard characters \* or ?, which matches any sequence of characters or any single character respectively. -It is recommended to use forward-slash `/` as path separator on all operating systems. The filename must match the filename in the reported warning exactly. -For instance, if the warning contains a relative path, then the suppression must match that relative path. +It is recommended to use forward-slash `/` in the filename pattern as path separator on all operating systems. -## Command line suppression +### Command line suppression The `--suppress=` command line option is used to specify suppressions on the command line. Example: cppcheck --suppress=memleak:src/file1.cpp src/ -## Suppressions in a file +### Suppressions in a file You can create a suppressions file for example as follows: @@ -518,6 +533,11 @@ You can specify suppressions in a XML file, for example as follows: +The `id` and `fileName` patterns may contain `**`, `*` or `?`. +`**`: matches zero or more characters, including path separators +`*`: matches zero or more characters, excluding path separators +`?`: matches any single character except path separators + The XML format is extensible and may be extended with further attributes in the future. The usage of the suppressions file is as follows: diff --git a/man/reference-cfg-format.md b/man/reference-cfg-format.md index 5ced0b065a4..bf28512bda2 100644 --- a/man/reference-cfg-format.md +++ b/man/reference-cfg-format.md @@ -1,6 +1,6 @@ --- title: Cppcheck .cfg format -subtitle: Version 2.17.99 +subtitle: Version 2.18.3 author: Cppcheck team lang: en documentclass: report diff --git a/man/writing-addons.md b/man/writing-addons.md index ef097840227..ae59f480c6d 100644 --- a/man/writing-addons.md +++ b/man/writing-addons.md @@ -1,6 +1,6 @@ --- title: Writing addons -subtitle: Version 2.17.99 +subtitle: Version 2.18.3 author: Cppcheck team lang: en documentclass: report diff --git a/test/cli/inline-suppress_test.py b/test/cli/inline-suppress_test.py index 9c7421656d2..f4201b7b7a9 100644 --- a/test/cli/inline-suppress_test.py +++ b/test/cli/inline-suppress_test.py @@ -1,10 +1,11 @@ -# python -m pytest test-inline-suppress.py +# python -m pytest inline-suppress_test.py import json import os import pytest import sys +import time from testutils import cppcheck __script_dir = os.path.dirname(os.path.abspath(__file__)) @@ -247,6 +248,35 @@ def test_build_dir(tmpdir): assert stdout == '' assert ret == 0, stdout +def test_build_dir_jobs_suppressions(tmpdir): #14064 + args = [ + '-q', + '--template=simple', + '--cppcheck-build-dir={}'.format(tmpdir), + '--enable=style', + '--inline-suppr', + '-j4', + 'reanalysis' + ] + + ret, stdout, stderr = cppcheck(args, cwd=__script_dir) + lines = stderr.splitlines() + assert lines == [] + assert stdout == '' + assert ret == 0, stdout + + a1Path = os.path.join(tmpdir, 'd.a1') + assert os.path.exists(a1Path) + mtimeOld = os.path.getmtime(a1Path) + + time.sleep(1) + + for _ in range(1, 10): + cppcheck(args, cwd=__script_dir) + + mtimeNew = os.path.getmtime(a1Path) + assert mtimeOld == mtimeNew + def __test_build_dir_unused_template(tmpdir, extra_args): args = [ @@ -470,4 +500,4 @@ def test_unmatched_cfg(): '{}cfg.c:14:0: information: Unmatched suppression: id [unmatchedSuppression]'.format(__proj_inline_suppres_path), ] assert stdout == '' - assert ret == 0, stdout \ No newline at end of file + assert ret == 0, stdout diff --git a/test/cli/reanalysis/a.cpp b/test/cli/reanalysis/a.cpp new file mode 100644 index 00000000000..aad7e3efa61 --- /dev/null +++ b/test/cli/reanalysis/a.cpp @@ -0,0 +1,4 @@ +int main() { + int i; // cppcheck-suppress unusedVariable +} + diff --git a/test/cli/reanalysis/b.cpp b/test/cli/reanalysis/b.cpp new file mode 100644 index 00000000000..cb4df470113 --- /dev/null +++ b/test/cli/reanalysis/b.cpp @@ -0,0 +1,2 @@ +int main() {} + diff --git a/test/cli/reanalysis/c.cpp b/test/cli/reanalysis/c.cpp new file mode 100644 index 00000000000..cb4df470113 --- /dev/null +++ b/test/cli/reanalysis/c.cpp @@ -0,0 +1,2 @@ +int main() {} + diff --git a/test/cli/reanalysis/d.cpp b/test/cli/reanalysis/d.cpp new file mode 100644 index 00000000000..cb4df470113 --- /dev/null +++ b/test/cli/reanalysis/d.cpp @@ -0,0 +1,2 @@ +int main() {} + diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 746b7b7d8fd..fc5e16bd89b 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -236,6 +236,7 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(premiumOptions3); TEST_CASE(premiumOptions4); TEST_CASE(premiumOptions5); + TEST_CASE(premiumOptionsAll); TEST_CASE(premiumOptionsMetrics); TEST_CASE(premiumOptionsCertCIntPrecision); TEST_CASE(premiumOptionsLicenseFile); @@ -1456,6 +1457,23 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS(false, settings->severity.isEnabled(Severity::warning)); } + void premiumOptionsAll() { + REDIRECT; + asPremium(); + const char * const argv[] = { + "cppcheck", + "--premium=autosar:all", + "--premium=cert-c:all", + "--premium=cert-c++:all", + "--premium=misra-c-2023:all", + "--premium=misra-c++-2023:all", + "file.c" + }; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS("--autosar:all --cert-c:all --cert-c++:all --misra-c-2023:all --misra-c++-2023:all", + settings->premiumArgs); + } + void premiumOptionsMetrics() { REDIRECT; asPremium(); diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 6d13655d840..89ed16c3bbd 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -4583,7 +4583,7 @@ class TestCondition : public TestFixture { if (std::numeric_limits::is_signed) { ASSERT_EQUALS("[test.cpp:6:18]: (style) Condition 'o[1]=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); } else { - ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:6]: (style) Condition 'o[1]=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:4:25] -> [test.cpp:6:18]: (style) Condition 'o[1]=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); } check("void f(int x) {\n" // #11449 @@ -5323,7 +5323,7 @@ class TestCondition : public TestFixture { if (std::numeric_limits::is_signed) { ASSERT_EQUALS("[test.cpp:5:22]: (style) Condition 'buffer.back()=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); } else { - ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (style) Condition 'buffer.back()=='\\0'' is always false\n", errout_str()); + ASSERT_EQUALS("[test.cpp:3:22] -> [test.cpp:5:22]: (style) Condition 'buffer.back()=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); } // #9353 diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index 65ad80e802c..a7dd05013c8 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -314,6 +314,8 @@ class TestSimplifyTemplate : public TestFixture { TEST_CASE(explicitBool2); TEST_CASE(templateArgPreserveType); // #13882 - type of template argument + + TEST_CASE(dumpTemplateArgFrom); } struct CheckOptions @@ -333,6 +335,20 @@ class TestSimplifyTemplate : public TestFixture { return tokenizer.tokens()->stringifyList(nullptr, true); } +#define dump(...) dump_(__FILE__, __LINE__, __VA_ARGS__) + template + std::string dump_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { + const Settings settings1 = settingsBuilder(settings).library("std.cfg").debugwarnings(options.debugwarnings).build(); + SimpleTokenizer tokenizer(settings1, *this); + + ASSERT_LOC(tokenizer.tokenize(code), file, line); + + std::ostringstream ostr; + (tokenizer.dump)(ostr); + + return ostr.str(); + } + void template1() { const char code[] = "template T f(T val) { T a; }\n" "f(10);"; @@ -6623,6 +6639,30 @@ class TestSimplifyTemplate : public TestFixture { "class Test<64> { uint32_t i ; i = ( uint32_t ) 64 ; } ;", tok(code)); } + + void dumpTemplateArgFrom() { + const char code[] = "template void foo(T t) {}\n" + "foo(23);"; + const std::string d = dump(code); + ASSERT(!d.empty()); + + // Assert that first 'int' token has templateArg location info + const std::string::size_type strpos1 = d.find(" str=\"int\" "); + ASSERT(strpos1 < d.size()); + const std::string::size_type endpos1 = d.find('>', strpos1); + const std::string::size_type templateArgPos1 = d.find(" templateArgFileIndex=\"0\" templateArgLineNumber=\"2\" templateArgColumn=\"5\""); + ASSERT(templateArgPos1 > strpos1 && templateArgPos1 < endpos1); + + // Assert that second 'int' token has templateArg location info + const std::string::size_type strpos2 = d.find(" str=\"int\" ", endpos1); + ASSERT(strpos2 < d.size()); + const std::string::size_type endpos2 = d.find('>', strpos2); + const std::string::size_type templateArgPos2 = d.find(" templateArgFileIndex=\"0\" templateArgLineNumber=\"2\" templateArgColumn=\"5\"", endpos1); + ASSERT(templateArgPos2 > strpos2 && templateArgPos2 < endpos2); + + // Assert there is no further unexpected templateArg location info + ASSERT(d.find(" templateArg", endpos2) == std::string::npos); + } }; REGISTER_TEST(TestSimplifyTemplate) diff --git a/win_installer/productInfo.wxi b/win_installer/productInfo.wxi index f82ad89f144..62308c0ce5c 100644 --- a/win_installer/productInfo.wxi +++ b/win_installer/productInfo.wxi @@ -1,8 +1,8 @@ - + - +