Skip to content

Commit

Permalink
skipEnhancedForLoopVariable property is added in ModifiedControlVaria…
Browse files Browse the repository at this point in the history
…bleCheck. solves #1015
  • Loading branch information
Bhavik3 authored and romani committed Jun 23, 2015
1 parent 52a0d10 commit d80e678
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
* Examples:
* <p>
* <pre>
* &lt;module name=&quot;ModifiedControlVariableCheck&quot;&gt;
* &lt;module name=&quot;ModifiedControlVariable&quot;&gt;
* &lt;/module&gt;
* </pre>
* </p>
Expand All @@ -67,6 +67,33 @@
* </code>
* </pre>
* </p>
* <p>
* By default, This Check validates
* <a href = "http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2">
* Enhanced For-Loop</a>.
* </p>
* <p>
* Option 'skipEnhancedForLoopVariable' could be used to skip check of variable
* from Enhanced For Loop.
* </p>
* <p>
* An example of how to configure the check so that it skips enhanced For Loop Variable is:
* </p>
* <pre>
* &lt;module name="ModifiedControlVariable"&gt;
* &lt;property name="skipEnhancedForLoopVariable" value="true"/&gt;
* &lt;/module&gt;
* </pre>
* <p>Example:</p>
* <p>
* <pre>
* <code>
* for (String line: lines) {
* line = line.trim(); // it will skip this violation
* }
* </code>
* </pre>
* </p>
*
* @author Daniel Grenner
* @author <a href="mailto:piotr.listkiewicz@gmail.com">liscju</a>
Expand All @@ -92,35 +119,25 @@ public final class ModifiedControlVariableCheck extends Check {
/** Stack of block parameters. */
private final Deque<Deque<String>> variableStack = new ArrayDeque<>();

/** Controls whether to skip enhanced for-loop variable. */
private boolean skipEnhancedForLoopVariable;

/**
* Whether to skip enhanced for-loop variable or not.
* @param skipEnhancedForLoopVariable whether to skip enhanced for-loop variable
*/
public void setSkipEnhancedForLoopVariable(boolean skipEnhancedForLoopVariable) {
this.skipEnhancedForLoopVariable = skipEnhancedForLoopVariable;
}

@Override
public int[] getDefaultTokens() {
return new int[] {
TokenTypes.OBJBLOCK,
TokenTypes.LITERAL_FOR,
TokenTypes.FOR_ITERATOR,
TokenTypes.FOR_EACH_CLAUSE,
TokenTypes.ASSIGN,
TokenTypes.PLUS_ASSIGN,
TokenTypes.MINUS_ASSIGN,
TokenTypes.STAR_ASSIGN,
TokenTypes.DIV_ASSIGN,
TokenTypes.MOD_ASSIGN,
TokenTypes.SR_ASSIGN,
TokenTypes.BSR_ASSIGN,
TokenTypes.SL_ASSIGN,
TokenTypes.BAND_ASSIGN,
TokenTypes.BXOR_ASSIGN,
TokenTypes.BOR_ASSIGN,
TokenTypes.INC,
TokenTypes.POST_INC,
TokenTypes.DEC,
TokenTypes.POST_DEC,
};
return getAcceptableTokens();
}

@Override
public int[] getRequiredTokens() {
return getDefaultTokens();
return getAcceptableTokens();
}

@Override
Expand Down Expand Up @@ -190,18 +207,23 @@ public void visitToken(DetailAST ast) {
}
}


