001: ////////////////////////////////////////////////////////////////////////////////
002: // checkstyle: Checks Java source code for adherence to a set of rules.
003: // Copyright (C) 2001-2007 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:
020: package com.puppycrawl.tools.checkstyle.checks.coding;
021:
022: import antlr.collections.AST;
023: import com.puppycrawl.tools.checkstyle.api.Check;
024: import com.puppycrawl.tools.checkstyle.api.TokenTypes;
025: import com.puppycrawl.tools.checkstyle.api.DetailAST;
026:
027: /**
028: * <p>
029: * Checks for overly complicated boolean return statements.
030: * Idea shamelessly stolen from the equivalent PMD rule (pmd.sourceforge.net).
031: * </p>
032: * <p>
033: * An example of how to configure the check is:
034: * </p>
035: * <pre>
036: * <module name="SimplifyBooleanReturn"/>
037: * </pre>
038: * @author Lars Kühne
039: */
040: public class SimplifyBooleanReturnCheck extends Check {
041: /** {@inheritDoc} */
042: public int[] getDefaultTokens() {
043: return new int[] { TokenTypes.LITERAL_IF };
044: }
045:
046: /** {@inheritDoc} */
047: public void visitToken(DetailAST aAST) {
048: // LITERAL_IF has the following four or five children:
049: // '('
050: // condition
051: // ')'
052: // thenStatement
053: // [ LITERAL_ELSE (with the elseStatement as a child) ]
054:
055: // don't bother if this is not if then else
056: final AST elseLiteral = aAST
057: .findFirstToken(TokenTypes.LITERAL_ELSE);
058: if (elseLiteral == null) {
059: return;
060: }
061: final AST elseStatement = elseLiteral.getFirstChild();
062:
063: // skip '(' and ')'
064: // TODO: Introduce helpers in DetailAST
065: final AST condition = aAST.getFirstChild().getNextSibling();
066: final AST thenStatement = condition.getNextSibling()
067: .getNextSibling();
068:
069: if (returnsOnlyBooleanLiteral(thenStatement)
070: && returnsOnlyBooleanLiteral(elseStatement)) {
071: log(aAST.getLineNo(), aAST.getColumnNo(),
072: "simplify.boolreturn");
073: }
074: }
075:
076: /**
077: * Returns if an AST is a return statment with a boolean literal
078: * or a compound statement that contains only such a return statement.
079: *
080: * Returns <code>true</code> iff aAST represents
081: * <br>
082: * <pre>
083: * return true/false;
084: * <pre>
085: * or
086: * <br>
087: * <pre>
088: * {
089: * return true/false;
090: * }
091: * <pre>
092: *
093: * @param aAST the sytax tree to check
094: * @return if aAST is a return statment with a boolean literal.
095: */
096: private static boolean returnsOnlyBooleanLiteral(AST aAST) {
097: if (isBooleanLiteralReturnStatement(aAST)) {
098: return true;
099: }
100:
101: final AST firstStmnt = aAST.getFirstChild();
102: return isBooleanLiteralReturnStatement(firstStmnt);
103: }
104:
105: /**
106: * Returns if an AST is a return statment with a boolean literal.
107: *
108: * Returns <code>true</code> iff aAST represents
109: * <br>
110: * <pre>
111: * return true/false;
112: * <pre>
113: *
114: * @param aAST the sytax tree to check
115: * @return if aAST is a return statment with a boolean literal.
116: */
117: private static boolean isBooleanLiteralReturnStatement(AST aAST) {
118: if ((aAST == null)
119: || (aAST.getType() != TokenTypes.LITERAL_RETURN)) {
120: return false;
121: }
122:
123: final AST expr = aAST.getFirstChild();
124:
125: if ((expr == null) || (expr.getType() == TokenTypes.SEMI)) {
126: return false;
127: }
128:
129: final AST value = expr.getFirstChild();
130: return isBooleanLiteralType(value.getType());
131: }
132:
133: /**
134: * Checks if a token type is a literal true or false.
135: * @param aTokenType the TokenType
136: * @return true iff aTokenType is LITERAL_TRUE or LITERAL_FALSE
137: */
138: private static boolean isBooleanLiteralType(final int aTokenType) {
139: final boolean isTrue = (aTokenType == TokenTypes.LITERAL_TRUE);
140: final boolean isFalse = (aTokenType == TokenTypes.LITERAL_FALSE);
141: return isTrue || isFalse;
142: }
143: }
|