Skip to content

Commit 58ae116

Browse files
authoredSep 26, 2018
Create script to apply style to diffs (radareorg#11261)
* restore tabs size to 8 chars * fixes clang-format-diff for function declaration * DEVELOPERS: explain pre-commit hook * sys/pre-commit: do not consider unstaged changes * sys/pre-commit: change doc * create an example in doc * suggest --no-verify
1 parent 59a2013 commit 58ae116

9 files changed

+271
-27
lines changed
 

‎doc/clang-format ‎.clang-format

+5-16
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,12 @@ IndentCaseLabels: false
99
IndentFunctionDeclarationAfterType: false
1010
IndentWidth: 8
1111
UseTab: Always
12-
IndentCaseLabels: false
1312
ColumnLimit: 0
1413
BreakBeforeBraces: Attach
15-
BraceWrapping: {
16-
AfterClass: 'true'
17-
AfterControlStatement: 'true'
18-
AfterEnum : 'true'
19-
AfterFunction : 'true'
20-
AfterNamespace : 'true'
21-
AfterStruct : 'true'
22-
AfterUnion : 'true'
23-
BeforeCatch : 'true'
24-
BeforeElse : 'true'
25-
IndentBraces : 'true'
26-
}
27-
BreakBeforeTernaryOperators: false
28-
AllowShortIfStatementsOnASingleLine: true
14+
BreakBeforeTernaryOperators: true
15+
AllowShortIfStatementsOnASingleLine: false
2916
AllowShortCaseLabelsOnASingleLine: true
3017
AllowShortFunctionsOnASingleLine: Inline
31-
AllowShortLoopsOnASingleLine: true
18+
AllowShortLoopsOnASingleLine: false
19+
AlignAfterOpenBracket: DontAlign
20+
ForEachMacros: ['r_list_foreach', 'ls_foreach', 'fcn_tree_foreach_intersect', 'r_skiplist_foreach', 'graph_foreach_anode']

‎.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
clang-log/
2-
.clang-format
32
.clang_complete
43
.tmp-format
54
.#*

‎CONTRIBUTING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ try to keep the codebase consistent and clean.
2121
* Fork the repository on GitHub.
2222
* Create a topic branch from master. Please avoid working directly on the ```master``` branch.
2323
* Make commits of logical units.
24-
* Check for unnecessary whitespace with ```git diff --check``` and be sure to follow the CODINGSTYLE (more on this in the next section).
24+
* Check for coding style issues with ```git diff master..mybranch | ./sys/clang-format-diff.py -p1``` and be sure to follow the CODINGSTYLE (more on this in [DEVELOPERS.md](https://github.com/radare/radare2/blob/master/DEVELOPERS.md)).
2525
* Submit the Pull Request(PR) on Github.
2626
* When relevant, write a test for
2727
[radare2-regressions](https://github.com/radare/radare2-regressions) and

‎DEVELOPERS.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ static int findMinMax(RList *maps, ut64 *min, ut64 *max, int skip, int width);
3636
In order to contribute with patches or plugins we encourage you to
3737
use the same coding style as the rest of the code base.
3838
39+
Please use `./sys/clang-format-diff.py` before submitting a PR, to be sure to
40+
follow the coding style. If you find a bug in this script, please create an
41+
issue on GitHub. You can also install the pre-commit hook
42+
`./sys/pre-commit-indent.sh` by copying it in `.git/hooks/pre-commit`, so it
43+
will check the coding style of the modified lines before committing them.
44+
3945
You may find some additional notes on this topic in doc/vim.
4046
4147
* Tabs are used for indentation. In a switch statement, the
@@ -51,7 +57,7 @@ default:
5157
}
5258
```
5359

54-
* Lines should be at most 78 chars. A tab is considered as 4 chars.
60+
* Lines should be at most 78 chars. A tab is considered as 8 chars.
5561

5662
* Braces open on the same line as the for/while/if/else/function/etc. Closing
5763
braces are put on a line of their own, except in the else of an if statement
@@ -201,7 +207,7 @@ r_core_wrap.cxx:32103:61: error: assigning to 'RDebugReasonType' from incompatib
201207
202208
* See doc/vim for vimrc
203209
204-
* See doc/clang-format for work-in-progress support for automated indentation
210+
* See .clang-format for work-in-progress support for automated indentation
205211
206212
* Use the r2 types instead of the ones in stdint, which are known to cause some
207213
portability issues. So, instead of uint8_t, use ut8, etc..

‎doc/indent-example.c

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include "r_core.h"
2+
#include "r_util.h"
3+
#include <stdio.h>
4+
5+
typedef struct r_core_rtr_host_t2 {
6+
int proto;
7+
char host[512];
8+
int port;
9+
char file[1024];
10+
RSocket *fd;
11+
} RCoreRtrHost2;
12+
13+
static const char *help_msg_aa[] = {
14+
"Usage:", "aa[0*?]", " # see also 'af' and 'afna'",
15+
"aa", " ", "alias for 'af@@ sym.*;af@entry0;afva'", //;.afna @@ fcn.*'",
16+
"aa*", "", "analyze all flags starting with sym. (af @@ sym.*)",
17+
NULL,
18+
};
19+
20+
static int cmpaddr(const void *_a, const void *_b) {
21+
const RAnalFunction *a = _a, *b = _b;
22+
return a->addr - b->addr;
23+
}
24+
25+
int main (int argc, char **argv) {
26+
r_anal_esil_set_pc (core->anal->esil, fcn ? fcn->addr : core->offset);
27+
switch (*input) {
28+
case 'a': // "afta"
29+
{
30+
type_cmd_afta (core, fcn);
31+
break;
32+
}
33+
case 'm': // "aftm"
34+
{
35+
seek = core->offset;
36+
r_anal_esil_set_pc (core->anal->esil, fcn ? fcn->addr : core->offset);
37+
r_core_anal_type_match (core, fcn);
38+
r_core_seek (core, seek, true);
39+
break;
40+
}
41+
case '?':
42+
default:
43+
r_core_cmd_help (core, help_msg_aft);
44+
break;
45+
}
46+
return 0;
47+
}

‎doc/vim

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
" my own indentation for C using the coding styles
77
set cindent
8-
set tabstop=4
8+
set tabstop=8
99
set noexpandtab
1010
set smartindent
1111
set cino=:0,+0,(2,J0,{1,}0,>4,)1,m2

‎sys/clang-format-diff.py

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
#!/usr/bin/env python3
2+
#
3+
#===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===#
4+
#
5+
# The LLVM Compiler Infrastructure
6+
#
7+
# This file is distributed under the University of Illinois Open Source
8+
# License. See LICENSE.TXT for details.
9+
#
10+
#===------------------------------------------------------------------------===#
11+
12+
#
13+
# Slightly modified to handle the definition of functions, which do not
14+
# require a space before the parenthesis
15+
#
16+
17+
r"""
18+
ClangFormat Diff Reformatter
19+
============================
20+
21+
This script reads input from a unified diff and reformats all the changed
22+
lines. This is useful to reformat all the lines touched by a specific patch.
23+
Example usage for git/svn users:
24+
25+
git diff -U0 --no-color HEAD^ | clang-format-diff.py -p1 -i
26+
svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i
27+
28+
"""
29+
30+
import argparse
31+
import difflib
32+
import re
33+
import subprocess
34+
import sys
35+
import tempfile
36+
import os
37+
from functools import reduce
38+
try:
39+
from StringIO import StringIO
40+
except ImportError:
41+
from io import StringIO
42+
43+
44+
def main():
45+
parser = argparse.ArgumentParser(description=
46+
'Reformat changed lines in diff. Without -i '
47+
'option just output the diff that would be '
48+
'introduced. Use something like: '
49+
'git diff master..my-branch | ./sys/clang-format-diff.py -p1 -i')
50+
parser.add_argument('-i', action='store_true', default=False,
51+
help='apply edits to files instead of displaying a diff')
52+
parser.add_argument('-p', metavar='NUM', default=0,
53+
help='strip the smallest prefix containing P slashes')
54+
parser.add_argument('-regex', metavar='PATTERN', default=None,
55+
help='custom pattern selecting file paths to reformat '
56+
'(case sensitive, overrides -iregex)')
57+
parser.add_argument('-iregex', metavar='PATTERN', default=
58+
r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc|js|ts|proto'
59+
r'|protodevel|java)',
60+
help='custom pattern selecting file paths to reformat '
61+
'(case insensitive, overridden by -regex)')
62+
parser.add_argument('-sort-includes', action='store_true', default=False,
63+
help='let clang-format sort include blocks')
64+
parser.add_argument('-v', '--verbose', action='store_true',
65+
help='be more verbose, ineffective without -i')
66+
parser.add_argument('-style',
67+
help='formatting style to apply (LLVM, Google, Chromium, '
68+
'Mozilla, WebKit)')
69+
parser.add_argument('-binary', default='clang-format',
70+
help='location of binary to use for clang-format')
71+
args = parser.parse_args()
72+
73+
# Extract changed lines for each file.
74+
filename = None
75+
lines_by_file = {}
76+
for line in sys.stdin:
77+
match = re.search('^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line)
78+
if match:
79+
filename = match.group(2)
80+
if filename == None:
81+
continue
82+
83+
if args.regex is not None:
84+
if not re.match('^%s$' % args.regex, filename):
85+
continue
86+
else:
87+
if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
88+
continue
89+
90+
match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
91+
if match:
92+
start_line = int(match.group(1))
93+
line_count = 1
94+
if match.group(3):
95+
line_count = int(match.group(3))
96+
if line_count == 0:
97+
continue
98+
end_line = start_line + line_count - 1
99+
lines_by_file.setdefault(filename, []).append(
100+
[start_line, end_line])
101+
102+
# Reformat files containing changes in place.
103+
for filename, lines in lines_by_file.items():
104+
command = [args.binary, filename]
105+
if args.sort_includes:
106+
command.append('-sort-includes')
107+
if lines:
108+
s = [('-lines', str(x[0]) + ':' + str(x[1])) for x in lines]
109+
s = reduce(lambda x, y: x + y, s)
110+
command.extend(s)
111+
if args.style:
112+
command.extend(['-style', args.style])
113+
p = subprocess.Popen(command,
114+
stdout=subprocess.PIPE,
115+
stderr=None,
116+
stdin=subprocess.PIPE,
117+
universal_newlines=True)
118+
stdout, stderr = p.communicate()
119+
if p.returncode != 0:
120+
sys.exit(p.returncode)
121+
122+
with open(filename) as f:
123+
code = f.readlines()
124+
formatted_code = StringIO(stdout).readlines()
125+
modified_lines = dict()
126+
if lines:
127+
for x in lines:
128+
for i in range(x[0], x[1] + 1):
129+
modified_lines[i] = True
130+
131+
# handle functions definitions/declarations: do not use space before (
132+
for i, l in enumerate(formatted_code):
133+
if lines and i + 1 not in modified_lines:
134+
continue
135+
136+
if l.startswith('R_API ') or l.startswith('static '):
137+
formatted_code[i] = l.replace(' (', '(')
138+
139+
diff = difflib.unified_diff(code, formatted_code,
140+
filename, filename,
141+
'(before formatting)', '(after formatting)')
142+
diff_string = ''.join(diff)
143+
if len(diff_string) > 0:
144+
if args.i:
145+
f = tempfile.NamedTemporaryFile(delete=False)
146+
f.write(diff_string.encode())
147+
f.close()
148+
os.system('git apply -p0 < "%s"' % (f.name))
149+
os.unlink(f.name)
150+
else:
151+
sys.stdout.write(diff_string)
152+
153+
if __name__ == '__main__':
154+
main()

‎sys/indent.sh

+12-6
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ P=`readlink $0`
1212
cd `dirname $P`/..
1313

1414
if [ -z "${IFILE}" ]; then
15-
echo "Usage: r2-indent [-i|-u] [file] [...]"
15+
echo "Usage: r2-indent [-a|-i|-u|-c] [file] [...]"
1616
echo " -a indent all whitelisted files"
1717
echo " -i indent in place (modify file)"
1818
echo " -u unified diff of the file"
19+
echo " -c use clang-format"
1920
exit 1
2021
fi
2122

@@ -52,6 +53,12 @@ if [ "${IFILE}" = "-u" ]; then
5253
IFILE="$1"
5354
fi
5455

56+
if [ "${IFILE}" = "-c" ]; then
57+
shift
58+
UNCRUST=0
59+
IFILE="$1"
60+
fi
61+
5562
if [ "`echo $IFILE | cut -c 1`" != / ]; then
5663
IFILE="$OLDPWD/$IFILE"
5764
fi
@@ -80,11 +87,11 @@ indentFile() {
8087
echo "Indenting ${IFILE} ..." >&2
8188
(
8289
if [ "${UNCRUST}" = 1 ]; then
83-
cp -f doc/clang-format ${CWD}/.clang-format
90+
cp -f .clang-format ${CWD}/.clang-format
8491
cd "$CWD"
85-
r2pm -r uncrustify -c ${CWD}/doc/uncrustify.cfg -f "${IFILE}" -o .tmp-format || exit 1
92+
r2pm -r uncrustify -c ${CWD}/doc/uncrustify.cfg -f "${IFILE}" -o .tmp-format
8693
else
87-
cp -f doc/clang-format ${CWD}/.clang-format
94+
cp -f .clang-format ${CWD}/.clang-format
8895
cd "$CWD"
8996
clang-format "${IFILE}" > .tmp-format
9097
fi
@@ -147,12 +154,11 @@ indentFile() {
147154
fi
148155
rm -f .tmp-format2
149156
)
150-
rm -f ${CWD}/.clang-format
151157
}
152158

153159
while : ; do
154160
[ "$PWD" = / ] && break
155-
if [ -f doc/clang-format ]; then
161+
if [ -f .clang-format ]; then
156162
ROOTDIR=$PWD
157163
while : ; do
158164
[ -z "${IFILE}" ] && break

‎sys/pre-commit-indent.sh

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/bin/sh
2+
#
3+
# A hook script to verify what is about to be committed follows the coding
4+
# style. Called by "git commit" with no arguments. The hook should exit with
5+
# non-zero status after issuing an appropriate message if it wants to stop the
6+
# commit.
7+
#
8+
# To enable this hook, move it to ".git/hooks/pre-commit".
9+
10+
TMPFILE="$(mktemp)"
11+
if [ -z "$TMPFILE" ] ; then
12+
echo "mktemp returned an empty string for \"TMPFILE\"."
13+
exit 1
14+
fi
15+
16+
UNSTAGED_DIFF="$(mktemp)"
17+
if [ -z "$UNSTAGED_DIFF" ] ; then
18+
echo "mktemp returned an empty string for \"UNSTAGED_DIFF\"."
19+
exit 1
20+
fi
21+
22+
git diff > ${UNSTAGED_DIFF} || exit 1
23+
git checkout -- . || exit 1
24+
git diff --cached | ./sys/clang-format-diff.py -p1 > "${TMPFILE}"
25+
26+
restore_exit() {
27+
git apply < "${UNSTAGED_DIFF}" 2>/dev/null
28+
rm -f "${TMPFILE}"
29+
rm -f "${UNSTAGED_DIFF}"
30+
exit 1
31+
}
32+
33+
if [ -s "${TMPFILE}" ] ; then
34+
echo "Please follow the coding style!"
35+
echo "Run \`git diff --cached | ./sys/clang-format-diff.py -p1 -i\` to apply the changes listed below and remember to add them to git."
36+
echo
37+
cat "${TMPFILE}"
38+
echo
39+
echo "If you think the current style is ok, just run \`git commit --no-verify\` to bypass this check."
40+
restore_exit 1
41+
fi
42+
43+
restore_exit 0

0 commit comments

Comments
 (0)
Please sign in to comment.