1 package org.codehaus.mojo.taglist;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.io.LineNumberReader;
27 import java.io.Reader;
28 import java.nio.file.Files;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.List;
32 import java.util.Locale;
33
34 import org.apache.commons.lang3.StringUtils;
35 import org.apache.maven.plugin.logging.Log;
36 import org.codehaus.mojo.taglist.beans.FileReport;
37 import org.codehaus.mojo.taglist.beans.TagReport;
38 import org.codehaus.mojo.taglist.tags.TagClass;
39 import org.codehaus.plexus.util.FileUtils;
40
41
42
43
44
45
46
47
48
49
50
51 public class FileAnalyser {
52
53
54
55 private static final String STAR_COMMENT = "*";
56
57
58
59
60 private static final String SLASH_COMMENT = "//";
61
62
63
64
65 private static final int MAX_COMMENT_CHARACTERS = 99999;
66
67
68
69
70 private final String encoding;
71
72
73
74
75 private final Locale sourceFileLocale;
76
77
78
79
80 private final Collection<String> sourceDirs;
81
82
83
84
85 private final String includes;
86
87
88
89
90 private final String excludes;
91
92
93
94
95 private final Log log;
96
97
98
99
100 private final boolean multipleLineCommentsOn;
101
102
103
104
105 private final boolean emptyCommentsOn;
106
107
108
109
110 private final List<TagClass> tagClasses;
111
112
113
114
115
116
117
118 public FileAnalyser(TagListReport report, List<TagClass> tagClasses) {
119
120
121 multipleLineCommentsOn = report.isMultipleLineComments();
122 emptyCommentsOn = report.isEmptyComments();
123 log = report.getLog();
124 sourceDirs = report.getSourceDirs();
125 encoding = report.getInputEncoding();
126 sourceFileLocale = report.getSourceFileLocale();
127 this.tagClasses = tagClasses;
128 this.includes = report.getIncludesCommaSeparated();
129 this.excludes = report.getExcludesCommaSeparated();
130 }
131
132
133
134
135
136
137 public Collection<TagReport> execute() throws IOException {
138 List<File> fileList = findFilesToScan();
139
140 for (File file : fileList) {
141 if (file.exists()) {
142 scanFile(file);
143 }
144 }
145
146
147 Collection<TagReport> tagReports = new ArrayList<>();
148 for (TagClass tc : tagClasses) {
149 tagReports.add(tc.getTagReport());
150 }
151
152 return tagReports;
153 }
154
155
156
157
158
159
160 private List<File> findFilesToScan() throws IOException {
161 List<File> filesList = new ArrayList<>();
162 for (String sourceDir : sourceDirs) {
163 filesList.addAll(FileUtils.getFiles(new File(sourceDir), includes, excludes));
164 }
165 return filesList;
166 }
167
168
169
170
171
172
173
174
175 private Reader getReader(File file) throws IOException {
176 InputStream in = Files.newInputStream(file.toPath());
177 return (encoding == null) ? new InputStreamReader(in) : new InputStreamReader(in, encoding);
178 }
179
180
181
182
183
184
185 public void scanFile(File file) {
186 try (LineNumberReader reader = new LineNumberReader(getReader(file))) {
187
188 String currentLine = reader.readLine();
189 while (currentLine != null) {
190 int index;
191
192 for (TagClass tagClass : tagClasses) {
193 index = tagClass.tagMatchContains(currentLine, sourceFileLocale);
194 if (index != TagClass.NO_MATCH) {
195
196 String commentType = extractCommentType(currentLine, index);
197 if (commentType == null) {
198
199
200 break;
201 }
202
203 int tagLength = tagClass.getLastTagMatchStringLength();
204 int commentStartIndex = reader.getLineNumber();
205 StringBuilder comment = new StringBuilder();
206
207 String firstLine = StringUtils.strip(currentLine.substring(index + tagLength));
208 firstLine = StringUtils.removeEnd(firstLine, "*/");
209 if (firstLine.isEmpty() || ":".equals(firstLine)) {
210
211 if (!emptyCommentsOn) {
212 continue;
213 }
214 } else {
215
216 if (firstLine.charAt(0) == ':') {
217 comment.append(firstLine.substring(1).trim());
218 } else {
219 comment.append(firstLine);
220 }
221
222 if (multipleLineCommentsOn) {
223
224
225 reader.mark(MAX_COMMENT_CHARACTERS);
226
227
228 String futureLine = reader.readLine();
229
230
231 while (futureLine != null
232 && futureLine.trim().startsWith(commentType)
233 && !futureLine.contains(tagClass.getLastTagMatchString())) {
234 String currentComment = futureLine
235 .substring(futureLine.indexOf(commentType) + commentType.length())
236 .trim();
237 if (currentComment.startsWith("@")
238 || currentComment.isEmpty()
239 || "/".equals(currentComment)) {
240
241 break;
242 }
243
244 boolean newTagFound = false;
245 for (TagClass tc : tagClasses) {
246 if (tc.tagMatchStartsWith(currentComment, sourceFileLocale)) {
247 newTagFound = true;
248 break;
249 }
250 }
251 if (newTagFound) {
252
253 break;
254 }
255
256 comment.append(" ");
257 comment.append(currentComment);
258 futureLine = reader.readLine();
259 }
260
261
262
263 reader.reset();
264 }
265 }
266 TagReport tagReport = tagClass.getTagReport();
267 FileReport fileReport = tagReport.getFileReport(file, encoding);
268 fileReport.addComment(comment.toString(), commentStartIndex);
269 }
270 }
271 currentLine = reader.readLine();
272 }
273 } catch (IOException e) {
274 log.error("Error while scanning the file " + file.getPath(), e);
275 }
276 }
277
278
279
280
281
282
283
284
285 private String extractCommentType(String currentLine, int index) {
286 String commentType = null;
287 String beforeTag = currentLine.substring(0, index).trim();
288 if (beforeTag.endsWith(SLASH_COMMENT)) {
289 commentType = SLASH_COMMENT;
290 } else if (beforeTag.endsWith(STAR_COMMENT)) {
291 commentType = STAR_COMMENT;
292 }
293 return commentType;
294 }
295 }