diff --git a/.clang-format b/.clang-format index cf00c631a..c8b69fbbf 100644 --- a/.clang-format +++ b/.clang-format @@ -43,7 +43,7 @@ TabWidth: 4 UseTab: Never --- Language: Cpp -Standard: c++17 +Standard: c++20 AccessModifierOffset: -4 PackConstructorInitializers: Never diff --git a/CMakeLists.txt b/CMakeLists.txt index 894ccd075..d84e37cde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,7 +174,7 @@ if(NOT CMAKE_C_STANDARD) set(CMAKE_C_STANDARD_REQUIRED ON) endif() if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) endif() diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj index 94ce78b2f..5e69035c4 100644 --- a/Transmission.xcodeproj/project.pbxproj +++ b/Transmission.xcodeproj/project.pbxproj @@ -483,6 +483,7 @@ EDC37BCD2EE9C2AD001E2612 /* api-compat.cc in Sources */ = {isa = PBXBuildFile; fileRef = EDC37BCC2EE9C2AD001E2612 /* api-compat.cc */; }; EDC37BCE2EE9C2AD001E2612 /* api-compat.h in Headers */ = {isa = PBXBuildFile; fileRef = EDC37BCB2EE9C2AD001E2612 /* api-compat.h */; }; EDC749F92D98AE3000A12D0F /* PowerManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = EDC749F82D98AE2900A12D0F /* PowerManager.mm */; }; + EDD735D62D83087400852628 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDD735D52D83087400852628 /* UniformTypeIdentifiers.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; F11545ACA7C4D7A464F703AB /* block-info.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A044CBD8C049AFCBD4DB411 /* block-info.h */; settings = {ATTRIBUTES = (Project, ); }; }; F63480631E1D7274005B9E09 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F63480621E1D7274005B9E09 /* Images.xcassets */; }; /* End PBXBuildFile section */ @@ -1478,6 +1479,7 @@ EDC37BCC2EE9C2AD001E2612 /* api-compat.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "api-compat.cc"; sourceTree = ""; }; EDC749F72D98ADE200A12D0F /* PowerManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PowerManager.h; sourceTree = ""; }; EDC749F82D98AE2900A12D0F /* PowerManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PowerManager.mm; sourceTree = ""; }; + EDD735D52D83087400852628 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; }; F63480621E1D7274005B9E09 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Images/Images.xcassets; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1505,6 +1507,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + EDD735D62D83087400852628 /* UniformTypeIdentifiers.framework in Frameworks */, C87369652809984200573C90 /* UserNotifications.framework in Frameworks */, 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 4D1838DD09DEC0E80047D688 /* libtransmission.a in Frameworks */, @@ -2185,6 +2188,7 @@ A2F35BBA15C5A0A100EBF632 /* Frameworks */ = { isa = PBXGroup; children = ( + EDD735D52D83087400852628 /* UniformTypeIdentifiers.framework */, C87369642809984200573C90 /* UserNotifications.framework */, 55869925257074EC00F77A43 /* libcurl.tbd */, C88771AB2803EE53005C7523 /* libiconv.tbd */, @@ -4381,8 +4385,9 @@ LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; OTHER_CPLUSPLUSFLAGS = ( "$(inherited)", - "-fmodules", - "-fcxx-modules", + "-fno-modules", + "-Xclang", + "-fno-cxx-modules", ); PRODUCT_NAME = Transmission; SYSTEM_HEADER_SEARCH_PATHS = ( @@ -4457,7 +4462,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; @@ -4644,8 +4649,9 @@ LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; OTHER_CPLUSPLUSFLAGS = ( "$(inherited)", - "-fmodules", - "-fcxx-modules", + "-fno-modules", + "-Xclang", + "-fno-cxx-modules", ); PRODUCT_NAME = Transmission; SYSTEM_HEADER_SEARCH_PATHS = ( @@ -4662,7 +4668,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; @@ -4765,7 +4771,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; @@ -4849,8 +4855,9 @@ LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; OTHER_CPLUSPLUSFLAGS = ( "$(inherited)", - "-fmodules", - "-fcxx-modules", + "-fno-modules", + "-Xclang", + "-fno-cxx-modules", ); PRODUCT_NAME = Transmission; SYSTEM_HEADER_SEARCH_PATHS = ( @@ -5034,8 +5041,9 @@ INSTALL_PATH = /Library/QuickLook; OTHER_CPLUSPLUSFLAGS = ( "$(inherited)", - "-fmodules", - "-fcxx-modules", + "-fno-modules", + "-Xclang", + "-fno-cxx-modules", ); PRODUCT_BUNDLE_IDENTIFIER = "org.m0k.transmission.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5061,8 +5069,9 @@ INSTALL_PATH = /Library/QuickLook; OTHER_CPLUSPLUSFLAGS = ( "$(inherited)", - "-fmodules", - "-fcxx-modules", + "-fno-modules", + "-Xclang", + "-fno-cxx-modules", ); PRODUCT_BUNDLE_IDENTIFIER = "org.m0k.transmission.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5088,8 +5097,9 @@ INSTALL_PATH = /Library/QuickLook; OTHER_CPLUSPLUSFLAGS = ( "$(inherited)", - "-fmodules", - "-fcxx-modules", + "-fno-modules", + "-Xclang", + "-fno-cxx-modules", ); PRODUCT_BUNDLE_IDENTIFIER = "org.m0k.transmission.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/gtk/Notify.cc b/gtk/Notify.cc index a05476c96..9ce932cb8 100644 --- a/gtk/Notify.cc +++ b/gtk/Notify.cc @@ -53,6 +53,7 @@ template Glib::VariantContainerBase make_variant_tuple(Ts&&... args) { return Glib::VariantContainerBase::create_tuple( + // TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1 { Glib::Variant>>::create(std::forward(args))... }); } diff --git a/gtk/Torrent.cc b/gtk/Torrent.cc index 170e2ed0e..84358f105 100644 --- a/gtk/Torrent.cc +++ b/gtk/Torrent.cc @@ -40,8 +40,6 @@ Glib::Value& column_value_cast(Glib::ValueBase& value, Gtk::TreeModelColumn>> void update_cache_value(T& value, U&& new_value, Torrent::ChangeFlags& changes, Torrent::ChangeFlag flag) { - using std::rel_ops::operator!=; - if (value != new_value) { value = std::forward(new_value); diff --git a/libtransmission/.clang-tidy b/libtransmission/.clang-tidy index 7f202edc2..cf4cb67dd 100644 --- a/libtransmission/.clang-tidy +++ b/libtransmission/.clang-tidy @@ -3,7 +3,15 @@ HeaderFilterRegex: .*/libtransmission/.* # TODO: Enable `portability-template-virtual-member-function` after https://github.com/llvm/llvm-project/issues/139031 is fixed # TODO: Enable `cppcoreguidelines-pro-bounds-pointer-arithmetic` after converting all pointers to std::span +# TODO: Enable `modernize-use-constraints` after GCC >= 10, clang 10 +# TODO: Enable `modernize-use-integer-sign-comparison` (P0586R2) after GCC >= 10.1, clang >= 13 # PRs welcome to fix & re-enable any of these explicitly-disabled checks +# +# -modernize-use-ranges: GCC 10.1, clang 15 +# -modernize-loop-convert (P0896R4): GCC 10.1, clang 15 +# -readability-container-contains (P0458R2): GCC 9.1, clang 13 +# Ref: https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html +# Ref: https://libcxx.llvm.org/Status/Cxx20.html Checks: > bugprone-*, -bugprone-branch-clone, @@ -36,12 +44,18 @@ Checks: > -misc-no-recursion, -misc-non-private-member-variables-in-classes, modernize-*, + -modernize-loop-convert, + -modernize-use-constraints, + -modernize-use-designated-initializers, + -modernize-use-integer-sign-comparison, + -modernize-use-ranges, -modernize-use-trailing-return-type, performance-*, -performance-move-const-arg, portability-*, -portability-template-virtual-member-function, readability-*, + -readability-container-contains, -readability-enum-initial-value, -readability-function-cognitive-complexity, -readability-identifier-length, diff --git a/libtransmission/announce-list.h b/libtransmission/announce-list.h index 4ef1a5d69..b32bd2075 100644 --- a/libtransmission/announce-list.h +++ b/libtransmission/announce-list.h @@ -82,19 +82,19 @@ public: return std::size(trackers_); } - [[nodiscard]] TR_CONSTEXPR20 tracker_info const& at(size_t i) const + [[nodiscard]] TR_CONSTEXPR_VEC tracker_info const& at(size_t i) const { return trackers_.at(i); } [[nodiscard]] tr_tracker_tier_t nextTier() const; - [[nodiscard]] TR_CONSTEXPR20 bool operator==(tr_announce_list const& that) const + [[nodiscard]] TR_CONSTEXPR_VEC bool operator==(tr_announce_list const& that) const { return trackers_ == that.trackers_; } - [[nodiscard]] bool operator!=(tr_announce_list const& that) const + [[nodiscard]] TR_CONSTEXPR_VEC bool operator!=(tr_announce_list const& that) const { return trackers_ != that.trackers_; } @@ -113,7 +113,7 @@ public: bool replace(tr_tracker_id_t id, std::string_view announce_url_sv); size_t set(char const* const* announce_urls, tr_tracker_tier_t const* tiers, size_t n); - TR_CONSTEXPR20 void clear() + TR_CONSTEXPR_VEC void clear() { trackers_.clear(); } diff --git a/libtransmission/announcer.cc b/libtransmission/announcer.cc index 36551fc41..015fdce49 100644 --- a/libtransmission/announcer.cc +++ b/libtransmission/announcer.cc @@ -926,22 +926,22 @@ void on_announce_error(tr_tier* tier, char const* err, tr_announce_event e, time auto const* const current_tracker = tier->currentTracker(); TR_ASSERT(current_tracker != nullptr); - auto req = tr_announce_request{}; - req.port = announcer->session->advertisedPeerPort(); - req.announce_url = current_tracker->announce_url; - req.tracker_id = current_tracker->tracker_id; - req.info_hash = tor->info_hash(); - req.peer_id = tor->peer_id(); - req.up = tier->byteCounts[TR_ANN_UP]; - req.down = tier->byteCounts[TR_ANN_DOWN]; - req.corrupt = tier->byteCounts[TR_ANN_CORRUPT]; - req.leftUntilComplete = tor->has_metainfo() ? tor->total_size() - tor->has_total() : INT64_MAX; - req.event = event; - req.numwant = event == TR_ANNOUNCE_EVENT_STOPPED ? 0 : Numwant; - req.key = tor->announce_key(); - req.partial_seed = tor->is_partial_seed(); - req.log_name = tier->buildLogName(); - return req; + return { + .event = event, + .partial_seed = tor->is_partial_seed(), + .port = announcer->session->advertisedPeerPort(), + .key = tor->announce_key(), + .numwant = event == TR_ANNOUNCE_EVENT_STOPPED ? 0 : Numwant, + .up = tier->byteCounts[TR_ANN_UP], + .down = tier->byteCounts[TR_ANN_DOWN], + .corrupt = tier->byteCounts[TR_ANN_CORRUPT], + .leftUntilComplete = tor->has_metainfo() ? tor->total_size() - tor->has_total() : INT64_MAX, + .announce_url = current_tracker->announce_url, + .tracker_id = current_tracker->tracker_id, + .peer_id = tor->peer_id(), + .info_hash = tor->info_hash(), + .log_name = tier->buildLogName(), + }; } [[nodiscard]] tr_tier* getTier(tr_announcer_impl* announcer, tr_sha1_digest_t const& info_hash, size_t tier_id) diff --git a/libtransmission/api-compat.cc b/libtransmission/api-compat.cc index e51cac7de..b429f6b1c 100644 --- a/libtransmission/api-compat.cc +++ b/libtransmission/api-compat.cc @@ -653,6 +653,7 @@ void convert_keys(tr_variant& var, State& state) var.visit( [&state](auto& val) { + // TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1 using ValueType = std::decay_t; if constexpr (std::is_same_v || std::is_same_v) diff --git a/libtransmission/error.h b/libtransmission/error.h index 586a15c07..a08cec913 100644 --- a/libtransmission/error.h +++ b/libtransmission/error.h @@ -14,9 +14,9 @@ struct tr_error { public: - tr_error() = default; + TR_CONSTEXPR_STR tr_error() = default; - tr_error(int code, std::string message) + TR_CONSTEXPR_STR tr_error(int code, std::string message) : message_{ std::move(message) } , code_{ code } { @@ -27,7 +27,7 @@ public: return code_; } - [[nodiscard]] TR_CONSTEXPR20 auto message() const noexcept + [[nodiscard]] TR_CONSTEXPR_STR auto message() const noexcept { return std::string_view{ message_ }; } @@ -42,24 +42,24 @@ public: return has_value(); } - void set(int code, std::string&& message) + TR_CONSTEXPR_STR void set(int code, std::string&& message) { code_ = code; message_ = std::move(message); } - void set(int code, std::string_view message) + TR_CONSTEXPR_STR void set(int code, std::string_view message) { code_ = code; message_.assign(message); } - void set(int code, char const* const message) + TR_CONSTEXPR_STR void set(int code, char const* const message) { set(code, std::string_view{ message != nullptr ? message : "" }); } - void prefix_message(std::string_view prefix) + TR_CONSTEXPR_STR void prefix_message(std::string_view prefix) { message_.insert(std::begin(message_), std::begin(prefix), std::end(prefix)); } diff --git a/libtransmission/file-piece-map.h b/libtransmission/file-piece-map.h index c8b5cf240..12eb93f92 100644 --- a/libtransmission/file-piece-map.h +++ b/libtransmission/file-piece-map.h @@ -45,7 +45,7 @@ public: explicit tr_file_piece_map(tr_torrent_metainfo const& tm); tr_file_piece_map(tr_block_info const& block_info, uint64_t const* file_sizes, size_t n_files); - [[nodiscard]] TR_CONSTEXPR20 piece_span_t piece_span_for_file(tr_file_index_t const file) const noexcept + [[nodiscard]] TR_CONSTEXPR_VEC piece_span_t piece_span_for_file(tr_file_index_t const file) const noexcept { return file_pieces_[file]; } @@ -59,7 +59,7 @@ public: return std::size(file_pieces_); } - [[nodiscard]] TR_CONSTEXPR20 auto byte_span_for_file(tr_file_index_t const file) const + [[nodiscard]] TR_CONSTEXPR_VEC auto byte_span_for_file(tr_file_index_t const file) const { auto const& span = file_bytes_[file]; return tr_byte_span_t{ span.begin, span.end }; @@ -84,7 +84,7 @@ private: class tr_file_priorities { public: - TR_CONSTEXPR20 explicit tr_file_priorities(tr_file_piece_map const* fpm) noexcept + TR_CONSTEXPR_VEC explicit tr_file_priorities(tr_file_piece_map const* fpm) noexcept : fpm_{ fpm } { } diff --git a/libtransmission/magnet-metainfo.h b/libtransmission/magnet-metainfo.h index 09e238b7a..d9f0ea67b 100644 --- a/libtransmission/magnet-metainfo.h +++ b/libtransmission/magnet-metainfo.h @@ -40,7 +40,7 @@ public: return std::size(webseed_urls_); } - [[nodiscard]] TR_CONSTEXPR20 auto const& webseed(size_t i) const + [[nodiscard]] TR_CONSTEXPR_VEC auto const& webseed(size_t i) const { return webseed_urls_.at(i); } diff --git a/libtransmission/makemeta.h b/libtransmission/makemeta.h index 98d3cffd5..f4cfbf631 100644 --- a/libtransmission/makemeta.h +++ b/libtransmission/makemeta.h @@ -127,7 +127,7 @@ public: return files_.file_count(); } - [[nodiscard]] TR_CONSTEXPR20 auto file_size(tr_file_index_t i) const noexcept + [[nodiscard]] TR_CONSTEXPR_VEC auto file_size(tr_file_index_t i) const noexcept { return files_.file_size(i); } @@ -142,7 +142,7 @@ public: return tr_sys_path_basename(top_); } - [[nodiscard]] auto const& path(tr_file_index_t i) const noexcept + [[nodiscard]] TR_CONSTEXPR_VEC auto const& path(tr_file_index_t i) const noexcept { return files_.path(i); } diff --git a/libtransmission/net.cc b/libtransmission/net.cc index 6ea5591b1..c8d1592a0 100644 --- a/libtransmission/net.cc +++ b/libtransmission/net.cc @@ -665,7 +665,7 @@ std::optional tr_address::from_ipv4_mapped() const noexcept // --- tr_socket_addrses -std::string tr_socket_address::display_name(tr_address const& address, tr_port port) noexcept +std::string tr_socket_address::display_name(tr_address const& address, tr_port port) { return fmt::format(fmt::runtime(address.is_ipv6() ? "[{:s}]:{:d}" : "{:s}:{:d}"), address.display_name(), port.host()); } diff --git a/libtransmission/net.h b/libtransmission/net.h index 40a8179cf..085b2f3af 100644 --- a/libtransmission/net.h +++ b/libtransmission/net.h @@ -427,9 +427,9 @@ struct tr_address switch (type) { case TR_AF_INET: - return tr_address{ TR_AF_INET, { { { { INADDR_ANY } } } } }; + return tr_address{ TR_AF_INET, { .addr4 = { INADDR_ANY } } }; case TR_AF_INET6: - return tr_address{ TR_AF_INET6, { IN6ADDR_ANY_INIT } }; + return tr_address{ TR_AF_INET6, { .addr6 = IN6ADDR_ANY_INIT } }; default: TR_ASSERT_MSG(false, "invalid type"); return tr_address{}; @@ -472,8 +472,8 @@ struct tr_socket_address return port_; } - [[nodiscard]] static std::string display_name(tr_address const& address, tr_port port) noexcept; - [[nodiscard]] auto display_name() const noexcept + [[nodiscard]] static std::string display_name(tr_address const& address, tr_port port); + [[nodiscard]] auto display_name() const { return display_name(address_, port_); } diff --git a/libtransmission/peer-mgr-wishlist.cc b/libtransmission/peer-mgr-wishlist.cc index 3051022d5..ca85b4e83 100644 --- a/libtransmission/peer-mgr-wishlist.cc +++ b/libtransmission/peer-mgr-wishlist.cc @@ -23,7 +23,7 @@ namespace { -[[nodiscard]] std::vector make_spans(small::vector const& blocks) +[[nodiscard]] TR_CONSTEXPR_VEC std::vector make_spans(small::vector const& blocks) { if (std::empty(blocks)) { @@ -34,7 +34,7 @@ namespace spans.reserve(std::size(blocks)); for (auto span_begin = std::begin(blocks), end = std::end(blocks); span_begin != end;) { - static auto constexpr NotAdjacent = [](tr_block_index_t const lhs, tr_block_index_t const rhs) + auto constexpr NotAdjacent = [](tr_block_index_t const lhs, tr_block_index_t const rhs) { return lhs + 1U != rhs; }; @@ -218,7 +218,7 @@ private: } } - TR_CONSTEXPR20 void reset_blocks_bitfield(tr_bitfield const& requests) + TR_CONSTEXPR_VEC void reset_blocks_bitfield(tr_bitfield const& requests) { for (auto& candidate : candidates_) { @@ -253,7 +253,7 @@ private: // --- - TR_CONSTEXPR20 void peer_disconnect(tr_bitfield const& have, tr_bitfield const& requests) + TR_CONSTEXPR_VEC void peer_disconnect(tr_bitfield const& have, tr_bitfield const& requests) { dec_replication_bitfield(have); reset_blocks_bitfield(requests); diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc index f86e7c831..c76ddd559 100644 --- a/libtransmission/peer-mgr.cc +++ b/libtransmission/peer-mgr.cc @@ -15,7 +15,6 @@ #include #include #include // std::tie -#include #include #include #include @@ -76,11 +75,11 @@ private: } return TorrentInfo{ - tor->info_hash(), // info_hash - tor->peer_id(), // client_peer_id - tor->id(), // id - tor->is_done(), // is_done - tor->is_running() // is_running + .info_hash = tor->info_hash(), + .client_peer_id = tor->peer_id(), + .id = tor->id(), + .is_done = tor->is_done(), + .is_running = tor->is_running(), }; } @@ -308,8 +307,8 @@ void tr_peer_info::update_canonical_priority() // FFFF:FFFF:FFFF:FFFF:5555:5555:5555:5555, etc... static auto constexpr MaskStartBaseOffset = std::array{ 2U, 6U }; auto const base_idx = MaskStartBaseOffset[type]; - auto const mismatch_idx = std::mismatch(first, second, second).first - first; - for (auto i = mismatch_idx >= base_idx ? mismatch_idx + 1 : base_idx; i < address_size; ++i) + auto const mismatch_idx = static_cast(std::mismatch(first, second, second).first - first); + for (auto i = mismatch_idx >= base_idx ? mismatch_idx + 1U : base_idx; i < address_size; ++i) { first[i] &= std::byte{ 0x55 }; second[i] &= std::byte{ 0x55 }; @@ -354,8 +353,7 @@ constexpr struct } template - [[nodiscard]] constexpr std::enable_if_t())>, tr_peer_info>, bool> - operator()(T const& a, T const& b) const noexcept + [[nodiscard]] constexpr bool operator()(T const& a, T const& b) const noexcept { return compare(*a, *b) < 0; } @@ -2460,9 +2458,7 @@ struct ComparePeerInfo } template - [[nodiscard]] std::enable_if_t())>, tr_peer_info>, bool> operator()( - T const& a, - T const& b) const noexcept + [[nodiscard]] bool operator()(T const& a, T const& b) const noexcept { return compare(*a, *b) < 0; } diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index fce79e5e6..e0c906d8f 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -2606,6 +2606,9 @@ using SessionAccessors = std::pair; [](tr_session const& /*src*/) -> tr_variant { return tr_variant::unmanaged_string(LONG_VERSION_STRING); }, nullptr); + // `row` could have been replaced by structured bindings, + // but it's not available until clang 16 + // https://github.com/llvm/llvm-project/commit/44f2baa3804a62ca793f0ff3e43aa71cea91a795 for (auto const& row : tr_session::Scripts) { auto const script = row.script; diff --git a/libtransmission/serializer.h b/libtransmission/serializer.h index 669174ca6..46f69be84 100644 --- a/libtransmission/serializer.h +++ b/libtransmission/serializer.h @@ -31,6 +31,7 @@ namespace detail // NOLINTBEGIN(readability-identifier-naming) // use std-style naming for these traits +// TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1 template using remove_cvref_t = std::remove_cv_t>; diff --git a/libtransmission/session-alt-speeds.cc b/libtransmission/session-alt-speeds.cc index f8002e615..ea14e41f0 100644 --- a/libtransmission/session-alt-speeds.cc +++ b/libtransmission/session-alt-speeds.cc @@ -77,7 +77,7 @@ void tr_session_alt_speeds::set_active(bool active, ChangeReason reason, bool fo } } -[[nodiscard]] bool tr_session_alt_speeds::is_active_minute(time_t time) const noexcept +[[nodiscard]] bool tr_session_alt_speeds::is_active_minute(time_t time) const { auto const tm = *std::localtime(&time); diff --git a/libtransmission/session-alt-speeds.h b/libtransmission/session-alt-speeds.h index 624a67a32..e7bf057de 100644 --- a/libtransmission/session-alt-speeds.h +++ b/libtransmission/session-alt-speeds.h @@ -189,7 +189,7 @@ private: void set_active(bool active, ChangeReason reason, bool force); // whether `time` hits in one of the `minutes_` that is true - [[nodiscard]] bool is_active_minute(time_t time) const noexcept; + [[nodiscard]] bool is_active_minute(time_t time) const; static int constexpr MinutesPerHour = 60; static int constexpr MinutesPerDay = MinutesPerHour * 24; diff --git a/libtransmission/session-id.cc b/libtransmission/session-id.cc index 71f8398e1..d319058a3 100644 --- a/libtransmission/session-id.cc +++ b/libtransmission/session-id.cc @@ -110,13 +110,14 @@ tr_session_id::session_id_t tr_session_id::make_session_id() return session_id; } +// NOLINTNEXTLINE(bugprone-exception-escape) tr_session_id::~tr_session_id() { destroy_lockfile(current_lock_file_, std::data(current_value_)); destroy_lockfile(previous_lock_file_, std::data(previous_value_)); } -bool tr_session_id::is_local(std::string_view session_id) noexcept +bool tr_session_id::is_local(std::string_view session_id) { if (std::empty(session_id)) { @@ -158,7 +159,7 @@ bool tr_session_id::is_local(std::string_view session_id) noexcept return is_local; } -std::string_view tr_session_id::sv() const noexcept +std::string_view tr_session_id::sv() const { if (auto const now = get_current_time_(); now >= expires_at_) { @@ -174,7 +175,7 @@ std::string_view tr_session_id::sv() const noexcept return std::string_view{ std::data(current_value_), std::size(current_value_) - 1 }; } -char const* tr_session_id::c_str() const noexcept +char const* tr_session_id::c_str() const { return std::data(sv()); // current_value_ is zero-terminated } diff --git a/libtransmission/session-id.h b/libtransmission/session-id.h index 3309b5c5c..eead896d0 100644 --- a/libtransmission/session-id.h +++ b/libtransmission/session-id.h @@ -36,11 +36,11 @@ public: * relative paths to absolute before passing through RPC, or presenting * different UI for local and remote sessions. */ - [[nodiscard]] static bool is_local(std::string_view session_id) noexcept; + [[nodiscard]] static bool is_local(std::string_view session_id); // current session identifier - [[nodiscard]] std::string_view sv() const noexcept; - [[nodiscard]] char const* c_str() const noexcept; + [[nodiscard]] std::string_view sv() const; + [[nodiscard]] char const* c_str() const; private: static auto constexpr SessionIdSize = size_t{ 48 }; diff --git a/libtransmission/session.h b/libtransmission/session.h index 469883b3f..85316239f 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -555,7 +555,7 @@ public: explicit tr_session(std::string_view config_dir, tr_variant const& settings_dict); - [[nodiscard]] std::string_view sessionId() const noexcept + [[nodiscard]] std::string_view sessionId() const { return session_id_.sv(); } diff --git a/libtransmission/torrent-files.h b/libtransmission/torrent-files.h index 9b3244402..671d42af1 100644 --- a/libtransmission/torrent-files.h +++ b/libtransmission/torrent-files.h @@ -40,7 +40,7 @@ public: return std::size(files_); } - [[nodiscard]] TR_CONSTEXPR20 uint64_t file_size(tr_file_index_t file_index) const + [[nodiscard]] TR_CONSTEXPR_VEC uint64_t file_size(tr_file_index_t file_index) const { return files_.at(file_index).size_; } @@ -50,7 +50,7 @@ public: return total_size_; } - [[nodiscard]] TR_CONSTEXPR20 std::string const& path(tr_file_index_t file_index) const + [[nodiscard]] TR_CONSTEXPR_VEC std::string const& path(tr_file_index_t file_index) const { return files_.at(file_index).path_; } @@ -71,17 +71,17 @@ public: } } - void reserve(size_t n_files) + TR_CONSTEXPR_VEC void reserve(size_t n_files) { files_.reserve(n_files); } - void shrink_to_fit() + TR_CONSTEXPR_VEC void shrink_to_fit() { files_.shrink_to_fit(); } - TR_CONSTEXPR20 void clear() noexcept + TR_CONSTEXPR_VEC void clear() noexcept { files_.clear(); total_size_ = uint64_t{}; @@ -102,7 +102,7 @@ public: return ret; } - tr_file_index_t add(std::string_view path, uint64_t file_size) + TR_CONSTEXPR_VEC tr_file_index_t add(std::string_view path, uint64_t file_size) { auto const ret = static_cast(std::size(files_)); files_.emplace_back(path, file_size); @@ -176,7 +176,7 @@ private: struct file_t { public: - void set_path(std::string_view subpath) + TR_CONSTEXPR_STR void set_path(std::string_view subpath) { if (path_ != subpath) { @@ -185,7 +185,7 @@ private: } } - file_t(std::string_view path, uint64_t size) + TR_CONSTEXPR_STR file_t(std::string_view path, uint64_t size) : path_{ path } , size_{ size } { diff --git a/libtransmission/torrent-magnet.h b/libtransmission/torrent-magnet.h index 84ba0ca7e..9f24322e0 100644 --- a/libtransmission/torrent-magnet.h +++ b/libtransmission/torrent-magnet.h @@ -48,7 +48,7 @@ public: return metadata_; } - [[nodiscard]] TR_CONSTEXPR20 std::string_view log_name() const noexcept + [[nodiscard]] TR_CONSTEXPR_STR std::string_view log_name() const noexcept { return log_name_; } diff --git a/libtransmission/torrent-metainfo.h b/libtransmission/torrent-metainfo.h index 0c7c9ffe5..a3e3569fb 100644 --- a/libtransmission/torrent-metainfo.h +++ b/libtransmission/torrent-metainfo.h @@ -46,11 +46,11 @@ public: { return files().file_count(); } - [[nodiscard]] TR_CONSTEXPR20 auto file_size(tr_file_index_t i) const + [[nodiscard]] TR_CONSTEXPR_VEC auto file_size(tr_file_index_t i) const { return files().file_size(i); } - [[nodiscard]] TR_CONSTEXPR20 auto const& file_subpath(tr_file_index_t i) const + [[nodiscard]] TR_CONSTEXPR_VEC auto const& file_subpath(tr_file_index_t i) const { return files().path(i); } @@ -132,7 +132,7 @@ public: return is_private_; } - [[nodiscard]] TR_CONSTEXPR20 tr_sha1_digest_t const& piece_hash(tr_piece_index_t piece) const + [[nodiscard]] TR_CONSTEXPR_VEC tr_sha1_digest_t const& piece_hash(tr_piece_index_t piece) const { return pieces_[piece]; } diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index 17a6c2f0f..712bfb206 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -1434,11 +1434,29 @@ tr_file_view tr_torrentFile(tr_torrent const* tor, tr_file_index_t file) if (tor->is_seed() || length == 0) { - return { subpath.c_str(), length, length, 1.0, begin, end, priority, wanted }; + return { + .name = subpath.c_str(), + .have = length, + .length = length, + .progress = 1.0, + .beginPiece = begin, + .endPiece = end, + .priority = priority, + .wanted = wanted, + }; } auto const have = tor->completion_.count_has_bytes_in_span(tor->byte_span_for_file(file)); - return { subpath.c_str(), have, length, have >= length ? 1.0 : have / double(length), begin, end, priority, wanted }; + return { + .name = subpath.c_str(), + .have = have, + .length = length, + .progress = have >= length ? 1.0 : have / double(length), + .beginPiece = begin, + .endPiece = end, + .priority = priority, + .wanted = wanted, + }; } size_t tr_torrentFileCount(tr_torrent const* torrent) @@ -1473,21 +1491,19 @@ size_t tr_torrentTrackerCount(tr_torrent const* tor) tr_torrent_view tr_torrentView(tr_torrent const* tor) { TR_ASSERT(tr_isTorrent(tor)); - - auto ret = tr_torrent_view{}; - ret.name = tor->name().c_str(); - ret.hash_string = tor->info_hash_string().c_str(); - ret.comment = tor->comment().c_str(); - ret.creator = tor->creator().c_str(); - ret.source = tor->source().c_str(); - ret.total_size = tor->total_size(); - ret.date_created = tor->date_created(); - ret.piece_size = tor->piece_size(); - ret.n_pieces = tor->piece_count(); - ret.is_private = tor->is_private(); - ret.is_folder = tor->file_count() > 1 || (tor->file_count() == 1 && tr_strv_contains(tor->file_subpath(0), '/')); - - return ret; + return { + .name = tor->name().c_str(), + .hash_string = tor->info_hash_string().c_str(), + .comment = tor->comment().c_str(), + .creator = tor->creator().c_str(), + .source = tor->source().c_str(), + .total_size = tor->total_size(), + .date_created = tor->date_created(), + .piece_size = tor->piece_size(), + .n_pieces = tor->piece_count(), + .is_private = tor->is_private(), + .is_folder = tor->file_count() > 1 || (tor->file_count() == 1 && tr_strv_contains(tor->file_subpath(0), '/')), + }; } std::string tr_torrentFilename(tr_torrent const* tor) diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index 2cef6059d..0e3147f8d 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -480,12 +480,12 @@ struct tr_torrent return metainfo_.file_count(); } - [[nodiscard]] TR_CONSTEXPR20 auto const& file_subpath(tr_file_index_t i) const + [[nodiscard]] TR_CONSTEXPR_VEC auto const& file_subpath(tr_file_index_t i) const { return metainfo_.file_subpath(i); } - [[nodiscard]] TR_CONSTEXPR20 auto file_size(tr_file_index_t i) const + [[nodiscard]] TR_CONSTEXPR_VEC auto file_size(tr_file_index_t i) const { return metainfo_.file_size(i); } @@ -517,7 +517,7 @@ struct tr_torrent return metainfo_.webseed_count(); } - [[nodiscard]] TR_CONSTEXPR20 auto const& webseed(size_t i) const + [[nodiscard]] TR_CONSTEXPR_VEC auto const& webseed(size_t i) const { return metainfo_.webseed(i); } @@ -1272,7 +1272,7 @@ private: // must be called after the torrent's announce list changes. void on_announce_list_changed(); - [[nodiscard]] TR_CONSTEXPR20 tr_byte_span_t byte_span_for_file(tr_file_index_t file) const + [[nodiscard]] TR_CONSTEXPR_VEC tr_byte_span_t byte_span_for_file(tr_file_index_t file) const { return fpm_.byte_span_for_file(file); } diff --git a/libtransmission/tr-buffer.h b/libtransmission/tr-buffer.h index 70da6fefe..c09ce4924 100644 --- a/libtransmission/tr-buffer.h +++ b/libtransmission/tr-buffer.h @@ -111,7 +111,7 @@ public: return {}; } - if (auto const n_sent = send(sockfd, reinterpret_cast(data()), n_bytes, 0); n_sent >= 0U) + if (auto const n_sent = send(sockfd, reinterpret_cast(data()), n_bytes, 0); n_sent >= 0) { drain(n_sent); return n_sent; diff --git a/libtransmission/tr-macros.h b/libtransmission/tr-macros.h index 8196bf20a..d85dff8d8 100644 --- a/libtransmission/tr-macros.h +++ b/libtransmission/tr-macros.h @@ -17,6 +17,18 @@ #define TR_CONSTEXPR20 #endif +#if __cpp_lib_constexpr_vector >= 201907L +#define TR_CONSTEXPR_VEC constexpr +#else +#define TR_CONSTEXPR_VEC +#endif + +#if __cpp_lib_constexpr_string >= 201907L +#define TR_CONSTEXPR_STR constexpr +#else +#define TR_CONSTEXPR_STR +#endif + #if __cplusplus >= 202302L // _MSVC_LANG value for C++23 not available yet #define TR_CONSTEXPR23 constexpr #else diff --git a/libtransmission/utils.h b/libtransmission/utils.h index 1a285426c..4fd5e6abd 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -114,33 +114,41 @@ template */ [[nodiscard]] bool tr_wildmat(char const* text, char const* pattern); +// c++23 (P1679R3), GCC 11.1, clang 12 template -[[nodiscard]] constexpr bool tr_strv_contains(std::string_view sv, T key) noexcept // c++23 +[[nodiscard]] constexpr bool tr_strv_contains(std::string_view sv, T key) noexcept { return sv.find(key) != std::string_view::npos; } -[[nodiscard]] constexpr bool tr_strv_starts_with(std::string_view sv, char key) // c++20 +// c++20 (P0457R2), GCC 9.1, clang 6 +[[nodiscard]] constexpr bool tr_strv_starts_with(std::string_view sv, char key) { return !std::empty(sv) && sv.front() == key; } -[[nodiscard]] constexpr bool tr_strv_starts_with(std::string_view sv, std::string_view key) // c++20 +// c++20 (P0457R2), GCC 9.1, clang 6 +[[nodiscard]] constexpr bool tr_strv_starts_with(std::string_view sv, std::string_view key) { return std::size(key) <= std::size(sv) && sv.substr(0, std::size(key)) == key; } -[[nodiscard]] constexpr bool tr_strv_starts_with(std::wstring_view sv, std::wstring_view key) // c++20 +// c++20 (P0457R2), GCC 9.1, clang 6 +[[nodiscard]] constexpr bool tr_strv_starts_with( + std::wstring_view sv, + std::wstring_view key) // c++20 (P0457R2), GCC 9.1, clang 6 { return std::size(key) <= std::size(sv) && sv.substr(0, std::size(key)) == key; } -[[nodiscard]] constexpr bool tr_strv_ends_with(std::string_view sv, std::string_view key) // c++20 +// c++20 (P0457R2), GCC 9.1, clang 6 +[[nodiscard]] constexpr bool tr_strv_ends_with(std::string_view sv, std::string_view key) { return std::size(key) <= std::size(sv) && sv.substr(std::size(sv) - std::size(key)) == key; } -[[nodiscard]] constexpr bool tr_strv_ends_with(std::string_view sv, char key) // c++20 +// c++20 (P0457R2), GCC 9.1, clang 6 +[[nodiscard]] constexpr bool tr_strv_ends_with(std::string_view sv, char key) { return !std::empty(sv) && sv.back() == key; } diff --git a/libtransmission/values.h b/libtransmission/values.h index 4f0b50331..5de5e6306 100644 --- a/libtransmission/values.h +++ b/libtransmission/values.h @@ -48,7 +48,7 @@ struct Config struct Units { template // NOLINTNEXTLINE(google-explicit-constructor, cppcoreguidelines-pro-type-member-init) - Units(Base base, Names... names) noexcept + Units(Base base, Names... names) { set_base(base); @@ -204,7 +204,7 @@ public: return compare(that) >= 0; } - std::string_view to_string(char* buf, size_t buflen) const noexcept + std::string_view to_string(char* buf, size_t buflen) const { auto idx = size_t{ 0 }; auto val = 1.0 * base_quantity_; diff --git a/libtransmission/variant.cc b/libtransmission/variant.cc index ba003d54b..48498c246 100644 --- a/libtransmission/variant.cc +++ b/libtransmission/variant.cc @@ -192,6 +192,7 @@ tr_variant& tr_variant::merge(tr_variant const& that) that.visit( [this](auto const& value) { + // TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1 using ValueType = std::decay_t; if constexpr ( diff --git a/libtransmission/variant.h b/libtransmission/variant.h index 92adff07f..9b90f2288 100644 --- a/libtransmission/variant.h +++ b/libtransmission/variant.h @@ -100,9 +100,9 @@ public: return Vector::const_iterator{ const_cast(this)->find(key) }; } - [[nodiscard]] auto contains(tr_quark const key) const noexcept + [[nodiscard]] TR_CONSTEXPR20 auto contains(tr_quark const key) const noexcept { - return find(key) != end(); // NOLINT(readability-container-contains) + return find(key) != end(); } [[nodiscard]] TR_CONSTEXPR20 auto size() const noexcept @@ -131,7 +131,7 @@ public: return 0U; } - bool replace_key(tr_quark const old_key, tr_quark const new_key) + TR_CONSTEXPR20 bool replace_key(tr_quark const old_key, tr_quark const new_key) { if (contains(new_key)) { @@ -309,6 +309,7 @@ public: template [[nodiscard]] constexpr auto* get_if() noexcept { + // TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1 static_assert( !std::is_same_v, std::string> && !std::is_same_v, std::string_view>, "not supported -- use value_if() instead."); @@ -318,6 +319,7 @@ public: template [[nodiscard]] constexpr auto const* get_if() const noexcept { + // TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1 static_assert( !std::is_same_v, std::string> && !std::is_same_v, std::string_view>, "not supported -- use value_if() instead."); diff --git a/macosx/CMakeLists.txt b/macosx/CMakeLists.txt index ce22180e4..a704e1136 100644 --- a/macosx/CMakeLists.txt +++ b/macosx/CMakeLists.txt @@ -9,8 +9,10 @@ find_program(CODESIGN_EXECUTABLE codesign REQUIRED) set(MAC_BUNDLE_NAME Transmission) add_compile_options( - $<$:-fmodules> - $<$:-fcxx-modules> + $<$:-fmodules> + + # https://github.com/llvm/llvm-project/issues/57432 + "$<$:-fno-modules;-Xclang;-fno-cxx-modules>" # equivalent of XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES for this directory $<$:-fobjc-arc> @@ -415,6 +417,7 @@ target_link_libraries(${TR_NAME}-mac "-framework Quartz" "-framework Security" "-weak_framework Sparkle" + "-weak_framework UniformTypeIdentifiers" "-weak_framework UserNotifications") if(NOT CMAKE_GENERATOR STREQUAL Xcode) diff --git a/macosx/Controller.mm b/macosx/Controller.mm index c129a6d77..462cdfba1 100644 --- a/macosx/Controller.mm +++ b/macosx/Controller.mm @@ -2,10 +2,17 @@ // It may be used under the MIT (SPDX: MIT) license. // License text can be found in the licenses/ folder. +#if __has_feature(modules) @import Carbon; @import UserNotifications; @import Sparkle; +#else +#import +#import + +#import +#endif #include /* atomic, atomic_fetch_add_explicit, memory_order_relaxed */ diff --git a/macosx/ExpandedPathToIconTransformer.mm b/macosx/ExpandedPathToIconTransformer.mm index 63b64bd49..f5186f971 100644 --- a/macosx/ExpandedPathToIconTransformer.mm +++ b/macosx/ExpandedPathToIconTransformer.mm @@ -2,7 +2,11 @@ // It may be used under the MIT (SPDX: MIT) license. // License text can be found in the licenses/ folder. +#if __has_feature(modules) @import AppKit; +#else +#import +#endif #import "ExpandedPathToIconTransformer.h" diff --git a/macosx/FileListNode.mm b/macosx/FileListNode.mm index 9a77477bd..ccaaea6d2 100644 --- a/macosx/FileListNode.mm +++ b/macosx/FileListNode.mm @@ -2,7 +2,11 @@ // It may be used under the MIT (SPDX: MIT) license. // License text can be found in the licenses/ folder. +#if __has_feature(modules) @import AppKit; +#else +#import +#endif #import "FileListNode.h" diff --git a/macosx/QuickLookExtension/CMakeLists.txt b/macosx/QuickLookExtension/CMakeLists.txt index 8043d2106..538b6d738 100644 --- a/macosx/QuickLookExtension/CMakeLists.txt +++ b/macosx/QuickLookExtension/CMakeLists.txt @@ -99,9 +99,11 @@ target_link_libraries(${TR_NAME}-mac-qlappex PRIVATE ${TR_NAME} "-framework Foundation" + "-framework AppKit" "-framework CoreFoundation" "-framework CoreServices" "-framework Quartz" + "-framework UniformTypeIdentifiers" "-framework QuickLook") install( diff --git a/macosx/QuickLookPlugin/GeneratePreviewForURL.mm b/macosx/QuickLookPlugin/GeneratePreviewForURL.mm index 4dd651a0b..d3d45bdbf 100644 --- a/macosx/QuickLookPlugin/GeneratePreviewForURL.mm +++ b/macosx/QuickLookPlugin/GeneratePreviewForURL.mm @@ -1,6 +1,12 @@ +#if __has_feature(modules) @import AppKit; @import CoreFoundation; @import QuickLook; +#else +#import +#import +#import +#endif #include #include diff --git a/macosx/QuickLookPlugin/GenerateThumbnailForURL.mm b/macosx/QuickLookPlugin/GenerateThumbnailForURL.mm index d97465565..934164401 100644 --- a/macosx/QuickLookPlugin/GenerateThumbnailForURL.mm +++ b/macosx/QuickLookPlugin/GenerateThumbnailForURL.mm @@ -1,5 +1,11 @@ +#if __has_feature(modules) @import CoreFoundation; @import QuickLook; +#else +#import +#import +#import +#endif QL_EXTERN_C_BEGIN OSStatus GenerateThumbnailForURL(void* thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize); diff --git a/macosx/SparkleProxy.mm b/macosx/SparkleProxy.mm index 496f43788..5f78a0f83 100644 --- a/macosx/SparkleProxy.mm +++ b/macosx/SparkleProxy.mm @@ -2,8 +2,13 @@ // It may be used under the MIT (SPDX: MIT) license. // License text can be found in the licenses/ folder. +#if __has_feature(modules) @import ObjectiveC; @import AppKit; +#else +#import +#import +#endif #import "NSStringAdditions.h" // Development-only proxy when app is not signed for running Sparkle diff --git a/macosx/main.mm b/macosx/main.mm index 396f5613b..0711709d5 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -2,7 +2,11 @@ // It may be used under the MIT (SPDX: MIT) license. // License text can be found in the licenses/ folder. +#if __has_feature(modules) @import AppKit; +#else +#import +#endif #include diff --git a/tests/libtransmission/.clang-tidy b/tests/libtransmission/.clang-tidy index 6b2af110a..d4cea88e3 100644 --- a/tests/libtransmission/.clang-tidy +++ b/tests/libtransmission/.clang-tidy @@ -3,6 +3,11 @@ HeaderFilterRegex: .*/tests/libtransmission/.* # Many of these checks are disabled only because the code hasn't been # cleaned up yet. Pull requests welcomed. +# +# -modernize-loop-convert (P0896R4): GCC 10.1, clang 15 +# -readability-container-contains (P0458R2): GCC 9.1, clang 13 +# Ref: https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html +# Ref: https://libcxx.llvm.org/Status/Cxx20.html Checks: > bugprone-*, -bugprone-easily-swappable-parameters, @@ -30,9 +35,13 @@ Checks: > -misc-no-recursion, -misc-non-private-member-variables-in-classes, modernize-*, + -modernize-loop-convert, + -modernize-use-designated-initializers, + -modernize-use-ranges, -modernize-use-trailing-return-type, performance-*, readability-*, + -readability-container-contains, -readability-enum-initial-value, -readability-function-cognitive-complexity, -readability-identifier-length, diff --git a/tests/libtransmission/announcer-udp-test.cc b/tests/libtransmission/announcer-udp-test.cc index e53ad18a5..53767fb23 100644 --- a/tests/libtransmission/announcer-udp-test.cc +++ b/tests/libtransmission/announcer-udp-test.cc @@ -635,35 +635,38 @@ TEST_F(AnnouncerUdpTest, canAnnounceIPv4) { tr_address::from_string("192.168.1.3"sv).value_or(tr_address{}), tr_port::from_host(2022) }, } }; - auto request = tr_announce_request{}; - request.event = TR_ANNOUNCE_EVENT_STARTED; - request.port = tr_port::from_host(80); - request.key = 0xCAFE; - request.numwant = 20; - request.up = 1; - request.down = 2; - request.corrupt = 3; - request.leftUntilComplete = 100; - request.announce_url = "https://127.0.0.1/announce"sv; - request.tracker_id = "fnord"s; - request.peer_id = tr_peerIdInit(); - request.info_hash = tr_rand_obj(); + auto const request = tr_announce_request{ + .event = TR_ANNOUNCE_EVENT_STARTED, + .port = tr_port::from_host(80), + .key = 0xCAFE, + .numwant = 20, + .up = 1, + .down = 2, + .corrupt = 3, + .leftUntilComplete = 100, + .announce_url = tr_interned_string{ "https://127.0.0.1/announce"sv }, + .tracker_id = "fnord"s, + .peer_id = tr_peerIdInit(), + .info_hash = tr_rand_obj(), + .log_name = {}, + }; - auto expected_response = tr_announce_response{}; - expected_response.info_hash = request.info_hash; - expected_response.did_connect = true; - expected_response.did_timeout = false; - expected_response.interval = Interval; - expected_response.min_interval = 0; // not specified in UDP announce - expected_response.seeders = Seeders; - expected_response.leechers = Leechers; - expected_response.downloads = std::nullopt; // not specified in UDP announce - expected_response.pex = std::vector{ tr_pex{ addresses[0] }, tr_pex{ addresses[1] }, tr_pex{ addresses[2] } }; - expected_response.pex6 = {}; - expected_response.errmsg = {}; - expected_response.warning = {}; - expected_response.tracker_id = {}; // not specified in UDP announce - expected_response.external_ip = {}; + auto const expected_response = tr_announce_response{ + .info_hash = request.info_hash, + .did_connect = true, + .did_timeout = false, + .interval = Interval, + .min_interval = 0, // not specified in UDP announce + .seeders = Seeders, + .leechers = Leechers, + .downloads = std::nullopt, // not specified in UDP announce + .pex = std::vector{ tr_pex{ addresses[0] }, tr_pex{ addresses[1] }, tr_pex{ addresses[2] } }, + .pex6 = {}, + .errmsg = {}, + .warning = {}, + .tracker_id = {}, // not specified in UDP announce + .external_ip = {}, + }; // build the announcer auto mediator = MockMediator{}; @@ -718,35 +721,38 @@ TEST_F(AnnouncerUdpTest, canAnnounceIPv6) { tr_address::from_string("fd12:3456:789a:1::3"sv).value_or(tr_address{}), tr_port::from_host(2022) }, } }; - auto request = tr_announce_request{}; - request.event = TR_ANNOUNCE_EVENT_STARTED; - request.port = tr_port::from_host(80); - request.key = 0xCAFE; - request.numwant = 20; - request.up = 1; - request.down = 2; - request.corrupt = 3; - request.leftUntilComplete = 100; - request.announce_url = "https://[::1]/announce"sv; - request.tracker_id = "fnord"s; - request.peer_id = tr_peerIdInit(); - request.info_hash = tr_rand_obj(); + auto const request = tr_announce_request{ + .event = TR_ANNOUNCE_EVENT_STARTED, + .port = tr_port::from_host(80), + .key = 0xCAFE, + .numwant = 20, + .up = 1, + .down = 2, + .corrupt = 3, + .leftUntilComplete = 100, + .announce_url = tr_interned_string{ "https://[::1]/announce"sv }, + .tracker_id = "fnord"s, + .peer_id = tr_peerIdInit(), + .info_hash = tr_rand_obj(), + .log_name = {}, + }; - auto expected_response = tr_announce_response{}; - expected_response.info_hash = request.info_hash; - expected_response.did_connect = true; - expected_response.did_timeout = false; - expected_response.interval = Interval; - expected_response.min_interval = 0; // not specified in UDP announce - expected_response.seeders = Seeders; - expected_response.leechers = Leechers; - expected_response.downloads = std::nullopt; // not specified in UDP announce - expected_response.pex = {}; - expected_response.pex6 = std::vector{ tr_pex{ addresses[0] }, tr_pex{ addresses[1] }, tr_pex{ addresses[2] } }; - expected_response.errmsg = {}; - expected_response.warning = {}; - expected_response.tracker_id = {}; // not specified in UDP announce - expected_response.external_ip = {}; + auto const expected_response = tr_announce_response{ + .info_hash = request.info_hash, + .did_connect = true, + .did_timeout = false, + .interval = Interval, + .min_interval = 0, // not specified in UDP announce + .seeders = Seeders, + .leechers = Leechers, + .downloads = std::nullopt, // not specified in UDP announce + .pex = {}, + .pex6 = std::vector{ tr_pex{ addresses[0] }, tr_pex{ addresses[1] }, tr_pex{ addresses[2] } }, + .errmsg = {}, + .warning = {}, + .tracker_id = {}, // not specified in UDP announce + .external_ip = {}, + }; // build the announcer auto mediator = MockMediator{}; diff --git a/tests/libtransmission/handshake-test.cc b/tests/libtransmission/handshake-test.cc index 8c9e60ce8..943230081 100644 --- a/tests/libtransmission/handshake-test.cc +++ b/tests/libtransmission/handshake-test.cc @@ -147,16 +147,20 @@ public: static auto constexpr PlaintextProtocolName = "\023BitTorrent protocol"sv; tr_socket_address const DefaultPeerSockAddr{ *tr_address::from_string("127.0.0.1"sv), tr_port::from_host(8080) }; - tr_handshake::Mediator::TorrentInfo const TorrentWeAreSeeding{ tr_sha1::digest("abcde"sv), - tr_peerIdInit(), - tr_torrent_id_t{ 100 }, - true /*is_done*/, - true /*is_running*/ }; - tr_handshake::Mediator::TorrentInfo const UbuntuTorrent{ *tr_sha1_from_string("2c6b6858d61da9543d4231a71db4b1c9264b0685"sv), - tr_peerIdInit(), - tr_torrent_id_t{ 101 }, - false /*is_done*/, - true /*is_running*/ }; + tr_handshake::Mediator::TorrentInfo const TorrentWeAreSeeding{ + .info_hash = tr_sha1::digest("abcde"sv), + .client_peer_id = tr_peerIdInit(), + .id = tr_torrent_id_t{ 100 }, + .is_done = true, + .is_running = true, + }; + tr_handshake::Mediator::TorrentInfo const UbuntuTorrent{ + .info_hash = *tr_sha1_from_string("2c6b6858d61da9543d4231a71db4b1c9264b0685"sv), + .client_peer_id = tr_peerIdInit(), + .id = tr_torrent_id_t{ 101 }, + .is_done = false, + .is_running = true, + }; auto createIncomingIo(tr_session* session) { diff --git a/tests/libtransmission/variant-test.cc b/tests/libtransmission/variant-test.cc index 329e8c503..c7ae1b43a 100644 --- a/tests/libtransmission/variant-test.cc +++ b/tests/libtransmission/variant-test.cc @@ -735,6 +735,7 @@ TEST_F(VariantTest, visitsNodesDepthFirst) node.visit( [&](auto const& val) { + // TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1 using ValueType = std::decay_t; if constexpr (