diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/CatchBlockOption.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/CatchBlockOption.java new file mode 100644 index 000000000..42c654fad --- /dev/null +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/CatchBlockOption.java @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2002 Oliver Burn +// +// 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, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// +package com.puppycrawl.tools.checkstyle; + +import java.io.Serializable; +import java.io.ObjectStreamException; +import java.util.Map; +import java.util.HashMap; + +/** + * Represents the options for a catch block. + * + * @author Oliver Burn + */ +public final class CatchBlockOption implements Serializable +{ + /** maps from a string representation to an option **/ + private static final Map STR_TO_OPT = new HashMap(); + + /** represents ignoring catch blocks **/ + public static final CatchBlockOption IGNORE = + new CatchBlockOption("ignore"); + /** represents requiring some text in the catch block **/ + public static final CatchBlockOption TEXT = new CatchBlockOption("text"); + /** represents requiring a statement in the catch block **/ + public static final CatchBlockOption STMT = new CatchBlockOption("stmt"); + + /** the string representation of the option **/ + private final String mStrRep; + + /** + * Creates a new CatchBlockOption instance. + * @param aStrRep the string representation + */ + private CatchBlockOption(String aStrRep) + { + mStrRep = aStrRep.trim().toLowerCase(); + STR_TO_OPT.put(mStrRep, this); + } + + /** @see Object **/ + public String toString() + { + return mStrRep; + } + + /** + * Returns the CatchBlockOption specified by a string representation. If no + * option exists then null is returned. + * @param aStrRep the String representation to parse + * @return the CatchBlockOption value represented by aStrRep, + * or null if none exists. + */ + public static CatchBlockOption decode(String aStrRep) + { + return (CatchBlockOption) STR_TO_OPT.get(aStrRep.trim().toLowerCase()); + } + + /** + * Ensures that we don't get multiple instances of one CatchBlockOption + * during deserialization. See Section 3.6 of the Java Object + * Serialization Specification for details. + * + * @return the serialization replacement object + * @throws ObjectStreamException if a deserialization error occurs + */ + private Object readResolve() throws ObjectStreamException + { + return decode(mStrRep); + } +} diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java index 7345731d5..7a7123bde 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java @@ -645,6 +645,18 @@ public class CheckStyleTask }); } + /** @param aTo the catch block option **/ + public void setCatchBlock(final String aTo) + { + mOptionMemory.add(new Runnable() + { + public void run() + { + mConfig.setCatchBlock(extractCatchBlockOption(aTo)); + } + }); + } + /** @param aTo the parenthesis padding option **/ public void setParenPad(final String aTo) { @@ -657,18 +669,6 @@ public class CheckStyleTask }); } - /** @param aAllowed whether empty catch blocks are allowed **/ - public void setAllowEmptyCatch(final boolean aAllowed) - { - mOptionMemory.add(new Runnable() - { - public void run() - { - mConfig.setAllowEmptyCatch(aAllowed); - } - }); - } - //////////////////////////////////////////////////////////////////////////// // The doers //////////////////////////////////////////////////////////////////////////// @@ -914,6 +914,22 @@ public class CheckStyleTask return opt; } + /** + * @param aFrom String to decode the option from + * @return the CatchBlockOption represented by aFrom + * @throws BuildException if unable to decode aFrom + */ + private CatchBlockOption extractCatchBlockOption(String aFrom) + throws BuildException + { + final CatchBlockOption opt = CatchBlockOption.decode(aFrom); + if (opt == null) { + throw new BuildException("Unable to parse '" + aFrom + "'.", + location); + } + return opt; + } + /** * @param aFrom String to decode the option from * @return the PadOption represented by aFrom diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Configuration.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Configuration.java index c8682f127..a2e6cbd3a 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Configuration.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Configuration.java @@ -186,13 +186,12 @@ public class Configuration private LeftCurlyOption mLCurlyOther = LeftCurlyOption.EOL; /** where to place right curlies **/ private RightCurlyOption mRCurly = RightCurlyOption.SAME; + /** how to process catch blocks **/ + private CatchBlockOption mCatchBlock = CatchBlockOption.TEXT; /** how to pad parenthesis **/ private PadOption mParenPadOption = PadOption.NOSPACE; - /** whether to allow emtpy exception handlers **/ - private boolean mAllowEmptyCatch = false; - //////////////////////////////////////////////////////////////////////////// // Constructors //////////////////////////////////////////////////////////////////////////// @@ -285,12 +284,13 @@ public class Configuration LeftCurlyOption.EOL, aLog)); setRCurly(getRightCurlyOptionProperty( aProps, RCURLY_PROP, RightCurlyOption.SAME, aLog)); + setCatchBlock( + getCatchBlockOptionProperty( + aProps, CATCH_BLOCK_PROP, CatchBlockOption.TEXT, aLog)); setParenPadOption(getPadOptionProperty(aProps, PAREN_PAD_PROP, PadOption.NOSPACE, aLog)); - setAllowEmptyCatch(getBooleanProperty( - aProps, ALLOW_EMPTY_CATCH_PROP, mAllowEmptyCatch)); } /** @@ -1005,6 +1005,18 @@ public class Configuration mRCurly = aTo; } + /** @return the catch block option **/ + public CatchBlockOption getCatchBlock() + { + return mCatchBlock; + } + + /** @param aTo set the catch block option **/ + public void setCatchBlock(CatchBlockOption aTo) + { + mCatchBlock = aTo; + } + /** @return the parenthesis padding option **/ public PadOption getParenPadOption() { @@ -1017,18 +1029,6 @@ public class Configuration mParenPadOption = aTo; } - /** @return whether empty catch blocks are allowed */ - public boolean isAllowEmptyCatch() - { - return mAllowEmptyCatch; - } - - /** @param aAllowEmptyCatch whether empty catch blocks are allowed */ - public void setAllowEmptyCatch(boolean aAllowEmptyCatch) - { - mAllowEmptyCatch = aAllowEmptyCatch; - } - //////////////////////////////////////////////////////////////////////////// // Private methods //////////////////////////////////////////////////////////////////////////// @@ -1137,6 +1137,34 @@ public class Configuration return retVal; } + /** + * @param aProps the properties set to use + * @param aLog where to log errors to + * @param aName the name of the property to parse + * @param aDefault the default value to use. + * + * @return the value of a CatchBlockOption property. If the property is not + * defined or cannot be decoded, then a default value is returned. + */ + private static CatchBlockOption getCatchBlockOptionProperty( + Properties aProps, + String aName, + CatchBlockOption aDefault, + PrintStream aLog) + { + CatchBlockOption retVal = aDefault; + final String strRep = aProps.getProperty(aName); + if (strRep != null) { + retVal = CatchBlockOption.decode(strRep); + if (retVal == null) { + aLog.println("Unable to parse " + aName + + " property with value " + strRep + + ", defaulting to " + aDefault + "."); + } + } + return retVal; + } + /** * @param aProps the properties set to use * @param aLog where to log errors to diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java index 4104581dc..fec00e480 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java @@ -101,6 +101,6 @@ public interface Defn /** property name for padding around parenthesis **/ String PAREN_PAD_PROP = "checkstyle.paren.pad"; - /** property name for allowing empty exception handlers **/ - String ALLOW_EMPTY_CATCH_PROP = "checkstyle.allow.empty.catch"; + /** property name for catch block options **/ + String CATCH_BLOCK_PROP = "checkstyle.catchblock"; } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java index 7ea29ab95..be5ba28bf 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java @@ -227,7 +227,7 @@ class Verifier { log(aSig.getName().getLineNo(), aSig.getName().getColumnNo(), - "method name '" + aSig.getName() + + "method name '" + aSig.getName().getText() + "' must match pattern '" + mConfig.getMethodPat() + "'."); } @@ -869,15 +869,59 @@ class Verifier } /** - * Report that the parser has found a (potentially empty) catch block. - * @param aLineNo the line number of the catch keyword - * @param aColNo the column number of the catch keyword - * @param aIsEmpty whether the block contains any statement + * Report that the parser has found a catch block. + * @param aBraces the start and end braces from the catch block + * @param aNoStmt whether there are any statements in the block */ - void reportCatchBlock(int aLineNo, int aColNo, boolean aIsEmpty) + void reportCatchBlock(MyCommonAST[] aBraces, boolean aNoStmt) { - if (aIsEmpty && !mConfig.isAllowEmptyCatch()) { - log(aLineNo, aColNo - 1, "Empty catch block."); + if (aNoStmt && (mConfig.getCatchBlock() == CatchBlockOption.STMT)) { + log(aBraces[0].getLineNo(), + aBraces[0].getColumnNo(), + "Must have at least one statement."); + } + else if (mConfig.getCatchBlock() == CatchBlockOption.TEXT) { + if (aBraces[0].getLineNo() == aBraces[1].getLineNo()) { + // Handle braces on the same line + final String txt = mLines[aBraces[0].getLineNo() - 1] + .substring(aBraces[0].getColumnNo() + 1, + aBraces[1].getColumnNo()); + if (txt.trim().length() == 0) { + log(aBraces[0].getLineNo(), + aBraces[0].getColumnNo(), + "Empty catch block."); + } + } + else { + // check only whitespace of first & last lines + if ((mLines[aBraces[0].getLineNo() - 1] + .substring(aBraces[0].getColumnNo() + 1).trim().length() + == 0) + && + (mLines[aBraces[1].getLineNo() - 1] + .substring(0, aBraces[1].getColumnNo()).trim().length() + == 0)) + { + + // Need to check if all lines are also only whitespace + boolean isBlank = true; + for (int i = aBraces[0].getLineNo(); + i < (aBraces[1].getLineNo() - 1); + i++) + { + if (mLines[i].trim().length() > 0) { + isBlank = false; + break; + } + } + + if (isBlank) { + log(aBraces[0].getLineNo(), + aBraces[0].getColumnNo(), + "Empty catch block."); + } + } + } } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/java.g b/src/checkstyle/com/puppycrawl/tools/checkstyle/java.g index 95ee7fb23..06905e731 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/java.g +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/java.g @@ -754,7 +754,7 @@ tryBlock { ver.verifyWSAroundBegin( c.getLine(), c.getColumn(), c.getText()); - ver.reportCatchBlock(c.getLine(), c.getColumn(), isEmpty[0]); + ver.reportCatchBlock(stmtBraces, isEmpty[0]); ver.verifyLCurlyOther(c.getLine(), stmtBraces[0]); } )*