From 9d716648dc61b613b81076fdcaa4c0165e3cdcc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Fri, 3 May 2024 19:12:47 +0200 Subject: [PATCH 01/14] fixed #12666 - got rid of ill-conceived `USE_MATCHCOMPILER` CMake option validation (#6348) (#6377) I went quite overboard when I introduced the validation of the define. That was not necessary in CMake as we provide feedback on the usage of the matchcompiler. So only handle the special options and otherwise rely on the regular CMake logic. (cherry picked from commit c4be14dde2a1217d07df65c9cdd08a4b5915386e) --- cmake/options.cmake | 24 ++++++++++++++---------- lib/CMakeLists.txt | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/cmake/options.cmake b/cmake/options.cmake index d63d67079af..a18592f588a 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -22,19 +22,23 @@ option(WARNINGS_ARE_ERRORS "Treat warnings as errors" option(EXTERNALS_AS_SYSTEM "Treat externals as system includes" OFF) set(USE_MATCHCOMPILER "Auto" CACHE STRING "Usage of match compiler") -set(_MATCHCOMPILER_STRINGS Auto Off On Verify) -set_property(CACHE USE_MATCHCOMPILER PROPERTY STRINGS ${_MATCHCOMPILER_STRINGS}) -if (NOT ${USE_MATCHCOMPILER} IN_LIST _MATCHCOMPILER_STRINGS) - message(FATAL_ERROR "Invalid USE_MATCHCOMPILER value '${USE_MATCHCOMPILER}'") -endif() -if (USE_MATCHCOMPILER STREQUAL "Auto") - if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") - set(USE_MATCHCOMPILER_OPT "On") +set_property(CACHE USE_MATCHCOMPILER PROPERTY STRINGS Auto Off On Verify) +if(USE_MATCHCOMPILER) + if(USE_MATCHCOMPILER STREQUAL "Auto") + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(STATUS "Non-debug build detected - enabling matchcompiler") + set(USE_MATCHCOMPILER_OPT "On") + else() + message(STATUS "Debug build detected - disabling matchcompiler") + set(USE_MATCHCOMPILER_OPT "Off") + endif() + elseif(USE_MATCHCOMPILER STREQUAL "Verify") + set(USE_MATCHCOMPILER_OPT "Verify") else() - set(USE_MATCHCOMPILER_OPT "Off") + set(USE_MATCHCOMPILER_OPT "On") endif() else() - set(USE_MATCHCOMPILER_OPT ${USE_MATCHCOMPILER}) + set(USE_MATCHCOMPILER_OPT "Off") endif() option(BUILD_CORE_DLL "Build lib as cppcheck-core.dll with Visual Studio" OFF) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 86a3970d8ff..7a884164761 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -10,7 +10,7 @@ function(build_src output filename) get_filename_component(file ${filename} NAME) set(outfile ${CMAKE_CURRENT_BINARY_DIR}/build/mc_${file}) set(${output} ${${output}} ${outfile} PARENT_SCOPE) - if (USE_MATCHCOMPILER STREQUAL "Verify") + if (USE_MATCHCOMPILER_OPT STREQUAL "Verify") set(verify_option "--verify") endif() add_custom_command( From 425b5a30f782f592f03aaef53d174d73cc8a6e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 5 May 2024 22:21:28 +0200 Subject: [PATCH 02/14] Fix #12710 (Checkers report: update premium checkers info) (#6360) --- lib/checkbool.cpp | 2 +- lib/checkclass.cpp | 4 +- lib/checkcondition.cpp | 7 ++- lib/checkers.cpp | 96 ++++++++++++++++++++++++++++++++++++++-- lib/checkio.cpp | 10 +++-- lib/checkmemoryleak.cpp | 7 ++- lib/checknullpointer.cpp | 2 +- lib/checkother.cpp | 15 +++++-- lib/checksizeof.cpp | 2 +- lib/checkunusedvar.cpp | 2 +- lib/settings.cpp | 87 +++++++++++++++++++++++++++++------- tools/get_checkers.py | 5 ++- 12 files changed, 200 insertions(+), 39 deletions(-) diff --git a/lib/checkbool.cpp b/lib/checkbool.cpp index 1cb44e4744e..966cc81265a 100644 --- a/lib/checkbool.cpp +++ b/lib/checkbool.cpp @@ -341,7 +341,7 @@ void CheckBool::assignBoolToPointerError(const Token *tok) //----------------------------------------------------------------------------- void CheckBool::checkComparisonOfBoolExpressionWithInt() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("compareBoolExpressionWithInt")) return; logChecker("CheckBool::checkComparisonOfBoolExpressionWithInt"); // warning diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 01aee5b29e9..647e936c36a 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1714,7 +1714,7 @@ void CheckClass::operatorEqMissingReturnStatementError(const Token *tok, bool er void CheckClass::operatorEqToSelf() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("operatorEqToSelf")) return; logChecker("CheckClass::operatorEqToSelf"); // warning @@ -2953,7 +2953,7 @@ void CheckClass::pureVirtualFunctionCallInConstructorError( void CheckClass::checkDuplInheritedMembers() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("duplInheritedMember")) return; logChecker("CheckClass::checkDuplInheritedMembers"); // warning diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index fa30ae0fcc4..39d8ad516ad 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -613,7 +613,9 @@ static bool isNonConstFunctionCall(const Token *ftok, const Library &library) void CheckCondition::multiCondition2() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings->severity.isEnabled(Severity::warning) && + !mSettings->isPremiumEnabled("identicalConditionAfterEarlyExit") && + !mSettings->isPremiumEnabled("identicalInnerCondition")) return; logChecker("CheckCondition::multiCondition2"); // warning @@ -1482,7 +1484,8 @@ void CheckCondition::alwaysTrueFalse() { if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("alwaysTrue") && - !mSettings->isPremiumEnabled("alwaysFalse")) + !mSettings->isPremiumEnabled("alwaysFalse") && + !mSettings->isPremiumEnabled("knownConditionTrueFalse")) return; logChecker("CheckCondition::alwaysTrueFalse"); // style diff --git a/lib/checkers.cpp b/lib/checkers.cpp index d6f6be3b861..e54943302b7 100644 --- a/lib/checkers.cpp +++ b/lib/checkers.cpp @@ -94,6 +94,7 @@ namespace checkers { {"CheckOther::checkUnreachableCode","style"}, {"CheckOther::checkVariableScope","style,notclang"}, {"CheckOther::checkPassByReference","performance,c++"}, + {"CheckOther::checkConstVariable","style,c++"}, {"CheckOther::checkConstPointer","style"}, {"CheckOther::checkCharVariable","warning,portability"}, {"CheckOther::checkIncompleteStatement","warning"}, @@ -146,6 +147,7 @@ namespace checkers { {"CheckUnusedVar::checkStructMemberUsage","style"}, {"CheckIO::checkCoutCerrMisusage","c"}, {"CheckIO::checkFileUsage",""}, + {"CheckIO::invalidScanf",""}, {"CheckIO::checkWrongPrintfScanfArguments",""}, {"CheckCondition::assignIf","style"}, {"CheckCondition::checkBadBitmaskCheck","style"}, @@ -202,6 +204,7 @@ namespace checkers { {"CheckMemoryLeakInClass::check",""}, {"CheckMemoryLeakStructMember::check",""}, {"CheckMemoryLeakNoVar::check",""}, + {"CheckMemoryLeakNoVar::checkForUnsafeArgAlloc",""}, }; const std::map premiumCheckers{ @@ -230,7 +233,6 @@ namespace checkers { {"Autosar: A2-13-1",""}, {"Autosar: A2-13-3",""}, {"Autosar: A2-13-5",""}, - {"Autosar: A2-13-6",""}, {"Autosar: A2-5-2",""}, {"Autosar: A20-8-2","warning"}, {"Autosar: A20-8-3","warning"}, @@ -404,6 +406,9 @@ namespace checkers { {"Cert C: STR32-C",""}, {"Cert C: STR34-C",""}, {"Cert C: STR38-C",""}, + {"Misra C++ 2008: 3-2-3",""}, + {"Misra C++ 2008: 3-2-4",""}, + {"Misra C++ 2008: 7-5-4",""}, {"Misra C++ 2008: M0-1-11",""}, {"Misra C++ 2008: M0-1-12",""}, {"Misra C++ 2008: M0-1-4",""}, @@ -578,18 +583,28 @@ namespace checkers { {"Misra C++ 2008: M9-6-2",""}, {"Misra C++ 2008: M9-6-3",""}, {"Misra C++ 2008: M9-6-4",""}, + {"Misra C++ 2023: 0.1.2",""}, {"Misra C++ 2023: 0.2.1",""}, + {"Misra C++ 2023: 0.2.2",""}, + {"Misra C++ 2023: 0.2.3",""}, + {"Misra C++ 2023: 0.2.4",""}, {"Misra C++ 2023: 10.0.1",""}, {"Misra C++ 2023: 10.1.2",""}, {"Misra C++ 2023: 10.2.1",""}, {"Misra C++ 2023: 10.2.2",""}, {"Misra C++ 2023: 10.2.3",""}, + {"Misra C++ 2023: 10.3.1",""}, {"Misra C++ 2023: 10.4.1",""}, {"Misra C++ 2023: 11.3.1",""}, + {"Misra C++ 2023: 11.3.2",""}, {"Misra C++ 2023: 11.6.1",""}, {"Misra C++ 2023: 11.6.3",""}, {"Misra C++ 2023: 12.2.1",""}, + {"Misra C++ 2023: 12.2.2",""}, + {"Misra C++ 2023: 12.2.3",""}, + {"Misra C++ 2023: 12.3.1",""}, {"Misra C++ 2023: 13.1.1",""}, + {"Misra C++ 2023: 13.1.2",""}, {"Misra C++ 2023: 13.3.1",""}, {"Misra C++ 2023: 13.3.2",""}, {"Misra C++ 2023: 13.3.3",""}, @@ -597,36 +612,86 @@ namespace checkers { {"Misra C++ 2023: 14.1.1",""}, {"Misra C++ 2023: 15.0.1",""}, {"Misra C++ 2023: 15.0.2",""}, + {"Misra C++ 2023: 15.1.2",""}, {"Misra C++ 2023: 15.1.3",""}, {"Misra C++ 2023: 15.1.5",""}, + {"Misra C++ 2023: 16.5.1",""}, + {"Misra C++ 2023: 16.5.2",""}, + {"Misra C++ 2023: 16.6.1",""}, {"Misra C++ 2023: 17.8.1",""}, + {"Misra C++ 2023: 18.1.1",""}, + {"Misra C++ 2023: 18.1.2",""}, + {"Misra C++ 2023: 18.3.1",""}, + {"Misra C++ 2023: 18.3.2",""}, + {"Misra C++ 2023: 18.3.3",""}, {"Misra C++ 2023: 18.4.1",""}, + {"Misra C++ 2023: 18.5.1",""}, {"Misra C++ 2023: 18.5.2",""}, + {"Misra C++ 2023: 19.0.1",""}, + {"Misra C++ 2023: 19.0.2",""}, + {"Misra C++ 2023: 19.0.3",""}, + {"Misra C++ 2023: 19.0.4",""}, + {"Misra C++ 2023: 19.1.1",""}, + {"Misra C++ 2023: 19.1.2",""}, + {"Misra C++ 2023: 19.1.3",""}, + {"Misra C++ 2023: 19.2.1",""}, + {"Misra C++ 2023: 19.2.2",""}, + {"Misra C++ 2023: 19.2.3",""}, + {"Misra C++ 2023: 19.3.1",""}, {"Misra C++ 2023: 19.3.2",""}, {"Misra C++ 2023: 19.3.3",""}, - {"Misra C++ 2023: 21.20.1",""}, - {"Misra C++ 2023: 21.20.2",""}, + {"Misra C++ 2023: 19.3.4",""}, + {"Misra C++ 2023: 19.6.1",""}, + {"Misra C++ 2023: 21.10.1",""}, + {"Misra C++ 2023: 21.10.2",""}, + {"Misra C++ 2023: 21.10.3",""}, + {"Misra C++ 2023: 21.2.1",""}, + {"Misra C++ 2023: 21.2.2",""}, + {"Misra C++ 2023: 21.2.3",""}, + {"Misra C++ 2023: 21.2.4",""}, + {"Misra C++ 2023: 21.6.1",""}, + {"Misra C++ 2023: 21.6.2",""}, {"Misra C++ 2023: 21.6.3",""}, {"Misra C++ 2023: 21.6.4",""}, {"Misra C++ 2023: 21.6.5",""}, {"Misra C++ 2023: 22.3.1",""}, {"Misra C++ 2023: 22.4.1",""}, + {"Misra C++ 2023: 23.11.1",""}, {"Misra C++ 2023: 24.5.1",""}, {"Misra C++ 2023: 24.5.2",""}, {"Misra C++ 2023: 25.5.1",""}, {"Misra C++ 2023: 25.5.2",""}, {"Misra C++ 2023: 25.5.3",""}, + {"Misra C++ 2023: 26.3.1",""}, + {"Misra C++ 2023: 28.3.1",""}, {"Misra C++ 2023: 28.6.1",""}, {"Misra C++ 2023: 28.6.2",""}, + {"Misra C++ 2023: 30.0.1",""}, {"Misra C++ 2023: 30.0.2",""}, {"Misra C++ 2023: 4.1.1",""}, {"Misra C++ 2023: 4.1.2",""}, + {"Misra C++ 2023: 5.0.1",""}, + {"Misra C++ 2023: 5.13.1",""}, {"Misra C++ 2023: 5.13.2",""}, + {"Misra C++ 2023: 5.13.3",""}, + {"Misra C++ 2023: 5.13.4",""}, {"Misra C++ 2023: 5.13.5",""}, {"Misra C++ 2023: 5.13.6",""}, + {"Misra C++ 2023: 5.13.7",""}, + {"Misra C++ 2023: 5.7.1",""}, + {"Misra C++ 2023: 5.7.2",""}, {"Misra C++ 2023: 5.7.3",""}, + {"Misra C++ 2023: 6.0.1",""}, + {"Misra C++ 2023: 6.0.2",""}, + {"Misra C++ 2023: 6.0.3",""}, + {"Misra C++ 2023: 6.0.4",""}, + {"Misra C++ 2023: 6.2.2",""}, + {"Misra C++ 2023: 6.2.3",""}, + {"Misra C++ 2023: 6.2.4",""}, {"Misra C++ 2023: 6.4.2",""}, {"Misra C++ 2023: 6.4.3",""}, + {"Misra C++ 2023: 6.5.1",""}, + {"Misra C++ 2023: 6.5.2",""}, {"Misra C++ 2023: 6.7.1",""}, {"Misra C++ 2023: 6.7.2",""}, {"Misra C++ 2023: 6.8.3",""}, @@ -636,20 +701,42 @@ namespace checkers { {"Misra C++ 2023: 7.0.1",""}, {"Misra C++ 2023: 7.0.2",""}, {"Misra C++ 2023: 7.0.3",""}, + {"Misra C++ 2023: 7.0.4",""}, {"Misra C++ 2023: 7.0.5",""}, {"Misra C++ 2023: 7.0.6",""}, + {"Misra C++ 2023: 7.11.1",""}, + {"Misra C++ 2023: 7.11.2",""}, + {"Misra C++ 2023: 7.11.3",""}, + {"Misra C++ 2023: 8.0.1",""}, {"Misra C++ 2023: 8.1.1",""}, + {"Misra C++ 2023: 8.1.2",""}, + {"Misra C++ 2023: 8.14.1",""}, + {"Misra C++ 2023: 8.18.2",""}, + {"Misra C++ 2023: 8.19.1",""}, + {"Misra C++ 2023: 8.2.1",""}, + {"Misra C++ 2023: 8.2.10",""}, {"Misra C++ 2023: 8.2.11",""}, {"Misra C++ 2023: 8.2.2",""}, {"Misra C++ 2023: 8.2.3",""}, {"Misra C++ 2023: 8.2.4",""}, + {"Misra C++ 2023: 8.2.5",""}, + {"Misra C++ 2023: 8.2.6",""}, + {"Misra C++ 2023: 8.2.7",""}, {"Misra C++ 2023: 8.2.8",""}, {"Misra C++ 2023: 8.2.9",""}, + {"Misra C++ 2023: 8.20.1",""}, + {"Misra C++ 2023: 8.3.1",""}, {"Misra C++ 2023: 8.3.2",""}, {"Misra C++ 2023: 9.2.1",""}, + {"Misra C++ 2023: 9.3.1",""}, + {"Misra C++ 2023: 9.4.1",""}, + {"Misra C++ 2023: 9.4.2",""}, {"Misra C++ 2023: 9.5.1",""}, {"Misra C++ 2023: 9.5.2",""}, {"Misra C++ 2023: 9.6.1",""}, + {"Misra C++ 2023: 9.6.2",""}, + {"Misra C++ 2023: 9.6.3",""}, + {"Misra C++ 2023: 9.6.4",""}, {"Misra C: 1.4",""}, {"Misra C: 1.5",""}, {"Misra C: 10.1",""}, @@ -675,6 +762,7 @@ namespace checkers { {"Misra C: 17.11",""}, {"Misra C: 17.12",""}, {"Misra C: 17.13",""}, + {"Misra C: 17.2",""}, {"Misra C: 17.3",""}, {"Misra C: 17.4",""}, {"Misra C: 17.9",""}, @@ -720,6 +808,8 @@ namespace checkers { {"Misra C: 8.17",""}, {"Misra C: 8.3",""}, {"Misra C: 8.4",""}, + {"Misra C: 8.6",""}, + {"Misra C: 8.7",""}, {"Misra C: 8.8",""}, {"Misra C: 9.6",""}, {"Misra C: 9.7",""}, diff --git a/lib/checkio.cpp b/lib/checkio.cpp index 6c26967eb6a..71d5bfa9a43 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -411,9 +411,11 @@ void CheckIO::incompatibleFileOpenError(const Token *tok, const std::string &fil //--------------------------------------------------------------------------- void CheckIO::invalidScanf() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("invalidscanf")) return; + logChecker("CheckIO::invalidScanf"); + const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope * scope : symbolDatabase->functionScopes) { for (const Token *tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { @@ -1710,7 +1712,7 @@ void CheckIO::wrongPrintfScanfArgumentsError(const Token* tok, nonneg int numFunction) { const Severity severity = numFormat > numFunction ? Severity::error : Severity::warning; - if (severity != Severity::error && !mSettings->severity.isEnabled(Severity::warning)) + if (severity != Severity::error && !mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("wrongPrintfScanfArgNum")) return; std::ostringstream errmsg; @@ -1729,7 +1731,7 @@ void CheckIO::wrongPrintfScanfArgumentsError(const Token* tok, void CheckIO::wrongPrintfScanfPosixParameterPositionError(const Token* tok, const std::string& functionName, nonneg int index, nonneg int numFunction) { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("wrongPrintfScanfParameterPositionError")) return; std::ostringstream errmsg; errmsg << functionName << ": "; @@ -1992,7 +1994,7 @@ void CheckIO::argumentType(std::ostream& os, const ArgumentInfo * argInfo) void CheckIO::invalidLengthModifierError(const Token* tok, nonneg int numFormat, const std::string& modifier) { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("invalidLengthModifierError")) return; std::ostringstream errmsg; errmsg << "'" << modifier << "' in format string (no. " << numFormat << ") is a length modifier and cannot be used without a conversion specifier."; diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 733e6053bcf..e9f7d4100aa 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -1093,9 +1093,14 @@ void CheckMemoryLeakNoVar::checkForUnusedReturnValue(const Scope *scope) void CheckMemoryLeakNoVar::checkForUnsafeArgAlloc(const Scope *scope) { // This test only applies to C++ source - if (!mTokenizer->isCPP() || !mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning)) + if (!mTokenizer->isCPP()) return; + if (!mSettings->isPremiumEnabled("leakUnsafeArgAlloc") && (!mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning))) + return; + + logChecker("CheckMemoryLeakNoVar::checkForUnsafeArgAlloc"); + for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { if (Token::Match(tok, "%name% (")) { const Token *endParamToken = tok->next()->link(); diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index 9c5d25096b5..f2421df32cd 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -441,7 +441,7 @@ void CheckNullPointer::nullPointerError(const Token *tok, const std::string &var return; } - if (!mSettings->isEnabled(value, inconclusive)) + if (!mSettings->isEnabled(value, inconclusive) && !mSettings->isPremiumEnabled("nullPointer")) return; const ErrorPath errorPath = getErrorPath(tok, value, "Null pointer dereference"); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 76364d83eb3..5d03fb87505 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -424,7 +424,9 @@ void CheckOther::invalidPointerCastError(const Token* tok, const std::string& fr void CheckOther::checkRedundantAssignment() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("redundantAssignment")) + if (!mSettings->severity.isEnabled(Severity::style) && + !mSettings->isPremiumEnabled("redundantAssignment") && + !mSettings->isPremiumEnabled("redundantAssignInSwitch")) return; logChecker("CheckOther::checkRedundantAssignment"); // style @@ -773,7 +775,7 @@ void CheckOther::checkUnreachableCode() // misra-c-2023-2.1 // misra-cpp-2008-0-1-1 // autosar - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unreachableCode")) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateBreak") && !mSettings->isPremiumEnabled("unreachableCode")) return; logChecker("CheckOther::checkUnreachableCode"); // style @@ -1326,9 +1328,11 @@ static bool isVariableMutableInInitializer(const Token* start, const Token * end void CheckOther::checkConstVariable() { - if (!mSettings->severity.isEnabled(Severity::style) || mTokenizer->isC()) + if ((!mSettings->severity.isEnabled(Severity::style) || mTokenizer->isC()) && !mSettings->isPremiumEnabled("constVariable")) return; + logChecker("CheckOther::checkConstVariable"); // style,c++ + const SymbolDatabase *const symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Variable *var : symbolDatabase->variableList()) { @@ -1476,6 +1480,7 @@ void CheckOther::checkConstPointer() { if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("constParameter") && + !mSettings->isPremiumEnabled("constParameterReference") && !mSettings->isPremiumEnabled("constPointer")) return; @@ -3344,7 +3349,9 @@ void CheckOther::unknownEvaluationOrder(const Token* tok) void CheckOther::checkAccessOfMovedVariable() { - if (!mTokenizer->isCPP() || mSettings->standards.cpp < Standards::CPP11 || !mSettings->severity.isEnabled(Severity::warning)) + if (!mTokenizer->isCPP() || mSettings->standards.cpp < Standards::CPP11) + return; + if (!mSettings->isPremiumEnabled("accessMoved") && !mSettings->severity.isEnabled(Severity::warning)) return; logChecker("CheckOther::checkAccessOfMovedVariable"); // c++11,warning const bool reportInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); diff --git a/lib/checksizeof.cpp b/lib/checksizeof.cpp index 50ddd100f8f..ffd9622bdc0 100644 --- a/lib/checksizeof.cpp +++ b/lib/checksizeof.cpp @@ -358,7 +358,7 @@ void CheckSizeof::sizeofCalculationError(const Token *tok, bool inconclusive) void CheckSizeof::sizeofFunction() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("sizeofFunctionCall")) return; logChecker("CheckSizeof::sizeofFunction"); // warning diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 6732c4502cb..52483dcec01 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1445,7 +1445,7 @@ void CheckUnusedVar::unassignedVariableError(const Token *tok, const std::string //--------------------------------------------------------------------------- void CheckUnusedVar::checkStructMemberUsage() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable")) + if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedStructMember") && !mSettings->isPremiumEnabled("unusedVariable")) return; logChecker("CheckUnusedVar::checkStructMemberUsage"); // style diff --git a/lib/settings.cpp b/lib/settings.cpp index e1780aa0d40..805556670d3 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -313,10 +313,11 @@ static const std::set autosarCheckers{ "comparePointers", "constParameter", "cstyleCast", - "ctuOneDefinitionViolation", + "ctuOneDefinitionRuleViolation", "doubleFree", "duplInheritedMember", "duplicateBreak", + "exceptThrowInDestructor", "funcArgNamesDifferent", "functionConst", "functionStatic", @@ -340,9 +341,11 @@ static const std::set autosarCheckers{ "redundantAssignment", "redundantInitialization", "returnDanglingLifetime", + "shadowArgument", + "shadowFunction", + "shadowVariable", "shiftTooManyBits", - "sizeofSideEffects", - "throwInDestructor", + "sizeofFunctionCall", "throwInNoexceptFunction", "uninitData", "uninitMember", @@ -353,7 +356,7 @@ static const std::set autosarCheckers{ "unusedStructMember", "unusedValue", "unusedVariable", - "useInitializerList", + "useInitializationList", "variableScope", "virtualCallInConstructor", "zerodiv", @@ -405,8 +408,11 @@ static const std::set certCppCheckers{ "accessMoved", "comparePointers", "containerOutOfBounds", - "ctuOneDefinitionViolation", - "deallocMismatch", + "ctuOneDefinitionRuleViolation", + "danglingLifetime", + "danglingReference", + "danglingTempReference", + "danglingTemporaryLifetime", "deallocThrow", "deallocuse", "doubleFree", @@ -414,11 +420,12 @@ static const std::set certCppCheckers{ "exceptThrowInDestructor", "initializerList", "invalidContainer", - "lifetime", "memleak", + "mismatchAllocDealloc", "missingReturn", "nullPointer", "operatorEqToSelf", + "returnDanglingLifetime", "sizeofCalculation", "uninitvar", "virtualCallInConstructor", @@ -433,10 +440,10 @@ static const std::set misrac2012Checkers{ "bufferAccessOutOfBounds", "comparePointers", "compareValueOutOfTypeRangeError", - "constPointer", + "constParameterPointer", "danglingLifetime", + "danglingTemporaryLifetime", "duplicateBreak", - "error", "funcArgNamesDifferent", "incompatibleFileOpen", "invalidFunctionArg", @@ -454,11 +461,14 @@ static const std::set misrac2012Checkers{ "redundantAssignment", "redundantCondition", "resourceLeak", + "returnDanglingLifetime", "shadowVariable", "sizeofCalculation", + "sizeofwithsilentarraypointer", "syntaxError", "uninitvar", "unknownEvaluationOrder", + "unreachableCode", "unreadVariable", "unusedLabel", "unusedVariable", @@ -474,10 +484,10 @@ static const std::set misrac2023Checkers{ "bufferAccessOutOfBounds", "comparePointers", "compareValueOutOfTypeRangeError", - "constPointer", + "constParameterPointer", "danglingLifetime", + "danglingTemporaryLifetime", "duplicateBreak", - "error", "funcArgNamesDifferent", "incompatibleFileOpen", "invalidFunctionArg", @@ -495,11 +505,14 @@ static const std::set misrac2023Checkers{ "redundantAssignment", "redundantCondition", "resourceLeak", + "returnDanglingLifetime", "shadowVariable", "sizeofCalculation", + "sizeofwithsilentarraypointer", "syntaxError", "uninitvar", "unknownEvaluationOrder", + "unreachableCode", "unreadVariable", "unusedLabel", "unusedVariable", @@ -513,7 +526,7 @@ static const std::set misracpp2008Checkers{ "constParameter", "constVariable", "cstyleCast", - "ctuOneDefinitionViolation", + "ctuOneDefinitionRuleViolation", "danglingLifetime", "duplInheritedMember", "duplicateBreak", @@ -522,7 +535,7 @@ static const std::set misracpp2008Checkers{ "functionConst", "functionStatic", "missingReturn", - "noExplicit", + "noExplicitConstructor", "overlappingWriteFunction", "overlappingWriteUnion", "pointerOutOfBounds", @@ -533,8 +546,7 @@ static const std::set misracpp2008Checkers{ "returnTempReference", "shadowVariable", "shiftTooManyBits", - "sizeofSideEffects", - "throwInDestructor", + "sizeofFunctionCall", "uninitDerivedMemberVar", "uninitDerivedMemberVarPrivate", "uninitMemberVar", @@ -549,11 +561,50 @@ static const std::set misracpp2008Checkers{ "unusedFunction", "unusedStructMember", "unusedVariable", - "varScope", "variableScope", "virtualCallInConstructor" }; +static const std::set misracpp2023Checkers{ + "accessForwarded", + "accessMoved", + "autoVariables", + "compareBoolExpressionWithInt", + "comparePointers", + "compareValueOutOfTypeRangeError", + "constParameter", + "constParameterReference", + "ctuOneDefinitionRuleViolation", + "danglingLifetime", + "identicalConditionAfterEarlyExit", + "identicalInnerCondition", + "ignoredReturnValue", + "invalidFunctionArg", + "invalidFunctionArgBool", + "invalidFunctionArgStr", + "knownConditionTrueFalse", + "missingReturn", + "noExplicitConstructor", + "operatorEqToSelf", + "overlappingWriteUnion", + "pointerOutOfBounds", + "pointerOutOfBoundsCond", + "preprocessorErrorDirective", + "redundantAssignInSwitch", + "redundantAssignment", + "redundantCopy", + "redundantInitialization", + "shadowVariable", + "subtractPointers", + "syntaxError", + "uninitMemberVar", + "uninitvar", + "unknownEvaluationOrder", + "unreachableCode", + "unreadVariable", + "virtualCallInConstructor" +}; + bool Settings::isPremiumEnabled(const char id[]) const { if (premiumArgs.find("autosar") != std::string::npos && autosarCheckers.count(id)) @@ -564,7 +615,9 @@ bool Settings::isPremiumEnabled(const char id[]) const return true; if (premiumArgs.find("misra-c-") != std::string::npos && (misrac2012Checkers.count(id) || misrac2023Checkers.count(id))) return true; - if (premiumArgs.find("misra-c++") != std::string::npos && misracpp2008Checkers.count(id)) + if (premiumArgs.find("misra-c++-2008") != std::string::npos && misracpp2008Checkers.count(id)) + return true; + if (premiumArgs.find("misra-c++-2023") != std::string::npos && misracpp2023Checkers.count(id)) return true; return false; } diff --git a/tools/get_checkers.py b/tools/get_checkers.py index ca0b8427689..4b7c7b3ea64 100644 --- a/tools/get_checkers.py +++ b/tools/get_checkers.py @@ -1,10 +1,11 @@ +import datetime import glob import os import re print("""/* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2023 Cppcheck team. + * Copyright (C) 2007-%i Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,7 +27,7 @@ #include "checkers.h" namespace checkers { - const std::map allCheckers{""") + const std::map allCheckers{""" % (datetime.date.today().year,)) for filename in glob.glob(os.path.expanduser('~/cppchecksolutions/cppcheck/lib/*.cpp')): for line in open(filename,'rt'): From 014fb25a569e7b30d17aa0a2c17f2c5666b42547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Wed, 15 May 2024 10:21:09 +0200 Subject: [PATCH 03/14] Deactivate failing scriptcheck using Python 3.5 (#6396) (#6405) (cherry picked from commit 1943b4dd7e64ae9c30501c82c2d0d6d42d5e4d52) Co-authored-by: chrchr-github <78114321+chrchr-github@users.noreply.github.com> --- .github/workflows/scriptcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scriptcheck.yml b/.github/workflows/scriptcheck.yml index 5f702f2fb22..5d428211265 100644 --- a/.github/workflows/scriptcheck.yml +++ b/.github/workflows/scriptcheck.yml @@ -48,7 +48,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - python-version: [3.5, 3.6, 3.7, 3.8, 3.9, '3.10', '3.11', '3.12'] + python-version: [3.6, 3.7, 3.8, 3.9, '3.10', '3.11', '3.12'] include: - python-version: '3.12' python-latest: true From 63f3ab707a186af437c3ae2e4475ca8083875d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 16 May 2024 21:42:14 +0200 Subject: [PATCH 04/14] Fix #12741 (Add Misra C++ 2023 option in --help output) (#6411) --- cli/cmdlineparser.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index c1232a95cb2..ab20f5848b0 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -1638,6 +1638,7 @@ void CmdLineParser::printHelp() const " * misra-c-2012 Misra C 2012\n" " * misra-c-2023 Misra C 2023\n" " * misra-c++-2008 Misra C++ 2008\n" + " * misra-c++-2023 Misra C++ 2023\n" " Other:\n" " * bughunting Soundy analysis\n" " * cert-c-int-precision=BITS Integer precision to use in Cert C analysis.\n" From 4108369bca623b6131305c241bb8ad1a664dba90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Tue, 21 May 2024 21:04:15 +0200 Subject: [PATCH 05/14] fixed #12715 - made Visual Studio conditions work again (#6404) --- lib/importproject.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 47c55e09a44..e67ac4c118b 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -567,6 +568,22 @@ namespace { TokenList tokenlist(&s); std::istringstream istr(c); tokenlist.createTokens(istr, Standards::Language::C); // TODO: check result + // TODO: put in a helper + // generate links + { + std::stack lpar; + for (Token* tok2 = tokenlist.front(); tok2; tok2 = tok2->next()) { + if (tok2->str() == "(") + lpar.push(tok2); + else if (tok2->str() == ")") { + if (lpar.empty()) + break; + Token::createMutualLinks(lpar.top(), tok2); + lpar.pop(); + } + } + } + tokenlist.createAst(); for (const Token *tok = tokenlist.front(); tok; tok = tok->next()) { if (tok->str() == "(" && tok->astOperand1() && tok->astOperand2()) { // TODO: this is wrong - it is Contains() not Equals() From 5bb02e04a16b3188e68f33f4e49a64dee3893d82 Mon Sep 17 00:00:00 2001 From: olabetskyi <153490942+olabetskyi@users.noreply.github.com> Date: Wed, 22 May 2024 12:06:11 +0300 Subject: [PATCH 06/14] Fix #12746: Add Misra C++ Version dropBox for gui (#6413) --- gui/projectfile.ui | 41 ++++++++++++++++++++++++++++++++++----- gui/projectfiledialog.cpp | 14 ++++++++++--- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/gui/projectfile.ui b/gui/projectfile.ui index 9c1cd7096a4..7bc0ef3a9ae 100644 --- a/gui/projectfile.ui +++ b/gui/projectfile.ui @@ -869,11 +869,42 @@ - - - Misra C++ 2008 - - + + + + + Misra C++ + + + + + + + + 2008 + + + + + 2023 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + diff --git a/gui/projectfiledialog.cpp b/gui/projectfiledialog.cpp index 1d89c899505..2bb43eb72a4 100644 --- a/gui/projectfiledialog.cpp +++ b/gui/projectfiledialog.cpp @@ -60,6 +60,7 @@ static constexpr char ADDON_MISRA[] = "misra"; static constexpr char CODING_STANDARD_MISRA_C_2023[] = "misra-c-2023"; static constexpr char CODING_STANDARD_MISRA_CPP_2008[] = "misra-cpp-2008"; +static constexpr char CODING_STANDARD_MISRA_CPP_2023[] = "misra-cpp-2023"; static constexpr char CODING_STANDARD_CERT_C[] = "cert-c-2016"; static constexpr char CODING_STANDARD_CERT_CPP[] = "cert-cpp-2016"; static constexpr char CODING_STANDARD_AUTOSAR[] = "autosar"; @@ -391,9 +392,15 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile) mUI->mBtnBrowseMisraFile->setEnabled(false); } + mUI->mMisraCpp->setEnabled(mPremium); + mUI->mMisraCppVersion->setEnabled(mUI->mMisraCpp->isChecked()); + connect(mUI->mMisraCpp, &QCheckBox::toggled, mUI->mMisraCppVersion, &QComboBox::setEnabled); + + mUI->mMisraCppVersion->setVisible(mPremium); + mUI->mMisraCppVersion->setCurrentIndex(projectFile->getCodingStandards().contains(CODING_STANDARD_MISRA_CPP_2023)); + mUI->mCertC2016->setChecked(mPremium && projectFile->getCodingStandards().contains(CODING_STANDARD_CERT_C)); mUI->mCertCpp2016->setChecked(mPremium && projectFile->getCodingStandards().contains(CODING_STANDARD_CERT_CPP)); - mUI->mMisraCpp2008->setChecked(mPremium && projectFile->getCodingStandards().contains(CODING_STANDARD_MISRA_CPP_2008)); mUI->mAutosar->setChecked(mPremium && projectFile->getCodingStandards().contains(CODING_STANDARD_AUTOSAR)); if (projectFile->getCertIntPrecision() <= 0) @@ -401,7 +408,6 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile) else mUI->mEditCertIntPrecision->setText(QString::number(projectFile->getCertIntPrecision())); - mUI->mMisraCpp2008->setEnabled(mPremium); mUI->mCertC2016->setEnabled(mPremium); mUI->mCertCpp2016->setEnabled(mPremium); mUI->mAutosar->setEnabled(mPremium); @@ -482,8 +488,10 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const codingStandards << CODING_STANDARD_CERT_CPP; if (mPremium && mUI->mMisraVersion->currentIndex() == 1) codingStandards << CODING_STANDARD_MISRA_C_2023; - if (mUI->mMisraCpp2008->isChecked()) + if (mUI->mMisraCpp->isChecked() && mUI->mMisraCppVersion->currentIndex() == 0) codingStandards << CODING_STANDARD_MISRA_CPP_2008; + if (mUI->mMisraCpp->isChecked() && mUI->mMisraCppVersion->currentIndex() == 1) + codingStandards << CODING_STANDARD_MISRA_CPP_2023; if (mUI->mAutosar->isChecked()) codingStandards << CODING_STANDARD_AUTOSAR; projectFile->setCodingStandards(std::move(codingStandards)); From c980604d11a00850981883b7e4e10e0e14fbd82e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 22 May 2024 13:25:21 +0200 Subject: [PATCH 07/14] Fix #12747 (GUI: when compliance report is generated the checkers-report should be provided.) (#6419) --- gui/compliancereportdialog.cpp | 17 +++++++++++++---- gui/compliancereportdialog.h | 5 +++-- gui/mainwindow.cpp | 3 ++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/gui/compliancereportdialog.cpp b/gui/compliancereportdialog.cpp index ff3812f352f..bcdf0699fb4 100644 --- a/gui/compliancereportdialog.cpp +++ b/gui/compliancereportdialog.cpp @@ -86,11 +86,12 @@ static std::vector toStdStringList(const QStringList& from) { return ret; } -ComplianceReportDialog::ComplianceReportDialog(ProjectFile* projectFile, QString resultsFile) : - QDialog(nullptr), +ComplianceReportDialog::ComplianceReportDialog(ProjectFile* projectFile, QString resultsFile, QString checkersReport) + : QDialog(nullptr), mUI(new Ui::ComplianceReportDialog), mProjectFile(projectFile), - mResultsFile(std::move(resultsFile)) + mResultsFile(std::move(resultsFile)), + mCheckersReport(std::move(checkersReport)) { mUI->setupUi(this); mUI->mEditProjectName->setText(projectFile->getProjectName()); @@ -146,6 +147,13 @@ void ComplianceReportDialog::save() mProjectFile->write(); } + QTemporaryFile tempCheckersReport; + if (tempCheckersReport.open()) { + QTextStream out(&tempCheckersReport); + out << mCheckersReport << "\n"; + tempCheckersReport.close(); + } + QTemporaryFile tempFiles; if (files && tempFiles.open()) { QTextStream out(&tempFiles); @@ -205,7 +213,8 @@ void ComplianceReportDialog::save() QStringList args{"--project-name=" + projectName, "--project-version=" + projectVersion, - "--output-file=" + outFile}; + "--output-file=" + outFile, + "--checkers-report=" + tempCheckersReport.fileName()}; if (!suppressions.isEmpty()) args << "--suppressions=" + suppressions.join(","); diff --git a/gui/compliancereportdialog.h b/gui/compliancereportdialog.h index ad3b79c5c45..af4146cef9f 100644 --- a/gui/compliancereportdialog.h +++ b/gui/compliancereportdialog.h @@ -35,7 +35,7 @@ class ComplianceReportDialog final : public QDialog Q_OBJECT public: - explicit ComplianceReportDialog(ProjectFile* projectFile, QString resultsFile); + explicit ComplianceReportDialog(ProjectFile* projectFile, QString resultsFile, QString checkersReport); ~ComplianceReportDialog() final; private slots: @@ -46,7 +46,8 @@ private slots: Ui::ComplianceReportDialog *mUI; ProjectFile* mProjectFile; - QString mResultsFile; + const QString mResultsFile; + const QString mCheckersReport; }; #endif // COMPLIANCEREPORTDIALOG_H diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index b5f8713ff0a..22386db4df9 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -22,6 +22,7 @@ #include "applicationlist.h" #include "aboutdialog.h" #include "analyzerinfo.h" +#include "checkstatistics.h" #include "checkthread.h" #include "common.h" #include "cppcheck.h" @@ -1593,7 +1594,7 @@ void MainWindow::complianceReport() mUI->mResults->save(tempResults.fileName(), Report::XMLV2, mCppcheckCfgProductName); - ComplianceReportDialog dlg(mProjectFile, tempResults.fileName()); + ComplianceReportDialog dlg(mProjectFile, tempResults.fileName(), mUI->mResults->getStatistics()->getCheckersReport()); dlg.exec(); } From 058fe171478140f45b72cb5ba0d3b7f40c257bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Thu, 23 May 2024 22:09:50 +0200 Subject: [PATCH 08/14] bumped simplecpp to 1.1.3 (#6435) --- externals/simplecpp/simplecpp.cpp | 39 ++++++++++++++++++++----------- externals/simplecpp/simplecpp.h | 7 +++++- 2 files changed, 31 insertions(+), 15 deletions(-) mode change 100644 => 100755 externals/simplecpp/simplecpp.cpp mode change 100644 => 100755 externals/simplecpp/simplecpp.h diff --git a/externals/simplecpp/simplecpp.cpp b/externals/simplecpp/simplecpp.cpp old mode 100644 new mode 100755 index d3bd1c0c9a2..812600bfbd0 --- a/externals/simplecpp/simplecpp.cpp +++ b/externals/simplecpp/simplecpp.cpp @@ -20,13 +20,13 @@ #include #include #include -#include +#include // IWYU pragma: keep #include #include #include #include #include -#include +#include // IWYU pragma: keep #include #include #include @@ -1984,7 +1984,7 @@ namespace simplecpp { if (paren == 0) return tok->next->next; tok = tok->next; - if (parametertokens.front()->next->str() != ")" && parametertokens.size() > args.size()) + if (parametertokens.size() > args.size() && parametertokens.front()->next->str() != ")") tok = expandToken(output, loc, tok, macros, expandedmacros, parametertokens)->previous; } } @@ -3085,9 +3085,11 @@ static std::string getFileName(const std::map::const_iterator it = dui.includePaths.begin(); it != dui.includePaths.end(); ++it) { std::string s = simplecpp::simplifyPath(getIncludePathFileName(*it, header)); @@ -3143,6 +3145,8 @@ std::map simplecpp::load(const simplecpp::To continue; } + if (dui.removeComments) + tokenlist->removeComments(); ret[filename] = tokenlist; filelist.push_back(tokenlist->front()); } @@ -3178,6 +3182,8 @@ std::map simplecpp::load(const simplecpp::To f.close(); TokenList *tokens = new TokenList(header2, filenames, outputList); + if (dui.removeComments) + tokens->removeComments(); ret[header2] = tokens; if (tokens->front()) filelist.push_back(tokens->front()); @@ -3268,6 +3274,9 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL sizeOfType.insert(std::make_pair("double *", sizeof(double *))); sizeOfType.insert(std::make_pair("long double *", sizeof(long double *))); + // use a dummy vector for the macros because as this is not part of the file and would add an empty entry - e.g. /usr/include/poll.h + std::vector dummy; + const bool hasInclude = (dui.std.size() == 5 && dui.std.compare(0,3,"c++") == 0 && dui.std >= "c++17"); MacroMap macros; for (std::list::const_iterator it = dui.defines.begin(); it != dui.defines.end(); ++it) { @@ -3279,26 +3288,26 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL continue; const std::string lhs(macrostr.substr(0,eq)); const std::string rhs(eq==std::string::npos ? std::string("1") : macrostr.substr(eq+1)); - const Macro macro(lhs, rhs, files); + const Macro macro(lhs, rhs, dummy); macros.insert(std::pair(macro.name(), macro)); } - macros.insert(std::make_pair("__FILE__", Macro("__FILE__", "__FILE__", files))); - macros.insert(std::make_pair("__LINE__", Macro("__LINE__", "__LINE__", files))); - macros.insert(std::make_pair("__COUNTER__", Macro("__COUNTER__", "__COUNTER__", files))); + macros.insert(std::make_pair("__FILE__", Macro("__FILE__", "__FILE__", dummy))); + macros.insert(std::make_pair("__LINE__", Macro("__LINE__", "__LINE__", dummy))); + macros.insert(std::make_pair("__COUNTER__", Macro("__COUNTER__", "__COUNTER__", dummy))); struct tm ltime = {}; getLocaltime(ltime); - macros.insert(std::make_pair("__DATE__", Macro("__DATE__", getDateDefine(<ime), files))); - macros.insert(std::make_pair("__TIME__", Macro("__TIME__", getTimeDefine(<ime), files))); + macros.insert(std::make_pair("__DATE__", Macro("__DATE__", getDateDefine(<ime), dummy))); + macros.insert(std::make_pair("__TIME__", Macro("__TIME__", getTimeDefine(<ime), dummy))); if (!dui.std.empty()) { std::string std_def = simplecpp::getCStdString(dui.std); if (!std_def.empty()) { - macros.insert(std::make_pair("__STDC_VERSION__", Macro("__STDC_VERSION__", std_def, files))); + macros.insert(std::make_pair("__STDC_VERSION__", Macro("__STDC_VERSION__", std_def, dummy))); } else { std_def = simplecpp::getCppStdString(dui.std); if (!std_def.empty()) - macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", std_def, files))); + macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", std_def, dummy))); } } @@ -3446,6 +3455,8 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL header2 = openHeader(f, dui, rawtok->location.file(), header, systemheader); if (f.is_open()) { TokenList * const tokens = new TokenList(f, files, header2, outputList); + if (dui.removeComments) + tokens->removeComments(); filedata[header2] = tokens; } } diff --git a/externals/simplecpp/simplecpp.h b/externals/simplecpp/simplecpp.h old mode 100644 new mode 100755 index 7ef0740c318..c72e4c655cf --- a/externals/simplecpp/simplecpp.h +++ b/externals/simplecpp/simplecpp.h @@ -272,6 +272,10 @@ namespace simplecpp { /** sizeof(T) */ std::map sizeOfType; + const std::vector& getFiles() const { + return files; + } + private: void combineOperators(); @@ -320,13 +324,14 @@ namespace simplecpp { * On the command line these are configured by -D, -U, -I, --include, -std */ struct SIMPLECPP_LIB DUI { - DUI() : clearIncludeCache(false) {} + DUI() : clearIncludeCache(false), removeComments(false) {} std::list defines; std::set undefined; std::list includePaths; std::list includes; std::string std; bool clearIncludeCache; + bool removeComments; /** remove comment tokens from included files */ }; SIMPLECPP_LIB long long characterLiteralToLL(const std::string& str); From d814c067344023aaf72afb80da5d62f0f22b5316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 25 May 2024 14:24:00 +0200 Subject: [PATCH 09/14] Fix #12772 (GUI: information messages are shown even though information tool button is deselected) (#6440) --- .github/workflows/CI-unixish.yml | 6 ++ gui/resultstree.cpp | 11 ++- gui/test/CMakeLists.txt | 2 + gui/test/resultstree/CMakeLists.txt | 24 +++++ gui/test/resultstree/resultstree.pro | 28 ++++++ gui/test/resultstree/testresultstree.cpp | 108 +++++++++++++++++++++++ gui/test/resultstree/testresultstree.h | 26 ++++++ 7 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 gui/test/resultstree/CMakeLists.txt create mode 100644 gui/test/resultstree/resultstree.pro create mode 100644 gui/test/resultstree/testresultstree.cpp create mode 100644 gui/test/resultstree/testresultstree.h diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 2f7dd0de492..e9e6e09181d 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -303,6 +303,12 @@ jobs: make -j$(nproc) ./test-projectfile popd + pushd gui/test/resultstree + qmake CONFIG+=debug CONFIG+=ccache + make -j$(nproc) + export QT_QPA_PLATFORM=offscreen + ./test-resultstree + popd pushd gui/test/translationhandler qmake CONFIG+=debug CONFIG+=ccache make -j$(nproc) diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index 2ee74f67e44..cc80f1099f2 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -250,9 +250,16 @@ bool ResultsTree::addErrorItem(const ErrorItem &item) } // Partially refresh the tree: Unhide file item if necessary - if (!hide) { - setRowHidden(fileItem->row(), QModelIndex(), !mShowSeverities.isShown(item.severity)); + setRowHidden(stditem->row(), fileItem->index(), hide || !mShowSeverities.isShown(item.severity)); + + bool hideFile = true; + for (int i = 0; i < fileItem->rowCount(); ++i) { + if (!isRowHidden(i, fileItem->index())) { + hideFile = false; + } } + setRowHidden(fileItem->row(), QModelIndex(), hideFile); + return true; } diff --git a/gui/test/CMakeLists.txt b/gui/test/CMakeLists.txt index ea868eb97e6..d086e890cb1 100644 --- a/gui/test/CMakeLists.txt +++ b/gui/test/CMakeLists.txt @@ -1,6 +1,8 @@ add_subdirectory(cppchecklibrarydata) add_subdirectory(filelist) add_subdirectory(projectfile) +# FIXME does not work in CI +#add_subdirectory(resultstree) add_subdirectory(translationhandler) add_subdirectory(xmlreportv2) # TODO: add all tests to CTest \ No newline at end of file diff --git a/gui/test/resultstree/CMakeLists.txt b/gui/test/resultstree/CMakeLists.txt new file mode 100644 index 00000000000..9c98e8dcf35 --- /dev/null +++ b/gui/test/resultstree/CMakeLists.txt @@ -0,0 +1,24 @@ +qt_wrap_cpp(test-resultstree_SRC testresultstree.h ${CMAKE_SOURCE_DIR}/gui/resultstree.h) +add_custom_target(build-resultstree-deps SOURCES ${test-resultstree_SRC}) +add_dependencies(gui-build-deps build-resultstree-deps) +add_executable(test-resultstree + ${test-resultstree_SRC} + testresultstree.cpp + ${CMAKE_SOURCE_DIR}/gui/resultstree.cpp + ${CMAKE_SOURCE_DIR}/gui/erroritem.cpp + ${CMAKE_SOURCE_DIR}/gui/showtypes.cpp + ${CMAKE_SOURCE_DIR}/gui/report.cpp + ${CMAKE_SOURCE_DIR}/gui/xmlreportv2.cpp + ) +target_include_directories(test-resultstree PRIVATE ${CMAKE_SOURCE_DIR}/gui ${CMAKE_SOURCE_DIR}/lib) +target_compile_definitions(test-resultstree PRIVATE SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}") +target_link_libraries(test-resultstree ${QT_CORE_LIB} ${QT_GUI_LIB} ${QT_WIDGETS_LIB} ${QT_TEST_LIB}) + +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # Q_UNUSED() in generated code + target_compile_options_safe(test-resultstree -Wno-extra-semi-stmt) +endif() + +if (REGISTER_GUI_TESTS) + add_test(NAME test-resultstree COMMAND $) +endif() diff --git a/gui/test/resultstree/resultstree.pro b/gui/test/resultstree/resultstree.pro new file mode 100644 index 00000000000..d4677d13eea --- /dev/null +++ b/gui/test/resultstree/resultstree.pro @@ -0,0 +1,28 @@ +TEMPLATE = app +TARGET = test-resultstree +DEPENDPATH += . +INCLUDEPATH += . ../../../lib +OBJECTS_DIR = ../../temp +MOC_DIR = ../../temp + +QT += widgets core +QT += testlib + +include(../common.pri) + +DEFINES += SRCDIR=\\\"$$PWD\\\" + +# tests +SOURCES += testresultstree.cpp \ + ../../resultstree.cpp \ + ../../erroritem.cpp \ + ../../showtypes.cpp \ + ../../report.cpp \ + ../../xmlreportv2.cpp + +HEADERS += testresultstree.h \ + ../../resultstree.h \ + ../../erroritem.h \ + ../../showtypes.h \ + ../../report.h \ + ../../xmlreportv2.h diff --git a/gui/test/resultstree/testresultstree.cpp b/gui/test/resultstree/testresultstree.cpp new file mode 100644 index 00000000000..b8fbb44b36f --- /dev/null +++ b/gui/test/resultstree/testresultstree.cpp @@ -0,0 +1,108 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2021 Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "testresultstree.h" +#include "resultstree.h" + +// headers that declare mocked functions/variables +#include "applicationlist.h" +#include "common.h" +#include "threadhandler.h" +#include "projectfile.h" +#include "xmlreportv2.h" + +#include "cppcheck.h" +#include "errorlogger.h" +#include "path.h" +#include "settings.h" + +#include + +// Mock GUI... +ProjectFile *ProjectFile::mActiveProject; +void ProjectFile::addSuppression(const SuppressionList::Suppression & /*unused*/) {} +QString ProjectFile::getWarningTags(std::size_t /*unused*/) const { + return QString(); +} +void ProjectFile::setWarningTags(std::size_t /*unused*/, const QString& /*unused*/) {} +bool ProjectFile::write(const QString & /*unused*/) { + return true; +} +std::string severityToString(Severity severity) { + return std::to_string((int)severity); +} +int ApplicationList::getApplicationCount() const { + return 0; +} +bool ThreadHandler::isChecking() const { + return false; +} +Application& ApplicationList::getApplication(const int /*unused*/) { + throw 1; +} +const Application& ApplicationList::getApplication(const int index) const { + return mApplications.at(index); +} +QString getPath(const QString &type) { + return "/" + type; +} +void setPath(const QString & /*unused*/, const QString & /*unused*/) {} +QString XmlReport::quoteMessage(const QString &message) { + return message; +} +QString XmlReport::unquoteMessage(const QString &message) { + return message; +} +XmlReport::XmlReport(const QString& filename) : Report(filename) {} + +// Mock LIB... +bool Path::isHeader(std::string const& /*unused*/) { + return false; +} +const std::set ErrorLogger::mCriticalErrorIds; +std::string ErrorMessage::FileLocation::getfile(bool /*unused*/) const { + return std::string(); +} +const char* CppCheck::version() { + return "1.0"; +} +std::pair Settings::getNameAndVersion(const std::string& /*unused*/) { + throw 1; +} +Severity severityFromString(const std::string& severity) { + return (Severity)std::stoi(severity); +} + +// Test... + +void TestResultsTree::test1() const +{ + // #12772 : GUI: information messages are shown even though information tool button is deselected + ResultsTree tree(nullptr); + tree.showResults(ShowTypes::ShowType::ShowInformation, false); + ErrorItem errorItem; + errorItem.errorPath << QErrorPathItem(); + errorItem.severity = Severity::information; + tree.addErrorItem(errorItem); + QCOMPARE(tree.isRowHidden(0,QModelIndex()), true); // Added item is hidden + tree.showResults(ShowTypes::ShowType::ShowInformation, true); + QCOMPARE(tree.isRowHidden(0,QModelIndex()), false); // Show item +} + +QTEST_MAIN(TestResultsTree) + diff --git a/gui/test/resultstree/testresultstree.h b/gui/test/resultstree/testresultstree.h new file mode 100644 index 00000000000..acea181ee5b --- /dev/null +++ b/gui/test/resultstree/testresultstree.h @@ -0,0 +1,26 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2021 Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +class TestResultsTree : public QObject { + Q_OBJECT + +private slots: + void test1() const; +}; From c2028297460b1e3307978422b88572a7c6f6d629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Sun, 26 May 2024 09:16:27 +0200 Subject: [PATCH 10/14] TokenList: avoid `Path::identify()` being called with empty filename from `determineCppC()` (#6326) (#6429) (cherry picked from commit ca945276f4bf11f0869376f8f1ae553f9cdc52f9) --- Makefile | 2 +- lib/tokenlist.cpp | 7 ++++--- test/testtokenlist.cpp | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index c97ea02ffdb..0d3f88f0cbb 100644 --- a/Makefile +++ b/Makefile @@ -858,7 +858,7 @@ test/testtoken.o: test/testtoken.cpp lib/addoninfo.h lib/check.h lib/color.h lib test/testtokenize.o: test/testtokenize.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.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 test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtokenize.cpp -test/testtokenlist.o: test/testtokenlist.cpp lib/addoninfo.h lib/check.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 test/fixture.h test/helpers.h +test/testtokenlist.o: test/testtokenlist.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.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 test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtokenlist.cpp test/testtokenrange.o: test/testtokenrange.cpp lib/addoninfo.h lib/check.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/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 25d1764f830..786647aa4ab 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -95,6 +95,7 @@ void TokenList::determineCppC() { // only try to determine if it wasn't enforced if (mLang == Standards::Language::None) { + ASSERT_LANG(!getSourceFilePath().empty()); mLang = Path::identify(getSourceFilePath()); // TODO: cannot enable assert as this might occur for unknown extensions //ASSERT_LANG(mLang != Standards::Language::None); @@ -372,11 +373,11 @@ bool TokenList::createTokensInternal(std::istream &code, const std::string& file // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) void TokenList::createTokens(simplecpp::TokenList&& tokenList) { - if (tokenList.cfront()) { + // tokenList.cfront() might be NULL if the file contained nothing to tokenize so we need to check the files instead + if (!tokenList.getFiles().empty()) { // this is a copy - // TODO: the same as TokenList.files - move that instead // TODO: this points to mFiles when called from createTokens(std::istream &, const std::string&) - mOrigFiles = mFiles = tokenList.cfront()->location.files; + mOrigFiles = mFiles = tokenList.getFiles(); } else mFiles.clear(); diff --git a/test/testtokenlist.cpp b/test/testtokenlist.cpp index 2e730cc6360..4b11c5c37db 100644 --- a/test/testtokenlist.cpp +++ b/test/testtokenlist.cpp @@ -20,6 +20,7 @@ #include "fixture.h" #include "helpers.h" #include "platform.h" +#include "preprocessor.h" #include "standards.h" #include "token.h" #include "tokenlist.h" @@ -27,6 +28,8 @@ #include #include +#include + class TestTokenList : public TestFixture { public: TestTokenList() : TestFixture("TestTokenList") {} @@ -39,6 +42,7 @@ class TestTokenList : public TestFixture { TEST_CASE(testaddtoken2); TEST_CASE(inc); TEST_CASE(isKeyword); + TEST_CASE(notokens); } // inspired by #5895 @@ -144,6 +148,19 @@ class TestTokenList : public TestFixture { ASSERT_EQUALS(false, tokenlist.front()->isKeyword()); } } + + void notokens() { + // analyzing /usr/include/poll.h caused Path::identify() to be called with an empty filename from + // TokenList::determineCppC() because there are no tokens + const char code[] = "#include "; + std::istringstream istr(code); + std::vector files; + simplecpp::TokenList tokens1(istr, files, "poll.h", nullptr); + Preprocessor preprocessor(settingsDefault, *this); + simplecpp::TokenList tokensP = preprocessor.preprocess(tokens1, "", files, true); + TokenList tokenlist(&settingsDefault); + tokenlist.createTokens(std::move(tokensP)); // do not assert + } }; REGISTER_TEST(TestTokenList) From c3d2d8092dfb3ed70b9263b0c9d9cf0439fadc57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 26 May 2024 11:10:03 +0200 Subject: [PATCH 11/14] CI: Fixed undefined symbol linker error in test-resultstree (#6445) --- gui/test/resultstree/testresultstree.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gui/test/resultstree/testresultstree.cpp b/gui/test/resultstree/testresultstree.cpp index b8fbb44b36f..55652dfbd15 100644 --- a/gui/test/resultstree/testresultstree.cpp +++ b/gui/test/resultstree/testresultstree.cpp @@ -74,6 +74,9 @@ XmlReport::XmlReport(const QString& filename) : Report(filename) {} bool Path::isHeader(std::string const& /*unused*/) { return false; } +bool Path::isHeader2(std::string const& /*unused*/) { + return false; +} const std::set ErrorLogger::mCriticalErrorIds; std::string ErrorMessage::FileLocation::getfile(bool /*unused*/) const { return std::string(); From 8cabf85ea3c3c0f298caa15d6a86a4217d525649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 26 May 2024 14:17:32 +0200 Subject: [PATCH 12/14] fixed #12763 - do not assert in markup processing for `unusedFunction` when a language is enforced (#6447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cherry pick from 9c21862159cffc02adc8c0c1c6f5272973068966 Co-authored-by: Oliver Stöneberg --- lib/cppcheck.cpp | 3 ++- lib/tokenlist.cpp | 7 +++++-- lib/tokenlist.h | 3 ++- test/cli/other_test.py | 24 +++++++++++++++++++++++- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 17948db683a..2a2efd1dcbd 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -643,7 +643,8 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string if (mUnusedFunctionsCheck && mSettings.useSingleJob() && mSettings.buildDir.empty()) { // this is not a real source file - we just want to tokenize it. treat it as C anyways as the language needs to be determined. Tokenizer tokenizer(mSettings, *this); - tokenizer.list.setLang(Standards::Language::C); + // enforce the language since markup files are special and do not adhere to the enforced language + tokenizer.list.setLang(Standards::Language::C, true); if (fileStream) { tokenizer.list.createTokens(*fileStream, filename); } diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 786647aa4ab..7795dfba990 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -2181,10 +2181,13 @@ bool TokenList::isCPP() const return mLang == Standards::Language::CPP; } -void TokenList::setLang(Standards::Language lang) +void TokenList::setLang(Standards::Language lang, bool force) { ASSERT_LANG(lang != Standards::Language::None); - ASSERT_LANG(mLang == Standards::Language::None); + if (!force) + { + ASSERT_LANG(mLang == Standards::Language::None); + } mLang = lang; } diff --git a/lib/tokenlist.h b/lib/tokenlist.h index c03cf3b6382..66bb008b783 100644 --- a/lib/tokenlist.h +++ b/lib/tokenlist.h @@ -68,7 +68,8 @@ class CPPCHECKLIB TokenList { /** @return true if the code is C++ */ bool isCPP() const; - void setLang(Standards::Language lang); + // TODO: get rid of this + void setLang(Standards::Language lang, bool force = false); /** * Delete all tokens in given token list diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 1ac8e4a341e..5fd2e2b82fe 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -1357,4 +1357,26 @@ def test_rule(tmpdir): lines = stderr.splitlines() assert lines == [ "{}:4:0: style: found 'f' [rule]".format(test_file) - ] \ No newline at end of file + ] + + +def test_markup_lang(tmpdir): + test_file_1 = os.path.join(tmpdir, 'test_1.qml') + with open(test_file_1, 'wt') as f: + pass + test_file_2 = os.path.join(tmpdir, 'test_2.cpp') + with open(test_file_2, 'wt') as f: + pass + + # do not assert processing markup file with enforced language + args = [ + '--library=qt', + '--enable=unusedFunction', + '--language=c++', + '-j1', + test_file_1, + test_file_2 + ] + + exitcode, stdout, _ = cppcheck(args) + assert exitcode == 0, stdout From cc7f2eae454b6fa15f58255009e57aea24b335a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 26 May 2024 14:18:17 +0200 Subject: [PATCH 13/14] 2.14.1: Set version --- cli/main.cpp | 2 +- lib/version.h | 2 +- win_installer/productInfo.wxi | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/main.cpp b/cli/main.cpp index 618bcbac4ab..4cabb0537d3 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -20,7 +20,7 @@ /** * * @mainpage Cppcheck - * @version 2.14.0 + * @version 2.14.1 * * @section overview_sec Overview * Cppcheck is a simple tool for static analysis of C/C++ code. diff --git a/lib/version.h b/lib/version.h index d99b949bd04..78aded14c45 100644 --- a/lib/version.h +++ b/lib/version.h @@ -7,7 +7,7 @@ #define CPPCHECK_MAJOR_VERSION 2 #define CPPCHECK_MINOR_VERSION 14 #define CPPCHECK_DEVMINOR_VERSION 14 -#define CPPCHECK_BUGFIX_VERSION 0 +#define CPPCHECK_BUGFIX_VERSION 1 #define STRINGIFY(x) STRING(x) #define STRING(VER) #VER diff --git a/win_installer/productInfo.wxi b/win_installer/productInfo.wxi index 870130db69e..b39b8c15f27 100644 --- a/win_installer/productInfo.wxi +++ b/win_installer/productInfo.wxi @@ -1,8 +1,8 @@ - + - + From 7cb8f2bc6f49748ff83ce405a3fefc24e6cf2a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 26 May 2024 17:58:01 +0200 Subject: [PATCH 14/14] Fix #12726: Update for CheckOrderEvaluation (#6448) cherry picked 9d4d1187dda0e3374822c59415a6493a4038975e Co-authored-by: olabetskyi <153490942+olabetskyi@users.noreply.github.com> --- lib/checkother.cpp | 120 +++++++++++++++++++++++++++++++++------------ lib/checkother.h | 2 +- test/testother.cpp | 45 +++++++++++++++++ 3 files changed, 134 insertions(+), 33 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 5d03fb87505..a2f54cbdd51 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3265,19 +3265,82 @@ void CheckOther::unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef Certainty::normal); } +static bool checkEvaluationOrderC(const Token * tok, const Token * tok2, const Token * parent, const Settings & settings, bool & selfAssignmentError) +{ + // self assignment.. + if (tok2 == tok && tok->str() == "=" && parent->str() == "=" && isSameExpression(false, tok->astOperand1(), parent->astOperand1(), settings.library, true, false)) { + if (settings.severity.isEnabled(Severity::warning) && isSameExpression(true, tok->astOperand1(), parent->astOperand1(), settings.library, true, false)) + selfAssignmentError = true; + return false; + } + // Is expression used? + bool foundError = false; + visitAstNodes((parent->astOperand1() != tok2) ? parent->astOperand1() : parent->astOperand2(), [&](const Token *tok3) { + if (tok3->str() == "&" && !tok3->astOperand2()) + return ChildrenToVisit::none; // don't handle address-of for now + if (tok3->str() == "(" && Token::simpleMatch(tok3->previous(), "sizeof")) + return ChildrenToVisit::none; // don't care about sizeof usage + if (isSameExpression(false, tok->astOperand1(), tok3, settings.library, true, false)) + foundError = true; + return foundError ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2; + }); -void CheckOther::checkEvaluationOrder() + return foundError; +} + +static bool checkEvaluationOrderCpp11(const Token * tok, const Token * tok2, const Token * parent, const Settings & settings) { - // This checker is not written according to C++11 sequencing rules - if (mTokenizer->isCPP() && mSettings->standards.cpp >= Standards::CPP11) - return; + if (tok->isAssignmentOp()) // TODO check assignment + return false; + if (tok->previous() == tok->astOperand1() && parent->isArithmeticalOp() && parent->isBinaryOp()) { + if (parent->astParent() && parent->astParent()->isAssignmentOp() && isSameExpression(false, tok->astOperand1(), parent->astParent()->astOperand1(), settings.library, true, false)) + return true; + } + bool foundUndefined{false}; + visitAstNodes((parent->astOperand1() != tok2) ? parent->astOperand1() : parent->astOperand2(), [&](const Token *tok3) { + if (tok3->str() == "&" && !tok3->astOperand2()) + return ChildrenToVisit::none; // don't handle address-of for now + if (tok3->str() == "(" && Token::simpleMatch(tok3->previous(), "sizeof")) + return ChildrenToVisit::none; // don't care about sizeof usage + if (isSameExpression(false, tok->astOperand1(), tok3, settings.library, true, false)) + foundUndefined = true; + return foundUndefined ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2; + }); - logChecker("CheckOther::checkEvaluationOrder"); // C/C++03 + return foundUndefined; +} +static bool checkEvaluationOrderCpp17(const Token * tok, const Token * tok2, const Token * parent, const Settings & settings, bool & foundUnspecified) +{ + if (tok->isAssignmentOp()) + return false; + bool foundUndefined{false}; + visitAstNodes((parent->astOperand1() != tok2) ? parent->astOperand1() : parent->astOperand2(), [&](const Token *tok3) { + if (tok3->str() == "&" && !tok3->astOperand2()) + return ChildrenToVisit::none; // don't handle address-of for now + if (tok3->str() == "(" && Token::simpleMatch(tok3->previous(), "sizeof")) + return ChildrenToVisit::none; // don't care about sizeof usage + if (isSameExpression(false, tok->astOperand1(), tok3, settings.library, true, false) && parent->isArithmeticalOp() && parent->isBinaryOp()) + foundUndefined = true; + if (tok3->tokType() == Token::eIncDecOp && isSameExpression(false, tok->astOperand1(), tok3->astOperand1(), settings.library, true, false)) { + if (parent->isArithmeticalOp() && parent->isBinaryOp()) + foundUndefined = true; + else + foundUnspecified = true; + } + return (foundUndefined || foundUnspecified) ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2; + }); + + return foundUndefined || foundUnspecified; +} + +void CheckOther::checkEvaluationOrder() +{ + logChecker("CheckOther::checkEvaluationOrder"); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope * functionScope : symbolDatabase->functionScopes) { for (const Token* tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) { - if (tok->tokType() != Token::eIncDecOp && !tok->isAssignmentOp()) + if (!tok->isIncDecOp() && !tok->isAssignmentOp()) continue; if (!tok->astOperand1()) continue; @@ -3308,32 +3371,22 @@ void CheckOther::checkEvaluationOrder() if (parent->str() == "(" && parent->astOperand2()) break; - // self assignment.. - if (tok2 == tok && - tok->str() == "=" && - parent->str() == "=" && - isSameExpression(false, tok->astOperand1(), parent->astOperand1(), mSettings->library, true, false)) { - if (mSettings->severity.isEnabled(Severity::warning) && - isSameExpression(true, tok->astOperand1(), parent->astOperand1(), mSettings->library, true, false)) - selfAssignmentError(parent, tok->astOperand1()->expressionString()); - break; + bool foundError{false}, foundUnspecified{false}, bSelfAssignmentError{false}; + if (mTokenizer->isCPP() && mSettings->standards.cpp >= Standards::CPP11) { + if (mSettings->standards.cpp >= Standards::CPP17) + foundError = checkEvaluationOrderCpp17(tok, tok2, parent, *mSettings, foundUnspecified); + else + foundError = checkEvaluationOrderCpp11(tok, tok2, parent, *mSettings); } - - // Is expression used? - bool foundError = false; - visitAstNodes((parent->astOperand1() != tok2) ? parent->astOperand1() : parent->astOperand2(), - [&](const Token *tok3) { - if (tok3->str() == "&" && !tok3->astOperand2()) - return ChildrenToVisit::none; // don't handle address-of for now - if (tok3->str() == "(" && Token::simpleMatch(tok3->previous(), "sizeof")) - return ChildrenToVisit::none; // don't care about sizeof usage - if (isSameExpression(false, tok->astOperand1(), tok3, mSettings->library, true, false)) - foundError = true; - return foundError ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2; - }); + else + foundError = checkEvaluationOrderC(tok, tok2, parent, *mSettings, bSelfAssignmentError); if (foundError) { - unknownEvaluationOrder(parent); + unknownEvaluationOrder(parent, foundUnspecified); + break; + } + if (bSelfAssignmentError) { + selfAssignmentError(parent, tok->astOperand1()->expressionString()); break; } } @@ -3341,10 +3394,13 @@ void CheckOther::checkEvaluationOrder() } } -void CheckOther::unknownEvaluationOrder(const Token* tok) +void CheckOther::unknownEvaluationOrder(const Token* tok, bool isUnspecifiedBehavior) { - reportError(tok, Severity::error, "unknownEvaluationOrder", - "Expression '" + (tok ? tok->expressionString() : std::string("x = x++;")) + "' depends on order of evaluation of side effects", CWE768, Certainty::normal); + isUnspecifiedBehavior ? + reportError(tok, Severity::portability, "unknownEvaluationOrder", + "Expression '" + (tok ? tok->expressionString() : std::string("x++, x++")) + "' depends on order of evaluation of side effects. Behavior is Unspecified according to c++17", CWE768, Certainty::normal) + : reportError(tok, Severity::error, "unknownEvaluationOrder", + "Expression '" + (tok ? tok->expressionString() : std::string("x = x++;")) + "' depends on order of evaluation of side effects", CWE768, Certainty::normal); } void CheckOther::checkAccessOfMovedVariable() diff --git a/lib/checkother.h b/lib/checkother.h index 79b62e96988..f2726bfd4e3 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -280,7 +280,7 @@ class CPPCHECKLIB CheckOther : public Check { void redundantPointerOpError(const Token* tok, const std::string& varname, bool inconclusive, bool addressOfDeref); void raceAfterInterlockedDecrementError(const Token* tok); void unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef); - void unknownEvaluationOrder(const Token* tok); + void unknownEvaluationOrder(const Token* tok, bool isUnspecifiedBehavior = false); void accessMovedError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive); void funcArgNamesDifferent(const std::string & functionName, nonneg int index, const Token* declaration, const Token* definition); void funcArgOrderDifferent(const std::string & functionName, const Token * declaration, const Token * definition, const std::vector & declarations, const std::vector & definitions); diff --git a/test/testother.cpp b/test/testother.cpp index 5faec17d2c5..213712b0011 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -10799,6 +10799,28 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:6]: (style) Label 'label' is not used.\n", errout_str()); } + #define checkCustomSettings(...) checkCustomSettings_(__FILE__, __LINE__, __VA_ARGS__) + void checkCustomSettings_(const char* file, int line, const char code[], bool cpp = true, bool inconclusive = true, bool runSimpleChecks=true, bool verbose=false, Settings* settings = nullptr) { + if (!settings) { + settings = &_settings; + } + settings->certainty.setEnabled(Certainty::inconclusive, inconclusive); + settings->verbose = verbose; + + // Tokenize.. + SimpleTokenizer tokenizer(*settings, *this); + ASSERT_LOC(tokenizer.tokenize(code, cpp), file, line); + + // Check.. + runChecks(tokenizer, this); + + (void)runSimpleChecks; // TODO Remove this + } + + void checkCustomSettings_(const char* file, int line, const char code[], Settings *s) { + checkCustomSettings_(file, line, code, true, true, true, false, s); + } + void testEvaluationOrder() { check("void f() {\n" " int x = dostuff();\n" @@ -10842,6 +10864,29 @@ class TestOther : public TestFixture { " a[x+y] = a[y+x]++;;\n" "}\n", false); ASSERT_EQUALS("[test.c:3]: (error) Expression 'a[x+y]=a[y+x]++' depends on order of evaluation of side effects\n", errout_str()); + + check("void f(int i) {\n" + " int n = ++i + i;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (error) Expression '++i+i' depends on order of evaluation of side effects\n", errout_str()); + + check("long int f1(const char *exp) {\n" + " return dostuff(++exp, ++exp, 10);\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (portability) Expression '++exp,++exp' depends on order of evaluation of side effects. Behavior is Unspecified according to c++17\n" + "[test.cpp:2]: (portability) Expression '++exp,++exp' depends on order of evaluation of side effects. Behavior is Unspecified according to c++17\n", errout_str()); + + check("void f(int i) {\n" + " int n = (~(-(++i)) + i);\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (error) Expression '~(-(++i))+i' depends on order of evaluation of side effects\n", errout_str()); + + /*const*/ Settings settings11 = settingsBuilder(_settings).cpp(Standards::CPP11).build(); + + checkCustomSettings("void f(int i) {\n" + " i = i++ + 2;\n" + "}", &settings11); + ASSERT_EQUALS("[test.cpp:2]: (error) Expression 'i+++2' depends on order of evaluation of side effects\n", errout_str()); } void testEvaluationOrderSelfAssignment() {