8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / tools / scripts / jstyle.pl
blobf48dc96b35f8686623ed331e526c8dc449130d99
1 #!/usr/bin/perl -w
3 # CDDL HEADER START
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
20 # CDDL HEADER END
24 # Copyright 2015 Toomas Soome <tsoome@me.com>
25 # Copyright 2008 Sun Microsystems, Inc. All rights reserved.
26 # Use is subject to license terms.
28 # jstyle - check for some common stylistic errors.
31 require 5.006;
32 use Getopt::Std;
33 use strict;
35 my $usage =
36 "usage: jstyle [-c] [-h] [-p] [-t] [-v] [-C] file ...
37 -c check continuation line indenting
38 -h perform heuristic checks that are sometimes wrong
39 -p perform some of the more picky checks
40 -t insist on indenting by tabs
41 -v verbose
42 -C don't check anything in header block comments
45 my %opts;
47 # Keep -s, as it's been around for a while. It just doesn't do anything
48 # anymore.
49 if (!getopts("chpstvC", \%opts)) {
50 print $usage;
51 exit 2;
54 my $check_continuation = $opts{'c'};
55 my $heuristic = $opts{'h'};
56 my $picky = $opts{'p'};
57 my $tabs = $opts{'t'};
58 my $verbose = $opts{'v'};
59 my $ignore_hdr_comment = $opts{'C'};
61 my ($filename, $line, $prev);
62 my $err_stat = 0; # Exit status
64 my $fmt;
66 if ($verbose) {
67 $fmt = "%s: %d: %s\n%s\n";
68 } else {
69 $fmt = "%s: %d: %s\n";
72 # Note, following must be in single quotes so that \s and \w work right.
73 my $typename = '(int|char|boolean|byte|short|long|float|double)';
74 my $keywords = '(for|if|while|switch|return|catch|synchronized|throw|assert)';
75 # See perlre(1) for the meaning of (??{ ... })
76 my $annotations = ""; $annotations = qr/@\w+\((?:(?>[^()]+)|(??{ $annotations }))*\)/;
77 my $generics = ""; $generics = qr/<(([\s\w,.?[\]]| & )+|(??{ $generics }))*>/;
78 my $relationalops = qr/>=|<=|<|>|!=|==/;
79 my $shiftops = qr/<<<|>>>|<<|>>/;
80 my $shiftassignmentops = qr/[<>]{2,3}=/;
81 my $assignmentops = qr/[-+\/*|&^%]?=/;
82 # These need to be in decreasing order of length
83 my $allops = qr/$shiftassignmentops|$shiftops|$relationalops|$assignmentops/;
85 if ($#ARGV >= 0) {
86 foreach my $arg (@ARGV) {
87 if (!open(STDIN, $arg)) {
88 printf "%s: can not open\n", $arg;
89 } else {
90 &jstyle($arg);
91 close STDIN;
94 } else {
95 &jstyle("<stdin>");
97 exit $err_stat;
99 sub err($) {
100 if ($verbose) {
101 printf $fmt, $filename, $., $_[0], $line;
102 } else {
103 printf $fmt, $filename, $., $_[0];
105 $err_stat = 1;
108 sub jstyle($) {
110 my $in_comment = 0;
111 my $in_header_comment = 0;
112 my $in_continuation = 0;
113 my $in_class = 0;
114 my $in_declaration = 0;
115 my $nextok = 0;
116 my $nocheck = 0;
117 my $expect_continuation = 0;
118 my $continuation_indent;
119 my $okmsg;
120 my $comment_prefix;
121 my $comment_done;
122 my $cpp_comment;
124 $filename = $_[0];
126 line: while (<STDIN>) {
127 s/\r?\n$//; # strip return and newline
129 # save the original line, then remove all text from within
130 # double or single quotes, we do not want to check such text.
132 $line = $_;
133 s/"[^"]*"/\"\"/g;
134 s/'.'/''/g;
136 # an /* END JSTYLED */ comment ends a no-check block.
137 if ($nocheck) {
138 if (/\/\* *END *JSTYLED *\*\//) {
139 $nocheck = 0;
140 } else {
141 next line;
145 # a /*JSTYLED*/ comment indicates that the next line is ok.
146 if ($nextok) {
147 if ($okmsg) {
148 err($okmsg);
150 $nextok = 0;
151 $okmsg = 0;
152 if (/\/\* *JSTYLED.*\*\//) {
153 /^.*\/\* *JSTYLED *(.*) *\*\/.*$/;
154 $okmsg = $1;
155 $nextok = 1;
157 $prev = $line;
158 next line;
161 # remember whether we expect to be inside a continuation line.
162 $in_continuation = $expect_continuation;
164 # check for proper continuation line. blank lines
165 # in the middle of the
166 # continuation do not count.
167 # XXX - only check within functions.
168 if ($check_continuation && $expect_continuation && $in_class &&
169 !/^\s*$/) {
170 # continuation line must start with whitespace of
171 # previous line, plus either 4 spaces or a tab, but
172 # do not check lines that start with a string constant
173 # since they are often shifted to the left to make them
174 # fit on the line.
175 if (!/^$continuation_indent \S/ &&
176 !/^$continuation_indent\t\S/ && !/^\s*"/) {
177 err("continuation line improperly indented");
179 $expect_continuation = 0;
182 # a /* BEGIN JSTYLED */ comment starts a no-check block.
183 if (/\/\* *BEGIN *JSTYLED *\*\//) {
184 $nocheck = 1;
187 # a /*JSTYLED*/ comment indicates that the next line is ok.
188 if (/\/\* *JSTYLED.*\*\//) {
189 /^.*\/\* *JSTYLED *(.*) *\*\/.*$/;
190 $okmsg = $1;
191 $nextok = 1;
193 if (/\/\/ *JSTYLED/) {
194 /^.*\/\/ *JSTYLED *(.*)$/;
195 $okmsg = $1;
196 $nextok = 1;
199 # is this the beginning or ending of a class?
200 if (/^(public\s+)*\w(class|interface)\s/) {
201 $in_class = 1;
202 $in_declaration = 1;
203 $prev = $line;
204 next line;
206 if (/^}\s*(\/\*.*\*\/\s*)*$/) {
207 $in_class = 0;
208 $prev = $line;
209 next line;
212 if ($comment_done) {
213 $in_comment = 0;
214 $in_header_comment = 0;
215 $comment_done = 0;
217 # does this looks like the start of a block comment?
218 if (/^\s*\/\*/ && !/^\s*\/\*.*\*\//) {
219 if (/^\s*\/\*./ && !/^\s*\/\*\*$/) {
220 err("improper first line of block comment");
222 if (!/^(\t| )*\/\*/) {
223 err("block comment not indented properly");
225 $in_comment = 1;
226 /^(\s*)\//;
227 $comment_prefix = $1;
228 if ($comment_prefix eq "") {
229 $in_header_comment = 1;
231 $prev = $line;
232 next line;
234 # are we still in the block comment?
235 if ($in_comment) {
236 if (/^$comment_prefix \*\/$/) {
237 $comment_done = 1;
238 } elsif (/\*\//) {
239 $comment_done = 1;
240 err("improper block comment close")
241 unless ($ignore_hdr_comment && $in_header_comment);
242 } elsif (!/^$comment_prefix \*[ \t]/ &&
243 !/^$comment_prefix \*$/) {
244 err("improper block comment")
245 unless ($ignore_hdr_comment && $in_header_comment);
249 if ($in_header_comment && $ignore_hdr_comment) {
250 $prev = $line;
251 next line;
254 # check for errors that might occur in comments and in code.
256 # check length of line.
257 # first, a quick check to see if there is any chance of being too long.
258 if ($line =~ tr/\t/\t/ * 7 + length($line) > 80) {
259 # yes, there is a chance.
260 # replace tabs with spaces and check again.
261 my $eline = $line;
262 1 while $eline =~
263 s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
264 if (length($eline) > 80) {
265 err("line > 80 characters");
269 # Allow spaces to be used to draw pictures in header comments, but
270 # disallow blocks of spaces almost everywhere else. In particular,
271 # five spaces are also allowed at the end of a line's indentation
272 # if the rest of the line belongs to a block comment.
273 if (!$in_header_comment &&
274 /[^ ] / &&
275 !(/^\t* \*/ && !/^\t* \*.* /)) {
276 err("spaces instead of tabs");
278 if ($tabs && /^ / && !/^ \*[ \t\/]/ && !/^ \*$/ &&
279 (!/^ \w/ || $in_class != 0)) {
280 err("indent by spaces instead of tabs");
282 if (!$in_comment && (/^(\t )* {1,3}\S/ || /^(\t )* {5,7}\S/) &&
283 !(/^\s*[-+|&\/?:=]/ || ($prev =~ /,\s*$/))) {
284 err("indent not a multiple of 4");
286 if (/\s$/) {
287 err("space or tab at end of line");
289 if (0) {
290 if (/^[\t]+ [^ \t\*]/ || /^[\t]+ \S/ || /^[\t]+ \S/) {
291 err("continuation line not indented by 4 spaces");
294 if (/\/\//) {
295 $cpp_comment = 1;
297 if (!$cpp_comment && /[^ \t(\/]\/\*/ && !/\w\(\/\*.*\*\/\);/) {
298 err("comment preceded by non-blank");
300 if (/\t +\t/) {
301 err("spaces between tabs");
303 if (/ \t+ /) {
304 err("tabs between spaces");
307 if ($in_comment) { # still in comment
308 $prev = $line;
309 next line;
312 if (!$cpp_comment && ((/\/\*\S/ && !/\/\*\*/) || /\/\*\*\S/)) {
313 err("missing blank after open comment");
315 if (!$cpp_comment && /\S\*\//) {
316 err("missing blank before close comment");
318 # check for unterminated single line comments.
319 if (/\S.*\/\*/ && !/\S.*\/\*.*\*\//) {
320 err("unterminated single line comment");
323 # delete any comments and check everything else. Be sure to leave
324 # //-style comments intact, and if there are multiple comments on a
325 # line, preserve whatever's in between.
326 s/(?<!\/)\/\*.*?\*\//\x01/g;
327 # Check for //-style comments only outside of block comments
328 if (m{(//(?!$))} && substr($_, $+[0], 1) !~ /[ \t]/) {
329 err("missing blank after start comment");
331 s/\/\/.*$/\x01/; # C++ comments
332 $cpp_comment = 0;
334 # delete any trailing whitespace; we have already checked for that.
335 s/\s*$//;
337 # We don't style (yet) what's inside annotations, so just delete them.
338 s/$annotations//;
340 # following checks do not apply to text in comments.
342 # if it looks like an operator at the end of the line, and it is
343 # not really the end of a comment (...*/), and it is not really
344 # a label (done:), and it is not a case label (case FOO:),
345 # or we are not in a function definition (ANSI C style) and the
346 # operator is a "," (to avoid hitting "int\nfoo(\n\tint i,\n\tint j)"),
347 # or we are in a function and the operator is a
348 # "*" (to avoid hitting on "char*\nfunc()").
349 if ((/[-+|&\/?:=]$/ && !/\*\/$/ && !/^\s*\w*:$/ &&
350 !/^\s\s*case\s\s*\w*:$/) ||
351 /,$/ ||
352 ($in_class && /\*$/)) {
353 $expect_continuation = 1;
354 if (!$in_continuation) {
355 /^(\s*)\S/;
356 $continuation_indent = $1;
359 while (/($allops)/g) {
360 my $z = substr($_, $-[1] - 1);
361 if ($z !~ /\s\Q$1\E(?:\s|$)/) {
362 my $m = $1;
363 my $shift;
364 # @+ is available only in the currently active
365 # dynamic scope. Assign it to a new variable
366 # to pass it into the if block.
367 if ($z =~ /($generics)/ &&
368 ($shift = $+[1])) {
369 pos $_ += $shift;
370 next;
373 # These need to be in decreasing order of length
374 # (violable as long as there's no ambiguity)
375 my $nospace = "missing space around";
376 if ($m =~ $shiftassignmentops) {
377 err("$nospace assignment operator");
378 } elsif ($m =~ $shiftops) {
379 err("$nospace shift operator");
380 } elsif ($m =~ $relationalops) {
381 err("$nospace relational operator");
382 } elsif ($m =~ $assignmentops) {
383 err("$nospace assignment operator");
387 if (/[,;]\S/ && !/\bfor \(;;\)/) {
388 err("comma or semicolon followed by non-blank");
390 # allow "for" statements to have empty "while" clauses
391 if (/\s[,;]/ && !/^[\t]+;$/ && !/^\s*for \([^;]*; ;[^;]*\)/) {
392 err("comma or semicolon preceded by blank");
394 if (0) {
395 if (/^\s*(&&|\|\|)/) {
396 err("improper boolean continuation");
399 if ($picky && /\S *(&&|\|\|)/ || /(&&|\|\|) *\S/) {
400 err("more than one space around boolean operator");
402 if (/\b$keywords\(/) {
403 err("missing space between keyword and paren");
405 if (/(\b$keywords\b.*){2,}/ && !/\bcase\b.*/) { # "case" excepted
406 err("more than one keyword on line");
408 if (/\b$keywords\s\s+\(/ &&
409 !/^#if\s+\(/) {
410 err("extra space between keyword and paren");
412 # try to detect "func (x)" but not "if (x)" or
413 # "int (*func)();"
414 if (/\w\s\(/) {
415 my $save = $_;
416 # strip off all keywords on the line
417 s/\b$keywords\s\(/XXX(/g;
418 #s/\b($typename|void)\s+\(+/XXX(/og;
419 if (/\w\s\(/) {
420 err("extra space between function name and left paren");
422 $_ = $save;
424 if (/\(\s/) {
425 err("whitespace after left paren");
427 # allow "for" statements to have empty "continue" clauses
428 if (/\s\)/ && !/^\s*for \([^;]*;[^;]*; \)/) {
429 err("whitespace before right paren");
431 if (/^\s*\(void\)[^ ]/) {
432 err("missing space after (void) cast");
434 if (/\S\{/ && !/\{\{/) {
435 err("missing space before left brace");
437 if ($in_class && /^\s+{/ && ($prev =~ /\)\s*$/)) {
438 err("left brace starting a line");
440 if (/}(else|while)/) {
441 err("missing space after right brace");
443 if (/}\s\s+(else|while)/) {
444 err("extra space after right brace");
446 if (/\b$typename\*/o) {
447 err("missing space between type name and *");
449 if ($heuristic) {
450 # cannot check this everywhere due to "struct {\n...\n} foo;"
451 if ($in_class && !$in_declaration &&
452 /}./ && !/}\s+=/ && !/{.*}[;,]$/ && !/}(\s|\x01)*$/ &&
453 !/} (else|while)/ && !/}}/) {
454 err("possible bad text following right brace");
456 # cannot check this because sub-blocks in
457 # the middle of code are ok
458 if ($in_class && /^\s+{/) {
459 err("possible left brace starting a line");
462 if (/^\s*else\W/) {
463 if ($prev =~ /^\s*}$/) {
464 my $str = "else and right brace should be on same line";
465 printf $fmt, $filename, $., $str, $prev;
466 if ($verbose) {
467 printf "%s\n", $line;
471 $prev = $line;
474 if ($picky && $prev eq "") {
475 err("last line in file is blank");