diff --git a/build.xml b/build.xml index 895468b47..15e73a5c0 100644 --- a/build.xml +++ b/build.xml @@ -161,7 +161,8 @@ paramPattern="^a[A-Z][a-zA-Z0-9]*$" lcurlyMethod="nl" lcurlyOther="nlow" - lcurlyType="nl"> + lcurlyType="nl" + rcurly="alone"> diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java index d8a1eff6d..5e1f7a2ea 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/CheckStyleTask.java @@ -306,24 +306,30 @@ public class CheckStyleTask mConfig.setCacheFile(aCacheFile.getAbsolutePath()); } - /** @param aTo the lefy curly placement option for methods **/ + /** @param aTo the left curly placement option for methods **/ public void setLCurlyMethod(String aTo) { mConfig.setLCurlyMethod(extractLeftCurlyOption(aTo)); } - /** @param aTo the lefy curly placement option for types **/ + /** @param aTo the left curly placement option for types **/ public void setLCurlyType(String aTo) { mConfig.setLCurlyType(extractLeftCurlyOption(aTo)); } - /** @param aTo the lefy curly placement option for others **/ + /** @param aTo the left curly placement option for others **/ public void setLCurlyOther(String aTo) { mConfig.setLCurlyOther(extractLeftCurlyOption(aTo)); } + /** @param aTo the right curly placement option **/ + public void setRCurly(String aTo) + { + mConfig.setRCurly(extractRightCurlyOption(aTo)); + } + //////////////////////////////////////////////////////////////////////////// // The doers //////////////////////////////////////////////////////////////////////////// @@ -545,4 +551,20 @@ public class CheckStyleTask } return opt; } + + /** + * @param aFrom String to decode the option from + * @return the RightCurlyOption represented by aFrom + * @throws BuildException if unable to decode aFrom + */ + private RightCurlyOption extractRightCurlyOption(String aFrom) + throws BuildException + { + final RightCurlyOption opt = RightCurlyOption.decode(aFrom); + if (opt == null) { + throw new BuildException("Unable to parse '" + aFrom + "'.", + location); + } + return opt; + } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Configuration.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Configuration.java index b98bd7c4c..1a2244f01 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Configuration.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Configuration.java @@ -156,6 +156,8 @@ public class Configuration private LeftCurlyOption mLCurlyType = LeftCurlyOption.EOL; /** where to place left curlies on others **/ private LeftCurlyOption mLCurlyOther = LeftCurlyOption.EOL; + /** where to place right curlies **/ + private RightCurlyOption mRCurly = RightCurlyOption.SAME; //////////////////////////////////////////////////////////////////////////// // Constructors @@ -243,6 +245,8 @@ public class Configuration setLCurlyOther(getLeftCurlyOptionProperty( aProps, LCURLY_OTHER_PROP, LeftCurlyOption.EOL, aLog)); + setRCurly(getRightCurlyOptionProperty( + aProps, RCURLY_PROP, RightCurlyOption.SAME, aLog)); } /** @@ -817,6 +821,18 @@ public class Configuration mLCurlyOther = aTo; } + /** @return the right curly placement option **/ + public RightCurlyOption getRCurly() + { + return mRCurly; + } + + /** @param aTo set the right curly placement option **/ + public void setRCurly(RightCurlyOption aTo) + { + mRCurly = aTo; + } + //////////////////////////////////////////////////////////////////////////// // Private methods @@ -897,4 +913,32 @@ 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 RightCurlyOption property. If the property is not + * defined or cannot be decoded, then a default value is returned. + */ + private static RightCurlyOption getRightCurlyOptionProperty( + Properties aProps, + String aName, + RightCurlyOption aDefault, + PrintStream aLog) + { + RightCurlyOption retVal = aDefault; + final String strRep = aProps.getProperty(aName); + if (strRep != null) { + retVal = RightCurlyOption.decode(strRep); + if (retVal == null) { + aLog.println("Unable to parse " + aName + + " property with value " + strRep + + ", defaulting to " + aDefault + "."); + } + } + return retVal; + } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java index f76e3a983..fb0a3b998 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Defn.java @@ -85,4 +85,6 @@ public interface Defn String LCURLY_TYPE_PROP = "checkstyle.lcurly.type"; /** property name for lcurly placement for others **/ String LCURLY_OTHER_PROP = "checkstyle.lcurly.other"; + /** property name for rcurly placement **/ + String RCURLY_PROP = "checkstyle.rcurly"; } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/RightCurlyOption.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/RightCurlyOption.java new file mode 100644 index 000000000..2280e0646 --- /dev/null +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/RightCurlyOption.java @@ -0,0 +1,73 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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.util.Map; +import java.util.HashMap; + +/** + * Represents the options for placing the right curly brace '}'. + * + * @author Oliver Burn + * @version 1.0 + */ +public final class RightCurlyOption +{ + /** maps from a string representation to an option **/ + private static final Map STR_TO_OPT = new HashMap(); + + /** represents placing the brace alone on a line **/ + public static final RightCurlyOption ALONE = new RightCurlyOption("alone"); + /** represents placing the brace on the same line **/ + public static final RightCurlyOption SAME = new RightCurlyOption("same"); + /** represents ignoring the placement **/ + public static final RightCurlyOption IGNORE = + new RightCurlyOption("ignore"); + + /** the string representation of the option **/ + private final String mStrRep; + + /** + * Creates a new RightCurlyOption instance. + * @param aStrRep the string representation + */ + private RightCurlyOption(String aStrRep) + { + mStrRep = aStrRep.trim().toLowerCase(); + STR_TO_OPT.put(mStrRep, this); + } + + /** @see Object **/ + public String toString() + { + return mStrRep; + } + + /** + * Returns the RightCurlyOption specified by a string representation. If no + * option exists then null is returned. + * @param aStrRep the String representation to parse + * @return the RightCurlyOption value represented by aStrRep, + * or null if none exists. + */ + public static RightCurlyOption decode(String aStrRep) + { + return (RightCurlyOption) STR_TO_OPT.get(aStrRep.trim().toLowerCase()); + } +} diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java index 85164bd31..b230b6680 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Verifier.java @@ -605,6 +605,27 @@ class Verifier } + /** + * Verify the correct placement of the right curly brace. + * @param aBrace location of the brace + * @param aStartLine line the next statement starts on + */ + void verifyRCurly(MyCommonAST aBrace, int aStartLine) + { + final RightCurlyOption option = mConfig.getRCurly(); + if ((mConfig.getRCurly() == RightCurlyOption.SAME) + && (aBrace.getLineNo() != aStartLine)) + { + log(aBrace.getLineNo(), "'}' should be on the same line."); + } + else if ((mConfig.getRCurly() == RightCurlyOption.ALONE) + && (aBrace.getLineNo() == aStartLine)) + { + log(aBrace.getLineNo(), "'}' should be alone on a line."); + } + } + + /** * Verify that a constructor length is ok. * @param aLineNo line the constructor block starts at diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/java.g b/src/checkstyle/com/puppycrawl/tools/checkstyle/java.g index abd8e6754..712e055ba 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/java.g +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/java.g @@ -582,7 +582,14 @@ statement[int[] aType, MyCommonAST[] aCurlies] warnWhenFollowAmbig = false; } : - ee:"else"! {stmtType[0] = STMT_OTHER; } statement[stmtType, stmtBraces] + ee:"else"! + { + if (stmtType[0] == STMT_COMPOUND) { + ver.verifyRCurly(stmtBraces[1], ee.getLine()); + } + stmtType[0] = STMT_OTHER; + } + statement[stmtType, stmtBraces] { ver.verifyWSAroundBegin(ee.getLine(), ee.getColumn(), ee.getText()); if (stmtType[0] == STMT_OTHER) { @@ -723,33 +730,32 @@ forIter tryBlock { final MyCommonAST[] stmtBraces = new MyCommonAST[2]; + final MethodSignature ignoreMS = new MethodSignature(); } : t:"try"^ compoundStatement[stmtBraces] { ver.verifyWSAroundBegin(t.getLine(), t.getColumn(), t.getText()); ver.verifyLCurlyOther(t.getLine(), stmtBraces[0]); } - (handler)* - ( - f:"finally"^ compoundStatement[stmtBraces] + + ( + c:"catch"^ { ver.verifyRCurly(stmtBraces[1], c.getLine()); } + LPAREN! parameterDeclaration[ignoreMS] RPAREN! compoundStatement[stmtBraces] + { + ver.verifyWSAroundBegin( + c.getLine(), c.getColumn(), c.getText()); + ver.verifyLCurlyOther(c.getLine(), stmtBraces[0]); + } + )* + + ( + f:"finally"^ { ver.verifyRCurly(stmtBraces[1], f.getLine()); } + compoundStatement[stmtBraces] { ver.verifyLCurlyOther(f.getLine(), stmtBraces[0]); } )? ; -// an exception handler -handler -{ - final MyCommonAST[] stmtBraces = new MyCommonAST[2]; -} - : c:"catch"^ LPAREN! parameterDeclaration[new MethodSignature()] RPAREN! compoundStatement[stmtBraces] - { - ver.verifyWSAroundBegin(c.getLine(), c.getColumn(), c.getText()); - ver.verifyLCurlyOther(c.getLine(), stmtBraces[0]); - } - ; - - // expressions // Note that most of these expressions follow the pattern // thisLevelExpression : diff --git a/src/tests/com/puppycrawl/tools/checkstyle/CheckerTest.java b/src/tests/com/puppycrawl/tools/checkstyle/CheckerTest.java index 5c9b1e68e..135d43a1b 100644 --- a/src/tests/com/puppycrawl/tools/checkstyle/CheckerTest.java +++ b/src/tests/com/puppycrawl/tools/checkstyle/CheckerTest.java @@ -45,6 +45,7 @@ public class CheckerTest mConfig.setLCurlyMethod(LeftCurlyOption.NL); mConfig.setLCurlyOther(LeftCurlyOption.NLOW); mConfig.setLCurlyType(LeftCurlyOption.NL); + mConfig.setRCurly(RightCurlyOption.ALONE); } protected String getPath(String aFilename) @@ -643,6 +644,7 @@ public class CheckerTest throws Exception { mConfig.setJavadocScope(Scope.NOTHING); + mConfig.setRCurly(RightCurlyOption.SAME); final Checker c = createChecker(); final String filepath = getPath("InputLeftCurlyOther.java"); assertNotNull(c); @@ -650,9 +652,13 @@ public class CheckerTest filepath + ":19: '{' should be on the previous line.", filepath + ":21: '{' should be on the previous line.", filepath + ":23: '{' should be on the previous line.", + filepath + ":25: '}' should be on the same line.", + filepath + ":28: '}' should be on the same line.", filepath + ":30: '{' should be on the previous line.", filepath + ":34: '{' should be on the previous line.", + filepath + ":40: '}' should be on the same line.", filepath + ":42: '{' should be on the previous line.", + filepath + ":44: '}' should be on the same line.", filepath + ":46: '{' should be on the previous line.", filepath + ":52: '{' should be on the previous line.", filepath + ":54: '{' should be on the previous line.",