1 package com.puppycrawl.tools.checkstyle; 20 21 import java.io.File ; 22 import java.io.FileNotFoundException ; 23 import java.io.IOException ; 24 import java.io.Reader ; 25 import java.util.ArrayList ; 26 import java.util.Arrays ; 27 import java.util.HashMap ; 28 import java.util.HashSet ; 29 import java.util.Iterator ; 30 import java.util.Map ; 31 import java.util.Set ; 32 33 import antlr.RecognitionException; 34 import antlr.TokenStreamException; 35 import antlr.TokenStreamRecognitionException; 36 import antlr.TokenStream; 37 38 import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; 39 import com.puppycrawl.tools.checkstyle.api.Check; 40 import com.puppycrawl.tools.checkstyle.api.CheckstyleException; 41 import com.puppycrawl.tools.checkstyle.api.Configuration; 42 import com.puppycrawl.tools.checkstyle.api.Context; 43 import com.puppycrawl.tools.checkstyle.api.DetailAST; 44 import com.puppycrawl.tools.checkstyle.api.FileContents; 45 import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; 46 import com.puppycrawl.tools.checkstyle.api.TokenTypes; 47 import com.puppycrawl.tools.checkstyle.api.Utils; 48 import com.puppycrawl.tools.checkstyle.grammars.GeneratedJavaRecognizer; 49 import com.puppycrawl.tools.checkstyle.grammars.GeneratedJavaLexer; 50 51 import org.apache.commons.logging.Log; 52 import org.apache.commons.logging.LogFactory; 53 54 61 public final class TreeWalker 62 extends AbstractFileSetCheck 63 { 64 72 private static final class SilentJavaRecognizer 73 extends GeneratedJavaRecognizer 74 { 75 80 public SilentJavaRecognizer(TokenStream aLexer) 81 { 82 super(aLexer); 83 } 84 85 89 public void reportError(RecognitionException aRex) 90 { 91 } 92 93 97 public void reportError(String aMsg) 98 { 99 } 100 101 105 public void reportWarning(String aMsg) 106 { 107 } 108 } 109 110 111 private static final int DEFAULT_TAB_WIDTH = 8; 112 113 114 private final Map mTokenToChecks = new HashMap (); 115 116 private final Set mAllChecks = new HashSet (); 117 118 private int mTabWidth = DEFAULT_TAB_WIDTH; 119 120 private PropertyCacheFile mCache = new PropertyCacheFile(null, null); 121 122 123 private ClassLoader mClassLoader; 124 125 126 private Context mChildContext; 127 128 129 private ModuleFactory mModuleFactory; 130 131 134 private final boolean mRecursive; 135 136 137 private static final Log LOG = 138 LogFactory.getLog("com.puppycrawl.tools.checkstyle.TreeWalker"); 139 140 143 public TreeWalker() 144 { 145 setFileExtensions(new String []{"java"}); 146 final String recursive = 150 System.getProperty("checkstyle.use.recursive.algorithm", "false"); 151 mRecursive = "true".equals(recursive); 152 if (mRecursive) { 153 LOG.debug("TreeWalker uses recursive algorithm"); 154 } 155 else { 156 LOG.debug("TreeWalker uses iterative algorithm"); 157 } 158 } 159 160 161 public void setTabWidth(int aTabWidth) 162 { 163 mTabWidth = aTabWidth; 164 } 165 166 167 public void setCacheFile(String aFileName) 168 { 169 final Configuration configuration = getConfiguration(); 170 mCache = new PropertyCacheFile(configuration, aFileName); 171 } 172 173 174 public void setClassLoader(ClassLoader aClassLoader) 175 { 176 mClassLoader = aClassLoader; 177 } 178 179 183 public void setModuleFactory(ModuleFactory aModuleFactory) 184 { 185 mModuleFactory = aModuleFactory; 186 } 187 188 189 public void finishLocalSetup() 190 { 191 final DefaultContext checkContext = new DefaultContext(); 192 checkContext.add("classLoader", mClassLoader); 193 checkContext.add("messages", getMessageCollector()); 194 checkContext.add("severity", getSeverity()); 195 checkContext.add("tabWidth", String.valueOf(mTabWidth)); 199 200 mChildContext = checkContext; 201 } 202 203 208 public void setupChild(Configuration aChildConf) 209 throws CheckstyleException 210 { 211 final String name = aChildConf.getName(); 213 final Object module = mModuleFactory.createModule(name); 214 if (!(module instanceof Check)) { 215 throw new CheckstyleException( 216 "TreeWalker is not allowed as a parent of " + name); 217 } 218 final Check c = (Check) module; 219 c.contextualize(mChildContext); 220 c.configure(aChildConf); 221 c.init(); 222 223 registerCheck(c); 224 } 225 226 230 private void process(File aFile) 231 { 232 final String fileName = aFile.getPath(); 234 final long timestamp = aFile.lastModified(); 235 if (mCache.alreadyChecked(fileName, timestamp)) { 236 return; 237 } 238 239 try { 240 getMessageDispatcher().fireFileStarted(fileName); 241 final String [] lines = Utils.getLines(fileName, getCharset()); 242 final FileContents contents = new FileContents(fileName, lines); 243 final DetailAST rootAST = TreeWalker.parse(contents); 244 walk(rootAST, contents); 245 } 246 catch (final FileNotFoundException fnfe) { 247 Utils.getExceptionLogger() 248 .debug("FileNotFoundException occured.", fnfe); 249 getMessageCollector().add( 250 new LocalizedMessage( 251 0, 252 Defn.CHECKSTYLE_BUNDLE, 253 "general.fileNotFound", 254 null, 255 getId(), 256 this.getClass())); 257 } 258 catch (final IOException ioe) { 259 Utils.getExceptionLogger().debug("IOException occured.", ioe); 260 getMessageCollector().add( 261 new LocalizedMessage( 262 0, 263 Defn.CHECKSTYLE_BUNDLE, 264 "general.exception", 265 new String [] {ioe.getMessage()}, 266 getId(), 267 this.getClass())); 268 } 269 catch (final RecognitionException re) { 270 Utils.getExceptionLogger() 271 .debug("RecognitionException occured.", re); 272 getMessageCollector().add( 273 new LocalizedMessage( 274 re.getLine(), 275 re.getColumn(), 276 Defn.CHECKSTYLE_BUNDLE, 277 "general.exception", 278 new String [] {re.getMessage()}, 279 getId(), 280 this.getClass())); 281 } 282 catch (final TokenStreamRecognitionException tre) { 283 Utils.getExceptionLogger() 284 .debug("TokenStreamRecognitionException occured.", tre); 285 final RecognitionException re = tre.recog; 286 if (re != null) { 287 getMessageCollector().add( 288 new LocalizedMessage( 289 re.getLine(), 290 re.getColumn(), 291 Defn.CHECKSTYLE_BUNDLE, 292 "general.exception", 293 new String [] {re.getMessage()}, 294 getId(), 295 this.getClass())); 296 } 297 else { 298 getMessageCollector().add( 299 new LocalizedMessage( 300 0, 301 Defn.CHECKSTYLE_BUNDLE, 302 "general.exception", 303 new String [] 304 {"TokenStreamRecognitionException occured."}, 305 getId(), 306 this.getClass())); 307 } 308 } 309 catch (final TokenStreamException te) { 310 Utils.getExceptionLogger() 311 .debug("TokenStreamException occured.", te); 312 getMessageCollector().add( 313 new LocalizedMessage( 314 0, 315 Defn.CHECKSTYLE_BUNDLE, 316 "general.exception", 317 new String [] {te.getMessage()}, 318 getId(), 319 this.getClass())); 320 } 321 catch (final Throwable err) { 322 Utils.getExceptionLogger().debug("Throwable occured.", err); 323 getMessageCollector().add( 324 new LocalizedMessage( 325 0, 326 Defn.CHECKSTYLE_BUNDLE, 327 "general.exception", 328 new String [] {"" + err}, 329 getId(), 330 this.getClass())); 331 } 332 333 if (getMessageCollector().size() == 0) { 334 mCache.checkedOk(fileName, timestamp); 335 } 336 else { 337 fireErrors(fileName); 338 } 339 340 getMessageDispatcher().fireFileFinished(fileName); 341 } 342 343 348 private void registerCheck(Check aCheck) 349 throws CheckstyleException 350 { 351 int[] tokens = new int[] {}; final Set checkTokens = aCheck.getTokenNames(); 353 if (!checkTokens.isEmpty()) { 354 tokens = aCheck.getRequiredTokens(); 355 356 final int acceptableTokens[] = aCheck.getAcceptableTokens(); 358 Arrays.sort(acceptableTokens); 359 final Iterator it = checkTokens.iterator(); 360 while (it.hasNext()) { 361 final String token = (String ) it.next(); 362 try { 363 final int tokenId = TokenTypes.getTokenId(token); 364 if (Arrays.binarySearch(acceptableTokens, tokenId) >= 0) { 365 registerCheck(token, aCheck); 366 } 367 } 369 catch (final IllegalArgumentException ex) { 370 throw new CheckstyleException("illegal token \"" 371 + token + "\" in check " + aCheck, ex); 372 } 373 } 374 } 375 else { 376 tokens = aCheck.getDefaultTokens(); 377 } 378 for (int i = 0; i < tokens.length; i++) { 379 registerCheck(tokens[i], aCheck); 380 } 381 mAllChecks.add(aCheck); 382 } 383 384 389 private void registerCheck(int aTokenID, Check aCheck) 390 { 391 registerCheck(TokenTypes.getTokenName(aTokenID), aCheck); 392 } 393 394 399 private void registerCheck(String aToken, Check aCheck) 400 { 401 ArrayList visitors = (ArrayList ) mTokenToChecks.get(aToken); 402 if (visitors == null) { 403 visitors = new ArrayList (); 404 mTokenToChecks.put(aToken, visitors); 405 } 406 407 visitors.add(aCheck); 408 } 409 410 415 private void walk(DetailAST aAST, FileContents aContents) 416 { 417 getMessageCollector().reset(); 418 notifyBegin(aAST, aContents); 419 420 if (aAST != null) { 422 if (useRecursiveAlgorithm()) { 423 processRec(aAST); 424 } 425 else { 426 processIter(aAST); 427 } 428 } 429 430 notifyEnd(aAST); 431 } 432 433 434 439 private void notifyBegin(DetailAST aRootAST, FileContents aContents) 440 { 441 final Iterator it = mAllChecks.iterator(); 442 while (it.hasNext()) { 443 final Check check = (Check) it.next(); 444 check.setFileContents(aContents); 445 check.beginTree(aRootAST); 446 } 447 } 448 449 453 private void notifyEnd(DetailAST aRootAST) 454 { 455 final Iterator it = mAllChecks.iterator(); 456 while (it.hasNext()) { 457 final Check check = (Check) it.next(); 458 check.finishTree(aRootAST); 459 } 460 } 461 462 467 private void processRec(DetailAST aAST) 468 { 469 if (aAST == null) { 470 return; 471 } 472 473 notifyVisit(aAST); 474 475 final DetailAST child = (DetailAST) aAST.getFirstChild(); 476 if (child != null) { 477 processRec(child); 478 } 479 480 notifyLeave(aAST); 481 482 final DetailAST sibling = (DetailAST) aAST.getNextSibling(); 483 if (sibling != null) { 484 processRec(sibling); 485 } 486 } 487 488 492 private void notifyVisit(DetailAST aAST) 493 { 494 final ArrayList visitors = 495 (ArrayList ) mTokenToChecks.get( 496 TokenTypes.getTokenName(aAST.getType())); 497 if (visitors != null) { 498 for (int i = 0; i < visitors.size(); i++) { 499 final Check check = (Check) visitors.get(i); 500 check.visitToken(aAST); 501 } 502 } 503 } 504 505 509 private void notifyLeave(DetailAST aAST) 510 { 511 final ArrayList visitors = 512 (ArrayList ) mTokenToChecks.get( 513 TokenTypes.getTokenName(aAST.getType())); 514 if (visitors != null) { 515 for (int i = 0; i < visitors.size(); i++) { 516 final Check check = (Check) visitors.get(i); 517 check.leaveToken(aAST); 518 } 519 } 520 } 521 522 529 public static DetailAST parse(FileContents aContents) 530 throws RecognitionException, TokenStreamException 531 { 532 DetailAST rootAST = null; 533 534 try { 535 rootAST = parse(aContents, true, true, true); 536 } 537 catch (final RecognitionException exception) { 538 try { 539 rootAST = parse(aContents, true, true, false); 540 } 541 catch (final RecognitionException exception2) { 542 rootAST = parse(aContents, false, false, false); 543 } 544 } 545 return rootAST; 546 } 547 548 559 private static DetailAST parse( 560 FileContents aContents, 561 boolean aSilentlyConsumeErrors, 562 boolean aTreatAssertAsKeyword, 563 boolean aTreatEnumAsKeyword) 564 throws RecognitionException, TokenStreamException 565 { 566 final Reader sar = new StringArrayReader(aContents.getLines()); 567 final GeneratedJavaLexer lexer = new GeneratedJavaLexer(sar); 568 lexer.setFilename(aContents.getFilename()); 569 lexer.setCommentListener(aContents); 570 lexer.setTreatAssertAsKeyword(aTreatAssertAsKeyword); 571 lexer.setTreatEnumAsKeyword(aTreatEnumAsKeyword); 572 573 final GeneratedJavaRecognizer parser = 574 aSilentlyConsumeErrors 575 ? new SilentJavaRecognizer(lexer) 576 : new GeneratedJavaRecognizer(lexer); 577 parser.setFilename(aContents.getFilename()); 578 parser.setASTNodeClass(DetailAST.class.getName()); 579 parser.compilationUnit(); 580 581 return (DetailAST) parser.getAST(); 582 } 583 584 585 public void process(File [] aFiles) 586 { 587 final File [] javaFiles = filter(aFiles); 588 589 for (int i = 0; i < javaFiles.length; i++) { 590 process(javaFiles[i]); 591 } 592 } 593 594 597 public void destroy() 598 { 599 for (final Iterator it = mAllChecks.iterator(); it.hasNext();) { 600 final Check c = (Check) it.next(); 601 c.destroy(); 602 } 603 mCache.destroy(); 604 super.destroy(); 605 } 606 607 611 private boolean useRecursiveAlgorithm() 612 { 613 return mRecursive; 614 } 615 616 621 private void processIter(DetailAST aRoot) 622 { 623 DetailAST curNode = aRoot; 624 while (curNode != null) { 625 notifyVisit(curNode); 626 DetailAST toVisit = (DetailAST) curNode.getFirstChild(); 627 while ((curNode != null) && (toVisit == null)) { 628 notifyLeave(curNode); 629 toVisit = (DetailAST) curNode.getNextSibling(); 630 if (toVisit == null) { 631 curNode = curNode.getParent(); 632 } 633 } 634 curNode = toVisit; 635 } 636 } 637 } 638 | Popular Tags |