mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
212 lines
6.4 KiB
Bash
Executable File
212 lines
6.4 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
|
|
else
|
|
clang-format --dry-run -style="$CLANG_FORMAT_STYLE" -i $FILES
|
|
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
|
|
FILES_WITHOUT_C_STDLIB_INCLUDES="$(echo $FILES | tr ' ' '\n' | grep -v \
|
|
-e '^runtime/support\.h$' \
|
|
-e '^runtime/support\.c$' \
|
|
-e '^runtime/early-linked\.c$' \
|
|
-e '^include/revng/Support/Assert\.h$' \
|
|
-e '^include/revng/Support/ClassSentinel\.h$' \
|
|
-e '^share/revngc/revng-c-include\.c$' \
|
|
)"
|
|
$GREP "^\s*#include <.*\.h>" $FILES_WITHOUT_C_STDLIB_INCLUDES | cat
|
|
|
|
# Parenthesis at the end of line (except for raw strings)
|
|
$GREP "(\$" $FILES | grep -v 'R"LLVM.*(' | cat
|
|
|
|
# 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 header files
|
|
for FILE in $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
|
|
|
|
}
|
|
|
|
# First, run the checks and output warnings in a human readable format.
|
|
run_clang_format
|
|
run_revng_checks | sort -u
|
|
|
|
# Second, re-run the check commands, and fail if any of them prints anything.
|
|
# This ensures that that user sees all the errors on the command line, while at
|
|
# the same time setting a proper exit value that can be checked by other scripts
|
|
# or by git hooks.
|
|
if [[ $( run_clang_format 2>&1 | head -c 1 | wc -c ) -ne 0 ]]; then
|
|
exit 1
|
|
fi
|
|
if [[ $( run_revng_checks 2>&1 | head -c 1 | wc -c ) -ne 0 ]]; then
|
|
exit 1
|
|
fi
|