1
2
3
4
5 package com.qulice.checkstyle;
6
7 import java.util.HashMap;
8 import java.util.Map;
9 import java.util.regex.Matcher;
10 import java.util.regex.Pattern;
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 final class RequiredJavaDocTag {
36
37
38
39
40 private final String name;
41
42
43
44
45 private final Pattern tag;
46
47
48
49
50 private final Pattern content;
51
52
53
54
55 private final Reporter reporter;
56
57
58
59
60
61
62
63
64
65 RequiredJavaDocTag(
66 final String cname,
67 final Pattern ptag,
68 final Pattern patt,
69 final Reporter rep
70 ) {
71 this.name = cname;
72 this.tag = ptag;
73 this.content = patt;
74 this.reporter = rep;
75 }
76
77
78
79
80
81
82
83
84 void matchTagFormat(
85 final String[] lines,
86 final int start,
87 final int end
88 ) {
89 final Pattern loose = Pattern.compile(
90 String.format("@%s\\b", this.name)
91 );
92 Integer looseline = null;
93 final Map<Integer, String> found = new HashMap<>(1);
94 for (int pos = start; pos <= end; pos += 1) {
95 final String line = lines[pos];
96 final Matcher matcher = this.tag.matcher(line);
97 if (RequiredJavaDocTag.tagFound(matcher)) {
98 found.put(pos, matcher.group("cont"));
99 break;
100 }
101 if (looseline == null && loose.matcher(line).find()) {
102 looseline = pos;
103 }
104 }
105 if (found.isEmpty()) {
106 this.logMissing(start, looseline);
107 } else {
108 this.logMismatches(found);
109 }
110 }
111
112 private void logMissing(final int start, final Integer looseline) {
113 if (looseline == null) {
114 this.reporter.log(
115 start + 1,
116 "Missing ''@{0}'' tag in class/interface comment",
117 this.name
118 );
119 } else {
120 this.reporter.log(
121 looseline + 1,
122 "Malformed ''@{0}'' tag, expected '' * @{0} <value>'' format",
123 this.name
124 );
125 }
126 }
127
128 private void logMismatches(final Map<Integer, String> found) {
129 for (final Map.Entry<Integer, String> item : found.entrySet()) {
130 if (!this.content.matcher(item.getValue()).matches()) {
131 this.reporter.log(
132 item.getKey() + 1,
133 "Tag text ''{0}'' does not match the pattern ''{1}''",
134 item.getValue(),
135 this.content.toString()
136 );
137 }
138 }
139 }
140
141 private static boolean tagFound(final Matcher matcher) {
142 return matcher.matches()
143 && !RequiredJavaDocTag.empty(matcher.group("name"))
144 && !RequiredJavaDocTag.empty(matcher.group("cont"));
145 }
146
147 private static boolean empty(final String str) {
148 return str == null || str.chars().allMatch(Character::isWhitespace);
149 }
150
151
152
153
154
155
156
157 @FunctionalInterface
158 interface Reporter {
159
160
161
162
163
164
165
166
167
168 void log(int line, String msg, Object... args);
169 }
170 }