Skip to content

Commit

Permalink
[CI] Add clang-tidy to lint (ray-project#18124)
Browse files Browse the repository at this point in the history
* clang-tidy

* fix

* fix script

* test clang compiler

* fix clang-tidy rules

* Fix windows and other issues.

* Fix

* Improve information when running check-git-clang-tidy-output.sh on different OS
  • Loading branch information
mwtian authored Sep 9, 2021
1 parent 8a06647 commit 26fd10c
Show file tree
Hide file tree
Showing 12 changed files with 656 additions and 12 deletions.
7 changes: 5 additions & 2 deletions .buildkite/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ RUN apt-get install -y -qq \
sudo unzip unrar apt-utils dialog tzdata wget rsync \
language-pack-en tmux cmake gdb vim htop \
libgtk2.0-dev zlib1g-dev libgl1-mesa-dev maven \
openjdk-8-jre openjdk-8-jdk clang-format-7
RUN ln -s /usr/bin/clang-format-7 /usr/bin/clang-format
openjdk-8-jre openjdk-8-jdk clang-format-7 jq \
clang-tidy-12 clang-12
RUN ln -s /usr/bin/clang-format-7 /usr/bin/clang-format && \
ln -s /usr/bin/clang-tidy-12 /usr/bin/clang-tidy && \
ln -s /usr/bin/clang-12 /usr/bin/clang
RUN curl -o- https://get.docker.com | sh

# System conf for tests
Expand Down
34 changes: 34 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Disable the following checks due to frequent false positives, noisiness,
# inconsistent style with existing codebase and other reasons:
# -misc-non-private-member-variables-in-classes (potentially too restrictive)
# -misc-unused-parameters (can be cleaned up in batch and enabled)
# -modernize-avoid-c-arrays (too restrictive)
# -modernize-pass-by-value (too restrictive)
# -modernize-return-braced-init-list (inconsistent style)
# -modernize-use-emplace (more subtle behavior)
# -modernize-use-trailing-return-type (inconsistent style)
#
# TODO: enable google-* and readability-* families of checks.
Checks: >
abseil-*,
bugprone-*,
misc-*,
-misc-non-private-member-variables-in-classes,
-misc-unused-parameters,
modernize-*,
-modernize-avoid-c-arrays,
-modernize-pass-by-value,
-modernize-return-braced-init-list,
-modernize-use-emplace,
-modernize-use-trailing-return-type,
performance-*,
CheckOptions:
# Reduce noisiness of the bugprone-narrowing-conversions check.
- key: bugprone-narrowing-conversions.IgnoreConversionFromTypes
value: 'size_t;ptrdiff_t;size_type;difference_type'
- key: bugprone-narrowing-conversions.WarnOnEquivalentBitWidth
value: 'false'

# Turn all the warnings from the checks above into errors.
WarningsAsErrors: "*"
30 changes: 21 additions & 9 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
# Bazel build
# C/C++ documentation: https://docs.bazel.build/versions/master/be/c-cpp.html

load("@rules_proto//proto:defs.bzl", "proto_library")
load("@rules_python//python:defs.bzl", "py_library")
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_proto_library", "cc_test")
load("@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library")
load("@com_github_grpc_grpc//bazel:cython_library.bzl", "pyx_library")
load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
load("//bazel:ray.bzl", "COPTS", "PYX_COPTS", "PYX_SRCS", "copy_to_workspace")

package(
default_visibility = ["//visibility:public"],
)

config_setting(
name = "msvc-cl",
flag_values = {"@bazel_tools//tools/cpp:compiler": "msvc-cl"},
Expand Down Expand Up @@ -1808,21 +1813,28 @@ cc_library(
],
)

filegroup(
name = "iwyu_sh",
srcs = ["ci/travis/iwyu.sh"],
)

filegroup(
name = "extra_actions_base_proto",
srcs = [
# TODO: Replace our file with the built-in copy once this issue is resolved:
# https://github.com/bazelbuild/bazel/issues/8738
"thirdparty/protobuf/extra_actions_base.proto",
#"@bazel_tools//src/main/protobuf:extra_actions_base.proto",
],
)

proto_library(
name = "extra_actions_base_proto_lib",
srcs = ["thirdparty/protobuf/extra_actions_base.proto"],
)

cc_proto_library(
name = "extra_actions_cc_proto_lib",
deps = [":extra_actions_base_proto_lib"],
)

filegroup(
name = "iwyu_sh",
srcs = ["ci/travis/iwyu.sh"],
)

action_listener(
name = "iwyu_cpp",
extra_actions = [":iwyu_action"],
Expand Down
22 changes: 22 additions & 0 deletions bazel/BUILD.rapidjson
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
licenses(["notice"])

package(default_visibility = ["//visibility:public"])

filegroup(
name = "license",
srcs = ["license.txt"],
)

cc_library(
name = "rapidjson",
hdrs = glob([
"include/rapidjson/*.h",
"include/rapidjson/*/*.h",
]),
copts = [
"-Wno-non-virtual-dtor",
"-Wno-unused-variable",
"-Wno-implicit-fallthrough",
],
includes = ["include"],
)
1 change: 1 addition & 0 deletions bazel/ray.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ def copy_to_workspace(name, srcs, dstdir = ""):
dstdir = "." + ("\\" + dstdir.replace("/", "\\")).rstrip("\\") + "\\",
),
local = 1,
tags = ["no-cache"],
)

