added check that overriding finalize method calls super.finalize
This commit is contained in:
parent
18718ffeab
commit
bb52a25c6c
|
|
@ -79,6 +79,9 @@
|
|||
<li>
|
||||
<a href="#SuperClone">SuperClone</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#SuperFinalize">SuperFinalize</a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<!--Content-->
|
||||
|
|
@ -870,6 +873,31 @@ return !valid();
|
|||
<a href="config.html#treewalker">TreeWalker</a>
|
||||
</p>
|
||||
|
||||
|
||||
<!-- --> <a name="SuperFinalize"></a> <h2>SuperFinalize</h2> <h4>Description</h4>
|
||||
<p class="body">
|
||||
Checks that an overriding <span class="code">finalize()</span> method invokes <span class="code">super.finalize()</span>.
|
||||
</p>
|
||||
<p class="body">
|
||||
Reference: <a href="http://java.sun.com/docs/books/tutorial/java/data/garbagecollection.html">Cleaning
|
||||
Up Unused Objects</a>.
|
||||
</p>
|
||||
<h4>Examples</h4>
|
||||
<p class="body">
|
||||
To configure the check:
|
||||
</p>
|
||||
<pre class="body">
|
||||
<module name="SuperFinalize"/>
|
||||
</pre>
|
||||
<h4>Package</h4>
|
||||
<p class="body">
|
||||
com.puppycrawl.tools.checkstyle.checks.coding
|
||||
</p>
|
||||
<h4>Parent Module</h4>
|
||||
<p class="body">
|
||||
<a href="config.html#treewalker">TreeWalker</a>
|
||||
</p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -112,6 +112,9 @@
|
|||
<li class="body">Added a check that an overriding clone() method invokes
|
||||
super.clone().</li>
|
||||
|
||||
<li class="body">Added a check that an overriding finalize() method invokes
|
||||
super.finalize().</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p class="body">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,228 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// checkstyle: Checks Java source code for adherence to a set of rules.
|
||||
// Copyright (C) 2001-2003 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.LinkedList;
|
||||
|
||||
import antlr.collections.AST;
|
||||
|
||||
import com.puppycrawl.tools.checkstyle.api.Check;
|
||||
import com.puppycrawl.tools.checkstyle.api.DetailAST;
|
||||
import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
|
||||
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Abstract class for checking that an overriding method with no parameters
|
||||
* invokes the super method.
|
||||
* </p>
|
||||
* @author Rick Giles
|
||||
*/
|
||||
public abstract class AbstractSuperCheck
|
||||
extends Check
|
||||
{
|
||||
/**
|
||||
* Stack node for a method definition and a record of
|
||||
* whether the method has a call to the super method.
|
||||
* @author Rick Giles
|
||||
*/
|
||||
private class MethodNode
|
||||
{
|
||||
/** method definition */
|
||||
private DetailAST mMethod;
|
||||
|
||||
/** true if the overriding method calls the super method */
|
||||
private boolean mCallsSuper;
|
||||
|
||||
/**
|
||||
* Constructs a stack node for a method definition.
|
||||
* @param aAST AST for the method definition.
|
||||
*/
|
||||
public MethodNode(DetailAST aAST)
|
||||
{
|
||||
mMethod = aAST;
|
||||
mCallsSuper = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the overriding method has a call to the super method.
|
||||
*/
|
||||
public void setCallsSuper()
|
||||
{
|
||||
mCallsSuper = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the overriding method has a call to the super
|
||||
* method.
|
||||
* @return true if the overriding method has a call to the super
|
||||
* method.
|
||||
*/
|
||||
public boolean getCallsSuper()
|
||||
{
|
||||
return mCallsSuper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the overriding method definition AST.
|
||||
* @return the overriding method definition AST.
|
||||
*/
|
||||
public DetailAST getMethod()
|
||||
{
|
||||
return mMethod;
|
||||
}
|
||||
}
|
||||
|
||||
/** stack of methods */
|
||||
private final LinkedList mMethodStack = new LinkedList();
|
||||
|
||||
/** @see Check */
|
||||
public int[] getDefaultTokens()
|
||||
{
|
||||
return new int[] {
|
||||
TokenTypes.METHOD_DEF,
|
||||
TokenTypes.LITERAL_SUPER,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the overriding method.
|
||||
* @return the name of the overriding method.
|
||||
*/
|
||||
protected abstract String getMethodName();
|
||||
|
||||
/**
|
||||
*
|
||||
* @see com.puppycrawl.tools.checkstyle.api.Check
|
||||
*/
|
||||
public void beginTree(DetailAST aRootAST)
|
||||
{
|
||||
mMethodStack.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see com.puppycrawl.tools.checkstyle.api.Check
|
||||
*/
|
||||
public void visitToken(DetailAST aAST)
|
||||
{
|
||||
if (isOverridingMethod(aAST)) {
|
||||
mMethodStack.add(new MethodNode(aAST));
|
||||
}
|
||||
else if (isSuperCall(aAST)) {
|
||||
final MethodNode methodNode = (MethodNode) mMethodStack.getLast();
|
||||
methodNode.setCallsSuper();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a 'super' literal is a call to the super method
|
||||
* for this check.
|
||||
* @param aAST the AST node of a 'super' literal.
|
||||
* @return true if aAST is a call to the super method
|
||||
* for this check.
|
||||
*/
|
||||
private boolean isSuperCall(DetailAST aAST)
|
||||
{
|
||||
if (aAST.getType() != TokenTypes.LITERAL_SUPER) {
|
||||
return false;
|
||||
}
|
||||
// dot operator?
|
||||
DetailAST parent = aAST.getParent();
|
||||
if ((parent == null) || (parent.getType() != TokenTypes.DOT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// same name of method?
|
||||
final AST sibling = aAST.getNextSibling();
|
||||
if ((sibling == null) || (sibling.getType() != TokenTypes.IDENT)) {
|
||||
return false;
|
||||
}
|
||||
final String name = sibling.getText();
|
||||
if (!getMethodName().equals(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0 parameters?
|
||||
final DetailAST args = (DetailAST) parent.getNextSibling();
|
||||
if ((args == null) || (args.getType() != TokenTypes.ELIST)) {
|
||||
return false;
|
||||
}
|
||||
if (args.getChildCount() != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// in an overriding method for this check?
|
||||
while (parent != null) {
|
||||
if (parent.getType() == TokenTypes.METHOD_DEF) {
|
||||
return isOverridingMethod(parent);
|
||||
}
|
||||
else if ((parent.getType() == TokenTypes.CTOR_DEF)
|
||||
|| (parent.getType() == TokenTypes.INSTANCE_INIT))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see com.puppycrawl.tools.checkstyle.api.Check
|
||||
*/
|
||||
public void leaveToken(DetailAST aAST)
|
||||
{
|
||||
if (isOverridingMethod(aAST)) {
|
||||
final MethodNode methodNode =
|
||||
(MethodNode) mMethodStack.removeLast();
|
||||
if (!methodNode.getCallsSuper()) {
|
||||
final DetailAST methodAST = methodNode.getMethod();
|
||||
final DetailAST nameAST =
|
||||
methodAST.findFirstToken(TokenTypes.IDENT);
|
||||
log(nameAST.getLineNo(), nameAST.getColumnNo(),
|
||||
"missing.super.call",
|
||||
new Object[] {nameAST.getText()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an AST is a method definition for this check,
|
||||
* with 0 parameters.
|
||||
* @param aAST the method definition AST.
|
||||
* @return true if the method of aAST is a method for this check.
|
||||
*/
|
||||
private boolean isOverridingMethod(DetailAST aAST)
|
||||
{
|
||||
if ((aAST.getType() != TokenTypes.METHOD_DEF)
|
||||
|| ScopeUtils.inInterfaceBlock(aAST))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final DetailAST nameAST = aAST.findFirstToken(TokenTypes.IDENT);
|
||||
final String name = nameAST.getText();
|
||||
if (!getMethodName().equals(name)) {
|
||||
return false;
|
||||
}
|
||||
final DetailAST params = aAST.findFirstToken(TokenTypes.PARAMETERS);
|
||||
return (params.getChildCount() == 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,14 +19,6 @@
|
|||
|
||||
package com.puppycrawl.tools.checkstyle.checks.coding;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import antlr.collections.AST;
|
||||
|
||||
import com.puppycrawl.tools.checkstyle.api.Check;
|
||||
import com.puppycrawl.tools.checkstyle.api.DetailAST;
|
||||
import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
|
||||
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
|
@ -46,186 +38,14 @@ import com.puppycrawl.tools.checkstyle.api.TokenTypes;
|
|||
* @author Rick Giles
|
||||
*/
|
||||
public class SuperCloneCheck
|
||||
extends Check
|
||||
extends AbstractSuperCheck
|
||||
{
|
||||
/**
|
||||
* Stack node for a clone method definition and a record of
|
||||
* whether the clone method has a call to super.clone().
|
||||
* @author Rick Giles
|
||||
*/
|
||||
private class CloneNode
|
||||
{
|
||||
/** clone method definition */
|
||||
private DetailAST mCloneMethod;
|
||||
|
||||
/** true if the clone method calls super.clone() */
|
||||
private boolean mCallsSuper;
|
||||
|
||||
/**
|
||||
* Constructs a stack node for a clone method definition.
|
||||
* @param aAST AST for the clone method definition.
|
||||
*/
|
||||
public CloneNode(DetailAST aAST)
|
||||
{
|
||||
mCloneMethod = aAST;
|
||||
mCallsSuper = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the clone method has a call to super.clone().
|
||||
*/
|
||||
public void setCallsSuper()
|
||||
{
|
||||
mCallsSuper = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the clone method has a call to
|
||||
* super.clone().
|
||||
* @return true if the clone method has a call to
|
||||
* super.clone().
|
||||
*/
|
||||
public boolean getCallsSuper()
|
||||
{
|
||||
return mCallsSuper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the clone method definition AST.
|
||||
* @return the clone method definition AST.
|
||||
*/
|
||||
public DetailAST getCloneMethod()
|
||||
{
|
||||
return mCloneMethod;
|
||||
}
|
||||
}
|
||||
|
||||
/** stack of clone methods */
|
||||
private final LinkedList mCloneStack = new LinkedList();
|
||||
|
||||
/** @see Check */
|
||||
public int[] getDefaultTokens()
|
||||
{
|
||||
return new int[] {
|
||||
TokenTypes.METHOD_DEF,
|
||||
TokenTypes.LITERAL_SUPER,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see com.puppycrawl.tools.checkstyle.api.Check
|
||||
* @see com.puppycrawl.tools.checkstyle.checks.coding.AbstractSuperCheck
|
||||
*/
|
||||
public void beginTree(DetailAST aRootAST)
|
||||
protected String getMethodName()
|
||||
{
|
||||
mCloneStack.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see com.puppycrawl.tools.checkstyle.api.Check
|
||||
*/
|
||||
public void visitToken(DetailAST aAST)
|
||||
{
|
||||
if (isCloneMethod(aAST)) {
|
||||
mCloneStack.add(new CloneNode(aAST));
|
||||
}
|
||||
else if (isSuperClone(aAST)) {
|
||||
final CloneNode cloneNode = (CloneNode) mCloneStack.getLast();
|
||||
cloneNode.setCallsSuper();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a 'super' literal calls super.clone()
|
||||
* within a clone() method.
|
||||
* @param aAST the AST node for a 'super' literal.
|
||||
* @return true if aAST is a call to super.clone within a
|
||||
* clone() method.
|
||||
*/
|
||||
private boolean isSuperClone(DetailAST aAST)
|
||||
{
|
||||
if (aAST.getType() != TokenTypes.LITERAL_SUPER) {
|
||||
return false;
|
||||
}
|
||||
// dot operator?
|
||||
DetailAST parent = aAST.getParent();
|
||||
if ((parent == null) || (parent.getType() != TokenTypes.DOT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// named 'clone'?
|
||||
final AST sibling = aAST.getNextSibling();
|
||||
if ((sibling == null) || (sibling.getType() != TokenTypes.IDENT)) {
|
||||
return false;
|
||||
}
|
||||
final String name = sibling.getText();
|
||||
if (!"clone".equals(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0 parameters?
|
||||
final DetailAST args = (DetailAST) parent.getNextSibling();
|
||||
if ((args == null) || (args.getType() != TokenTypes.ELIST)) {
|
||||
return false;
|
||||
}
|
||||
if (args.getChildCount() != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// in a clone() method?
|
||||
while (parent != null) {
|
||||
if (parent.getType() == TokenTypes.METHOD_DEF) {
|
||||
return isCloneMethod(parent);
|
||||
}
|
||||
else if ((parent.getType() == TokenTypes.CTOR_DEF)
|
||||
|| (parent.getType() == TokenTypes.INSTANCE_INIT))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see com.puppycrawl.tools.checkstyle.api.Check
|
||||
*/
|
||||
public void leaveToken(DetailAST aAST)
|
||||
{
|
||||
if (isCloneMethod(aAST)) {
|
||||
final CloneNode cloneNode = (CloneNode) mCloneStack.removeLast();
|
||||
if (!cloneNode.getCallsSuper()) {
|
||||
final DetailAST methodAST = cloneNode.getCloneMethod();
|
||||
final DetailAST nameAST =
|
||||
methodAST.findFirstToken(TokenTypes.IDENT);
|
||||
log(nameAST.getLineNo(), nameAST.getColumnNo(),
|
||||
"missing.super.call",
|
||||
new Object[] {nameAST.getText()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an AST is a class clone method definition,
|
||||
* i.e. defines a method clone' and 0 parameters.
|
||||
* @param aAST the method definition AST.
|
||||
* @return true if the method of aAST is clone().
|
||||
*/
|
||||
private boolean isCloneMethod(DetailAST aAST)
|
||||
{
|
||||
if ((aAST.getType() != TokenTypes.METHOD_DEF)
|
||||
|| ScopeUtils.inInterfaceBlock(aAST))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final DetailAST nameAST = aAST.findFirstToken(TokenTypes.IDENT);
|
||||
final String name = nameAST.getText();
|
||||
if (!"clone".equals(name)) {
|
||||
return false;
|
||||
}
|
||||
final DetailAST params = aAST.findFirstToken(TokenTypes.PARAMETERS);
|
||||
return (params.getChildCount() == 0);
|
||||
return "clone";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// checkstyle: Checks Java source code for adherence to a set of rules.
|
||||
// Copyright (C) 2001-2003 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;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Checks that an overriding finalize() method invokes super.finalize().
|
||||
* </p>
|
||||
* <p>
|
||||
* Reference:<a
|
||||
* href="http://java.sun.com/docs/books/tutorial/java/data/garbagecollection.html">
|
||||
* Cleaning up unused objects</a>.
|
||||
* </p>
|
||||
* <p>
|
||||
* An example of how to configure the check is:
|
||||
* </p>
|
||||
* <pre>
|
||||
* <module name="SuperFinalize"/>
|
||||
* </pre>
|
||||
* @author Rick Giles
|
||||
*/
|
||||
public class SuperFinalizeCheck
|
||||
extends AbstractSuperCheck
|
||||
{
|
||||
|
||||
/**
|
||||
* @see com.puppycrawl.tools.checkstyle.checks.coding.AbstractSuperCheck
|
||||
*/
|
||||
protected String getMethodName()
|
||||
{
|
||||
return "finalize";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.puppycrawl.tools.checkstyle.coding;
|
||||
public class InputFinalize
|
||||
{
|
||||
public InputFinalize() throws Throwable
|
||||
{
|
||||
super.equals(new String());
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public void finalize() throws Throwable
|
||||
{
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public void method() throws Throwable
|
||||
{
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
{
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
class NoSuperFinalize
|
||||
{
|
||||
public void finalize()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class InnerFinalize
|
||||
{
|
||||
public void finalize()
|
||||
{
|
||||
class Inner
|
||||
{
|
||||
public void finalize() throws Throwable
|
||||
{
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ import com.puppycrawl.tools.checkstyle.checks.coding.SimplifyBooleanExpressionCh
|
|||
import com.puppycrawl.tools.checkstyle.checks.coding.SimplifyBooleanReturnCheckTest;
|
||||
import com.puppycrawl.tools.checkstyle.checks.coding.StringLiteralEqualityCheckTest;
|
||||
import com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest;
|
||||
import com.puppycrawl.tools.checkstyle.checks.coding.SuperFinalizeCheckTest;
|
||||
import com.puppycrawl.tools.checkstyle.checks.design.DesignForExtensionCheckTest;
|
||||
import com.puppycrawl.tools.checkstyle.checks.design.FinalClassCheckTest;
|
||||
import com.puppycrawl.tools.checkstyle.checks.design.HideUtilityClassConstructorCheckTest;
|
||||
|
|
@ -171,6 +172,7 @@ public class AllTests {
|
|||
suite.addTest(new TestSuite(StringArrayReaderTest.class));
|
||||
suite.addTest(new TestSuite(StringLiteralEqualityCheckTest.class));
|
||||
suite.addTest(new TestSuite(SuperCloneCheckTest.class));
|
||||
suite.addTest(new TestSuite(SuperFinalizeCheckTest.class));
|
||||
suite.addTest(new TestSuite(TabCharacterCheckTest.class));
|
||||
suite.addTest(new TestSuite(TodoCommentCheckTest.class));
|
||||
suite.addTest(new TestSuite(TranslationCheckTest.class));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
package com.puppycrawl.tools.checkstyle.checks.coding;
|
||||
|
||||
import com.puppycrawl.tools.checkstyle.BaseCheckTestCase;
|
||||
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
|
||||
|
||||
public class SuperFinalizeCheckTest
|
||||
extends BaseCheckTestCase
|
||||
{
|
||||
public void testIt() throws Exception
|
||||
{
|
||||
final DefaultConfiguration checkConfig =
|
||||
createCheckConfig(SuperFinalizeCheck.class);
|
||||
final String[] expected = {
|
||||
"27:17: Method 'finalize' should call 'super.finalize'.",
|
||||
"34:17: Method 'finalize' should call 'super.finalize'.",
|
||||
};
|
||||
verify(checkConfig, getPath("coding/InputFinalize.java"), expected);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue