//////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. // Copyright (C) 2001-2005 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.usage; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.Scope; import com.puppycrawl.tools.checkstyle.api.ScopeUtils; import com.puppycrawl.tools.checkstyle.api.TokenTypes; /** * <p>Checks that a private method is used. * </p> * <p> * An example of how to configure the check is: * </p> * <pre> * <module name="usage.UnusedPrivateMethod"/> * </pre> * * @author Rick Giles */ public class UnusedPrivateMethodCheck extends AbstractUsageCheck { /** Controls if checks skips serialization methods.*/ private boolean mAllowSerializationMethods; /** @see com.puppycrawl.tools.checkstyle.api.Check */ public int[] getDefaultTokens() { return new int[] { TokenTypes.METHOD_DEF, }; } /** @see com.puppycrawl.tools.checkstyle.checks.usage.AbstractUsageCheck */ public String getErrorKey() { return "unused.method"; } /** * Configure the check to allow (or not) serialization-related methods. * @param aFlag new value for allowSerializationMethods value. */ public void setAllowSerializationMethods(boolean aFlag) { mAllowSerializationMethods = aFlag; } /** @see com.puppycrawl.tools.checkstyle.checks.usage.AbstractUsageCheck */ public boolean mustCheckReferenceCount(DetailAST aAST) { final DetailAST mods = aAST.findFirstToken(TokenTypes.MODIFIERS); if ((mods == null) || (ScopeUtils.getScopeFromMods(mods) != Scope.PRIVATE)) { return false; } return !mAllowSerializationMethods || !(isWriteObject(aAST) || isReadObject(aAST) || isWriteReplaceOrReadResolve(aAST)); } /** * Checks if a given method is writeObject(). * @param aAST method def to check * @return true if this is a writeObject() definition */ private boolean isWriteObject(DetailAST aAST) { // name is writeObject... final DetailAST ident = aAST.findFirstToken(TokenTypes.IDENT); if (!"writeObject".equals(ident.getText())) { return false; } // returns void... final DetailAST typeAST = (DetailAST) aAST.findFirstToken(TokenTypes.TYPE).getFirstChild(); if (typeAST.getType() != TokenTypes.LITERAL_VOID) { return false; } // should have one parameter... final DetailAST params = aAST.findFirstToken(TokenTypes.PARAMETERS); if (params == null || params.getChildCount() != 1) { return false; } // and paramter's type should be java.io.ObjectOutputStream final DetailAST type = (DetailAST) ((DetailAST) params.getFirstChild()) .findFirstToken(TokenTypes.TYPE).getFirstChild(); final String typeName = FullIdent.createFullIdent(type).getText(); if (!"java.io.ObjectOutputStream".equals(typeName) && !"ObjectOutputStream".equals(typeName)) { return false; } // and, finally, it should throws java.io.IOException final DetailAST throwsAST = aAST.findFirstToken(TokenTypes.LITERAL_THROWS); if (throwsAST == null || throwsAST.getChildCount() != 1) { return false; } final DetailAST expt = (DetailAST) throwsAST.getFirstChild(); final String exceptionName = FullIdent.createFullIdent(expt).getText(); if (!"java.io.IOException".equals(exceptionName) && !"IOException".equals(exceptionName)) { return false; } return true; } /** * Checks if a given method is readObject(). * @param aAST method def to check * @return true if this is a readObject() definition */ private boolean isReadObject(DetailAST aAST) { // name is readObject... final DetailAST ident = aAST.findFirstToken(TokenTypes.IDENT); if (!"readObject".equals(ident.getText())) { return false; } // returns void... final DetailAST typeAST = (DetailAST) aAST.findFirstToken(TokenTypes.TYPE).getFirstChild(); if (typeAST.getType() != TokenTypes.LITERAL_VOID) { return false; } // should have one parameter... final DetailAST params = aAST.findFirstToken(TokenTypes.PARAMETERS); if (params == null || params.getChildCount() != 1) { return false; } // and paramter's type should be java.io.ObjectInputStream final DetailAST type = (DetailAST) ((DetailAST) params.getFirstChild()) .findFirstToken(TokenTypes.TYPE).getFirstChild(); final String typeName = FullIdent.createFullIdent(type).getText(); if (!"java.io.ObjectInputStream".equals(typeName) && !"ObjectInputStream".equals(typeName)) { return false; } // and, finally, it should throws java.io.IOException // and java.lang.ClassNotFoundException final DetailAST throwsAST = aAST.findFirstToken(TokenTypes.LITERAL_THROWS); if (throwsAST == null || throwsAST.getChildCount() != 3) { return false; } final DetailAST excpt1 = (DetailAST) throwsAST.getFirstChild(); final String exception1 = FullIdent.createFullIdent(excpt1).getText(); final String exception2 = FullIdent.createFullIdent(throwsAST.getLastChild()).getText(); if (!"java.io.IOException".equals(exception1) && !"IOException".equals(exception1) && !"java.io.IOException".equals(exception2) && !"IOException".equals(exception2) || !"java.lang.ClassNotFoundException".equals(exception1) && !"ClassNotFoundException".equals(exception1) && !"java.lang.ClassNotFoundException".equals(exception2) && !"ClassNotFoundException".equals(exception2)) { return false; } return true; } /** * Checks if a given method is writeReplace() or readResolve(). * @param aAST method def to check * @return true if this is a writeReplace() definition */ private boolean isWriteReplaceOrReadResolve(DetailAST aAST) { // name is writeReplace or readResolve... final DetailAST ident = aAST.findFirstToken(TokenTypes.IDENT); if (!"writeReplace".equals(ident.getText()) && !"readResolve".equals(ident.getText())) { return false; } // returns Object... final DetailAST typeAST = (DetailAST) aAST.findFirstToken(TokenTypes.TYPE).getFirstChild(); if (typeAST.getType() != TokenTypes.DOT && typeAST.getType() != TokenTypes.IDENT) { return false; } // should have no parameters... final DetailAST params = aAST.findFirstToken(TokenTypes.PARAMETERS); if (params != null && params.getChildCount() != 0) { return false; } // and, finally, it should throws java.io.ObjectStreamException final DetailAST throwsAST = aAST.findFirstToken(TokenTypes.LITERAL_THROWS); if (throwsAST == null || throwsAST.getChildCount() != 1) { return false; } final DetailAST excpt = (DetailAST) throwsAST.getFirstChild(); final String exception = FullIdent.createFullIdent(excpt).getText(); if (!"java.io.ObjectStreamException".equals(exception) && !"ObjectStreamException".equals(exception)) { return false; } return true; } }