001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 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 * Checks the number of other classes a given class relies on. Also the square 027 * of this has been shown to indicate the amount of maintenance required 028 * in functional programs (on a file basis) at least. 029 * </p> 030 * <p> 031 * This check processes files in the following way: 032 * </p> 033 * <ol> 034 * <li> 035 * Iterates over all tokens that might contain type reference. 036 * </li> 037 * <li> 038 * If a class was imported with direct import (i.e. {@code import java.math.BigDecimal}), 039 * or the class was referenced with the package name (i.e. {@code java.math.BigDecimal value}) 040 * and the package was added to the {@code excludedPackages} parameter, 041 * the class does not increase complexity. 042 * </li> 043 * <li> 044 * If a class name was added to the {@code excludedClasses} parameter, 045 * the class does not increase complexity. 046 * </li> 047 * </ol> 048 * <ul> 049 * <li> 050 * Property {@code max} - Specify the maximum threshold allowed. 051 * Default value is {@code 20}. 052 * </li> 053 * <li> 054 * Property {@code excludedClasses} - Specify user-configured class names to ignore. 055 * Default value is {@code ArrayIndexOutOfBoundsException, ArrayList, Boolean, Byte, 056 * Character, Class, Deprecated, Deque, Double, Exception, Float, FunctionalInterface, 057 * HashMap, HashSet, IllegalArgumentException, IllegalStateException, 058 * IndexOutOfBoundsException, Integer, LinkedList, List, Long, Map, NullPointerException, 059 * Object, Override, Queue, RuntimeException, SafeVarargs, SecurityException, Set, Short, 060 * SortedMap, SortedSet, String, StringBuffer, StringBuilder, SuppressWarnings, Throwable, 061 * TreeMap, TreeSet, UnsupportedOperationException, Void, boolean, byte, char, double, 062 * float, int, long, short, void}. 063 * </li> 064 * <li> 065 * Property {@code excludeClassesRegexps} - Specify user-configured regular 066 * expressions to ignore classes. 067 * Default value is {@code ^$}. 068 * </li> 069 * <li> 070 * Property {@code excludedPackages} - Specify user-configured packages to ignore. 071 * All excluded packages should end with a period, so it also appends a dot to a package name. 072 * Default value is {@code {}}. 073 * </li> 074 * </ul> 075 * <p> 076 * To configure the check: 077 * </p> 078 * <pre> 079 * <module name="ClassFanOutComplexity"/> 080 * </pre> 081 * <p> 082 * To configure the check with a threshold of 10: 083 * </p> 084 * <pre> 085 * <module name="ClassFanOutComplexity"> 086 * <property name="max" value="10"/> 087 * </module> 088 * </pre> 089 * <p> 090 * Override property {@code excludedPackages} to mark some packages as excluded. 091 * Each member of {@code excludedPackages} should be a valid identifier: 092 * </p> 093 * <ul> 094 * <li> 095 * {@code java.util} - valid, excludes all classes inside {@code java.util}, 096 * but not from the subpackages. 097 * </li> 098 * <li> 099 * {@code java.util.} - invalid, should not end with a dot. 100 * </li> 101 * <li> 102 * {@code java.util.*} - invalid, should not end with a star. 103 * </li> 104 * </ul> 105 * <p> 106 * Note, that checkstyle will ignore all classes from the {@code java.lang} 107 * package and its subpackages, even if the {@code java.lang} was not listed 108 * in the {@code excludedPackages} parameter. 109 * </p> 110 * <p> 111 * Also node, that {@code excludedPackages} will not exclude classes, imported 112 * via wildcard (e.g. {@code import java.math.*}). Instead of wildcard import 113 * you should use direct import (e.g. {@code import java.math.BigDecimal}). 114 * </p> 115 * <p> 116 * Also note, that checkstyle will not exclude classes within the same file even 117 * if it was listed in the {@code excludedPackages} parameter. 118 * For example, assuming the config is 119 * </p> 120 * <pre> 121 * <module name="ClassDataAbstractionCoupling"> 122 * <property name="excludedPackages" value="a.b"/> 123 * </module> 124 * </pre> 125 * <p> 126 * And the file {@code a.b.Foo.java} is: 127 * </p> 128 * <pre> 129 * package a.b; 130 * 131 * import a.b.Bar; 132 * import a.b.c.Baz; 133 * 134 * public class Foo { 135 * public Bar bar; // Will be ignored, located inside ignored a.b package 136 * public Baz baz; // Will not be ignored, located inside a.b.c package 137 * public Data data; // Will not be ignored, same file 138 * 139 * class Data { 140 * public Foo foo; // Will not be ignored, same file 141 * } 142 * } 143 * </pre> 144 * <p> 145 * The {@code bar} member will not be counted, since the {@code a.b} 146 * added to the {@code excludedPackages}. The {@code baz} member will be counted, 147 * since the {@code a.b.c} was not added to the {@code excludedPackages}. 148 * The {@code data} and {@code foo} members will be counted, as they are inside same file. 149 * </p> 150 * <p> 151 * Example of usage: 152 * </p> 153 * <pre> 154 * <module name="ClassFanOutComplexity"> 155 * <property name="excludedPackages" value="java.util, java.math"/> 156 * </module> 157 * </pre> 158 * 159 * @since 3.4 160 */ 161public final class ClassFanOutComplexityCheck extends AbstractClassCouplingCheck { 162 163 /** 164 * A key is pointing to the warning message text in "messages.properties" 165 * file. 166 */ 167 public static final String MSG_KEY = "classFanOutComplexity"; 168 169 /** Default value of max value. */ 170 private static final int DEFAULT_MAX = 20; 171 172 /** Creates new instance of this check. */ 173 public ClassFanOutComplexityCheck() { 174 super(DEFAULT_MAX); 175 } 176 177 @Override 178 public int[] getRequiredTokens() { 179 return new int[] { 180 TokenTypes.PACKAGE_DEF, 181 TokenTypes.IMPORT, 182 TokenTypes.CLASS_DEF, 183 TokenTypes.EXTENDS_CLAUSE, 184 TokenTypes.IMPLEMENTS_CLAUSE, 185 TokenTypes.ANNOTATION, 186 TokenTypes.INTERFACE_DEF, 187 TokenTypes.ENUM_DEF, 188 TokenTypes.TYPE, 189 TokenTypes.LITERAL_NEW, 190 TokenTypes.LITERAL_THROWS, 191 TokenTypes.ANNOTATION_DEF, 192 }; 193 } 194 195 @Override 196 public int[] getAcceptableTokens() { 197 return getRequiredTokens(); 198 } 199 200 @Override 201 protected String getLogMessageId() { 202 return MSG_KEY; 203 } 204 205}