Files
revng-revng/scripts/revng-check-conventions
Alessandro Di Federico 2b55d1df22 Adopt cmake-format
2022-03-17 18:52:18 +01:00

234 lines
6.9 KiB
Bash
Executable File

#!/bin/bash
#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
set -e
function print_usage() {
cat > /dev/stderr << END_USAGE_TEXT
SYNOPSIS
$0 [<options>] [FILES...]
DESCRIPTION
Checks that the files specified in FILES... respect the rev.ng coding
conventions, and prints all the violations.
If the FILES... arguments are missing, checks that all the C++ source files in
the project that have already been added to the git repository project
respect the rev.ng coding conventions.
OPTIONS
--help
Prints this help and exit
--force-format
In addition to checking the rev.ng coding conventions on the specified
files, uses clang-format to try to enforce the coding conventions
automatically.
If this fails, exit with failure, otherwise exit with success.
WARNING: using this option will overwrite your files, make sure to backup
important stuff.
--use-local-clang-format-file
By default, clang-format is executed with a hard-coded configuration that
should apply to all the projects under the rev.ng umbrella.
When this option is passed, the hard-coded configuration is ignored, and
clang-format looks for configuration in a .clang-format file in the
current directory or in its parent directories.
This allows to use different clang-format configuration on per-project
basis, in cases where the hard-coded configuration does not fit (e.g Qt
projects where Qt coding conventions are a better fit).
See clang-format documentation for more details.
--print-clang-format-config
Print the clang-format configuration to stdout, ignoring all the other
arguments except for --use-local-clang-format-file.
The conventions are not checked.
FILES
List of filenames of the files for which you want to check the rev.ng
coding conventions.
RETURN VALUES
On success exit code is 0.
On failure, i.e. if there is at least one file that is not respecting the
coding conventions, exit code is 1.
END_USAGE_TEXT
}
SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FORCE_FORMAT="0"
USE_CLANG_FORMAT_FILE="0"
PRINT_CLANG_FORMAT_CONFIG="0"
while [[ $# > 0 ]]; do
key="$1"
case $key in
--print-clang-format-config)
PRINT_CLANG_FORMAT_CONFIG="1"
shift # past argument
;;
--force-format)
FORCE_FORMAT="1"
shift # past argument
;;
--use-local-clang-format-file)
USE_CLANG_FORMAT_FILE="1"
shift # past argument
;;
--help)
print_usage
exit 0
;;
-*)
echo "Error: unrecognized option $key" > /dev/stderr
print_usage
exit 1
;;
*)
break
;;
esac
done
CLANG_FORMAT_STYLE_FILE="$SCRIPT_PATH/clang-format-style-file"
if ! test -e "$CLANG_FORMAT_STYLE_FILE"; then
CLANG_FORMAT_STYLE_FILE="$SCRIPT_PATH/../../share/revng/clang-format-style-file"
if ! test -e "$CLANG_FORMAT_STYLE_FILE"; then
echo "Can't find clang-format-style-file" > /dev/stderr
exit 1
fi
fi
CLANG_FORMAT_STYLE=$(cat "$CLANG_FORMAT_STYLE_FILE")
if test "$USE_CLANG_FORMAT_FILE" -gt 0; then
CLANG_FORMAT_STYLE=file
fi
# If the user passed the --print-clang-format-config, dump the config and exit
# with success.
if test "$PRINT_CLANG_FORMAT_CONFIG" -gt 0; then
clang-format --dry-run -style="$CLANG_FORMAT_STYLE" --dump-config
exit 0
fi
if [[ $# -eq 0 ]]; then
FILES="$(git ls-files | grep -E '\.(c|cc|cpp|h|hpp)$')"
else
FILES="$@"
fi
GREP="git grep -n --color=always"
# Run clang-format on FILES
function run_clang_format() {
if test "$FORCE_FORMAT" -gt 0; then
clang-format -style="$CLANG_FORMAT_STYLE" -i $FILES || true
else
clang-format --dry-run -style="$CLANG_FORMAT_STYLE" -i $FILES
fi
}
# Run black
function run_black() {
readarray -t PYTHON_FILES < <(( git grep -l '^#!.*python' && git ls-files | grep '\.py$' ) | sort -u )
if [[ ${#PYTHON_FILES[@]} -eq 0 ]]; then return; fi
if test "$FORCE_FORMAT" -gt 0; then
black -q -l 100 "${PYTHON_FILES[@]}"
else
black --check -l 100 "${PYTHON_FILES[@]}" | grep 'Oh no'
fi
}
# Run cmake-format
function run_cmake_format() {
if test "$FORCE_FORMAT" -gt 0; then
cmake-format -i $(git ls-files | grep -i cmake) -l error
else
cmake-format --check $(git ls-files | grep -i cmake) -l error
fi
}
# Run revng-specific checks on files
function run_revng_checks() {
# Check for lines longer than 80 columns
$GREP -E '^.{81,}$' $FILES | cat
# Things should never match
for REGEXP in '\(--> 0\)' ';;' '^\s*->.*;$' 'Twine [^&]'; do
$GREP "$REGEXP" $FILES | cat
done
# Things should never match (except in support.c)
FILTERED_FILES="$(echo $FILES | tr ' ' '\n' | grep -v \
-e '^runtime/support\.c$' \
-e '^lib/Support/Assert\.cpp$' \
)"
for REGEXP in '\babort(' '\bassert(' 'assert(false' 'llvm_unreachable'; do
$GREP "$REGEXP" $FILTERED_FILES | cat
done
# Things should never be at the end of a line
for REGEXP in '::' '<' 'RegisterPass.*>' '} else' '\bopt\b.*>'; do
$GREP "$REGEXP\$" $FILES | cat
done
# Includes should never use <..> except for C++ standard includes
$GREP "^\s*#include <.*\.hpp>" $FILES | cat
CXX_FILES="$(echo $FILES | tr ' ' '\n' | grep -v \
-e '^runtime/support\.h$' \
-e '^include/revng/Runtime/.*$' \
-e '^include/revng/PipelineC/.*$' \
-e '^include/revng/Support/Assert\.h$' \
-e '^include/revng/Support/ClassSentinel\.h$' \
-e '\.c$' \
)"
$GREP "^\s*#include <.*\.h>" $CXX_FILES | cat
# Parenthesis at the end of line (except for raw strings)
$GREP "(\$" $FILES | grep -v 'R"LLVM.*(' | cat
# Ban whitespaces at the end of a line
$GREP " \$" | cat
# Ban tabs altogether
$GREP -P "\t" | cat
# Ensure all files end with a newline
git ls-files | while read FILE; do
if test -s "$FILE" && ! test $(tail -c 1 "$FILE" | base64) == "Cg=="; then
echo "$FILE does not end with a newline"
fi
done
# Things should never be at the beginning of a line
for REGEXP in '\*>' '/[^/\*]' ':[^:\(]*)' '==' '\!=' '<[^<]' '>' '>=' '<=' '//\s*WIP' '#if\s*[01]'; do
$GREP "^\s*$REGEXP" $FILES | cat
done
# Check there are no static functions in C++ header files
for FILE in $CXX_FILES; do
if [[ $FILE == *h ]]; then
$GREP -H '^static\b[^=]*$' "$FILE" | cat
head -n1 "$FILE" | grep -E '^#pragma once$' > /dev/null || echo "$FILE: header does not start with #pragma once"
fi
done
}
if test $( ( run_clang_format && run_black && run_cmake_format && run_revng_checks | sort -u ) |& tee /dev/stderr | wc -c ) -ne 0; then
exit 1
fi