From 0e7542a664318cfc40953ed95f48084ff9470129 Mon Sep 17 00:00:00 2001 From: bgs99 Date: Sat, 11 May 2024 14:59:47 +0300 Subject: [PATCH] clang-tidy (#5) * clang-tidy config and fixes * tidy script * CI tidy checks * Run only on pushes to main --- .clang-format | 5 ++-- .clang-tidy | 37 ++++++++++++++++++++++++++++ .github/workflows/ci.yaml | 29 ++++++++++++++++++++-- CMakeLists.txt | 3 +-- include/pfr-orm/api.hpp | 11 ++++++--- include/pfr-orm/definitions.hpp | 3 ++- include/pfr-orm/detail/escaping.hpp | 11 --------- include/pfr-orm/detail/field.hpp | 3 +++ include/pfr-orm/detail/type_name.hpp | 12 ++++----- include/pfr-orm/postges-helpers.hpp | 3 --- lib/detail/escaping.cpp | 13 ---------- lib/detail/operations.cpp | 10 +++++--- scripts/tidy.py | 24 ++++++++++++++++++ test/Person.hpp | 21 ---------------- test/nested.cpp | 1 + test/simple.cpp | 1 + test/test.cpp | 24 +++++++++++++++--- 17 files changed, 138 insertions(+), 73 deletions(-) create mode 100644 .clang-tidy delete mode 100644 include/pfr-orm/detail/escaping.hpp delete mode 100644 lib/detail/escaping.cpp create mode 100755 scripts/tidy.py delete mode 100644 test/Person.hpp diff --git a/.clang-format b/.clang-format index 24677c0..08ce9cc 100644 --- a/.clang-format +++ b/.clang-format @@ -2,13 +2,12 @@ BasedOnStyle: LLVM IncludeBlocks: Regroup IncludeCategories: - - Regex: '^)' + - Regex: "^<(fmt/|boost/|libpq-fe\\.h>)" CaseSensitive: true Priority: 3 - Priority: 2 - ForEachMacros: [] diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..fbb34c6 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,37 @@ +Checks: + - readability-* + - portability-* + - performance-* + - modernize-* + - misc-* + - cppcoreguidelines-* + - concurrency-* + - cert-* + - bugprone-* + - -misc-include-cleaner # not reliable + - -llvm-header-guard # #pragma once + - -llvm-include-order # managed by clang-format + - -modernize-use-trailing-return-type # TODO + - -misc-no-recursion # simplifies code + +CheckOptions: + - { key: readability-identifier-naming.ClassCase, value: CamelCase } + - { key: readability-identifier-naming.StructCase, value: CamelCase } + - { key: readability-identifier-naming.MemberCase, value: camelBack } + - { key: readability-identifier-naming.FunctionCase, value: camelBack } + - { key: readability-identifier-naming.LocalVariableCase, value: camelBack } + - { key: readability-identifier-naming.ParameterCase, value: camelBack } + - { key: readability-identifier-naming.StaticConstantCase, value: CamelCase } + - { key: readability-identifier-naming.EnumConstantCase, value: CamelCase } + - { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase } + - { key: readability-identifier-naming.ConstantMemberCase, value: camelBack } + - { key: readability-identifier-length.MinimumVariableNameLength, value: 3 } + - { key: readability-identifier-length.MinimumParameterNameLength, value: 3 } + - { + key: readability-identifier-length.IgnoredParameterNames, + value: "i|j|k|x|y|z|os", + } + - { + key: readability-identifier-length.IgnoredVariableNames, + value: "i|j|k|x|y|z|os", + } diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4a83b0f..f248f11 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,7 +1,9 @@ name: tests on: - - push - - pull_request + push: + branches: + - main + pull_request: jobs: check-format: @@ -22,6 +24,29 @@ jobs: - name: Check formatting run: python ${{ github.workspace }}/scripts/check_format.py --clang-format=clang-format-18 + check-tidy: + runs-on: ubuntu-22.04 + env: + build_dir: ${{ github.workspace }}/build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Add LLVM apt key + run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/llvm-toolchain-focal-18.asc + + - name: Add LLVM repo + run: sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-18 main' + + - name: Install dependencies + run: sudo apt-get install libfmt-dev libpq-dev clang-tidy-18 + + - name: Configure CMake + run: cmake -B ${{ env.build_dir }} -S ${{ github.workspace }} + + - name: Run clang-tidy + run: python ${{ github.workspace }}/scripts/tidy.py --clang-tidy=run-clang-tidy-18 --compile-commands=${{ env.build_dir }} + test: runs-on: ${{ matrix.os }} strategy: diff --git a/CMakeLists.txt b/CMakeLists.txt index bae1610..45ef05e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,8 +11,7 @@ find_package(PostgreSQL REQUIRED) add_library(pfr-orm STATIC) target_compile_features(pfr-orm PUBLIC cxx_std_20) -target_sources(pfr-orm PRIVATE lib/detail/escaping.cpp - lib/detail/operations.cpp) +target_sources(pfr-orm PRIVATE lib/detail/operations.cpp) target_include_directories(pfr-orm PUBLIC include) target_link_libraries( pfr-orm diff --git a/include/pfr-orm/api.hpp b/include/pfr-orm/api.hpp index e010f13..e1bb3bd 100644 --- a/include/pfr-orm/api.hpp +++ b/include/pfr-orm/api.hpp @@ -10,6 +10,7 @@ #include #include +#include static_assert(BOOST_PFR_ENABLED, "Boost.PFR is not supported, cannot build"); static_assert(BOOST_PFR_CORE_NAME_ENABLED, @@ -18,14 +19,14 @@ static_assert(BOOST_PFR_CORE_NAME_ENABLED, namespace pfrorm { /// Identifier mode -enum class IdMode { +enum class IdMode : std::uint8_t { Auto, ///< Automatically generated by database Manual, ///< Provided when persisting }; template class FieldDescriptor { public: - constexpr std::size_t get() const { return this->field; } + [[nodiscard]] constexpr std::size_t get() const { return this->field; } private: std::size_t field; @@ -37,6 +38,7 @@ template class FieldDescriptor { detail::getFieldDescriptor(const auto C::*, std::string_view); }; +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage): TODO #define PFRORM_FIELD(type, field) \ ::pfrorm::detail::getFieldDescriptor(&type::field, #field) @@ -56,7 +58,7 @@ template struct CompositeRegistrationData {}; /// ORM composite value registration /// @tparam T registered type template -std::optional> CompositeRegistration = +constexpr std::optional> CompositeRegistration = std::nullopt; enum class NativeType : std::uint8_t { @@ -71,7 +73,8 @@ template struct ValueRegistrationData { /// Basic value type mapping /// @tparam T registered value type template -std::optional> ValueRegistration = std::nullopt; +constexpr std::optional> ValueRegistration = + std::nullopt; template <> inline constexpr auto ValueRegistration = diff --git a/include/pfr-orm/definitions.hpp b/include/pfr-orm/definitions.hpp index 20f825b..e642fe3 100644 --- a/include/pfr-orm/definitions.hpp +++ b/include/pfr-orm/definitions.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -134,7 +135,7 @@ getFieldDescriptionOfField(const std::string_view name) { template constexpr std::array getFieldDescriptions(std::array names, - std::index_sequence) { + std::index_sequence /*indices*/) { return {getFieldDescriptionOfField>( names[Idx])...}; } diff --git a/include/pfr-orm/detail/escaping.hpp b/include/pfr-orm/detail/escaping.hpp deleted file mode 100644 index 476b1ad..0000000 --- a/include/pfr-orm/detail/escaping.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include -#include - -namespace pfrorm::detail { - -std::string addIdentifierPrefix(std::string_view prefix, - std::string_view identifier); - -} diff --git a/include/pfr-orm/detail/field.hpp b/include/pfr-orm/detail/field.hpp index 61d20b1..7e8bd77 100644 --- a/include/pfr-orm/detail/field.hpp +++ b/include/pfr-orm/detail/field.hpp @@ -3,7 +3,10 @@ #include #include +#include +#include #include +#include #include #include diff --git a/include/pfr-orm/detail/type_name.hpp b/include/pfr-orm/detail/type_name.hpp index 9ab9400..d78af9e 100644 --- a/include/pfr-orm/detail/type_name.hpp +++ b/include/pfr-orm/detail/type_name.hpp @@ -7,11 +7,11 @@ namespace pfrorm::detail { template constexpr std::string_view wrappedTypeNameImpl() { #ifdef __clang__ - return __PRETTY_FUNCTION__; + return static_cast(__PRETTY_FUNCTION__); #elif defined(__GNUC__) - return __PRETTY_FUNCTION__; + return static_cast(__PRETTY_FUNCTION__); #elif defined(_MSC_VER) - return __FUNCSIG__; + return static_cast(__FUNCSIG__); #else #error "Unsupported compiler" #endif @@ -20,14 +20,14 @@ template constexpr std::string_view wrappedTypeNameImpl() { template constexpr std::string_view WrappedTypeName = wrappedTypeNameImpl(); -constexpr std::string_view voidTypeName = "void"; +constexpr std::string_view VoidTypeName = "void"; constexpr std::size_t WrappedTypeNamePrefixLength = - wrappedTypeNameImpl().find(voidTypeName); + wrappedTypeNameImpl().find(VoidTypeName); constexpr std::size_t WrappedTypeNameSuffixLength = wrappedTypeNameImpl().length() - WrappedTypeNamePrefixLength - - voidTypeName.length(); + VoidTypeName.length(); template constexpr std::size_t TypeNameLength = diff --git a/include/pfr-orm/postges-helpers.hpp b/include/pfr-orm/postges-helpers.hpp index 4087487..a2ea861 100644 --- a/include/pfr-orm/postges-helpers.hpp +++ b/include/pfr-orm/postges-helpers.hpp @@ -1,15 +1,12 @@ #pragma once -#include #include #include -#include #include #include #include #include -#include #include namespace pfrorm::postgres { diff --git a/lib/detail/escaping.cpp b/lib/detail/escaping.cpp deleted file mode 100644 index cdfd17c..0000000 --- a/lib/detail/escaping.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include - -#include - -namespace pfrorm::detail { - -std::string addIdentifierPrefix(const std::string_view prefix, - const std::string_view identifier) { - - return fmt::format("{}_{}", prefix, identifier); -} - -} // namespace pfrorm::detail diff --git a/lib/detail/operations.cpp b/lib/detail/operations.cpp index 6684d90..dc48f28 100644 --- a/lib/detail/operations.cpp +++ b/lib/detail/operations.cpp @@ -1,10 +1,13 @@ +#include +#include +#include + #include "multilambda.hpp" -#include "pfr-orm/api.hpp" -#include "pfr-orm/definitions.hpp" -#include "pfr-orm/postges-helpers.hpp" #include #include +#include #include +#include #include #include @@ -39,6 +42,7 @@ void createTableFields(const FieldDescription &description, toString(descr.nativeType), isPrimaryKey ? " PRIMARY KEY" : ""); first = false; }; + const auto createCompositeField = [&prefixes, &connection, &appender, &first](const CompositeFieldDescription &descr) { diff --git a/scripts/tidy.py b/scripts/tidy.py new file mode 100755 index 0000000..22c64cf --- /dev/null +++ b/scripts/tidy.py @@ -0,0 +1,24 @@ +#!/usr/bin/python + +from pathlib import Path +import subprocess +import argparse + +from common.project import cpp_files + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(add_help=True) + parser.add_argument('--clang-tidy', + help='clang-tidy executable to use', + type=str, + default='run-clang-tidy') + parser.add_argument('--compile-commands', + help='Path to the directory with compile commands', + type=Path, + default='build') + + args = parser.parse_args() + + subprocess.run([args.clang_tidy, '-quiet', '-p', args.compile_commands.as_posix(), + *[file.as_posix() for file in cpp_files()]]) diff --git a/test/Person.hpp b/test/Person.hpp deleted file mode 100644 index 8a71db0..0000000 --- a/test/Person.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -#include -#include - -struct Person { - std::uint64_t id; - - std::string name; -}; - -template <> struct pfrorm::EntityRegistration { - /// Identifier mode - constexpr static IdMode Id = IdMode::Auto; - - /// Identifier field - constexpr static std::uint64_t Person::*IdField = &Person::id; -}; - -static_assert(pfrorm::DatabaseEntity); diff --git a/test/nested.cpp b/test/nested.cpp index 506756b..99bb388 100644 --- a/test/nested.cpp +++ b/test/nested.cpp @@ -1,6 +1,7 @@ #include #include +#include #include namespace { diff --git a/test/simple.cpp b/test/simple.cpp index 67bbd1d..d211c91 100644 --- a/test/simple.cpp +++ b/test/simple.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include diff --git a/test/test.cpp b/test/test.cpp index 291a3c4..e824e02 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,8 +1,14 @@ +#include #include #include #include #include +#include +#include +#include +#include +#include #include @@ -28,11 +34,21 @@ constexpr auto pfrorm::EntityRegistration = static_assert(pfrorm::DatabaseEntity); int main(int argc, char **argv) { - fmt::println("{}", pfrorm::DatabaseEntityDescription.name); + const std::span args{argv, static_cast(argc)}; - pg_orm::Connection conn = pg_orm::connect(argv[1]); + try { + pg_orm::Connection conn = pg_orm::connect(args[1]); - pg_orm::createTable(*conn); + pg_orm::createTable(*conn); - assert(!pg_orm::exists(*conn)); + assert(!pg_orm::exists(*conn)); + + return 0; + } catch (const std::exception &ex) { + fmt::print("{}\n", ex.what()); + return 1; + } catch (...) { + fmt::print("Unknown exception\n"); + return 1; + } }