From a3e95abeb52c1fce782d38e75a1bcc674d3ff988 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 17 Oct 2012 10:25:35 +0100 Subject: [PATCH] Document bracket whitespace rules & add syntax-check rule This documents the following whitespace rules if(foo) // Bad if (foo) // Good int foo (int wizz) // Bad int foo(int wizz) // Good bar = foo (wizz); // Bad bar = foo(wizz); // Good typedef int (*foo) (int wizz); // Bad typedef int (*foo)(int wizz); // Good int foo( int wizz ); // Bad int foo(int wizz); // Good There is a syntax-check rule extension to validate all these rules. Checking for 'function (...args...)' is quite difficult since it needs to ignore valid usage with keywords like 'if (...test...)' and while/for/switch. It must also ignore source comments and quoted strings. It is not possible todo this with a simple regex in the normal syntax-check style. So a short Perl script is created instead to analyse the source. In practice this works well enough. The only thing it can't cope with is multi-line quoted strings of the form "start of string\ more lines\ more line\ the end" but this can and should be written as "start of string" "more lines" "more line" "the end" with this simple change, the bracket checking script does not have any false positives across libvirt source, provided it is only run against .c files. It is not practical to run it against .h files, since those use whitespace extensively to get alignment (though this is somewhat inconsistent and could arguably be fixed). The only limitation is that it cannot detect a violation where the first arg starts with a '*', eg foo(*wizz); since this generates too many false positives on function typedefs which can't be supressed efficiently. Signed-off-by: Daniel P. Berrange --- HACKING | 31 ++++++++++ build-aux/bracket-spacing.pl | 116 +++++++++++++++++++++++++++++++++++ cfg.mk | 7 ++- docs/hacking.html.in | 49 +++++++++++++++ 4 files changed, 202 insertions(+), 1 deletion(-) create mode 100755 build-aux/bracket-spacing.pl diff --git a/HACKING b/HACKING index 90d2a1cb17..0ee988a8a8 100644 --- a/HACKING +++ b/HACKING @@ -179,6 +179,37 @@ otherwise. For example, it is preferable to use "/* */" comments rather than declare them at the beginning of a scope, rather than immediately before use. +Bracket spacing +=============== +The keywords "if", "for", "while", and "switch" must have a single space +following them before the opening bracket. eg + + if(foo) // Bad + if (foo) // Good + +Function implementations mustnothave any whitespace between the function name and the opening bracket. eg + + int foo (int wizz) // Bad + int foo(int wizz) // Good + +Function calls mustnothave any whitespace between the function name and the opening bracket. eg + + bar = foo (wizz); // Bad + bar = foo(wizz); // Good + +Function typedefs mustnothave any whitespace between the closing bracket of the function name and +opening bracket of the arg list. eg + + typedef int (*foo) (int wizz); // Bad + typedef int (*foo)(int wizz); // Good + +There must not be any whitespace immediately following any opening bracket, or +immediately prior to any closing bracket + + int foo( int wizz ); // Bad + int foo(int wizz); // Good + + Curly braces ============ Omit the curly braces around an "if", "while", "for" etc. body only when that diff --git a/build-aux/bracket-spacing.pl b/build-aux/bracket-spacing.pl new file mode 100755 index 0000000000..d3a916f4b0 --- /dev/null +++ b/build-aux/bracket-spacing.pl @@ -0,0 +1,116 @@ +#!/usr/bin/perl +# +# bracket-spacing.pl: Report any usage of 'function (..args..)' +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see +# . +# +# Authors: +# Daniel P. Berrange + +use strict; +use warnings; + +my $ret = 0; +my $incomment = 0; + +foreach my $file (@ARGV) { + open FILE, $file; + + while (defined (my $line = )) { + my $data = $line; + + # Kill any quoted strongs + $data =~ s,".*?","XXX",g; + + # Kill any C++ style comments + $data =~ s,//.*$,//,; + + next if $data =~ /^#/; + + # Kill contents of multi-line comments + # and detect end of multi-line comments + if ($incomment) { + if ($data =~ m,\*/,) { + $incomment = 0; + $data =~ s,^.*\*/,*/,; + } else { + $data = ""; + } + } + + # Kill single line comments, and detect + # start of multi-line comments + if ($data =~ m,/\*.*\*/,) { + $data =~ s,/\*.*\*/,/* */,; + } elsif ($data =~ m,/\*,) { + $incomment = 1; + $data =~ s,/\*.*,/*,; + } + + # We need to match things like + # + # int foo (int bar, bool wizz); + # foo (bar, wizz); + # + # but not match things like: + # + # typedef int (*foo)(bar wizz) + # + # we can't do this (efficiently) without + # missing things like + # + # foo (*bar, wizz); + # + while ($data =~ /(\w+)\s\((?!\*)/) { + my $kw = $1; + + # Allow space after keywords only + if ($kw =~ /^(if|for|while|switch|return)$/) { + $data =~ s/($kw\s\()/XXX(/; + } else { + print "$file:$.: $line"; + $ret = 1; + last; + } + } + + # Require whitespace immediately after keywords, + # but none after the opening bracket + while ($data =~ /(if|for|while|switch|return)\(/ || + $data =~ /(if|for|while|switch|return)\s+\(\s/) { + print "$file:$.: $line"; + $ret = 1; + last; + } + + # Forbid whitespace between )( of a function typedef + while ($data =~ /\(\*\w+\)\s+\(/) { + print "$file:$.: $line"; + $ret = 1; + last; + } + + # Forbid whitespace following ( or prior to ) + while ($data =~ /\S\s+\)/ || + $data =~ /\(\s+\S/) { + print "$file:$.: $line"; + $ret = 1; + last; + } + } + close FILE; +} + +exit $ret; diff --git a/cfg.mk b/cfg.mk index cda04e418a..802e94efed 100644 --- a/cfg.mk +++ b/cfg.mk @@ -718,7 +718,12 @@ _autogen: ./config.status # regenerate HACKING as part of the syntax-check -syntax-check: $(top_srcdir)/HACKING +syntax-check: $(top_srcdir)/HACKING bracket-spacing-check + +bracket-spacing-check: + $(AM_V_GEN)files=`$(VC_LIST) | grep '\.c$$'`; \ + $(PERL) $(top_srcdir)/build-aux/bracket-spacing.pl $$files || \ + (echo $(ME): incorrect whitespace around brackets, see HACKING for rules && exit 1) # sc_po_check can fail if generated files are not built first sc_po_check: \ diff --git a/docs/hacking.html.in b/docs/hacking.html.in index d41b39c490..40acdbbd95 100644 --- a/docs/hacking.html.in +++ b/docs/hacking.html.in @@ -212,6 +212,55 @@

+

Bracket spacing

+ +

+ The keywords if, for, while, + and switch must have a single space following them + before the opening bracket. eg +

+
+      if(foo)   // Bad
+      if (foo)  // Good
+
+ +

+ Function implementations must not have any whitespace + between the function name and the opening bracket. eg +

+
+      int foo (int wizz)  // Bad
+      int foo(int wizz)   // Good
+
+ +

+ Function calls must not have any whitespace + between the function name and the opening bracket. eg +

+
+      bar = foo (wizz);  // Bad
+      bar = foo(wizz);   // Good
+
+ +

+ Function typedefs must not have any whitespace + between the closing bracket of the function name and opening + bracket of the arg list. eg +

+
+      typedef int (*foo) (int wizz);  // Bad
+      typedef int (*foo)(int wizz);   // Good
+
+ +

+ There must not be any whitespace immediately following any + opening bracket, or immediately prior to any closing bracket +

+
+      int foo( int wizz );  // Bad
+      int foo(int wizz);    // Good
+
+

Curly braces

-- GitLab