View Javadoc
1   /*
2    * Copyright (c) 2011-2024 Qulice.com
3    *
4    * All rights reserved.
5    *
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions
8    * are met: 1) Redistributions of source code must retain the above
9    * copyright notice, this list of conditions and the following
10   * disclaimer. 2) Redistributions in binary form must reproduce the above
11   * copyright notice, this list of conditions and the following
12   * disclaimer in the documentation and/or other materials provided
13   * with the distribution. 3) Neither the name of the Qulice.com nor
14   * the names of its contributors may be used to endorse or promote
15   * products derived from this software without specific prior written
16   * permission.
17   *
18   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
20   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29   * OF THE POSSIBILITY OF SUCH DAMAGE.
30   */
31  package com.qulice.checkstyle;
32  
33  import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
34  import com.puppycrawl.tools.checkstyle.api.FileText;
35  import java.io.File;
36  import org.cactoos.text.Joined;
37  
38  /**
39   * Make sure each line indentation is either:
40   * <ul>
41   * <li>the same as previous one or less
42   * <li>bigger than previous by exactly 4
43   * </ul>
44   * All other cases must cause a failure.
45   *
46   * @since 0.3
47   */
48  public final class CascadeIndentationCheck extends AbstractFileSetCheck {
49      /**
50       * Exact indentation increase difference.
51       */
52      private static final int LINE_INDENT_DIFF = 4;
53  
54      @Override
55      public void processFiltered(final File file, final FileText lines) {
56          int previous = 0;
57          for (int pos = 0; pos < lines.size(); pos += 1) {
58              final String line = lines.get(pos);
59              final int current = CascadeIndentationCheck.indentation(line);
60              if (CascadeIndentationCheck.inCommentBlock(line)
61                  || line.isEmpty()) {
62                  continue;
63              }
64              if (current > previous
65                  && current != previous
66                  + CascadeIndentationCheck.LINE_INDENT_DIFF) {
67                  this.log(
68                      pos + 1,
69                      String.format(
70                          new Joined(
71                              "",
72                              "Indentation (%d) must be same or ",
73                              "less than previous line (%d), or ",
74                              "bigger by exactly 4"
75                          ).toString(),
76                          current,
77                          previous
78                      )
79                  );
80              }
81              previous = current;
82          }
83      }
84  
85      /**
86       * Checks if the line belongs to a comment block.
87       * @param line Input.
88       * @return True if the line belongs to a comment block.
89       */
90      private static boolean inCommentBlock(final String line) {
91          final String trimmed = line.trim();
92          return !trimmed.isEmpty()
93              && (trimmed.charAt(0) == '*'
94                  || trimmed.startsWith("/*")
95                  || trimmed.startsWith("*/")
96                  );
97      }
98  
99      /**
100      * Calculates indentation of a line.
101      * @param line Input line
102      * @return Indentation of the given line.
103      */
104     private static int indentation(final String line) {
105         int result = 0;
106         for (int pos = 0; pos < line.length(); pos += 1) {
107             if (!Character.isWhitespace(line.charAt(pos))) {
108                 break;
109             }
110             result += 1;
111         }
112         return result;
113     }
114 
115 }