Disable volatile workaround for excess precision segv for SSE
[xapian.git] / xapian-maintainer-tools / xapian-check-patch
blob57b741c87d1555800f1ca14972369f019e64f8a5
1 #! /usr/bin/perl -w
2 # Copyright (c) 2007-2015 Olly Betts
4 # Permission is hereby granted, free of charge, to any person obtaining a copy
5 # of this software and associated documentation files (the "Software"), to
6 # deal in the Software without restriction, including without limitation the
7 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 # sell copies of the Software, and to permit persons to whom the Software is
9 # furnished to do so, subject to the following conditions:
11 # The above copyright notice and this permission notice shall be included in
12 # all copies or substantial portions of the Software.
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 # IN THE SOFTWARE.
22 require 5.000;
23 use strict;
24 use POSIX;
26 if (defined $ARGV[0] && $ARGV[0] eq '--help') {
27 print <<END;
28 Syntax: $0 [PATCH]...
30 Nit-pick Xapian patches.
32 A patch can be supplied on stdin, or one or more patch files listed on the
33 command line.
35 Produces output suitable for use with vim's quick-fix mode, and similar
36 features in other editors.
38 Example usage:
40 git diff master.. | xapian-check-patch > tmp.qf
41 vim -q tmp.qf
42 END
43 exit 0;
46 my ($fnm, $lineno);
47 my $add_lines = 0;
48 my $del_lines = 0;
49 my $files = 0;
50 # SVN property changes don't have an "Index: [...]" line.
51 my $want_tabs = -1;
52 my $check_trailing = 0;
53 my $check_space_tab = 0;
54 my $in_comment = 0;
55 my $lang;
56 while (<>) {
57 if (/^Index: (.+)/ || m!^diff --git a/.+ b/(.+)!) {
58 ++$files;
59 $fnm = $1;
60 $lineno = 1;
61 $lang = undef;
62 $in_comment = 0;
63 # Don't know!
64 $want_tabs = -1;
65 if ($fnm =~ /\.cc$/) {
66 if ($fnm !~ m!\b(?:cdb|portability/)! &&
67 $fnm !~ m!\bcommon/msvc_dirent\.cc$!) {
68 $lang = 'c++';
69 $want_tabs = 1 unless ($fnm =~ m!\blanguages/steminternal\.cc$!);
71 } elsif ($fnm =~ /\.c$/) {
72 if ($fnm !~ m!\blanguages/compiler/! &&
73 $fnm !~ m!/lemon\.c$!) {
74 $lang = 'c';
75 $want_tabs = 1;
77 } elsif ($fnm =~ /\.h$/) {
78 if ($fnm !~ m!\binclude/xapian/intrusive_ptr\.h! &&
79 $fnm !~ m!\blanguages/compiler/! &&
80 $fnm !~ m!\bcommon/msvc_dirent\.h$!) {
81 $lang = 'h';
82 $want_tabs = 1 unless ($fnm =~ m!/omega/cdb!);
84 } elsif ($fnm =~ /\.py(?:\.in)?$/) {
85 $lang = 'py';
86 $want_tabs = 0;
88 $check_trailing =
89 $fnm !~ /\.sbl$/ &&
90 $fnm !~ m!\bcommon/msvc_dirent\.! &&
91 $fnm !~ m!/lemon\.c$! &&
92 $fnm !~ m!/queryparser\.lt$! &&
93 $fnm !~ m!\bcdb! &&
94 $fnm !~ m!/testdata/etext\.txt$!;
95 $check_space_tab =
96 $fnm !~ /\.sbl$/;
97 # print STDERR "$fnm: lang=" . ($lang // "UNKNOWN") . "\;
98 next;
100 my $pre3 = substr($_, 0, 3);
101 if ($pre3 eq '@@ ') {
102 /^\@\@ -\d+,\d+ \+(\d+),\d+\b/ and $lineno = $1;
103 $in_comment = 0;
104 next;
106 if ($pre3 eq '---' || $pre3 eq '+++') {
107 next;
109 my $msg;
110 my $fullline = $_;
111 # Uncomment commented out parameter names: foo(int /*bar*/) -> foo(int bar)
112 s!/\*([A-Za-z_][A-Za-z_0-9]*)\*/([,)])!$1$2!g;
113 # Trim comments:
114 if (s!/(?:\*.*?\*/|/.*)!!g) {
115 s/\s+$//;
117 if (s!/\*.*!!g) {
118 s/\s+$//;
119 $in_comment = 1;
121 # Trim content of comments ending on this line:
122 if (s!^(.).*\*/!$1*/!) {
123 $in_comment = 0;
125 if ($in_comment) {
126 $_ = '';
127 } else {
128 # Drop comment content for "*" continuation lines (when /* isn't in hunk):
129 s/^(.)(\s*\*).*/$1$2/;
132 # Replace multiple spaces before line continuation marker:
133 s! +\\$! \\!;
135 if (defined $lang && ($lang eq 'c++' || $lang eq 'h' || $lang eq 'c') && !(/^[-+]\s*\#/)) {
136 # Replace string literals containing escaped quotes:
137 if (/['"]/) {
138 my $quote = substr($_, $-[0], 1);
139 my $start = $+[0];
140 my $i = $start;
141 my $esc = 0;
142 QUOTELOOP: while (1) {
143 if ($i >= length($_)) {
144 $_ = substr($_, 0, $start) . "X\n";
145 last;
147 my $c = substr($_, $i, 1);
148 if ($c eq $quote) {
149 $_ = substr($_, 0, $start) . "X" . substr($_, $i);
150 $i = $start + 2;
151 # See if there's another string after this one:
152 while ($i != length($_)) {
153 $c = substr($_, $i, 1);
154 ++$i;
155 if ($c eq '"' || $c eq "'") {
156 $quote = $c;
157 $start = $i;
158 $esc = 0;
159 next QUOTELOOP;
162 last;
164 if ($c eq '\\') {
165 ++$i;
166 $c = substr($_, $i, 1);
167 if ($c eq 'x') {
168 ++$i while (substr($_, $i, 1) =~ /^[A-Fa-f0-9]$/);
169 next;
170 } elsif ($c =~ /^[0-7]/) {
171 my $j = $i;
172 ++$i while ($i - $j <= 3 && substr($_, $i, 1) =~ /^[0-7]$/);
173 next;
174 } elsif ($c eq '"' || $c eq "'") {
175 ++$esc;
178 ++$i;
183 if ($check_trailing && /^\+.*[ \t]$/) {
184 $msg = "added/changed line has trailing whitespace:";
185 } elsif ($check_space_tab && /^\+.* \t/) {
186 $msg = "added/changed line has space before tab:";
187 } elsif ($want_tabs == 1 and /^\+\t* {8}/) {
188 $msg = "added/changed line uses spaces for indentation rather than tab:";
189 } elsif (!$want_tabs and /^\+ *\t/) {
190 $msg = "added/changed line uses tab for indentation rather than spaces:";
191 } elsif (/^-.*\bFIX(?:ME)\b/) {
192 $msg = "FIX"."ME removed:";
193 } elsif (/^\+.*\bFIX(?:ME)\b/) {
194 $msg = "FIX"."ME added:";
195 } elsif (defined $lang && /^\+.*\\([abcefp]|brief|code|deprecated|endcode|exception|file|internal|li|param|private|return|todo)\b/) {
196 $msg = "Doxygen command '\\$1' introduced by '\\' not '\@':";
197 } elsif (m!^\+(?:.*[;{])?\s*/[/*]{1,2}\w!) {
198 $msg = "added/changed line has comment without whitespace before the text:";
199 } else {
200 if (defined $lang && ($lang eq 'c++' || $lang eq 'h' || $lang eq 'c')) {
201 if (m!^\+\s*(case|catch|class|do|for|if|namespace|struct|switch|try|union|while)\b([^ ]| \s)!) {
202 $msg = "'$1' not followed by exactly one space:";
203 } elsif (m!^\+\s*(return)\b([^ ;]| \s)!) {
204 $msg = "'$1' not followed by exactly one space:";
205 } elsif (m!^\+\s*(else)\b([^ \n]| \s)!) {
206 $msg = "'$1' not followed by exactly one space:";
207 } elsif (m!^(?:}|}\s{2,}|}\t|^[^}]*)\b(catch)\b!) {
208 $msg = "'$1' not preceded by exactly '} ':";
209 } elsif (m!^(?:}|}\s{2,}|}\t)\b(else|while)\b!) {
210 $msg = "'}' and '$1' not separated by exactly one space:";
211 } elsif (m!^\+.*\((?: [^;]|\t)!) {
212 # Allow: for ( ; i != 10; ++i)
213 $msg = "Whitespace after '(':";
214 } elsif (m!^\+.*\H.*\h\)!) {
215 $msg = "Whitespace before ')':";
216 } elsif (m!^\+.*; (\w+)([-+]{2})\)!) {
217 $msg = "Prefer '$2$1' to '$1$2':";
218 } elsif (m,^\+\s*[^#].*[\w)](?!-[->]|\+\+)((?:\&\&|\|\||<<|>>|[-+/*%~=<>!&|^])=?|[?]),) {
219 my @pre = @-;
220 my @post = @+;
221 my $op = $1;
222 $msg = "Missing space before '$op':";
223 if (substr($_, $pre[1] - 8, 8) eq 'operator') {
224 # operator*() etc
225 $msg = undef;
226 } elsif ($op eq '>' && substr($_, 0, $pre[1]) =~ /[A-Za-z0-9_]</) {
227 # y = static_cast<char>(x);
228 $msg = undef;
229 } elsif ($op eq '>') {
230 $msg = undef;
231 } elsif ($op eq '<' && substr($_, $pre[1] - 1, 1) =~ /^[A-Za-z0-9_]$/ && substr($_, $post[1]) =~ />/) {
232 # y = static_cast<char>(x);
233 $msg = undef;
234 } elsif ($op eq '<' &&
235 substr($_, 0, $pre[1]) =~ /(?:list|map|multimap|multiset|priority_queue|set|unordered_map|unordered_set|vector)$/) {
236 # y = priority_queue<Foo*,
237 # Bar>;
238 $msg = undef;
239 } elsif ($op eq '&&' && substr($_, $pre[1] - 4, 4) eq 'auto') {
240 # auto&& x
241 $msg = undef;
242 } elsif (($op eq '<<' || $op eq '>>') &&
243 substr($_, 0, $pre[1]) =~ /\b(?:0x[0-9a-fA-F]+|[0-9]+)$/ &&
244 substr($_, $post[1]) =~ /^(?:0x[0-9a-fA-F]+|[0-9]+)\b/) {
245 # 0x00b1<<26
246 $msg = undef;
247 } elsif (($op eq '-' || $op eq '+') &&
248 substr($_, 0, $pre[1]) =~ /[0-9]\.?e$/) {
249 # 1.2e-3, 7.e+3
250 $msg = undef;
251 } elsif ($op eq '>>' &&
252 /[A-Za-z0-9_]<.+</) {
253 # vector<vector<int>> v;
254 $msg = undef;
255 } elsif ($op =~ /^[*&|]$/) {
256 # FIXME: *: const char* x;
257 # FIXME: &: const char& x;
258 # FIXME: |: FOO|BAR
259 $msg = undef;
261 } elsif (m@^\+\s*[^#\s].*((?:\&\&|\|\||<<|>>|[-+/*%~=<>!&|^])=?|[?:,])(?<!(?:-[->]|\+\+|::))(?:[\w\(]| \s)@) {
262 my @pre = @-;
263 my @post = @+;
264 my $op = $1;
265 $msg = "Should have exactly one space after '$op':";
266 if ($op eq '~' && substr($_, $post[1]) =~ /^[A-Za-z][A-Za-z0-9_]*\(/) {
267 # Destructor - e.g. ~Foo();
268 $msg = undef;
269 } elsif (($op eq '-' || $op eq '+' || $op eq '!' || $op eq '~') &&
270 substr($_, 0, $pre[1]) =~ m@(?:[-+/*%~=<>&|,;?:] |[\[(]|\b(?:return|case) |^\+\s*)$@) {
271 # Unary -, +, !, ~: e.g. foo = +1; bar = x * (-y); baz = a * -b;
272 $msg = undef;
273 } elsif ($op eq ',' && (
274 /\b(?:AssertRel(?:Paranoid)?|TEST_REL)\(/ ||
275 /{[^()]*}/)) {
276 # AssertRel(a,<,b);
277 $msg = undef;
278 } elsif ($op eq '>>' &&
279 /[A-Za-z0-9_]<.+</) {
280 # vector<vector<int>>&
281 $msg = undef;
282 } elsif ($op =~ /^[*&<>|]$/) {
283 # FIXME: *: const char *x;
284 # FIXME: *: const char &x;
285 # FIXME: < >: y = static_cast<char>(x);
286 # FIXME: |: FOO|BAR
287 $msg = undef;
289 } elsif (m@^\+[^#]*?[^#\h] +(,|->)@) {
290 $msg = "Space before '$1':";
291 } elsif (m,^\+[^#]*?[^#\h] ,) {
292 $msg = "Multiple spaces:";
296 if (defined $msg) {
297 print "$fnm:$lineno: $msg";
298 if ($msg =~ /:$/) {
299 print " $fullline";
300 } else {
301 print "\n";
304 my $first_char = substr($fullline, 0, 1);
305 if ($first_char eq ' ') {
306 ++$lineno;
307 } elsif ($first_char eq '+') {
308 ++$lineno;
309 ++$add_lines;
310 } elsif ($first_char eq '-') {
311 ++$del_lines;
314 print STDERR <<"__END__";
315 Files patched:\t$files
316 Lines added:\t$add_lines
317 Lines removed:\t$del_lines
318 __END__