diff --git a/CMakeLists.txt b/CMakeLists.txt index ce03c9756..515621160 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,9 +28,10 @@ option(SOURCEMETA_CORE_CONTRIB_GOOGLEBENCHMARK "Build the GoogleBenchmark librar include(Sourcemeta) -# Don't force downstream consumers on it +# Don't force downstream consumers on this if(PROJECT_IS_TOP_LEVEL) sourcemeta_enable_simd() + sourcemeta_clang_tidy_attempt_enable() endif() # TODO: Turn this into a re-usable utility CMake function @@ -116,11 +117,13 @@ if(SOURCEMETA_CORE_DOCS) endif() if(PROJECT_IS_TOP_LEVEL) + # TODO: Try once more to enable this per target, + # so, we don't need to manually disable it here + sourcemeta_clang_tidy_attempt_disable() sourcemeta_target_clang_format(SOURCES src/*.h src/*.cc benchmark/*.h benchmark/*.cc test/*.h test/*.cc) - sourcemeta_target_clang_tidy(SOURCES src/*.cc) endif() # Testing diff --git a/Makefile b/Makefile index d447bd57a..9c166e3fd 100644 --- a/Makefile +++ b/Makefile @@ -25,9 +25,6 @@ compile: .always $(CMAKE) --install ./build --prefix ./build/dist --config $(PRESET) --verbose \ --component sourcemeta_core_dev -lint: .always - $(CMAKE) --build ./build --config $(PRESET) --target clang_tidy - test: .always $(CMAKE) -E env UBSAN_OPTIONS=print_stacktrace=1 \ $(CTEST) --test-dir ./build --build-config $(PRESET) \ diff --git a/cmake/Sourcemeta.cmake b/cmake/Sourcemeta.cmake index b75c969c1..50fb7b33e 100644 --- a/cmake/Sourcemeta.cmake +++ b/cmake/Sourcemeta.cmake @@ -10,11 +10,11 @@ include("${SOURCEMETA_UTILITIES_DIRECTORY}/commands/copy-file.cmake") include("${SOURCEMETA_UTILITIES_DIRECTORY}/targets/library.cmake") include("${SOURCEMETA_UTILITIES_DIRECTORY}/targets/executable.cmake") include("${SOURCEMETA_UTILITIES_DIRECTORY}/targets/clang-format.cmake") -include("${SOURCEMETA_UTILITIES_DIRECTORY}/targets/clang-tidy.cmake") include("${SOURCEMETA_UTILITIES_DIRECTORY}/targets/shellcheck.cmake") include("${SOURCEMETA_UTILITIES_DIRECTORY}/targets/doxygen.cmake") include("${SOURCEMETA_UTILITIES_DIRECTORY}/targets/googletest.cmake") include("${SOURCEMETA_UTILITIES_DIRECTORY}/targets/googlebenchmark.cmake") +include("${SOURCEMETA_UTILITIES_DIRECTORY}/clang-tidy.cmake") # To let downstream projects directly include this file if(NOT PROJECT_IS_TOP_LEVEL) diff --git a/cmake/common/targets/clang-tidy.cmake b/cmake/common/clang-tidy.cmake similarity index 81% rename from cmake/common/targets/clang-tidy.cmake rename to cmake/common/clang-tidy.cmake index 47954d1d0..f4b3d657f 100644 --- a/cmake/common/targets/clang-tidy.cmake +++ b/cmake/common/clang-tidy.cmake @@ -1,4 +1,4 @@ -function(sourcemeta_target_clang_tidy_attempt_install) +function(sourcemeta_clang_tidy_attempt_install) cmake_parse_arguments(SOURCEMETA_TARGET_CLANG_TIDY_ATTEMPT_INSTALL "" "OUTPUT_DIRECTORY" "" ${ARGN}) if(NOT SOURCEMETA_TARGET_CLANG_TIDY_ATTEMPT_INSTALL_OUTPUT_DIRECTORY) message(FATAL_ERROR "You must pass the output directory in the OUTPUT_DIRECTORY option") @@ -76,9 +76,17 @@ function(sourcemeta_target_clang_tidy_attempt_install) message(STATUS "Installed `clang-tidy` pre-built binary to ${CLANG_TIDY_BINARY_OUTPUT}") endfunction() -function(sourcemeta_target_clang_tidy) - cmake_parse_arguments(SOURCEMETA_TARGET_CLANG_TIDY "REQUIRED" "" "SOURCES" ${ARGN}) - sourcemeta_target_clang_tidy_attempt_install(OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") +function(sourcemeta_clang_tidy_attempt_enable) + cmake_parse_arguments(SOURCEMETA_TARGET_CLANG_TIDY "REQUIRED" "" "" ${ARGN}) + + if(SOURCEMETA_COMPILER_LLVM) + message(STATUS "Enabling ClangTidy alongside compilation") + else() + message(STATUS "Ignoring ClangTidy setup on a compiler other than LLVM") + return() + endif() + + sourcemeta_clang_tidy_attempt_install(OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") if(SOURCEMETA_TARGET_CLANG_TIDY_REQUIRED) find_program(CLANG_TIDY_BIN NAMES clang-tidy NO_DEFAULT_PATH @@ -94,37 +102,24 @@ function(sourcemeta_target_clang_tidy) endif() endif() - - # This covers the empty list too - if(NOT SOURCEMETA_TARGET_CLANG_TIDY_SOURCES) - message(FATAL_ERROR "You must pass file globs to analyze in the SOURCES option") - endif() - file(GLOB_RECURSE SOURCEMETA_TARGET_CLANG_TIDY_FILES - ${SOURCEMETA_TARGET_CLANG_TIDY_SOURCES}) - set(CLANG_TIDY_CONFIG "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/clang-tidy.config") - if(CMAKE_SYSTEM_NAME STREQUAL "MSYS") - # Because `clang-tidy` is typically a Windows `.exe`, transform the path accordingly - execute_process(COMMAND cygpath -w "${CLANG_TIDY_CONFIG}" - OUTPUT_VARIABLE CLANG_TIDY_CONFIG OUTPUT_STRIP_TRAILING_WHITESPACE) - endif() - - if(CLANG_TIDY_BIN) - add_custom_target(clang_tidy - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - VERBATIM - COMMAND "${CLANG_TIDY_BIN}" -p "${PROJECT_BINARY_DIR}" - --config-file "${CLANG_TIDY_CONFIG}" - ${SOURCEMETA_TARGET_CLANG_TIDY_FILES} - COMMENT "Analyzing sources using ClangTidy") - else() - add_custom_target(clang_tidy - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - VERBATIM - COMMAND "${CMAKE_COMMAND}" -E echo "Could not locate ClangTidy" - COMMAND "${CMAKE_COMMAND}" -E false) + # TODO: Support other platforms too, like Linux + if(APPLE) + execute_process(COMMAND xcrun --show-sdk-path + OUTPUT_VARIABLE MACOSX_SDK_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND "${CMAKE_CXX_COMPILER}" -print-resource-dir + OUTPUT_VARIABLE MACOSX_RESOURCE_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_CXX_CLANG_TIDY + "${CLANG_TIDY_BIN};--config-file=${CLANG_TIDY_CONFIG};-header-filter=${PROJECT_SOURCE_DIR}/src/*" + "--extra-arg=-std=c++${CMAKE_CXX_STANDARD}" + "--extra-arg=-isysroot" + "--extra-arg=${MACOSX_SDK_PATH}" + "--extra-arg=-resource-dir=${MACOSX_RESOURCE_PATH}" + PARENT_SCOPE) endif() +endfunction() - set_target_properties(clang_tidy PROPERTIES FOLDER "Linting") +function(sourcemeta_clang_tidy_attempt_disable) + unset(CMAKE_CXX_CLANG_TIDY PARENT_SCOPE) endfunction() diff --git a/cmake/common/clang-tidy.config b/cmake/common/clang-tidy.config new file mode 100644 index 000000000..7f1e88899 --- /dev/null +++ b/cmake/common/clang-tidy.config @@ -0,0 +1,19 @@ +--- +# See https://clang.llvm.org/extra/clang-tidy/index.html +# First disable all default checks (with -*) +Checks: '-*, + modernize-*' +# TODO(bavulapati): iterate through the rules and enable them incrementally inorder to send smaller PRs + # bugprone-*,-bugprone-branch-clone,-bugprone-easily-swappable-parameters,-bugprone-empty-catch, + # clang-analyzer-*, + # clang-diagnostic-*, + # modernize-*, + # concurrency-*, + # cppcoreguidelines-*,-cppcoreguidelines-rvalue-reference-param-not-moved, + # performance-*,-performance-enum-size, + # portability-*, + # objc-*, + # misc-*,-misc-no-recursion,-misc-unused-parameters,-misc-const-correctness' +WarningsAsErrors: '*' +FormatStyle: none +UseColor: true diff --git a/cmake/common/targets/clang-tidy.config b/cmake/common/targets/clang-tidy.config deleted file mode 100644 index a7de0a47b..000000000 --- a/cmake/common/targets/clang-tidy.config +++ /dev/null @@ -1,22 +0,0 @@ ---- -# See https://clang.llvm.org/extra/clang-tidy/index.html -# First disable all default checks (with -*) -Checks: '-*, - bugprone-*,-bugprone-branch-clone,-bugprone-easily-swappable-parameters,-bugprone-empty-catch, - clang-analyzer-*, - clang-diagnostic-*, - modernize-*, - concurrency-*, - cppcoreguidelines-*,-cppcoreguidelines-rvalue-reference-param-not-moved, - performance-*,-performance-enum-size, - portability-*, - objc-*, - misc-*,-misc-no-recursion,-misc-unused-parameters,-misc-const-correctness' -WarningsAsErrors: '*' -HeaderFilterRegex: '' -FormatStyle: none -CheckOptions: - # See https://clang.llvm.org/extra/clang-tidy/checks/misc/include-cleaner.html - # Otherwise ClangTidy wants us to directly include private headers from our modules - - key: misc-include-cleaner.IgnoreHeaders - value: 'src\/core\/.*;uriparser\/.*' diff --git a/src/core/json/include/sourcemeta/core/json_array.h b/src/core/json/include/sourcemeta/core/json_array.h index 5772abac5..d43fdc459 100644 --- a/src/core/json/include/sourcemeta/core/json_array.h +++ b/src/core/json/include/sourcemeta/core/json_array.h @@ -56,31 +56,39 @@ template class JSONArray { /// Get a mutable end iterator on the array auto end() noexcept -> iterator { return this->data.end(); } /// Get a constant begin iterator on the array - auto begin() const noexcept -> const_iterator { return this->data.begin(); } + [[nodiscard]] auto begin() const noexcept -> const_iterator { + return this->data.begin(); + } /// Get a constant end iterator on the array - auto end() const noexcept -> const_iterator { return this->data.end(); } + [[nodiscard]] auto end() const noexcept -> const_iterator { + return this->data.end(); + } /// Get a constant begin iterator on the array - auto cbegin() const noexcept -> const_iterator { return this->data.cbegin(); } + [[nodiscard]] auto cbegin() const noexcept -> const_iterator { + return this->data.cbegin(); + } /// Get a constant end iterator on the array - auto cend() const noexcept -> const_iterator { return this->data.cend(); } + [[nodiscard]] auto cend() const noexcept -> const_iterator { + return this->data.cend(); + } /// Get a mutable reverse begin iterator on the array auto rbegin() noexcept -> reverse_iterator { return this->data.rbegin(); } /// Get a mutable reverse end iterator on the array auto rend() noexcept -> reverse_iterator { return this->data.rend(); } /// Get a constant reverse begin iterator on the array - auto rbegin() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator { return this->data.rbegin(); } /// Get a constant reverse end iterator on the array - auto rend() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return this->data.rend(); } /// Get a constant reverse begin iterator on the array - auto crbegin() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator { return this->data.crbegin(); } /// Get a constant reverse end iterator on the array - auto crend() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator { return this->data.crend(); } diff --git a/src/core/json/include/sourcemeta/core/json_hash.h b/src/core/json/include/sourcemeta/core/json_hash.h index 14bfe9b35..10a6139b9 100644 --- a/src/core/json/include/sourcemeta/core/json_hash.h +++ b/src/core/json/include/sourcemeta/core/json_hash.h @@ -14,6 +14,7 @@ template struct HashJSON { return value.fast_hash(); } + [[nodiscard]] inline auto is_perfect(const hash_type) const noexcept -> bool { return false; } @@ -45,6 +46,7 @@ template struct PropertyHashJSON { } }; + [[nodiscard]] inline auto perfect(const T &value, const std::size_t size) const noexcept -> hash_type { hash_type result; @@ -134,6 +136,7 @@ template struct PropertyHashJSON { } } + [[nodiscard]] inline auto is_perfect(const hash_type &hash) const noexcept -> bool { // If there is anything written past the first byte, // then it is a perfect hash diff --git a/src/core/json/include/sourcemeta/core/json_object.h b/src/core/json/include/sourcemeta/core/json_object.h index 03e4e5fb2..e442b2000 100644 --- a/src/core/json/include/sourcemeta/core/json_object.h +++ b/src/core/json/include/sourcemeta/core/json_object.h @@ -45,12 +45,21 @@ template class FlatMap { } } - auto begin() const noexcept -> const_iterator { return this->data.begin(); } - auto end() const noexcept -> const_iterator { return this->data.end(); } - auto cbegin() const noexcept -> const_iterator { return this->data.cbegin(); } - auto cend() const noexcept -> const_iterator { return this->data.cend(); } + [[nodiscard]] auto begin() const noexcept -> const_iterator { + return this->data.begin(); + } + [[nodiscard]] auto end() const noexcept -> const_iterator { + return this->data.end(); + } + [[nodiscard]] auto cbegin() const noexcept -> const_iterator { + return this->data.cbegin(); + } + [[nodiscard]] auto cend() const noexcept -> const_iterator { + return this->data.cend(); + } - inline auto hash(const key_type &key) const noexcept -> hash_type { + [[nodiscard]] inline auto hash(const key_type &key) const noexcept + -> hash_type { return this->hasher(key); } @@ -134,7 +143,8 @@ template class FlatMap { } // As a performance optimisation if the hash is known - inline auto find(const key_type &key, const hash_type key_hash) const + [[nodiscard]] inline auto find(const key_type &key, + const hash_type key_hash) const -> const_iterator { assert(this->hash(key) == key_hash); @@ -161,7 +171,8 @@ template class FlatMap { return this->cend(); } - inline auto try_at(const key_type &key, const hash_type key_hash) const + [[nodiscard]] inline auto try_at(const key_type &key, + const hash_type key_hash) const -> const mapped_type * { assert(this->hash(key) == key_hash); @@ -185,7 +196,8 @@ template class FlatMap { } // As a performance optimisation if the hash is known - auto contains(const key_type &key, const hash_type key_hash) const -> bool { + [[nodiscard]] auto contains(const key_type &key, + const hash_type key_hash) const -> bool { assert(this->hash(key) == key_hash); // Move the perfect hash condition out of the loop for extra performance @@ -208,7 +220,8 @@ template class FlatMap { // As a performance optimisation if the hash is known - inline auto at(const key_type &key, const hash_type key_hash) const + [[nodiscard]] inline auto at(const key_type &key, + const hash_type key_hash) const -> const mapped_type & { assert(this->hash(key) == key_hash); @@ -262,7 +275,8 @@ template class FlatMap { #endif } - inline auto at(const size_type index) const noexcept -> const Entry & { + [[nodiscard]] inline auto at(const size_type index) const noexcept + -> const Entry & { return this->data[index]; } @@ -317,9 +331,13 @@ template class FlatMap { return this->erase(key, this->hash(key)); } - inline auto size() const noexcept -> size_type { return this->data.size(); } + [[nodiscard]] inline auto size() const noexcept -> size_type { + return this->data.size(); + } - inline auto empty() const noexcept -> bool { return this->data.empty(); } + [[nodiscard]] inline auto empty() const noexcept -> bool { + return this->data.empty(); + } inline auto clear() noexcept -> void { this->data.clear(); } @@ -418,44 +436,48 @@ template class JSONObject { using const_pointer = typename Container::const_pointer; using const_iterator = typename Container::const_iterator; - inline auto begin() const noexcept -> const_iterator { + [[nodiscard]] inline auto begin() const noexcept -> const_iterator { return this->data.begin(); } /// Get a constant end iterator on the object - inline auto end() const noexcept -> const_iterator { + [[nodiscard]] inline auto end() const noexcept -> const_iterator { return this->data.end(); } /// Get a constant begin iterator on the object - inline auto cbegin() const noexcept -> const_iterator { + [[nodiscard]] inline auto cbegin() const noexcept -> const_iterator { return this->data.cbegin(); } /// Get a constant end iterator on the object - inline auto cend() const noexcept -> const_iterator { + [[nodiscard]] inline auto cend() const noexcept -> const_iterator { return this->data.cend(); } /// Attempt to find an entry by key - inline auto find(const Key &key) const -> const_iterator { + [[nodiscard]] inline auto find(const Key &key) const -> const_iterator { return this->data.find(key, this->data.hash(key)); } /// Check if an entry with the given key exists - inline auto defines(const Key &key, - const typename Container::hash_type hash) const -> bool { + [[nodiscard]] inline auto + defines(const Key &key, const typename Container::hash_type hash) const + -> bool { return this->data.contains(key, hash); } /// Check the size of the object - inline auto size() const -> std::size_t { return this->data.size(); } + [[nodiscard]] inline auto size() const -> std::size_t { + return this->data.size(); + } /// Access an object entry by its underlying positional index - inline auto at(const size_type index) const noexcept -> const + [[nodiscard]] inline auto at(const size_type index) const noexcept -> const typename Container::Entry & { return this->data.at(index); } // Hash an object property - inline auto hash(const Key &property) const -> typename Container::hash_type { + [[nodiscard]] inline auto hash(const Key &property) const -> + typename Container::hash_type { return this->data.hasher(property); } diff --git a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_pointer.h b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_pointer.h index 6c89f85fc..1442d3e1f 100644 --- a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_pointer.h +++ b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_pointer.h @@ -68,31 +68,39 @@ template class GenericPointer { /// Get a mutable end iterator on the pointer auto end() noexcept -> iterator { return this->data.end(); } /// Get a constant begin iterator on the pointer - auto begin() const noexcept -> const_iterator { return this->data.begin(); } + [[nodiscard]] auto begin() const noexcept -> const_iterator { + return this->data.begin(); + } /// Get a constant end iterator on the pointer - auto end() const noexcept -> const_iterator { return this->data.end(); } + [[nodiscard]] auto end() const noexcept -> const_iterator { + return this->data.end(); + } /// Get a constant begin iterator on the pointer - auto cbegin() const noexcept -> const_iterator { return this->data.cbegin(); } + [[nodiscard]] auto cbegin() const noexcept -> const_iterator { + return this->data.cbegin(); + } /// Get a constant end iterator on the pointer - auto cend() const noexcept -> const_iterator { return this->data.cend(); } + [[nodiscard]] auto cend() const noexcept -> const_iterator { + return this->data.cend(); + } /// Get a mutable reverse begin iterator on the pointer auto rbegin() noexcept -> reverse_iterator { return this->data.rbegin(); } /// Get a mutable reverse end iterator on the pointer auto rend() noexcept -> reverse_iterator { return this->data.rend(); } /// Get a constant reverse begin iterator on the pointer - auto rbegin() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator { return this->data.rbegin(); } /// Get a constant reverse end iterator on the pointer - auto rend() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return this->data.rend(); } /// Get a constant reverse begin iterator on the pointer - auto crbegin() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator { return this->data.crbegin(); } /// Get a constant reverse end iterator on the pointer - auto crend() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator { return this->data.crend(); } @@ -437,7 +445,7 @@ template class GenericPointer { /// assert(left.concat(right) == /// sourcemeta::core::Pointer{"foo", "bar", "baz"}); /// ``` - auto concat(const GenericPointer &other) const + [[nodiscard]] auto concat(const GenericPointer &other) const -> GenericPointer { GenericPointer result{*this}; result.push_back(other); @@ -455,7 +463,8 @@ template class GenericPointer { /// const sourcemeta::core::Pointer prefix{"foo", "bar"}; /// assert(pointer.starts_with(prefix)); /// ``` - auto starts_with(const GenericPointer &other) const -> bool { + [[nodiscard]] auto + starts_with(const GenericPointer &other) const -> bool { return other.data.size() <= this->data.size() && std::equal(other.data.cbegin(), other.data.cend(), this->data.cbegin()); @@ -473,8 +482,8 @@ template class GenericPointer { /// const sourcemeta::core::Pointer prefix{"foo", "bar", "baz"}; /// assert(pointer.starts_with(prefix, tail)); /// ``` - auto starts_with(const GenericPointer &other, - const Token &tail) const -> bool { + [[nodiscard]] auto starts_with(const GenericPointer &other, + const Token &tail) const -> bool { if (other.size() == this->size() + 1) { assert(!other.empty()); return other.starts_with(*this) && other.back() == tail; @@ -494,7 +503,8 @@ template class GenericPointer { /// const sourcemeta::core::Pointer prefix{"foo", "bar", "qux"}; /// assert(pointer.starts_with_initial(prefix)); /// ``` - auto starts_with_initial(const GenericPointer &other) const + [[nodiscard]] auto + starts_with_initial(const GenericPointer &other) const -> bool { const auto prefix_size{other.size()}; if (prefix_size == 0) { @@ -525,8 +535,9 @@ template class GenericPointer { /// assert(pointer.rebase(prefix, replacement) == /// sourcemeta::core::Pointer{"qux", "baz"}); /// ``` - auto rebase(const GenericPointer &prefix, - const GenericPointer &replacement) const + [[nodiscard]] auto + rebase(const GenericPointer &prefix, + const GenericPointer &replacement) const -> GenericPointer { typename Container::size_type index{0}; while (index < prefix.size()) { @@ -560,7 +571,8 @@ template class GenericPointer { /// /// If the JSON Pointer is not relative to the base, a copy of the original /// input pointer is returned. - auto resolve_from(const GenericPointer &base) const + [[nodiscard]] auto + resolve_from(const GenericPointer &base) const -> GenericPointer { typename Container::size_type index{0}; while (index < base.size()) { @@ -580,14 +592,16 @@ template class GenericPointer { } /// Compare JSON Pointer instances - auto operator==(const GenericPointer &other) const noexcept + [[nodiscard]] auto + operator==(const GenericPointer &other) const noexcept -> bool { return this->data == other.data; } /// Overload to support ordering of JSON Pointers. Typically for sorting /// reasons. - auto operator<(const GenericPointer &other) const noexcept + [[nodiscard]] auto + operator<(const GenericPointer &other) const noexcept -> bool { return this->data < other.data; } diff --git a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_position.h b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_position.h index 6da8ea21e..2e36acbd5 100644 --- a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_position.h +++ b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_position.h @@ -51,8 +51,9 @@ class SOURCEMETA_CORE_JSONPOINTER_EXPORT PointerPositionTracker { auto operator()(const JSON::ParsePhase phase, const JSON::Type, const std::uint64_t line, const std::uint64_t column, const JSON &value) -> void; - auto get(const Pointer &pointer) const -> std::optional; - auto size() const -> std::size_t; + [[nodiscard]] auto get(const Pointer &pointer) const + -> std::optional; + [[nodiscard]] auto size() const -> std::size_t; private: // Exporting symbols that depends on the standard C++ library is considered diff --git a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_template.h b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_template.h index c79fb91f9..0a6eb600f 100644 --- a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_template.h +++ b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_template.h @@ -85,31 +85,39 @@ template class GenericPointerTemplate { /// Get a mutable end iterator on the pointer auto end() noexcept -> iterator { return this->data.end(); } /// Get a constant begin iterator on the pointer - auto begin() const noexcept -> const_iterator { return this->data.begin(); } + [[nodiscard]] auto begin() const noexcept -> const_iterator { + return this->data.begin(); + } /// Get a constant end iterator on the pointer - auto end() const noexcept -> const_iterator { return this->data.end(); } + [[nodiscard]] auto end() const noexcept -> const_iterator { + return this->data.end(); + } /// Get a constant begin iterator on the pointer - auto cbegin() const noexcept -> const_iterator { return this->data.cbegin(); } + [[nodiscard]] auto cbegin() const noexcept -> const_iterator { + return this->data.cbegin(); + } /// Get a constant end iterator on the pointer - auto cend() const noexcept -> const_iterator { return this->data.cend(); } + [[nodiscard]] auto cend() const noexcept -> const_iterator { + return this->data.cend(); + } /// Get a mutable reverse begin iterator on the pointer auto rbegin() noexcept -> reverse_iterator { return this->data.rbegin(); } /// Get a mutable reverse end iterator on the pointer auto rend() noexcept -> reverse_iterator { return this->data.rend(); } /// Get a constant reverse begin iterator on the pointer - auto rbegin() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator { return this->data.rbegin(); } /// Get a constant reverse end iterator on the pointer - auto rend() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return this->data.rend(); } /// Get a constant reverse begin iterator on the pointer - auto crbegin() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator { return this->data.crbegin(); } /// Get a constant reverse end iterator on the pointer - auto crend() const noexcept -> const_reverse_iterator { + [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator { return this->data.crend(); } @@ -172,7 +180,8 @@ template class GenericPointerTemplate { /// /// assert(left.concat(right) == expected); /// ``` - auto concat(const GenericPointerTemplate &&other) const + [[nodiscard]] auto + concat(const GenericPointerTemplate &&other) const -> GenericPointerTemplate { GenericPointerTemplate result{*this}; result.data.reserve(result.data.size() + other.data.size()); diff --git a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_walker.h b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_walker.h index cece2d5ec..9441f564b 100644 --- a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_walker.h +++ b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_walker.h @@ -19,10 +19,18 @@ template class GenericPointerWalker { GenericPointerWalker(const JSON &document) { this->walk(document, {}); } using const_iterator = typename internal::const_iterator; - auto begin() const -> const_iterator { return this->pointers.begin(); }; - auto end() const -> const_iterator { return this->pointers.end(); }; - auto cbegin() const -> const_iterator { return this->pointers.cbegin(); }; - auto cend() const -> const_iterator { return this->pointers.cend(); }; + [[nodiscard]] auto begin() const -> const_iterator { + return this->pointers.begin(); + }; + [[nodiscard]] auto end() const -> const_iterator { + return this->pointers.end(); + }; + [[nodiscard]] auto cbegin() const -> const_iterator { + return this->pointers.cbegin(); + }; + [[nodiscard]] auto cend() const -> const_iterator { + return this->pointers.cend(); + }; private: auto walk(const JSON &document, const PointerT &pointer) -> void { diff --git a/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h b/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h index 5c772f539..38dac4d69 100644 --- a/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h +++ b/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h @@ -110,7 +110,7 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaFrame { SchemaFrame(const Mode mode) : mode_{mode} {} // Query the current mode that the schema frame was configured with - auto mode() const noexcept -> Mode { return this->mode_; } + [[nodiscard]] auto mode() const noexcept -> Mode { return this->mode_; } /// A single entry in a JSON Schema reference map struct ReferencesEntry { @@ -182,7 +182,7 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaFrame { using Paths = std::set; /// Export the frame entries as JSON - auto to_json() const -> JSON; + [[nodiscard]] auto to_json() const -> JSON; /// Analyse a schema or set of schemas from a given root. Passing /// multiple paths that have any overlap is undefined behaviour @@ -194,45 +194,47 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaFrame { const Paths &paths = {empty_pointer}) -> void; /// Access the analysed schema locations - auto locations() const noexcept -> const Locations &; + [[nodiscard]] auto locations() const noexcept -> const Locations &; /// Access the analysed schema references - auto references() const noexcept -> const References &; + [[nodiscard]] auto references() const noexcept -> const References &; /// Check whether the analysed schema has no external references - auto standalone() const -> bool; + [[nodiscard]] auto standalone() const -> bool; /// Get the vocabularies associated with a location entry - auto vocabularies(const Location &location, - const SchemaResolver &resolver) const -> Vocabularies; + [[nodiscard]] auto vocabularies(const Location &location, + const SchemaResolver &resolver) const + -> Vocabularies; /// Get the URI associated with a location entry - auto uri(const Location &location, - const Pointer &relative_schema_location = empty_pointer) const + [[nodiscard]] auto + uri(const Location &location, + const Pointer &relative_schema_location = empty_pointer) const -> JSON::String; /// Get the location associated by traversing a pointer from another location - auto traverse(const Location &location, - const Pointer &relative_schema_location) const + [[nodiscard]] auto traverse(const Location &location, + const Pointer &relative_schema_location) const -> const Location &; /// Get the location associated with a given URI - auto traverse(const JSON::String &uri) const + [[nodiscard]] auto traverse(const JSON::String &uri) const -> std::optional>; /// Try to dereference a reference location into its destination location - auto + [[nodiscard]] auto dereference(const Location &location, const Pointer &relative_schema_location = empty_pointer) const -> std::pair>>; /// Get the unresolved instance locations associated with a location entry - auto instance_locations(const Location &location) const -> const + [[nodiscard]] auto instance_locations(const Location &location) const -> const typename Instances::mapped_type &; /// Find all references to a given location pointer - auto references_to(const Pointer &pointer) const -> std::vector< + [[nodiscard]] auto references_to(const Pointer &pointer) const -> std::vector< std::reference_wrapper>; private: diff --git a/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h b/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h index f09e16ed2..269554737 100644 --- a/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h +++ b/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h @@ -93,10 +93,11 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaTransformRule { -> std::pair; /// Check if the rule applies to a schema - auto check(const JSON &schema, const JSON &root, - const Vocabularies &vocabularies, const SchemaWalker &walker, - const SchemaResolver &resolver, const SchemaFrame &frame, - const SchemaFrame::Location &location) const -> Result; + [[nodiscard]] auto + check(const JSON &schema, const JSON &root, const Vocabularies &vocabularies, + const SchemaWalker &walker, const SchemaResolver &resolver, + const SchemaFrame &frame, const SchemaFrame::Location &location) const + -> Result; /// A method to optionally fix any reference location that was affected by the /// transformation. @@ -236,14 +237,15 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaTransformer { -> bool; /// Report back the rules from the bundle that need to be applied to a schema - auto check(const JSON &schema, const SchemaWalker &walker, - const SchemaResolver &resolver, const Callback &callback, - const std::optional &default_dialect = std::nullopt, - const std::optional &default_id = std::nullopt) const + [[nodiscard]] auto + check(const JSON &schema, const SchemaWalker &walker, + const SchemaResolver &resolver, const Callback &callback, + const std::optional &default_dialect = std::nullopt, + const std::optional &default_id = std::nullopt) const -> bool; - auto begin() const -> auto { return this->rules.cbegin(); } - auto end() const -> auto { return this->rules.cend(); } + [[nodiscard]] auto begin() const -> auto { return this->rules.cbegin(); } + [[nodiscard]] auto end() const -> auto { return this->rules.cend(); } private: // Exporting symbols that depends on the standard C++ library is considered diff --git a/src/core/jsonschema/include/sourcemeta/core/jsonschema_walker.h b/src/core/jsonschema/include/sourcemeta/core/jsonschema_walker.h index 4083ade59..a953b52fa 100644 --- a/src/core/jsonschema/include/sourcemeta/core/jsonschema_walker.h +++ b/src/core/jsonschema/include/sourcemeta/core/jsonschema_walker.h @@ -65,10 +65,10 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaIterator { const JSON &input, const SchemaWalker &walker, const SchemaResolver &resolver, const std::optional &default_dialect = std::nullopt); - auto begin() const -> const_iterator; - auto end() const -> const_iterator; - auto cbegin() const -> const_iterator; - auto cend() const -> const_iterator; + [[nodiscard]] auto begin() const -> const_iterator; + [[nodiscard]] auto end() const -> const_iterator; + [[nodiscard]] auto cbegin() const -> const_iterator; + [[nodiscard]] auto cend() const -> const_iterator; private: // Exporting symbols that depends on the standard C++ library is considered @@ -132,10 +132,10 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaIteratorFlat { const JSON &input, const SchemaWalker &walker, const SchemaResolver &resolver, const std::optional &default_dialect = std::nullopt); - auto begin() const -> const_iterator; - auto end() const -> const_iterator; - auto cbegin() const -> const_iterator; - auto cend() const -> const_iterator; + [[nodiscard]] auto begin() const -> const_iterator; + [[nodiscard]] auto end() const -> const_iterator; + [[nodiscard]] auto cbegin() const -> const_iterator; + [[nodiscard]] auto cend() const -> const_iterator; private: // Exporting symbols that depends on the standard C++ library is considered @@ -189,10 +189,10 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaKeywordIterator { const JSON &input, const SchemaWalker &walker, const SchemaResolver &resolver, const std::optional &default_dialect = std::nullopt); - auto begin() const -> const_iterator; - auto end() const -> const_iterator; - auto cbegin() const -> const_iterator; - auto cend() const -> const_iterator; + [[nodiscard]] auto begin() const -> const_iterator; + [[nodiscard]] auto end() const -> const_iterator; + [[nodiscard]] auto cbegin() const -> const_iterator; + [[nodiscard]] auto cend() const -> const_iterator; private: // Exporting symbols that depends on the standard C++ library is considered diff --git a/src/core/uri/include/sourcemeta/core/uri.h b/src/core/uri/include/sourcemeta/core/uri.h index 3312a7603..f5a69015f 100644 --- a/src/core/uri/include/sourcemeta/core/uri.h +++ b/src/core/uri/include/sourcemeta/core/uri.h @@ -85,7 +85,7 @@ class SOURCEMETA_CORE_URI_EXPORT URI { /// const sourcemeta::core::URI uri{"urn:example:schema"}; /// assert(uri.is_urn()); /// ``` - auto is_urn() const -> bool; + [[nodiscard]] auto is_urn() const -> bool; /// Check if the URI is a tag as described by RFC 4151. For example: /// @@ -96,7 +96,7 @@ class SOURCEMETA_CORE_URI_EXPORT URI { /// const sourcemeta::core::URI uri{"tag:yaml.org,2002:int"}; /// assert(uri.is_tag()); /// ``` - auto is_tag() const -> bool; + [[nodiscard]] auto is_tag() const -> bool; /// Check if the URI has the `mailto` scheme. For example: /// @@ -107,7 +107,7 @@ class SOURCEMETA_CORE_URI_EXPORT URI { /// const sourcemeta::core::URI uri{"mailto:joe@example.com"}; /// assert(uri.is_mailto()); /// ``` - auto is_mailto() const -> bool; + [[nodiscard]] auto is_mailto() const -> bool; /// Check if the URI only consists of a fragment. For example: /// @@ -118,7 +118,7 @@ class SOURCEMETA_CORE_URI_EXPORT URI { /// const sourcemeta::core::URI uri{"#foo"}; /// assert(uri.is_fragment_only()); /// ``` - auto is_fragment_only() const -> bool; + [[nodiscard]] auto is_fragment_only() const -> bool; /// Check if the URI is relative. For example: /// @@ -129,7 +129,7 @@ class SOURCEMETA_CORE_URI_EXPORT URI { /// sourcemeta::core::URI uri{"./foo"}; /// assert(uri.is_relative()); /// ``` - auto is_relative() const -> bool; + [[nodiscard]] auto is_relative() const -> bool; /// Check if the host is an ipv6 address. For example: /// @@ -140,7 +140,7 @@ class SOURCEMETA_CORE_URI_EXPORT URI { /// sourcemeta::core::URI uri{"http://[::1]"}; /// assert(uri.is_ipv6()); /// ``` - auto is_ipv6() const -> bool; + [[nodiscard]] auto is_ipv6() const -> bool; /// Check if the URI corresponds to the empty URI. For example: /// @@ -151,7 +151,7 @@ class SOURCEMETA_CORE_URI_EXPORT URI { /// sourcemeta::core::URI uri{""}; /// assert(uri.empty()); /// ``` - auto empty() const -> bool; + [[nodiscard]] auto empty() const -> bool; /// Get the scheme part of the URI, if any. For example: /// diff --git a/test/jsonschema/jsonschema_transformer_test.cc b/test/jsonschema/jsonschema_transformer_test.cc index 40b24faea..3a0201b30 100644 --- a/test/jsonschema/jsonschema_transformer_test.cc +++ b/test/jsonschema/jsonschema_transformer_test.cc @@ -541,9 +541,10 @@ TEST(JSONSchema_transformer, check_throw_if_no_dialect_invalid_default) { "qux": "xxx" })JSON"); - EXPECT_THROW(bundle.check(document, sourcemeta::core::schema_official_walker, - sourcemeta::core::schema_official_resolver, nullptr, - "https://example.com/invalid"), + EXPECT_THROW((void)bundle.check(document, + sourcemeta::core::schema_official_walker, + sourcemeta::core::schema_official_resolver, + nullptr, "https://example.com/invalid"), sourcemeta::core::SchemaResolutionError); }