blob: 3a24357f6eb4a0d1df12571e62745b7e2a21b437 [file] [log] [blame]
The Android Open Source Project88b60792009-03-03 19:28:42 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
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
17import java.util.regex.Pattern;
18import java.util.regex.Matcher;
19import java.util.ArrayList;
20
21public class Comment
22{
23 static final Pattern LEADING_WHITESPACE = Pattern.compile(
24 "^[ \t\n\r]*(.*)$",
25 Pattern.DOTALL);
26
27 static final Pattern TAG_BEGIN = Pattern.compile(
28 "[\r\n][\r\n \t]*@",
29 Pattern.DOTALL);
30
31 static final Pattern TAG = Pattern.compile(
32 "(@[^ \t\r\n]+)[ \t\r\n]+(.*)",
33 Pattern.DOTALL);
34
35 static final Pattern INLINE_TAG = Pattern.compile(
36 "(.*?)\\{(@[^ \t\r\n\\}]+)[ \t\r\n]*(.*?)\\}",
37 Pattern.DOTALL);
38
39 static final Pattern FIRST_SENTENCE = Pattern.compile(
40 "((.*?)\\.)[ \t\r\n\\<](.*)",
41 Pattern.DOTALL);
42
43 private static final String[] KNOWN_TAGS = new String[] {
44 "@author",
45 "@since",
46 "@version",
47 "@deprecated",
48 "@undeprecate",
49 "@docRoot",
50 "@inheritDoc",
51 "@more",
52 "@code",
53 "@samplecode",
54 "@sample",
55 "@include",
56 "@serial",
57 "@com.intel.drl.spec_ref",
58 "@ar.org.fitc.spec_ref",
59 };
60
61 public Comment(String text, ContainerInfo base, SourcePositionInfo sp)
62 {
63 mText = text;
64 mBase = base;
65 // sp now points to the end of the text, not the beginning!
66 mPosition = SourcePositionInfo.findBeginning(sp, text);
67 }
68
69 private void parseRegex(String text)
70 {
71 Matcher m;
72
73 m = LEADING_WHITESPACE.matcher(text);
74 m.matches();
75 text = m.group(1);
76
77 m = TAG_BEGIN.matcher(text);
78
79 int start = 0;
80 int end = 0;
81 while (m.find()) {
82 end = m.start();
83
84 tag(text, start, end);
85
86 start = m.end()-1; // -1 is the @
87 }
88 end = text.length();
89 tag(text, start, end);
90 }
91
92 private void tag(String text, int start, int end)
93 {
94 SourcePositionInfo pos = SourcePositionInfo.add(mPosition, mText, start);
95
96 if (start >= 0 && end > 0 && (end-start) > 0) {
97 text = text.substring(start, end);
98
99 Matcher m = TAG.matcher(text);
100 if (m.matches()) {
101 // out of line tag
102 tag(m.group(1), m.group(2), false, pos);
103 } else {
104 // look for inline tags
105 m = INLINE_TAG.matcher(text);
106 start = 0;
107 while (m.find()) {
108 String str = m.group(1);
109 String tagname = m.group(2);
110 String tagvalue = m.group(3);
111 tag(null, m.group(1), true, pos);
112 tag(tagname, tagvalue, true, pos);
113 start = m.end();
114 }
115 int len = text.length();
116 if (start != len) {
117 tag(null, text.substring(start), true, pos);
118 }
119 }
120 }
121 }
122
123 private void tag(String name, String text, boolean isInline, SourcePositionInfo pos)
124 {
125 /*
126 String s = isInline ? "inline" : "outofline";
127 System.out.println("---> " + s
128 + " name=[" + name + "] text=[" + text + "]");
129 */
130 if (name == null) {
131 mInlineTagsList.add(new TextTagInfo("Text", "Text", text, pos));
132 }
133 else if (name.equals("@param")) {
134 mParamTagsList.add(new ParamTagInfo("@param", "@param", text, mBase, pos));
135 }
136 else if (name.equals("@see")) {
137 mSeeTagsList.add(new SeeTagInfo("@see", "@see", text, mBase, pos));
138 }
139 else if (name.equals("@link") || name.equals("@linkplain")) {
140 mInlineTagsList.add(new SeeTagInfo(name, "@see", text, mBase, pos));
141 }
142 else if (name.equals("@throws") || name.equals("@exception")) {
143 mThrowsTagsList.add(new ThrowsTagInfo("@throws", "@throws", text, mBase, pos));
144 }
145 else if (name.equals("@return")) {
146 mReturnTagsList.add(new ParsedTagInfo("@return", "@return", text, mBase, pos));
147 }
148 else if (name.equals("@deprecated")) {
149 if (text.length() == 0) {
150 Errors.error(Errors.MISSING_COMMENT, pos,
151 "@deprecated tag with no explanatory comment");
152 text = "No replacement.";
153 }
154 mDeprecatedTagsList.add(new ParsedTagInfo("@deprecated", "@deprecated", text, mBase, pos));
155 }
156 else if (name.equals("@literal")) {
157 mInlineTagsList.add(new LiteralTagInfo(name, name, text, pos));
158 }
159 else if (name.equals("@hide") || name.equals("@doconly")) {
160 // nothing
161 }
162 else if (name.equals("@attr")) {
163 AttrTagInfo tag = new AttrTagInfo("@attr", "@attr", text, mBase, pos);
164 mAttrTagsList.add(tag);
165 Comment c = tag.description();
166 if (c != null) {
167 for (TagInfo t: c.tags()) {
168 mInlineTagsList.add(t);
169 }
170 }
171 }
172 else if (name.equals("@undeprecate")) {
173 mUndeprecateTagsList.add(new TextTagInfo("@undeprecate", "@undeprecate", text, pos));
174 }
175 else if (name.equals("@include") || name.equals("@sample")) {
176 mInlineTagsList.add(new SampleTagInfo(name, "@include", text, mBase, pos));
177 }
178 else {
179 boolean known = false;
180 for (String s: KNOWN_TAGS) {
181 if (s.equals(name)) {
182 known = true;
183 break;
184 }
185 }
186 if (!known) {
187 Errors.error(Errors.UNKNOWN_TAG, pos == null ? null : new SourcePositionInfo(pos),
188 "Unknown tag: " + name);
189 }
190 TagInfo t = new TextTagInfo(name, name, text, pos);
191 if (isInline) {
192 mInlineTagsList.add(t);
193 } else {
194 mTagsList.add(t);
195 }
196 }
197 }
198
199 private void parseBriefTags()
200 {
201 int N = mInlineTagsList.size();
202
203 // look for "@more" tag, which means that we might go past the first sentence.
204 int more = -1;
205 for (int i=0; i<N; i++) {
206 if (mInlineTagsList.get(i).name().equals("@more")) {
207 more = i;
208 }
209 }
210 if (more >= 0) {
211 for (int i=0; i<more; i++) {
212 mBriefTagsList.add(mInlineTagsList.get(i));
213 }
214 } else {
215 for (int i=0; i<N; i++) {
216 TagInfo t = mInlineTagsList.get(i);
217 if (t.name().equals("Text")) {
218 Matcher m = FIRST_SENTENCE.matcher(t.text());
219 if (m.matches()) {
220 String text = m.group(1);
221 TagInfo firstSentenceTag = new TagInfo(t.name(), t.kind(), text, t.position());
222 mBriefTagsList.add(firstSentenceTag);
223 break;
224 }
225 }
226 mBriefTagsList.add(t);
227
228 }
229 }
230 }
231
232 public TagInfo[] tags()
233 {
234 init();
235 return mInlineTags;
236 }
237
238 public TagInfo[] tags(String name)
239 {
240 init();
241 ArrayList<TagInfo> results = new ArrayList<TagInfo>();
242 int N = mInlineTagsList.size();
243 for (int i=0; i<N; i++) {
244 TagInfo t = mInlineTagsList.get(i);
245 if (t.name().equals(name)) {
246 results.add(t);
247 }
248 }
249 return results.toArray(new TagInfo[results.size()]);
250 }
251
252 public ParamTagInfo[] paramTags()
253 {
254 init();
255 return mParamTags;
256 }
257
258 public SeeTagInfo[] seeTags()
259 {
260 init();
261 return mSeeTags;
262 }
263
264 public ThrowsTagInfo[] throwsTags()
265 {
266 init();
267 return mThrowsTags;
268 }
269
270 public TagInfo[] returnTags()
271 {
272 init();
273 return mReturnTags;
274 }
275
276 public TagInfo[] deprecatedTags()
277 {
278 init();
279 return mDeprecatedTags;
280 }
281
282 public TagInfo[] undeprecateTags()
283 {
284 init();
285 return mUndeprecateTags;
286 }
287
288 public AttrTagInfo[] attrTags()
289 {
290 init();
291 return mAttrTags;
292 }
293
294 public TagInfo[] briefTags()
295 {
296 init();
297 return mBriefTags;
298 }
299
300 public boolean isHidden()
301 {
302 if (mHidden >= 0) {
303 return mHidden != 0;
304 } else {
305 if (DroidDoc.checkLevel(DroidDoc.SHOW_HIDDEN)) {
306 mHidden = 0;
307 return false;
308 }
309 boolean b = mText.indexOf("@hide") >= 0;
310 mHidden = b ? 1 : 0;
311 return b;
312 }
313 }
314
315 public boolean isDocOnly() {
316 if (mDocOnly >= 0) {
317 return mDocOnly != 0;
318 } else {
319 boolean b = (mText != null) && (mText.indexOf("@doconly") >= 0);
320 mDocOnly = b ? 1 : 0;
321 return b;
322 }
323 }
324
325 private void init()
326 {
327 if (!mInitialized) {
328 initImpl();
329 }
330 }
331
332 private void initImpl()
333 {
334 isHidden();
335 isDocOnly();
336 parseRegex(mText);
337 parseBriefTags();
338 mText = null;
339 mInitialized = true;
340
341 mInlineTags = mInlineTagsList.toArray(new TagInfo[mInlineTagsList.size()]);
342 mParamTags = mParamTagsList.toArray(new ParamTagInfo[mParamTagsList.size()]);
343 mSeeTags = mSeeTagsList.toArray(new SeeTagInfo[mSeeTagsList.size()]);
344 mThrowsTags = mThrowsTagsList.toArray(new ThrowsTagInfo[mThrowsTagsList.size()]);
345 mReturnTags = ParsedTagInfo.joinTags(mReturnTagsList.toArray(
346 new ParsedTagInfo[mReturnTagsList.size()]));
347 mDeprecatedTags = ParsedTagInfo.joinTags(mDeprecatedTagsList.toArray(
348 new ParsedTagInfo[mDeprecatedTagsList.size()]));
349 mUndeprecateTags = mUndeprecateTagsList.toArray(new TagInfo[mUndeprecateTagsList.size()]);
350 mAttrTags = mAttrTagsList.toArray(new AttrTagInfo[mAttrTagsList.size()]);
351 mBriefTags = mBriefTagsList.toArray(new TagInfo[mBriefTagsList.size()]);
352
353 mParamTagsList = null;
354 mSeeTagsList = null;
355 mThrowsTagsList = null;
356 mReturnTagsList = null;
357 mDeprecatedTagsList = null;
358 mUndeprecateTagsList = null;
359 mAttrTagsList = null;
360 mBriefTagsList = null;
361 }
362
363 boolean mInitialized;
364 int mHidden = -1;
365 int mDocOnly = -1;
366 String mText;
367 ContainerInfo mBase;
368 SourcePositionInfo mPosition;
369 int mLine = 1;
370
371 TagInfo[] mInlineTags;
372 TagInfo[] mTags;
373 ParamTagInfo[] mParamTags;
374 SeeTagInfo[] mSeeTags;
375 ThrowsTagInfo[] mThrowsTags;
376 TagInfo[] mBriefTags;
377 TagInfo[] mReturnTags;
378 TagInfo[] mDeprecatedTags;
379 TagInfo[] mUndeprecateTags;
380 AttrTagInfo[] mAttrTags;
381
382 ArrayList<TagInfo> mInlineTagsList = new ArrayList<TagInfo>();
383 ArrayList<TagInfo> mTagsList = new ArrayList<TagInfo>();
384 ArrayList<ParamTagInfo> mParamTagsList = new ArrayList<ParamTagInfo>();
385 ArrayList<SeeTagInfo> mSeeTagsList = new ArrayList<SeeTagInfo>();
386 ArrayList<ThrowsTagInfo> mThrowsTagsList = new ArrayList<ThrowsTagInfo>();
387 ArrayList<TagInfo> mBriefTagsList = new ArrayList<TagInfo>();
388 ArrayList<ParsedTagInfo> mReturnTagsList = new ArrayList<ParsedTagInfo>();
389 ArrayList<ParsedTagInfo> mDeprecatedTagsList = new ArrayList<ParsedTagInfo>();
390 ArrayList<TagInfo> mUndeprecateTagsList = new ArrayList<TagInfo>();
391 ArrayList<AttrTagInfo> mAttrTagsList = new ArrayList<AttrTagInfo>();
392
393
394}