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