def native_java_binary(module_name, name, native_binary_name):
Expand Down
6 changes: 6 additions & 0 deletions bazel/ray_deps_setup.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,9 @@ def ray_deps_setup():
build_file = "@com_github_ray_project_ray//bazel:BUILD.nlohmann_json",
)

auto_http_archive(
name = "rapidjson",
url = "https://github.com/Tencent/rapidjson/archive/v1.1.0.zip",
build_file = True,
sha256 = "8e00c38829d6785a2dfb951bb87c6974fa07dfe488aa5b25deec4b8bc0f6a3ab",
)
32 changes: 32 additions & 0 deletions ci/generate_compile_commands/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Tool for listening on Bazel actions and generate compile commands database.
#
# Using Bazel aspect to generate compile commands would be faster. Also Bazel
# action listeners are deprecated. We can switch to that if a stable solution
# exists, e.g. https://github.com/grailbio/bazel-compilation-database

cc_binary(
name = "extract_compile_command",
srcs = ["extract_compile_command.cc"],
# Build fails on Windows, and not part of Ray either.
tags = ["manual"],
deps = [
"//:extra_actions_cc_proto_lib",
"@com_google_protobuf//:protobuf",
"@rapidjson",
],
)

action_listener(
name = "compile_command_listener",
extra_actions = [":compile_command_action"],
mnemonics = ["CppCompile"],
)

extra_action(
name = "compile_command_action",
cmd = "$(location :extract_compile_command) \
$(EXTRA_ACTION_FILE) \
$(output $(ACTION_ID).compile_command.json)",
out_templates = ["$(ACTION_ID).compile_command.json"],
tools = [":extract_compile_command"],
)
121 changes: 121 additions & 0 deletions ci/generate_compile_commands/extract_compile_command.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright 2016 The Kythe Authors. All rights reserved.
*
* Licensed 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.
*
* Adapted from
* https://github.com/xulongwu4/bazel-compilation-database/blob/master/kythe/generate_compile_commands/extract_compile_command.cc
*/
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <cstdio>
#include <string>
#include <vector>

#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/stubs/common.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#include "thirdparty/protobuf/extra_actions_base.pb.h"

namespace {
using ::google::protobuf::io::CodedInputStream;
using ::google::protobuf::io::FileInputStream;

bool ReadExtraAction(const std::string &path, blaze::ExtraActionInfo *info,
blaze::CppCompileInfo *cpp_info) {
int fd = ::open(path.c_str(), O_RDONLY, S_IREAD | S_IWRITE);
if (fd < 0) {
perror("Failed to open input: ");
return false;
}
FileInputStream file_input(fd);
file_input.SetCloseOnDelete(true);

CodedInputStream input(&file_input);
if (!info->ParseFromCodedStream(&input)) return false;
if (!info->HasExtension(blaze::CppCompileInfo::cpp_compile_info)) return false;
*cpp_info = info->GetExtension(blaze::CppCompileInfo::cpp_compile_info);
return true;
}

std::string JoinCommand(const std::vector<std::string> &command) {
std::string output;
if (command.empty()) return output;

// TODO(shahms): Deal with embedded spaces and quotes.
auto iter = command.begin();
output = *iter++;
for (; iter != command.end(); ++iter) {
output += " " + *iter;
}
return output;
}

std::string FormatCompilationCommand(const std::string &source_file,
const std::vector<std::string> &command) {
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
writer.StartObject();
writer.Key("file");
writer.String(source_file.c_str());
writer.Key("directory");
writer.String("@BAZEL_ROOT@");
writer.Key("command");
writer.String(JoinCommand(command).c_str());
writer.EndObject();
return buffer.GetString();
}
} // namespace

int main(int argc, char **argv) {
GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 3) {
std::cerr << "usage: " << argv[0] << " extra-action-file output-file" << std::endl;
return 1;
}
std::string extra_action_file = argv[1];
std::string output_file = argv[2];
blaze::ExtraActionInfo info;
blaze::CppCompileInfo cpp_info;
if (!ReadExtraAction(extra_action_file, &info, &cpp_info)) return 1;

