added new check EmptyForInitializerPad and changed logic in NoWhiteSpaceBefore and ParenPad to fix bug #895072

This commit is contained in:
Lars Kühne 2004-02-15 11:31:32 +00:00
parent 0b2ea87e30
commit da2328d0f1
11 changed files with 285 additions and 4 deletions

View File

@ -22,6 +22,9 @@
<!--Left menu-->
<td class="menu" valign="top">
<ul>
<li>
<a href="#EmptyForInitializerPad">EmptyForInitializerPad</a>
</li>
<li>
<a href="#EmptyForIteratorPad">EmptyForIteratorPad</a>
</li>
@ -57,6 +60,59 @@
<!--Content-->
<td class="content" valign="top" align="left">
<a name="EmptyForInitializerPad"></a> <h2>EmptyForInitializerPad</h2> <h4>Description</h4>
<p class="body">
Checks the padding of an empty for initializer; that is whether white
space is required at an empty for initializer, or such white space is
forbidden.
No check occurs if there is a line wrap at the initializer, as in
</p>
<pre class="body">
for (
; i < j; i++, j--)
</pre>
<h4>Properties</h4>
<table width="100%" border="1" cellpadding="5" class="body">
<tr class="header">
<th>name</th>
<th>description</th>
<th>type</th>
<th>default value</th>
</tr>
<tr>
<td>option</td>
<td>policy on how to pad an empty for iterator</td>
<td><a href="property_types.html#parenPad">pad policy</a></td>
<td><span class="default">nospace</span></td>
</tr>
</table>
<h4>Examples</h4>
<p class="body">
To configure the check:
</p>
<pre class="body">
&lt;module name=&quot;EmptyForInitializerPad&quot;/&gt;
</pre>
<p class="body">
To configure the check to require white space at an empty for iterator:
</p>
<pre class="body">
&lt;module name=&quot;EmptyForInitializerPad&quot;&gt;
&lt;property name=&quot;option&quot; value=&quot;space&quot;/&gt;
&lt;/module&gt;
</pre>
<h4>Package</h4>
<p class="body">
com.puppycrawl.tools.checkstyle.checks.whitespace
</p>
<h4>Parent Module</h4>
<p class="body">
<a href="config.html#treewalker">TreeWalker</a>
</p>
<a name="EmptyForIteratorPad"></a> <h2>EmptyForIteratorPad</h2> <h4>Description</h4>
<p class="body">
@ -68,7 +124,7 @@
<pre class="body">
for (Iterator foo = very.long.line.iterator();
foo.hasNext();
)
)
</pre>
<h4>Properties</h4>
<table width="100%" border="1" cellpadding="5" class="body">

View File

@ -120,10 +120,13 @@
(request 885993).</li>
<li class="body">Added check to forbid endline
comments. (module TrailingComment, reuest 744970)</li>
comments. (module TrailingComment, request 744970)</li>
<li class="body">Added applyTo(Public|Protected|Package|Private)
properties to check MemberName(request 695935)</li>
properties to check MemberName. (request 695935)</li>
<li class="body">Added check to verify padding in empty for loop initializers.
(module EmptyForInitializerPad, part of fix for bug 895072)</li>
</ul>
@ -161,6 +164,10 @@
<li class="body">Cast causes MagicNumberCheck error.
(bug 890706)</li>
<li class="body">Conflict between ParenPad and
NoWhiteSpaceBefore when code uses empty for loop initializers. (bug 895072)
</li>
</ul>
<p class="body">
@ -170,6 +177,16 @@
<li class="body">Removed ignoreLines property of
RegexpHeader check. To make some line optional use
&quot;^.*$&quot; regexp for this line.</li>
<li class="body">Fixing bug 895072 required changing the logic of
the NoWhiteSpaceBefore and ParenPad checks.
When a for loop has an empty initializer
(like <span class="code">for (; i < j; i++)</span>)
both checks will not check whitespace between the opening parenthesis
and the first semicolon any more.
To enforce your coding rules for such code, you have to use
the EmptyForInitializerPad check (not available yet).</li>
</ul>
<a name="release3_3"></a>

