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 * The configurable token set. 067 * Used to protect Checks against malicious users who specify an 068 * unacceptable token set in the configuration file. 069 * The default implementation returns the check's default tokens. 070 * @return the token set this check is designed for. 071 * @see TokenTypes 072 */ 073 public abstract int[] getAcceptableTokens(); 074 075 /** 076 * The tokens that this check must be registered for. 077 * @return the token set this must be registered for. 078 * @see TokenTypes 079 */ 080 public abstract int[] getRequiredTokens(); 081 082 /** 083 * Whether comment nodes are required or not. 084 * @return false as a default value. 085 */ 086 public boolean isCommentNodesRequired() { 087 return false; 088 } 089 090 /** 091 * Adds a set of tokens the check is interested in. 092 * @param strRep the string representation of the tokens interested in 093 */ 094 public final void setTokens(String... strRep) { 095 Collections.addAll(tokens, strRep); 096 } 097 098 /** 099 * Returns the tokens registered for the check. 100 * @return the set of token names 101 */ 102 public final Set<String> getTokenNames() { 103 return Collections.unmodifiableSet(tokens); 104 } 105 106 /** 107 * Set the global object used to collect messages. 108 * @param messages the messages to log with 109 */ 110 public final void setMessages(LocalizedMessages messages) { 111 this.messages = messages; 112 } 113 114 /** 115 * Initialize the check. This is the time to verify that the check has 116 * everything required to perform it job. 117 */ 118 public void init() { 119 // No code by default, should be overridden only by demand at subclasses 120 } 121 122 /** 123 * Destroy the check. It is being retired from service. 124 */ 125 public void destroy() { 126 // No code by default, should be overridden only by demand at subclasses 127 } 128 129 /** 130 * Called before the starting to process a tree. Ideal place to initialize 131 * information that is to be collected whilst processing a tree. 132 * @param rootAST the root of the tree 133 */ 134 public void beginTree(DetailAST rootAST) { 135 // No code by default, should be overridden only by demand at subclasses 136 } 137 138 /** 139 * Called after finished processing a tree. Ideal place to report on 140 * information collected whilst processing a tree. 141 * @param rootAST the root of the tree 142 */ 143 public void finishTree(DetailAST rootAST) { 144 // No code by default, should be overridden only by demand at subclasses 145 } 146 147 /** 148 * Called to process a token. 149 * @param ast the token to process 150 */ 151 public void visitToken(DetailAST ast) { 152 // No code by default, should be overridden only by demand at subclasses 153 } 154 155 /** 156 * Called after all the child nodes have been process. 157 * @param ast the token leaving 158 */ 159 public void leaveToken(DetailAST ast) { 160 // No code by default, should be overridden only by demand at subclasses 161 } 162 163 /** 164 * Returns the lines associated with the tree. 165 * @return the file contents 166 */ 167 public final String[] getLines() { 168 return fileContents.getLines(); 169 } 170 171 /** 172 * Returns the line associated with the tree. 173 * @param index index of the line 174 * @return the line from the file contents 175 */ 176 public final String getLine(int index) { 177 return fileContents.getLine(index); 178 } 179 180 /** 181 * Set the file contents associated with the tree. 182 * @param contents the manager 183 */ 184 public final void setFileContents(FileContents contents) { 185 fileContents = contents; 186 } 187 188 /** 189 * Returns the file contents associated with the tree. 190 * @return the file contents 191 */ 192 public final FileContents getFileContents() { 193 return fileContents; 194 } 195 196 /** 197 * Set the class loader associated with the tree. 198 * @param classLoader the class loader 199 */ 200 public final void setClassLoader(ClassLoader classLoader) { 201 this.classLoader = classLoader; 202 } 203 204 /** 205 * Returns the class loader associated with the tree. 206 * @return the class loader 207 */ 208 public final ClassLoader getClassLoader() { 209 return classLoader; 210 } 211 212 /** 213 * Get tab width to report errors with. 214 * @return the tab width to report errors with 215 */ 216 protected final int getTabWidth() { 217 return tabWidth; 218 } 219 220 /** 221 * Set the tab width to report errors with. 222 * @param tabWidth an {@code int} value 223 */ 224 public final void setTabWidth(int tabWidth) { 225 this.tabWidth = tabWidth; 226 } 227 228 @Override 229 public final void log(int line, String key, Object... args) { 230 messages.add( 231 new LocalizedMessage( 232 line, 233 getMessageBundle(), 234 key, 235 args, 236 getSeverityLevel(), 237 getId(), 238 getClass(), 239 getCustomMessages().get(key))); 240 } 241 242 @Override 243 public final void log(int lineNo, int colNo, String key, 244 Object... args) { 245 final int col = 1 + CommonUtils.lengthExpandedTabs( 246 getLines()[lineNo - 1], colNo, tabWidth); 247 messages.add( 248 new LocalizedMessage( 249 lineNo, 250 col, 251 getMessageBundle(), 252 key, 253 args, 254 getSeverityLevel(), 255 getId(), 256 getClass(), 257 getCustomMessages().get(key))); 258 } 259}