1# Copyright (c) 2021-2022 Huawei Device Co., Ltd. 2# Licensed under the Apache License, Version 2.0 (the "License"); 3# you may not use this file except in compliance with the License. 4# You may obtain a copy of the License at 5# 6# http://www.apache.org/licenses/LICENSE-2.0 7# 8# Unless required by applicable law or agreed to in writing, software 9# distributed under the License is distributed on an "AS IS" BASIS, 10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11# See the License for the specific language governing permissions and 12# limitations under the License. 13 14option(PANDA_ENABLE_CLANG_TIDY "Enable clang-tidy checks during compilation" true) 15 16# There seems to be a bug in either clang-tidy or CMake: 17# When clang/gcc is used for cross-compilation, it is ran on host and use defines and options for host 18# For example for arm32 cross-compilation Clang-Tidy: 19# - don't know about -march=armv7-a 20# - believes that size of pointer is 64 instead of 32 for aarch32 21# TODO: Retry once we upgrade the checker. 22if(CMAKE_CROSSCOMPILING AND PANDA_TARGET_ARM32) 23 set(PANDA_ENABLE_CLANG_TIDY false) 24endif() 25 26# TODO (runtime): Remove this when enable tidy on qemu builds. 27if(CMAKE_CROSSCOMPILING) 28 set(PANDA_ENABLE_CLANG_TIDY false) 29endif() 30 31if(PANDA_TARGET_MACOS) 32 set(PANDA_ENABLE_CLANG_TIDY false) 33endif() 34 35if(PANDA_ENABLE_CLANG_TIDY) 36 # Currently we fix a certain version of clang-tidy to avoid unstable linting, 37 # which may occur if different versions of the tools are used by developers. 38 set(panda_clang_tidy "clang-tidy-9") 39 40 # Require clang-tidy 41 find_program( 42 CLANG_TIDY 43 NAMES ${panda_clang_tidy} 44 DOC "Path to clang-tidy executable") 45 if(NOT CLANG_TIDY) 46 message(FATAL_ERROR "clang-tidy not found, but requested for build. Use -DPANDA_ENABLE_CLANG_TIDY=false to suppress.") 47 endif() 48 49 unset(panda_clang_tidy) 50 51 message(STATUS "clang-tidy found: ${CLANG_TIDY}") 52 # NB! Even if config is malformed, clang-tidy -dump-config returns 0 on failure. 53 # Hence we check for ERROR_VARIABLE instead of RESULT_VARIABLE. 54 execute_process( 55 COMMAND ${CLANG_TIDY} -dump-config 56 WORKING_DIRECTORY ${PANDA_ROOT} 57 ERROR_VARIABLE dump_config_stderr) 58 if (dump_config_stderr AND NOT "${dump_config_stderr}" STREQUAL "") 59 message(FATAL_ERROR "${dump_config_stderr}") 60 endif() 61 # See https://gitlab.kitware.com/cmake/cmake/issues/18926. 62 # Create a preprocessor definition that depends on .clang-tidy content so 63 # the compile command will change when .clang-tidy changes. This ensures 64 # that a subsequent build re-runs clang-tidy on all sources even if they 65 # do not otherwise need to be recompiled. Nothing actually uses this 66 # definition. We add it to targets on which we run clang-tidy just to 67 # get the build dependency on the .clang-tidy file. 68 file(SHA1 ${CMAKE_CURRENT_SOURCE_DIR}/.clang-tidy clang_tidy_sha1) 69 set(CLANG_TIDY_DEFINITIONS "CLANG_TIDY_SHA1=${clang_tidy_sha1}") 70 unset(clang_tidy_sha1) 71 configure_file(${PANDA_ROOT}/.clang-tidy ${PANDA_BINARY_ROOT}/.clang-tidy COPYONLY) 72endif() 73 74# Add a target to clang-tidy checks. 75# 76# Example usage: 77# 78# panda_add_to_clang_tidy(TARGET target_name 79# CHECKS 80# "-check-to-be-disabled" 81# "-glob-to-be-disabled-*" 82# "check-to-be-enabled" 83# "glob-to-be-enabled-*" 84# ) 85# 86# This function makes target_name to be co-compiled with clang-tidy. 87# The list of CHECKS allows to pass per-target checks in additions to 88# global ones (see below). CHECKS follow clang-tidy syntax of checks. 89# By default all checks are enabled globally, so the most reasonable use 90# case for CHECKS is to pass checks to be suppressed. 91 92# NB! Important caveats: 93# * We use permissive policy for checks, i.e. everything is enabled by default, 94# then exceptions are suppressed explicitly. 95# * We maintain the list of global exceptions in this function (not in .clang-tidy) 96# because of its syntax limitations (in particular, all checks should be passed 97# as a single string in YAML, which is not readable). 98# * -header-filter is set to check only headers of the target_name. It is supposed 99# that each components is responsible for QA'ing only its code base. 100function(panda_add_to_clang_tidy) 101 if(NOT PANDA_ENABLE_CLANG_TIDY) 102 return() 103 endif() 104 105 set(prefix ARG) 106 set(noValues) 107 set(singleValues TARGET) 108 set(multiValues CHECKS) 109 110 cmake_parse_arguments(${prefix} 111 "${noValues}" 112 "${singleValues}" 113 "${multiValues}" 114 ${ARGN}) 115 116 set(clang_tidy_params 117 "${CLANG_TIDY}" 118 "-config=" 119 "-format-style=file" 120 #"-header-filter='^(${CMAKE_CURRENT_SOURCE_DIR}|${CMAKE_CURRENT_BINARY_DIR}).*'" 121 "-p='${PANDA_BINARY_ROOT}'" 122 ) 123 124 set(clang_tidy_default_exceptions 125 # aliases for other checks(here full list: https://clang.llvm.org/extra/clang-tidy/checks/list.html): 126 "-hicpp-braces-around-statements" # alias for readability-braces-around-statements 127 "-google-readability-braces-around-statements" # alias for readability-braces-around-statements 128 "-google-readability-function-size" # alias for readability-function-size 129 "-hicpp-explicit-conversions" # alias for google-explicit-constructor 130 "-hicpp-function-size" # alias for readability-function-size 131 "-hicpp-no-array-decay" # alias for cppcoreguidelines-pro-bounds-array-to-pointer-decay 132 "-hicpp-avoid-c-arrays" # alias for modernize-avoid-c-arrays 133 "-cppcoreguidelines-avoid-c-arrays" # alias for modernize-avoid-c-arrays 134 "-cppcoreguidelines-avoid-magic-numbers" # alias for readability-magic-numbers 135 "-cppcoreguidelines-non-private-member-variables-in-classes" # alias for misc-non-private-member-variables-in-classes 136 "-cert-dcl03-c" # alias for misc-static-assert 137 "-hicpp-static-assert" # alias for misc-static-assert 138 "-hicpp-no-malloc" # alias for cppcoreguidelines-no-malloc 139 "-hicpp-vararg" # alias for cppcoreguidelines-pro-type-vararg 140 "-hicpp-member-init" # alias for cppcoreguidelines-pro-type-member-init 141 "-hicpp-move-const-arg" # alias for performance-move-const-arg 142 "-cert-oop54-cpp" # alias for bugprone-unhandled-self-assignment 143 # explicitly disabled checks 144 "-bugprone-macro-parentheses" # disabled because it is hard to write macros with types with it 145 "-llvm-header-guard" # disabled because of incorrect root prefix 146 "-llvm-include-order" # disabled because conflicts with the clang-format 147 "-readability-identifier-naming" # disabled because we will use little-hump-style 148 "-google-runtime-references" # disabled to use non-const references 149 "-fuchsia-trailing-return" # disabled because we have a lot of false positives and it is stylistic check 150 "-fuchsia-default-arguments-calls" # disabled because we use functions with default arguments a lot 151 "-fuchsia-default-arguments-declarations" # disabled because we use functions with default arguments a lot 152 "-modernize-use-trailing-return-type" # disabled as a stylistic check 153 "-clang-analyzer-optin.cplusplus.UninitializedObject" # disabled due to instability on clang-9 and clang-10 154 "-readability-static-accessed-through-instance" # TODO(knazarov) fix all occurences 155 "-readability-convert-member-functions-to-static" # TODO(knazarov) fix all occurences 156 "-bugprone-sizeof-expression" # TODO(knazarov) fix all occurences 157 "-bugprone-branch-clone" # TODO(knazarov) fix all occurences 158 # TODOs 159 "-cppcoreguidelines-owning-memory" # TODO(dtrubenkov): look if we want to use GSL or gsl-lite 160 "-cppcoreguidelines-pro-bounds-array-to-pointer-decay" # TODO(dtrubenkov): look into issue with ASSERT 161 "-cppcoreguidelines-pro-bounds-constant-array-index" # TODO(dtrubenkov): look if we want to use GSL or gsl-lite 162 "-cppcoreguidelines-pro-type-const-cast" # TODO(dtrubenkov): consider to remove from global list 163 "-cppcoreguidelines-pro-type-reinterpret-cast" # TODO(dtrubenkov): consider to remove from global list 164 "-cppcoreguidelines-pro-type-static-cast-downcast" # TODO(dtrubenkov): look into it 165 "-fuchsia-default-arguments" # TODO(dtrubenkov): look into it 166 "-fuchsia-overloaded-operator" # TODO(dtrubenkov): consider to remove from global list 167 "-modernize-use-nodiscard" # TODO(dtrubenkov): look into it 168 "-cert-dcl50-cpp" # ailas for cppcoreguidelines-pro-type-vararg 169 # candidates for removal: 170 "-hicpp-noexcept-move" # For some reason become failed in DEFAULT_MOVE_SEMANTIC 171 "-performance-noexcept-move-constructor" # Same as above 172 ) 173 # NB! Replace with list(JOIN ...) after switching to CMake 3.12+ 174 string(REPLACE ";" "," default_exceptions "${clang_tidy_default_exceptions}") 175 176 set(clang_tidy_checks "-checks=*,${default_exceptions}") 177 178 if(DEFINED ARG_CHECKS) 179 # NB! Replace with list(JOIN ...) after switching to CMake 3.12+ 180 string(REPLACE ";" "," custom_checks "${ARG_CHECKS}") 181 set(clang_tidy_checks "${clang_tidy_checks},${custom_checks}") 182 endif() 183 184 list(APPEND clang_tidy_params "${clang_tidy_checks}") 185 186 set_target_properties(${ARG_TARGET} PROPERTIES CXX_CLANG_TIDY "${clang_tidy_params}") 187endfunction() 188