mirror of
https://github.com/lifting-bits/remill
synced 2026-06-21 13:56:07 +00:00
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:
Executable
+58
@@ -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
|
||||
Executable
+193
@@ -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())
|
||||
Reference in New Issue
Block a user