diff --git a/.circleci/config.yml b/.circleci/config.yml index ff0e1036f2ca5..52fb9cd1ec75e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -82,6 +82,14 @@ jobs: - run: ci/coverage_publish.sh - store_artifacts: path: /build/envoy/generated/coverage + + clang_tidy: + executor: ubuntu-build + steps: + - run: rm -rf /home/circleci/project/.git # CircleCI git caching is likely broken + - checkout + - run: ci/do_circle_ci.sh bazel.clang_tidy + format: executor: ubuntu-build resource_class: small @@ -140,6 +148,7 @@ workflows: - ipv6_tests - coverage - format + - clang_tidy - build_image - docs: filters: diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000000000..55d1c2389161b --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,14 @@ +Checks: 'clang-diagnostic-*,clang-analyzer-*,abseil-*,bugprone-*,modernize-*,performance-*,readability-redundant-*,readability-braces-around-statements' + +#TODO(lizan): grow this list, fix possible warnings and make more checks as error +WarningsAsErrors: 'bugprone-assert-side-effect,modernize-make-shared,modernize-make-unique,readability-redundant-smartptr-get,readability-braces-around-statements' + +CheckOptions: + - key: bugprone-assert-side-effect.AssertMacros + value: 'ASSERT' + + - key: bugprone-dangling-handle.HandleClasses + value: 'std::basic_string_view;std::experimental::basic_string_view;absl::string_view' + + - key: modernize-use-auto.MinTypeNameLength + value: '10' diff --git a/ci/README.md b/ci/README.md index f8f6787ce67a6..e7169a54f2c09 100644 --- a/ci/README.md +++ b/ci/README.md @@ -82,7 +82,8 @@ The `./ci/run_envoy_docker.sh './ci/do_ci.sh '` targets are: * `bazel.release.server_only` — build Envoy static binary under `-c opt` with gcc. * `bazel.coverage` — build and run tests under `-c dbg` with gcc, generating coverage information in `$ENVOY_DOCKER_BUILD_DIR/envoy/generated/coverage/coverage.html`. * `bazel.coverity` — build Envoy static binary and run Coverity Scan static analysis. -* `bazel.tsan` — build and run tests under `-c dbg --config=clang-tsan` with clang-6.0. +* `bazel.tsan` — build and run tests under `-c dbg --config=clang-tsan` with clang. +* `bazel.clang_tidy` — build and run clang-tidy over all source files. * `check_format`— run `clang-format-6.0` and `buildifier` on entire source tree. * `fix_format`— run and enforce `clang-format-6.0` and `buildifier` on entire source tree. * `check_spelling`— run `misspell` on entire project. diff --git a/ci/build_setup.sh b/ci/build_setup.sh index 0f292edc4bf5e..f13905ca9139e 100755 --- a/ci/build_setup.sh +++ b/ci/build_setup.sh @@ -114,8 +114,8 @@ mkdir -p "${ENVOY_FILTER_EXAMPLE_SRCDIR}"/bazel mkdir -p "${ENVOY_CI_DIR}"/bazel ln -sf "${ENVOY_SRCDIR}"/bazel/get_workspace_status "${ENVOY_FILTER_EXAMPLE_SRCDIR}"/bazel/ ln -sf "${ENVOY_SRCDIR}"/bazel/get_workspace_status "${ENVOY_CI_DIR}"/bazel/ -ln -sf "${ENVOY_SRCDIR}"/.bazelrc "${ENVOY_FILTER_EXAMPLE_SRCDIR}"/ -ln -sf "${ENVOY_SRCDIR}"/.bazelrc "${ENVOY_CI_DIR}"/ +cp -f "${ENVOY_SRCDIR}"/.bazelrc "${ENVOY_FILTER_EXAMPLE_SRCDIR}"/ +cp -f "${ENVOY_SRCDIR}"/.bazelrc "${ENVOY_CI_DIR}"/ # TODO(PiotrSikora): remove once we deprecate tools/bazel.rc in favor of .bazelrc. mkdir -p "${ENVOY_FILTER_EXAMPLE_SRCDIR}"/tools mkdir -p "${ENVOY_CI_DIR}"/tools @@ -127,8 +127,8 @@ export BUILDIFIER_BIN="/usr/local/bin/buildifier" function cleanup() { # Remove build artifacts. This doesn't mess with incremental builds as these # are just symlinks. - rm -f "${ENVOY_SRCDIR}"/bazel-* - rm -f "${ENVOY_CI_DIR}"/bazel-* + rm -rf "${ENVOY_SRCDIR}"/bazel-* + rm -rf "${ENVOY_CI_DIR}"/bazel-* rm -rf "${ENVOY_CI_DIR}"/bazel rm -rf "${ENVOY_CI_DIR}"/tools } diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 83539c1fa17ba..8f6311a6edb02 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -172,6 +172,11 @@ elif [[ "$1" == "bazel.coverage" ]]; then cd "${ENVOY_BUILD_DIR}" SRCDIR="${GCOVR_DIR}" "${ENVOY_SRCDIR}"/test/run_envoy_bazel_coverage.sh exit 0 +elif [[ "$1" == "bazel.clang_tidy" ]]; then + setup_clang_toolchain + cd "${ENVOY_CI_DIR}" + ./run_clang_tidy.sh + exit 0 elif [[ "$1" == "bazel.coverity" ]]; then # Coverity Scan version 2017.07 fails to analyze the entirely of the Envoy # build when compiled with Clang 5. Revisit when Coverity Scan explicitly diff --git a/ci/run_clang_tidy.sh b/ci/run_clang_tidy.sh new file mode 100755 index 0000000000000..5809052058299 --- /dev/null +++ b/ci/run_clang_tidy.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +set -e + +echo "Generating compilation database..." +# The compilation database generate script doesn't support passing build options via CLI. +# Writing them into bazelrc +echo "build ${BAZEL_BUILD_OPTIONS}" >> .bazelrc + +# bazel build need to be run to setup virtual includes, generating files which are consumed +# by clang-tidy +"${ENVOY_SRCDIR}/tools/gen_compilation_database.py" --run_bazel_build + +# It had to be in ENVOY_CI_DIR to run bazel to generate compile database, but clang-tidy-diff +# diff against current directory, moving them to ENVOY_SRCDIR. +mv ./compile_commands.json "${ENVOY_SRCDIR}/compile_commands.json" +cd "${ENVOY_SRCDIR}" + +if [[ "${RUN_FULL_CLANG_TIDY}" == 1 ]]; then + echo "Running full clang-tidy..." + run-clang-tidy-7 +elif [[ -z "${CIRCLE_PR_NUMBER}" && "$CIRCLE_BRANCH" == "master" ]]; then + echo "On master branch, running clang-tidy-diff against previous commit..." + git diff HEAD^ | clang-tidy-diff-7.py -p 1 +else + echo "Running clang-tidy-diff against master branch..." + git fetch https://github.com/envoyproxy/envoy.git master + git diff $(git merge-base HEAD FETCH_HEAD)..HEAD | clang-tidy-diff-7.py -p 1 +fi diff --git a/tools/gen_compilation_database.py b/tools/gen_compilation_database.py index c312eefb2bee4..39398cf4a7a11 100755 --- a/tools/gen_compilation_database.py +++ b/tools/gen_compilation_database.py @@ -3,9 +3,15 @@ import argparse import os import json +import subprocess -def generateCompilationDatabase(): - os.system("bazel/gen_compilation_database.sh //source/... //test/... //tools/...") +def generateCompilationDatabase(args): + if args.run_bazel_build: + subprocess.check_call(["bazel", "build"] + args.bazel_targets) + + gen_compilation_database_sh = os.path.join(os.path.realpath(os.path.dirname(__file__)), + "../bazel/gen_compilation_database.sh") + subprocess.check_call([gen_compilation_database_sh] + args.bazel_targets) def isCompileTarget(target, args): filename = target["file"] @@ -40,14 +46,19 @@ def fixCompilationDatabase(args): db = json.load(db_file) db = [modifyCompileCommand(target) for target in db if isCompileTarget(target, args)] + + # Remove to avoid writing into symlink + os.remove("compile_commands.json") with open("compile_commands.json", "w") as db_file: json.dump(db, db_file, indent=2) if __name__ == "__main__": parser = argparse.ArgumentParser(description='Generate JSON compilation database') - parser.add_argument('--include_external', type=bool, default=False) - parser.add_argument('--include_genfiles', type=bool, default=False) - parser.add_argument('--include_headers', type=bool, default=False) + parser.add_argument('--run_bazel_build', action='store_true') + parser.add_argument('--include_external', action='store_true') + parser.add_argument('--include_genfiles', action='store_true') + parser.add_argument('--include_headers', action='store_true') + parser.add_argument('bazel_targets', nargs='*', default=["//source/...", "//test/...", "//tools/..."]) args = parser.parse_args() - generateCompilationDatabase() + generateCompilationDatabase(args) fixCompilationDatabase(args)