VariableDeclarationUsageDistanceCheck was imported #223

This commit is contained in:
Max 2014-08-03 15:00:29 +04:00 committed by Roman Ivanov
parent a5031acb33
commit c4e886312a
6 changed files with 1870 additions and 0 deletions

View File

@ -0,0 +1,892 @@
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2014 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.coding;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import antlr.collections.ASTEnumeration;
import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.FullIdent;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
/**
* <p>
* Checks the distance between declaration of variable and its first usage.
* </p>
* Example #1:
* <pre>
* <code>int count;
* a = a + b;
* b = a + a;
* count = b; // DECLARATION OF VARIABLE 'count'
* // SHOULD BE HERE (distance = 3)</code>
* </pre>
* Example #2:
* <pre>
* <code>int count;
* {
* a = a + b;
* count = b; // DECLARATION OF VARIABLE 'count'
* // SHOULD BE HERE (distance = 2)
* }</code>
* </pre>
*
* <p>
* Check can detect a block of initialization methods. If a variable is used in
* such a block and there is no other statements after this variable then distance=1.
* </p>
* <p>
* <b>Case #1:</b>
* <pre>
* int <b>minutes</b> = 5;
* Calendar cal = Calendar.getInstance();
* cal.setTimeInMillis(timeNow);
* cal.set(Calendar.SECOND, 0);
* cal.set(Calendar.MILLISECOND, 0);
* cal.set(Calendar.HOUR_OF_DAY, hh);
* cal.set(Calendar.MINUTE, <b>minutes</b>);
*
* The distance for the variable <b>minutes</b> is 1 even
* though this variable is used in the fifth method's call.
* </pre>
* </p>
* <p>
* <b>Case #2:</b>
* <pre>
* int <b>minutes</b> = 5;
* Calendar cal = Calendar.getInstance();
* cal.setTimeInMillis(timeNow);
* cal.set(Calendar.SECOND, 0);
* cal.set(Calendar.MILLISECOND, 0);
* <i>System.out.println(cal);</i>
* cal.set(Calendar.HOUR_OF_DAY, hh);
* cal.set(Calendar.MINUTE, <b>minutes</b>);
*
* The distance for the variable <b>minutes</b> is 6 because there is one more expression
* (except the initialization block) between the declaration of this variable and its usage.
* </pre>
* </p>
*
* There are several additional options to configure the check:
* <pre>
* 1. allowedDistance - allows to set a distance
* between declaration of variable and its first usage.
* 2. ignoreVariablePattern - allows to set a RegEx pattern for
* ignoring the distance calculation for variables listed in this pattern.
* 3. validateBetweenScopes - allows to calculate the distance between
* declaration of variable and its first usage in the different scopes.
* 4. ignoreFinal - allows to ignore variables with a 'final' modifier.
* </pre>
* ATTENTION!! (Not supported cases)
* <pre>
* Case #1:
* <code>{
* int c;
* int a = 3;
* int b = 2;
* {
* a = a + b;
* c = b;
* }
* }</code>
*
* Distance for variable 'a' = 1;
* Distance for variable 'b' = 1;
* Distance for variable 'c' = 2.
* </pre>
* As distance by default is 1 the Check doesn't raise warning for variables 'a'
* and 'b' to move them into the block.
* <pre>
* Case #2:
* <code>int sum = 0;
* for (int i = 0; i < 20; i++) {
* a++;
* b--;
* sum++;
* if (sum > 10) {
* res = true;
* }
* }</code>
* Distance for variable 'sum' = 3.
* </pre>
* <p>
* As the distance is more then the default one, the Check raises warning for variable
* 'sum' to move it into the 'for(...)' block. But there is situation when
* variable 'sum' hasn't to be 0 within each iteration. So, to avoid such
* warnings you can use Suppression Filter, provided by Checkstyle, for the
* whole class.
* </p>
*
* <p>
* An example how to configure this Check:
* </p>
* <pre>
* &lt;module name="VariableDeclarationUsageDistance"/&gt;
* </pre>
* <p>
* An example of how to configure this Check:
* - to set the allowed distance to 4;
* - to ignore variables with prefix '^temp';
* - to force the validation between scopes;
* - to check the final variables;
* </p>
* <pre>
* &lt;module name="VariableDeclarationUsageDistance"&gt;
* &lt;property name="allowedDistance" value="4"&gt;
* &lt;property name="ignoreVariablePattern" value="^temp.*"&gt;
* &lt;property name="validateBetweenScopes" value="true"&gt;
* &lt;property name="mIgnoreFinal" value="false"&gt;
* &lt;/module&gt;
* </pre>
*
* @author <a href="mailto:rd.ryly@gmail.com">Ruslan Diachenko</a>
* @author <a href="mailto:barataliba@gmail.com">Baratali Izmailov</a>
*/
public class VariableDeclarationUsageDistanceCheck extends Check
{
/**
* Warning message key.
*/
public static final String MSG_KEY = "variable.declaration.usage.distance";
/**
* Default value of distance between declaration of variable and its first
* usage.
*/
private static final int DEFAULT_DISTANCE = 3;
/** Allowed distance between declaration of variable and its first usage. */
private int mAllowedDistance = DEFAULT_DISTANCE;
/**
* RegExp pattern to ignore distance calculation for variables listed in
* this pattern.
*/
private Pattern mIgnoreVariablePattern = Pattern.compile("");
/**
* Allows to calculate distance between declaration of variable and its
* first usage in different scopes.
*/
private boolean mValidateBetweenScopes;
/** Allows to ignore variables with 'final' modifier. */
private boolean mIgnoreFinal = true;
/**
* Sets an allowed distance between declaration of variable and its first
* usage.
* @param aAllowedDistance
* Allowed distance between declaration of variable and its first
* usage.
*/
public void setAllowedDistance(int aAllowedDistance)
{
this.mAllowedDistance = aAllowedDistance;
}
/**
* Sets RegExp pattern to ignore distance calculation for variables listed
* in this pattern.
* @param aIgnorePattern
* Pattern contains ignored variables.
*/
public void setIgnoreVariablePattern(String aIgnorePattern)
{
this.mIgnoreVariablePattern = Pattern.compile(aIgnorePattern);
}
/**
* Sets option which allows to calculate distance between declaration of
* variable and its first usage in different scopes.
* @param aValidateBetweenScopes
* Defines if allow to calculate distance between declaration of
* variable and its first usage in different scopes or not.
*/
public void setValidateBetweenScopes(boolean aValidateBetweenScopes)
{
this.mValidateBetweenScopes = aValidateBetweenScopes;
}
/**
* Sets ignore option for variables with 'final' modifier.
* @param aIgnoreFinal
* Defines if ignore variables with 'final' modifier or not.
*/
public void setIgnoreFinal(boolean aIgnoreFinal)
{
this.mIgnoreFinal = aIgnoreFinal;
}
@Override
public int[] getDefaultTokens()
{
return new int[] {TokenTypes.VARIABLE_DEF};
}
@Override
public void visitToken(DetailAST aAST)
{
final int parentType = aAST.getParent().getType();
final DetailAST modifiers = aAST.getFirstChild();
if ((mIgnoreFinal && modifiers.branchContains(TokenTypes.FINAL))
|| parentType == TokenTypes.OBJBLOCK)
{
;// no code
}
else {
final DetailAST variable = aAST.findFirstToken(TokenTypes.IDENT);
if (!isVariableMatchesIgnorePattern(variable.getText())) {
final DetailAST semicolonAst = aAST.getNextSibling();
Entry<DetailAST, Integer> entry = null;
if (mValidateBetweenScopes) {
entry = calculateDistanceBetweenScopes(semicolonAst, variable);
}
else {
entry = calculateDistanceInSingleScope(semicolonAst, variable);
}
final DetailAST variableUsageAst = entry.getKey();
final int dist = entry.getValue();
if (dist > mAllowedDistance
&& !isInitializationSequence(variableUsageAst, variable.getText()))
{
log(variable.getLineNo(),
MSG_KEY, variable.getText(), dist, mAllowedDistance);
}
}
}
}
/**
* Get name of instance whose method is called.
* @param aMethodCallAst
* DetailAST of METHOD_CALL.
* @return name of instance.
*/
private static String getInstanceName(DetailAST aMethodCallAst)
{
final String methodCallName =
FullIdent.createFullIdentBelow(aMethodCallAst).getText();
final int lastDotIndex = methodCallName.lastIndexOf('.');
String instanceName = "";
if (lastDotIndex != -1) {
instanceName = methodCallName.substring(0, lastDotIndex);
}
return instanceName;
}
/**
* Processes statements until usage of variable to detect sequence of
* initialization methods.
* @param aVariableUsageAst
* DetailAST of expression that uses variable named aVariableName.
* @param aVariableName
* name of considered variable.
* @return true if statements between declaration and usage of variable are
* initialization methods.
*/
private static boolean isInitializationSequence(
DetailAST aVariableUsageAst, String aVariableName)
{
boolean result = true;
boolean isUsedVariableDeclarationFound = false;
DetailAST currentSiblingAst = aVariableUsageAst;
String initInstanceName = "";
while (result
&& !isUsedVariableDeclarationFound
&& currentSiblingAst != null)
{
switch (currentSiblingAst.getType()) {
case TokenTypes.EXPR:
final DetailAST methodCallAst = currentSiblingAst.getFirstChild();
if (methodCallAst != null
&& methodCallAst.getType() == TokenTypes.METHOD_CALL)
{
final String instanceName =
getInstanceName(methodCallAst);
// method is called without instance
if (instanceName.isEmpty()) {
result = false;
}
// differs from previous instance
else if (!instanceName.equals(initInstanceName)) {
if (!initInstanceName.isEmpty()) {
result = false;
}
else {
initInstanceName = instanceName;
}
}
}
else { // is not method call
result = false;
}
break;
case TokenTypes.VARIABLE_DEF:
final String currentVariableName = currentSiblingAst.
findFirstToken(TokenTypes.IDENT).getText();
isUsedVariableDeclarationFound = aVariableName.equals(currentVariableName);
break;
case TokenTypes.SEMI:
break;
default:
result = false;
}
currentSiblingAst = currentSiblingAst.getPreviousSibling();
}
return result;
}
/**
* Calculates distance between declaration of variable and its first usage
* in single scope.
* @param aSemicolonAst
* Regular node of Ast which is checked for content of checking
* variable.
* @param aVariableIdentAst
* Variable which distance is calculated for.
* @return entry which contains expression with variable usage and distance.
*/
private Entry<DetailAST, Integer> calculateDistanceInSingleScope(
DetailAST aSemicolonAst, DetailAST aVariableIdentAst)
{
int dist = 0;
boolean firstUsageFound = false;
DetailAST currentAst = aSemicolonAst;
DetailAST variableUsageAst = null;
while (!firstUsageFound && currentAst != null
&& currentAst.getType() != TokenTypes.RCURLY)
{
if (currentAst.getFirstChild() != null) {
if (isChild(currentAst, aVariableIdentAst)) {
switch (currentAst.getType()) {
case TokenTypes.VARIABLE_DEF:
dist++;
break;
case TokenTypes.SLIST:
dist = 0;
break;
case TokenTypes.LITERAL_FOR:
case TokenTypes.LITERAL_WHILE:
case TokenTypes.LITERAL_DO:
case TokenTypes.LITERAL_IF:
case TokenTypes.LITERAL_SWITCH:
if (isVariableInOperatorExpr(currentAst, aVariableIdentAst)) {
dist++;
}
else { // variable usage is in inner scope
// reset counters, because we can't determine distance
dist = 0;
}
break;
default:
if (currentAst.branchContains(TokenTypes.SLIST)) {
dist = 0;
}
else {
dist++;
}
}
variableUsageAst = currentAst;
firstUsageFound = true;
}
else if (currentAst.getType() != TokenTypes.VARIABLE_DEF) {
dist++;
}
}
currentAst = currentAst.getNextSibling();
}
// If variable wasn't used after its declaration, distance is 0.
if (!firstUsageFound) {
dist = 0;
}
return new SimpleEntry<DetailAST, Integer>(variableUsageAst, dist);
}
/**
* Calculates distance between declaration of variable and its first usage
* in multiple scopes.
* @param aAST
* Regular node of Ast which is checked for content of checking
* variable.
* @param aVariable
* Variable which distance is calculated for.
* @return entry which contains expression with variable usage and distance.
*/
private Entry<DetailAST, Integer> calculateDistanceBetweenScopes(
DetailAST aAST, DetailAST aVariable)
{
int dist = 0;
DetailAST currentScopeAst = aAST;
DetailAST variableUsageAst = null;
while (currentScopeAst != null) {
final List<DetailAST> variableUsageExpressions = new ArrayList<DetailAST>();
DetailAST currentStatementAst = currentScopeAst;
currentScopeAst = null;
while (currentStatementAst != null
&& currentStatementAst.getType() != TokenTypes.RCURLY)
{
if (currentStatementAst.getFirstChild() != null) {
if (isChild(currentStatementAst, aVariable)) {
variableUsageExpressions.add(currentStatementAst);
}
// If expression doesn't contain variable and this variable
// hasn't been met yet, than distance + 1.
else if (variableUsageExpressions.size() == 0
&& currentStatementAst.getType() != TokenTypes.VARIABLE_DEF)
{
dist++;
}
}
currentStatementAst = currentStatementAst.getNextSibling();
}
// If variable usage exists in a single scope, then look into
// this scope and count distance until variable usage.
if (variableUsageExpressions.size() == 1) {
final DetailAST blockWithVariableUsage = variableUsageExpressions
.get(0);
DetailAST exprWithVariableUsage = null;
switch (blockWithVariableUsage.getType()) {
case TokenTypes.VARIABLE_DEF:
case TokenTypes.EXPR:
dist++;
break;
case TokenTypes.LITERAL_FOR:
case TokenTypes.LITERAL_WHILE:
case TokenTypes.LITERAL_DO:
exprWithVariableUsage = getFirstNodeInsideForWhileDoWhileBlocks(
blockWithVariableUsage, aVariable);
break;
case TokenTypes.LITERAL_IF:
exprWithVariableUsage = getFirstNodeInsideIfBlock(
blockWithVariableUsage, aVariable);
break;
case TokenTypes.LITERAL_SWITCH:
exprWithVariableUsage = getFirstNodeInsideSwitchBlock(
blockWithVariableUsage, aVariable);
break;
case TokenTypes.LITERAL_TRY:
exprWithVariableUsage =
getFirstNodeInsideTryCatchFinallyBlocks(blockWithVariableUsage, aVariable);
break;
default:
exprWithVariableUsage = blockWithVariableUsage.getFirstChild();
}
currentScopeAst = exprWithVariableUsage;
if (exprWithVariableUsage != null) {
variableUsageAst = exprWithVariableUsage;
}
else {
variableUsageAst = blockWithVariableUsage;
}
}
// If variable usage exists in different scopes, then distance =
// distance until variable first usage.
else if (variableUsageExpressions.size() > 1) {
dist++;
variableUsageAst = variableUsageExpressions.get(0);
}
// If there's no any variable usage, then distance = 0.
else {
variableUsageAst = null;
}
}
return new SimpleEntry<DetailAST, Integer>(variableUsageAst, dist);
}
/**
* Gets first Ast node inside FOR, WHILE or DO-WHILE blocks if variable
* usage is met only inside the block (not in its declaration!).
* @param aBlock
* Ast node represents FOR, WHILE or DO-WHILE block.
* @param aVariable
* Variable which is checked for content in block.
* @return If variable usage is met only inside the block
* (not in its declaration!) than return the first Ast node
* of this block, otherwise - null.
*/
private DetailAST getFirstNodeInsideForWhileDoWhileBlocks(
DetailAST aBlock, DetailAST aVariable)
{
DetailAST firstNodeInsideBlock = null;
if (!isVariableInOperatorExpr(aBlock, aVariable)) {
DetailAST currentNode = null;
// Find currentNode for DO-WHILE block.
if (aBlock.getType() == TokenTypes.LITERAL_DO) {
currentNode = aBlock.getFirstChild();
}
// Find currentNode for FOR or WHILE block.
else {
// Looking for RPAREN ( ')' ) token to mark the end of operator
// expression.
currentNode = aBlock.findFirstToken(TokenTypes.RPAREN);
if (currentNode != null) {
currentNode = currentNode.getNextSibling();
}
}
if (currentNode != null) {
final int currentNodeType = currentNode.getType();
if (currentNodeType == TokenTypes.SLIST) {
firstNodeInsideBlock = currentNode.getFirstChild();
}
else if (currentNodeType == TokenTypes.VARIABLE_DEF
|| currentNodeType == TokenTypes.EXPR)
{
; // no code
}
else {
firstNodeInsideBlock = currentNode;
}
}
}
return firstNodeInsideBlock;
}
/**
* Gets first Ast node inside IF block if variable usage is met
* only inside the block (not in its declaration!).
* @param aBlock
* Ast node represents IF block.
* @param aVariable
* Variable which is checked for content in block.
* @return If variable usage is met only inside the block
* (not in its declaration!) than return the first Ast node
* of this block, otherwise - null.
*/
private DetailAST getFirstNodeInsideIfBlock(
DetailAST aBlock, DetailAST aVariable)
{
DetailAST firstNodeInsideBlock = null;
if (!isVariableInOperatorExpr(aBlock, aVariable)) {
DetailAST currentNode = aBlock.getLastChild();
final List<DetailAST> variableUsageExpressions =
new ArrayList<DetailAST>();
while (currentNode != null
&& currentNode.getType() == TokenTypes.LITERAL_ELSE)
{
final DetailAST previousNode =
currentNode.getPreviousSibling();
// Checking variable usage inside IF block.
if (isChild(previousNode, aVariable)) {
variableUsageExpressions.add(previousNode);
}
// Looking into ELSE block, get its first child and analyze it.
currentNode = currentNode.getFirstChild();
if (currentNode.getType() == TokenTypes.LITERAL_IF) {
currentNode = currentNode.getLastChild();
}
else if (isChild(currentNode, aVariable)) {
variableUsageExpressions.add(currentNode);
currentNode = null;
}
}
// If IF block doesn't include ELSE than analyze variable usage
// only inside IF block.
if (currentNode != null
&& isChild(currentNode, aVariable))
{
variableUsageExpressions.add(currentNode);
}
// If variable usage exists in several related blocks, then
// firstNodeInsideBlock = null, otherwise if variable usage exists
// only inside one block, then get node from
// variableUsageExpressions.
if (variableUsageExpressions.size() == 1) {
firstNodeInsideBlock = variableUsageExpressions.get(0);
}
}
return firstNodeInsideBlock;
}
/**
* Gets first Ast node inside SWITCH block if variable usage is met
* only inside the block (not in its declaration!).
* @param aBlock
* Ast node represents SWITCH block.
* @param aVariable
* Variable which is checked for content in block.
* @return If variable usage is met only inside the block
* (not in its declaration!) than return the first Ast node
* of this block, otherwise - null.
*/
private DetailAST getFirstNodeInsideSwitchBlock(
DetailAST aBlock, DetailAST aVariable)
{
DetailAST firstNodeInsideBlock = null;
if (!isVariableInOperatorExpr(aBlock, aVariable)) {
DetailAST currentNode = aBlock
.findFirstToken(TokenTypes.CASE_GROUP);
final List<DetailAST> variableUsageExpressions =
new ArrayList<DetailAST>();
// Checking variable usage inside all CASE blocks.
while (currentNode != null
&& currentNode.getType() == TokenTypes.CASE_GROUP)
{
final DetailAST lastNodeInCaseGroup =
currentNode.getLastChild();
if (isChild(lastNodeInCaseGroup, aVariable)) {
variableUsageExpressions.add(lastNodeInCaseGroup);
}
currentNode = currentNode.getNextSibling();
}
// If variable usage exists in several related blocks, then
// firstNodeInsideBlock = null, otherwise if variable usage exists
// only inside one block, then get node from
// variableUsageExpressions.
if (variableUsageExpressions.size() == 1) {
firstNodeInsideBlock = variableUsageExpressions.get(0);
}
}
return firstNodeInsideBlock;
}
/**
* Gets first Ast node inside TRY-CATCH-FINALLY blocks if variable usage is
* met only inside the block (not in its declaration!).
* @param aBlock
* Ast node represents TRY-CATCH-FINALLY block.
* @param aVariable
* Variable which is checked for content in block.
* @return If variable usage is met only inside the block
* (not in its declaration!) than return the first Ast node
* of this block, otherwise - null.
*/
private static DetailAST getFirstNodeInsideTryCatchFinallyBlocks(
DetailAST aBlock, DetailAST aVariable)
{
DetailAST currentNode = aBlock.getFirstChild();
final List<DetailAST> variableUsageExpressions =
new ArrayList<DetailAST>();
// Checking variable usage inside TRY block.
if (isChild(currentNode, aVariable)) {
variableUsageExpressions.add(currentNode);
}
// Switch on CATCH block.
currentNode = currentNode.getNextSibling();
// Checking variable usage inside all CATCH blocks.
while (currentNode != null
&& currentNode.getType() == TokenTypes.LITERAL_CATCH)
{
final DetailAST catchBlock = currentNode.getLastChild();
if (isChild(catchBlock, aVariable)) {
variableUsageExpressions.add(catchBlock);
}
currentNode = currentNode.getNextSibling();
}
// Checking variable usage inside FINALLY block.
if (currentNode != null) {
final DetailAST finalBlock = currentNode.getLastChild();
if (isChild(finalBlock, aVariable)) {
variableUsageExpressions.add(finalBlock);
}
}
DetailAST variableUsageNode = null;
// If variable usage exists in several related blocks, then
// firstNodeInsideBlock = null, otherwise if variable usage exists
// only inside one block, then get node from
// variableUsageExpressions.
if (variableUsageExpressions.size() == 1) {
variableUsageNode = variableUsageExpressions.get(0).getFirstChild();
}
return variableUsageNode;
}
/**
* Checks if variable is in operator declaration. For instance:
* <pre>
* boolean b = true;
* if (b) {...}
* </pre>
* Variable 'b' is in declaration of operator IF.
* @param aOperator
* Ast node which represents operator.
* @param aVariable
* Variable which is checked for content in operator.
* @return true if operator contains variable in its declaration, otherwise
* - false.
*/
private boolean isVariableInOperatorExpr(
DetailAST aOperator, DetailAST aVariable)
{
boolean isVarInOperatorDeclr = false;
final DetailAST openingBracket =
aOperator.findFirstToken(TokenTypes.LPAREN);
if (openingBracket != null) {
// Get EXPR between brackets
DetailAST exprBetweenBrackets = openingBracket
.getNextSibling();
// Look if variable is in operator expression
while (exprBetweenBrackets.getType() != TokenTypes.RPAREN) {
if (isChild(exprBetweenBrackets, aVariable)) {
isVarInOperatorDeclr = true;
break;
}
exprBetweenBrackets = exprBetweenBrackets.getNextSibling();
}
// Variable may be met in ELSE declaration or in CASE declaration.
// So, check variable usage in these declarations.
if (!isVarInOperatorDeclr) {
switch (aOperator.getType()) {
case TokenTypes.LITERAL_IF:
final DetailAST elseBlock = aOperator.getLastChild();
if (elseBlock.getType() == TokenTypes.LITERAL_ELSE) {
// Get IF followed by ELSE
final DetailAST firstNodeInsideElseBlock = elseBlock
.getFirstChild();
if (firstNodeInsideElseBlock.getType()
== TokenTypes.LITERAL_IF)
{
isVarInOperatorDeclr |=
isVariableInOperatorExpr(
firstNodeInsideElseBlock,
aVariable);
}
}
break;
case TokenTypes.LITERAL_SWITCH:
DetailAST currentCaseBlock = aOperator
.findFirstToken(TokenTypes.CASE_GROUP);
while (currentCaseBlock != null
&& currentCaseBlock.getType()
== TokenTypes.CASE_GROUP)
{
final DetailAST firstNodeInsideCaseBlock =
currentCaseBlock.getFirstChild();
if (isChild(firstNodeInsideCaseBlock,
aVariable))
{
isVarInOperatorDeclr = true;
break;
}
currentCaseBlock = currentCaseBlock.getNextSibling();
}
break;
default:
;// no code
}
}
}
return isVarInOperatorDeclr;
}
/**
* Checks if Ast node contains given element.
* @param aParent
* Node of AST.
* @param aAST
* Ast element which is checked for content in Ast node.
* @return true if Ast element was found in Ast node, otherwise - false.
*/
private static boolean isChild(DetailAST aParent, DetailAST aAST)
{
boolean isChild = false;
final ASTEnumeration astList = aParent.findAllPartial(aAST);
while (astList.hasMoreNodes()) {
final DetailAST ast = (DetailAST) astList.nextNode();
DetailAST astParent = ast.getParent();
while (astParent != null) {
if (astParent.equals(aParent)
&& astParent.getLineNo() == aParent.getLineNo())
{
isChild = true;
break;
}
astParent = astParent.getParent();
}
}
return isChild;
}
/**
* Checks if entrance variable is contained in ignored pattern.
* @param aVariable
* Variable which is checked for content in ignored pattern.
* @return true if variable was found, otherwise - false.
*/
private boolean isVariableMatchesIgnorePattern(String aVariable)
{
final Matcher matcher = mIgnoreVariablePattern.matcher(aVariable);
return matcher.matches();
}
}

