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