Add CI configuration for clang-tidy on Windows (#6997)

* Add CI configuration for clang-tidy on Windows

* Fix issues reported by clang-tidy on Windows

* Workaround clang-tidy defects on Windows

* Fix C-style casts (which clang-tidy didn't report)
This commit is contained in:
Mike Gelfand 2024-07-16 22:13:29 +01:00 committed by GitHub
parent e334f3c37f
commit c21ee87eea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 331 additions and 218 deletions

View File

@ -0,0 +1,61 @@
name: Prepare Win32 build dependencies
inputs:
arch:
description: Architecture (x86, x64)
required: true
type:
description: Type (CoreDeps, Deps)
required: true
runs:
using: composite
steps:
- name: Get Build Tools
shell: pwsh
run: |
$DepsPrefix = (Join-Path (Get-Item .).Root.Name "${{ inputs.arch }}-prefix")
"DEPS_PREFIX=${DepsPrefix}" | Out-File $Env:GITHUB_ENV -Append
(Join-Path $DepsPrefix bin) | Out-File $Env:GITHUB_PATH -Append
choco install `
jom `
nasm `
nodejs
& "C:\Program Files\OpenSSL\unins000.exe" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- | Out-Host
(Join-Path $Env:ProgramFiles NASM) | Out-File $Env:GITHUB_PATH -Append
(Join-Path (Get-Item -Path "${Env:ProgramFiles(x86)}\WiX Toolset v3.*")[0].FullName bin) | Out-File $Env:GITHUB_PATH -Append
Install-Module -Name Pscx -RequiredVersion 4.0.0-beta4 -AllowPrerelease -Force
- name: Get Cache Key
id: cache-key
shell: pwsh
run: |
try {
$DepsHash = & (Join-Path . src release windows main.ps1) -Mode DepsHash -BuildArch ${{ inputs.arch }} -BuildPart ${{ inputs.type }}
"hash=${DepsHash}" | Out-File $Env:GITHUB_OUTPUT -Append
} catch {
Write-Error ("{1}{0}{2}{0}{3}" -f [Environment]::NewLine, $_.ToString(), $_.InvocationInfo.PositionMessage, $_.ScriptStackTrace) -ErrorAction Continue
exit 1
}
- name: Restore Cache
uses: actions/cache/restore@v4
id: restore-cache
with:
path: ${{ env.DEPS_PREFIX }}
key: ${{ github.job }}-${{ inputs.arch }}-${{ steps.cache-key.outputs.hash }}
- name: Build Dependencies
if: steps.restore-cache.outputs.cache-hit != 'true'
shell: pwsh
run: |
try {
& (Join-Path . src release windows main.ps1) -Mode Build -BuildArch ${{ inputs.arch }} -BuildPart ${{ inputs.type }}
} catch {
Write-Error ("{1}{0}{2}{0}{3}" -f [Environment]::NewLine, $_.ToString(), $_.InvocationInfo.PositionMessage, $_.ScriptStackTrace) -ErrorAction Continue
exit 1
}
- name: Save Cache
if: steps.restore-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
id: cache
with:
path: ${{ env.DEPS_PREFIX }}
key: ${{ github.job }}-${{ inputs.arch }}-${{ steps.cache-key.outputs.hash }}

View File

@ -272,6 +272,43 @@ jobs:
run: |
if grep 'warning:' makelog; then exit 1; fi
clang-tidy-libtransmission-win32:
runs-on: windows-2022
needs: [ what-to-make ]
if: ${{ needs.what-to-make.outputs.test-style == 'true' }}
steps:
- name: Show Configuration
run: |
echo '${{ toJSON(needs) }}'
echo '${{ toJSON(runner) }}'
- name: Get Source
uses: actions/checkout@v4
with:
submodules: recursive
path: src
- name: Prepare Build Deps
uses: ./src/.github/actions/prepare-deps-win32
with:
arch: x64
type: CoreDeps
- name: Configure
run: |
Import-VisualStudioVars -VisualStudioVersion 2022 -Architecture x64
cmake `
-S src `
-B obj `
-G Ninja `
-DCMAKE_BUILD_TYPE=Debug `
-DCMAKE_PREFIX_PATH="${Env:DEPS_PREFIX}" `
-DRUN_CLANG_TIDY=ON
- name: Make
run: |
Import-VisualStudioVars -VisualStudioVersion 2022 -Architecture x64
cmake --build obj --config Debug --target transmission.lib 2>&1 | tee makelog
- name: Test for warnings
run: |
if (Select-String -Path makelog -Pattern 'warning:') { exit 1 }
macos-14-arm64:
runs-on: macos-14
needs: [ what-to-make ]
@ -458,51 +495,16 @@ jobs:
run: |
echo '${{ toJSON(needs) }}'
echo '${{ toJSON(runner) }}'
- name: Get Build Tools
run: |
$DepsPrefix = (Join-Path (Get-Item .).Root.Name "${{ matrix.arch }}-prefix")
"DEPS_PREFIX=${DepsPrefix}" | Out-File $Env:GITHUB_ENV -Append
(Join-Path $DepsPrefix bin) | Out-File $Env:GITHUB_PATH -Append
choco install `
jom `
nasm `
nodejs
& "C:\Program Files\OpenSSL\unins000.exe" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- | Out-Host
(Join-Path $Env:ProgramFiles NASM) | Out-File $Env:GITHUB_PATH -Append
(Join-Path (Get-Item -Path "${Env:ProgramFiles(x86)}\WiX Toolset v3.*")[0].FullName bin) | Out-File $Env:GITHUB_PATH -Append
Install-Module -Name Pscx -RequiredVersion 4.0.0-beta4 -AllowPrerelease -Force
- name: Get Source
uses: actions/checkout@v4
with:
path: src
submodules: recursive
- name: Get Cache Key
id: cache-key
run: |
try {
$DepsHash = & (Join-Path . src release windows main.ps1) -Mode DepsHash -BuildArch ${{ matrix.arch }}
"hash=${DepsHash}" | Out-File $Env:GITHUB_OUTPUT -Append
} catch {
Write-Error ("{1}{0}{2}{0}{3}" -f [Environment]::NewLine, $_.ToString(), $_.InvocationInfo.PositionMessage, $_.ScriptStackTrace) -ErrorAction Continue
exit 1
}
- name: Get Cache
uses: actions/cache@v4
id: cache
- name: Prepare Build Deps
uses: ./src/.github/actions/prepare-deps-win32
with:
path: ${{ env.DEPS_PREFIX }}
key: ${{ github.job }}-${{ matrix.arch }}-${{ steps.cache-key.outputs.hash }}
- name: Build Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: |
try {
& (Join-Path . src release windows main.ps1) -Mode Build -BuildArch ${{ matrix.arch }} -BuildPart Deps
} catch {
Write-Error ("{1}{0}{2}{0}{3}" -f [Environment]::NewLine, $_.ToString(), $_.InvocationInfo.PositionMessage, $_.ScriptStackTrace) -ErrorAction Continue
exit 1
}
arch: ${{ matrix.arch }}
type: Deps
- name: Configure
run: |
Import-VisualStudioVars -VisualStudioVersion 2022 -Architecture ${{ matrix.arch }}

View File

@ -14,20 +14,32 @@
#define ERROR_DIRECTORY_NOT_SUPPORTED 336
#endif
#define TR_ERROR_IS_ENOENT(code) ((code) == ERROR_FILE_NOT_FOUND || (code) == ERROR_PATH_NOT_FOUND)
#define TR_ERROR_IS_ENOSPC(code) ((code) == ERROR_DISK_FULL)
#define TR_ERROR_EINVAL ERROR_INVALID_PARAMETER
#define TR_ERROR_EISDIR ERROR_DIRECTORY_NOT_SUPPORTED
#else /* _WIN32 */
#include <errno.h>
#define TR_ERROR_IS_ENOENT(code) ((code) == ENOENT)
#define TR_ERROR_IS_ENOSPC(code) ((code) == ENOSPC)
#include <cerrno>
#define TR_ERROR_EINVAL EINVAL
#define TR_ERROR_EISDIR EISDIR
#endif /* _WIN32 */
constexpr inline bool tr_error_is_enoent(int code) noexcept
{
#ifdef _WIN32
return code == ERROR_FILE_NOT_FOUND || code == ERROR_PATH_NOT_FOUND;
#else
return code == ENOENT;
#endif
}
constexpr inline bool tr_error_is_enospc(int code) noexcept
{
#ifdef _WIN32
return code == ERROR_DISK_FULL;
#else
return code == ENOSPC;
#endif
}

View File

@ -452,13 +452,13 @@ extern "C"
if (auto const wide_path = tr_win32_utf8_to_native(path); !std::empty(wide_path))
{
ULARGE_INTEGER freeBytesAvailable;
ULARGE_INTEGER totalBytesAvailable;
ULARGE_INTEGER free_bytes_available;
ULARGE_INTEGER total_bytes_available;
if (GetDiskFreeSpaceExW(wide_path.c_str(), &freeBytesAvailable, &totalBytesAvailable, nullptr))
if (GetDiskFreeSpaceExW(wide_path.c_str(), &free_bytes_available, &total_bytes_available, nullptr) != 0)
{
ret.free = freeBytesAvailable.QuadPart;
ret.total = totalBytesAvailable.QuadPart;
ret.free = free_bytes_available.QuadPart;
ret.total = total_bytes_available.QuadPart;
}
}

View File

@ -27,14 +27,6 @@
using namespace std::literals;
#ifndef MAXSIZE_T
#define MAXSIZE_T ((SIZE_T) ~((SIZE_T)0))
#endif
/* MSDN (http://msdn.microsoft.com/en-us/library/2k2xf226.aspx) only mentions
"i64" suffix for C code, but no warning is issued */
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
struct tr_sys_dir_win32
{
std::wstring pattern;
@ -45,6 +37,8 @@ struct tr_sys_dir_win32
namespace
{
auto constexpr DeltaEpochInMicrosecs = UINT64_C(11644473600000000);
auto constexpr NativeLocalPathPrefix = L"\\\\?\\"sv;
auto constexpr NativeUncPathPrefix = L"\\\\?\\UNC\\"sv;
@ -72,11 +66,16 @@ constexpr time_t filetime_to_unix_time(FILETIME const& t)
tmp <<= 32;
tmp |= t.dwLowDateTime;
tmp /= 10; /* to microseconds */
tmp -= DELTA_EPOCH_IN_MICROSECS;
tmp -= DeltaEpochInMicrosecs;
return tmp / 1000000UL;
}
constexpr bool to_bool(BOOL value) noexcept
{
return value != FALSE;
}
constexpr auto stat_to_sys_path_info(DWORD attributes, DWORD size_low, DWORD size_high, FILETIME const& mtime)
{
auto info = tr_sys_path_info{};
@ -103,7 +102,7 @@ constexpr auto stat_to_sys_path_info(DWORD attributes, DWORD size_low, DWORD siz
return info;
}
auto constexpr Slashes = "\\/"sv;
auto constexpr Slashes = R"(\/)"sv;
constexpr bool is_slash(char c)
{
@ -119,27 +118,22 @@ bool is_valid_path(std::string_view path)
{
if (is_unc_path(path))
{
if (path[2] != '\0' && !isalnum(path[2]))
if (path[2] != '\0' && isalnum(path[2]) == 0)
{
return false;
}
}
else
else if (auto const pos = path.find(':'); pos != std::string_view::npos)
{
auto pos = path.find(':');
if (pos != path.npos)
{
if (pos != 1 || !isalpha(path[0]))
if (pos != 1 || isalpha(path[0]) == 0)
{
return false;
}
path.remove_prefix(2);
}
}
return path.find_first_of("<>:\"|?*"sv) == path.npos;
return path.find_first_of(R"(<>:"|?*)"sv) == std::string_view::npos;
}
auto path_to_fixed_native_path(std::string_view path)
@ -200,7 +194,7 @@ std::string native_path_to_path(std::wstring_view wide_path)
{
wide_path.remove_prefix(std::size(NativeUncPathPrefix));
auto path = tr_win32_native_to_utf8(wide_path);
path.insert(0, "\\\\"sv);
path.insert(0, R"(\\)"sv);
return path;
}
@ -239,7 +233,7 @@ tr_sys_file_t open_file(std::string_view path, DWORD access, DWORD disposition,
bool create_dir(std::string_view path, int flags, int /*permissions*/, bool okay_if_exists, tr_error* error)
{
bool ret;
bool ret = false;
DWORD error_code = ERROR_SUCCESS;
auto const wide_path = path_to_native_path(path);
@ -256,7 +250,7 @@ bool create_dir(std::string_view path, int flags, int /*permissions*/, bool okay
}
else
{
ret = CreateDirectoryW(wide_path.c_str(), nullptr);
ret = to_bool(CreateDirectoryW(wide_path.c_str(), nullptr));
if (!ret)
{
@ -282,14 +276,10 @@ bool create_dir(std::string_view path, int flags, int /*permissions*/, bool okay
return ret;
}
void create_temp_path(
char* path_template,
void (*callback)(char const* path, void* param, tr_error* error),
void* callback_param,
tr_error* error)
template<typename CallbackT>
void create_temp_path(char* path_template, CallbackT&& callback, tr_error* error)
{
TR_ASSERT(path_template != nullptr);
TR_ASSERT(callback != nullptr);
auto path = std::string{ path_template };
auto path_size = std::size(path);
@ -313,7 +303,7 @@ void create_temp_path(
local_error = {};
(*callback)(path.c_str(), callback_param, &local_error);
callback(path.c_str(), &local_error);
if (!local_error)
{
@ -336,7 +326,7 @@ std::optional<tr_sys_path_info> tr_sys_file_get_info_(tr_sys_file_t handle, tr_e
TR_ASSERT(handle != TR_BAD_SYS_FILE);
auto attributes = BY_HANDLE_FILE_INFORMATION{};
if (GetFileInformationByHandle(handle, &attributes))
if (to_bool(GetFileInformationByHandle(handle, &attributes)))
{
return stat_to_sys_path_info(
attributes.dwFileAttributes,
@ -367,7 +357,7 @@ std::optional<BY_HANDLE_FILE_INFORMATION> get_file_info(char const* path, tr_err
// TODO: Use GetFileInformationByHandleEx on >= Server 2012
auto info = BY_HANDLE_FILE_INFORMATION{};
if (!GetFileInformationByHandle(handle, &info))
if (!to_bool(GetFileInformationByHandle(handle, &info)))
{
set_system_error_if_file_found(error, GetLastError());
CloseHandle(handle);
@ -378,23 +368,6 @@ std::optional<BY_HANDLE_FILE_INFORMATION> get_file_info(char const* path, tr_err
return info;
}
void file_open_temp_callback(char const* path, void* param, tr_error* error)
{
auto* const result = static_cast<tr_sys_file_t*>(param);
TR_ASSERT(result != nullptr);
*result = open_file(path, GENERIC_READ | GENERIC_WRITE, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, error);
}
void dir_create_temp_callback(char const* path, void* param, tr_error* error)
{
auto* const result = static_cast<bool*>(param);
TR_ASSERT(result != nullptr);
*result = create_dir(path, 0, 0, false, error);
}
} // namespace
bool tr_sys_path_exists(char const* path, tr_error* error)
@ -406,7 +379,7 @@ bool tr_sys_path_exists(char const* path, tr_error* error)
if (auto const wide_path = path_to_native_path(path); !std::empty(wide_path))
{
DWORD attributes = GetFileAttributesW(wide_path.c_str());
DWORD const attributes = GetFileAttributesW(wide_path.c_str());
if (attributes != INVALID_FILE_ATTRIBUTES)
{
@ -444,7 +417,7 @@ std::optional<tr_sys_path_info> tr_sys_path_get_info(std::string_view path, int
else if ((flags & TR_SYS_PATH_NO_FOLLOW) != 0)
{
auto attributes = WIN32_FILE_ATTRIBUTE_DATA{};
if (GetFileAttributesExW(wide_path.c_str(), GetFileExInfoStandard, &attributes))
if (to_bool(GetFileAttributesExW(wide_path.c_str(), GetFileExInfoStandard, &attributes)))
{
return stat_to_sys_path_info(
attributes.dwFileAttributes,
@ -475,13 +448,13 @@ bool tr_sys_path_is_relative(std::string_view path)
}
/* Local path: `X:` */
if (std::size(path) == 2 && isalpha(path[0]) && path[1] == ':')
if (std::size(path) == 2 && isalpha(path[0]) != 0 && path[1] == ':')
{
return false;
}
/* Local path: `X:\...`. */
if (std::size(path) > 2 && isalpha(path[0]) && path[1] == ':' && is_slash(path[2]))
if (std::size(path) > 2 && isalpha(path[0]) != 0 && path[1] == ':' && is_slash(path[2]))
{
return false;
}
@ -584,15 +557,18 @@ std::string_view tr_sys_path_basename(std::string_view path, tr_error* error)
return !std::empty(path) ? path : "/"sv;
}
[[nodiscard]] static bool isWindowsDeviceRoot(char ch) noexcept
namespace
{
[[nodiscard]] bool isWindowsDeviceRoot(char ch) noexcept
{
return isalpha(static_cast<int>(ch)) != 0;
}
[[nodiscard]] static constexpr bool isPathSeparator(char ch) noexcept
[[nodiscard]] constexpr bool isPathSeparator(char ch) noexcept
{
return ch == '/' || ch == '\\';
}
} // namespace
// This function is adapted from Node.js's path.win32.dirname() function,
// which is copyrighted by Joyent, Inc. and other Node contributors
@ -674,7 +650,7 @@ std::string_view tr_sys_path_dirname(std::string_view path)
}
auto end = std::string_view::npos;
auto matched_slash = bool{ true };
auto matched_slash = true;
for (std::string_view::size_type i = len - 1; i >= offset; --i)
{
if (isPathSeparator(path[i]))
@ -720,25 +696,19 @@ bool tr_sys_path_rename(char const* src_path, char const* dst_path, tr_error* er
if (!std::empty(wide_src_path) && !std::empty(wide_dst_path))
{
DWORD flags = MOVEFILE_REPLACE_EXISTING;
DWORD attributes;
attributes = GetFileAttributesW(wide_src_path.c_str());
if (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
if (auto const src_attributes = GetFileAttributesW(wide_src_path.c_str());
src_attributes != INVALID_FILE_ATTRIBUTES && (src_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
flags = 0;
}
else
{
attributes = GetFileAttributesW(wide_dst_path.c_str());
if (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
else if (auto const dst_attributes = GetFileAttributesW(wide_dst_path.c_str());
dst_attributes != INVALID_FILE_ATTRIBUTES && (dst_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
flags = 0;
}
}
ret = MoveFileExW(wide_src_path.c_str(), wide_dst_path.c_str(), flags);
ret = to_bool(MoveFileExW(wide_src_path.c_str(), wide_dst_path.c_str(), flags));
}
if (!ret)
@ -764,7 +734,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error* erro
auto cancel = BOOL{ FALSE };
DWORD const flags = COPY_FILE_ALLOW_DECRYPTED_DESTINATION | COPY_FILE_FAIL_IF_EXISTS;
if (CopyFileExW(wide_src_path.c_str(), wide_dst_path.c_str(), nullptr, nullptr, &cancel, flags) == 0)
if (!to_bool(CopyFileExW(wide_src_path.c_str(), wide_dst_path.c_str(), nullptr, nullptr, &cancel, flags)))
{
set_system_error(error, GetLastError());
return false;
@ -787,11 +757,11 @@ bool tr_sys_path_remove(char const* path, tr_error* error)
{
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
ret = RemoveDirectoryW(wide_path.c_str());
ret = to_bool(RemoveDirectoryW(wide_path.c_str()));
}
else
{
ret = DeleteFileW(wide_path.c_str());
ret = to_bool(DeleteFileW(wide_path.c_str()));
}
}
}
@ -824,11 +794,9 @@ tr_sys_file_t tr_sys_file_open(char const* path, int flags, int /*permissions*/,
TR_ASSERT(path != nullptr);
TR_ASSERT((flags & (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE)) != 0);
tr_sys_file_t ret;
DWORD native_access = 0;
DWORD native_disposition = OPEN_EXISTING;
DWORD native_flags = FILE_ATTRIBUTE_NORMAL;
bool success;
if ((flags & TR_SYS_FILE_READ) != 0)
{
@ -854,9 +822,8 @@ tr_sys_file_t tr_sys_file_open(char const* path, int flags, int /*permissions*/,
native_flags |= FILE_FLAG_SEQUENTIAL_SCAN;
}
ret = open_file(path, native_access, native_disposition, native_flags, error);
success = ret != TR_BAD_SYS_FILE;
auto ret = open_file(path, native_access, native_disposition, native_flags, error);
auto success = ret != TR_BAD_SYS_FILE;
if (success && (flags & TR_SYS_FILE_APPEND) != 0)
{
@ -880,7 +847,11 @@ tr_sys_file_t tr_sys_file_open_temp(char* path_template, tr_error* error)
tr_sys_file_t ret = TR_BAD_SYS_FILE;
create_temp_path(path_template, file_open_temp_callback, &ret, error);
create_temp_path(
path_template,
[&ret](char const* path, tr_error* error)
{ ret = open_file(path, GENERIC_READ | GENERIC_WRITE, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, error); },
error);
return ret;
}
@ -889,7 +860,7 @@ bool tr_sys_file_close(tr_sys_file_t handle, tr_error* error)
{
TR_ASSERT(handle != TR_BAD_SYS_FILE);
bool ret = CloseHandle(handle);
bool const ret = to_bool(CloseHandle(handle));
if (!ret)
{
@ -911,9 +882,9 @@ bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_
}
bool ret = false;
DWORD my_bytes_read;
DWORD my_bytes_read = 0;
if (ReadFile(handle, buffer, (DWORD)size, &my_bytes_read, nullptr))
if (to_bool(ReadFile(handle, buffer, static_cast<DWORD>(size), &my_bytes_read, nullptr)))
{
if (bytes_read != nullptr)
{
@ -948,15 +919,14 @@ bool tr_sys_file_read_at(
}
bool ret = false;
OVERLAPPED overlapped;
DWORD my_bytes_read;
auto overlapped = OVERLAPPED{};
DWORD my_bytes_read = 0;
overlapped.Offset = (DWORD)offset;
offset >>= 32;
overlapped.OffsetHigh = (DWORD)offset;
overlapped.Offset = static_cast<DWORD>(offset);
overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
overlapped.hEvent = nullptr;
if (ReadFile(handle, buffer, (DWORD)size, &my_bytes_read, &overlapped))
if (to_bool(ReadFile(handle, buffer, static_cast<DWORD>(size), &my_bytes_read, &overlapped)))
{
if (bytes_read != nullptr)
{
@ -985,9 +955,9 @@ bool tr_sys_file_write(tr_sys_file_t handle, void const* buffer, uint64_t size,
}
bool ret = false;
DWORD my_bytes_written;
DWORD my_bytes_written = 0;
if (WriteFile(handle, buffer, (DWORD)size, &my_bytes_written, nullptr))
if (to_bool(WriteFile(handle, buffer, static_cast<DWORD>(size), &my_bytes_written, nullptr)))
{
if (bytes_written != nullptr)
{
@ -1022,15 +992,14 @@ bool tr_sys_file_write_at(
}
bool ret = false;
OVERLAPPED overlapped;
DWORD my_bytes_written;
auto overlapped = OVERLAPPED{};
DWORD my_bytes_written = 0;
overlapped.Offset = (DWORD)offset;
offset >>= 32;
overlapped.OffsetHigh = (DWORD)offset;
overlapped.Offset = static_cast<DWORD>(offset);
overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
overlapped.hEvent = nullptr;
if (WriteFile(handle, buffer, (DWORD)size, &my_bytes_written, &overlapped))
if (to_bool(WriteFile(handle, buffer, static_cast<DWORD>(size), &my_bytes_written, &overlapped)))
{
if (bytes_written != nullptr)
{
@ -1054,7 +1023,7 @@ bool tr_sys_file_truncate(tr_sys_file_t handle, uint64_t size, tr_error* error)
FILE_END_OF_FILE_INFO info;
info.EndOfFile.QuadPart = size;
bool ret = SetFileInformationByHandle(handle, FileEndOfFileInfo, &info, sizeof(info));
bool const ret = to_bool(SetFileInformationByHandle(handle, FileEndOfFileInfo, &info, sizeof(info)));
if (!ret)
{
@ -1070,9 +1039,9 @@ bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, tr_
if ((flags & TR_SYS_FILE_PREALLOC_SPARSE) != 0)
{
DWORD tmp;
DWORD tmp = 0;
if (!DeviceIoControl(handle, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &tmp, nullptr))
if (!to_bool(DeviceIoControl(handle, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &tmp, nullptr)))
{
set_system_error(error, GetLastError());
return false;
@ -1089,7 +1058,7 @@ bool tr_sys_file_lock(tr_sys_file_t handle, int operation, tr_error* error)
TR_ASSERT(
!!(operation & TR_SYS_FILE_LOCK_SH) + !!(operation & TR_SYS_FILE_LOCK_EX) + !!(operation & TR_SYS_FILE_LOCK_UN) == 1);
bool ret;
bool ret = false;
auto overlapped = OVERLAPPED{};
if ((operation & TR_SYS_FILE_LOCK_UN) == 0)
@ -1150,7 +1119,10 @@ bool tr_sys_dir_create_temp(char* path_template, tr_error* error)
bool ret = false;
create_temp_path(path_template, dir_create_temp_callback, &ret, error);
create_temp_path(
path_template,
[&ret](char const* path, tr_error* error) { ret = create_dir(path, 0, 0, false, error); },
error);
return ret;
}
@ -1195,7 +1167,7 @@ char const* tr_sys_dir_read_name(tr_sys_dir_t handle, tr_error* error)
}
else
{
if (!FindNextFileW(handle->find_handle, &handle->find_data))
if (!to_bool(FindNextFileW(handle->find_handle, &handle->find_data)))
{
error_code = GetLastError();
}
@ -1221,7 +1193,7 @@ bool tr_sys_dir_close(tr_sys_dir_t handle, tr_error* error)
{
TR_ASSERT(handle != TR_BAD_SYS_DIR);
bool ret = FindClose(handle->find_handle);
bool const ret = to_bool(FindClose(handle->find_handle));
if (!ret)
{

View File

@ -46,7 +46,7 @@ bool preallocate_file_sparse(tr_sys_file_t fd, uint64_t length, tr_error* error)
tr_logAddDebug(fmt::format("Fast preallocation failed: {} ({})", local_error.message(), local_error.code()));
if (!TR_ERROR_IS_ENOSPC(local_error.code()))
if (!tr_error_is_enospc(local_error.code()))
{
static char constexpr Zero = '\0';
@ -86,7 +86,7 @@ bool preallocate_file_full(tr_sys_file_t fd, uint64_t length, tr_error* error)
tr_logAddDebug(fmt::format("Full preallocation failed: {} ({})", local_error.message(), local_error.code()));
if (!TR_ERROR_IS_ENOSPC(local_error.code()))
if (!tr_error_is_enospc(local_error.code()))
{
auto buf = std::array<uint8_t, 4096>{};
bool success = true;

View File

@ -26,12 +26,12 @@ struct tr_peer;
class ActiveRequests::Impl
{
public:
size_t size() const
[[nodiscard]] size_t size() const
{
return size_;
}
size_t count(tr_peer const* peer) const
[[nodiscard]] size_t count(tr_peer const* peer) const
{
auto const it = count_.find(peer);
return it != std::end(count_) ? it->second : size_t{};

View File

@ -608,40 +608,40 @@ private:
// ---
size_t protocol_send_keepalive() const;
size_t protocol_send_keepalive() const; // NOLINT(modernize-use-nodiscard)
template<typename... Args>
size_t protocol_send_message(uint8_t type, Args const&... args) const;
size_t protocol_send_reject(peer_request const& req) const
size_t protocol_send_reject(peer_request const& req) const // NOLINT(modernize-use-nodiscard)
{
TR_ASSERT(io_->supports_fext());
return protocol_send_message(BtPeerMsgs::FextReject, req.index, req.offset, req.length);
}
size_t protocol_send_cancel(peer_request const& req) const
size_t protocol_send_cancel(peer_request const& req) const // NOLINT(modernize-use-nodiscard)
{
return protocol_send_message(BtPeerMsgs::Cancel, req.index, req.offset, req.length);
}
size_t protocol_send_request(peer_request const& req) const
size_t protocol_send_request(peer_request const& req) const // NOLINT(modernize-use-nodiscard)
{
TR_ASSERT(is_valid_request(req));
return protocol_send_message(BtPeerMsgs::Request, req.index, req.offset, req.length);
}
size_t protocol_send_dht_port(tr_port const port) const
size_t protocol_send_dht_port(tr_port const port) const // NOLINT(modernize-use-nodiscard)
{
return protocol_send_message(BtPeerMsgs::DhtPort, port.host());
}
size_t protocol_send_have(tr_piece_index_t const index) const
size_t protocol_send_have(tr_piece_index_t const index) const // NOLINT(modernize-use-nodiscard)
{
static_assert(sizeof(tr_piece_index_t) == sizeof(uint32_t));
return protocol_send_message(BtPeerMsgs::Have, index);
}
size_t protocol_send_choke(bool const choke) const
size_t protocol_send_choke(bool const choke) const // NOLINT(modernize-use-nodiscard)
{
return protocol_send_message(choke ? BtPeerMsgs::Choke : BtPeerMsgs::Unchoke);
}

View File

@ -54,7 +54,7 @@ namespace
#ifdef _WIN32
std::string win32_get_known_folder_ex(REFKNOWNFOLDERID folder_id, DWORD flags)
{
if (PWSTR path; SHGetKnownFolderPath(folder_id, flags | KF_FLAG_DONT_UNEXPAND, nullptr, &path) == S_OK)
if (PWSTR path = nullptr; SHGetKnownFolderPath(folder_id, flags | KF_FLAG_DONT_UNEXPAND, nullptr, &path) == S_OK)
{
auto ret = tr_win32_native_to_utf8(path);
CoTaskMemFree(path);

View File

@ -128,7 +128,7 @@ bool tr_session_id::is_local(std::string_view session_id) noexcept
auto error = tr_error{};
if (auto lockfile_fd = tr_sys_file_open(lockfile_path, TR_SYS_FILE_READ, 0, &error); lockfile_fd == TR_BAD_SYS_FILE)
{
if (TR_ERROR_IS_ENOENT(error.code()))
if (tr_error_is_enoent(error.code()))
{
error = {};
}

View File

@ -101,10 +101,19 @@ int cond_wait(void* vcond, void* vlock, struct timeval const* tv)
return success == std::cv_status::timeout ? 1 : 0;
}
#if defined(_WIN32) && defined(__clang_analyzer__)
// See https://github.com/llvm/llvm-project/issues/98823
#define WORKAROUND_CLANG_TIDY_GH98823
#endif
unsigned long thread_current_id()
{
#ifndef WORKAROUND_CLANG_TIDY_GH98823
thread_local auto const hashed = std::hash<std::thread::id>()(std::this_thread::get_id());
return hashed;
#else
return 0;
#endif
}
void init_evthreads_once()

View File

@ -11,7 +11,6 @@
#include <functional>
#include <memory>
#include <tuple>
#include <utility>
struct event_base;

View File

@ -29,7 +29,7 @@ using namespace std::literals;
namespace
{
enum class tr_app_type
enum class tr_app_type : uint8_t
{
EXE,
BATCH
@ -52,17 +52,22 @@ void set_system_error(tr_error* error, DWORD code, std::string_view what)
}
}
constexpr bool to_bool(BOOL value) noexcept
{
return value != FALSE;
}
// "The sort is case-insensitive, Unicode order, without regard to locale" © MSDN
class WStrICompare
{
public:
[[nodiscard]] auto compare(std::wstring_view a, std::wstring_view b) const noexcept // <=>
[[nodiscard]] static auto compare(std::wstring_view a, std::wstring_view b) noexcept // <=>
{
int diff = wcsnicmp(std::data(a), std::data(b), std::min(std::size(a), std::size(b)));
if (diff == 0)
{
diff = std::size(a) < std::size(b) ? -1 : (std::size(a) > std::size(b) ? 1 : 0);
diff = tr_compare_3way(std::size(a), std::size(b));
}
return diff;
@ -178,6 +183,9 @@ void append_argument(std::string& arguments, char const* argument)
case '"':
backslash_count = backslash_count * 2 + 1;
break;
default:
break;
}
if (backslash_count != 0)
@ -298,7 +306,7 @@ bool tr_spawn_async(
PROCESS_INFORMATION pi;
bool const ret = CreateProcessW(
bool const ret = to_bool(CreateProcessW(
nullptr,
std::data(cmd_line),
nullptr,
@ -308,7 +316,7 @@ bool tr_spawn_async(
std::empty(full_env) ? nullptr : to_env_string(full_env).data(),
std::empty(current_dir) ? nullptr : current_dir.c_str(),
&si,
&pi);
&pi));
if (ret)
{

View File

@ -90,6 +90,7 @@ extern "C"
int dht_sendto(int sockfd, void const* buf, int len, int flags, struct sockaddr const* to, int tolen)
{
// NOLINTNEXTLINE(readability-redundant-casting)
return static_cast<int>(sendto(sockfd, static_cast<char const*>(buf), len, flags, to, tolen));
}

View File

@ -75,21 +75,32 @@ Config::Units<StorageUnits> Config::Storage{ Config::Base::Kilo, "B"sv, "kB"sv,
// ---
#if defined(_WIN32) && defined(__clang_analyzer__)
// See https://github.com/llvm/llvm-project/issues/44701
#define WORKAROUND_CLANG_TIDY_GH44701
#endif
std::optional<std::locale> tr_locale_set_global(char const* locale_name) noexcept
{
#ifndef WORKAROUND_CLANG_TIDY_GH44701
try
#endif
{
return tr_locale_set_global(std::locale{ locale_name });
}
#ifndef WORKAROUND_CLANG_TIDY_GH44701
catch (std::runtime_error const&)
{
return {};
}
#endif
}
std::optional<std::locale> tr_locale_set_global(std::locale const& locale) noexcept
{
#ifndef WORKAROUND_CLANG_TIDY_GH44701
try
#endif
{
auto old_locale = std::locale::global(locale);
@ -98,10 +109,12 @@ std::optional<std::locale> tr_locale_set_global(std::locale const& locale) noexc
return old_locale;
}
#ifndef WORKAROUND_CLANG_TIDY_GH44701
catch (std::exception const&)
{
return {};
}
#endif
}
// ---
@ -336,7 +349,7 @@ std::string tr_win32_format_message(uint32_t code)
nullptr,
code,
0,
(LPWSTR)&wide_text,
reinterpret_cast<LPWSTR>(&wide_text),
0,
nullptr);
@ -355,7 +368,7 @@ std::string tr_win32_format_message(uint32_t code)
LocalFree(wide_text);
// Most (all?) messages contain "\r\n" in the end, chop it
while (!std::empty(text) && isspace(text.back()))
while (!std::empty(text) && isspace(text.back()) != 0)
{
text.resize(text.size() - 1);
}
@ -370,7 +383,7 @@ namespace tr_main_win32_impl
std::optional<std::vector<std::string>> win32MakeUtf8Argv()
{
int argc;
int argc = 0;
auto argv = std::vector<std::string>{};
if (wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); wargv != nullptr)
{
@ -390,7 +403,7 @@ std::optional<std::vector<std::string>> win32MakeUtf8Argv()
argv.emplace_back(std::move(str));
}
LocalFree(wargv);
LocalFree(reinterpret_cast<HLOCAL>(wargv));
}
if (static_cast<int>(std::size(argv)) == argc)

View File

@ -34,6 +34,11 @@ namespace libtransmission
namespace
{
constexpr bool to_bool(BOOL value) noexcept
{
return value != FALSE;
}
BOOL tr_get_overlapped_result_ex(
HANDLE handle,
LPOVERLAPPED overlapped,
@ -48,7 +53,7 @@ BOOL tr_get_overlapped_result_ex(
if (!is_real_impl_valid)
{
real_impl = (impl_t)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetOverlappedResultEx");
real_impl = reinterpret_cast<impl_t>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetOverlappedResultEx"));
is_real_impl_valid = true;
}
@ -142,14 +147,15 @@ private:
return;
}
if ((fd_ = CreateFileW(
fd_ = CreateFileW(
wide_path.c_str(),
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
nullptr)) == INVALID_HANDLE_VALUE)
nullptr);
if (fd_ == INVALID_HANDLE_VALUE)
{
tr_logAddError(fmt::format(_("Couldn't read '{path}'"), fmt::arg("path", path)));
return;
@ -157,7 +163,15 @@ private:
overlapped_.Pointer = this;
if (!ReadDirectoryChangesW(fd_, buffer_, sizeof(buffer_), false, Win32WatchMask, nullptr, &overlapped_, nullptr))
if (!to_bool(ReadDirectoryChangesW(
fd_,
std::data(buffer_),
std::size(buffer_),
FALSE,
Win32WatchMask,
nullptr,
&overlapped_,
nullptr)))
{
tr_logAddError(fmt::format(_("Couldn't read '{path}'"), fmt::arg("path", path)));
return;
@ -188,7 +202,8 @@ private:
bufferevent_setcb(event_, &Win32Watchdir::onBufferEvent, nullptr, nullptr, this);
bufferevent_enable(event_, EV_READ);
thread_ = (HANDLE)_beginthreadex(nullptr, 0, Win32Watchdir::staticThreadFunc, this, 0, nullptr);
// NOLINTNEXTLINE(performance-no-int-to-ptr)
thread_ = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, Win32Watchdir::staticThreadFunc, this, 0, nullptr));
if (thread_ == nullptr)
{
tr_logAddError(_("Couldn't create thread"));
@ -203,22 +218,31 @@ private:
unsigned int threadFunc()
{
DWORD bytes_transferred;
DWORD bytes_transferred = 0;
while (tr_get_overlapped_result_ex(fd_, &overlapped_, &bytes_transferred, INFINITE, FALSE))
while (to_bool(tr_get_overlapped_result_ex(fd_, &overlapped_, &bytes_transferred, INFINITE, FALSE)))
{
PFILE_NOTIFY_INFORMATION info = (PFILE_NOTIFY_INFORMATION)buffer_;
auto* info = reinterpret_cast<PFILE_NOTIFY_INFORMATION>(std::data(buffer_));
while (info->NextEntryOffset != 0)
{
*((BYTE**)&info) += info->NextEntryOffset;
*reinterpret_cast<BYTE**>(&info) += info->NextEntryOffset;
}
info->NextEntryOffset = bytes_transferred - ((BYTE*)info - (BYTE*)buffer_);
info->NextEntryOffset = bytes_transferred -
(reinterpret_cast<BYTE*>(info) - reinterpret_cast<BYTE*>(std::data(buffer_)));
send(notify_pipe_[1], (char const*)buffer_, bytes_transferred, 0);
send(notify_pipe_[1], reinterpret_cast<char const*>(std::data(buffer_)), bytes_transferred, 0);
if (!ReadDirectoryChangesW(fd_, buffer_, sizeof(buffer_), FALSE, Win32WatchMask, nullptr, &overlapped_, nullptr))
if (!to_bool(ReadDirectoryChangesW(
fd_,
std::data(buffer_),
std::size(buffer_),
FALSE,
Win32WatchMask,
nullptr,
&overlapped_,
nullptr)))
{
tr_logAddError(_("Couldn't read directory changes"));
return 0;
@ -249,7 +273,7 @@ private:
auto buffer = std::vector<char>{};
buffer.resize(sizeof(FILE_NOTIFY_INFORMATION) + name_size);
PFILE_NOTIFY_INFORMATION ev = (PFILE_NOTIFY_INFORMATION)std::data(buffer);
auto* ev = reinterpret_cast<PFILE_NOTIFY_INFORMATION>(std::data(buffer));
size_t const header_size = offsetof(FILE_NOTIFY_INFORMATION, FileName);
@ -263,7 +287,7 @@ private:
break;
}
if (nread == (size_t)-1)
if (nread == static_cast<size_t>(-1))
{
auto const error_code = errno;
tr_logAddError(fmt::format(
@ -292,12 +316,12 @@ private:
{
name_size = nleft;
buffer.resize(sizeof(FILE_NOTIFY_INFORMATION) + name_size);
ev = (PFILE_NOTIFY_INFORMATION)std::data(buffer);
ev = reinterpret_cast<PFILE_NOTIFY_INFORMATION>(std::data(buffer));
}
// consume entire name into buffer
nread = bufferevent_read(event, &buffer[header_size], nleft);
if (nread == (size_t)-1)
if (nread == static_cast<size_t>(-1))
{
auto const error_code = errno;
tr_logAddError(fmt::format(
@ -330,7 +354,7 @@ private:
HANDLE fd_ = INVALID_HANDLE_VALUE;
OVERLAPPED overlapped_ = {};
DWORD buffer_[8 * 1024 / sizeof(DWORD)];
std::array<DWORD, 8 * 1024 / sizeof(DWORD)> buffer_ = {};
std::array<evutil_socket_t, 2> notify_pipe_{ static_cast<evutil_socket_t>(-1), static_cast<evutil_socket_t>(-1) };
struct bufferevent* event_ = nullptr;
HANDLE thread_ = {};
@ -342,9 +366,9 @@ std::unique_ptr<Watchdir> Watchdir::create(
std::string_view dirname,
Callback callback,
TimerMaker& timer_maker,
struct event_base* event_base)
struct event_base* evbase)
{
return std::make_unique<Win32Watchdir>(dirname, std::move(callback), timer_maker, event_base);
return std::make_unique<Win32Watchdir>(dirname, std::move(callback), timer_maker, evbase);
}
} // namespace libtransmission

View File

@ -46,7 +46,7 @@ namespace
auto error = tr_error{};
auto const info = tr_sys_path_get_info(path, 0, &error);
if (error && !TR_ERROR_IS_ENOENT(error.code()))
if (error && !tr_error_is_enoent(error.code()))
{
tr_logAddWarn(fmt::format(
_("Skipping '{path}': {error} ({error_code})"),

View File

@ -129,7 +129,7 @@ CURLcode ssl_context_func(CURL* /*curl*/, void* ssl_ctx, void* /*user_data*/)
for (auto& sys_store_name : SysStoreNames)
{
HCERTSTORE const sys_cert_store = CertOpenSystemStoreW(0, sys_store_name);
auto* const sys_cert_store = CertOpenSystemStoreW(0, sys_store_name);
if (sys_cert_store == nullptr)
{
continue;
@ -145,7 +145,7 @@ CURLcode ssl_context_func(CURL* /*curl*/, void* ssl_ctx, void* /*user_data*/)
break;
}
tr_x509_cert_t const cert = tr_x509_cert_new(sys_cert->pbCertEncoded, sys_cert->cbCertEncoded);
auto* const cert = tr_x509_cert_new(sys_cert->pbCertEncoded, sys_cert->cbCertEncoded);
if (cert == nullptr)
{
continue;
@ -406,7 +406,7 @@ public:
// if unset: steady-state, all is good
// if set: do not accept new tasks
// if set and deadline reached: kill all remaining tasks
std::atomic<time_t> deadline_ = {};
std::atomic<time_t> deadline_ = {}; // NOLINT(readability-redundant-member-init)
[[nodiscard]] auto deadline() const
{

View File

@ -10,7 +10,7 @@ Param(
[string] $BuildArch,
[Parameter()]
[ValidateSet('All', 'Deps', 'App')]
[ValidateSet('All', 'CoreDeps', 'Deps', 'App')]
[string] $BuildPart = 'All',
[Parameter()]
@ -258,14 +258,23 @@ if (-not $SourceDir) {
if ($Mode -eq 'DepsHash') {
Import-Script Toolchain
$Names = @(
Invoke-Build Expat -CacheArchiveNameOnly
Invoke-Build DBus -CacheArchiveNameOnly
$Names = @()
if (@('All', 'CoreDeps', 'Deps') -contains $BuildPart) {
$Names = $Names + @(
Invoke-Build Zlib -CacheArchiveNameOnly
Invoke-Build OpenSsl -CacheArchiveNameOnly
Invoke-Build Curl -CacheArchiveNameOnly
)
}
if (@('All', 'Deps') -contains $BuildPart) {
$Names = $Names + @(
Invoke-Build Expat -CacheArchiveNameOnly
Invoke-Build DBus -CacheArchiveNameOnly
Invoke-Build Qt$UseQtVersion -CacheArchiveNameOnly
)
}
Write-Output (Get-StringHash ($Names -join ':'))
}
@ -285,12 +294,15 @@ if ($Mode -eq 'Build') {
$Env:CMAKE_CXX_COMPILER_LAUNCHER = ''
}
if (@('All', 'Deps') -contains $BuildPart) {
Invoke-Build Expat
Invoke-Build DBus
if (@('All', 'CoreDeps', 'Deps') -contains $BuildPart) {
Invoke-Build Zlib
Invoke-Build OpenSsl
Invoke-Build Curl
}
if (@('All', 'Deps') -contains $BuildPart) {
Invoke-Build Expat
Invoke-Build DBus
Invoke-Build Qt$UseQtVersion
}