001: ////////////////////////////////////////////////////////////////////////////////
002: // checkstyle: Checks Java source code for adherence to a set of rules.
003: // Copyright (C) 2001-2005 Oliver Burn
004: //
005: // This library is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU Lesser General Public
007: // License as published by the Free Software Foundation; either
008: // version 2.1 of the License, or (at your option) any later version.
009: //
010: // This library is distributed in the hope that it will be useful,
011: // but WITHOUT ANY WARRANTY; without even the implied warranty of
012: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: // Lesser General Public License for more details.
014: //
015: // You should have received a copy of the GNU Lesser General Public
016: // License along with this library; if not, write to the Free Software
017: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: ////////////////////////////////////////////////////////////////////////////////
019: package com.puppycrawl.tools.checkstyle.checks.usage;
020:
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.Set;
024:
025: import com.puppycrawl.tools.checkstyle.api.DetailAST;
026: import com.puppycrawl.tools.checkstyle.api.Scope;
027: import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
028: import com.puppycrawl.tools.checkstyle.api.TokenTypes;
029: import com.puppycrawl.tools.checkstyle.checks.usage.transmogrify.Definition;
030: import com.puppycrawl.tools.checkstyle.checks.usage.transmogrify.Reference;
031: import com.puppycrawl.tools.checkstyle.checks.usage.transmogrify.SymTabAST;
032:
033: /**
034: * <p>Checks that a private field is used in more than one method,
035: * constructor, or initializer.
036: * </p>
037: * <p>
038: * Rationale: a private field used in only one method, constructor, or
039: * initializer should be replaced by a local variable.
040: * </p>
041: * <p>
042: * An example of how to configure the check is:
043: * </p>
044: * <pre>
045: * <module name="usage.OneMethodPrivateField"/>
046: * </pre>
047: *
048: * @author Rick Giles
049: */
050: public class OneMethodPrivateFieldCheck extends AbstractUsageCheck {
051: /** @see com.puppycrawl.tools.checkstyle.api.Check */
052: public int[] getDefaultTokens() {
053: return new int[] { TokenTypes.VARIABLE_DEF, };
054: }
055:
056: /** @see com.puppycrawl.tools.checkstyle.checks.usage.AbstractUsageCheck */
057: public String getErrorKey() {
058: return "one.method.private.field";
059: }
060:
061: /** @see com.puppycrawl.tools.checkstyle.checks.usage.AbstractUsageCheck */
062: public boolean mustCheckReferenceCount(DetailAST aAST) {
063: final DetailAST mods = aAST
064: .findFirstToken(TokenTypes.MODIFIERS);
065: return ((mods != null) && (ScopeUtils.getScopeFromMods(mods) == Scope.PRIVATE));
066: }
067:
068: /** @see com.puppycrawl.tools.checkstyle.checks.usage.AbstractUsageCheck */
069: public void applyTo(Set aNodes) {
070: // apply the check to each private field
071: final Set methods = new HashSet();
072: final Iterator it = aNodes.iterator();
073: while (it.hasNext()) {
074: methods.clear();
075: final DetailAST nameAST = (DetailAST) it.next();
076: // find methods using the field
077: final Iterator refIt = getReferences(nameAST);
078: while (refIt.hasNext()) {
079: final Reference ref = (Reference) refIt.next();
080: final SymTabAST refNode = ref.getTreeNode();
081: final DetailAST refDetail = refNode.getDetailNode();
082: // don't need to check a self-reference
083: if (refDetail == nameAST) {
084: continue;
085: }
086: DetailAST parent = refDetail.getParent();
087: while (parent != null) {
088: final int type = parent.getType();
089: if ((type == TokenTypes.METHOD_DEF)
090: || (type == TokenTypes.CTOR_DEF)
091: || (type == TokenTypes.INSTANCE_INIT)
092: || (type == TokenTypes.STATIC_INIT)) {
093: methods.add(parent);
094: break;
095: }
096: // initializer for inner class?
097: else if (type == TokenTypes.CLASS_DEF) {
098: break;
099: }
100: parent = parent.getParent();
101: }
102: }
103: if (methods.size() == 1) {
104: log(nameAST.getLineNo(), nameAST.getColumnNo(),
105: getErrorKey(), nameAST.getText());
106: }
107: }
108: }
109:
110: /**
111: * Returns the references to an AST.
112: * @param aAST the AST for the references.
113: * @return an iterator for the references to aAST.
114: */
115: private Iterator getReferences(DetailAST aAST) {
116: final SymTabAST ident = getASTManager().get(aAST);
117: final Definition definition = (Definition) ident
118: .getDefinition();
119: if (definition != null) {
120: return definition.getReferences();
121: }
122: final Set dummy = new HashSet();
123: return dummy.iterator();
124: }
125: }
|