View File

@ -64,3 +64,4 @@ unnecessary.paren.literal=Unnecessary parentheses around literal ''{0}''.
unnecessary.paren.return=Unnecessary parentheses around return value.
unnecessary.paren.string=Unnecessary parentheses around string {0}.
package.dir.mismatch=Package declaration does not match directory ''{0}''.
variable.declaration.usage.distance=Distance between variable ''{0}'' declaration and its first usage is {1}, but allowed {2}.

View File

@ -0,0 +1,215 @@
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2014 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.coding;
import static com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck.MSG_KEY;
import static java.text.MessageFormat.format;
import org.junit.Test;
import com.puppycrawl.tools.checkstyle.BaseCheckTestSupport;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
public class VariableDeclarationUsageDistanceCheckTest extends
BaseCheckTestSupport
{
@Test
public void testGeneralLogic() throws Exception
{
final DefaultConfiguration checkConfig = createCheckConfig(VariableDeclarationUsageDistanceCheck.class);
checkConfig.addAttribute("allowedDistance", "1");
checkConfig.addAttribute("ignoreVariablePattern", "");
checkConfig.addAttribute("validateBetweenScopes", "true");
checkConfig.addAttribute("ignoreFinal", "false");
final String[] expected = {
"30: " + getCheckMessage(MSG_KEY, "a", 2, 1),
"38: " + getCheckMessage(MSG_KEY, "temp", 2, 1),
"44: " + getCheckMessage(MSG_KEY, "temp", 2, 1),
"57: " + getCheckMessage(MSG_KEY, "count", 2, 1),
"71: " + getCheckMessage(MSG_KEY, "count", 4, 1),
"96: " + getCheckMessage(MSG_KEY, "arg", 2, 1),
"144: " + getCheckMessage(MSG_KEY, "m", 3, 1),
"145: " + getCheckMessage(MSG_KEY, "n", 2, 1),
"184: " + getCheckMessage(MSG_KEY, "result", 2, 1),
"219: " + getCheckMessage(MSG_KEY, "t", 5, 1),
"222: " + getCheckMessage(MSG_KEY, "c", 3, 1),
"223: " + getCheckMessage(MSG_KEY, "d2", 3, 1),
"260: " + getCheckMessage(MSG_KEY, "selected", 2, 1),
"261: " + getCheckMessage(MSG_KEY, "model", 2, 1),
"287: " + getCheckMessage(MSG_KEY, "sw", 2, 1),
"300: " + getCheckMessage(MSG_KEY, "wh", 2, 1),
"343: " + getCheckMessage(MSG_KEY, "green", 2, 1),
"344: " + getCheckMessage(MSG_KEY, "blue", 3, 1),
"367: " + getCheckMessage(MSG_KEY, "intervalMs", 2, 1),
"454: " + getCheckMessage(MSG_KEY, "aOpt", 3, 1),
"455: " + getCheckMessage(MSG_KEY, "bOpt", 2, 1),
"471: " + getCheckMessage(MSG_KEY, "l1", 3, 1),
"471: " + getCheckMessage(MSG_KEY, "l2", 2, 1),
"479: " + getCheckMessage(MSG_KEY, "myOption", 7, 1),
"491: " + getCheckMessage(MSG_KEY, "myOption", 6, 1),
"504: " + getCheckMessage(MSG_KEY, "count", 4, 1),
"505: " + getCheckMessage(MSG_KEY, "files", 2, 1),
"540: " + getCheckMessage(MSG_KEY, "id", 2, 1),
"542: " + getCheckMessage(MSG_KEY, "parentId", 3, 1),
};
verify(checkConfig, getPath("coding/InputVariableDeclarationUsageDistanceCheck.java"), expected);
}
@Test
public void testDistance() throws Exception
{
final DefaultConfiguration checkConfig = createCheckConfig(VariableDeclarationUsageDistanceCheck.class);
checkConfig.addAttribute("allowedDistance", "3");
checkConfig.addAttribute("ignoreVariablePattern", "");
checkConfig.addAttribute("validateBetweenScopes", "true");
checkConfig.addAttribute("ignoreFinal", "false");
final String[] expected = {
"71: " + getCheckMessage(MSG_KEY, "count", 4, 3),
"219: " + getCheckMessage(MSG_KEY, "t", 5, 3),
"479: " + getCheckMessage(MSG_KEY, "myOption", 7, 3),
"491: " + getCheckMessage(MSG_KEY, "myOption", 6, 3),
"504: " + getCheckMessage(MSG_KEY, "count", 4, 3),
};
verify(checkConfig, getPath("coding/InputVariableDeclarationUsageDistanceCheck.java"), expected);
}
@Test
public void testVariableRegExp() throws Exception
{
final DefaultConfiguration checkConfig = createCheckConfig(VariableDeclarationUsageDistanceCheck.class);
checkConfig.addAttribute("allowedDistance", "1");
checkConfig.addAttribute("ignoreVariablePattern",
"a|b|c|d|block|dist|t|m");
checkConfig.addAttribute("validateBetweenScopes", "true");
checkConfig.addAttribute("ignoreFinal", "false");
final String[] expected = {
"38: " + getCheckMessage(MSG_KEY, "temp", 2, 1),
"44: " + getCheckMessage(MSG_KEY, "temp", 2, 1),
"57: " + getCheckMessage(MSG_KEY, "count", 2, 1),
"71: " + getCheckMessage(MSG_KEY, "count", 4, 1),
"96: " + getCheckMessage(MSG_KEY, "arg", 2, 1),
"145: " + getCheckMessage(MSG_KEY, "n", 2, 1),
"184: " + getCheckMessage(MSG_KEY, "result", 2, 1),
"223: " + getCheckMessage(MSG_KEY, "d2", 3, 1),
"260: " + getCheckMessage(MSG_KEY, "selected", 2, 1),
"261: " + getCheckMessage(MSG_KEY, "model", 2, 1),
"287: " + getCheckMessage(MSG_KEY, "sw", 2, 1),
"300: " + getCheckMessage(MSG_KEY, "wh", 2, 1),
"343: " + getCheckMessage(MSG_KEY, "green", 2, 1),
"344: " + getCheckMessage(MSG_KEY, "blue", 3, 1),
"367: " + getCheckMessage(MSG_KEY, "intervalMs", 2, 1),
"454: " + getCheckMessage(MSG_KEY, "aOpt", 3, 1),
"455: " + getCheckMessage(MSG_KEY, "bOpt", 2, 1),
"471: " + getCheckMessage(MSG_KEY, "l1", 3, 1),
"471: " + getCheckMessage(MSG_KEY, "l2", 2, 1),
"479: " + getCheckMessage(MSG_KEY, "myOption", 7, 1),
"491: " + getCheckMessage(MSG_KEY, "myOption", 6, 1),
"504: " + getCheckMessage(MSG_KEY, "count", 4, 1),
"505: " + getCheckMessage(MSG_KEY, "files", 2, 1),
"540: " + getCheckMessage(MSG_KEY, "id", 2, 1),
"542: " + getCheckMessage(MSG_KEY, "parentId", 3, 1),
};
verify(checkConfig, getPath("coding/InputVariableDeclarationUsageDistanceCheck.java"), expected);
}
@Test
public void testValidateBetweenScopesOption() throws Exception
{
final DefaultConfiguration checkConfig = createCheckConfig(VariableDeclarationUsageDistanceCheck.class);
checkConfig.addAttribute("allowedDistance", "1");
checkConfig.addAttribute("ignoreVariablePattern", "");
checkConfig.addAttribute("validateBetweenScopes", "false");
checkConfig.addAttribute("ignoreFinal", "false");
final String[] expected = {
"30: " + getCheckMessage(MSG_KEY, "a", 2, 1),
"38: " + getCheckMessage(MSG_KEY, "temp", 2, 1),
"44: " + getCheckMessage(MSG_KEY, "temp", 2, 1),
"71: " + getCheckMessage(MSG_KEY, "count", 4, 1),
"96: " + getCheckMessage(MSG_KEY, "arg", 2, 1),
"219: " + getCheckMessage(MSG_KEY, "t", 5, 1),
"222: " + getCheckMessage(MSG_KEY, "c", 3, 1),
"223: " + getCheckMessage(MSG_KEY, "d2", 3, 1),
"300: " + getCheckMessage(MSG_KEY, "wh", 2, 1),
"343: " + getCheckMessage(MSG_KEY, "green", 2, 1),
"344: " + getCheckMessage(MSG_KEY, "blue", 3, 1),
"367: " + getCheckMessage(MSG_KEY, "intervalMs", 2, 1),
"454: " + getCheckMessage(MSG_KEY, "aOpt", 3, 1),
"455: " + getCheckMessage(MSG_KEY, "bOpt", 2, 1),
"471: " + getCheckMessage(MSG_KEY, "l1", 3, 1),
"471: " + getCheckMessage(MSG_KEY, "l2", 2, 1),
"479: " + getCheckMessage(MSG_KEY, "myOption", 7, 1),
"491: Distance between variable 'myOption' declaration and its first usage is 6, but allowed 1.",
"505: Distance between variable 'files' declaration and its first usage is 2, but allowed 1.",
"540: Distance between variable 'id' declaration and its first usage is 2, but allowed 1.",
"542: Distance between variable 'parentId' declaration and its first usage is 4, but allowed 1.",
};
verify(checkConfig, getPath("coding/InputVariableDeclarationUsageDistanceCheck.java"), expected);
}
@Test
public void testIgnoreFinalOption() throws Exception
{
final DefaultConfiguration checkConfig = createCheckConfig(VariableDeclarationUsageDistanceCheck.class);
checkConfig.addAttribute("allowedDistance", "1");
checkConfig.addAttribute("ignoreVariablePattern", "");
checkConfig.addAttribute("validateBetweenScopes", "true");
checkConfig.addAttribute("ignoreFinal", "true");
final String[] expected = {
"30: " + getCheckMessage(MSG_KEY, "a", 2, 1),
"38: " + getCheckMessage(MSG_KEY, "temp", 2, 1),
"44: " + getCheckMessage(MSG_KEY, "temp", 2, 1),
"57: " + getCheckMessage(MSG_KEY, "count", 2, 1),
"71: " + getCheckMessage(MSG_KEY, "count", 4, 1),
"96: " + getCheckMessage(MSG_KEY, "arg", 2, 1),
"144: " + getCheckMessage(MSG_KEY, "m", 3, 1),
"145: " + getCheckMessage(MSG_KEY, "n", 2, 1),
"184: " + getCheckMessage(MSG_KEY, "result", 2, 1),
"219: " + getCheckMessage(MSG_KEY, "t", 5, 1),
"222: " + getCheckMessage(MSG_KEY, "c", 3, 1),
"223: " + getCheckMessage(MSG_KEY, "d2", 3, 1),
"260: " + getCheckMessage(MSG_KEY, "selected", 2, 1),
"261: " + getCheckMessage(MSG_KEY, "model", 2, 1),
"287: " + getCheckMessage(MSG_KEY, "sw", 2, 1),
"300: " + getCheckMessage(MSG_KEY, "wh", 2, 1),
"343: " + getCheckMessage(MSG_KEY, "green", 2, 1),
"344: " + getCheckMessage(MSG_KEY, "blue", 3, 1),
"454: " + getCheckMessage(MSG_KEY, "aOpt", 3, 1),
"455: " + getCheckMessage(MSG_KEY, "bOpt", 2, 1),
"471: " + getCheckMessage(MSG_KEY, "l1", 3, 1),
"471: " + getCheckMessage(MSG_KEY, "l2", 2, 1),
"479: " + getCheckMessage(MSG_KEY, "myOption", 7, 1),
"491: " + getCheckMessage(MSG_KEY, "myOption", 6, 1),
"504: " + getCheckMessage(MSG_KEY, "count", 4, 1),
"505: " + getCheckMessage(MSG_KEY, "files", 2, 1),
"540: " + getCheckMessage(MSG_KEY, "id", 2, 1),
"542: " + getCheckMessage(MSG_KEY, "parentId", 3, 1),
};
verify(checkConfig, getPath("coding/InputVariableDeclarationUsageDistanceCheck.java"), expected);
}
/**
* Gets the check message 'as is' from appropriate 'messages.properties' file.
* @param messageKey the key of message in 'messages.properties' file.
* @param arguments the arguments of message in 'messages.properties' file.
*/
public String getCheckMessage(String messageKey, Object ... arguments)
{
return format(getCheckMessage(messageKey), arguments);
}
}

