1 package com.puppycrawl.tools.checkstyle.checks.indentation; 20 21 import java.util.Arrays ; 22 23 import com.puppycrawl.tools.checkstyle.api.DetailAST; 24 import com.puppycrawl.tools.checkstyle.api.TokenTypes; 25 import com.puppycrawl.tools.checkstyle.api.Utils; 26 27 32 public abstract class ExpressionHandler 33 { 34 37 private IndentationCheck mIndentCheck; 38 39 40 private DetailAST mMainAst; 41 42 43 private String mTypeName; 44 45 46 private ExpressionHandler mParent; 47 48 49 private IndentLevel mLevel; 50 51 60 public ExpressionHandler(IndentationCheck aIndentCheck, 61 String aTypeName, DetailAST aExpr, ExpressionHandler aParent) 62 { 63 mIndentCheck = aIndentCheck; 64 mTypeName = aTypeName; 65 mMainAst = aExpr; 66 mParent = aParent; 67 } 68 69 77 public final IndentLevel getLevel() 78 { 79 if (mLevel == null) { 80 mLevel = getLevelImpl(); 81 } 82 return mLevel; 83 } 84 85 90 protected IndentLevel getLevelImpl() 91 { 92 return mParent.suggestedChildLevel(this); 93 } 94 95 104 public IndentLevel suggestedChildLevel(ExpressionHandler aChild) 105 { 106 return new IndentLevel(getLevel(), getBasicOffset()); 107 } 108 109 116 protected final void logError(DetailAST aAst, String aSubtypeName, 117 int aActualLevel) 118 { 119 logError(aAst, aSubtypeName, aActualLevel, getLevel()); 120 } 121 122 130 protected final void logError(DetailAST aAst, String aSubtypeName, 131 int aActualLevel, IndentLevel aExpectedLevel) 132 { 133 final String typeStr = 134 ("".equals(aSubtypeName) ? "" : (" " + aSubtypeName)); 135 final Object [] args = new Object [] { 136 mTypeName + typeStr, 137 new Integer (aActualLevel), 138 aExpectedLevel, 139 }; 140 mIndentCheck.indentationLog(aAst.getLineNo(), 141 "indentation.error", 142 args); 143 } 144 145 152 private void logChildError(int aLine, 153 int aActualLevel, 154 IndentLevel aExpectedLevel) 155 { 156 final Object [] args = new Object [] { 157 mTypeName, 158 new Integer (aActualLevel), 159 aExpectedLevel, 160 }; 161 mIndentCheck.indentationLog(aLine, 162 "indentation.child.error", 163 args); 164 } 165 166 173 protected final boolean startsLine(DetailAST aAst) 174 { 175 return getLineStart(aAst) == expandedTabsColumnNo(aAst); 176 } 177 178 186 static boolean areOnSameLine(DetailAST aAst1, DetailAST aAst2) 187 { 188 return (aAst1 != null) && (aAst2 != null) 189 && (aAst1.getLineNo() == aAst2.getLineNo()); 190 } 191 192 198 static DetailAST getFirstToken(DetailAST aAST) 199 { 200 DetailAST first = aAST; 201 DetailAST child = (DetailAST) aAST.getFirstChild(); 202 203 while (child != null) { 204 final DetailAST toTest = getFirstToken(child); 205 if ((toTest.getLineNo() < first.getLineNo()) 206 || ((toTest.getLineNo() == first.getLineNo()) 207 && (toTest.getColumnNo() < first.getColumnNo()))) 208 { 209 first = toTest; 210 } 211 child = (DetailAST) child.getNextSibling(); 212 } 213 214 return first; 215 } 216 217 224 protected final int getLineStart(DetailAST aAst) 225 { 226 final String line = mIndentCheck.getLines()[aAst.getLineNo() - 1]; 227 return getLineStart(line); 228 } 229 230 235 243 protected final void checkLinesIndent(int aStartLine, int aEndLine, 244 IndentLevel aIndentLevel) 245 { 246 checkSingleLine(aStartLine, aIndentLevel); 248 249 aIndentLevel = new IndentLevel(aIndentLevel, getBasicOffset()); 251 for (int i = aStartLine + 1; i <= aEndLine; i++) { 252 checkSingleLine(i, aIndentLevel); 253 } 254 } 255 256 261 protected boolean shouldIncreaseIndent() 262 { 263 return true; 264 } 265 266 274 private void checkLinesIndent(LineSet aLines, 275 IndentLevel aIndentLevel, 276 boolean aFirstLineMatches, 277 int aFirstLine) 278 { 279 if (aLines.isEmpty()) { 280 return; 281 } 282 283 final int startLine = aLines.firstLine(); 285 final int endLine = aLines.lastLine(); 286 final int startCol = aLines.firstLineCol(); 287 288 final int realStartCol = 289 getLineStart(mIndentCheck.getLines()[startLine - 1]); 290 291 if (realStartCol == startCol) { 292 checkSingleLine(startLine, startCol, aIndentLevel, 293 aFirstLineMatches); 294 } 295 296 302 305 if (aFirstLineMatches 306 || ((aFirstLine > mMainAst.getLineNo()) && shouldIncreaseIndent())) 307 { 308 aIndentLevel = new IndentLevel(aIndentLevel, getBasicOffset()); 309 } 310 311 for (int i = startLine + 1; i <= endLine; i++) { 313 final Integer col = aLines.getStartColumn(new Integer (i)); 314 318 if (col != null) { 319 checkSingleLine(i, col.intValue(), aIndentLevel, false); 320 } 321 } 322 } 323 324 330 private void checkSingleLine(int aLineNum, IndentLevel aIndentLevel) 331 { 332 final String line = mIndentCheck.getLines()[aLineNum - 1]; 333 final int start = getLineStart(line); 334 if (aIndentLevel.gt(start)) { 335 logChildError(aLineNum, start, aIndentLevel); 336 } 337 } 338 339 347 348 private void checkSingleLine(int aLineNum, int aColNum, 349 IndentLevel aIndentLevel, boolean aMustMatch) 350 { 351 final String line = mIndentCheck.getLines()[aLineNum - 1]; 352 final int start = getLineStart(line); 353 if (aMustMatch ? !aIndentLevel.accept(start) 358 : (aColNum == start) && aIndentLevel.gt(start)) 359 { 360 logChildError(aLineNum, start, aIndentLevel); 361 } 362 } 363 364 371 protected final int getLineStart(String aLine) 372 { 373 for (int start = 0; start < aLine.length(); start++) { 374 final char c = aLine.charAt(start); 375 376 if (!Character.isWhitespace(c)) { 377 return Utils.lengthExpandedTabs( 378 aLine, start, mIndentCheck.getIndentationTabWidth()); 379 } 380 } 381 return 0; 382 } 383 384 388 398 protected final void checkChildren(DetailAST aParent, 399 int[] aTokenTypes, 400 IndentLevel aStartLevel, 401 boolean aFirstLineMatches, 402 boolean aAllowNesting) 403 { 404 Arrays.sort(aTokenTypes); 405 for (DetailAST child = (DetailAST) aParent.getFirstChild(); 406 child != null; 407 child = (DetailAST) child.getNextSibling()) 408 { 409 if (Arrays.binarySearch(aTokenTypes, child.getType()) >= 0) { 410 checkExpressionSubtree(child, aStartLevel, 411 aFirstLineMatches, aAllowNesting); 412 } 413 } 414 } 415 416 424 protected final void checkExpressionSubtree( 425 DetailAST aTree, 426 IndentLevel aLevel, 427 boolean aFirstLineMatches, 428 boolean aAllowNesting 429 ) 430 { 431 final LineSet subtreeLines = new LineSet(); 432 final int firstLine = getFirstLine(Integer.MAX_VALUE, aTree); 433 if (aFirstLineMatches && !aAllowNesting) { 434 subtreeLines.addLineAndCol(new Integer (firstLine), 435 getLineStart(mIndentCheck.getLines()[firstLine - 1])); 436 } 437 findSubtreeLines(subtreeLines, aTree, aAllowNesting); 438 439 checkLinesIndent(subtreeLines, aLevel, aFirstLineMatches, firstLine); 440 } 441 442 450 protected final int getFirstLine(int aStartLine, DetailAST aTree) 451 { 452 456 final int currLine = aTree.getLineNo(); 457 if (currLine < aStartLine) { 458 aStartLine = currLine; 459 } 460 461 for (DetailAST node = (DetailAST) aTree.getFirstChild(); 463 node != null; 464 node = (DetailAST) node.getNextSibling()) 465 { 466 aStartLine = getFirstLine(aStartLine, node); 467 } 468 469 return aStartLine; 470 } 471 472 480 protected final int expandedTabsColumnNo(DetailAST aAST) 481 { 482 final String line = 483 mIndentCheck.getLines()[aAST.getLineNo() - 1]; 484 485 return Utils.lengthExpandedTabs(line, aAST.getColumnNo(), 486 mIndentCheck.getIndentationTabWidth()); 487 } 488 489 496 protected final void findSubtreeLines(LineSet aLines, DetailAST aTree, 497 boolean aAllowNesting) 498 { 499 503 if (getIndentCheck().getHandlerFactory().isHandledType(aTree.getType()) 504 || (aTree.getLineNo() < 0)) 505 { 506 return; 507 } 508 509 516 final Integer lineNum = new Integer (aTree.getLineNo()); 517 final Integer colNum = aLines.getStartColumn(lineNum); 518 519 final int thisLineColumn = expandedTabsColumnNo(aTree); 520 if ((colNum == null) || (thisLineColumn < colNum.intValue())) { 521 aLines.addLineAndCol(lineNum, thisLineColumn); 522 } 523 524 for (DetailAST node = (DetailAST) aTree.getFirstChild(); 526 node != null; 527 node = (DetailAST) node.getNextSibling()) 528 { 529 findSubtreeLines(aLines, node, aAllowNesting); 530 } 531 } 532 533 536 protected final void checkModifiers() 537 { 538 final DetailAST modifiers = 539 mMainAst.findFirstToken(TokenTypes.MODIFIERS); 540 for (DetailAST modifier = (DetailAST) modifiers.getFirstChild(); 541 modifier != null; 542 modifier = (DetailAST) modifier.getNextSibling()) 543 { 544 549 if (startsLine(modifier) 550 && !getLevel().accept(expandedTabsColumnNo(modifier))) 551 { 552 logError(modifier, "modifier", 553 expandedTabsColumnNo(modifier)); 554 } 555 } 556 } 557 558 561 public abstract void checkIndentation(); 562 563 568 protected final IndentationCheck getIndentCheck() 569 { 570 return mIndentCheck; 571 } 572 573 578 protected final DetailAST getMainAst() 579 { 580 return mMainAst; 581 } 582 583 588 protected final ExpressionHandler getParent() 589 { 590 return mParent; 591 } 592 593 597 protected final int getBasicOffset() 598 { 599 return getIndentCheck().getBasicOffset(); 600 } 601 602 607 protected final int getBraceAdjustement() 608 { 609 return getIndentCheck().getBraceAdjustement(); 610 } 611 612 617 protected final void checkRParen(DetailAST aLparen, DetailAST aRparen) 618 { 619 if (aRparen == null) { 621 return; 622 } 623 624 final int rparenLevel = expandedTabsColumnNo(aRparen); 627 if (getLevel().accept(rparenLevel) || !startsLine(aRparen)) { 628 return; 629 } 630 631 final int lparenLevel = expandedTabsColumnNo(aLparen); 633 if (rparenLevel == (lparenLevel + 1)) { 634 return; 635 } 636 637 logError(aRparen, "rparen", rparenLevel); 638 } 639 640 644 protected final void checkLParen(final DetailAST aLparen) 645 { 646 if ((aLparen == null) 649 || getLevel().accept(expandedTabsColumnNo(aLparen)) 650 || !startsLine(aLparen)) 651 { 652 return; 653 } 654 logError(aLparen, "lparen", expandedTabsColumnNo(aLparen)); 655 } 656 } 657 | Popular Tags |