2 *******************************************************************************
\r
3 * Copyright (C) 2004-2007, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
9 * Generate a list of ICU's public APIs, sorted by qualified name and signature
\r
10 * public APIs are all non-internal, non-package apis in com.ibm.icu.[lang|math|text|util].
\r
11 * For each API, list
\r
12 * - public, package, protected, or private (PB PK PT PR)
\r
13 * - static or non-static (STK NST)
\r
14 * - final or non-final (FN NF)
\r
15 * - synchronized or non-synchronized (SYN NSY)
\r
16 * - stable, draft, deprecated, obsolete (ST DR DP OB)
\r
17 * - abstract or non-abstract (AB NA)
\r
18 * - constructor, member, field (C M F)
\r
20 * Requires JDK 1.4.2 or later
\r
22 * Sample invocation:
\r
23 * c:/j2sdk1.4.2/bin/javadoc
\r
24 * -classpath c:/jd2sk1.4.2/lib/tools.jar
\r
25 * -doclet com.ibm.icu.dev.tool.docs.CheckAPI
\r
26 * -docletpath c:/doug/cvsproj/icu4j/src
\r
27 * -sourcepath c:/eclipse2.1/workspace2/icu4j/src
\r
28 * -compare c:/doug/cvsproj/icu4j/src/com/ibm/icu/dev/tool/docs/api2_6_1.txt
\r
32 * todo: separate generation of data files (which requires taglet) from
\r
33 * comparison and report generation (which does not require it)
\r
34 * todo: provide command-line control of filters of which subclasses/packages to process
\r
35 * todo: record full inheritance heirarchy, not just immediate inheritance
\r
36 * todo: allow for aliasing comparisons (force (pkg.)*class to be treated as though it
\r
37 * were in a different pkg/class heirarchy (facilitates comparison of icu4j and java)
\r
40 package com.ibm.icu.dev.tool.docs;
\r
42 import com.sun.javadoc.*;
\r
46 public class CheckAPI {
\r
48 String compare; // file
\r
53 String srcName = "Current"; // default source name
\r
56 private static final int DATA_FILE_VERSION = 1;
\r
57 private static final char SEP = ';';
\r
59 private static final int STA = 0, STA_DRAFT = 0, STA_STABLE = 1, STA_DEPRECATED = 2, STA_OBSOLETE = 3;
\r
60 private static final int VIS = 1, VIS_PACKAGE = 0, VIS_PUBLIC= 1, VIS_PROTECTED = 2, VIS_PRIVATE = 3;
\r
61 private static final int STK = 2, STK_STATIC = 1;
\r
62 private static final int FIN = 3, FIN_FINAL = 1;
\r
63 private static final int SYN = 4, SYN_SYNCHRONIZED = 1;
\r
64 private static final int ABS = 5, ABS_ABSTRACT = 1;
\r
65 private static final int CAT = 6, CAT_CLASS = 0, CAT_FIELD = 1, CAT_CONSTRUCTOR = 2, CAT_METHOD = 3;
\r
66 private static final int PAK = 7;
\r
67 private static final int CLS = 8;
\r
68 private static final int NAM = 9;
\r
69 private static final int SIG = 10;
\r
70 private static final int EXC = 11;
\r
71 private static final int NUM_TYPES = 11;
\r
73 static abstract class APIInfo {
\r
74 public abstract int getVal(int typ);
\r
75 public abstract String get(int typ, boolean brief);
\r
76 public abstract void write(BufferedWriter w, boolean brief, boolean html, boolean detail);
\r
79 final static class Info extends APIInfo {
\r
81 private String pack; // package
\r
82 private String cls; // enclosing class
\r
83 private String name; // name
\r
84 private String sig; // signature, class: inheritance, method: signature, field: type, const: signature
\r
85 private String exc; // throws
\r
87 public int getVal(int typ) {
\r
89 return (info >> (typ*2)) & 0x3;
\r
92 public String get(int typ, boolean brief) {
\r
94 String[] vals = brief ? shortNames[typ] : names[typ];
\r
97 case PAK: return pack;
\r
98 case CLS: return cls;
\r
99 case NAM: return name;
\r
100 case SIG: return sig;
\r
101 case EXC: return exc;
\r
104 int val = (info >> (typ*2)) & 0x3;
\r
108 private void setType(int typ, int val) {
\r
110 info &= ~(0x3 << (typ*2));
\r
111 info |= (val&0x3) << (typ * 2);
\r
114 private void setType(int typ, String val) {
\r
116 String[] vals = shortNames[typ];
\r
117 if (vals == null) {
\r
119 case PAK: pack = val; break;
\r
120 case CLS: cls = val; break;
\r
121 case NAM: name = val; break;
\r
122 case SIG: sig = val; break;
\r
123 case EXC: exc = val; break;
\r
128 for (int i = 0; i < vals.length; ++i) {
\r
129 if (val.equalsIgnoreCase(vals[i])) {
\r
130 info &= ~(0x3 << (typ*2));
\r
131 info |= i << (typ*2);
\r
136 throw new IllegalArgumentException("unrecognized value '" + val + "' for type '" + typeNames[typ] + "'");
\r
139 public void write(BufferedWriter w, boolean brief, boolean html, boolean detail) {
\r
142 for (int i = 0; i < NUM_TYPES; ++i) {
\r
143 String s = get(i, true);
\r
150 // remove all occurrences of icu packages from the param string
\r
151 // fortunately, all the packages have 4 chars (lang, math, text, util).
\r
154 final String ICUPACK = "com.ibm.icu.";
\r
155 StringBuffer buf = new StringBuffer();
\r
156 for (int i = 0; i < sig.length();) {
\r
157 int n = sig.indexOf(ICUPACK, i);
\r
159 buf.append(sig.substring(i));
\r
162 buf.append(sig.substring(i, n));
\r
163 i = n + ICUPACK.length() + 5; // trailing 'xxxx.'
\r
165 xsig = buf.toString();
\r
168 // construct signature
\r
169 for (int i = STA; i < CAT; ++i) { // include status
\r
170 String s = get(i, false);
\r
171 if (s != null && s.length() > 0) {
\r
183 int val = getVal(CAT);
\r
186 if (sig.indexOf("extends") == -1) {
\r
187 w.write("interface ");
\r
191 if (cls.length() > 0) {
\r
209 case CAT_CONSTRUCTOR:
\r
210 int n = xsig.indexOf('(');
\r
212 w.write(xsig.substring(0, n));
\r
218 w.write(xsig.substring(n));
\r
224 catch (IOException e) {
\r
225 RuntimeException re = new RuntimeException("IO Error");
\r
231 public boolean read(BufferedReader r) {
\r
234 for (; i < NUM_TYPES; ++i) {
\r
235 setType(i, readToken(r));
\r
237 r.readLine(); // swallow line end sequence
\r
239 catch (IOException e) {
\r
240 if (i == 0) { // assume if first read returns error, we have reached end of input
\r
243 RuntimeException re = new RuntimeException("IO Error");
\r
251 public boolean read(ProgramElementDoc doc) {
\r
254 // Doc. isField, isMethod, isConstructor, isClass, isInterface
\r
255 // ProgramElementDoc. containingClass, containingPackage
\r
256 // ProgramElementDoc. isPublic, isProtected, isPrivate, isPackagePrivate
\r
257 // ProgramElementDoc. isStatic, isFinal
\r
258 // MemberDoc.isSynthetic
\r
259 // ExecutableMemberDoc isSynchronized, signature
\r
260 // Type.toString() // e.g. "String[][]"
\r
261 // ClassDoc.isAbstract, superClass, interfaces, fields, methods, constructors, innerClasses
\r
263 // ConstructorDoc qualifiedName
\r
264 // MethodDoc isAbstract, returnType
\r
268 setType(STA, tagStatus(doc));
\r
271 if (doc.isPublic()) {
\r
272 setType(VIS, VIS_PUBLIC);
\r
273 } else if (doc.isProtected()) {
\r
274 setType(VIS, VIS_PROTECTED);
\r
275 } else if (doc.isPrivate()) {
\r
276 setType(VIS, VIS_PRIVATE);
\r
278 // default is package
\r
282 if (doc.isStatic()) {
\r
283 setType(STK, STK_STATIC);
\r
285 // default is non-static
\r
289 if (doc.isFinal()) {
\r
290 setType(FIN, FIN_FINAL);
\r
292 // default is non-final
\r
296 if (doc.isField()) {
\r
297 setType(CAT, CAT_FIELD);
\r
298 } else if (doc.isMethod()) {
\r
299 setType(CAT, CAT_METHOD);
\r
300 } else if (doc.isConstructor()) {
\r
301 setType(CAT, CAT_CONSTRUCTOR);
\r
302 } else if (doc.isClass() || doc.isInterface()) {
\r
303 setType(CAT, CAT_CLASS);
\r
306 setType(PAK, doc.containingPackage().name());
\r
307 setType(CLS, (doc.isClass() || doc.isInterface() || (doc.containingClass() == null)) ? "" : doc.containingClass().name());
\r
308 setType(NAM, doc.name());
\r
310 if (doc instanceof FieldDoc) {
\r
311 FieldDoc fdoc = (FieldDoc)doc;
\r
312 setType(SIG, fdoc.type().toString());
\r
313 } else if (doc instanceof ClassDoc) {
\r
314 ClassDoc cdoc = (ClassDoc)doc;
\r
316 if (cdoc.isClass() && cdoc.isAbstract()) { // interfaces are abstract by default, don't mark them as abstract
\r
317 setType(ABS, ABS_ABSTRACT);
\r
320 StringBuffer buf = new StringBuffer();
\r
321 if (cdoc.isClass()) {
\r
322 buf.append("extends ");
\r
323 buf.append(cdoc.superclass().qualifiedName());
\r
325 ClassDoc[] imp = cdoc.interfaces();
\r
326 if (imp != null && imp.length > 0) {
\r
327 if (buf.length() > 0) {
\r
330 buf.append("implements");
\r
331 for (int i = 0; i < imp.length; ++i) {
\r
336 buf.append(imp[i].qualifiedName());
\r
339 setType(SIG, buf.toString());
\r
341 ExecutableMemberDoc emdoc = (ExecutableMemberDoc)doc;
\r
342 if (emdoc.isSynchronized()) {
\r
343 setType(SYN, SYN_SYNCHRONIZED);
\r
346 if (doc instanceof MethodDoc) {
\r
347 MethodDoc mdoc = (MethodDoc)doc;
\r
348 if (mdoc.isAbstract()) {
\r
349 setType(ABS, ABS_ABSTRACT);
\r
351 setType(SIG, mdoc.returnType().toString() + emdoc.signature());
\r
354 setType(SIG, emdoc.signature());
\r
361 public static Comparator defaultComparator() {
\r
362 final Comparator c = new Comparator() {
\r
363 public int compare(Object lhs, Object rhs) {
\r
364 Info lhi = (Info)lhs;
\r
365 Info rhi = (Info)rhs;
\r
366 int result = lhi.pack.compareTo(rhi.pack);
\r
368 result = (lhi.getVal(CAT) == CAT_CLASS ? lhi.name : lhi.cls)
\r
369 .compareTo(rhi.getVal(CAT) == CAT_CLASS ? rhi.name : rhi.cls);
\r
371 result = lhi.getVal(CAT)- rhi.getVal(CAT);
\r
373 result = lhi.name.compareTo(rhi.name);
\r
375 result = lhi.sig.compareTo(rhi.sig);
\r
386 public static Comparator changedComparator() {
\r
387 final Comparator c = new Comparator() {
\r
388 public int compare(Object lhs, Object rhs) {
\r
389 Info lhi = (Info)lhs;
\r
390 Info rhi = (Info)rhs;
\r
391 int result = lhi.pack.compareTo(rhi.pack);
\r
393 result = (lhi.getVal(CAT) == CAT_CLASS ? lhi.name : lhi.cls)
\r
394 .compareTo(rhi.getVal(CAT) == CAT_CLASS ? rhi.name : rhi.cls);
\r
396 result = lhi.getVal(CAT)- rhi.getVal(CAT);
\r
398 result = lhi.name.compareTo(rhi.name);
\r
399 if (result == 0 && lhi.getVal(CAT) != CAT_CLASS) {
\r
400 result = lhi.sig.compareTo(rhi.sig);
\r
411 public static Comparator classFirstComparator() {
\r
412 final Comparator c = new Comparator() {
\r
413 public int compare(Object lhs, Object rhs) {
\r
414 Info lhi = (Info)lhs;
\r
415 Info rhi = (Info)rhs;
\r
416 int result = lhi.pack.compareTo(rhi.pack);
\r
418 boolean lcls = lhi.getVal(CAT) == CAT_CLASS;
\r
419 boolean rcls = rhi.getVal(CAT) == CAT_CLASS;
\r
420 result = lcls == rcls ? 0 : (lcls ? -1 : 1);
\r
422 result = (lcls ? lhi.name : lhi.cls).compareTo(rcls ? rhi.name : rhi.cls);
\r
424 result = lhi.getVal(CAT)- rhi.getVal(CAT);
\r
426 result = lhi.name.compareTo(rhi.name);
\r
427 if (result == 0 && !lcls) {
\r
428 result = lhi.sig.compareTo(rhi.sig);
\r
440 private static final String[] typeNames = {
\r
441 "status", "visibility", "static", "final", "synchronized",
\r
442 "abstract", "category", "package", "class", "name", "signature"
\r
445 private static final String[][] names = {
\r
446 { "draft ", "stable ", "deprecated", "obsolete " },
\r
447 { "package", "public", "protected", "private" },
\r
450 { "", "synchronized" },
\r
451 { "", "abstract" },
\r
452 { "class", "field", "constructor", "method" },
\r
460 private static final String[][] shortNames = {
\r
461 { "DR", "ST", "DP", "OB" },
\r
462 { "PK", "PB", "PT", "PR" },
\r
467 { "L", "F", "C", "M" },
\r
475 private static void validateType(int typ) {
\r
476 if (typ < 0 || typ > NUM_TYPES) {
\r
477 throw new IllegalArgumentException("bad type index: " + typ);
\r
481 public String toString() {
\r
482 return get(NAM, true);
\r
486 static final class DeltaInfo extends APIInfo {
\r
490 DeltaInfo(Info a, Info b) {
\r
495 public int getVal(int typ) {
\r
496 return a.getVal(typ);
\r
499 public String get(int typ, boolean brief) {
\r
500 return a.get(typ, brief);
\r
503 public void write(BufferedWriter w, boolean brief, boolean html, boolean detail) {
\r
504 a.write(w, brief, html, detail);
\r
511 catch (Exception e) {
\r
513 b.write(w, brief, html, detail);
\r
516 public String toString() {
\r
517 return a.get(NAM, true);
\r
521 public static int optionLength(String option) {
\r
522 if (option.equals("-html")) {
\r
524 } else if (option.equals("-name")) {
\r
526 } else if (option.equals("-output")) {
\r
528 } else if (option.equals("-compare")) {
\r
534 public static boolean start(RootDoc root) {
\r
535 return new CheckAPI(root).run();
\r
538 CheckAPI(RootDoc root) {
\r
541 // this.compare = "c:/doug/cvsproj/icu4j/src/com/ibm/icu/dev/tool/docs/api2_8.txt";
\r
543 String[][] options = root.options();
\r
544 for (int i = 0; i < options.length; ++i) {
\r
545 String opt = options[i][0];
\r
546 if (opt.equals("-html")) {
\r
548 } else if (opt.equals("-name")) {
\r
549 this.srcName = options[i][1];
\r
550 } else if (opt.equals("-output")) {
\r
551 this.output = options[i][1];
\r
552 } else if (opt.equals("-compare")) {
\r
553 this.compare = options[i][1];
\r
557 if (compare != null) {
\r
559 // URL url = new URL(compare);
\r
560 File f = new File(compare);
\r
561 InputStream is = new FileInputStream(f);
\r
562 InputStreamReader isr = new InputStreamReader(is);
\r
563 BufferedReader br = new BufferedReader(isr);
\r
565 // read header line
\r
566 /*int version = */Integer.parseInt(readToken(br));
\r
567 // check version if we change it later, probably can just rebuild though
\r
568 this.compareName = readToken(br);
\r
572 this.compareSet = new TreeSet(Info.defaultComparator());
\r
573 for (Info info = new Info(); info.read(br); info = new Info()) {
\r
574 compareSet.add(info);
\r
577 catch (Exception e) {
\r
578 RuntimeException re = new RuntimeException("error reading " + compare);
\r
584 results = new TreeSet(Info.defaultComparator());
\r
587 private boolean run() {
\r
588 doDocs(root.classes());
\r
590 OutputStream os = System.out;
\r
591 if (output != null) {
\r
593 os = new FileOutputStream(output);
\r
595 catch (FileNotFoundException e) {
\r
596 RuntimeException re = new RuntimeException(e.getMessage());
\r
602 BufferedWriter bw = null;
\r
604 OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
\r
605 bw = new BufferedWriter(osw);
\r
607 if (compareSet == null) {
\r
608 // writing data file
\r
609 bw.write(String.valueOf(DATA_FILE_VERSION) + SEP); // header version
\r
610 bw.write(srcName + SEP); // source name
\r
612 writeResults(results, bw, true, false, false);
\r
614 // writing comparison info
\r
615 TreeSet removed = (TreeSet)compareSet.clone();
\r
616 removed.removeAll(results);
\r
618 TreeSet added = (TreeSet)results.clone();
\r
619 added.removeAll(compareSet);
\r
621 Iterator ai = added.iterator();
\r
622 Iterator ri = removed.iterator();
\r
623 ArrayList changed = new ArrayList();
\r
624 Comparator c = Info.changedComparator();
\r
625 Info a = null, r = null;
\r
626 while (ai.hasNext() && ri.hasNext()) {
\r
627 if (a == null) a = (Info)ai.next();
\r
628 if (r == null) r = (Info)ri.next();
\r
629 int result = c.compare(a, r);
\r
632 } else if (result > 0) {
\r
635 changed.add(new DeltaInfo(a, r));
\r
636 a = null; ai.remove();
\r
637 r = null; ri.remove();
\r
641 added = stripAndResort(added);
\r
642 removed = stripAndResort(removed);
\r
645 String title = "ICU4J API Comparison: " + srcName + " with " + compareName;
\r
647 bw.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
\r
649 bw.write("<html>");
\r
651 bw.write("<head>");
\r
653 bw.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
\r
655 bw.write("<title>");
\r
657 bw.write("</title>");
\r
659 bw.write("<body>");
\r
670 bw.write("Removed from " + compareName);
\r
674 if (removed.size() > 0) {
\r
675 writeResults(removed, bw, false, true, false);
\r
677 bw.write("<p>(no API removed)</p>");
\r
684 bw.write("Changed in " + srcName);
\r
688 if (changed.size() > 0) {
\r
689 writeResults(changed, bw, false, true, true);
\r
691 bw.write("<p>(no API changed)</p>");
\r
698 bw.write("Added in " + srcName);
\r
702 if (added.size() > 0) {
\r
703 writeResults(added, bw, false, true, false);
\r
705 bw.write("<p>(no API added)</p>");
\r
709 bw.write("<p><i>Contents generated by CheckAPI tool.<br/>Copyright (C) 2004, International Business Machines Corporation, All Rights Reserved.</i></p>");
\r
711 bw.write("</body>");
\r
713 bw.write("</html>");
\r
716 bw.write("Comparing " + srcName + " with " + compareName);
\r
721 bw.write("=== Removed from " + compareName + " ===");
\r
723 if (removed.size() > 0) {
\r
724 writeResults(removed, bw, false, false, false);
\r
726 bw.write("(no API removed)");
\r
731 bw.write("=== Changed in " + srcName + " ===");
\r
733 if (changed.size() > 0) {
\r
734 writeResults(changed, bw, false, false, true);
\r
736 bw.write("(no API changed)");
\r
741 bw.write("=== Added in " + srcName + " ===");
\r
743 if (added.size() > 0) {
\r
744 writeResults(added, bw, false, false, false);
\r
746 bw.write("(no API added)");
\r
753 } catch (IOException e) {
\r
754 try { bw.close(); } catch (IOException e2) {}
\r
755 RuntimeException re = new RuntimeException("write error: " + e.getMessage());
\r
763 private void doDocs(ProgramElementDoc[] docs) {
\r
764 if (docs != null && docs.length > 0) {
\r
765 for (int i = 0; i < docs.length; ++i) {
\r
771 private void doDoc(ProgramElementDoc doc) {
\r
772 if (ignore(doc)) return;
\r
774 if (doc.isClass() || doc.isInterface()) {
\r
775 ClassDoc cdoc = (ClassDoc)doc;
\r
776 doDocs(cdoc.fields());
\r
777 doDocs(cdoc.constructors());
\r
778 doDocs(cdoc.methods());
\r
779 doDocs(cdoc.innerClasses());
\r
782 Info info = new Info();
\r
783 if (info.read(doc)) {
\r
788 private boolean ignore(ProgramElementDoc doc) {
\r
789 if (doc == null) return true;
\r
790 if (doc.isPrivate() || doc.isPackagePrivate()) return true;
\r
791 if (doc instanceof ConstructorDoc && ((ConstructorDoc)doc).isSynthetic()) return true;
\r
792 if (doc.qualifiedName().indexOf(".misc") != -1) return true;
\r
793 Tag[] tags = doc.tags();
\r
794 for (int i = 0; i < tags.length; ++i) {
\r
795 if (tagKindIndex(tags[i].kind()) == INTERNAL) return true;
\r
801 private static void writeResults(Collection c, BufferedWriter w, boolean brief, boolean html, boolean detail) {
\r
802 Iterator iter = c.iterator();
\r
803 String pack = null;
\r
804 String clas = null;
\r
805 while (iter.hasNext()) {
\r
806 APIInfo info = (APIInfo)iter.next();
\r
808 info.write(w, brief, false, detail);
\r
811 String p = info.get(PAK, true);
\r
812 if (!p.equals(pack)) {
\r
815 if (clas != null) {
\r
819 if (pack != null) {
\r
824 w.write("<h3>Package ");
\r
831 w.write("Package ");
\r
842 if (info.getVal(CAT) != CAT_CLASS) {
\r
843 String name = info.get(CLS, true);
\r
844 if (!name.equals(clas)) {
\r
846 if (clas != null) {
\r
863 info.write(w, brief, html, detail);
\r
866 info.write(w, brief, html, detail);
\r
869 catch (IOException e) {
\r
870 System.err.println("IOException " + e.getMessage() + " writing " + info);
\r
876 if (clas != null) {
\r
880 if (pack != null) {
\r
885 catch (IOException e) {
\r
890 private static String readToken(BufferedReader r) throws IOException {
\r
891 char[] buf = new char[256];
\r
893 for (; i < buf.length; ++i) {
\r
896 throw new IOException("unexpected EOF");
\r
897 } else if (c == SEP) {
\r
902 if (i == buf.length) {
\r
903 throw new IOException("unterminated token" + new String(buf));
\r
906 return new String(buf, 0, i);
\r
909 private static TreeSet stripAndResort(TreeSet t) {
\r
911 TreeSet r = new TreeSet(Info.classFirstComparator());
\r
916 private static void stripClassInfo(Collection c) {
\r
917 // c is sorted with class info first
\r
918 Iterator iter = c.iterator();
\r
919 String cname = null;
\r
920 while (iter.hasNext()) {
\r
921 Info info = (Info)iter.next();
\r
922 String cls = info.get(CLS, true);
\r
923 if (cname != null) {
\r
924 if (cname.equals(cls)) {
\r
930 if (info.getVal(CAT) == CAT_CLASS) {
\r
931 cname = info.get(NAM, true);
\r
936 private static int tagStatus(final Doc doc) {
\r
939 void set(int val) { if (res != -1) throw new RuntimeException("bad doc: " + doc); res = val; }
\r
942 System.err.println("warning: no tag for " + doc);
\r
949 Tag[] tags = doc.tags();
\r
950 Result result = new Result();
\r
951 for (int i = 0; i < tags.length; ++i) {
\r
954 String kind = tag.kind();
\r
955 int ix = tagKindIndex(kind);
\r
963 result.set(STA_DRAFT);
\r
967 result.set(STA_STABLE);
\r
971 result.set(STA_DEPRECATED);
\r
975 result.set(STA_OBSOLETE);
\r
991 throw new RuntimeException("unknown index " + ix + " for tag: " + kind);
\r
995 return result.get();
\r
998 private static final int UNKNOWN = -1;
\r
999 private static final int INTERNAL = 0;
\r
1000 private static final int DRAFT = 1;
\r
1001 private static final int STABLE = 2;
\r
1002 private static final int SINCE = 3;
\r
1003 private static final int DEPRECATED = 4;
\r
1004 private static final int AUTHOR = 5;
\r
1005 private static final int SEE = 6;
\r
1006 private static final int VERSION = 7;
\r
1007 private static final int PARAM = 8;
\r
1008 private static final int RETURN = 9;
\r
1009 private static final int THROWS = 10;
\r
1010 private static final int OBSOLETE = 11;
\r
1011 private static final int EXCEPTION = 12;
\r
1012 private static final int SERIAL = 13;
\r
1014 private static int tagKindIndex(String kind) {
\r
1015 final String[] tagKinds = {
\r
1016 "@internal", "@draft", "@stable", "@since", "@deprecated", "@author", "@see", "@version",
\r
1017 "@param", "@return", "@throws", "@obsolete", "@exception", "@serial"
\r
1020 for (int i = 0; i < tagKinds.length; ++i) {
\r
1021 if (kind.equals(tagKinds[i])) {
\r