View File

@ -0,0 +1,567 @@
package com.puppycrawl.tools.checkstyle.design;
public class InputVariableDeclarationUsageDistanceCheck {
private static final int test1;
static {
int b;
int d;
{
d = ++b;
}
}
static {
int c;
int a = 3;
int b = 2;
{
a = a + b;
c = b;
}
{
c--;
}
a = 7;
}
static {
int a = -1;
int b = 2;
b++;
int c = --b;
a = b; // DECLARATION OF VARIABLE 'a' SHOULD BE HERE (distance = 2)
}
public InputVariableDeclarationUsageDistanceCheck(int test1) {
int temp = -1;
this.test1 = test1;
temp = test1; // DECLARATION OF VARIABLE 'temp' SHOULD BE HERE (distance = 2)
}
public boolean testMethod() {
int temp = 7;
new InputVariableDeclarationUsageDistanceCheck(2);
InputVariableDeclarationUsageDistanceCheck(temp); // DECLARATION OF VARIABLE 'temp' SHOULD BE HERE (distance = 2)
boolean result = false;
String str = "";
if (test1 > 1) {
str = "123";
result = true;
}
return result;
}
public void testMethod2() {
int count;
int a = 3;
int b = 2;
{
a = a
+ b
- 5
+ 2
* a;
count = b; // DECLARATION OF VARIABLE 'count' SHOULD BE HERE (distance = 2)
}
}
public void testMethod3() {
int count;
int a = 3;
int b = 3;
a = a + b;
b = a + a;
testMethod2();
count = b; // DECLARATION OF VARIABLE 'count' SHOULD BE HERE (distance = 4)
}
public void testMethod4(int arg) {
int d;
for (int i = 0; i < 10; i++) {
d++;
if (i > 5) {
d += arg;
}
}
String ar[] = { "1", "2" };
for (String st : ar) {
System.out.println(st);
}
}
public void testMethod5() {
int arg = 7;
boolean b = true;
boolean bb = false;
if (b)
if (!bb)
b = false;
testMethod4(arg); // DECLARATION OF VARIABLE 'arg' SHOULD BE HERE (distance = 2)
}
public void testMethod6() {
int blockNumWithSimilarVar = 3;
int dist = 0;
int index = 0;
int block = 0;
if (blockNumWithSimilarVar <= 1) {
do {
dist++;
if (block > 4) {
break;
}
index++;
block++;
} while (index < 7);
} else {
while (index < 8) {
dist += block;
index++;
block++;
}
}
}
public boolean testMethod7(int a) {
boolean res;
switch (a) {
case 1:
res = true;
break;
default:
res = false;
}
return res;
}
public void testMethod8() {
int b;
int c;
int m;
int n;
{
c++;
b++;
}
{
n++; // DECLARATION OF VARIABLE 'n' SHOULD BE HERE (distance = 2)
m++; // DECLARATION OF VARIABLE 'm' SHOULD BE HERE (distance = 3)
b++;
}
}
public void testMethod9() {
boolean result = false;
boolean b1 = true;
boolean b2 = false;
if (b1) {
if (!b2) {
result = true;
}
result = true;
}
}
public boolean testMethod10() {
boolean result;
try {
result = true;
} catch (IOException e) {
result = false;
} finally {
result = false;
}
return result;
}
public void testMethod11() {
int a = 0;
int b = 10;
boolean result;
try {
b--;
} catch (IOException e) {
b++;
result = false; // DECLARATION OF VARIABLE 'result' SHOULD BE HERE (distance = 2)
} finally {
a++;
}
}
public void testMethod12() {
boolean result = false;
boolean b3 = true;
boolean b1 = true;
boolean b2 = false;
if (b1) {
if (b3) {
if (!b2) {
result = true;
}
result = true;
}
}
}
public void testMethod13() {
int i = 9;
int j = 6;
int g = i + 8;
int k = j + 10;
}
public void testMethod14() {
Session s = openSession();
Transaction t = s.beginTransaction();
A a = new A();
E d1 = new E();
C1 c = new C1();
E d2 = new E();
a.setForward(d1);
d1.setReverse(a);
c.setForward(d2); // DECLARATION OF VARIABLE 'c' SHOULD BE HERE (distance = 3)
// DECLARATION OF VARIABLE 'd2' SHOULD BE HERE (distance = 3)
d2.setReverse(c);
Serializable aid = s.save(a);
Serializable d2id = s.save(d2);
t.commit(); // DECLARATION OF VARIABLE 't' SHOULD BE HERE (distance = 5)
s.close();
}
public boolean isCheckBoxEnabled(TreePath path) {
DataLabelModel model = (DataLabelModel) getModel();
if (recursiveState) {
for (int index = 0; index < path.getPathCount(); ++index) {
int nodeIndex = model.getNodeIndex(path.getPathComponent(index));
if (disabled.contains(nodeIndex)) {
return false;
}
}
} else {
int nodeIndex = model.getNodeIndex(path.getLastPathComponent());
if (disabled.contains(nodeIndex)) {
return false;
}
}
return true;
}
public Object readObject(IObjectInputStream in) throws IOException {
SimpleDay startDay = new SimpleDay(in.readInt());
SimpleDay endDay = new SimpleDay(in.readInt());
return new SimplePeriod(startDay, endDay);
}
public int[] getSelectedIndices() {
int[] selected = new int[paths.length];
DataLabelModel model = (DataLabelModel) getModel();
int a = 0;
a++;
for (int index = 0; index < paths.length; ++index) {
selected[index] = model.getNodeIndex(paths[index].getLastPathComponent()); // DECLARATION OF VARIABLE 'selected' SHOULD BE HERE (distance = 2)
// DECLARATION OF VARIABLE 'model' SHOULD BE HERE (distance = 2)
}
return selected;
}
public void testMethod15() {
String confDebug = subst(element.getAttribute(CONFIG_DEBUG_ATTR));
if (!confDebug.equals("") && !confDebug.equals("null")) {
LogLog.warn("The \"" + CONFIG_DEBUG_ATTR + "\" attribute is deprecated.");
LogLog.warn("Use the \"" + INTERNAL_DEBUG_ATTR + "\" attribute instead.");
LogLog.setInternalDebugging(OptionConverter.toBoolean(confDebug, true));
}
int i = 0;
int k = 7;
boolean b = false;
for (; i < k; i++) {
b = true;
k++;
}
int sw;
switch (i) {
case 0:
k++;
sw = 0; // DECLARATION OF VARIABLE 'sw' SHOULD BE HERE (distance = 2)
break;
case 1:
b = false;
break;
default:
b = true;
}
int wh;
b = true;
do {
k--;
i++;
} while (wh > 0); // DECLARATION OF VARIABLE 'wh' SHOULD BE HERE (distance = 2)
if (wh > 0) {
k++;
} else if (!b) {
i++;
} else {
i--;
}
}
public void testMethod16() {
int wh = 1;
if (i > 0) {
k++;
} else if (wh > 0) {
i++;
} else {
i--;
}
}
protected JMenuItem createSubMenuItem(LogLevel level) {
final JMenuItem result = new JMenuItem(level.toString());
final LogLevel logLevel = level;
result.setMnemonic(level.toString().charAt(0));
result.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showLogLevelColorChangeDialog(result, logLevel); // DECLARATION OF VARIABLE 'logLevel' SHOULD BE HERE (distance = 2)
}
});
return result;
}
public static Color darker(Color color, double fraction) {
int red = (int) Math.round(color.getRed() * (1.0 - fraction));
int green = (int) Math.round(color.getGreen() * (1.0 - fraction));
int blue = (int) Math.round(color.getBlue() * (1.0 - fraction));
if (red < 0) {
red = 0;
} else if (red > 255) {
red = 255;
}
if (green < 0) { // DECLARATION OF VARIABLE 'green' SHOULD BE HERE (distance = 2)
green = 0;
} else if (green > 255) {
green = 255;
}
if (blue < 0) { // DECLARATION OF VARIABLE 'blue' SHOULD BE HERE (distance = 3)
// blue = 0;
}
int alpha = color.getAlpha();
return new Color(red, green, blue, alpha);
}
public void testFinal() {
AuthUpdateTask authUpdateTask = null;
final long intervalMs = 30 * 60000L; // 30 min
authUpdateTask = new AuthUpdateTask(authCheckUrl, authInfo, new IAuthListener() {
@Override
public void authTokenChanged(String cookie, String token) {
fireAuthTokenChanged(cookie, token);
}
});
Timer authUpdateTimer = new Timer("Auth Guard", true);
authUpdateTimer.schedule(authUpdateTask, intervalMs / 2, intervalMs); // DECLARATION OF VARIABLE 'intervalMs' SHOULD BE HERE (distance = 2)
}
public void testForCycle() {
int filterCount = 0;
for (int i = 0; i < 10; i++, filterCount++) {
int abc = 0;
System.out.println(abc);
for (int j = 0; j < 10; j++) {
abc = filterCount;
System.out.println(abc);
}
}
}
public void testIssue32_1()
{
Option srcDdlFile = OptionBuilder.create("f");
Option logDdlFile = OptionBuilder.create("o");
Option help = OptionBuilder.create("h");
Options options = new Options();
options.something();
options.something();
options.something();
options.something();
options.addOption(srcDdlFile, logDdlFile, help); // distance=1
}
public void testIssue32_2()
{
int mm = Integer.parseInt(time.substring(div + 1).trim());
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timeNow);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.HOUR_OF_DAY, hh);
cal.set(Calendar.MINUTE, mm); // distance=1
}
public void testIssue32_3(MyObject[] objects) {
Calendar cal = Calendar.getInstance();
for(int i=0; i<objects.length; i++) {
objects[i].setEnabled(true);
objects[i].setColor(0x121212);
objects[i].setUrl("http://google.com");
objects[i].setSize(789);
objects[i].setCalendar(cal); // distance=1
}
}
public void testIssue32_4(boolean flag) {
StringBuilder builder = new StringBuilder();
builder.append("flag is ");
builder.append(flag);
final String line = ast.getLineNo();
if(flag) {
builder.append("line of AST is:");
builder.append("\n");
builder.append(String.valueOf(line)); //distance=1
builder.append("\n");
}
return builder.toString();
}
public void testIssue32_5() {
Option a;
Option b;
Option c;
boolean isCNull = isNull(c); // distance=1
boolean isBNull = isNull(b); // distance=1
boolean isANull = isNull(a); // distance=1
}
public void testIssue32_6() {
Option aOpt;
Option bOpt;
Option cOpt;
isNull(cOpt); // distance = 1
isNull(bOpt); // distance = 2
isNull(aOpt); // distance = 3
}
public void testIssue32_7() {
String line = "abc";
writer.write(line);
line.charAt(1);
builder.append(line);
test(line, line, line);
}
public void testIssue32_8(Writer w1, Writer w2, Writer w3) {
String l1="1", l2="2", l3="3";
w1.write(l3); //distance=1
w2.write(l2); //distance=2
w3.write(l1); //distance=3
}
public void testIssue32_9() {
Options options = new Options();
Option myOption = null;
options.addBindFile(null);
options.addBindFile(null);
options.addBindFile(null);
options.addBindFile(null);
options.addBindFile(null);
System.out.println("message");
myOption.setArgName("abc"); // distance=7
}
public void testIssue32_10() {
Options options = new Options();
Option myOption = null;
options.addBindFile(null);
options.addBindFile(null);
options.addBindFile(null);
options.addBindFile(null);
options.addBindFile(null);
myOption.setArgName("q"); // distance=6
}
public int testIssue32_11(File toDir)
throws IOException, FTPException,
ParseException, InterruptedException
{
int count = 0;
FTPFile[] files = client.dirDetails(".");
log.info("Data archivation started");
archiveOldData(archDir, files);
log.info("Data archivation finished");
if (files == null || files.length == 0) {
warn("No files on a remote site");
}
else {
log.debug("Files on remote site: " + files.length);
for (FTPFile ftpFile : files) {
if (!file.exists()) {
getFile(client, ftpFile, file);
file.setLastModified(ftpFile.lastModified().getTime());
count++;
}
}
}
client.quit();
return count;
}
//////////////////////////////////////////////////
// False positive. Will be fixed in future.
//////////////////////////////////////////////////
private TreeMapNode buildTree(List<Object[]> tree)
{
state.clear();
revState.clear();
TreeMapNode root = null;
for (Object[] s : tree) {
Integer id = (Integer) s[0];
String label = (String) s[1];
Integer parentId = (Integer) s[2]; ///!!!!!!!!
Number weight = (Number) s[3];
Number value = (Number) s[4];
Integer childCount = (Integer) s[5];
TreeMapNode node;
if (childCount == 0) {
node = new TreeMapNode(label,
weight != null ? weight.doubleValue() : 0.0,
new DefaultValue(value != null ? value.doubleValue()
: 0.0));
}
else {
node = new TreeMapNode(label);
}
state.put(id, node);
revState.put(node, id);
if (parentId == null || parentId == -1) { ///!!!!!!!
root = node;
}
else {
state.get(parentId).add(node);
}
}
return root;
}
}

