blob: 4eb23ef2a994b12b8c86a574878b1f3adaf18f54 [file] [log] [blame]
Ben Dodson920dbbb2010-08-04 15:21:06 -07001/*
2 * Copyright (C) 2010 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.doclava;
18
19import java.util.regex.Pattern;
20import java.util.regex.Matcher;
21import java.util.ArrayList;
22
23public class Comment {
24 static final Pattern LEADING_WHITESPACE = Pattern.compile("^[ \t\n\r]*(.*)$", Pattern.DOTALL);
25
26 static final Pattern TAG_BEGIN = Pattern.compile("[\r\n][\r\n \t]*@", Pattern.DOTALL);
27
28 static final Pattern TAG = Pattern.compile("(@[^ \t\r\n]+)[ \t\r\n]+(.*)", Pattern.DOTALL);
29
30 static final Pattern INLINE_TAG =
31 Pattern.compile("(.*?)\\{(@[^ \t\r\n\\}]+)[ \t\r\n]*(.*?)\\}", Pattern.DOTALL);
32
33 static final Pattern FIRST_SENTENCE =
34 Pattern.compile("((.*?)\\.)[ \t\r\n\\<](.*)", Pattern.DOTALL);
35
36 private static final String[] KNOWN_TAGS =
37 new String[] {"@author", "@since", "@version", "@deprecated", "@undeprecate", "@docRoot",
38 "@sdkCurrent", "@inheritDoc", "@more", "@samplecode", "@sample", "@include",
39 "@serial", "@com.intel.drl.spec_ref", "@ar.org.fitc.spec_ref",};
40
41 public Comment(String text, ContainerInfo base, SourcePositionInfo sp) {
42 mText = text;
43 mBase = base;
44 // sp now points to the end of the text, not the beginning!
45 mPosition = SourcePositionInfo.findBeginning(sp, text);
46 }
47
48 private void parseRegex(String text) {
49 Matcher m;
50
51 m = LEADING_WHITESPACE.matcher(text);
52 m.matches();
53 text = m.group(1);
54
55 m = TAG_BEGIN.matcher(text);
56
57 int start = 0;
58 int end = 0;
59 while (m.find()) {
60 end = m.start();
61
62 tag(text, start, end);
63
64 start = m.end() - 1; // -1 is the @
65 }
66 end = text.length();
67 tag(text, start, end);
68 }
69
70 private void tag(String text, int start, int end) {
71 SourcePositionInfo pos = SourcePositionInfo.add(mPosition, mText, start);
72
73 if (start >= 0 && end > 0 && (end - start) > 0) {
74 text = text.substring(start, end);
75
76 Matcher m = TAG.matcher(text);
77 if (m.matches()) {
78 // out of line tag
79 tag(m.group(1), m.group(2), false, pos);
80 } else {
81 // look for inline tags
82 m = INLINE_TAG.matcher(text);
83 start = 0;
84 while (m.find()) {
85 String str = m.group(1);
86 String tagname = m.group(2);
87 String tagvalue = m.group(3);
88 tag(null, m.group(1), true, pos);
89 tag(tagname, tagvalue, true, pos);
90 start = m.end();
91 }
92 int len = text.length();
93 if (start != len) {
94 tag(null, text.substring(start), true, pos);
95 }
96 }
97 }
98 }
99
100 private void tag(String name, String text, boolean isInline, SourcePositionInfo pos) {
101 /*
102 * String s = isInline ? "inline" : "outofline"; System.out.println("---> " + s + " name=[" +
103 * name + "] text=[" + text + "]");
104 */
105 if (name == null) {
106 mInlineTagsList.add(new TextTagInfo("Text", "Text", text, pos));
107 } else if (name.equals("@param")) {
108 mParamTagsList.add(new ParamTagInfo("@param", "@param", text, mBase, pos));
109 } else if (name.equals("@see")) {
110 mSeeTagsList.add(new SeeTagInfo("@see", "@see", text, mBase, pos));
111 } else if (name.equals("@link") || name.equals("@linkplain")) {
112 mInlineTagsList.add(new SeeTagInfo(name, "@see", text, mBase, pos));
113 } else if (name.equals("@throws") || name.equals("@exception")) {
114 mThrowsTagsList.add(new ThrowsTagInfo("@throws", "@throws", text, mBase, pos));
115 } else if (name.equals("@return")) {
116 mReturnTagsList.add(new ParsedTagInfo("@return", "@return", text, mBase, pos));
117 } else if (name.equals("@deprecated")) {
118 if (text.length() == 0) {
119 Errors.error(Errors.MISSING_COMMENT, pos, "@deprecated tag with no explanatory comment");
120 text = "No replacement.";
121 }
122 mDeprecatedTagsList.add(new ParsedTagInfo("@deprecated", "@deprecated", text, mBase, pos));
123 } else if (name.equals("@literal")) {
124 mInlineTagsList.add(new LiteralTagInfo(text, pos));
125 } else if (name.equals("@code")) {
126 mInlineTagsList.add(new CodeTagInfo(text, pos));
127 } else if (name.equals("@hide") || name.equals("@pending") || name.equals("@doconly")) {
128 // nothing
129 } else if (name.equals("@attr")) {
130 AttrTagInfo tag = new AttrTagInfo("@attr", "@attr", text, mBase, pos);
131 mAttrTagsList.add(tag);
132 Comment c = tag.description();
133 if (c != null) {
134 for (TagInfo t : c.tags()) {
135 mInlineTagsList.add(t);
136 }
137 }
138 } else if (name.equals("@undeprecate")) {
139 mUndeprecateTagsList.add(new TextTagInfo("@undeprecate", "@undeprecate", text, pos));
140 } else if (name.equals("@include") || name.equals("@sample")) {
141 mInlineTagsList.add(new SampleTagInfo(name, "@include", text, mBase, pos));
142 } else {
143 boolean known = false;
144 for (String s : KNOWN_TAGS) {
145 if (s.equals(name)) {
146 known = true;
147 break;
148 }
149 }
150 if (!known) {
151 Errors.error(Errors.UNKNOWN_TAG, pos == null ? null : new SourcePositionInfo(pos),
152 "Unknown tag: " + name);
153 }
154 TagInfo t = new TextTagInfo(name, name, text, pos);
155 if (isInline) {
156 mInlineTagsList.add(t);
157 } else {
158 mTagsList.add(t);
159 }
160 }
161 }
162
163 private void parseBriefTags() {
164 int N = mInlineTagsList.size();
165
166 // look for "@more" tag, which means that we might go past the first sentence.
167 int more = -1;
168 for (int i = 0; i < N; i++) {
169 if (mInlineTagsList.get(i).name().equals("@more")) {
170 more = i;
171 }
172 }
173 if (more >= 0) {
174 for (int i = 0; i < more; i++) {
175 mBriefTagsList.add(mInlineTagsList.get(i));
176 }
177 } else {
178 for (int i = 0; i < N; i++) {
179 TagInfo t = mInlineTagsList.get(i);
180 if (t.name().equals("Text")) {
181 Matcher m = FIRST_SENTENCE.matcher(t.text());
182 if (m.matches()) {
183 String text = m.group(1);
184 TagInfo firstSentenceTag = new TagInfo(t.name(), t.kind(), text, t.position());
185 mBriefTagsList.add(firstSentenceTag);
186 break;
187 }
188 }
189 mBriefTagsList.add(t);
190
191 }
192 }
193 }
194
195 public TagInfo[] tags() {
196 init();
197 return mInlineTags;
198 }
199
200 public TagInfo[] tags(String name) {
201 init();
202 ArrayList<TagInfo> results = new ArrayList<TagInfo>();
203 int N = mInlineTagsList.size();
204 for (int i = 0; i < N; i++) {
205 TagInfo t = mInlineTagsList.get(i);
206 if (t.name().equals(name)) {
207 results.add(t);
208 }
209 }
210 return results.toArray(new TagInfo[results.size()]);
211 }
212
213 public ParamTagInfo[] paramTags() {
214 init();
215 return mParamTags;
216 }
217
218 public SeeTagInfo[] seeTags() {
219 init();
220 return mSeeTags;
221 }
222
223 public ThrowsTagInfo[] throwsTags() {
224 init();
225 return mThrowsTags;
226 }
227
228 public TagInfo[] returnTags() {
229 init();
230 return mReturnTags;
231 }
232
233 public TagInfo[] deprecatedTags() {
234 init();
235 return mDeprecatedTags;
236 }
237
238 public TagInfo[] undeprecateTags() {
239 init();
240 return mUndeprecateTags;
241 }
242
243 public AttrTagInfo[] attrTags() {
244 init();
245 return mAttrTags;
246 }
247
248 public TagInfo[] briefTags() {
249 init();
250 return mBriefTags;
251 }
252
253 public boolean isHidden() {
254 if (mHidden != -1) {
255 return mHidden != 0;
256 } else {
257 if (Doclava.checkLevel(Doclava.SHOW_HIDDEN)) {
258 mHidden = 0;
259 return false;
260 }
261 boolean b = mText.indexOf("@hide") >= 0 || mText.indexOf("@pending") >= 0;
262 mHidden = b ? 1 : 0;
263 return b;
264 }
265 }
266
267 public boolean isDocOnly() {
268 if (mDocOnly != -1) {
269 return mDocOnly != 0;
270 } else {
271 boolean b = (mText != null) && (mText.indexOf("@doconly") >= 0);
272 mDocOnly = b ? 1 : 0;
273 return b;
274 }
275 }
276
277 public boolean isDeprecated() {
278 if (mDeprecated != -1) {
279 return mDeprecated != 0;
280 } else {
281 boolean b = (mText != null) && (mText.indexOf("@deprecated") >= 0);
282 mDeprecated = b ? 1 : 0;
283 return b;
284 }
285 }
286
287 private void init() {
288 if (!mInitialized) {
289 initImpl();
290 }
291 }
292
293 private void initImpl() {
294 isHidden();
295 isDocOnly();
296 isDeprecated();
297
298 // Don't bother parsing text if we aren't generating documentation.
Ben Dodson9ccd9e32010-08-06 17:18:52 -0700299 if (Doclava.parseComments()) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700300 parseRegex(mText);
301 parseBriefTags();
302 } else {
303 // Forces methods to be recognized by findOverriddenMethods in MethodInfo.
304 mInlineTagsList.add(new TextTagInfo("Text", "Text", mText,
305 SourcePositionInfo.add(mPosition, mText, 0)));
306 }
307
308 mText = null;
309 mInitialized = true;
310
311 mInlineTags = mInlineTagsList.toArray(new TagInfo[mInlineTagsList.size()]);
312 mParamTags = mParamTagsList.toArray(new ParamTagInfo[mParamTagsList.size()]);
313 mSeeTags = mSeeTagsList.toArray(new SeeTagInfo[mSeeTagsList.size()]);
314 mThrowsTags = mThrowsTagsList.toArray(new ThrowsTagInfo[mThrowsTagsList.size()]);
315 mReturnTags =
316 ParsedTagInfo.joinTags(mReturnTagsList.toArray(new ParsedTagInfo[mReturnTagsList.size()]));
317 mDeprecatedTags =
318 ParsedTagInfo.joinTags(mDeprecatedTagsList.toArray(new ParsedTagInfo[mDeprecatedTagsList
319 .size()]));
320 mUndeprecateTags = mUndeprecateTagsList.toArray(new TagInfo[mUndeprecateTagsList.size()]);
321 mAttrTags = mAttrTagsList.toArray(new AttrTagInfo[mAttrTagsList.size()]);
322 mBriefTags = mBriefTagsList.toArray(new TagInfo[mBriefTagsList.size()]);
323
324 mParamTagsList = null;
325 mSeeTagsList = null;
326 mThrowsTagsList = null;
327 mReturnTagsList = null;
328 mDeprecatedTagsList = null;
329 mUndeprecateTagsList = null;
330 mAttrTagsList = null;
331 mBriefTagsList = null;
332 }
333
334 boolean mInitialized;
335 int mHidden = -1;
336 int mDocOnly = -1;
337 int mDeprecated = -1;
338 String mText;
339 ContainerInfo mBase;
340 SourcePositionInfo mPosition;
341 int mLine = 1;
342
343 TagInfo[] mInlineTags;
344 TagInfo[] mTags;
345 ParamTagInfo[] mParamTags;
346 SeeTagInfo[] mSeeTags;
347 ThrowsTagInfo[] mThrowsTags;
348 TagInfo[] mBriefTags;
349 TagInfo[] mReturnTags;
350 TagInfo[] mDeprecatedTags;
351 TagInfo[] mUndeprecateTags;
352 AttrTagInfo[] mAttrTags;
353
354 ArrayList<TagInfo> mInlineTagsList = new ArrayList<TagInfo>();
355 ArrayList<TagInfo> mTagsList = new ArrayList<TagInfo>();
356 ArrayList<ParamTagInfo> mParamTagsList = new ArrayList<ParamTagInfo>();
357 ArrayList<SeeTagInfo> mSeeTagsList = new ArrayList<SeeTagInfo>();
358 ArrayList<ThrowsTagInfo> mThrowsTagsList = new ArrayList<ThrowsTagInfo>();
359 ArrayList<TagInfo> mBriefTagsList = new ArrayList<TagInfo>();
360 ArrayList<ParsedTagInfo> mReturnTagsList = new ArrayList<ParsedTagInfo>();
361 ArrayList<ParsedTagInfo> mDeprecatedTagsList = new ArrayList<ParsedTagInfo>();
362 ArrayList<TagInfo> mUndeprecateTagsList = new ArrayList<TagInfo>();
363 ArrayList<AttrTagInfo> mAttrTagsList = new ArrayList<AttrTagInfo>();
364
365
366}