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//////////////////////////////////////////////////////////////////////////////// 019package com.puppycrawl.tools.checkstyle.checks.whitespace; 020 021import com.puppycrawl.tools.checkstyle.api.DetailAST; 022import com.puppycrawl.tools.checkstyle.api.TokenTypes; 023import com.puppycrawl.tools.checkstyle.api.Utils; 024import com.puppycrawl.tools.checkstyle.checks.AbstractOptionCheck; 025 026/** 027 * <p> 028 * Checks the padding between the identifier of a method definition, 029 * constructor definition, method call, or constructor invocation; 030 * and the left parenthesis of the parameter list. 031 * That is, if the identifier and left parenthesis are on the same line, 032 * checks whether a space is required immediately after the identifier or 033 * such a space is forbidden. 034 * If they are not on the same line, reports an error, unless configured to 035 * allow line breaks. 036 * </p> 037 * <p> By default the check will check the following tokens: 038 * {@link TokenTypes#CTOR_DEF CTOR_DEF}, 039 * {@link TokenTypes#LITERAL_NEW LITERAL_NEW}, 040 * {@link TokenTypes#METHOD_CALL METHOD_CALL}, 041 * {@link TokenTypes#METHOD_DEF METHOD_DEF}, 042 * {@link TokenTypes#SUPER_CTOR_CALL SUPER_CTOR_CALL}. 043 * </p> 044 * <p> 045 * An example of how to configure the check is: 046 * </p> 047 * <pre> 048 * <module name="MethodParamPad"/> 049 * </pre> 050 * <p> An example of how to configure the check to require a space 051 * after the identifier of a method definition, except if the left 052 * parenthesis occurs on a new line, is: 053 * </p> 054 * <pre> 055 * <module name="MethodParamPad"> 056 * <property name="tokens" value="METHOD_DEF"/> 057 * <property name="option" value="space"/> 058 * <property name="allowLineBreaks" value="true"/> 059 * </module> 060 * </pre> 061 * @author Rick Giles 062 * @version 1.0 063 */ 064 065public class MethodParamPadCheck 066 extends AbstractOptionCheck<PadOption> 067{ 068 /** 069 * Sets the pad option to nospace. 070 */ 071 public MethodParamPadCheck() 072 { 073 super(PadOption.NOSPACE, PadOption.class); 074 } 075 076 /** Whether whitespace is allowed if the method identifier is at a 077 * linebreak */ 078 private boolean allowLineBreaks; 079 080 @Override 081 public int[] getDefaultTokens() 082 { 083 return new int[] { 084 TokenTypes.CTOR_DEF, 085 TokenTypes.LITERAL_NEW, 086 TokenTypes.METHOD_CALL, 087 TokenTypes.METHOD_DEF, 088 TokenTypes.SUPER_CTOR_CALL, 089 }; 090 } 091 092 @Override 093 public void visitToken(DetailAST ast) 094 { 095 final DetailAST parenAST; 096 if ((ast.getType() == TokenTypes.METHOD_CALL)) { 097 parenAST = ast; 098 } 099 else { 100 parenAST = ast.findFirstToken(TokenTypes.LPAREN); 101 // array construction => parenAST == null 102 if (parenAST == null) { 103 return; 104 } 105 } 106 107 final String line = getLines()[parenAST.getLineNo() - 1]; 108 if (Utils.whitespaceBefore(parenAST.getColumnNo(), line)) { 109 if (!allowLineBreaks) { 110 log(parenAST, "line.previous", parenAST.getText()); 111 } 112 } 113 else { 114 final int before = parenAST.getColumnNo() - 1; 115 if ((PadOption.NOSPACE == getAbstractOption()) 116 && (Character.isWhitespace(line.charAt(before)))) 117 { 118 log(parenAST , "ws.preceded", parenAST.getText()); 119 } 120 else if ((PadOption.SPACE == getAbstractOption()) 121 && !Character.isWhitespace(line.charAt(before))) 122 { 123 log(parenAST, "ws.notPreceded", parenAST.getText()); 124 } 125 } 126 } 127 128 /** 129 * Control whether whitespace is flagged at linebreaks. 130 * @param allowLineBreaks whether whitespace should be 131 * flagged at linebreaks. 132 */ 133 public void setAllowLineBreaks(boolean allowLineBreaks) 134 { 135 this.allowLineBreaks = allowLineBreaks; 136 } 137}