1#!/bin/sh -- # This comment tells perl not to loop! 2# 3#************************************************************** 4# 5# Licensed to the Apache Software Foundation (ASF) under one 6# or more contributor license agreements. See the NOTICE file 7# distributed with this work for additional information 8# regarding copyright ownership. The ASF licenses this file 9# to you under the Apache License, Version 2.0 (the 10# "License"); you may not use this file except in compliance 11# with the License. You may obtain a copy of the License at 12# 13# http://www.apache.org/licenses/LICENSE-2.0 14# 15# Unless required by applicable law or agreed to in writing, 16# software distributed under the License is distributed on an 17# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18# KIND, either express or implied. See the License for the 19# specific language governing permissions and limitations 20# under the License. 21# 22#************************************************************** 23 24** 25 26 27eval 'exec perl -S $0 "$@"' 28if 0; 29# 30# @(#)jstyle 1.2 98/01/08 31# 32# jstyle - check for some common stylistic errors. 33# 34# jstyle is a sort of "lint" for Java coding style. 35# 36# There's a lot this can't check for, like proper 37# indentation of continuation lines. There's also 38# a lot more this could check for. 39# 40# A note to the non perl literate: 41# 42# perl regular expressions are pretty much like egrep 43# regular expressions, with the following special symbols 44# 45# \s any space character 46# \S any non-space character 47# \w any "word" character [a-zA-Z0-9_] 48# \W any non-word character 49# \d a digit [0-9] 50# \D a non-digit 51# \b word boundary (between \w and \W) 52# \B non-word boundary 53# 54#require "getopts.pl"; 55# XXX - because some versions of perl can not find the lib directory, 56# we just include this here. 57;# getopts.pl - a better getopt.pl 58 59;# Usage: 60;# do Getopts("a:bc"); # -a takes arg. -b & -c not. Sets opt_* as a 61;# # side effect. 62 63sub Getopts { 64 local($argumentative) = @_; 65 local(@args,$_,$first,$rest); 66 local($[) = 0; 67 local($errs) = 0; 68 69 @args = split( / */, $argumentative ); 70 while(($_ = $ARGV[0]) =~ /^-(.)(.*)/) { 71 ($first,$rest) = ($1,$2); 72 $pos = index($argumentative,$first); 73 if($pos >= $[) { 74 if($args[$pos+1] eq ":") { 75 shift(@ARGV); 76 if($rest eq "") { 77 $rest = shift(@ARGV); 78 } 79 eval "\$opt_$first = \$rest;"; 80 } 81 else { 82 eval "\$opt_$first = 1"; 83 if($rest eq "") { 84 shift(@ARGV); 85 } 86 else { 87 $ARGV[0] = "-$rest"; 88 } 89 } 90 } 91 else { 92 print STDERR "Unknown option: $first\n"; 93 ++$errs; 94 if($rest ne "") { 95 $ARGV[0] = "-$rest"; 96 } 97 else { 98 shift(@ARGV); 99 } 100 } 101 } 102 $errs == 0; 103} 104 1051; 106# end of getopts.pl 107 108$usage = 109"usage: jstyle [-c] [-h] [-p] [-s] [-t] [-v] [-C] file ... 110 -c check continuation line indenting 111 -h perform heuristic checks that are sometimes wrong 112 -p perform some of the more picky checks 113 -s check for spaces vs. tabs 114 -t insist on indenting by tabs 115 -v verbose 116 -C don't check anything in header block comments 117 -S print out overall statistics 118"; 119 120if (!&Getopts("chpstvCS")) { 121 print $usage; 122 exit 1; 123} 124 125$check_continuation = $opt_c; 126$heuristic = $opt_h; 127$picky = $opt_p; 128$spaces = $opt_s; 129$tabs = $opt_t; 130$verbose = $opt_v; 131$ignore_hdr_comment = $opt_C; 132$statistics = $opt_S; 133 134if ($verbose) { 135 $fmt = "%s: %d: %s\n%s\n"; 136} else { 137 $fmt = "%s: %d: %s\n"; 138} 139 140# Note, following must be in single quotes so that \s and \w work right. 141$typename = '(int|char|boolean|byte|short|long|float|double)'; 142 143if ($#ARGV >= 0) { 144 foreach $arg (@ARGV) { 145 if (!open(STDIN, $arg)) { 146 printf "%s: can not open\n", $arg; 147 } else { 148 &jstyle($arg); 149 close STDIN; 150 } 151 } 152} else { 153 &jstyle("<stdin>"); 154} 155 156if ($statistics != 0) { 157 foreach $key (sort(keys %errcount)) { 158 printf "%6d %s\n", $errcount{$key}, $key; 159 } 160 printf " -----\n"; 161 printf "%6d Total warnings\n", $tot_errcount; 162 printf "%6d Lines of code\n", $totlines; 163} 164 165sub err { 166 if ($statistics == 0) { 167 printf $fmt, $filename, $., $_[0], $line; 168 } else { 169 $msg = $_[0]; 170 $msg =~ s/ \([0-9][0-9]*\)$//; 171 $errcount{$msg} += 1; 172 $tot_errcount += 1; 173 } 174} 175 176sub jstyle { 177 178$in_comment = 0; 179$in_header_comment = 0; 180$in_continuation = 0; 181$in_class = 0; 182$in_declaration = 0; 183$note_level = 0; 184$nextok = 0; 185$nocheck = 0; 186$expect_continuation = 0; 187$prev = ''; 188 189$filename = $_[0]; 190 191line: while (<STDIN>) { 192 ++$totlines; 193 s/\r?\n$//; # strip return and newline 194 195 # save the original line, then remove all text from within 196 # double or single quotes, we do not want to check such text. 197 198 $line = $_; 199 s/"[^"]*"/\"\"/g; 200 s/'.'/''/g; 201 202 # an /* END JSTYLED */ comment ends a no-check block. 203 if ($nocheck) { 204 if (/\/\* *END *JSTYLED *\*\//) { 205 $nocheck = 0; 206 } else { 207 next line; 208 } 209 } 210 211 # a /*JSTYLED*/ comment indicates that the next line is ok. 212 if ($nextok) { 213 if ($okmsg) { 214 do err($okmsg); 215 } 216 $nextok = 0; 217 $okmsg = 0; 218 if (/\/\* *JSTYLED.*\*\//) { 219 /^.*\/\* *JSTYLED *(.*) *\*\/.*$/; 220 $okmsg = $1; 221 $nextok = 1; 222 } 223 $prev = $line; 224 next line; 225 } 226 227 # check length of line. 228 # first, a quick check to see if there is any chance of being too long. 229 if ($line =~ tr/\t/\t/ * 7 + length($line) > 100) { 230 # yes, there is a chance. 231 # replace tabs with spaces and check again. 232 $eline = $line; 233 1 while $eline =~ 234 s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e; 235 $l = length($eline); 236 if (length($eline) > 100) { 237 do err("line > 100 characters ($l)"); 238 } 239 } 240# this is the fastest way to check line length, 241# but it doesn't work with perl 3.0. 242# if ($line =~ tr/\t/\t/ * 7 + length($line) > 80) { 243# $pos = $oldp = $p = 0; 244# while (($p = index($line, "\t", $p)) >= 0) { 245# $pos = ($pos + $p - $oldp + 8) & ~7; 246# $oldp = ++$p; 247# } 248# $pos += length($line) - $oldp; 249# if ($pos > 80) { 250# do err("line > 80 characters"); 251# } 252# } 253 254 # remember whether we expect to be inside a continuation line. 255 $in_continuation = $expect_continuation; 256 257 # check for proper continuation line. blank lines 258 # in the middle of the 259 # continuation do not count. 260 # XXX - only check within functions. 261 if ($check_continuation && $expect_continuation && $in_class && 262 !/^\s*$/) { 263 # continuation line must start with whitespace of 264 # previous line, plus either 4 spaces or a tab, but 265 # do not check lines that start with a string constant 266 # since they are often shifted to the left to make them 267 # fit on the line. 268 if (!/^$continuation_indent \S/ && 269 !/^$continuation_indent\t\S/ && !/^\s*"/) { 270 do err("continuation line improperly indented"); 271 } 272 $expect_continuation = 0; 273 } 274 275 # a /* BEGIN JSTYLED */ comment starts a no-check block. 276 if (/\/\* *BEGIN *JSTYLED *\*\//) { 277 $nocheck = 1; 278 } 279 280 # a /*JSTYLED*/ comment indicates that the next line is ok. 281 if (/\/\* *JSTYLED.*\*\//) { 282 /^.*\/\* *JSTYLED *(.*) *\*\/.*$/; 283 $okmsg = $1; 284 $nextok = 1; 285 } 286 if (/\/\/ *JSTYLED/) { 287 /^.*\/\/ *JSTYLED *(.*)$/; 288 $okmsg = $1; 289 $nextok = 1; 290 } 291 292 # is this the beginning or ending of a class? 293 if (/^(public\s+)*\w(class|interface)\s/) { 294 $in_class = 1; 295 $in_declaration = 1; 296 $prev = $line; 297 next line; 298 } 299 if (/^}\s*(\/\*.*\*\/\s*)*$/) { 300 $in_class = 0; 301 $prev = $line; 302 next line; 303 } 304 305 if (!$spaces) { 306 # strip trailing spaces 307 s/\s*$//; 308 } 309 310 # does this looks like the start of a block comment? 311 if (/^\s*\/\*(\*|)$/) { 312 if (!/^(\t| )*\/\*(\*|)$/) { 313 do err("block comment not indented properly"); 314 } 315 $in_comment = 1; 316 s/\/\*(\*|)/ /; 317 $comment_prefix = $_; 318 if ($comment_prefix eq " ") { 319 $in_header_comment = 1; 320 } 321 $prev = $line; 322 next line; 323 } 324 if (/^\s*\/\*./ && !/^\s*\/\*\*$/ && !/^\s*\/\*.*\*\//) { 325 do err("improper first line of block comment"); 326 # it's a bad one, but it still is one. 327 # avoid ripple effect of not recognizing this. 328 if (!/^(\t| )*\/\*(\*|)/) { 329 do err("block comment not indented properly"); 330 } 331 $in_comment = 1; 332 s/\/\*.*/ /; 333 $comment_prefix = $_; 334 if ($comment_prefix eq " ") { 335 $in_header_comment = 1; 336 } 337 $prev = $line; 338 next line; 339 } 340 # are we still in the block comment? 341 if ($in_comment && !/^$comment_prefix\*/) { 342 # assume out of comment 343 $in_comment = 0; 344 $in_header_comment = 0; 345 } 346 347 if ($in_header_comment && $ignore_hdr_comment) { 348 $prev = $line; 349 next line; 350 } 351 352 # check for errors that might occur in comments and in code. 353 354 # allow spaces to be used to draw pictures in header comments. 355 if ($spaces && /[^ ] / && !/".* .*"/ && !$in_header_comment) { 356 do err("spaces instead of tabs"); 357 } 358 if ($tabs && /^ / && !/^ \*[ \t\/]/ && !/^ \*$/ && 359 (!/^ \w/ || $in_class != 0)) { 360 do err("indent by spaces instead of tabs"); 361 } 362 if (!$in_comment && (/^(\t )* {1,3}\S/ || /^(\t )* {5,7}\S/) && 363 !(/^\s*[-+|&\/?:=]/ || ($prev =~ /,\s*$/))) { 364 do err("indent not a multiple of 4"); 365 } 366 if ($spaces && /\s$/) { 367 do err("space or tab at end of line"); 368 } 369if (0) { 370 if (/^[\t]+ [^ \t\*]/ || /^[\t]+ \S/ || /^[\t]+ \S/) { 371 do err("continuation line not indented by 4 spaces"); 372 } 373} 374 if (/[^ \t(]\/\*/ && !/\w\(\/\*.*\*\/\);/) { 375 do err("comment preceded by non-blank"); 376 } 377 if ($spaces && /\t[ ]+\t/) { 378 do err("spaces between tabs"); 379 } 380 if ($spaces && / [\t]+ /) { 381 do err("tabs between spaces"); 382 } 383 384 if ($in_comment) { # still in comment 385 $prev = $line; 386 next line; 387 } 388 389 if ((/\/\*\S/ && !/\/\*\*/) || /\/\*\*\S/) { 390 do err("missing blank after open comment"); 391 } 392 if (/\S\*\//) { 393 do err("missing blank before close comment"); 394 } 395 # allow // at beginnging of line, often used to comment out code 396 if (/.\/\/\S/) { # C++ comments 397 do err("missing blank after start comment"); 398 } 399 # check for unterminated single line comments. 400 if (/\S.*\/\*/ && !/\S.*\/\*.*\*\//) { 401 do err("unterminated single line comment"); 402 } 403 404 # delete any comments and check everything else. 405 s/\/\*.*\*\///g; 406 s/\/\/.*$//; # C++ comments 407 408 # delete any trailing whitespace; we have already checked for that. 409 s/\s*$//; 410 411 # following checks do not apply to text in comments. 412 413 # if it looks like an operator at the end of the line, and it is 414 # not really the end of a comment (...*/), and it is not really 415 # a label (done:), and it is not a case label (case FOO:), 416 # or we are not in a function definition (ANSI C style) and the 417 # operator is a "," (to avoid hitting "int\nfoo(\n\tint i,\n\tint j)"), 418 # or we are in a function and the operator is a 419 # "*" (to avoid hitting on "char*\nfunc()"). 420 if ((/[-+|&\/?:=]$/ && !/\*\/$/ && !/^\s*\w*:$/ && 421 !/^\s\s*case\s\s*\w*:$/) || 422 /,$/ || 423 ($in_class && /\*$/)) { 424 $expect_continuation = 1; 425 if (!$in_continuation) { 426 /^(\s*)\S/; 427 $continuation_indent = $1; 428 } 429 } 430 if (/[^<>\s][!<>=]=/ || /[^<>][!<>=]=\S/ || 431 (/[^->]>[^=>\s]/ && !/[^->]>$/) || (/[^<]<[^=<\s]/ && !/[^<]<$/) || 432 /[^<\s]<[^<]/ || /[^->\s]>[^>]/) { 433 do err("missing space around relational operator"); 434 } 435 if (/\S>>=/ || /\S<<=/ || />>=\S/ || /<<=\S/ || /\S[-+*\/&|^%]=/ || 436 (/[^-+*\/&|^%!<>=\s]=[^=]/ && !/[^-+*\/&|^%!<>=\s]=$/) || 437 (/[^!<>=]=[^=\s]/ && !/[^!<>=]=$/)) { 438 do err("missing space around assignment operator"); 439 } 440 if (/[,;]\S/ && !/\bfor \(;;\)/) { 441 do err("comma or semicolon followed by non-blank"); 442 } 443 # allow "for" statements to have empty "while" clauses 444 if (/\s[,;]/ && !/^[\t]+;$/ && !/^\s*for \([^;]*; ;[^;]*\)/) { 445 do err("comma or semicolon preceded by blank"); 446 } 447if (0) { 448 if (/^\s*(&&|\|\|)/) { 449 do err("improper boolean continuation"); 450 } 451} 452 if ($picky && /\S *(&&|\|\|)/ || /(&&|\|\|) *\S/) { 453 do err("more than one space around boolean operator"); 454 } 455 if (/\b(for|if|while|switch|return|case|catch|synchronized)\(/) { 456 do err("missing space between keyword and paren"); 457 } 458 if (/(\b(for|if|while|switch|return|catch|synchronized)\b.*){2,}/) { 459 # multiple "case" allowed 460 do err("more than one keyword on line"); 461 } 462 if (/\b(for|if|while|switch|return|case|catch|synchronized)\s\s+\(/ && 463 !/^#if\s+\(/) { 464 do err("extra space between keyword and paren"); 465 } 466 # try to detect "func (x)" but not "if (x)" or 467 # "int (*func)();" 468 if (/\w\s\(/) { 469 $s = $_; 470 # strip off all keywords on the line 471 s/\b(for|if|while|switch|return|case|catch|synchronized)\s\(/XXX(/g; 472 #s/\b($typename|void)\s+\(+/XXX(/og; 473 if (/\w\s\(/) { 474 do err("extra space between function name and left paren"); 475 } 476 $_ = $s; 477 } 478 if (/\(\s/) { 479 do err("whitespace after left paren"); 480 } 481 # allow "for" statements to have empty "continue" clauses 482 if (/\s\)/ && !/^\s*for \([^;]*;[^;]*; \)/) { 483 do err("whitespace before right paren"); 484 } 485 if (/^\s*\(void\)[^ ]/) { 486 do err("missing space after (void) cast"); 487 } 488 if (/\S{/ && !/{{/) { 489 do err("missing space before left brace"); 490 } 491 if ($in_class && /^\s+{/ && ($prev =~ /\)\s*$/)) { 492 do err("left brace starting a line"); 493 } 494 if (/}(else|while)/) { 495 do err("missing space after right brace"); 496 } 497 if (/}\s\s+(else|while)/) { 498 do err("extra space after right brace"); 499 } 500 if (/\b$typename\*/o) { 501 do err("missing space between type name and *"); 502 } 503 if ($heuristic) { 504 # cannot check this everywhere due to "struct {\n...\n} foo;" 505 if ($in_class && !$in_declaration && 506 /}./ && !/}\s+=/ && !/{.*}[;,]$/ && !/}(\s|)*$/ && 507 !/} (else|while)/ && !/}}/) { 508 do err("possible bad text following right brace"); 509 } 510 # cannot check this because sub-blocks in 511 # the middle of code are ok 512 if ($in_class && /^\s+{/) { 513 do err("possible left brace starting a line"); 514 } 515 } 516 if (/^\s*else\W/) { 517 if ($prev =~ /^\s*}$/) { 518 $str = "else and right brace should be on same line"; 519 if ($statistics == 0) { 520 printf $fmt, $filename, $., $str, $prev; 521 if ($verbose) { 522 printf "%s\n", $line; 523 } 524 } else { 525 $errcount{$str} += 1; 526 $tot_errcount += 1; 527 } 528 } 529 } 530 $prev = $line; 531} 532 533if ($picky && $prev eq "") { 534 do err("last line in file is blank"); 535} 536 537} 538