001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2022 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.checks.metrics;
021
022import com.puppycrawl.tools.checkstyle.api.TokenTypes;
023
024/**
025 * <p>
026 * Measures the number of instantiations of other classes
027 * within the given class or record. This type of coupling is not caused by inheritance or
028 * the object oriented paradigm. Generally speaking, any data type with other
029 * data types as members or local variable that is an instantiation (object)
030 * of another class has data abstraction coupling (DAC). The higher the DAC,
031 * the more complex the structure of the class.
032 * </p>
033 * <p>
034 * This check processes files in the following way:
035 * </p>
036 * <ol>
037 * <li>
038 * Iterates over the list of tokens (defined below) and counts all mentioned classes.
039 * <ul>
040 * <li>
041 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#IMPORT">
042 * PACKAGE_DEF</a>
043 * </li>
044 * <li>
045 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#IMPORT">
046 * IMPORT</a>
047 * </li>
048 * <li>
049 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF">
050 * CLASS_DEF</a>
051 * </li>
052 * <li>
053 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF">
054 * INTERFACE_DEF</a>
055 * </li>
056 * <li>
057 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF">
058 * ENUM_DEF</a>
059 * </li>
060 * <li>
061 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_NEW">
062 * LITERAL_NEW</a>
063 * </li>
064 * <li>
065 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_DEF">
066 * RECORD_DEF</a>
067 * </li>
068 * </ul>
069 * </li>
070 * <li>
071 * If a class was imported with direct import (i.e. {@code import java.math.BigDecimal}),
072 * or the class was referenced with the package name (i.e. {@code java.math.BigDecimal value})
073 * and the package was added to the {@code excludedPackages} parameter, the class
074 * does not increase complexity.
075 * </li>
076 * <li>
077 * If a class name was added to the {@code excludedClasses} parameter,
078 * the class does not increase complexity.
079 * </li>
080 * </ol>
081 * <ul>
082 * <li>
083 * Property {@code max} - Specify the maximum threshold allowed.
084 * Type is {@code int}.
085 * Default value is {@code 7}.
086 * </li>
087 * <li>
088 * Property {@code excludedClasses} - Specify user-configured class names to ignore.
089 * Type is {@code java.lang.String[]}.
090 * Default value is {@code ArrayIndexOutOfBoundsException, ArrayList, Boolean, Byte,
091 * Character, Class, Collection, Deprecated, Deque, Double, DoubleStream, EnumSet, Exception,
092 * Float, FunctionalInterface, HashMap, HashSet, IllegalArgumentException, IllegalStateException,
093 * IndexOutOfBoundsException, IntStream, Integer, LinkedHashMap, LinkedHashSet, LinkedList, List,
094 * Long, LongStream, Map, NullPointerException, Object, Optional, OptionalDouble, OptionalInt,
095 * OptionalLong, Override, Queue, RuntimeException, SafeVarargs, SecurityException, Set, Short,
096 * SortedMap, SortedSet, Stream, String, StringBuffer, StringBuilder, SuppressWarnings, Throwable,
097 * TreeMap, TreeSet, UnsupportedOperationException, Void, boolean, byte, char, double,
098 * float, int, long, short, var, void}.
099 * </li>
100 * <li>
101 * Property {@code excludeClassesRegexps} - Specify user-configured regular
102 * expressions to ignore classes.
103 * Type is {@code java.util.regex.Pattern[]}.
104 * Default value is {@code ^$}.
105 * </li>
106 * <li>
107 * Property {@code excludedPackages} - Specify user-configured packages to ignore.
108 * Type is {@code java.lang.String[]}.
109 * Default value is {@code ""}.
110 * </li>
111 * </ul>
112 * <p>
113 * To configure the check:
114 * </p>
115 * <pre>
116 * &lt;module name="ClassDataAbstractionCoupling"/&gt;
117 * </pre>
118 * <p>
119 * Example:
120 * </p>
121 * <p>
122 * The check passes without violations in the following:
123 * </p>
124 * <pre>
125 * class InputClassCoupling {
126 *   Set set = new HashSet(); // HashSet ignored due to default excludedClasses property
127 *   Map map = new HashMap(); // HashMap ignored due to default excludedClasses property
128 *   Date date = new Date(); // Counted, 1
129 *   Time time = new Time(); // Counted, 2
130 *   Place place = new Place(); // Counted, 3
131 * }
132 * </pre>
133 * <p>
134 * The check results in a violation in the following:
135 * </p>
136 * <pre>
137 * class InputClassCoupling {
138 *   Set set = new HashSet(); // HashSet ignored due to default excludedClasses property
139 *   Map map = new HashMap(); // HashMap ignored due to default excludedClasses property
140 *   Date date = new Date(); // Counted, 1
141 *   Time time = new Time(); // Counted, 2
142 *   // instantiation of 5 other user defined classes
143 *   Place place = new Place(); // violation, total is 8
144 * }
145 * </pre>
146 * <p>
147 * To configure the check with a threshold of 2:
148 * </p>
149 * <pre>
150 * &lt;module name="ClassDataAbstractionCoupling"&gt;
151 *   &lt;property name="max" value="2"/&gt;
152 * &lt;/module&gt;
153 * </pre>
154 * <p>
155 * Example:
156 * </p>
157 * <p>
158 * The check passes without violations in the following:
159 * </p>
160 * <pre>
161 * class InputClassCoupling {
162 *   Set set = new HashSet(); // HashSet ignored due to default excludedClasses property
163 *   Map map = new HashMap(); // HashMap ignored due to default excludedClasses property
164 *   Date date = new Date(); // Counted, 1
165 *   Time time = new Time(); // Counted, 2
166 * }
167 * </pre>
168 * <p>
169 * The check results in a violation in the following:
170 * </p>
171 * <pre>
172 * class InputClassCoupling {
173 *   Set set = new HashSet(); // HashSet ignored due to default excludedClasses property
174 *   Map map = new HashMap(); // HashMap ignored due to default excludedClasses property
175 *   Date date = new Date(); // Counted, 1
176 *   Time time = new Time(); // Counted, 2
177 *   Place place = new Place(); // violation, total is 3
178 * }
179 * </pre>
180 * <p>
181 * To configure the check with three excluded classes {@code HashMap},
182 * {@code HashSet} and {@code Place}:
183 * </p>
184 * <pre>
185 * &lt;module name="ClassDataAbstractionCoupling"&gt;
186 *   &lt;property name="excludedClasses" value="HashMap, HashSet, Place"/&gt;
187 * &lt;/module&gt;
188 * </pre>
189 * <p>
190 * Example:
191 * </p>
192 * <p>
193 * The check passes without violations in the following:
194 * </p>
195 * <pre>
196 * class InputClassCoupling {
197 *   Set set = new HashSet(); // Ignored
198 *   Map map = new HashMap(); // Ignored
199 *   Date date = new Date(); // Counted, 1
200 *   Time time = new Time(); // Counted, 2
201 *   // instantiation of 5 other user defined classes
202 *   Place place = new Place(); // Ignored
203 * }
204 * </pre>
205 * <p>
206 * The check results in a violation in the following:
207 * </p>
208 * <pre>
209 * class InputClassCoupling {
210 *   Set set = new HashSet(); // Ignored
211 *   Map map = new HashMap(); // Ignored
212 *   Date date = new Date(); // Counted, 1
213 *   Time time = new Time(); // Counted, 2
214 *   // instantiation of 5 other user defined classes
215 *   Space space = new Space(); // violation, total is 8
216 * }
217 * </pre>
218 * <p>
219 * To configure the check to exclude classes with a regular expression
220 * {@code .*Reader$}:
221 * </p>
222 * <pre>
223 * &lt;module name="ClassDataAbstractionCoupling"&gt;
224 *   &lt;property name="excludeClassesRegexps" value=".*Reader$"/&gt;
225 * &lt;/module&gt;
226 * </pre>
227 * <p>
228 * Example:
229 * </p>
230 * <p>
231 * The check passes without violations in the following:
232 * </p>
233 * <pre>
234 * class InputClassCoupling {
235 *   Set set = new HashSet(); // HashSet ignored due to default excludedClasses property
236 *   Map map = new HashMap(); // HashMap ignored due to default excludedClasses property
237 *   Date date = new Date(); // Counted, 1
238 *   Time time = new Time(); // Counted, 2
239 *   // instantiation of 5 other user defined classes
240 *   BufferedReader br = new BufferedReader(); // Ignored
241 * }
242 * </pre>
243 * <p>
244 * The check results in a violation in the following:
245 * </p>
246 * <pre>
247 * class InputClassCoupling {
248 *   Set set = new HashSet(); // HashSet ignored due to default excludedClasses property
249 *   Map map = new HashMap(); // HashMap ignored due to default excludedClasses property
250 *   Date date = new Date(); // Counted, 1
251 *   Time time = new Time(); // Counted, 2
252 *   // instantiation of 5 other user defined classes
253 *   File file = new File(); // violation, total is 8
254 * }
255 * </pre>
256 * <p>
257 * To configure the check with an excluded package {@code java.io}:
258 * </p>
259 * <pre>
260 * &lt;module name="ClassDataAbstractionCoupling"&gt;
261 *   &lt;property name="excludedPackages" value="java.io"/&gt;
262 * &lt;/module&gt;
263 * </pre>
264 * <p>
265 * Example:
266 * </p>
267 * <p>
268 * The check passes without violations in the following:
269 * </p>
270 * <pre>
271 * import java.io.BufferedReader;
272 *
273 * class InputClassCoupling {
274 *   Set set = new HashSet(); // HashSet ignored due to default excludedClasses property
275 *   Map map = new HashMap(); // HashMap ignored due to default excludedClasses property
276 *   Date date = new Date(); // Counted, 1
277 *   Time time = new Time(); // Counted, 2
278 *   // instantiation of 5 other user defined classes
279 *   BufferedReader br = new BufferedReader(); // Ignored
280 * }
281 * </pre>
282 * <p>
283 * The check results in a violation in the following:
284 * </p>
285 * <pre>
286 * import java.util.StringTokenizer;
287 *
288 * class InputClassCoupling {
289 *   Set set = new HashSet(); // HashSet ignored due to default excludedClasses property
290 *   Map map = new HashMap(); // HashMap ignored due to default excludedClasses property
291 *   Date date = new Date(); // Counted, 1
292 *   Time time = new Time(); // Counted, 2
293 *   // instantiation of 5 other user defined classes
294 *   StringTokenizer st = new StringTokenizer(); // violation, total is 8
295 * }
296 * </pre>
297 * <p>
298 * Override property {@code excludedPackages} to mark some packages as excluded.
299 * Each member of {@code excludedPackages} should be a valid identifier:
300 * </p>
301 * <ul>
302 * <li>
303 * {@code java.util} - valid, excludes all classes inside {@code java.util},
304 * but not from the subpackages.
305 * </li>
306 * <li>
307 * {@code java.util.} - invalid, should not end with a dot.
308 * </li>
309 * <li>
310 * {@code java.util.*} - invalid, should not end with a star.
311 * </li>
312 * </ul>
313 * <p>
314 * Note, that checkstyle will ignore all classes from the {@code java.lang}
315 * package and its subpackages, even if the {@code java.lang} was not listed
316 * in the {@code excludedPackages} parameter.
317 * </p>
318 * <p>
319 * Also note, that {@code excludedPackages} will not exclude classes, imported
320 * via wildcard (e.g. {@code import java.math.*}). Instead of wildcard import
321 * you should use direct import (e.g. {@code import java.math.BigDecimal}).
322 * </p>
323 * <p>
324 * Also note, that checkstyle will not exclude classes within the same file
325 * even if it was listed in the {@code excludedPackages} parameter.
326 * For example, assuming the config is
327 * </p>
328 * <pre>
329 * &lt;module name="ClassDataAbstractionCoupling"&gt;
330 *   &lt;property name="excludedPackages" value="a.b"/&gt;
331 * &lt;/module&gt;
332 * </pre>
333 * <p>
334 * And the file {@code a.b.Foo.java} is:
335 * </p>
336 * <pre>
337 * package a.b;
338 *
339 * import a.b.Bar;
340 * import a.b.c.Baz;
341 *
342 * class Foo {
343 *   Bar bar; // Will be ignored, located inside ignored a.b package
344 *   Baz baz; // Will not be ignored, located inside a.b.c package
345 *   Data data; // Will not be ignored, same file
346 *
347 *   class Data {
348 *     Foo foo; // Will not be ignored, same file
349 *   }
350 * }
351 * </pre>
352 * <p>
353 * The {@code bar} member will not be counted, since the {@code a.b} added
354 * to the {@code excludedPackages}. The {@code baz} member will be counted,
355 * since the {@code a.b.c} was not added to the {@code excludedPackages}.
356 * The {@code data} and {@code foo} members will be counted, as they are inside same file.
357 * </p>
358 * <p>
359 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
360 * </p>
361 * <p>
362 * Violation Message Keys:
363 * </p>
364 * <ul>
365 * <li>
366 * {@code classDataAbstractionCoupling}
367 * </li>
368 * </ul>
369 *
370 * @since 3.4
371 *
372 */
373public final class ClassDataAbstractionCouplingCheck
374    extends AbstractClassCouplingCheck {
375
376    /**
377     * A key is pointing to the warning message text in "messages.properties"
378     * file.
379     */
380    public static final String MSG_KEY = "classDataAbstractionCoupling";
381
382    /** Default allowed complexity. */
383    private static final int DEFAULT_MAX = 7;
384
385    /** Creates bew instance of the check. */
386    public ClassDataAbstractionCouplingCheck() {
387        super(DEFAULT_MAX);
388    }
389
390    @Override
391    public int[] getRequiredTokens() {
392        return new int[] {
393            TokenTypes.PACKAGE_DEF,
394            TokenTypes.IMPORT,
395            TokenTypes.CLASS_DEF,
396            TokenTypes.INTERFACE_DEF,
397            TokenTypes.ENUM_DEF,
398            TokenTypes.LITERAL_NEW,
399            TokenTypes.RECORD_DEF,
400        };
401    }
402
403    @Override
404    public int[] getAcceptableTokens() {
405        return getRequiredTokens();
406    }
407
408    @Override
409    protected String getLogMessageId() {
410        return MSG_KEY;
411    }
412
413}