• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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