View File

@ -0,0 +1,94 @@
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2004 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.checks.whitespace;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.api.Utils;
import com.puppycrawl.tools.checkstyle.checks.AbstractOptionCheck;
import com.puppycrawl.tools.checkstyle.checks.AbstractOption;
/**
* <p>Checks the padding of an empty for initializer; that is whether a
* space is required at an empty for initializer, or such spaces are
* forbidden. No check occurs if there is a line wrap at the initializer, as in
* </p>
* <pre class="body">
for (
; i < j; i++, j--)
</pre>
* <p>
* The policy to verify is specified using the {@link PadOption} class and
* defaults to {@link PadOption#NOSPACE}.
* </p>
* <p>
* An example of how to configure the check is:
* </p>
* <pre>
* &lt;module name="EmptyForInitializerPad"/&gt;
* </pre>
* <p>
* @author lkuehne
* @version 1.0
*/
public class EmptyForInitializerPadCheck
extends AbstractOptionCheck
{
/**
* Sets the paren pad otion to nospace.
*/
public EmptyForInitializerPadCheck()
{
super(PadOption.NOSPACE);
}
/** @see com.puppycrawl.tools.checkstyle.api.Check */
public int[] getDefaultTokens()
{
return new int[] {TokenTypes.FOR_INIT,
};
}
/** @see com.puppycrawl.tools.checkstyle.api.Check */
public void visitToken(DetailAST aAST)
{
if (aAST.getChildCount() == 0) {
//empty for initializer. test pad before semi.
final DetailAST semi = (DetailAST) aAST.getNextSibling();
final int semiLineIdx = semi.getLineNo() - 1;
final String line = getLines()[semiLineIdx];
final int before = semi.getColumnNo() - 1;
//don't check if semi at beginning of line
if (!Utils.whitespaceBefore(before, line)) {
final AbstractOption abstractOption = getAbstractOption();
if ((PadOption.NOSPACE == abstractOption)
&& (Character.isWhitespace(line.charAt(before))))
{
log(semi.getLineNo(), before, "ws.preceded", ";");
}
else if ((PadOption.SPACE == abstractOption)
&& !Character.isWhitespace(line.charAt(before)))
{
log(semi.getLineNo(), before, "ws.notPreceded", ";");
}
}
}
}
}

View File

@ -92,6 +92,18 @@ public class NoWhitespaceBeforeCheck
final int before = aAST.getColumnNo() - 1;
if ((before < 0) || Character.isWhitespace(line.charAt(before))) {
// empty FOR initializer?
if (aAST.getType() == TokenTypes.SEMI) {
final DetailAST sibling = aAST.getPreviousSibling();
if ((sibling != null)
&& (sibling.getType() == TokenTypes.FOR_INIT)
&& (sibling.getChildCount() == 0))
{
return;
}
}
boolean flag = !mAllowLineBreaks;
// verify all characters before '.' are whitespace
for (int i = 0; !flag && i < before; i++) {

View File

@ -82,7 +82,9 @@ public class ParenPadCheck
// Strange logic in this method to guard against checking RPAREN tokens
// that are associated with a TYPECAST token.
if (aAST.getType() != TokenTypes.RPAREN) {
processLeft(aAST);
if (!isPreceedsEmptyForInit(aAST)) {
processLeft(aAST);
}
}
else if ((aAST.getParent() == null)
|| (aAST.getParent().getType() != TokenTypes.TYPECAST))
@ -111,4 +113,23 @@ public class ParenPadCheck
}
return followsEmptyForIterator;
}
/**
* @param aAST the token to check
* @return whether a token preceeds an empty for initializer
*/
private boolean isPreceedsEmptyForInit(DetailAST aAST)
{
boolean preceedsEmptyForInintializer = false;
final DetailAST parent = aAST.getParent();
if ((parent != null)
&& (parent.getType() == TokenTypes.LITERAL_FOR))
{
final DetailAST forIterator =
parent.findFirstToken(TokenTypes.FOR_INIT);
preceedsEmptyForInintializer = (forIterator.getChildCount() == 0)
&& (aAST == forIterator.getPreviousSibling());
}
return preceedsEmptyForInintializer;
}
}