@Override
public void leaveToken(DetailAST ast) {
switch (ast.getType()) {
case TokenTypes.FOR_ITERATOR:
leaveForIter(ast.getParent());
break;
case TokenTypes.FOR_EACH_CLAUSE:
leaveForEach(ast);
final DetailAST paramDef =
ast.findFirstToken(TokenTypes.VARIABLE_DEF);
if (shouldCheckEnhancedForLoopVariable(paramDef)) {
leaveForEach(paramDef);
}
break;
case TokenTypes.LITERAL_FOR:
leaveForDef(ast);
if (!getCurrentVariables().isEmpty()) {
leaveForDef(ast);
}
break;
case TokenTypes.OBJBLOCK:
exitBlock();
Expand Down Expand Up @@ -291,13 +313,21 @@ private Set<String> getVariablesManagedByForLoop(DetailAST ast) {
return Sets.intersection(initializedVariables, iteratingVariables);
}

/**
* Determines whether enhanced for-loop variable should be checked or not.
* @param ast The ast to compare.
* @return true if enhanced for-loop variable should be checked.
*/
private boolean shouldCheckEnhancedForLoopVariable(DetailAST ast) {
return !skipEnhancedForLoopVariable
|| ast.getParent().getType() != TokenTypes.FOR_EACH_CLAUSE;
}

/**
* Push current variables to the stack.
* @param forEach a for-each clause
* @param paramDef a for-each clause variable
*/
private void leaveForEach(DetailAST forEach) {
final DetailAST paramDef =
forEach.findFirstToken(TokenTypes.VARIABLE_DEF);
private void leaveForEach(DetailAST paramDef) {
final DetailAST paramName = paramDef.findFirstToken(TokenTypes.IDENT);
getCurrentVariables().push(paramName.getText());
}
Expand All @@ -311,7 +341,6 @@ private void leaveForDef(DetailAST ast) {
if (forInitAST != null) {
final Set<String> variablesManagedByForLoop = getVariablesManagedByForLoop(ast);
popCurrentVariables(variablesManagedByForLoop.size());

}
else {
// this is for-each loop, just pop veriables
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,25 @@ public void testModifiedControlVariable() throws Exception {
verify(checkConfig, getPath("coding/InputModifiedControl.java"), expected);
}

@Test
public void testEnhancedForLoopVariableTrue() throws Exception {
final DefaultConfiguration checkConfig =
createCheckConfig(ModifiedControlVariableCheck.class);
checkConfig.addAttribute("skipEnhancedForLoopVariable", "true");

final String[] expected = {
};
verify(checkConfig, getPath("coding/InputModifiedControlVariableEnhancedForLoopVariable.java"), expected);
}

@Test
public void testEnhancedForLoopVariableFalse() throws Exception {
final DefaultConfiguration checkConfig =
createCheckConfig(ModifiedControlVariableCheck.class);

final String[] expected = {
"9:18: " + getCheckMessage(MSG_KEY, "line"),
};
verify(checkConfig, getPath("coding/InputModifiedControlVariableEnhancedForLoopVariable.java"), expected);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.puppycrawl.tools.checkstyle.coding;

public class InputModifiedControlVariableEnhancedForLoopVariable {

public void method2()
{
final String[] lines = {"line1", "line2", "line3"};
for (String line: lines) {
line = line.trim();
}
}
}
51 changes: 51 additions & 0 deletions src/xdocs/config_coding.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1114,13 +1114,64 @@ class MyClass {
</source>
</subsection>

<subsection name="Properties">
<table>
<tr class="header">
<th>name</th>
<th>description</th>
<th>type</th>
<th>default value</th>
</tr>

<tr>
<td>skipEnhancedForLoopVariable</td>
<td>Controls whether to check <a href = "http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2">enhanced for-loop</a> variable.</td>
<td>
<a
href="property_types.html#boolean">Boolean</a>
</td>
<td>
<code>
false
</code>
</td>
</tr>
</table>
</subsection>

<subsection name="Example">
<p>
To configure the check:
</p>
<source>
&lt;module name=&quot;ModifiedControlVariable&quot;/&gt;
</source>

<p>
By default, This Check validates
<a href = "http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2">
Enhanced For-Loop</a>.
</p>
<p>
Option 'skipEnhancedForLoopVariable' could be used to skip check of variable
from Enhanced For Loop.
</p>
<p>
An example of how to configure the check so that it skips enhanced For Loop Variable is:
</p>
<source>
&lt;module name="ModifiedControlVariable"&gt;
&lt;property name="skipEnhancedForLoopVariable" value="true"/&gt;
&lt;/module&gt;
</source>
<p>Example:</p>
<p>
<source>
for ( String line: lines ) {
line = line.trim(); // it will skip this violation
}
</source>
</p>
</subsection>

<subsection name="Package">
Expand Down

0 comments on commit d80e678

Please sign in to comment.