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