Setup clang-format as an Arcanist linter

Summary:
This uses clang-format-diff as a linter for Arcanist.

`arc lint` flow, also run as part of `arc diff` unless skipped with
`--nolint`, will now run the linter shell script on the changed files,
and prompt the user to accept the suggested changes.

Message when clang-format-diff is not installed:
{F6654094}

Example of the noise during code review when clang-format-diff is not installed:
https://reviews.llvm.org/differential/changeset/?ref=1115809

Prompt when clang-format-diff is installed and suggests edits:
{F6650223}

Reviewers: probinson, scott.linder

Reviewed By: scott.linder

Subscribers: scott.linder, MyDeveloperDay, JonasToth, danilaml, JDevlieghere, dberris, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D49116
This commit is contained in:
Siddhartha Bagaria 2020-03-30 14:20:58 -04:00 committed by Scott Linder
parent 0af6d27e2e
commit 3c371491a2
2 changed files with 71 additions and 0 deletions

12
.arclint Normal file
View File

@ -0,0 +1,12 @@
{
"linters": {
"clang-format": {
"type": "script-and-regex",
"script-and-regex.script": "utils/arcanist/clang-format.sh",
"script-and-regex.regex": "/^(?P<severity>[[:alpha:]]+)\n(?P<message>[^\n]+)\n(====|(?P<line>\\d),(?P<char>\\d)\n(?P<original>.*)>>>>\n(?P<replacement>.*)<<<<\n)$/s",
"include": [
"(\\.(cc|cpp|h)$)"
]
}
}
}

59
utils/arcanist/clang-format.sh Executable file
View File

@ -0,0 +1,59 @@
#!/bin/bash
set -euo pipefail
# "script-and-regex.regex": "/^(?P<severity>.*?)\n(?P<message>.*?)\n(?P<line>\\d),(?P<char>\\d)(\n(?P<original>.*?)>>>>\n(?P<replacement>.*?)<<<<?)$/s",
# Arcanist linter that invokes clang-format.
# stdout from this script is parsed into a regex and used by Arcanist.
# https://secure.phabricator.com/book/phabricator/article/arcanist_lint_script_and_regex/
# To skip running all linters when creating/updating a diff, use `arc diff --nolint`.
if ! hash clang-format-diff >/dev/null; then
# advice severity level is completely non-disruptive.
# switch to warning or error if you want to prompt the user.
echo "advice"
echo "clang-format-diff not found in user's PATH; not linting file."
echo "===="
exit 0
fi
src_file="${1}"
original_file="$(mktemp)"
formatted_file="$(mktemp)"
readonly src_file
readonly original_file
readonly formatted_file
cp -p "${src_file}" "${original_file}"
cp -p "${src_file}" "${formatted_file}"
cleanup() {
rc=$?
rm "${formatted_file}" "${original_file}"
exit ${rc}
}
trap 'cleanup' INT HUP QUIT TERM EXIT
# Arcanist can filter out lint messages for unchanged lines, but for that, we
# need to generate line by line lint messages. Instead, we generate one lint
# message on line 1, char 1 with file content edited using clang-format-diff.
if git rev-parse --git-dir >/dev/null; then
arc_base_commit=$(arc which --show-base)
# An alternative is to use git-clang-format.
git diff -U0 --no-color "${arc_base_commit}"| clang-format-diff -style LLVM -i -p1
else
svn diff --diff-cmd=diff -x -U0 "${src_file}" | clang-format-diff -style LLVM -i
fi
cp -p "${src_file}" "${formatted_file}"
cp -p "${original_file}" "${src_file}"
if ! diff -q "${src_file}" "${formatted_file}" > /dev/null ; then
echo "autofix"
echo "clang-format suggested style edits found:"
echo "1,1" # line,char of start of replacement.
cat "${src_file}"
echo ">>>>"
cat "${formatted_file}"
echo "<<<<"
fi