Skip to content

Commit

Permalink
refactor: make code compatible for cppcheck (#75)
Browse files Browse the repository at this point in the history
- add a CI job for it
  • Loading branch information
Viatorus authored Nov 2, 2023
1 parent cc0ac15 commit 3452749
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 10 deletions.
1 change: 1 addition & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Checks: >
-cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-avoid-do-while,
-cppcoreguidelines-avoid-const-or-ref-data-members,
-misc-include-cleaner,
WarningsAsErrors: ''
Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ jobs:
echo "CC=gcc-11" >> $GITHUB_ENV
echo "CXX=g++-11" >> $GITHUB_ENV
- name: Install cppcheck
run: |
sudo apt update && sudo apt install -y cppcheck
cppcheck --version
- name: Install clang-format and clang-tidy
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
Expand All @@ -34,7 +39,9 @@ jobs:
- name: Run clang-format
run: cmake -D FORMAT_COMMAND=clang-format -P cmake/lint.cmake

- name: Run clang-tidy
- name: Run cppcheck and clang-tidy
# Cppcheck's checks are disabled. They are mostly redundant to clang-tidy and there are too many false positives.
# But the parsing of cppcheck is kept to be compatible with its compiler frontend.
if: ${{ !cancelled() }}
run: |
cmake --preset=ci-checks
Expand Down
3 changes: 2 additions & 1 deletion CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"name": "cppcheck",
"hidden": true,
"cacheVariables": {
"CMAKE_CXX_CPPCHECK": "cppcheck;--inline-suppr"
"CMAKE_CXX_CPPCHECK": "cppcheck;--error-exitcode=13"
}
},
{
Expand Down Expand Up @@ -171,6 +171,7 @@
"ci-build",
"ci-unix",
"clang-tidy",
"cppcheck",
"dev-mode"
]
},
Expand Down
10 changes: 8 additions & 2 deletions include/emio/detail/format/formatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -790,10 +790,16 @@ concept has_validate_function_v = requires {
{ formatter<T>::validate(std::declval<reader&>()) } -> std::same_as<result<void>>;
};

template <typename T>
concept has_static_validate_function_v = requires { &formatter<T>::validate; };

template <typename T>
concept has_member_validate_function_v = requires { std::declval<formatter<T>>().validate(std::declval<reader&>()); };

template <typename T>
concept has_any_validate_function_v =
requires { &formatter<T>::validate; } || std::is_member_function_pointer_v<decltype(&formatter<T>::validate)> ||
requires { std::declval<formatter<T>>().validate(std::declval<reader&>()); };
has_static_validate_function_v<T> || std::is_member_function_pointer_v<decltype(&formatter<T>::validate)> ||
has_member_validate_function_v<T>;

template <typename T>
inline constexpr bool is_core_type_v =
Expand Down
1 change: 1 addition & 0 deletions include/emio/detail/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ int is_arg_span2(const args_span<T>& t);
bool is_arg_span2(...);

template <typename T>
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): only used within type traits
constexpr bool is_args_span = sizeof(is_arg_span2(std::declval<T>())) == sizeof(int);

template <typename CRTP, input_validation Validation>
Expand Down
10 changes: 8 additions & 2 deletions include/emio/detail/scan/scanner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,16 @@ concept has_validate_function_v = requires {
{ scanner<T>::validate(std::declval<reader&>()) } -> std::same_as<result<void>>;
};

template <typename T>
concept has_static_validate_function_v = requires { &scanner<T>::validate; };

template <typename T>
concept has_member_validate_function_v = requires { std::declval<scanner<T>>().validate(std::declval<reader&>()); };

template <typename T>
concept has_any_validate_function_v =
requires { &scanner<T>::validate; } || std::is_member_function_pointer_v<decltype(&scanner<T>::validate)> ||
requires { std::declval<scanner<T>>().validate(std::declval<reader&>()); };
has_static_validate_function_v<T> || std::is_member_function_pointer_v<decltype(&scanner<T>::validate)> ||
has_member_validate_function_v<T>;

template <typename T>
inline constexpr bool is_core_type_v =
Expand Down
2 changes: 2 additions & 0 deletions include/emio/detail/validated_string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class validated_string : public validated_string_storage {
template <typename S>
requires(std::is_constructible_v<std::string_view, S>)
consteval validated_string(const S& s) noexcept
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): can construct a std::string_view
: validated_string_storage{validated_string_storage::from<Trait, Args...>(s)} {
if (get().has_error()) {
std::terminate();
Expand All @@ -88,6 +89,7 @@ class validated_string : public validated_string_storage {
* Returns format/scan string as valid one.
* @return The valid format/scan string or invalid_format if the validation failed.
*/
// NOLINTNEXTLINE(modernize-use-nodiscard): result<...> is already declared with nodiscard
constexpr result<valid_string<Trait, Args...>> as_valid() const noexcept {
if (get().has_value()) {
return valid_string<Trait, Args...>{*this};
Expand Down
5 changes: 2 additions & 3 deletions include/emio/ranges.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,8 @@ class formatter<T> {
static constexpr result<void> validate_for_each(std::index_sequence<Ns...> /*unused*/, reader& format_rdr) noexcept {
size_t reader_pos = 0;
result<void> res = success;
const auto validate = [&reader_pos, &res]<typename U>(std::type_identity<U> /*unused*/,
reader r /*copy!*/) noexcept {
res = U::validate(r);
const auto validate = [&reader_pos, &res](const auto type_identity, reader r /*copy!*/) noexcept {
res = decltype(type_identity)::type::validate(r);
if (res.has_error()) {
return false;
}
Expand Down
22 changes: 21 additions & 1 deletion test/static_analysis/test_main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
// Include all.
#include <emio/emio.hpp> // NOLINT(misc-include-cleaner): required to parse all headers with static analysers
#include <emio/emio.hpp>

consteval emio::result<void> compile_time_test() {
emio::static_buffer<128> buf;
EMIO_TRYV(emio::format_to(buf, "abc"));
return emio::format_to(buf, "abc {}", 13);
}

emio::result<void> test() {
EMIO_TRYV(compile_time_test());
if (emio::format("abc").size() != 3) {
return emio::err::invalid_data;
}
if (emio::format("{}", "abc").size() != 3) {
return emio::err::invalid_data;
}
return emio::format(emio::runtime("abc {}"), 13);
}

int main() {
if (test().has_error()) {
return 1;
}
return 0;
}

0 comments on commit 3452749

Please sign in to comment.