std::vector<std::string> args;
args.push_back(cpp_info.tool());
args.insert(args.end(), cpp_info.compiler_option().begin(),
cpp_info.compiler_option().end());
if (std::find(args.begin(), args.end(), "-c") == args.end()) {
args.push_back("-c");
args.push_back(cpp_info.source_file());
}
if (std::find(args.begin(), args.end(), "-o") == args.end()) {
args.push_back("-o");
args.push_back(cpp_info.output_file());
}

FILE *output = ::fopen(output_file.c_str(), "w");
if (output == nullptr) {
perror("Unable to open file for writing: ");
return 1;
}
::fputs(FormatCompilationCommand(cpp_info.source_file(), args).c_str(), output);
::fclose(output);

google::protobuf::ShutdownProtobufLibrary();
return 0;
}
92 changes: 92 additions & 0 deletions ci/travis/check-git-clang-tidy-output.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/bin/bash

# TODO: integrate this script into pull request workflow.

printError() {
printf '\033[31mERROR:\033[0m %s\n' "$@"
}

printInfo() {
printf '\033[32mINFO:\033[0m %s\n' "$@"
}

log_err() {
printError "Setting up clang-tidy encountered an error"
}

set -eo pipefail

trap '[ $? -eq 0 ] || log_err' EXIT

printInfo "Fetching workspace info ..."

WORKSPACE=$(bazel info workspace)
BAZEL_ROOT=$(bazel info execution_root)

printInfo "Generating compilation database ..."

case "${OSTYPE}" in
linux*)
printInfo " Running on Linux, using clang to build C++ targets. Please make sure it is installed ..."
CC=clang bazel build //ci/generate_compile_commands:extract_compile_command //:ray_pkg \
--experimental_action_listener=//ci/generate_compile_commands:compile_command_listener;;
darwin*)
printInfo " Running on MacOS, assuming default C++ compiler is clang ..."
bazel build //ci/generate_compile_commands:extract_compile_command //:ray_pkg \
--experimental_action_listener=//ci/generate_compile_commands:compile_command_listener;;
msys*)
printInfo " Running on Windows, using clang-cl to build C++ targets. Please make sure it is installed ..."
CC=clang-cl bazel build //ci/generate_compile_commands:extract_compile_command //:ray_pkg \
--experimental_action_listener=//ci/generate_compile_commands:compile_command_listener;;
esac

printInfo "Assembling compilation database ..."

TMPFILE=$(mktemp)
printf '[\n' >"$TMPFILE"
find "$BAZEL_ROOT" -name '*.compile_command.json' -exec cat {} + >>"$TMPFILE"
printf '\n]\n' >>"$TMPFILE"

if [[ "${OSTYPE}" =~ darwin* ]]; then
sed -i '' "s|@BAZEL_ROOT@|$BAZEL_ROOT|g" "$TMPFILE"
sed -i '' "s/}{/},\n{/g" "$TMPFILE"
else
sed -i "s|@BAZEL_ROOT@|$BAZEL_ROOT|g" "$TMPFILE"
sed -i "s/}{/},\n{/g" "$TMPFILE"
fi

OUTFILE=$WORKSPACE/compile_commands.json

if hash jq 2>/dev/null; then
printInfo "Formatting compilation database ..."
jq . "$TMPFILE" >"$OUTFILE"
else
printInfo "Can not find jq. Skip formatting compilation database."
cp --no-preserve=mode "$TMPFILE" "$OUTFILE"
fi

# Compare against the master branch, because most development is done against it.
base_commit="$(git merge-base HEAD master)"
if [ "$base_commit" = "$(git rev-parse HEAD)" ]; then
# Prefix of master branch, so compare against parent commit
base_commit="$(git rev-parse HEAD^)"
printInfo "Running clang-tidy against parent commit $base_commit"
else
printInfo "Running clang-tidy against parent commit $base_commit from master branch"
fi

trap - EXIT

if git diff -U0 "$base_commit" | ci/travis/clang-tidy-diff.py -p1 -fix; then
printInfo "clang-tidy passed."
else
printError "clang-tidy failed. See above for details including suggested fixes."
printError
printError "If you think the warning is too aggressive, the proposed fix is incorrect or are unsure about how to"
printError "fix, feel free to raise the issue on the PR or Anyscale #learning-cplusplus Slack channel."
printError
printError "To run clang-tidy locally with fix suggestions, make sure clang and clang-tidy are installed and"
printError "available in PATH (version 12 is preferred). Then run"
printError "scripts/check-git-clang-tidy-output.sh"
printError "from repo root."
fi
Loading

0 comments on commit 26fd10c

Please sign in to comment.