001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2019 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 * This metric measures the number of instantiations of other classes
027 * within the given class. 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 * </ul>
065 * </li>
066 * <li>
067 * If a class was imported with direct import (i.e. {@code import java.math.BigDecimal}),
068 * or the class was referenced with the package name (i.e. {@code java.math.BigDecimal value})
069 * and the package was added to the {@code excludedPackages} parameter, the class
070 * does not increase complexity.
071 * </li>
072 * <li>
073 * If a class name was added to the {@code excludedClasses} parameter,
074 * the class does not increase complexity.
075 * </li>
076 * </ol>
077 * <ul>
078 * <li>
079 * Property {@code max} - Specify the maximum threshold allowed.
080 * Default value is {@code 7}.
081 * </li>
082 * <li>
083 * Property {@code excludedClasses} - Specify user-configured class names to ignore.
084 * Default value is {@code ArrayIndexOutOfBoundsException, ArrayList, Boolean, Byte,
085 * Character, Class, Deprecated, Deque, Double, Exception, Float, FunctionalInterface,
086 * HashMap, HashSet, IllegalArgumentException, IllegalStateException,
087 * IndexOutOfBoundsException, Integer, LinkedList, List, Long, Map, NullPointerException,
088 * Object, Override, Queue, RuntimeException, SafeVarargs, SecurityException, Set, Short,
089 * SortedMap, SortedSet, String, StringBuffer, StringBuilder, SuppressWarnings, Throwable,
090 * TreeMap, TreeSet, UnsupportedOperationException, Void, boolean, byte, char, double,
091 * float, int, long, short, void}.
092 * </li>
093 * <li>
094 * Property {@code excludeClassesRegexps} - Specify user-configured regular
095 * expressions to ignore classes.
096 * Default value is {@code ^$}.
097 * </li>
098 * <li>
099 * Property {@code excludedPackages} - Specify user-configured packages to ignore.
100 * Default value is {@code {}}.
101 * </li>
102 * </ul>
103 * <p>
104 * To configure the check:
105 * </p>
106 * <pre>
107 * &lt;module name="ClassDataAbstractionCoupling"/&gt;
108 * </pre>
109 * <p>
110 * To configure the check with a threshold of 5:
111 * </p>
112 * <pre>
113 * &lt;module name="ClassDataAbstractionCoupling"&gt;
114 *   &lt;property name="max" value="5"/&gt;
115 * &lt;/module&gt;
116 * </pre>
117 * <p>
118 * To configure the check with two excluded classes {@code HashMap} and {@code HashSet}:
119 * </p>
120 * <pre>
121 * &lt;module name="ClassDataAbstractionCoupling"&gt;
122 *   &lt;property name="excludedClasses" value="HashMap, HashSet"/&gt;
123 * &lt;/module&gt;
124 * </pre>
125 * <p>
126 * To configure the check with two regular expressions {@code ^Array.*} and {@code .*Exception$}:
127 * </p>
128 * <pre>
129 * &lt;module name="ClassDataAbstractionCoupling"&gt;
130 *   &lt;property name="excludeClassesRegexps"
131 *     value="^Array.*, .*Exception$"/&gt;
132 * &lt;/module&gt;
133 * </pre>
134 * <p>
135 * The following example demonstrates usage of <b>excludedClasses</b> and
136 * <b>excludeClassesRegexps</b> properties
137 * </p>
138 * <p>
139 * Expected result is one class {@code Date}
140 * </p>
141 * <pre>
142 * &lt;module name="ClassDataAbstractionCoupling"&gt;
143 *   &lt;property name="excludedClasses" value="ArrayList"/&gt;
144 *   &lt;property name="excludeClassesRegexps" value="^Hash.*"/&gt;
145 * &lt;/module&gt;
146 * </pre>
147 * <pre>
148 * public class InputClassCoupling {
149 *   public Set _set = new HashSet();
150 *   public Map _map = new HashMap();
151 *   public List&lt;String&gt; _list = new ArrayList&lt;&gt;();
152 *   public Date _date = new Date();
153 * }
154 * </pre>
155 * <p>
156 * To configure the check with two excluded classes {@code HashMap} and {@code HashSet}:
157 * </p>
158 * <pre>
159 * &lt;module name="ClassDataAbstractionCoupling"&gt;
160 *   &lt;property name="excludedClasses" value="HashMap, HashSet"/&gt;
161 * &lt;/module&gt;
162 * </pre>
163 * <p>
164 * To configure the check with two regular expressions {@code ^Array.*} and {@code .*Exception$}:
165 * </p>
166 * <pre>
167 * &lt;module name="ClassDataAbstractionCoupling"&gt;
168 *   &lt;property name="excludeClassesRegexps" value="^Array.*, .*Exception$"/&gt;
169 * &lt;/module&gt;
170 * </pre>
171 * <p>
172 * The following example demonstrates usage of <b>excludedClasses</b> and
173 * <b>excludeClassesRegexps</b> properties
174 * </p>
175 * <p>
176 * Expected result is one class {@code Date}
177 * </p>
178 * <pre>
179 * &lt;module name="ClassDataAbstractionCoupling"&gt;
180 *   &lt;property name="excludedClasses" value="ArrayList"/&gt;
181 *   &lt;property name="excludeClassesRegexps" value="^Hash.*"/&gt;
182 * &lt;/module&gt;
183 * </pre>
184 * <pre>
185 * public class InputClassCoupling {
186 *   public Set _set = new HashSet();
187 *   public Map _map = new HashMap();
188 *   public List&lt;String&gt; _list = new ArrayList&lt;&gt;();
189 *   public Date _date = new Date();
190 * }
191 * </pre>
192 * <p>
193 * Override property {@code excludedPackages} to mark some packages as excluded.
194 * Each member of {@code excludedPackages} should be a valid identifier:
195 * </p>
196 * <ul>
197 * <li>
198 * {@code java.util} - valid, excludes all classes inside {@code java.util},
199 * but not from the subpackages.
200 * </li>
201 * <li>
202 * {@code java.util.} - invalid, should not end with a dot.
203 * </li>
204 * <li>
205 * {@code java.util.*} - invalid, should not end with a star.
206 * </li>
207 * </ul>
208 * <p>
209 * Note, that checkstyle will ignore all classes from the {@code java.lang}
210 * package and its subpackages, even if the {@code java.lang} was not listed
211 * in the {@code excludedPackages} parameter.
212 * </p>
213 * <p>
214 * Also note, that {@code excludedPackages} will not exclude classes, imported
215 * via wildcard (e.g. {@code import java.math.*}). Instead of wildcard import
216 * you should use direct import (e.g. {@code import java.math.BigDecimal}).
217 * </p>
218 * <p>
219 * Also note, that checkstyle will not exclude classes within the same file
220 * even if it was listed in the {@code excludedPackages} parameter.
221 * For example, assuming the config is
222 * </p>
223 * <pre>
224 * &lt;module name="ClassDataAbstractionCoupling"&gt;
225 *   &lt;property name="excludedPackages" value="a.b"/&gt;
226 * &lt;/module&gt;
227 * </pre>
228 * <p>
229 * And the file {@code a.b.Foo.java} is:
230 * </p>
231 * <pre>
232 * package a.b;
233 *
234 * import a.b.Bar;
235 * import a.b.c.Baz;
236 *
237 * public class Foo {
238 *   public Bar bar; // Will be ignored, located inside ignored a.b package
239 *   public Baz baz; // Will not be ignored, located inside a.b.c package
240 *   public Data data; // Will not be ignored, same file
241 *
242 *   class Data {
243 *     public Foo foo; // Will not be ignored, same file
244 *   }
245 * }
246 * </pre>
247 * <p>
248 * The {@code bar} member will not be counted, since the {@code a.b} added
249 * to the {@code excludedPackages}. The {@code baz} member will be counted,
250 * since the {@code a.b.c} was not added to the {@code excludedPackages}.
251 * The {@code data} and {@code foo} members will be counted, as they are inside same file.
252 * </p>
253 * <p>
254 * Example of usage:
255 * </p>
256 * <pre>
257 * &lt;module name="ClassDataAbstractionCoupling"&gt;
258 *   &lt;property name="excludedPackages" value="java.util, java.math"/&gt;
259 * &lt;/module&gt;
260 * </pre>
261 *
262 * @since 3.4
263 *
264 */
265public final class ClassDataAbstractionCouplingCheck
266    extends AbstractClassCouplingCheck {
267
268    /**
269     * A key is pointing to the warning message text in "messages.properties"
270     * file.
271     */
272    public static final String MSG_KEY = "classDataAbstractionCoupling";
273
274    /** Default allowed complexity. */
275    private static final int DEFAULT_MAX = 7;
276
277    /** Creates bew instance of the check. */
278    public ClassDataAbstractionCouplingCheck() {
279        super(DEFAULT_MAX);
280    }
281
282    @Override
283    public int[] getRequiredTokens() {
284        return new int[] {
285            TokenTypes.PACKAGE_DEF,
286            TokenTypes.IMPORT,
287            TokenTypes.CLASS_DEF,
288            TokenTypes.INTERFACE_DEF,
289            TokenTypes.ENUM_DEF,
290            TokenTypes.LITERAL_NEW,
291        };
292    }
293
294    @Override
295    public int[] getAcceptableTokens() {
296        return getRequiredTokens();
297    }
298
299    // -@cs[SimpleAccessorNameNotation] Overrides method from the base class.
300    // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166
301    @Override
302    protected String getLogMessageId() {
303        return MSG_KEY;
304    }
305
306}