001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2014 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 020package com.puppycrawl.tools.checkstyle.checks.whitespace; 021 022import com.puppycrawl.tools.checkstyle.api.DetailAST; 023import com.puppycrawl.tools.checkstyle.api.TokenTypes; 024 025/** 026 * <p>Checks the padding of parentheses; that is whether a space is required 027 * after a left parenthesis and before a right parenthesis, or such spaces are 028 * forbidden, with the exception that it does 029 * not check for padding of the right parenthesis at an empty for iterator. 030 * Use Check {@link EmptyForIteratorPadCheck EmptyForIteratorPad} to validate 031 * empty for iterators. 032 * </p> 033 * <p> 034 * The policy to verify is specified using the {@link PadOption} class and 035 * defaults to {@link PadOption#NOSPACE}. 036 * </p> 037 * <p> By default the check will check parentheses that occur with the following 038 * tokens: 039 * {@link TokenTypes#CTOR_CALL CTOR_CALL}, 040 * {@link TokenTypes#LPAREN LPAREN}, 041 * {@link TokenTypes#METHOD_CALL METHOD_CALL}, 042 * {@link TokenTypes#RPAREN RPAREN}, 043 * {@link TokenTypes#SUPER_CTOR_CALL SUPER_CTOR_CALL}, 044 * </p> 045 * <p> 046 * An example of how to configure the check is: 047 * </p> 048 * <pre> 049 * <module name="ParenPad"/> 050 * </pre> 051 * <p> 052 * An example of how to configure the check to require spaces for the 053 * parentheses of constructor, method, and super constructor invocations is: 054 * </p> 055 * <pre> 056 * <module name="ParenPad"> 057 * <property name="tokens" 058 * value="CTOR_CALL, METHOD_CALL, SUPER_CTOR_CALL"/> 059 * <property name="option" value="space"/> 060 * </module> 061 * </pre> 062 * @author Oliver Burn 063 * @version 1.0 064 */ 065public class ParenPadCheck extends AbstractParenPadCheck 066{ 067 @Override 068 public int[] getDefaultTokens() 069 { 070 return new int[] {TokenTypes.RPAREN, 071 TokenTypes.LPAREN, 072 TokenTypes.CTOR_CALL, 073 TokenTypes.SUPER_CTOR_CALL, 074 TokenTypes.METHOD_CALL, 075 }; 076 } 077 078 @Override 079 public void visitToken(DetailAST ast) 080 { 081 DetailAST theAst = ast; 082 // Strange logic in this method to guard against checking RPAREN tokens 083 // that are associated with a TYPECAST token. 084 if (theAst.getType() != TokenTypes.RPAREN) { 085 if ((theAst.getType() == TokenTypes.CTOR_CALL) 086 || (theAst.getType() == TokenTypes.SUPER_CTOR_CALL)) 087 { 088 theAst = theAst.getFirstChild(); 089 } 090 if (!isPreceedsEmptyForInit(theAst)) { 091 processLeft(theAst); 092 } 093 } 094 else if (((theAst.getParent() == null) 095 || (theAst.getParent().getType() != TokenTypes.TYPECAST) 096 || (theAst.getParent().findFirstToken(TokenTypes.RPAREN) 097 != theAst)) 098 && !isFollowsEmptyForIterator(theAst)) 099 { 100 processRight(theAst); 101 } 102 } 103 104 /** 105 * @param ast the token to check 106 * @return whether a token follows an empty for iterator 107 */ 108 private boolean isFollowsEmptyForIterator(DetailAST ast) 109 { 110 boolean followsEmptyForIterator = false; 111 final DetailAST parent = ast.getParent(); 112 //Only traditional for statements are examined, not for-each statements 113 if ((parent != null) 114 && (parent.getType() == TokenTypes.LITERAL_FOR) 115 && (parent.findFirstToken(TokenTypes.FOR_EACH_CLAUSE) == null)) 116 { 117 final DetailAST forIterator = 118 parent.findFirstToken(TokenTypes.FOR_ITERATOR); 119 followsEmptyForIterator = (forIterator.getChildCount() == 0) 120 && (ast == forIterator.getNextSibling()); 121 } 122 return followsEmptyForIterator; 123 } 124 125 /** 126 * @param ast the token to check 127 * @return whether a token preceeds an empty for initializer 128 */ 129 private boolean isPreceedsEmptyForInit(DetailAST ast) 130 { 131 boolean preceedsEmptyForInintializer = false; 132 final DetailAST parent = ast.getParent(); 133 //Only traditional for statements are examined, not for-each statements 134 if ((parent != null) 135 && (parent.getType() == TokenTypes.LITERAL_FOR) 136 && (parent.findFirstToken(TokenTypes.FOR_EACH_CLAUSE) == null)) 137 { 138 final DetailAST forIterator = 139 parent.findFirstToken(TokenTypes.FOR_INIT); 140 preceedsEmptyForInintializer = (forIterator.getChildCount() == 0) 141 && (ast == forIterator.getPreviousSibling()); 142 } 143 return preceedsEmptyForInintializer; 144 } 145}