Coverage Report - com.puppycrawl.tools.checkstyle.checks.indentation.ExpressionHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
ExpressionHandler
99%
130/131
93%
86/92
2.613
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2014  Oliver Burn
 4  
 //
 5  
 // This library is free software; you can redistribute it and/or
 6  
 // modify it under the terms of the GNU Lesser General Public
 7  
 // License as published by the Free Software Foundation; either
 8  
 // version 2.1 of the License, or (at your option) any later version.
 9  
 //
 10  
 // This library is distributed in the hope that it will be useful,
 11  
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 // Lesser General Public License for more details.
 14  
 //
 15  
 // You should have received a copy of the GNU Lesser General Public
 16  
 // License along with this library; if not, write to the Free Software
 17  
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 18  
 ////////////////////////////////////////////////////////////////////////////////
 19  
 package com.puppycrawl.tools.checkstyle.checks.indentation;
 20  
 
 21  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 22  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 23  
 import com.puppycrawl.tools.checkstyle.api.Utils;
 24  
 import java.util.Arrays;
 25  
 
 26  
 /**
 27  
  * Abstract base class for all handlers.
 28  
  *
 29  
  * @author jrichard
 30  
  */
 31  
 public abstract class ExpressionHandler
 32  
 {
 33  
     /**
 34  
      * The instance of <code>IndentationCheck</code> using this handler.
 35  
      */
 36  
     private final IndentationCheck mIndentCheck;
 37  
 
 38  
     /** the AST which is handled by this handler */
 39  
     private final DetailAST mMainAst;
 40  
 
 41  
     /** name used during output to user */
 42  
     private final String mTypeName;
 43  
 
 44  
     /** containing AST handler */
 45  
     private final ExpressionHandler mParent;
 46  
 
 47  
     /** indentation amount for this handler */
 48  
     private IndentLevel mLevel;
 49  
 
 50  
     /**
 51  
      * Construct an instance of this handler with the given indentation check,
 52  
      * name, abstract syntax tree, and parent handler.
 53  
      *
 54  
      * @param aIndentCheck   the indentation check
 55  
      * @param aTypeName      the name of the handler
 56  
      * @param aExpr          the abstract syntax tree
 57  
      * @param aParent        the parent handler
 58  
      */
 59  
     public ExpressionHandler(IndentationCheck aIndentCheck,
 60  
             String aTypeName, DetailAST aExpr, ExpressionHandler aParent)
 61  1809
     {
 62  1809
         mIndentCheck = aIndentCheck;
 63  1809
         mTypeName = aTypeName;
 64  1809
         mMainAst = aExpr;
 65  1809
         mParent = aParent;
 66  1809
     }
 67  
 
 68  
     /**
 69  
      * Get the indentation amount for this handler. For performance reasons,
 70  
      * this value is cached. The first time this method is called, the
 71  
      * indentation amount is computed and stored. On further calls, the stored
 72  
      * value is returned.
 73  
      *
 74  
      * @return the expected indentation amount
 75  
      */
 76  
     public final IndentLevel getLevel()
 77  
     {
 78  7312
         if (mLevel == null) {
 79  1377
             mLevel = getLevelImpl();
 80  
         }
 81  7312
         return mLevel;
 82  
     }
 83  
 
 84  
     /**
 85  
      * Compute the indentation amount for this handler.
 86  
      *
 87  
      * @return the expected indentation amount
 88  
      */
 89  
     protected IndentLevel getLevelImpl()
 90  
     {
 91  1112
         return mParent.suggestedChildLevel(this);
 92  
     }
 93  
 
 94  
     /**
 95  
      * Indentation level suggested for a child element. Children don't have
 96  
      * to respect this, but most do.
 97  
      *
 98  
      * @param aChild  child AST (so suggestion level can differ based on child
 99  
      *                  type)
 100  
      *
 101  
      * @return suggested indentation for child
 102  
      */
 103  
     public IndentLevel suggestedChildLevel(ExpressionHandler aChild)
 104  
     {
 105  23
         return new IndentLevel(getLevel(), getBasicOffset());
 106  
     }
 107  
 
 108  
     /**
 109  
      * Log an indentation error.
 110  
      *
 111  
      * @param aAst           the expression that caused the error
 112  
      * @param aSubtypeName   the type of the expression
 113  
      * @param aActualLevel    the actual indent level of the expression
 114  
      */
 115  
     protected final void logError(DetailAST aAst, String aSubtypeName,
 116  
                                   int aActualLevel)
 117  
     {
 118  121
         logError(aAst, aSubtypeName, aActualLevel, getLevel());
 119  121
     }
 120  
 
 121  
     /**
 122  
      * Log an indentation error.
 123  
      *
 124  
      * @param aAst           the expression that caused the error
 125  
      * @param aSubtypeName   the type of the expression
 126  
      * @param aActualLevel   the actual indent level of the expression
 127  
      * @param aExpectedLevel the expected indent level of the expression
 128  
      */
 129  
     protected final void logError(DetailAST aAst, String aSubtypeName,
 130  
                                   int aActualLevel, IndentLevel aExpectedLevel)
 131  
     {
 132  201
         final String typeStr =
 133  
             ("".equals(aSubtypeName) ? "" : (" " + aSubtypeName));
 134  201
         mIndentCheck.indentationLog(aAst.getLineNo(), "indentation.error",
 135  
                 mTypeName + typeStr, aActualLevel, aExpectedLevel);
 136  201
     }
 137  
 
 138  
     /**
 139  
      * Log child indentation error.
 140  
      *
 141  
      * @param aLine           the expression that caused the error
 142  
      * @param aActualLevel   the actual indent level of the expression
 143  
      * @param aExpectedLevel the expected indent level of the expression
 144  
      */
 145  
     private void logChildError(int aLine,
 146  
                                int aActualLevel,
 147  
                                IndentLevel aExpectedLevel)
 148  
     {
 149  146
         mIndentCheck.indentationLog(aLine, "indentation.child.error",
 150  
                 mTypeName, aActualLevel, aExpectedLevel);
 151  146
     }
 152  
 
 153  
     /**
 154  
      * Determines if the given expression is at the start of a line.
 155  
      *
 156  
      * @param aAst   the expression to check
 157  
      *
 158  
      * @return true if it is, false otherwise
 159  
      */
 160  
     protected final boolean startsLine(DetailAST aAst)
 161  
     {
 162  2292
         return getLineStart(aAst) == expandedTabsColumnNo(aAst);
 163  
     }
 164  
 
 165  
     /**
 166  
      * Determines if two expressions are on the same line.
 167  
      *
 168  
      * @param aAst1   the first expression
 169  
      * @param aAst2   the second expression
 170  
      *
 171  
      * @return true if they are, false otherwise
 172  
      */
 173  
     static boolean areOnSameLine(DetailAST aAst1, DetailAST aAst2)
 174  
     {
 175  728
         return (aAst1 != null) && (aAst2 != null)
 176  
             && (aAst1.getLineNo() == aAst2.getLineNo());
 177  
     }
 178  
 
 179  
     /**
 180  
      * Searchs in given sub-tree (including given node) for the token
 181  
      * which represents first symbol for this sub-tree in file.
 182  
      * @param aAST a root of sub-tree in which the search shoul be performed.
 183  
      * @return a token which occurs first in the file.
 184  
      */
 185  
     static DetailAST getFirstToken(DetailAST aAST)
 186  
     {
 187  394
         DetailAST first = aAST;
 188  394
         DetailAST child = aAST.getFirstChild();
 189  
 
 190  631
         while (child != null) {
 191  237
             final DetailAST toTest = getFirstToken(child);
 192  237
             if ((toTest.getLineNo() < first.getLineNo())
 193  
                 || ((toTest.getLineNo() == first.getLineNo())
 194  
                     && (toTest.getColumnNo() < first.getColumnNo())))
 195  
             {
 196  74
                 first = toTest;
 197  
             }
 198  237
             child = child.getNextSibling();
 199  237
         }
 200  
 
 201  394
         return first;
 202  
     }
 203  
 
 204  
     /**
 205  
      * Get the start of the line for the given expression.
 206  
      *
 207  
      * @param aAst   the expression to find the start of the line for
 208  
      *
 209  
      * @return the start of the line for the given expression
 210  
      */
 211  
     protected final int getLineStart(DetailAST aAst)
 212  
     {
 213  2819
         final String line = mIndentCheck.getLines()[aAst.getLineNo() - 1];
 214  2819
         return getLineStart(line);
 215  
     }
 216  
 
 217  
     // TODO: this whole checking of consecuitive/expression line indents is
 218  
     // smelling pretty bad... and is in serious need of pruning.  But, I
 219  
     // want to finish the invalid tests before I start messing around with
 220  
     // it.
 221  
 
 222  
     /**
 223  
      * Check the indentation of consecutive lines for the expression we are
 224  
      * handling.
 225  
      *
 226  
      * @param aStartLine     the first line to check
 227  
      * @param aEndLine       the last line to check
 228  
      * @param aIndentLevel   the required indent level
 229  
      */
 230  
     protected final void checkLinesIndent(int aStartLine, int aEndLine,
 231  
         IndentLevel aIndentLevel)
 232  
     {
 233  
         // check first line
 234  114
         checkSingleLine(aStartLine, aIndentLevel);
 235  
 
 236  
         // check following lines
 237  114
         final IndentLevel offsetLevel =
 238  
             new IndentLevel(aIndentLevel, getBasicOffset());
 239  141
         for (int i = aStartLine + 1; i <= aEndLine; i++) {
 240  27
             checkSingleLine(i, offsetLevel);
 241  
         }
 242  114
     }
 243  
 
 244  
     /**
 245  
      * @return true if indentation should be increased after
 246  
      *              fisrt line in checkLinesIndent()
 247  
      *         false otherwise
 248  
      */
 249  
     protected boolean shouldIncreaseIndent()
 250  
     {
 251  65
         return true;
 252  
     }
 253  
 
 254  
     /**
 255  
      * Check the indentation for a set of lines.
 256  
      *
 257  
      * @param aLines              the set of lines to check
 258  
      * @param aIndentLevel        the indentation level
 259  
      * @param aFirstLineMatches   whether or not the first line has to match
 260  
      * @param aFirstLine          firstline of whole expression
 261  
      */
 262  
     private void checkLinesIndent(LineSet aLines,
 263  
                                   IndentLevel aIndentLevel,
 264  
                                   boolean aFirstLineMatches,
 265  
                                   int aFirstLine)
 266  
     {
 267  1619
         if (aLines.isEmpty()) {
 268  32
             return;
 269  
         }
 270  
 
 271  
         // check first line
 272  1587
         final int startLine = aLines.firstLine();
 273  1587
         final int endLine = aLines.lastLine();
 274  1587
         final int startCol = aLines.firstLineCol();
 275  
 
 276  1587
         final int realStartCol =
 277  
             getLineStart(mIndentCheck.getLines()[startLine - 1]);
 278  
 
 279  1587
         if (realStartCol == startCol) {
 280  727
             checkSingleLine(startLine, startCol, aIndentLevel,
 281  
                 aFirstLineMatches);
 282  
         }
 283  
 
 284  
         // if first line starts the line, following lines are indented
 285  
         // one level; but if the first line of this expression is
 286  
         // nested with the previous expression (which is assumed if it
 287  
         // doesn't start the line) then don't indent more, the first
 288  
         // indentation is absorbed by the nesting
 289  
 
 290  
         // TODO: shouldIncreaseIndent() is a hack, should be removed
 291  
         //       after complete rewriting of checkExpressionSubtree()
 292  
 
 293  1587
         IndentLevel theLevel = aIndentLevel;
 294  1587
         if (aFirstLineMatches
 295  
             || ((aFirstLine > mMainAst.getLineNo()) && shouldIncreaseIndent()))
 296  
         {
 297  649
             theLevel = new IndentLevel(aIndentLevel, getBasicOffset());
 298  
         }
 299  
 
 300  
         // check following lines
 301  1729
         for (int i = startLine + 1; i <= endLine; i++) {
 302  142
             final Integer col = aLines.getStartColumn(i);
 303  
             // startCol could be null if this line didn't have an
 304  
             // expression that was required to be checked (it could be
 305  
             // checked by a child expression)
 306  
 
 307  142
             if (col != null) {
 308  130
                 checkSingleLine(i, col.intValue(), theLevel, false);
 309  
             }
 310  
         }
 311  1587
     }
 312  
 
 313  
     /**
 314  
      * Check the indent level for a single line.
 315  
      *
 316  
      * @param aLineNum       the line number to check
 317  
      * @param aIndentLevel   the required indent level
 318  
      */
 319  
     private void checkSingleLine(int aLineNum, IndentLevel aIndentLevel)
 320  
     {
 321  141
         final String line = mIndentCheck.getLines()[aLineNum - 1];
 322  141
         final int start = getLineStart(line);
 323  141
         if (aIndentLevel.gt(start)) {
 324  9
             logChildError(aLineNum, start, aIndentLevel);
 325  
         }
 326  141
     }
 327  
 
 328  
     /**
 329  
      * Check the indentation for a single line.
 330  
      *
 331  
      * @param aLineNum       the number of the line to check
 332  
      * @param aColNum        the column number we are starting at
 333  
      * @param aIndentLevel   the indentation level
 334  
      * @param aMustMatch     whether or not the indentation level must match
 335  
      */
 336  
 
 337  
     private void checkSingleLine(int aLineNum, int aColNum,
 338  
         IndentLevel aIndentLevel, boolean aMustMatch)
 339  
     {
 340  857
         final String line = mIndentCheck.getLines()[aLineNum - 1];
 341  857
         final int start = getLineStart(line);
 342  
         // if must match is set, it is an error if the line start is not
 343  
         // at the correct indention level; otherwise, it is an only an
 344  
         // error if this statement starts the line and it is less than
 345  
         // the correct indentation level
 346  857
         if (aMustMatch ? !aIndentLevel.accept(start)
 347  
             : (aColNum == start) && aIndentLevel.gt(start))
 348  
         {
 349  137
             logChildError(aLineNum, start, aIndentLevel);
 350  
         }
 351  857
     }
 352  
 
 353  
     /**
 354  
      * Get the start of the specified line.
 355  
      *
 356  
      * @param aLine   the specified line number
 357  
      *
 358  
      * @return the start of the specified line
 359  
      */
 360  
     protected final int getLineStart(String aLine)
 361  
     {
 362  55962
         for (int start = 0; start < aLine.length(); start++) {
 363  55962
             final char c = aLine.charAt(start);
 364  
 
 365  55962
             if (!Character.isWhitespace(c)) {
 366  5808
                 return Utils.lengthExpandedTabs(
 367  
                     aLine, start, mIndentCheck.getIndentationTabWidth());
 368  
             }
 369  
         }
 370  0
         return 0;
 371  
     }
 372  
 
 373  
     // TODO: allowNesting either shouldn't be allowed with
 374  
     //  firstLineMatches, or I should change the firstLineMatches logic
 375  
     //  so it doesn't match if the first line is nested
 376  
 
 377  
     /**
 378  
      * Check the indent level of the children of the specified parent
 379  
      * expression.
 380  
      *
 381  
      * @param aParent             the parent whose children we are checking
 382  
      * @param aTokenTypes         the token types to check
 383  
      * @param aStartLevel         the starting indent level
 384  
      * @param aFirstLineMatches   whether or not the first line needs to match
 385  
      * @param aAllowNesting       whether or not nested children are allowed
 386  
      */
 387  
     protected final void checkChildren(DetailAST aParent,
 388  
                                        int[] aTokenTypes,
 389  
                                        IndentLevel aStartLevel,
 390  
                                        boolean aFirstLineMatches,
 391  
                                        boolean aAllowNesting)
 392  
     {
 393  561
         Arrays.sort(aTokenTypes);
 394  561
         for (DetailAST child = aParent.getFirstChild();
 395  2708
                 child != null;
 396  2147
                 child = child.getNextSibling())
 397  
         {
 398  2147
             if (Arrays.binarySearch(aTokenTypes, child.getType()) >= 0) {
 399  575
                 checkExpressionSubtree(child, aStartLevel,
 400  
                     aFirstLineMatches, aAllowNesting);
 401  
             }
 402  
         }
 403  561
     }
 404  
 
 405  
     /**
 406  
      * Check the indentation level for an expression subtree.
 407  
      *
 408  
      * @param aTree               the expression subtree to check
 409  
      * @param aLevel              the indentation level
 410  
      * @param aFirstLineMatches   whether or not the first line has to match
 411  
      * @param aAllowNesting       whether or not subtree nesting is allowed
 412  
      */
 413  
     protected final void checkExpressionSubtree(
 414  
         DetailAST aTree,
 415  
         IndentLevel aLevel,
 416  
         boolean aFirstLineMatches,
 417  
         boolean aAllowNesting
 418  
     )
 419  
     {
 420  1619
         final LineSet subtreeLines = new LineSet();
 421  1619
         final int firstLine = getFirstLine(Integer.MAX_VALUE, aTree);
 422  1619
         if (aFirstLineMatches && !aAllowNesting) {
 423  404
             subtreeLines.addLineAndCol(firstLine,
 424  
                 getLineStart(mIndentCheck.getLines()[firstLine - 1]));
 425  
         }
 426  1619
         findSubtreeLines(subtreeLines, aTree, aAllowNesting);
 427  
 
 428  1619
         checkLinesIndent(subtreeLines, aLevel, aFirstLineMatches, firstLine);
 429  1619
     }
 430  
 
 431  
     /**
 432  
      * Get the first line for a given expression.
 433  
      *
 434  
      * @param aStartLine   the line we are starting from
 435  
      * @param aTree        the expression to find the first line for
 436  
      *
 437  
      * @return the first line of the expression
 438  
      */
 439  
     protected final int getFirstLine(int aStartLine, DetailAST aTree)
 440  
     {
 441  
         // find line for this node
 442  
         // TODO: getLineNo should probably not return < 0, but it is for
 443  
         // the interface methods... I should ask about this
 444  12695
         int realStart = aStartLine;
 445  12695
         final int currLine = aTree.getLineNo();
 446  12695
         if (currLine < realStart) {
 447  1763
             realStart = currLine;
 448  
         }
 449  
 
 450  
         // check children
 451  12695
         for (DetailAST node = aTree.getFirstChild();
 452  23731
             node != null;
 453  11036
             node = node.getNextSibling())
 454  
         {
 455  11036
             realStart = getFirstLine(realStart, node);
 456  
         }
 457  
 
 458  12695
         return realStart;
 459  
     }
 460  
 
 461  
     /**
 462  
      * Get the column number for the start of a given expression, expanding
 463  
      * tabs out into spaces in the process.
 464  
      *
 465  
      * @param aAST   the expression to find the start of
 466  
      *
 467  
      * @return the column number for the start of the expression
 468  
      */
 469  
     protected final int expandedTabsColumnNo(DetailAST aAST)
 470  
     {
 471  11113
         final String line =
 472  
             mIndentCheck.getLines()[aAST.getLineNo() - 1];
 473  
 
 474  11113
         return Utils.lengthExpandedTabs(line, aAST.getColumnNo(),
 475  
             mIndentCheck.getIndentationTabWidth());
 476  
     }
 477  
 
 478  
     /**
 479  
      * Find the set of lines for a given subtree.
 480  
      *
 481  
      * @param aLines          the set of lines to add to
 482  
      * @param aTree           the subtree to examine
 483  
      * @param aAllowNesting   whether or not to allow nested subtrees
 484  
      */
 485  
     protected final void findSubtreeLines(LineSet aLines, DetailAST aTree,
 486  
         boolean aAllowNesting)
 487  
     {
 488  
         // find line for this node
 489  
         // TODO: getLineNo should probably not return < 0, but it is for
 490  
         // the interface methods... I should ask about this
 491  
 
 492  6254
         if (getIndentCheck().getHandlerFactory().isHandledType(aTree.getType())
 493  
             || (aTree.getLineNo() < 0))
 494  
         {
 495  529
             return;
 496  
         }
 497  
 
 498  
         // TODO: the problem with this is that not all tree tokens actually
 499  
         // have the right column number -- I should get a list of these
 500  
         // and verify that checking nesting this way won't cause problems
 501  
 //          if (aAllowNesting && aTree.getColumnNo() != getLineStart(aTree)) {
 502  
 //              return;
 503  
 //          }
 504  
 
 505  5725
         final int lineNum = aTree.getLineNo();
 506  5725
         final Integer colNum = aLines.getStartColumn(lineNum);
 507  
 
 508  5725
         final int thisLineColumn = expandedTabsColumnNo(aTree);
 509  5725
         if ((colNum == null) || (thisLineColumn < colNum.intValue())) {
 510  2327
             aLines.addLineAndCol(lineNum, thisLineColumn);
 511  
         }
 512  
 
 513  
         // check children
 514  5725
         for (DetailAST node = aTree.getFirstChild();
 515  10083
             node != null;
 516  4358
             node = node.getNextSibling())
 517  
         {
 518  4358
             findSubtreeLines(aLines, node, aAllowNesting);
 519  
         }
 520  5725
     }
 521  
 
 522  
     /**
 523  
      * Check the indentation level of modifiers.
 524  
      */
 525  
     protected final void checkModifiers()
 526  
     {
 527  275
         final DetailAST modifiers =
 528  
             mMainAst.findFirstToken(TokenTypes.MODIFIERS);
 529  275
         for (DetailAST modifier = modifiers.getFirstChild();
 530  494
              modifier != null;
 531  219
              modifier = modifier.getNextSibling())
 532  
         {
 533  
             /*
 534  
             if (!areOnSameLine(modifier, prevExpr)) {
 535  
                 continue;
 536  
             }
 537  
             */
 538  219
             if (startsLine(modifier)
 539  
                 && !getLevel().accept(expandedTabsColumnNo(modifier)))
 540  
             {
 541  12
                 logError(modifier, "modifier",
 542  
                     expandedTabsColumnNo(modifier));
 543  
             }
 544  
         }
 545  275
     }
 546  
 
 547  
     /**
 548  
      * Check the indentation of the expression we are handling.
 549  
      */
 550  
     public abstract void checkIndentation();
 551  
 
 552  
     /**
 553  
      * Accessor for the IndentCheck attribute.
 554  
      *
 555  
      * @return the IndentCheck attribute
 556  
      */
 557  
     protected final IndentationCheck getIndentCheck()
 558  
     {
 559  10172
         return mIndentCheck;
 560  
     }
 561  
 
 562  
     /**
 563  
      * Accessor for the MainAst attribute.
 564  
      *
 565  
      * @return the MainAst attribute
 566  
      */
 567  
     protected final DetailAST getMainAst()
 568  
     {
 569  13112
         return mMainAst;
 570  
     }
 571  
 
 572  
     /**
 573  
      * Accessor for the Parent attribute.
 574  
      *
 575  
      * @return the Parent attribute
 576  
      */
 577  
     protected final ExpressionHandler getParent()
 578  
     {
 579  2038
         return mParent;
 580  
     }
 581  
 
 582  
     /**
 583  
      * A shortcut for <code>IndentationCheck</code> property.
 584  
      * @return value of basicOffset property of <code>IndentationCheck</code>
 585  
      */
 586  
     protected final int getBasicOffset()
 587  
     {
 588  2653
         return getIndentCheck().getBasicOffset();
 589  
     }
 590  
 
 591  
     /**
 592  
      * A shortcut for <code>IndentationCheck</code> property.
 593  
      * @return value of braceAdjustment property
 594  
      *         of <code>IndentationCheck</code>
 595  
      */
 596  
     protected final int getBraceAdjustement()
 597  
     {
 598  1195
         return getIndentCheck().getBraceAdjustement();
 599  
     }
 600  
 
 601  
     /**
 602  
      * Check the indentation of the right parenthesis.
 603  
      * @param aRparen parenthesis to check
 604  
      * @param aLparen left parenthesis associated with aRparen
 605  
      */
 606  
     protected final void checkRParen(DetailAST aLparen, DetailAST aRparen)
 607  
     {
 608  
         // no paren - no check :)
 609  692
         if (aRparen == null) {
 610  309
             return;
 611  
         }
 612  
 
 613  
         // the rcurly can either be at the correct indentation,
 614  
         // or not first on the line ...
 615  383
         final int rparenLevel = expandedTabsColumnNo(aRparen);
 616  383
         if (getLevel().accept(rparenLevel) || !startsLine(aRparen)) {
 617  373
             return;
 618  
         }
 619  
 
 620  
         // or has <lparen level> + 1 indentation
 621  10
         final int lparenLevel = expandedTabsColumnNo(aLparen);
 622  10
         if (rparenLevel == (lparenLevel + 1)) {
 623  1
             return;
 624  
         }
 625  
 
 626  9
         logError(aRparen, "rparen", rparenLevel);
 627  9
     }
 628  
 
 629  
     /**
 630  
      * Check the indentation of the left parenthesis.
 631  
      * @param aLparen parenthesis to check
 632  
      */
 633  
     protected final void checkLParen(final DetailAST aLparen)
 634  
     {
 635  
         // the rcurly can either be at the correct indentation, or on the
 636  
         // same line as the lcurly
 637  1003
         if ((aLparen == null)
 638  
             || getLevel().accept(expandedTabsColumnNo(aLparen))
 639  
             || !startsLine(aLparen))
 640  
         {
 641  1002
             return;
 642  
         }
 643  1
         logError(aLparen, "lparen", expandedTabsColumnNo(aLparen));
 644  1
     }
 645  
 }