From 99e983ef3de3f59bc06359cb91f3f72d854e14f5 Mon Sep 17 00:00:00 2001 From: firewave Date: Wed, 24 Sep 2025 19:58:22 +0200 Subject: [PATCH 1/4] added `constness_ptr` as pointer wrapper to ensure actual method constness --- simplecpp.cpp | 4 +-- simplecpp.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/simplecpp.cpp b/simplecpp.cpp index 799d6c9b..98491775 100644 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -537,7 +537,7 @@ void simplecpp::TokenList::clear() backToken = nullptr; while (frontToken) { Token * const next = frontToken->next; - delete frontToken; + delete frontToken.get(); frontToken = next; } sizeOfType.clear(); @@ -2250,7 +2250,7 @@ namespace simplecpp { const bool canBeConcatenatedStringOrChar = isStringLiteral_(A->str()) || isCharLiteral_(A->str()); const bool unexpectedA = (!A->name && !A->number && !A->str().empty() && !canBeConcatenatedWithEqual && !canBeConcatenatedStringOrChar); - Token * const B = tok->next->next; + const Token * const B = tok->next->next; if (!B->name && !B->number && B->op && !B->isOneOf("#=")) throw invalidHashHash::unexpectedToken(tok->location, name(), B); diff --git a/simplecpp.h b/simplecpp.h index a014a6fc..b40f617b 100644 --- a/simplecpp.h +++ b/simplecpp.h @@ -72,6 +72,65 @@ namespace simplecpp { class Macro; class FileDataCache; + // as std::optional behaves similarly we could use that instead if we ever move to C++17. + // it is not a simple drop-in as our "operator bool()" indicates if the pointer is non-null + // whereas std::optional indicates if a value is set. + // + // This is similar to std::experimental::propagate_const + // see https://en.cppreference.com/w/cpp/experimental/propagate_const + template + class constness_ptr + { + public: + explicit constness_ptr(T* p) + : mPtr(p) + {} + + constness_ptr &operator=(T* p) { + mPtr = p; + return *this; + } + + T* get() noexcept { + return mPtr; + } + + const T* get() const noexcept { + return mPtr; + } + + operator T*() noexcept { + return mPtr; + } + + operator const T*() const noexcept { + return mPtr; + } + + T* operator->() noexcept { + return mPtr; + } + + const T* operator->() const noexcept { + return mPtr; + } + + T& operator*() noexcept { + return *mPtr; + } + + const T& operator*() const noexcept { + return *mPtr; + } + + explicit operator bool() const noexcept { + return mPtr != nullptr; + } + + private: + T* mPtr; + }; + /** * Location in source code */ @@ -154,8 +213,8 @@ namespace simplecpp { bool number; bool whitespaceahead; Location location; - Token *previous; - Token *next; + constness_ptr previous; + constness_ptr next; mutable const Token *nextcond; const Token *previousSkipComments() const { @@ -367,8 +426,8 @@ namespace simplecpp { unsigned int fileIndex(const std::string &filename); - Token *frontToken; - Token *backToken; + constness_ptr frontToken; + constness_ptr backToken; std::vector &files; }; From c3ded0d9d273a947b721c5fca4fc42fc4acd67bb Mon Sep 17 00:00:00 2001 From: firewave Date: Thu, 25 Sep 2025 08:27:28 +0200 Subject: [PATCH 2/4] s --- simplecpp.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/simplecpp.h b/simplecpp.h index b40f617b..8af52156 100644 --- a/simplecpp.h +++ b/simplecpp.h @@ -82,7 +82,10 @@ namespace simplecpp { class constness_ptr { public: - explicit constness_ptr(T* p) +#ifndef _MSC_VER + explicit +#endif + constness_ptr(T* p) : mPtr(p) {} From 020f63fe181d640b974002949b8dddfbd6f6adf7 Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 17 Mar 2025 12:43:05 +0100 Subject: [PATCH 3/4] avoid `bugprone-exception-escape` in `Macro` copy constructor mitigated `misc-const-correctness` clang-tidy false positive fixed `readability-math-missing-parentheses` clang-tidy warnings .clang-tidy: disabled `readability-use-concise-preprocessor-directives` split up Clang warnings in CMake disabled `-Wnrvo` Clang warning mitigated `misc-const-correctness` clang-tidy warnings clang-tidy.yml: updated to Clang 21 --- .clang-tidy | 1 + .github/workflows/clang-tidy.yml | 10 +++++----- CMakeLists.txt | 17 +++++++++++++---- simplecpp.cpp | 25 ++++++++++++++++--------- simplecpp.h | 1 + 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index c03da523..806a8608 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -49,6 +49,7 @@ Checks: > -readability-magic-numbers, -readability-redundant-inline-specifier, -readability-simplify-boolean-expr, + -readability-use-concise-preprocessor-directives, -readability-uppercase-literal-suffix, -performance-avoid-endl, -performance-enum-size, diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 9ebb6683..8dbd3667 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -33,19 +33,19 @@ jobs: run: | wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 20 - sudo apt-get install clang-tidy-20 + sudo ./llvm.sh 21 + sudo apt-get install clang-tidy-21 - name: Verify clang-tidy configuration run: | - clang-tidy-20 --verify-config + clang-tidy-21 --verify-config - name: Prepare CMake run: | cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_EXPORT_COMPILE_COMMANDS=ON env: - CXX: clang-20 + CXX: clang-21 - name: Clang-Tidy run: | - run-clang-tidy-20 -q -j $(nproc) -p=cmake.output + run-clang-tidy-21 -q -j $(nproc) -p=cmake.output diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cc62e88..efdc0d96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,16 +49,25 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") # no need for c++98 compatibility add_compile_options(-Wno-c++98-compat-pedantic) # these are not really fixable - add_compile_options(-Wno-exit-time-destructors -Wno-global-constructors -Wno-weak-vtables) + add_compile_options(-Wno-exit-time-destructors) + add_compile_options(-Wno-global-constructors) + add_compile_options(-Wno-weak-vtables) add_compile_options_safe(-Wno-unsafe-buffer-usage) + add_compile_options_safe(-Wno-nrvo) # we are not interested in these - add_compile_options(-Wno-multichar -Wno-four-char-constants) + add_compile_options(-Wno-multichar) + add_compile_options(-Wno-four-char-constants) # ignore C++11-specific warning - add_compile_options(-Wno-suggest-override -Wno-suggest-destructor-override) + add_compile_options(-Wno-suggest-override) + add_compile_options(-Wno-suggest-destructor-override) # contradicts -Wcovered-switch-default add_compile_options(-Wno-switch-default) # TODO: fix these? - add_compile_options(-Wno-padded -Wno-sign-conversion -Wno-implicit-int-conversion -Wno-shorten-64-to-32 -Wno-shadow-field-in-constructor) + add_compile_options(-Wno-padded) + add_compile_options(-Wno-sign-conversion) + add_compile_options(-Wno-implicit-int-conversion) + add_compile_options(-Wno-shorten-64-to-32) + add_compile_options(-Wno-shadow-field-in-constructor) if (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 14 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 14) # TODO: verify this regression still exists in clang-15 diff --git a/simplecpp.cpp b/simplecpp.cpp index 98491775..6f14977f 100644 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -874,7 +874,7 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, back()->setstr(currentToken); location.adjust(currentToken); if (currentToken.find_first_of("\r\n") == std::string::npos) - location.col += 2 + 2 * delim.size(); + location.col += 2 + (2 * delim.size()); else location.col += 1 + delim.size(); @@ -1329,6 +1329,7 @@ void simplecpp::TokenList::constFoldLogicalOp(Token *tok) void simplecpp::TokenList::constFoldQuestionOp(Token **tok1) { bool gotoTok1 = false; + // NOLINTNEXTLINE(misc-const-correctness) - technically correct but used to access non-cost data for (Token *tok = *tok1; tok && tok->op != ')'; tok = gotoTok1 ? *tok1 : tok->next) { gotoTok1 = false; if (tok->str() != "?") @@ -1508,7 +1509,12 @@ namespace simplecpp { } Macro(const Macro &other) : nameTokDef(nullptr), files(other.files), tokenListDefine(other.files), valueDefinedInCode_(other.valueDefinedInCode_) { - *this = other; + // TODO: remove the try-catch - see #537 + // avoid bugprone-exception-escape clang-tidy warning + try { + *this = other; + } + catch (const Error&) {} // NOLINT(bugprone-empty-catch) } ~Macro() { @@ -1945,6 +1951,7 @@ namespace simplecpp { } } + // NOLINTNEXTLINE(misc-const-correctness) - technically correct but used to access non-cost data Token * const output_end_1 = output.back(); const Token *valueToken2; @@ -2528,11 +2535,11 @@ static void simplifySizeof(simplecpp::TokenList &expr, const std::mapnext) { if (tok->str() != "sizeof") continue; - simplecpp::Token *tok1 = tok->next; + const simplecpp::Token *tok1 = tok->next; if (!tok1) { throw std::runtime_error("missing sizeof argument"); } - simplecpp::Token *tok2 = tok1->next; + const simplecpp::Token *tok2 = tok1->next; if (!tok2) { throw std::runtime_error("missing sizeof argument"); } @@ -2547,7 +2554,7 @@ static void simplifySizeof(simplecpp::TokenList &expr, const std::mapnext) { + for (const simplecpp::Token *typeToken = tok1; typeToken != tok2; typeToken = typeToken->next) { if ((typeToken->str() == "unsigned" || typeToken->str() == "signed") && typeToken->next->name) continue; if (typeToken->str() == "*" && type.find('*') != std::string::npos) @@ -2598,11 +2605,11 @@ static void simplifyHasInclude(simplecpp::TokenList &expr, const simplecpp::DUI for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) { if (tok->str() != HAS_INCLUDE) continue; - simplecpp::Token *tok1 = tok->next; + const simplecpp::Token *tok1 = tok->next; if (!tok1) { throw std::runtime_error("missing __has_include argument"); } - simplecpp::Token *tok2 = tok1->next; + const simplecpp::Token *tok2 = tok1->next; if (!tok2) { throw std::runtime_error("missing __has_include argument"); } @@ -2620,7 +2627,7 @@ static void simplifyHasInclude(simplecpp::TokenList &expr, const simplecpp::DUI const bool systemheader = (tok1 && tok1->op == '<'); std::string header; if (systemheader) { - simplecpp::Token *tok3 = tok1->next; + const simplecpp::Token *tok3 = tok1->next; if (!tok3) { throw std::runtime_error("missing __has_include closing angular bracket"); } @@ -2631,7 +2638,7 @@ static void simplifyHasInclude(simplecpp::TokenList &expr, const simplecpp::DUI } } - for (simplecpp::Token *headerToken = tok1->next; headerToken != tok3; headerToken = headerToken->next) + for (const simplecpp::Token *headerToken = tok1->next; headerToken != tok3; headerToken = headerToken->next) header += headerToken->str(); } else { header = tok1->str().substr(1U, tok1->str().size() - 2U); diff --git a/simplecpp.h b/simplecpp.h index 8af52156..cf5853c7 100644 --- a/simplecpp.h +++ b/simplecpp.h @@ -488,6 +488,7 @@ namespace simplecpp { std::pair get(const std::string &sourcefile, const std::string &header, const DUI &dui, bool systemheader, std::vector &filenames, OutputList *outputList); void insert(FileData data) { + // NOLINTNEXTLINE(misc-const-correctness) - FP FileData *const newdata = new FileData(std::move(data)); mData.emplace_back(newdata); From cc4f3f715f0cff6f3bed3e207c7cb1660b362316 Mon Sep 17 00:00:00 2001 From: firewave Date: Sat, 27 Sep 2025 10:48:04 +0200 Subject: [PATCH 4/4] const --- simplecpp.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/simplecpp.cpp b/simplecpp.cpp index 6f14977f..4a99fd10 100644 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -1329,7 +1329,6 @@ void simplecpp::TokenList::constFoldLogicalOp(Token *tok) void simplecpp::TokenList::constFoldQuestionOp(Token **tok1) { bool gotoTok1 = false; - // NOLINTNEXTLINE(misc-const-correctness) - technically correct but used to access non-cost data for (Token *tok = *tok1; tok && tok->op != ')'; tok = gotoTok1 ? *tok1 : tok->next) { gotoTok1 = false; if (tok->str() != "?") @@ -1951,7 +1950,6 @@ namespace simplecpp { } } - // NOLINTNEXTLINE(misc-const-correctness) - technically correct but used to access non-cost data Token * const output_end_1 = output.back(); const Token *valueToken2;