#!/bin/sh # # @Authors: Christopher Hylands # # @Version: $Id: chkjava 64744 2012-10-01 22:51:43Z cxh $ # # @Copyright (c) 1997-2012 The Regents of the University of California. # All rights reserved. # # Permission is hereby granted, without written agreement and without # license or royalty fees, to use, copy, modify, and distribute this # software and its documentation for any purpose, provided that the # above copyright notice and the following two paragraphs appear in all # copies of this software. # # IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF # THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE # PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF # CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, # ENHANCEMENTS, OR MODIFICATIONS. # # PT_COPYRIGHT_VERSION_2 # COPYRIGHTENDKEY # Script to sanity check java files # 1) Report protected and private variables that do not have a leading _ # 2) Report lines longer than 80 chars # 3) Report public methods and variables after private or protected ones # 4) Make sure that each file includes a copyright, @version and @author # 5) Make sure that @author and @version are not @author: and @version: # 5.1) Warn if @contributor is used # 6) Check for spaces after commas # 7) Check for FIXMEs # 8) Check for lines with trailing spaces # 9) Check the rating # 10) Check for bogus spaces around declarations # 11) Check for %W% %G%, which are from SCCS # 12) Check for // System.out.println # 13) Check for @exception tags that are not worded properly # 14) Check for @exception # 15) Make sure that Parameters names do not start with capital letters # 16) Warn about catching CloneNotSupported # 17) Warn about import ... *; for everything but ptolemy.kernel.util # 18) Warn if the clone method copies port or parameters # 19) Warn if there is no trailing newline # 20) Warn if the class comment has * on each line. # 21) Warn if printStackTrace() or fillInStackTrace() are used # 22) Warn if setTypeAtLeast is present, but clone is not defined # 23) Check that the methods are alphabetical # Determine if we are on windows windows=no case "${OSTYPE-no}" in # Cygwin Bash cygwin*) windows=yes;; # Tcsh Windows*) windows=yes;; esac awk=awk if [ "$windows" = "yes" ]; then awk=gawk fi for file in $@ do results=`head -1 $file | grep "Generated By:JavaCC: Do not edit this line"` if [ "x$results" != "x" ]; then echo "$file: Skipping because is is generated by JavaCC" continue fi results=`grep protected $file | grep -v 'protected methods' | egrep -v '[ ]*\*' | grep -v 'protected variables' | grep -v 'protected class' | grep -v 'write-protected' | grep -v ' _'` if [ "x$results" != "x" ]; then echo "$results" | $awk '{ # If this is a constructor, then do not complain split($2,f,"(") # Skip over comments that start with // if (f[1] != filenm && $0 !~ /^[ ]*\/\//) { if (printedheader == 0) { print filenm".java: protected does not have a leading _" printedheader = 1 } print $0 } }' filenm=`basename $file .java` fi results=`grep private $file | egrep -v '[ ]*\*' | grep -v 'private methods' | grep -v 'private class' | grep -v 'private static final class' | grep -v 'private variables' | grep -v ' _'` if [ "x$results" != "x" ]; then echo "$results" | $awk '{ # If this is a constructor, then do not complain split($2,f,"(") # Skip over comments that start with // # or start with a non whitespace character if (f[1] != filenm && $0 !~ /^[ ]*\/\// && $0 !~/^[ ]*/) { if (printedheader == 0) { print filenm".java: private does not have a leading _" printedheader = 1 } print $0 } }' filenm=`basename $file .java` fi # Look for lines longer than 80 chars #$awk 'length($0) > 80 {if ($0 !~ /[Hh][Rr][Ee][Ff]/ && $1 !~ /@version/ ) {print FILENAME": Line more than 80 chars:"; print $0}}' $file # Look for public statements after private etc. $awk '$1 == "public" {sawpublic=1 if (sawprivate == 1 && sawinner != 1) { print FILENAME": public is after private" print $0 } if (sawprotected == 1 && sawinner != 1) { print FILENAME": public is after protected" print $0 } } $1 == "protected" { if (sawprivate == 1 && sawinner != 1) { print FILENAME": public is after private" print $0 } } $1 == "private" { if ( $0 ~ /private class/ || $0 ~/private static class/) { # Inner Class sawpublic=0 sawprotected=0 sawprivate=0 } else { # If we have a private constructor, then # allow it to be at the top of the file. # ArrayMath.java has one. split($2,constr,"("); np=split(FILENAME,path,"/") split(path[np],classname,".") if (constr[1] != classname[1]) { sawprivate=1 } } } $0 ~ /^[ ]*\/\/*[ ]*[Ii]nner.*[Cc]lass/ { # If we see an inner class comment, then # we basically ignore any out of order methods # after the comment. sawinner=1 }' $file # Check that certain keywords exist words="@version @author Copyright Regents" for word in $words do egrep -s $word $file > /dev/null retval=$? if [ $retval != 0 ]; then echo "$file does not contain $word" fi done # Look for @version: or @author: $awk '$0 ~ /@author:/ { print FILENAME": Remove trailing : from @author:" print $0 } $0 ~ /@version:/ { print FILENAME": Remove trailing : from @version:" print $0 } $0 ~/@contributor/ { print FILENAME": @contributor produces warnings under JDK1.4, instead, merge with @author so that the line looks like @author foo, bar, Contributor: bif" print $0 } $0 ~/@returns/ { print FILENAME": Remove trailing s from @returns" print $0 }' $file # Check that all commas have spaces # A line that contains ", is ok # A line that contains , is ok results=`sed 's/\r//' $file | egrep '[^"],[^v" ]' | grep -v ',[]'` if [ "x$results" != "x" ]; then echo "$file: comma without out trailing space:" echo "$results" fi # Check for FIXME results=`egrep 'FIXME' $file` if [ "x$results" != "x" ]; then echo "$file: contains a FIXME" echo "$results" fi # Check for lines with trailing spaces results=`egrep '[ ]+$' $file` if [ "x$results" != "x" ]; then echo "$file: contains trailing spaces or trailing tabs, run rmtrailingspace to fix this" echo "$results" fi # Check for lines with tabs results=`egrep '[ ]' $file` if [ "x$results" != "x" ]; then echo "$file: contains tabs, run rmtabs to fix this" echo "$results" fi # Check for problems with equals signs results=`egrep '[^-|*/ ><+&=\!]=' $file | \ egrep -iv 'HREF=|NAME=|=WxH|"="|=\\\"' ` if [ "x$results" != "x" ]; then echo "$file: contains an equal sign without a leading space" echo "$results" fi # Check for problems with equals signs # Note that we ignore =\", which is used in moml results=`egrep '=[^ =\\]' $file | \ egrep -iv 'HREF=|NAME=|=WxH|"="' ` if [ "x$results" != "x" ]; then echo "$file: contains an equal sign without a trailing space" echo "$results" fi # Check the rating results=`egrep '@(Pt.)*AcceptedRating' $file` if [ "x$results" != "x" ]; then rating=`echo $results | $awk '{print $2}' ` if [ "$rating" != "Green" ]; then echo "$file: does not have an AcceptedRating of Green" echo "$results" fi else echo "$file: does not have an @AcceptedRating or @Pt.AcceptedRating doc tag" fi results=`egrep '(public|private|protected) .* .*\(' $file | egrep ' \(|\( ' | grep -v ') throws' ` if [ "x$results" != "x" ]; then echo "$file: has extra spaces around '(' in decl (should be foo(int a)" echo "$results" fi results=`egrep '(public|private|protected) .* .*\(' $file | egrep '\){'` if [ "x$results" != "x" ]; then echo "$file: needs space between ')' and '{' in decl" echo "$results" fi # 11) Check for %W% %G%, which are from SCCS results=`egrep '%W%|%G%' $file` if [ "x$results" != "x" ]; then echo "$file: has old SCCS keywords: %W% or %G%" echo "$results" fi # 12) Check for // System.out.println results=`egrep '//' $file | grep System.out.println` if [ "x$results" != "x" ]; then echo "$file: has commented out println statements" echo "$results" fi # 13) Check for @exception tags that are not worded properly # Added a . to this regex so that we find things like # @exception java.util.NoSuchElementException If the enumeration is results=`egrep '@exception' $file | egrep -v '@exception [A-Za-z0-9.]* If' | grep -v 'Not thrown in this base class' | grep -v 'Always thrown' | grep -v "Thrown in derived classes if"` if [ "x$results" != "x" ]; then echo "$file: @exception tags should either be" echo " '@exception MyException If such and such occurs'" echo " or '@exception MyException Not thrown in this base class'" echo " or '@exception MyException Always thrown'" echo " or '@exception MyException Thrown in derived classes if'" echo "$results" fi # 13) Check for @exception results=`egrep '@throw' $file` if [ "x$results" != "x" ]; then echo "$file: contains @throw[s]. Use @exception instead." echo "$results" fi # 15) Make sure that Parameters names do not start with capital letters results=`egrep 'public Parameter [A-Z]' $file` if [ "x$results" != "x" ]; then echo "$file: contains a Parameter name that starts with a capital letter." echo "$results" fi # 16) Warn about catching CloneNotSupported results=`egrep 'catch .*CloneNotSupported' $file` if [ "x$results" != "x" ]; then echo "$file: catches CloneNotSupported, which is likely a mistake" echo "$results" fi # 17) Warn about import ..*; results=`egrep '^import .*\*;' $file | grep -v "import ptolemy.kernel.util.*;"` if [ "x$results" != "x" ]; then echo "$file: import ...*; should import each class individually" echo "$results" fi # 18) Warn if the clone method copies port or parameters results=`egrep 'Object clone\(W' $file` if [ "x$results" != "x" ]; then $awk '{ if ($0 ~ /Object clone/) { clonedecl=NR } else { if ($0 ~ /getPort/ || $0 ~ /getAttribute/) { if (NR - clonedecl < 20) { print FILENAME ": clone?" print " This class has a clone method that calls either getPort or getAttribute." print " If this class extends TypedAtomicActor, then consider removing the getPort" print " and getAttribute lines in this clone method," print" TypedAtomicActor does that for you." exit } } } }' $file fi # 19) Warn if there is no trailing newline results=`tail -1 $file | od -bv | tail -2 |head -1 | grep '012[ ]*$'` if [ "x$results" = "x" ]; then echo "$file: does not have a trailing newline" fi # 20) Warn if the class comment has * on each line. # Commented out because Eclipse 3.1 inserts * on each line #results=`egrep '^[ ]\*' $file | egrep -v ':[ ]\*/'` #if [ "x$results" != "x" ]; then # echo "$file: may have leading * on each line in the class comment" # echo "$results" #fi #21) Warn if printStackTrace() or fillInStackTrace() are used results=`egrep 'printStackTrace\(\)|fillInStackTrace\(\)' $file` if [ "x$results" != "x" ]; then echo "$file: calls printStackTrace() or fillInStackTrace(), use KernelException.stackTraceToString(ex) instead." echo "$results" fi # 22) Warn if setTypeAtLeast is present, but clone is not defined results=`egrep '\.setTypeAtLeast\(' $file` if [ "x$results" != "x" ]; then results2=`egrep 'Object clone\(W' $file` if [ "x$results2" = "x" ]; then echo "$file: calls setTypeAtLeast, but does not define clone()" echo "$results" fi fi # 23) Check that the methods are alphabetical # This is important because the javadoc output follows # the order of the methods in the file. accesses="public protected private" for access in $accesses do # Once we see the string 'inner class' we stop checking awk '{print $0; if ($0 ~ /inner class/) { exit}}' $file | egrep "^ $access" | grep -v = | grep '[a-zA-Z](' | sed 's/.* \([_A-Za-z0-9]*(\).*/\1/' > /tmp/chkjava.a awk '{print $0; if ($0 ~ /inner class/) { exit}}' $file | egrep "^ $access" | grep -v = | grep '[a-zA-Z](' | sed 's/.* \([_A-Za-z0-9]*(\).*/\1/' | sort > /tmp/chkjava.b diff /tmp/chkjava.a /tmp/chkjava.b > /dev/null retval=$? if [ $retval != 0 ]; then echo "$file: $access methods are not in alphabetical order" echo "methods are:" cat /tmp/chkjava.a echo "methods should be:" diff /tmp/chkjava.a /tmp/chkjava.b fi done done