1 package com.puppycrawl.tools.checkstyle.checks.metrics; 20 21 import com.puppycrawl.tools.checkstyle.api.Check; 22 import com.puppycrawl.tools.checkstyle.api.DetailAST; 23 import com.puppycrawl.tools.checkstyle.api.FullIdent; 24 import com.puppycrawl.tools.checkstyle.api.TokenTypes; 25 26 import com.puppycrawl.tools.checkstyle.checks.CheckUtils; 27 28 import java.util.HashSet ; 29 import java.util.Set ; 30 import java.util.Stack ; 31 32 38 public abstract class AbstractClassCouplingCheck extends Check 39 { 40 41 private final Set mIgnoredClassNames = new HashSet (); 42 43 private int mMax; 44 45 private String mPackageName; 46 47 48 private final Stack mContextStack = new Stack (); 49 50 private Context mContext; 51 52 56 protected AbstractClassCouplingCheck(int aDefaultMax) 57 { 58 setMax(aDefaultMax); 59 60 mIgnoredClassNames.add("boolean"); 61 mIgnoredClassNames.add("byte"); 62 mIgnoredClassNames.add("char"); 63 mIgnoredClassNames.add("double"); 64 mIgnoredClassNames.add("float"); 65 mIgnoredClassNames.add("int"); 66 mIgnoredClassNames.add("long"); 67 mIgnoredClassNames.add("short"); 68 mIgnoredClassNames.add("void"); 69 mIgnoredClassNames.add("Boolean"); 70 mIgnoredClassNames.add("Byte"); 71 mIgnoredClassNames.add("Character"); 72 mIgnoredClassNames.add("Double"); 73 mIgnoredClassNames.add("Float"); 74 mIgnoredClassNames.add("Integer"); 75 mIgnoredClassNames.add("Long"); 76 mIgnoredClassNames.add("Object"); 77 mIgnoredClassNames.add("Short"); 78 mIgnoredClassNames.add("String"); 79 mIgnoredClassNames.add("StringBuffer"); 80 mIgnoredClassNames.add("Void"); 81 mIgnoredClassNames.add("ArrayIndexOutOfBoundsException"); 82 mIgnoredClassNames.add("Exception"); 83 mIgnoredClassNames.add("RuntimeException"); 84 mIgnoredClassNames.add("IllegalArgumentException"); 85 mIgnoredClassNames.add("IllegalStateException"); 86 mIgnoredClassNames.add("IndexOutOfBoundsException"); 87 mIgnoredClassNames.add("NullPointerException"); 88 mIgnoredClassNames.add("Throwable"); 89 mIgnoredClassNames.add("SecurityException"); 90 mIgnoredClassNames.add("UnsupportedOperationException"); 91 } 92 93 94 public final int[] getDefaultTokens() 95 { 96 return getRequiredTokens(); 97 } 98 99 100 public final int getMax() 101 { 102 return mMax; 103 } 104 105 109 public final void setMax(int aMax) 110 { 111 mMax = aMax; 112 } 113 114 115 public final void beginTree(DetailAST aAST) 116 { 117 mPackageName = ""; 118 } 119 120 121 protected abstract String getLogMessageId(); 122 123 124 public void visitToken(DetailAST aAST) 125 { 126 switch (aAST.getType()) { 127 case TokenTypes.PACKAGE_DEF: 128 visitPackageDef(aAST); 129 break; 130 case TokenTypes.CLASS_DEF: 131 case TokenTypes.INTERFACE_DEF: 132 case TokenTypes.ANNOTATION_DEF: 133 case TokenTypes.ENUM_DEF: 134 visitClassDef(aAST); 135 break; 136 case TokenTypes.TYPE: 137 mContext.visitType(aAST); 138 break; 139 case TokenTypes.LITERAL_NEW: 140 mContext.visitLiteralNew(aAST); 141 break; 142 case TokenTypes.LITERAL_THROWS: 143 mContext.visitLiteralThrows(aAST); 144 break; 145 default: 146 throw new IllegalStateException (aAST.toString()); 147 } 148 } 149 150 151 public void leaveToken(DetailAST aAST) 152 { 153 switch (aAST.getType()) { 154 case TokenTypes.CLASS_DEF: 155 case TokenTypes.INTERFACE_DEF: 156 case TokenTypes.ANNOTATION_DEF: 157 case TokenTypes.ENUM_DEF: 158 leaveClassDef(); 159 break; 160 default: 161 } 163 } 164 165 169 private void visitPackageDef(DetailAST aPkg) 170 { 171 final FullIdent ident = FullIdent.createFullIdent(aPkg.getLastChild() 172 .getPreviousSibling()); 173 mPackageName = ident.getText(); 174 } 175 176 180 private void visitClassDef(DetailAST aClassDef) 181 { 182 mContextStack.push(mContext); 183 final String className = 184 aClassDef.findFirstToken(TokenTypes.IDENT).getText(); 185 mContext = new Context(className, 186 aClassDef.getLineNo(), 187 aClassDef.getColumnNo()); 188 } 189 190 191 private void leaveClassDef() 192 { 193 mContext.checkCoupling(); 194 mContext = (Context) mContextStack.pop(); 195 } 196 197 203 private class Context 204 { 205 206 private final Set mReferencedClassNames = new HashSet (); 207 208 private final String mClassName; 209 210 211 private final int mLineNo; 212 213 private final int mColumnNo; 214 215 221 public Context(String aClassName, int aLineNo, int aColumnNo) 222 { 223 mClassName = aClassName; 224 mLineNo = aLineNo; 225 mColumnNo = aColumnNo; 226 } 227 228 232 public void visitLiteralThrows(DetailAST aThrows) 233 { 234 for (DetailAST childAST = (DetailAST) aThrows.getFirstChild(); 235 childAST != null; 236 childAST = (DetailAST) childAST.getNextSibling()) 237 { 238 if (childAST.getType() != TokenTypes.COMMA) { 239 addReferencedClassName(childAST); 240 } 241 } 242 } 243 244 248 public void visitType(DetailAST aAST) 249 { 250 final String className = CheckUtils.createFullType(aAST).getText(); 251 mContext.addReferencedClassName(className); 252 } 253 254 258 public void visitLiteralNew(DetailAST aAST) 259 { 260 mContext.addReferencedClassName((DetailAST) aAST.getFirstChild()); 261 } 262 263 267 private void addReferencedClassName(DetailAST aAST) 268 { 269 final String className = FullIdent.createFullIdent(aAST).getText(); 270 addReferencedClassName(className); 271 } 272 273 277 private void addReferencedClassName(String aClassName) 278 { 279 if (isSignificant(aClassName)) { 280 mReferencedClassNames.add(aClassName); 281 } 282 } 283 284 285 public void checkCoupling() 286 { 287 mReferencedClassNames.remove(mClassName); 288 mReferencedClassNames.remove(mPackageName + "." + mClassName); 289 290 if (mReferencedClassNames.size() > mMax) { 291 log(mLineNo, mColumnNo, getLogMessageId(), 292 new Object [] { 293 new Integer (mReferencedClassNames.size()), 294 new Integer (getMax()), 295 mReferencedClassNames.toString(), }); 296 } 297 } 298 299 304 private boolean isSignificant(String aClassName) 305 { 306 return (aClassName.length() > 0) 307 && !mIgnoredClassNames.contains(aClassName) 308 && !aClassName.startsWith("java.lang."); 309 } 310 } 311 } 312 | Popular Tags |