diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000000..a2a2c95c1b --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# https://releases.llvm.org/14.0.0/tools/clang/tools/extra/docs/clang-tidy/index.html + +CheckOptions: [] +Checks: 'abseil-*,boost-*,bugprone-*,cert-*,clang-analyzer-*,concurrency-*,cppcoreguidelines-*,darwin-*,fuchsia-*,google-*,hicpp-*,linuxkernel-*,llvm-*,misc-*,modernize-*,performance-*,portability-*,readability-*' +ExtraArgs: +ExtraArgsBefore: [] +FormatStyle: none +HeaderFilterRegex: '' +InheritParentConfig: true +UseColor: true +User: 'clang-tidy' +WarningsAsErrors: '' diff --git a/.github/workflows/lint_and_test_cpp.yaml b/.github/workflows/lint_and_test_cpp.yaml index 799263566a..5e4fb7d468 100644 --- a/.github/workflows/lint_and_test_cpp.yaml +++ b/.github/workflows/lint_and_test_cpp.yaml @@ -50,16 +50,40 @@ env: jobs: cpp_clang_format_linter: - name: Lint + name: Format runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - name: clang-format run: ./scripts/run-clang-format.py --clang-format-executable clang-format-14 -e ./src/shell/linenoise -e ./src/shell/sds -e ./thirdparty -r . + cpp_clang_tidy_linter: + name: Tidy + runs-on: ubuntu-22.04 + container: + image: apache/pegasus:thirdparties-bin-ubuntu2204-${{ github.base_ref }} + steps: + - name: Install Softwares + run: | + apt-get update + apt-get install clang-tidy -y + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Rebuild thirdparty if needed + uses: "./.github/actions/rebuild_thirdparty_if_needed" + - name: clang-tidy + run: | + git config --global --add safe.directory $(pwd) + ./run.sh build --test --compiler clang-14,clang++-14 -t debug --skip_thirdparty -c --cmake_only + ./scripts/clang_tidy.py --rev-range $(git log origin/${{ github.base_ref }} -n1 --format=format:"%H") + shell: bash + iwyu: name: IWYU - needs: cpp_clang_format_linter + needs: + - cpp_clang_format_linter + - cpp_clang_tidy_linter runs-on: ubuntu-latest env: USE_JEMALLOC: OFF @@ -87,7 +111,9 @@ jobs: build_Release: name: Build Release - needs: cpp_clang_format_linter + needs: + - cpp_clang_format_linter + - cpp_clang_tidy_linter runs-on: ubuntu-latest env: USE_JEMALLOC: OFF @@ -170,7 +196,9 @@ jobs: build_ASAN: name: Build ASAN - needs: cpp_clang_format_linter + needs: + - cpp_clang_format_linter + - cpp_clang_tidy_linter runs-on: ubuntu-latest env: USE_JEMALLOC: OFF @@ -257,7 +285,9 @@ jobs: # before we find any way to reduce the time cost. # build_UBSAN: # name: Build UBSAN -# needs: cpp_clang_format_linter +# needs: +# - cpp_clang_format_linter +# - cpp_clang_tidy_linter # runs-on: ubuntu-latest # env: # USE_JEMALLOC: OFF @@ -337,7 +367,9 @@ jobs: build_with_jemalloc: name: Build with jemalloc - needs: cpp_clang_format_linter + needs: + - cpp_clang_format_linter + - cpp_clang_tidy_linter runs-on: ubuntu-latest env: USE_JEMALLOC: ON @@ -378,7 +410,9 @@ jobs: build_release_on_macos: name: Build Release on macOS - needs: cpp_clang_format_linter + needs: + - cpp_clang_format_linter + - cpp_clang_tidy_linter runs-on: macos-12 steps: - name: Install Softwares @@ -412,7 +446,9 @@ jobs: build_debug_on_centos7: name: Build Debug on CentOS 7 - needs: cpp_clang_format_linter + needs: + - cpp_clang_format_linter + - cpp_clang_tidy_linter runs-on: ubuntu-latest env: USE_JEMALLOC: OFF diff --git a/run.sh b/run.sh index dfe4f7ea98..8c6048b019 100755 --- a/run.sh +++ b/run.sh @@ -114,6 +114,7 @@ function usage_build() echo " --enable_rocksdb_portable build a portable rocksdb binary" echo " --test whether to build test binaries" echo " --iwyu specify the binary path of 'include-what-you-use' when build with IWYU" + echo " --cmake_only whether to run cmake only, default no" } function exit_if_fail() { @@ -131,6 +132,7 @@ function run_build() C_COMPILER="gcc" CXX_COMPILER="g++" BUILD_TYPE="release" + # TODO(yingchun): some boolean variables are using YES/NO, some are using ON/OFF, should be unified. CLEAR=NO CLEAR_THIRDPARTY=NO JOB_NUM=8 @@ -145,6 +147,7 @@ function run_build() BUILD_TEST=OFF IWYU="" BUILD_MODULES="" + CMAKE_ONLY=NO while [[ $# > 0 ]]; do key="$1" case $key in @@ -220,6 +223,9 @@ function run_build() IWYU="$2" shift ;; + --cmake_only) + CMAKE_ONLY=YES + ;; *) echo "ERROR: unknown option \"$key\"" echo @@ -353,6 +359,11 @@ function run_build() rm -f ${BUILD_LATEST_DIR} ln -s ${BUILD_DIR} ${BUILD_LATEST_DIR} + if [ "$CMAKE_ONLY" == "YES" ]; then + echo "CMake only, exit" + return + fi + echo "[$(date)] Building Pegasus ..." pushd $BUILD_DIR if [ ! -z "${IWYU}" ]; then diff --git a/scripts/clang_tidy.py b/scripts/clang_tidy.py new file mode 100755 index 0000000000..2a24eb8129 --- /dev/null +++ b/scripts/clang_tidy.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Most of the code are inspired by https://github.com/apache/kudu/blob/856fa3404b00ee02bd3bc1d77d414ede2b2cd02e/build-support/clang_tidy_gerrit.py + +import argparse +import collections +import json +import multiprocessing +from multiprocessing.pool import ThreadPool +import os +import re +import subprocess +import sys +import tempfile + +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) + +BUILD_PATH = os.path.join(ROOT, "build", "latest") + +def run_tidy(sha="HEAD", is_rev_range=False): + diff_cmdline = ["git", "diff" if is_rev_range else "show", sha] + + # Figure out which paths changed in the given diff. + changed_paths = subprocess.check_output(diff_cmdline + ["--name-only", "--pretty=format:"]).splitlines() + changed_paths = [p for p in changed_paths if p] + + # Produce a separate diff for each file and run clang-tidy-diff on it + # in parallel. + # + # Note: this will incorporate any configuration from .clang-tidy. + def tidy_on_path(path): + patch_file = tempfile.NamedTemporaryFile() + cmd = diff_cmdline + [ + "--src-prefix=%s/" % ROOT, + "--dst-prefix=%s/" % ROOT, + "--", + path] + subprocess.check_call(cmd, stdout=patch_file, cwd=ROOT) + # TODO(yingchun): some checks could be disabled before we fix them. + # "-checks=-llvm-include-order,-modernize-concat-nested-namespaces,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-macro-usage,-cppcoreguidelines-special-member-functions,-hicpp-special-member-functions,-modernize-use-trailing-return-type,-bugprone-easily-swappable-parameters,-google-readability-avoid-underscore-in-googletest-name,-cppcoreguidelines-avoid-c-arrays,-hicpp-avoid-c-arrays,-modernize-avoid-c-arrays,-llvm-header-guard,-cppcoreguidelines-pro-bounds-pointer-arithmetic", + cmdline = ["clang-tidy-diff", + "-clang-tidy-binary", + "clang-tidy", + "-p0", + "-path", BUILD_PATH, + "-extra-arg=-language=c++", + "-extra-arg=-std=c++17", + "-extra-arg=-Ithirdparty/output/include"] + return subprocess.check_output( + cmdline, + stdin=open(patch_file.name), + cwd=ROOT).decode() + pool = ThreadPool(multiprocessing.cpu_count()) + try: + return "".join(pool.imap(tidy_on_path, changed_paths)) + except KeyboardInterrupt as ki: + sys.exit(1) + finally: + pool.terminate() + pool.join() + + +if __name__ == "__main__": + # Basic setup and argument parsing. + parser = argparse.ArgumentParser(description="Run clang-tidy on a patch") + parser.add_argument("--rev-range", action="store_true", + default=False, + help="Whether the revision specifies the 'rev..' range") + parser.add_argument('rev', help="The git revision (or range of revisions) to process") + args = parser.parse_args() + + # Run clang-tidy and parse the output. + clang_output = run_tidy(args.rev, args.rev_range) + parsed = re.match(r'.+(warning|error): .+', clang_output, re.MULTILINE | re.DOTALL) + print(clang_output, file=sys.stderr) + if not parsed: + print("No warnings", file=sys.stderr) + sys.exit(0) + sys.exit(1) +