1 #!/bin/sh -- # This comment tells perl not to loop!
3 #***************************************************************************
5 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7 # Copyright 2008 by Sun Microsystems, Inc.
9 # OpenOffice.org - a multi-platform office productivity suite
11 # $RCSfile: jstyle.pl,v $
15 # This file is part of OpenOffice.org.
17 # OpenOffice.org is free software: you can redistribute it and/or modify
18 # it under the terms of the GNU Lesser General Public License version 3
19 # only, as published by the Free Software Foundation.
21 # OpenOffice.org is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 # GNU Lesser General Public License version 3 for more details
25 # (a copy is included in the LICENSE file that accompanied this code).
27 # You should have received a copy of the GNU Lesser General Public License
28 # version 3 along with OpenOffice.org. If not, see
29 # <http://www.openoffice.org/license.html>
30 # for a copy of the LGPLv3 License.
32 #***************************************************************************
35 eval 'exec perl -S $0 "$@"'
38 # @(#)jstyle 1.2 98/01/08
40 # jstyle - check for some common stylistic errors.
42 # jstyle is a sort of "lint" for Java coding style.
44 # There's a lot this can't check for, like proper
45 # indentation of continuation lines. There's also
46 # a lot more this could check for.
48 # A note to the non perl literate:
50 # perl regular expressions are pretty much like egrep
51 # regular expressions, with the following special symbols
53 # \s any space character
54 # \S any non-space character
55 # \w any "word" character [a-zA-Z0-9_]
56 # \W any non-word character
59 # \b word boundary (between \w and \W)
60 # \B non-word boundary
62 #require "getopts.pl";
63 # XXX - because some versions of perl can not find the lib directory,
64 # we just include this here.
65 ;# getopts.pl - a better getopt.pl
68 ;# do Getopts("a:bc"); # -a takes arg. -b & -c not. Sets opt_* as a
72 local($argumentative) = @_
;
73 local(@args
,$_,$first,$rest);
77 @args
= split( / */, $argumentative );
78 while(($_ = $ARGV[0]) =~
/^
-(.
)(.
*)/) {
79 ($first,$rest) = ($1,$2);
80 $pos = index
($argumentative,$first);
82 if($args[$pos+1] eq
":") {
87 eval "\$opt_$first = \$rest;";
90 eval "\$opt_$first = 1";
100 print STDERR
"Unknown option: $first\n";
117 "usage: jstyle [-c] [-h] [-p] [-s] [-t] [-v] [-C] file ...
118 -c check continuation line indenting
119 -h perform heuristic checks that are sometimes wrong
120 -p perform some of the more picky checks
121 -s check for spaces vs. tabs
122 -t insist on indenting by tabs
124 -C don't check anything in header block comments
125 -S print out overall statistics
128 if (!&Getopts
("chpstvCS")) {
133 $check_continuation = $opt_c;
139 $ignore_hdr_comment = $opt_C;
140 $statistics = $opt_S;
143 $fmt = "%s: %d: %s\n%s\n";
145 $fmt = "%s: %d: %s\n";
148 # Note, following must be in single quotes so that \s and \w work right.
149 $typename = '(int|char|boolean|byte|short|long|float|double)';
152 foreach
$arg (@ARGV
) {
153 if (!open
(STDIN
, $arg)) {
154 printf "%s: can not open\n", $arg;
164 if ($statistics != 0) {
165 foreach
$key (sort(keys
%errcount
)) {
166 printf "%6d %s\n", $errcount{$key}, $key;
169 printf "%6d Total warnings\n", $tot_errcount;
170 printf "%6d Lines of code\n", $totlines;
174 if ($statistics == 0) {
175 printf $fmt, $filename, $.
, $_[0], $line;
178 $msg =~ s
/ \
([0-9][0-9]*\
)$
//;
179 $errcount{$msg} += 1;
187 $in_header_comment = 0;
188 $in_continuation = 0;
194 $expect_continuation = 0;
199 line
: while (<STDIN
>) {
201 s
/\r?
\n$
//; # strip return and newline
203 # save the original line, then remove all text from within
204 # double or single quotes, we do not want to check such text.
210 # an /* END JSTYLED */ comment ends a no-check block.
212 if (/\/\* *END *JSTYLED *\*\//) {
219 # a /*JSTYLED*/ comment indicates that the next line is ok.
226 if (/\/\* *JSTYLED.*\*\//) {
227 /^.*\/\* *JSTYLED *(.*) *\*\/.*$/;
235 # check length of line.
236 # first, a quick check to see if there is any chance of being too long.
237 if ($line =~ tr/\t/\t/ * 7 + length($line) > 100) {
238 # yes, there is a chance.
239 # replace tabs with spaces and check again.
242 s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
244 if (length($eline) > 100) {
245 do err("line
> 100 characters
($l)");
248 # this is the fastest way to check line length,
249 # but it doesnt work with perl 3.0.
250 # if ($line =~ tr/\t/\t/ * 7 + length($line) > 80) {
251 # $pos = $oldp = $p = 0;
252 # while (($p = index($line, "\t", $p)) >= 0) {
253 # $pos = ($pos + $p - $oldp + 8) & ~7;
256 # $pos += length($line) - $oldp;
258 # do err("line
> 80 characters
");
262 # remember whether we expect to be inside a continuation line.
263 $in_continuation = $expect_continuation;
265 # check for proper continuation line. blank lines
266 # in the middle of the
267 # continuation do not count.
268 # XXX - only check within functions.
269 if ($check_continuation && $expect_continuation && $in_class &&
271 # continuation line must start with whitespace of
272 # previous line, plus either 4 spaces or a tab, but
273 # do not check lines that start with a string constant
274 # since they are often shifted to the left to make them
276 if (!/^$continuation_indent \S/ &&
277 !/^$continuation_indent\t\S/ && !/^\s*"/) {
278 do err
("continuation line improperly indented");
280 $expect_continuation = 0;
283 # a /* BEGIN JSTYLED */ comment starts a no-check block.
284 if (/\
/\
* *BEGIN
*JSTYLED
*\
*\
//) {
288 # a /*JSTYLED*/ comment indicates that the next line is ok.
289 if (/\
/\
* *JSTYLED.
*\
*\
//) {
290 /^.
*\
/\
* *JSTYLED
*(.
*) *\
*\
/.
*$
/;
294 if (/\
/\
/ *JSTYLED
/) {
295 /^.
*\
/\
/ *JSTYLED
*(.
*)$
/;
300 # is this the beginning or ending of a class?
301 if (/^
(public\s
+)*\w
(class|interface
)\s
/) {
307 if (/^
}\s
*(\
/\
*.
*\
*\
/\s
*)*$
/) {
314 # strip trailing spaces
318 # does this looks like the start of a block comment?
319 if (/^\s
*\
/\
*(\
*|
)$
/) {
320 if (!/^
(\t|
)*\
/\
*(\
*|
)$
/) {
321 do err
("block comment not indented properly");
325 $comment_prefix = $_;
326 if ($comment_prefix eq
" ") {
327 $in_header_comment = 1;
332 if (/^\s
*\
/\
*.
/ && !/^\s
*\
/\
*\
*$
/ && !/^\s
*\
/\
*.
*\
*\
//) {
333 do err
("improper first line of block comment");
334 # it's a bad one, but it still is one.
335 # avoid ripple effect of not recognizing this.
336 if (!/^
(\t|
)*\
/\
*(\
*|
)/) {
337 do err
("block comment not indented properly");
341 $comment_prefix = $_;
342 if ($comment_prefix eq
" ") {
343 $in_header_comment = 1;
348 # are we still in the block comment?
349 if ($in_comment && !/^
$comment_prefix\
*/) {
350 # assume out of comment
352 $in_header_comment = 0;
355 if ($in_header_comment && $ignore_hdr_comment) {
360 # check for errors that might occur in comments and in code.
362 # allow spaces to be used to draw pictures in header comments.
363 if ($spaces && /[^
] / && !/".* .*"/ && !$in_header_comment) {
364 do err
("spaces instead of tabs");
366 if ($tabs && /^
/ && !/^ \
*[ \t\
/]/ && !/^ \
*$
/ &&
367 (!/^ \w
/ ||
$in_class != 0)) {
368 do err
("indent by spaces instead of tabs");
370 if (!$in_comment && (/^
(\t )* {1,3}\S
/ ||
/^
(\t )* {5,7}\S
/) &&
371 !(/^\s
*[-+|
&\
/?
:=]/ ||
($prev =~
/,\s
*$
/))) {
372 do err
("indent not a multiple of 4");
374 if ($spaces && /\s$
/) {
375 do err
("space or tab at end of line");
378 if (/^
[\t]+ [^
\t\
*]/ ||
/^
[\t]+ \S
/ ||
/^
[\t]+ \S
/) {
379 do err
("continuation line not indented by 4 spaces");
382 if (/[^
\t(]\
/\
*/ && !/\w\
(\
/\
*.
*\
*\
/\
);/) {
383 do err
("comment preceded by non-blank");
385 if ($spaces && /\t[ ]+\t/) {
386 do err
("spaces between tabs");
388 if ($spaces && / [\t]+ /) {
389 do err
("tabs between spaces");
392 if ($in_comment) { # still in comment
397 if ((/\
/\
*\S
/ && !/\
/\
*\
*/) ||
/\
/\
*\
*\S
/) {
398 do err
("missing blank after open comment");
401 do err
("missing blank before close comment");
403 # allow // at beginnging of line, often used to comment out code
404 if (/.\
/\
/\S
/) { # C++ comments
405 do err
("missing blank after start comment");
407 # check for unterminated single line comments.
408 if (/\S.
*\
/\
*/ && !/\S.
*\
/\
*.
*\
*\
//) {
409 do err
("unterminated single line comment");
412 # delete any comments and check everything else.
414 s
/\
/\
/.
*$
/\x01/; # C++ comments
416 # delete any trailing whitespace; we have already checked for that.
419 # following checks do not apply to text in comments.
421 # if it looks like an operator at the end of the line, and it is
422 # not really the end of a comment (...*/), and it is not really
423 # a label (done:), and it is not a case label (case FOO:),
424 # or we are not in a function definition (ANSI C style) and the
425 # operator is a "," (to avoid hitting "int\nfoo(\n\tint i,\n\tint j)"),
426 # or we are in a function and the operator is a
427 # "*" (to avoid hitting on "char*\nfunc()").
428 if ((/[-+|
&\
/?
:=]$
/ && !/\
*\
/$
/ && !/^\s
*\w
*:$
/ &&
429 !/^\s\s
*case\s\s
*\w
*:$
/) ||
431 ($in_class && /\
*$
/)) {
432 $expect_continuation = 1;
433 if (!$in_continuation) {
435 $continuation_indent = $1;
438 if (/[^
<>\s
][!<>=]=/ ||
/[^
<>][!<>=]=\S
/ ||
439 (/[^
->]>[^
=>\s
]/ && !/[^
->]>$
/) ||
(/[^
<]<[^
=<\s
]/ && !/[^
<]<$
/) ||
440 /[^
<\s
]<[^
<]/ ||
/[^
->\s
]>[^
>]/) {
441 do err
("missing space around relational operator");
443 if (/\S
>>=/ ||
/\S
<<=/ ||
/>>=\S
/ ||
/<<=\S
/ ||
/\S
[-+*\
/&|^
%]=/ ||
444 (/[^
-+*\
/&|^
%!<>=\s
]=[^
=]/ && !/[^
-+*\
/&|^
%!<>=\s
]=$
/) ||
445 (/[^
!<>=]=[^
=\s
]/ && !/[^
!<>=]=$
/)) {
446 do err
("missing space around assignment operator");
448 if (/[,;]\S
/ && !/\bfor \
(;;\
)/) {
449 do err
("comma or semicolon followed by non-blank");
451 # allow "for" statements to have empty "while" clauses
452 if (/\s
[,;]/ && !/^
[\t]+;$
/ && !/^\s
*for \
([^
;]*; ;[^
;]*\
)/) {
453 do err
("comma or semicolon preceded by blank");
456 if (/^\s
*(&&|\|\|
)/) {
457 do err
("improper boolean continuation");
460 if ($picky && /\S
*(&&|\|\|
)/ ||
/(&&|\|\|
) *\S
/) {
461 do err
("more than one space around boolean operator");
463 if (/\b(for|
if|
while|switch|
return|
case|catch|synchronized
)\
(/) {
464 do err
("missing space between keyword and paren");
466 if (/(\b(for|
if|
while|switch|
return|catch|synchronized
)\b.
*){2,}/) {
467 # multiple "case" allowed
468 do err
("more than one keyword on line");
470 if (/\b(for|
if|
while|switch|
return|
case|catch|synchronized
)\s\s
+\
(/ &&
472 do err
("extra space between keyword and paren");
474 # try to detect "func (x)" but not "if (x)" or
478 # strip off all keywords on the line
479 s
/\b(for|
if|
while|switch|
return|
case|catch|synchronized
)\s\
(/XXX
(/g
;
480 #s/\b($typename|void)\s+\(+/XXX(/og;
482 do err
("extra space between function name and left paren");
487 do err
("whitespace after left paren");
489 # allow "for" statements to have empty "continue" clauses
490 if (/\s\
)/ && !/^\s
*for \
([^
;]*;[^
;]*; \
)/) {
491 do err
("whitespace before right paren");
493 if (/^\s
*\
(void\
)[^
]/) {
494 do err
("missing space after (void) cast");
496 if (/\S
{/ && !/{{/) {
497 do err
("missing space before left brace");
499 if ($in_class && /^\s
+{/ && ($prev =~
/\
)\s
*$
/)) {
500 do err
("left brace starting a line");
502 if (/}(else|
while)/) {
503 do err
("missing space after right brace");
505 if (/}\s\s
+(else|
while)/) {
506 do err
("extra space after right brace");
508 if (/\b$typename\
*/o
) {
509 do err
("missing space between type name and *");
512 # cannot check this everywhere due to "struct {\n...\n} foo;"
513 if ($in_class && !$in_declaration &&
514 /}.
/ && !/}\s
+=/ && !/{.
*}[;,]$
/ && !/}(\s|
\x01)*$
/ &&
515 !/} (else|
while)/ && !/}}/) {
516 do err
("possible bad text following right brace");
518 # cannot check this because sub-blocks in
519 # the middle of code are ok
520 if ($in_class && /^\s
+{/) {
521 do err
("possible left brace starting a line");
525 if ($prev =~
/^\s
*}$
/) {
526 $str = "else and right brace should be on same line";
527 if ($statistics == 0) {
528 printf $fmt, $filename, $.
, $str, $prev;
530 printf "%s\n", $line;
533 $errcount{$str} += 1;
541 if ($picky && $prev eq
"") {
542 do err
("last line in file is blank");