Enhanced the MethodName check to detect when a method name is the same as the residing class name. Thanks to Travis Schneeberger for providing patch #1892364.

This commit is contained in:
Oliver Burn 2008-04-21 12:22:40 +00:00
parent b81ed9788d
commit 7cb8afb266
7 changed files with 199 additions and 12 deletions

View File

@ -18,6 +18,7 @@
////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle.checks.naming;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
/**
@ -28,6 +29,14 @@ import com.puppycrawl.tools.checkstyle.api.TokenTypes;
* and defaults to
* <strong>^[a-z][a-zA-Z0-9]*$</strong>.
* </p>
*
* <p>
* Also, checks if a method name has the same name as the residing class.
* The default is false (it is not allowed). It is legal in Java to have
* method with the same name as a class. As long as a return type is specified
* it is a method and not a constructor which it could be easily confused as.
* </p>
*
* <p>
* An example of how to configure the check is:
* </p>
@ -43,12 +52,27 @@ import com.puppycrawl.tools.checkstyle.api.TokenTypes;
* &lt;property name="format" value="^[a-z](_?[a-zA-Z0-9]+)*$"/&gt;
* &lt;/module&gt;
* </pre>
*
* <p>
* An example of how to configure the check to allow method names
* to be equal to the residing class name is:
* </p>
* <pre>
* &lt;module name="MethodName"&gt;
* &lt;property name="allowClassName" value="true"/&gt;
* &lt;/module&gt;
* </pre>
* @author Oliver Burn
* @version 1.0
* @author Travis Schneeberger
* @version 1.1
*/
public class MethodNameCheck
extends AbstractAccessControlNameCheck
public class MethodNameCheck extends AbstractNameCheck
{
/**
* for allowing method name to be the same as the class name.
*/
private boolean mAllowClassName;
/** Creates a new <code>MethodNameCheck</code> instance. */
public MethodNameCheck()
{
@ -58,6 +82,35 @@ public class MethodNameCheck
@Override
public int[] getDefaultTokens()
{
return new int[] {TokenTypes.METHOD_DEF};
return new int[] {TokenTypes.METHOD_DEF, };
}
@Override
public void visitToken(DetailAST aAst)
{
super.visitToken(aAst); // Will check the name against the format.
if (!mAllowClassName) {
final DetailAST method =
aAst.findFirstToken(TokenTypes.IDENT);
//in all cases this will be the classDef type except anon inner
//with anon inner classes this will be the Literal_New keyword
final DetailAST classDefOrNew = aAst.getParent().getParent();
final DetailAST classIdent =
classDefOrNew.findFirstToken(TokenTypes.IDENT);
if (method.getText().equals(classIdent.getText())) {
log(method.getLineNo(), method.getColumnNo(),
"method.name.equals.class.name", method.getText());
}
}
}
/**
* Sets the property for allowing a method to be the same name as a class.
* @param aAllowClassName true to allow false to disallow
*/
public void setAllowClassName(boolean aAllowClassName)
{
mAllowClassName = aAllowClassName;
}
}

View File

@ -1,2 +1,3 @@
name.invalidPattern=Name ''{0}'' must match pattern ''{1}''.
illegal.abstract.class.name=Name ''{0}'' must match pattern ''{1}''.
method.name.equals.class.name=Method Name ''{0}'' must not equal the enclosing class name.

View File

@ -0,0 +1,51 @@
package com.puppycrawl.tools.checkstyle;
/**
* Test input for MethodNameCheck specifically
* whether the method name equals the class name.
*
* @author Travis Schneeberger
*/
public class InputMethNameEqualClsName {
//illegal name
public int InputMethNameEqualClsName() {
return 0;
}
class Inner {
//illegal name
public int Inner() {
return 0;
}
//OK name - name of the outter class's ctor
public int InputMethNameEqualClsName() {
return 0;
}
}
public void anotherMethod() {
new InputMethNameEqualClsName() {
//illegal name
public int InputMethNameEqualClsName() {
return 1;
}
};
}
}
interface SweetInterface {
//illegal name
int SweetInterface();
}
class Outter {
//illegal name
public void Outter() {
}
}

View File

@ -18,4 +18,46 @@ public class MethodNameCheckTest
};
verify(checkConfig, getPath("InputSimple.java"), expected);
}
@Test
public void testMethodEqClass() throws Exception
{
final DefaultConfiguration checkConfig =
createCheckConfig(MethodNameCheck.class);
final String[] expected = {
"12:16: Method Name 'InputMethNameEqualClsName' must not equal the enclosing class name.",
"12:16: Name 'InputMethNameEqualClsName' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"18:20: Method Name 'Inner' must not equal the enclosing class name.",
"18:20: Name 'Inner' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"23:20: Name 'InputMethNameEqualClsName' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"32:24: Method Name 'InputMethNameEqualClsName' must not equal the enclosing class name.",
"32:24: Name 'InputMethNameEqualClsName' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"42:9: Method Name 'SweetInterface' must not equal the enclosing class name.",
"42:9: Name 'SweetInterface' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"48:17: Method Name 'Outter' must not equal the enclosing class name.",
"48:17: Name 'Outter' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
verify(checkConfig, getPath("InputMethNameEqualClsName.java"), expected);
}
@Test
public void testMethodEqClassAllow() throws Exception
{
final DefaultConfiguration checkConfig =
createCheckConfig(MethodNameCheck.class);
checkConfig.addAttribute("allowClassName", "true"); //allow method names and class names to equal
final String[] expected = {
"12:16: Name 'InputMethNameEqualClsName' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"18:20: Name 'Inner' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"23:20: Name 'InputMethNameEqualClsName' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"32:24: Name 'InputMethNameEqualClsName' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"42:9: Name 'SweetInterface' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
"48:17: Name 'Outter' must match pattern '^[a-z][a-zA-Z0-9]*$'.",
};
verify(checkConfig, getPath("InputMethNameEqualClsName.java"), expected);
}
}

