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