View File

@ -713,6 +713,10 @@
<td><a href="config_misc.html#UpperEll">UpperEll</a></td>
<td>Checks that long constants are defined with an upper ell.</td>
</tr>
<tr>
<td><a href="config_coding.html#VariableDeclarationUsageDistance">VariableDeclarationUsageDistance</a></td>
<td>Checks the distance between declaration of variable and its first usage.</td>
</tr>
<tr>
<td><a href="config_design.html#VisibilityModifier">VisibilityModifier</a></td>
<td>Checks visibility of class members.</td>

View File

@ -2509,5 +2509,196 @@ case 3:
</subsection>
</section>
<section name="VariableDeclarationUsageDistance">
<subsection name="Description">
<p>
Checks the distance between declaration of variable and its first usage.
</p>
</subsection>
<subsection name="Properties">
<table>
<tr>
<th>name</th>
<th>description</th>
<th>type</th>
<th>default value</th>
</tr>
<tr>
<td>allowedDistance</td>
<td>A distance between declaration of variable and its first usage</td>
<td><a href="property_types.html#integer">integer</a></td>
<td>3</td>
</tr>
<tr>
<td>ignoreVariablePattern</td>
<td>pattern for ignoring the distance calculation</td>
<td><a href="property_types.html#regexp">regular expression</a></td>
<td>(not applied)</td>
</tr>
<tr>
<td>validateBetweenScopes</td>
<td>Allows to calculate the distance between declaration of variable and its first usage in the different scopes.</td>
<td><a href="property_types.html#boolean">Boolean</a></td>
<td><code>false</code></td>
</tr>
<tr>
<td>ignoreFinal</td>
<td>Allows to ignore variables with a 'final' modifier.</td>
<td><a href="property_types.html#boolean">Boolean</a></td>
<td><code>true</code></td>
</tr>
</table>
</subsection>
<subsection name="Examples">
<p>
Example #1:
</p>
<source>
int count;
a = a + b;
b = a + a;
count = b; // DECLARATION OF VARIABLE 'count'
// SHOULD BE HERE (distance = 3)
</source>
<p>
Example #2:
</p>
<source>
int count;
{
a = a + b;
count = b; // DECLARATION OF VARIABLE 'count'
// SHOULD BE HERE (distance = 2)
}
</source>
<p>
Check can detect a block of initialization methods. If a variable is used in
such a block and there is no other statements after this variable then distance=1.
</p>
<p>
Case #1:
</p>
<source>
int minutes = 5;
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timeNow);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.HOUR_OF_DAY, hh);
cal.set(Calendar.MINUTE, minutes);
</source>
<p>
The distance for the variable minutes is 1 even
though this variable is used in the fifth method's call.
</p>
<p>
Case #2:
</p>
<source>
int minutes = 5;
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timeNow);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
System.out.println(cal);
cal.set(Calendar.HOUR_OF_DAY, hh);
cal.set(Calendar.MINUTE, minutes);
</source>
<p>
The distance for the variable minutes is 6 because there is one more expression
(except the initialization block) between the declaration of this variable and its usage.
</p>
<p>
An example how to configure this Check:
</p>
<source>
&lt;module name="VariableDeclarationUsageDistance"/&gt;
</source>
<p>
An example of how to configure this Check:
- to set the allowed distance to 4;
- to ignore variables with prefix '^temp';
- to force the validation between scopes;
- to check the final variables;
</p>
<source>
&lt;module name="VariableDeclarationUsageDistance"&gt;
&lt;property name="allowedDistance" value="4"&gt;
&lt;property name="ignoreVariablePattern" value="^temp.*"&gt;
&lt;property name="validateBetweenScopes" value="true"&gt;
&lt;property name="mIgnoreFinal" value="false"&gt;
&lt;/module&gt;
</source>
</subsection>
<subsection name="Note">
<p>
ATTENTION!! (Not supported cases)
</p>
<source>
Case #1:
{
int c;
int a = 3;
int b = 2;
{
a = a + b;
c = b;
}
}
</source>
<p>
Distance for variable 'a' = 1;
Distance for variable 'b' = 1;
Distance for variable 'c' = 2.
</p>
<p>
As distance by default is 1 the Check doesn't raise warning for
variables 'a' and 'b' to move them into the block.
</p>
<p>
Case #2:
</p>
<source>
int sum = 0;
for (int i = 0; i < 20; i++) {
a++;
b--;
sum++;
if (sum > 10) {
res = true;
}
}
</source>
<p>
Distance for variable 'sum' = 3.
</p>
<p>
As the distance is more then the default one, the Check
raises warning for variable 'sum' to move it into the 'for(...)' block.
But there is situation when variable 'sum' hasn't to be 0 within each iteration.
So, to avoid such warnings you can use Suppression Filter, provided by
Checkstyle, for the whole class.
</p>
</subsection>
<subsection name="Package">
<p>
com.puppycrawl.tools.checkstyle.checks.coding
</p>
</subsection>
<subsection name="Parent Module">
<p>
<a href="config.html#TreeWalker">TreeWalker</a>
</p>
</subsection>
</section>
</body>
</document>