Skip to content

Commit

Permalink
Diamond Operator For Variable Definition Check #188
Browse files Browse the repository at this point in the history
  • Loading branch information
alexkravin committed Jul 7, 2014
1 parent a1c2d2a commit b79dacc
Show file tree
Hide file tree
Showing 7 changed files with 316 additions and 11 deletions.
Expand Up @@ -54,6 +54,9 @@ ForbidReturnInFinalBlockCheck.desk = Verifies the finally block design
ForbidThrowAnonymousExceptionsCheck.name = Forbid Throw Anonymous Exceptions
ForbidThrowAnonymousExceptionsCheck.desc = <p>Forbid throwing anonymous exception. limitation: This Check does not validate cases then Exception object is created before it is thrown.<br/>For example:</p><code><pre>catch (Exception e) {<br/> throw new RuntimeException() { //anonymous exception<br/> //some code<br/> };</code></pre>
DiamondOperatorForVariableDefinitionCheck.name = Diamond Operator For Variable Definition
DiamondOperatorForVariableDefinitionCheck.desc = This Check highlights variable definition statements where <a href= "http://docs.oracle.com/javase/7/docs/technotes/guides/language/type-inference-generic-instance-creation.html"> diamond operator</a> could be used.<br> <b>Rationale</b>: using diamond operator (introduced in Java 1.7) leads to shorter code<br> and better code readability. It is suggested by Oracle that the diamond primarily using<br> for variable declarations.<br><br> E.g. of statements: <p> <b>Without diamond operator:</b><br><code> Map&ltString, Map&ltString, Integer&gt&gt someMap = new HashMap&ltString, Map&ltString, Integer&gt&gt();</code><br> <b>With diamond operator:</b><br> <code> Map&ltString, Map&ltString, Integer&gt&gt someMap = new HashMap&lt&gt(); </code> </p> @author <a href="mailto:nesterenko-aleksey@list.ru">Aleksey Nesterenko</a>
IllegalCatchExtended.name = Illegal Catch Check Extended
IllegalCatchExtended.desc = Check for illegal catch but with option to ignore these catches in some cases
IllegalCatchExtended.allowThrow = Allow catching when throwing some exception
Expand Down
Expand Up @@ -108,6 +108,11 @@
<message-key key="confusing.condition.check"/>
</rule-metadata>

<rule-metadata name="%DiamondOperatorForVariableDefinitionCheck.name" internal-name="DiamondOperatorForVariableDefinitionCheck" parent="TreeWalker">
<alternative-name internal-name="com.github.sevntu.checkstyle.checks.coding.DiamondOperatorForVariableDefinitionCheck"/>
<description>%DiamondOperatorForVariableDefinitionCheck.desc</description>
</rule-metadata>

<rule-metadata name="%ForbidCertainImports.name" internal-name="ForbidCertainImports" parent="TreeWalker">
<alternative-name internal-name="com.puppycrawl.tools.checkstyle.checks.coding.ForbidCertainImportsCheck"/>
<description>%ForbidCertainImports.desc</description>
Expand Down Expand Up @@ -230,14 +235,14 @@
<message-key key="multiple.string.literal" />
</rule-metadata>

<rule-metadata name="%NestedTernaryCheck.name" internal-name="NestedTernary" parent="TreeWalker">
<alternative-name internal-name="com.github.sevntu.checkstyle.checks.coding.NestedTernaryCheck"/>
<description>%NestedTernaryCheck.desc</description>
<property-metadata name="ignoreFinal" datatype="Boolean" default-value="false">
<description>%NestedTernaryCheck.ignoreFinal</description>
</property-metadata>
</rule-metadata>

<rule-metadata name="%NestedTernaryCheck.name" internal-name="NestedTernary" parent="TreeWalker">
<alternative-name internal-name="com.github.sevntu.checkstyle.checks.coding.NestedTernaryCheck"/>
<description>%NestedTernaryCheck.desc</description>
<property-metadata name="ignoreFinal" datatype="Boolean" default-value="false">
<description>%NestedTernaryCheck.ignoreFinal</description>
</property-metadata>
</rule-metadata>
<rule-metadata name="%NoNullForCollectionReturnCheck.name" internal-name="NoNullForCollectionReturnCheck" parent="TreeWalker">
<alternative-name internal-name="com.github.sevntu.checkstyle.checks.coding.NoNullForCollectionReturnCheck"/>
<description>%NoNullForCollectionReturnCheck.desc</description>
Expand Down
@@ -0,0 +1,84 @@
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2011 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.github.sevntu.checkstyle.checks.coding;

import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;

/**
* This Check highlights variable definition statements where <a href=
* "http://docs.oracle.com/javase/7/docs/technotes/guides/language/type-inference-generic-instance-creation.html">
* diamond operator</a> could be used.<br>
* <b>Rationale</b>: using diamond operator (introduced in Java 1.7) leads to shorter code<br>
* and better code readability. It is suggested by Oracle that the diamond primarily using<br>
* for variable declarations.<br><br>
* E.g. of statements:
* <p>
* <b>Without diamond operator:</b><br><code>
* Map&ltString, Map&ltString, Integer&gt&gt someMap = new HashMap&ltString, Map&ltString, Integer&gt&gt();</code><br>
* <b>With diamond operator:</b><br>
* <code>
* Map&ltString, Map&ltString, Integer&gt&gt someMap = new HashMap&lt&gt();
* </code>
* </p>
* @author <a href="mailto:nesterenko-aleksey@list.ru">Aleksey Nesterenko</a>
*/
public class DiamondOperatorForVariableDefinitionCheck extends Check {

public static final String MSG_KEY = "diamond.operator.for.variable.definition";

@Override
public int[] getDefaultTokens() {
return new int[] { TokenTypes.VARIABLE_DEF };
}

@Override
public void visitToken(DetailAST variableDefNode) {

DetailAST assignNode = variableDefNode.findFirstToken(TokenTypes.ASSIGN);

if (assignNode != null) {
DetailAST newNode = assignNode.getFirstChild().getFirstChild();
if (newNode.getType() == TokenTypes.LITERAL_NEW) {
DetailAST typeArgs = newNode.findFirstToken(TokenTypes.TYPE_ARGUMENTS);
if (typeArgs != null && isSameTypeArgsInVariableDef(variableDefNode, typeArgs)) {
log(typeArgs, MSG_KEY);
}
}
}
}

/**
* Checks if type arguments of left and right side of assignment are equals
* @param variableDefNode
* current variable definition
* @param typeArgs
* right type arguments of assignment
* @return true or false
*/
private boolean isSameTypeArgsInVariableDef(DetailAST variableDefNode,
DetailAST typeArgs) {

DetailAST typeNode = variableDefNode.findFirstToken(TokenTypes.TYPE);
DetailAST variableDefTypeArgs = typeNode.findFirstToken(TokenTypes.TYPE_ARGUMENTS);

return variableDefTypeArgs != null && variableDefTypeArgs.equalsTree(typeArgs);
}
}
Expand Up @@ -23,6 +23,7 @@ declaration.order.static=Static variable definition in wrong order.
declaration.order.instance=Instance variable definition in wrong order.
declaration.order.access=Variable access definition in wrong order.
default.comes.last=Default should be the last switch label.
diamond.operator.for.variable.definition = Diamond operator expected.
doublechecked.locking.avoid=The double-checked locking idiom is broken and should be avoided.
empty.statement=Empty statement.
equals.avoid.null=String literal expressions should be on the left side of an equals comparison.
Expand Down
@@ -0,0 +1,42 @@
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2011 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.github.sevntu.checkstyle.checks.coding;

import static com.github.sevntu.checkstyle.checks.coding.DiamondOperatorForVariableDefinitionCheck.MSG_KEY;
import org.junit.Test;

import com.github.sevntu.checkstyle.BaseCheckTestSupport;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;

public class DiamondOperatorForVariableDefinitionCheckTest extends BaseCheckTestSupport {
private final DefaultConfiguration checkConfig = createCheckConfig(DiamondOperatorForVariableDefinitionCheck.class);

@Test
public void testDefault() throws Exception {
String[] expected = {
"31:58: " + getCheckMessage(MSG_KEY),
"33:26: " + getCheckMessage(MSG_KEY),
"35:41: " + getCheckMessage(MSG_KEY),
"152:88: " + getCheckMessage(MSG_KEY)
};
verify(checkConfig,
getPath("InputDiamondOperatorForVariableDefinitionCheck.java"), expected);
}

}
@@ -0,0 +1,156 @@

import java.io.File;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;

import javax.print.attribute.Attribute;
import javax.print.attribute.AttributeSet;
import javax.sql.rowset.Predicate;
import javax.swing.tree.TreePath;

import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.ShadowMatch;
import org.springframework.beans.factory.BeanFactory;

import testforbid.Classifier;
import testforbid.JointClassification;

public class InputDiamondOperatorForVariableDefinitionCheck {
static Map<String, List<String>> myMap1 = new TreeMap<String, List<String>>();
List<Integer> list =
new ArrayList<Integer>();
Map<String, List<String>> myMap = new HashMap<>();
List<Character> abc = new LinkedList<Character>();
private TreePath[] suppressParentPaths(TreePath[] paths) {
List<TreePath> selectedPaths = Arrays.asList(paths);
Collections.sort(selectedPaths, new Comparator<TreePath>() {
@Override
public int compare(TreePath o1, TreePath o2) {
int count1 = o1.getPathCount();
int count2 = o2.getPathCount();
if (count1 < count2) {
return -1;
}
if (count1 == count2) {
return 0;
}
return 1;
}
});
return paths;
}


private static class DemoAttributeSet implements AttributeSet {
public Enumeration<?> getAttributeNames() {
return (Enumeration<?>) new ArrayList<String>();
}

}

private TreePath[] suppressParentPaths1(TreePath[] paths) {
List<TreePath> selectedPaths = Arrays.asList(paths);
Collections.sort(selectedPaths, new Comparator<TreePath>() {
@Override
public int compare(TreePath o1, TreePath o2) {
int count1 = o1.getPathCount();
int count2 = o2.getPathCount();
if (count1 < count2) {
return -1;
}
if (count1 == count2) {
return 0;
}
return 1;
}
});


Object statusArray[] = null;
Arrays.sort(statusArray, new Comparator<Object>() {
public int compare(Object s1, Object s2) {
return 1;
}
});
return paths; }

List<Number> list = new LinkedList<Integer>();

public class XReqLib {
private static final String SLASH = "/";

private final String base;

public XReqLib(String base) {
if (base.endsWith(SLASH)) {
this.base = base.substring(0, base.length() - 1);
} else {
this.base = base;
}
}

public String contextPath(String path) {
if (path.startsWith(SLASH)) {
return base + SLASH + path.substring(1);
} else {
return base + SLASH + path;
}
}

}

private Classifier<CharSequence, JointClassification> classifier;

public void MnaNewsClassifier() {
// see AbstractExternalizable.readObject(File)

InputStream in = getClass().getResourceAsStream("mna-model.bin");
if (in == null) {
throw new IllegalStateException("cannot find mna-model.bin in " + getClass().getPackage().getName());
}
try {
try {
ObjectInputStream objIn = new ObjectInputStream(in);
Object obj = objIn.readObject();
this.classifier = (Classifier<CharSequence, JointClassification>) obj;
} finally {
in.close();
}
} catch (Exception e) {
throw new IllegalStateException("failed to load classifier: " + e, e);
}
}

public boolean isMna(CharSequence text) {
JointClassification jc = this.classifier.classify(text);
String bestCategory = jc.bestCategory();
return "mna".equals(bestCategory);
}

private Class<?> pointcutDeclarationScope;

private Class<?>[] pointcutParameterTypes = new Class<?>[0];

private BeanFactory beanFactory;

private transient ClassLoader pointcutClassLoader;

private transient PointcutExpression pointcutExpression;

private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);

}


@@ -1,7 +1,7 @@
<rules>
<!-- 'sizes' checks -->
<rule>
<key>com.github.sevntu.checkstyle.checks.sizes.LineLengthExtendedCheck</key>
<!-- 'sizes' checks -->
<rule>
<key>com.github.sevntu.checkstyle.checks.sizes.LineLengthExtendedCheck</key>
<name>Line Length Extended</name>
<category name="sizes"/>
<description>Checks for long lines.</description>
Expand Down Expand Up @@ -119,6 +119,13 @@
<description>Maximum number of lines of which block body may consist to be skipped by check.</description>
</param>
</rule>
<rule>
<key>com.github.sevntu.checkstyle.checks.coding.DiamondOperatorForVariableDefinitionCheck</key>
<name>Diamond Operator For Variable Definition</name>
<category name="design"/>
<description>Highlights variable definition statements where diamond operator could be used</description>
<configKey>Checker/TreeWalker/com.github.sevntu.checkstyle.checks.design.DiamondOperatorForVariableDefinitionCheck</configKey>
</rule>
<rule>
<key>com.github.sevntu.checkstyle.checks.design.ForbidWildcardAsReturnTypeCheck</key>
<name>Forbid Wildcard As Return Type</name>
Expand Down Expand Up @@ -292,6 +299,13 @@
<defaultValue></defaultValue>
</param>
</rule>
<rule>
<key>com.github.sevntu.checkstyle.checks.coding.DiamondOperatorForVariableDefinitionCheck</key>
<name>Diamond Operator For Variable Definition</name>
<category name="design"/>
<description>Highlights variable definition statements where diamond operator could be used</description>
<configKey>Checker/TreeWalker/com.github.sevntu.checkstyle.checks.design.DiamondOperatorForVariableDefinitionCheck</configKey>
</rule>
<rule>
<key>com.github.sevntu.checkstyle.checks.coding.EitherLogOrThrowCheck</key>
<name>Either log exception or throw exception</name>
Expand Down

0 comments on commit b79dacc

Please sign in to comment.