diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000..6a6abc7a5 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,10 @@ +--- +# See https://clang.llvm.org/extra/clang-tidy/index.html +Checks: ' + -*, + concurrency-*, + ' +WarningsAsErrors: '*' +SystemHeaders: false +UseColor: true +FormatStyle: none diff --git a/CMakeLists.txt b/CMakeLists.txt index edc2346f4..7156e2830 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,15 @@ option(SOURCEMETA_CORE_CONTRIB_GOOGLEBENCHMARK "Build the GoogleBenchmark librar include(Sourcemeta) +if(PROJECT_IS_TOP_LEVEL) + sourcemeta_target_clang_format(SOURCES + src/*.h src/*.cc + benchmark/*.h benchmark/*.cc + test/*.h test/*.cc) +endif() + +sourcemeta_enable_clang_tidy() # Locates and enables CLANG_TIDY + # Don't force downstream consumers on it if(PROJECT_IS_TOP_LEVEL) sourcemeta_enable_simd() @@ -80,6 +89,8 @@ if(SOURCEMETA_CORE_EXTENSION_ALTERSCHEMA) add_subdirectory(src/extension/alterschema) endif() +sourcemeta_disable_clang_tidy() + if(SOURCEMETA_CORE_ADDRESS_SANITIZER) sourcemeta_sanitizer(TYPE address) elseif(SOURCEMETA_CORE_UNDEFINED_SANITIZER) @@ -91,13 +102,6 @@ if(SOURCEMETA_CORE_DOCS) OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/website") endif() -if(PROJECT_IS_TOP_LEVEL) - 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/cmake/Sourcemeta.cmake b/cmake/Sourcemeta.cmake index b75c969c1..f9377319b 100644 --- a/cmake/Sourcemeta.cmake +++ b/cmake/Sourcemeta.cmake @@ -10,7 +10,7 @@ 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}/commands/clang-tidy.cmake") include("${SOURCEMETA_UTILITIES_DIRECTORY}/targets/shellcheck.cmake") include("${SOURCEMETA_UTILITIES_DIRECTORY}/targets/doxygen.cmake") include("${SOURCEMETA_UTILITIES_DIRECTORY}/targets/googletest.cmake") diff --git a/cmake/common/targets/clang-tidy.cmake b/cmake/common/commands/clang-tidy.cmake similarity index 75% rename from cmake/common/targets/clang-tidy.cmake rename to cmake/common/commands/clang-tidy.cmake index 47954d1d0..d7b7f637d 100644 --- a/cmake/common/targets/clang-tidy.cmake +++ b/cmake/common/commands/clang-tidy.cmake @@ -76,55 +76,15 @@ 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}) +function(sourcemeta_enable_clang_tidy) sourcemeta_target_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 - PATHS "${CMAKE_CURRENT_BINARY_DIR}/bin") - if(NOT CLANG_TIDY_BIN) - find_program(CLANG_TIDY_BIN NAMES clang-tidy REQUIRED) - endif() - else() - find_program(CLANG_TIDY_BIN NAMES clang-tidy NO_DEFAULT_PATH + find_program(CLANG_TIDY_BIN NAMES clang-tidy NO_DEFAULT_PATH PATHS "${CMAKE_CURRENT_BINARY_DIR}/bin") - if(NOT CLANG_TIDY_BIN) - find_program(CLANG_TIDY_BIN NAMES 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) - endif() + set(CLANG_TIDY_CONFIG_PATH "${CMAKE_CURRENT_SOURCE_DIR}/.clang-tidy") + # Add clang-tidy to the targets. Clang-tidy uses the .clang-tidy file for configuration. + set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_BIN};--config-file=${CLANG_TIDY_CONFIG_PATH};-header-filter=${CMAKE_CURRENT_SOURCE_DIR}/src/*" PARENT_SCOPE) +endfunction() - set_target_properties(clang_tidy PROPERTIES FOLDER "Linting") +function(sourcemeta_disable_clang_tidy) + unset(CMAKE_CXX_CLANG_TIDY PARENT_SCOPE) endfunction() 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/jsonschema/frame.cc b/src/core/jsonschema/frame.cc index 3a9635aac..fa1e642f3 100644 --- a/src/core/jsonschema/frame.cc +++ b/src/core/jsonschema/frame.cc @@ -76,11 +76,9 @@ auto find_anchors(const sourcemeta::core::JSON &schema, const sourcemeta::core::URI identifier(schema.at("$id").to_string()); if (identifier.is_fragment_only()) { result.insert( - {sourcemeta::core::JSON::String{ - identifier.fragment() - .value()}, // NOLINT(bugprone-unchecked-optional-access): - // Check for optional is happening - // inside is_fragment_only() + // Check for optional is happening inside is_fragment_only() + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) + {sourcemeta::core::JSON::String{identifier.fragment().value()}, AnchorType::Static}); } } @@ -95,11 +93,9 @@ auto find_anchors(const sourcemeta::core::JSON &schema, const sourcemeta::core::URI identifier(schema.at("id").to_string()); if (identifier.is_fragment_only()) { result.insert( - {sourcemeta::core::JSON::String{ - identifier.fragment() - .value()}, // NOLINT(bugprone-unchecked-optional-access): - // Check for optional is happening - // inside is_fragment_only() + // Check for optional is happening inside is_fragment_only() + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) + {sourcemeta::core::JSON::String{identifier.fragment().value()}, AnchorType::Static}); } } diff --git a/src/core/uri/uri.cc b/src/core/uri/uri.cc index 76842ec2e..be0e13e65 100644 --- a/src/core/uri/uri.cc +++ b/src/core/uri/uri.cc @@ -681,8 +681,6 @@ auto URI::try_resolve_from(const URI &base) -> URI & { this->scheme_ = base.scheme_; this->query_ = base.query_; return *this; - } else if (base.path().has_value() && base.path().value().starts_with("..")) { - return *this; } else if (base.is_relative() && this->is_relative() && base.path_.has_value() && this->path_.has_value() && this->path_.value().find('/') == std::string::npos &&