View File

@ -34,4 +34,21 @@ class InputForWhitespace
i++;
}
}
void method2()
{
for ( int i = 0; i < 1; i++ ) {
}
for ( int i = 0; i < 1; ) {
i++;
}
int i = 0;
for ( ; i < 1; i++ ) {
}
for (; i < 2; i++ ) {
}
}
}

View File

@ -208,3 +208,26 @@ interface IFoo
void foo() ;
// ^ whitespace
}
/**
* Avoid Whitespace errors in for loop.
* @author lkuehne
* @version 1.0
*/
class SpecialCasesInForLoop
{
void forIterator()
{
// avoid conflict between WhiteSpaceAfter ';' and ParenPad(nospace)
for (int i = 0; i++ < 5;) {
// ^ no whitespace
}
// bug 895072
// avoid confilct between ParenPad(space) and NoWhiteSpace before ';'
int i = 0;
for ( ; i < 5; i++ ) {
// ^ whitespace
}
}
}

View File

@ -13,6 +13,7 @@ public class AllTests {
TestSuite suite =
new TestSuite("Test for com.puppycrawl.tools.checkstyle.checks.whitespace");
suite.addTest(new TestSuite(EmptyForInitializerPadCheckTest.class));
suite.addTest(new TestSuite(EmptyForIteratorPadCheckTest.class));
suite.addTest(new TestSuite(MethodParamPadCheckTest.class));
suite.addTest(new TestSuite(NoWhitespaceAfterCheckTest.class));

View File

@ -0,0 +1,32 @@
package com.puppycrawl.tools.checkstyle.checks.whitespace;
import com.puppycrawl.tools.checkstyle.BaseCheckTestCase;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
public class EmptyForInitializerPadCheckTest
extends BaseCheckTestCase
{
private DefaultConfiguration mCheckConfig;
public void setUp()
{
mCheckConfig = createCheckConfig(EmptyForInitializerPadCheck.class);
}
public void testDefault() throws Exception
{
final String[] expected = {
"48:14: ';' is preceded with whitespace.",
};
verify(mCheckConfig, getPath("InputForWhitespace.java"), expected);
}
public void testSpaceOption() throws Exception
{
mCheckConfig.addAttribute("option", PadOption.SPACE.toString());
final String[] expected = {
"51:13: ';' is not preceded with whitespace.",
};
verify(mCheckConfig, getPath("InputForWhitespace.java"), expected);
}
}

View File

@ -17,6 +17,7 @@ public class EmptyForIteratorPadCheckTest
{
final String[] expected = {
"27:31: ';' is followed by whitespace.",
"43:32: ';' is followed by whitespace.",
};
verify(mCheckConfig, getPath("InputForWhitespace.java"), expected);
}

View File

@ -16,6 +16,7 @@ public class ParenPadCheckTest
"58:36: ')' is preceded with whitespace.",
"74:13: '(' is followed by whitespace.",
"74:18: ')' is preceded with whitespace.",
"229:27: ')' is preceded with whitespace.",
};
verify(checkConfig, getPath("InputWhitespace.java"), expected);
}
@ -49,6 +50,7 @@ public class ParenPadCheckTest
"165:10: ')' is not preceded with whitespace.",
"178:14: '(' is not followed by whitespace.",
"178:36: ')' is not preceded with whitespace.",
"222:14: '(' is not followed by whitespace.",
};
verify(checkConfig, getPath("InputWhitespace.java"), expected);
}
@ -61,6 +63,11 @@ public class ParenPadCheckTest
final String[] expected = {
"17:34: ')' is preceded with whitespace.",
"20:35: ')' is preceded with whitespace.",
"40:14: '(' is followed by whitespace.",
"40:36: ')' is preceded with whitespace.",
"43:14: '(' is followed by whitespace.",
"48:27: ')' is preceded with whitespace.",
"51:26: ')' is preceded with whitespace.",
};
verify(checkConfig, getPath("InputForWhitespace.java"), expected);
}