1
2
3
4
5 package com.qulice.checkstyle;
6
7 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
8 import com.puppycrawl.tools.checkstyle.api.DetailAST;
9 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 public final class JavadocTagsDotCheck extends AbstractCheck {
39
40
41
42
43 private static final String MESSAGE =
44 "No dot allowed at the end of a '@param' or '@return' Javadoc tag";
45
46 @Override
47 public int[] getDefaultTokens() {
48 return new int[] {
49 TokenTypes.METHOD_DEF,
50 TokenTypes.CTOR_DEF,
51 };
52 }
53
54 @Override
55 public int[] getAcceptableTokens() {
56 return this.getDefaultTokens();
57 }
58
59 @Override
60 public int[] getRequiredTokens() {
61 return this.getDefaultTokens();
62 }
63
64 @Override
65 public void visitToken(final DetailAST ast) {
66 final String[] lines = this.getLines();
67 final int cend = JavadocTagsDotCheck.findTrimmedTextUp(
68 lines, ast.getLineNo() - 1, "*/"
69 );
70 final int cstart = JavadocTagsDotCheck.findTrimmedTextUp(
71 lines, cend, "/**"
72 );
73 if (cstart >= 0 && cend > cstart) {
74 this.inspect(lines, cstart, cend);
75 }
76 }
77
78
79
80
81
82
83
84 private void inspect(final String[] lines, final int cstart, final int cend) {
85 int tag = -1;
86 for (int pos = cstart + 1; pos <= cend; pos += 1) {
87 final String trimmed = lines[pos].trim();
88 final boolean next = trimmed.startsWith("* @")
89 || "*/".equals(trimmed);
90 if (next && tag >= 0) {
91 this.verify(lines, tag, pos - 1);
92 tag = -1;
93 }
94 if (JavadocTagsDotCheck.isParamOrReturn(trimmed)) {
95 tag = pos;
96 }
97 }
98 }
99
100
101
102
103
104
105
106 private void verify(final String[] lines, final int from, final int until) {
107 for (int pos = until; pos >= from; pos -= 1) {
108 final String content = JavadocTagsDotCheck.stripMarker(lines[pos]);
109 if (!content.isEmpty()) {
110 if (content.endsWith(".")) {
111 this.log(pos + 1, JavadocTagsDotCheck.MESSAGE);
112 }
113 break;
114 }
115 }
116 }
117
118
119
120
121
122
123
124 private static boolean isParamOrReturn(final String trimmed) {
125 final String tag;
126 if (trimmed.startsWith("* @")) {
127 tag = trimmed.substring("* @".length());
128 } else {
129 tag = "";
130 }
131 return tag.startsWith("param ")
132 || tag.startsWith("return ")
133 || "return".equals(tag);
134 }
135
136
137
138
139
140
141 private static String stripMarker(final String line) {
142 String result = line.trim();
143 if (result.startsWith("*")) {
144 result = result.substring(1).trim();
145 }
146 return result;
147 }
148
149
150
151
152
153
154
155
156 private static int findTrimmedTextUp(
157 final String[] lines,
158 final int start,
159 final String text
160 ) {
161 int found = -1;
162 for (int pos = start - 1; pos >= 0; pos -= 1) {
163 if (lines[pos].trim().equals(text)) {
164 found = pos;
165 break;
166 }
167 }
168 return found;
169 }
170 }