View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.comments;
5   
6   import java.util.ArrayList;
7   import java.util.List;
8   
9   import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
10  import net.sourceforge.pmd.lang.java.ast.Comment;
11  import net.sourceforge.pmd.lang.rule.properties.IntegerProperty;
12  import net.sourceforge.pmd.util.StringUtil;
13  
14  /**
15   * A rule to manage those who just can't shut up...
16   * 
17   * @author Brian Remedios
18   */
19  public class CommentSizeRule extends AbstractCommentRule {
20  
21      public static final IntegerProperty MAX_LINES = new IntegerProperty("maxLines", "Maximum lines", 2, 200, 6, 2.0f);
22      public static final IntegerProperty MAX_LINE_LENGTH = new IntegerProperty("maxLineLength", "Maximum line length",
23              1, 200, 80, 2.0f);
24  
25      private static final String CR = "\n";
26  
27      public CommentSizeRule() {
28          definePropertyDescriptor(MAX_LINES);
29          definePropertyDescriptor(MAX_LINE_LENGTH);
30      }
31  
32      private static boolean hasRealText(String line) {
33  
34          if (StringUtil.isEmpty(line)) {
35              return false;
36          }
37  
38          return !StringUtil.isAnyOf(line.trim(), "//", "/*", "/**", "*", "*/");
39      }
40  
41      private boolean hasTooManyLines(Comment comment) {
42  
43          String[] lines = comment.getImage().split(CR);
44  
45          int start = 0; // start from top
46          for (; start < lines.length; start++) {
47              if (hasRealText(lines[start])) {
48                  break;
49              }
50          }
51  
52          int end = lines.length - 1; // go up from bottom
53          for (; end > 0; end--) {
54              if (hasRealText(lines[end])) {
55                  break;
56              }
57          }
58  
59          int lineCount = end - start + 1;
60  
61          return lineCount > getProperty(MAX_LINES);
62      }
63  
64      private String withoutCommentMarkup(String text) {
65  
66          return StringUtil.withoutPrefixes(text.trim(), "//", "*", "/**");
67      }
68  
69      private List<Integer> overLengthLineIndicesIn(Comment comment) {
70  
71          int maxLength = getProperty(MAX_LINE_LENGTH);
72  
73          List<Integer> indicies = new ArrayList<>();
74          String[] lines = comment.getImage().split(CR);
75  
76          int offset = comment.getBeginLine();
77  
78          for (int i = 0; i < lines.length; i++) {
79              String cleaned = withoutCommentMarkup(lines[i]);
80              if (cleaned.length() > maxLength) {
81                  indicies.add(i + offset);
82              }
83          }
84  
85          return indicies;
86      }
87  
88      @Override
89      public Object visit(ASTCompilationUnit cUnit, Object data) {
90  
91          for (Comment comment : cUnit.getComments()) {
92              if (hasTooManyLines(comment)) {
93                  addViolationWithMessage(data, cUnit, this.getMessage() + ": Too many lines", comment.getBeginLine(),
94                          comment.getEndLine());
95              }
96  
97              List<Integer> lineNumbers = overLengthLineIndicesIn(comment);
98              if (lineNumbers.isEmpty()) {
99                  continue;
100             }
101 
102             for (Integer lineNum : lineNumbers) {
103                 addViolationWithMessage(data, cUnit, this.getMessage() + ": Line too long", lineNum, lineNum);
104             }
105         }
106 
107         return super.visit(cUnit, data);
108     }
109 }