Running clang-format on files with some additional custom scripts for… (#444)

* Running clang-format on files with some additional custom scripts for my style

* Fix missing unique_ptr in remill/BC/Optimizer.h

* Fixes and selective disabling of clang-format
This commit is contained in:
Peter Goodman
2020-08-05 15:42:25 -04:00
committed by GitHub
parent e26fea16bb
commit 99df2e19d4
107 changed files with 38130 additions and 37234 deletions
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# Copyright 2020, Trail of Bits, Inc. All rights reserved.
# Get the list of changed C++ header and source files.
STAGED_FILES=$( git diff --cached --name-only --diff-filter=ACM | grep -e '\.\(h\)\|\(cpp\)$' )
if [[ "${STAGED_FILES}" = "" ]]; then
exit 0
fi
PYTHON3_EXE=$( which python3 )
if [[ "$?" == 1 ]]; then
echo "\t\033[41mPlease install python3\033[0m"
exit 1
fi
CLANG_FORMAT_EXE=$( which clang-format )
if [[ "$?" == 1 ]]; then
echo "\t\033[41mPlease install clang-format\033[0m"
exit 1
fi
THIS_FILE_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
NAME_OF_THIS_FILE_DIR=$( basename "${THIS_FILE_DIR}" )
IN_SCRIPTS_DIR=0
# This script being executed is located in the `scripts/` directory.
if [[ "${NAME_OF_THIS_FILE_DIR}" == "scripts" ]] ; then
SCRIPTS_DIR="${THIS_FILE_DIR}"
SOURCE_DIR=$( cd "$( dirname "${SCRIPTS_DIR}" )" && pwd )
IN_SCRIPTS_DIR=1
# This script being executed is located in the `.git/hooks` directory.
elif [[ "${NAME_OF_THIS_FILE_DIR}" == "hooks" ]] ; then
GIT_DIR=$( cd "$( dirname "${SCRIPTS_DIR}" )" && pwd )
SOURCE_DIR=$( cd "$( dirname "${GIT_DIR}" )" && pwd )
SCRIPTS_DIR="${SOURCE_DIR}/scripts"
# Not sure where this script is.
else
echo "\t\033[41mScript '${BASH_SOURCE[0]}' is in an unexpected location\033[0m"
echo 1
fi
# Run our wrapper of `clang-format` on the files that have changed.
${PYTHON3_EXE} "${SCRIPTS_DIR}/format-files" \
--source_dir "${SOURCE_DIR}" \
--format_exe "${CLANG_FORMAT_EXE}" \
--files ${STAGED_FILES} \
--check
if [[ "$?" == 0 ]] ; then
for staged_file in ${STAGED_FILES} ; do
git add "${staged_file}"
done
else
exit 1
fi
+193
View File
@@ -0,0 +1,193 @@
#!/usr/bin/env python3
# Copyright 2020, Trail of Bits, Inc. All rights reserved.
import argparse
import itertools
import os
import pathlib
import subprocess
import sys
import traceback
import shutil
REFLOW_COMMENT = "// !!! REFLOW-COMMENT"
def find_comment_lines(path):
new_lines = []
old_comments = []
needs_fixes = False
with open(path, "r") as lines:
num_leading_comment_lines = 0
for line_ in lines:
line = line_.rstrip("\n\r\t ")
unindented_line = line.lstrip("\t ")
new_lines.append(line)
if unindented_line.startswith("//"):
# Make sure that every line that begins a comment block
# is preceded by a new line or a closing brace.
if not num_leading_comment_lines and 1 < len(new_lines):
prev_line = new_lines[-2].strip()
if prev_line != "" and prev_line != "}":
new_lines[-1] = ""
new_lines.append(line)
needs_fixes = True
num_leading_comment_lines += 1
# The code style has it so that the comment on an `else` or `else if` statement
# appears on the line before the `else` or `else if`.
elif num_leading_comment_lines:
if unindented_line.startswith("} else"):
comment_lines = list(new_lines[-(num_leading_comment_lines + 1):-1])
del new_lines[-(num_leading_comment_lines+1):]
new_lines.append(REFLOW_COMMENT)
new_lines.append(line)
old_comments.append(comment_lines)
needs_fixes = True
num_leading_comment_lines = 0
else:
num_leading_comment_lines = 0
# Force an empty newline at the end of the file.
if len(new_lines) and new_lines[-1]:
new_lines.append("")
needs_fixes = True
return new_lines, old_comments, needs_fixes
def run_clang_format_on_files(format_exe, format_file, paths):
args = [format_exe, '-i']
args.extend(paths)
try:
subprocess.check_call(args)
except:
return
def run_clang_format_on_lines(format_exe, format_file, path, lines):
p = subprocess.Popen(
[format_exe,
'--assume-filename={}'.format(path),
'--style=file'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
try:
stdout_data, stderr_data = p.communicate("\n".join(lines))
return stdout_data.split("\n"), False
except:
p.kill()
stdout_data, stderr_data = p.communicate()
return stdout_data.split("\n"), True
def fixup_file(path, lines, old_comments):
new_lines = []
i = 0
for line in lines:
if line.strip() == REFLOW_COMMENT:
num_spaces = max(0, (len(line) - len(line.lstrip())) - 2)
new_indent = " " * num_spaces
for old_comment_line in old_comments[i]:
old_comment_line = old_comment_line.strip("\r\n\t ")
new_lines.append("{}{}".format(new_indent, old_comment_line))
i += 1
else:
new_lines.append(line)
with open(path, "w") as file:
file.write("\n".join(new_lines))
def main():
clang_format_exe = shutil.which('clang-format')
arg_parser = argparse.ArgumentParser()
if clang_format_exe:
arg_parser.add_argument(
'--format_exe',
help='Path to clang-format executable.',
required=False,
default=str(clang_format_exe))
else:
arg_parser.add_argument(
'--format_exe',
help='Path to clang-format executable.',
required=True)
arg_parser.add_argument(
'--source_dir',
help='Path to root of source directory.',
required=False,
default=str(os.path.dirname(os.path.dirname(__file__))))
arg_parser.add_argument(
'--files',
help='Specific files to format',
nargs='*')
args, _ = arg_parser.parse_known_args()
try:
source_dir = os.path.abspath(args.source_dir)
os.chdir(source_dir)
except:
print("'{}' passed to --source_dir is not a directory".format(args.source_dir))
return 1
format_file = os.path.abspath(os.path.join(source_dir, ".clang-format"))
if not os.path.isfile(format_file):
print("Could not find clang-format file at '{}'".format(format_file))
return 1
if not os.path.isfile(args.format_exe):
print("'{}' passed to --format_exe does not exist".format(args.format_exe))
return 1
# NOTE(pag): Go get the abs paths of the files here before we change the current
# working directory.
cxx_files = args.files
if cxx_files:
cxx_files = list(os.path.abspath(cxx_file) for cxx_file in cxx_files)
if not cxx_files:
cxx_header_files = pathlib.Path(source_dir).rglob("*.h")
cxx_source_files = pathlib.Path(source_dir).rglob("*.cpp")
cxx_files = itertools.chain(cxx_header_files, cxx_source_files)
in_place_files = []
for cxx_file_ in cxx_files:
cxx_file = os.path.abspath(cxx_file_)
if not (cxx_file.endswith(".h") or cxx_file.endswith(".cpp")):
continue
try:
new_lines, old_comments, needs_fixes = find_comment_lines(cxx_file)
except:
continue
if not needs_fixes:
in_place_files.append(cxx_file)
else:
new_lines, has_error = run_clang_format_on_lines(
args.format_exe, format_file, cxx_file, new_lines)
if not has_error:
fixup_file(cxx_file, new_lines, old_comments)
if in_place_files:
run_clang_format_on_files(args.format_exe, format_file, in_place_files)
return 0
if __name__ == "__main__":
exit(main())