From bb52a25c6c5d9d6099713cac6fcacea9e0ec2bdd Mon Sep 17 00:00:00 2001 From: Rick Giles Date: Mon, 7 Jul 2003 09:17:30 +0000 Subject: [PATCH] added check that overriding finalize method calls super.finalize --- docs/config_coding.html | 28 +++ docs/releasenotes.html | 3 + .../checks/coding/AbstractSuperCheck.java | 228 ++++++++++++++++++ .../checks/coding/SuperCloneCheck.java | 188 +-------------- .../checks/coding/SuperFinalizeCheck.java | 51 ++++ .../checkstyle/coding/InputFinalize.java | 44 ++++ .../puppycrawl/tools/checkstyle/AllTests.java | 2 + .../checks/coding/SuperFinalizeCheckTest.java | 19 ++ 8 files changed, 379 insertions(+), 184 deletions(-) create mode 100644 src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck.java create mode 100644 src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheck.java create mode 100644 src/testinputs/com/puppycrawl/tools/checkstyle/coding/InputFinalize.java create mode 100644 src/tests/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheckTest.java diff --git a/docs/config_coding.html b/docs/config_coding.html index 0250b59b6..89e18f059 100644 --- a/docs/config_coding.html +++ b/docs/config_coding.html @@ -79,6 +79,9 @@
  • SuperClone
  • +
  • + SuperFinalize +
  • @@ -870,6 +873,31 @@ return !valid(); TreeWalker

    + +

    SuperFinalize

    Description

    +

    + Checks that an overriding finalize() method invokes super.finalize(). +

    +

    + Reference: Cleaning + Up Unused Objects. +

    +

    Examples

    +

    + To configure the check: +

    +
    +<module name="SuperFinalize"/>
    +      
    +

    Package

    +

    + com.puppycrawl.tools.checkstyle.checks.coding +

    +

    Parent Module

    +

    + TreeWalker +

    + diff --git a/docs/releasenotes.html b/docs/releasenotes.html index 39e658e43..422a56477 100644 --- a/docs/releasenotes.html +++ b/docs/releasenotes.html @@ -112,6 +112,9 @@
  • Added a check that an overriding clone() method invokes super.clone().
  • +
  • Added a check that an overriding finalize() method invokes + super.finalize().
  • +

    diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck.java new file mode 100644 index 000000000..2e186c8e7 --- /dev/null +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck.java @@ -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; + +/** + *

    + * Abstract class for checking that an overriding method with no parameters + * invokes the super method. + *

    + * @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); + } +} diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/SuperCloneCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/SuperCloneCheck.java index 0aec0b4cb..6911553a5 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/SuperCloneCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/SuperCloneCheck.java @@ -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; /** *

    @@ -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"; } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheck.java new file mode 100644 index 000000000..abcbfea3a --- /dev/null +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheck.java @@ -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; + + +/** + *

    + * Checks that an overriding finalize() method invokes super.finalize(). + *

    + *

    + * Reference: + * Cleaning up unused objects. + *

    + *

    + * An example of how to configure the check is: + *

    + *
    + * <module name="SuperFinalize"/>
    + * 
    + * @author Rick Giles + */ +public class SuperFinalizeCheck + extends AbstractSuperCheck +{ + + /** + * @see com.puppycrawl.tools.checkstyle.checks.coding.AbstractSuperCheck + */ + protected String getMethodName() + { + return "finalize"; + } +} diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/coding/InputFinalize.java b/src/testinputs/com/puppycrawl/tools/checkstyle/coding/InputFinalize.java new file mode 100644 index 000000000..4de66643e --- /dev/null +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/coding/InputFinalize.java @@ -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(); + } + } + } +} \ No newline at end of file diff --git a/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java b/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java index f1a6bb9e3..6d05ccd17 100644 --- a/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java +++ b/src/tests/com/puppycrawl/tools/checkstyle/AllTests.java @@ -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)); diff --git a/src/tests/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheckTest.java new file mode 100644 index 000000000..bcf70045a --- /dev/null +++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheckTest.java @@ -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); + } +}