001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2015 the original author or authors. 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.api; 021 022import java.util.Collections; 023import java.util.Set; 024 025import org.apache.commons.lang3.ArrayUtils; 026 027import com.google.common.collect.Sets; 028import com.puppycrawl.tools.checkstyle.utils.CommonUtils; 029 030/** 031 * The base class for checks. 032 * 033 * @author Oliver Burn 034 * @see <a href="{@docRoot}/../writingchecks.html" target="_top">Writing 035 * your own checks</a> 036 */ 037public abstract class Check extends AbstractViolationReporter { 038 /** Default tab width for column reporting. */ 039 private static final int DEFAULT_TAB_WIDTH = 8; 040 041 /** The current file contents. */ 042 private FileContents fileContents; 043 044 /** The tokens the check is interested in. */ 045 private final Set<String> tokens = Sets.newHashSet(); 046 047 /** The object for collecting messages. */ 048 private LocalizedMessages messages; 049 050 /** The tab width for column reporting. */ 051 private int tabWidth = DEFAULT_TAB_WIDTH; 052 053 /** 054 * The class loader to load external classes. Not initialized as this must 055 * be set by my creator. 056 */ 057 private ClassLoader classLoader; 058 059 /** 060 * Whether comment nodes are required or not. 061 * @return false as a default value. 062 */ 063 public boolean isCommentNodesRequired() { 064 return false; 065 } 066 067 /** 068 * Returns the default token a check is interested in. Only used if the 069 * configuration for a check does not define the tokens. 070 * @return the default tokens 071 * @see TokenTypes 072 */ 073 public abstract int[] getDefaultTokens(); 074 075 /** 076 * The configurable token set. 077 * Used to protect Checks against malicious users who specify an 078 * unacceptable token set in the configuration file. 079 * The default implementation returns the check's default tokens. 080 * @return the token set this check is designed for. 081 * @see TokenTypes 082 */ 083 public int[] getAcceptableTokens() { 084 final int[] defaultTokens = getDefaultTokens(); 085 final int[] copy = new int[defaultTokens.length]; 086 System.arraycopy(defaultTokens, 0, copy, 0, defaultTokens.length); 087 return copy; 088 } 089 090 /** 091 * The tokens that this check must be registered for. 092 * @return the token set this must be registered for. 093 * @see TokenTypes 094 */ 095 public int[] getRequiredTokens() { 096 return ArrayUtils.EMPTY_INT_ARRAY; 097 } 098 099 /** 100 * Adds a set of tokens the check is interested in. 101 * @param strRep the string representation of the tokens interested in 102 */ 103 public final void setTokens(String... strRep) { 104 Collections.addAll(tokens, strRep); 105 } 106 107 /** 108 * Returns the tokens registered for the check. 109 * @return the set of token names 110 */ 111 public final Set<String> getTokenNames() { 112 return Collections.unmodifiableSet(tokens); 113 } 114 115 /** 116 * Set the global object used to collect messages. 117 * @param messages the messages to log with 118 */ 119 public final void setMessages(LocalizedMessages messages) { 120 this.messages = messages; 121 } 122 123 /** 124 * Initialize the check. This is the time to verify that the check has 125 * everything required to perform it job. 126 */ 127 public void init() { 128 // No code by default, should be overridden only by demand at subclasses 129 } 130 131 /** 132 * Destroy the check. It is being retired from service. 133 */ 134 public void destroy() { 135 // No code by default, should be overridden only by demand at subclasses 136 } 137 138 /** 139 * Called before the starting to process a tree. Ideal place to initialize 140 * information that is to be collected whilst processing a tree. 141 * @param rootAST the root of the tree 142 */ 143 public void beginTree(DetailAST rootAST) { 144 // No code by default, should be overridden only by demand at subclasses 145 } 146 147 /** 148 * Called after finished processing a tree. Ideal place to report on 149 * information collected whilst processing a tree. 150 * @param rootAST the root of the tree 151 */ 152 public void finishTree(DetailAST rootAST) { 153 // No code by default, should be overridden only by demand at subclasses 154 } 155 156 /** 157 * Called to process a token. 158 * @param ast the token to process 159 */ 160 public void visitToken(DetailAST ast) { 161 // No code by default, should be overridden only by demand at subclasses 162 } 163 164 /** 165 * Called after all the child nodes have been process. 166 * @param ast the token leaving 167 */ 168 public void leaveToken(DetailAST ast) { 169 // No code by default, should be overridden only by demand at subclasses 170 } 171 172 /** 173 * Returns the lines associated with the tree. 174 * @return the file contents 175 */ 176 public final String[] getLines() { 177 return fileContents.getLines(); 178 } 179 180 /** 181 * Returns the line associated with the tree. 182 * @param index index of the line 183 * @return the line from the file contents 184 */ 185 public final String getLine(int index) { 186 return fileContents.getLine(index); 187 } 188 189 /** 190 * Set the file contents associated with the tree. 191 * @param contents the manager 192 */ 193 public final void setFileContents(FileContents contents) { 194 fileContents = contents; 195 } 196 197 /** 198 * Returns the file contents associated with the tree. 199 * @return the file contents 200 */ 201 public final FileContents getFileContents() { 202 return fileContents; 203 } 204 205 /** 206 * Set the class loader associated with the tree. 207 * @param classLoader the class loader 208 */ 209 public final void setClassLoader(ClassLoader classLoader) { 210 this.classLoader = classLoader; 211 } 212 213 /** 214 * Returns the class loader associated with the tree. 215 * @return the class loader 216 */ 217 public final ClassLoader getClassLoader() { 218 return classLoader; 219 } 220 221 /** 222 * Get tab width to report errors with. 223 * @return the tab width to report errors with 224 */ 225 protected final int getTabWidth() { 226 return tabWidth; 227 } 228 229 /** 230 * Set the tab width to report errors with. 231 * @param tabWidth an {@code int} value 232 */ 233 public final void setTabWidth(int tabWidth) { 234 this.tabWidth = tabWidth; 235 } 236 237 @Override 238 public final void log(int line, String key, Object... args) { 239 messages.add( 240 new LocalizedMessage( 241 line, 242 getMessageBundle(), 243 key, 244 args, 245 getSeverityLevel(), 246 getId(), 247 getClass(), 248 getCustomMessages().get(key))); 249 } 250 251 @Override 252 public final void log(int lineNo, int colNo, String key, 253 Object... args) { 254 final int col = 1 + CommonUtils.lengthExpandedTabs( 255 getLines()[lineNo - 1], colNo, tabWidth); 256 messages.add( 257 new LocalizedMessage( 258 lineNo, 259 col, 260 getMessageBundle(), 261 key, 262 args, 263 getSeverityLevel(), 264 getId(), 265 getClass(), 266 getCustomMessages().get(key))); 267 } 268}