Support for the CatchBlock option. The code is a bit ugly, but it works.

This commit is contained in:
Oliver Burn 2002-05-26 12:58:30 +00:00
parent 39a7271a2a
commit 615219883b
6 changed files with 215 additions and 40 deletions

View File

@ -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 <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
*/
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 <code>CatchBlockOption</code> 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 <code>CatchBlockOption</code> 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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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";
}

View File

@ -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.");
}
}
}
}
}

View File

@ -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]);
}
)*