View File

@ -18,17 +18,17 @@
href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">
regular expression</a> for valid identifiers. This is an example of a
configuration of the <span class="code">MemberName</span> module to
ensure that member identifiers begin with
ensure that member identifiers begin with
<span class="code">&#39;m&#39;</span>, followed
by an upper case letter, and then letters and digits:
</p>
<source>
&lt;module name=&quot;MemberName&quot;&gt;
&lt;property name=&quot;format&quot; value=&quot;^m[A-Z][a-zA-Z0-9]*$&quot;/&gt;
&lt;/module&gt;
</source>
<p>
All naming modules belong to package <span
class="code">com.puppycrawl.tools.checkstyle.checks.naming</span> and
@ -141,7 +141,7 @@
clause parameters begin with <span class="code">"e"</span>, followed
by letters and digits:
</p>
<source>
&lt;module name=&quot;LocalVariableName&quot;&gt;
&lt;property name=&quot;format&quot; value=&quot;^e[a-zA-Z0-9]*$&quot;/&gt;
@ -169,10 +169,12 @@
</source>
<p>
Module <span class="code">MemberName</span> also has the following
properties:
The modules <span class="code">ConstantName</span>, <span
class="code">MemberName</span>, <span
class="code">StaticVariableName</span> and <span
class="code">TypeName</span> also have the following properties:
</p>
<table>
<tr>
<th>name</th>
@ -207,6 +209,38 @@
<td><span class="default">true</span></td>
</tr>
</table>
<p>
Module <span class="code">MethodName</span> also has the following
properties:
</p>
<table>
<tr>
<th>name</th>
<th>description</th>
<th>type</th>
<th>default value</th>
</tr>
<tr>
<td>allowClassName</td>
<td>
Controls whether to allow a method name to have the same
name as the residing class name. This is not to be confused
with a constructor. An easy mistake is to place a return
type on a constructor declaration which turns it into a
method. For example:
<pre>
class MyClass {
public void MyClass() {} //this is a method
public MyClass() {} //this is a constructor
}
</pre>
</td>
<td><a href="property_types.html#boolean">Boolean</a></td>
<td><span class="default">false</span></td>
</tr>
</table>
</section>
</body>
</document>

View File

@ -65,6 +65,12 @@
for ensuring there are no static import statements. Thanks to
Travis Schneeberger for providing patch #1940611.
</li>
<li>
Enhanced the <a href="config_naming.html">MethodName</a> check
to detect when a method name is the same as the residing class
name. Thanks to Travis Schneeberger for providing patch
#1892364.
</li>
</ul>
<p>Fixed Bugs:</p>

View File

@ -322,7 +322,7 @@
<div class="csBottomBar">
<div class="csBottomBarContents">
Copyright &copy; 2001-2007, Oliver Burn
Copyright &copy; 2001-2008, Oliver Burn
</div>
</div>
</body>