2 *******************************************************************************
\r
3 * Copyright (C) 2004-2010, 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 java.io.BufferedReader;
\r
43 import java.io.BufferedWriter;
\r
44 import java.io.File;
\r
45 import java.io.FileInputStream;
\r
46 import java.io.FileNotFoundException;
\r
47 import java.io.FileOutputStream;
\r
48 import java.io.IOException;
\r
49 import java.io.InputStream;
\r
50 import java.io.InputStreamReader;
\r
51 import java.io.OutputStream;
\r
52 import java.io.OutputStreamWriter;
\r
53 import java.util.ArrayList;
\r
54 import java.util.Collection;
\r
55 import java.util.Comparator;
\r
56 import java.util.Iterator;
\r
57 import java.util.TreeSet;
\r
59 import com.sun.javadoc.ClassDoc;
\r
60 import com.sun.javadoc.ConstructorDoc;
\r
61 import com.sun.javadoc.Doc;
\r
62 import com.sun.javadoc.ExecutableMemberDoc;
\r
63 import com.sun.javadoc.FieldDoc;
\r
64 import com.sun.javadoc.MethodDoc;
\r
65 import com.sun.javadoc.ProgramElementDoc;
\r
66 import com.sun.javadoc.RootDoc;
\r
67 import com.sun.javadoc.Tag;
\r
69 public class CheckAPI {
\r
71 String compare; // file
\r
76 String srcName = "Current"; // default source name
\r
79 private static final int DATA_FILE_VERSION = 1;
\r
80 private static final char SEP = ';';
\r
82 private static final int STA = 0, STA_DRAFT = 0, STA_STABLE = 1, STA_DEPRECATED = 2, STA_OBSOLETE = 3;
\r
83 private static final int VIS = 1, VIS_PACKAGE = 0, VIS_PUBLIC= 1, VIS_PROTECTED = 2, VIS_PRIVATE = 3;
\r
84 private static final int STK = 2, STK_STATIC = 1;
\r
85 private static final int FIN = 3, FIN_FINAL = 1;
\r
86 private static final int SYN = 4, SYN_SYNCHRONIZED = 1;
\r
87 private static final int ABS = 5, ABS_ABSTRACT = 1;
\r
88 private static final int CAT = 6, CAT_CLASS = 0, CAT_FIELD = 1, CAT_CONSTRUCTOR = 2, CAT_METHOD = 3;
\r
89 private static final int PAK = 7;
\r
90 private static final int CLS = 8;
\r
91 private static final int NAM = 9;
\r
92 private static final int SIG = 10;
\r
93 private static final int EXC = 11;
\r
94 private static final int NUM_TYPES = 11;
\r
96 static abstract class APIInfo {
\r
97 public abstract int getVal(int typ);
\r
98 public abstract String get(int typ, boolean brief);
\r
99 public abstract void write(BufferedWriter w, boolean brief, boolean html, boolean detail);
\r
102 final static class Info extends APIInfo {
\r
104 private String pack; // package
\r
105 private String cls; // enclosing class
\r
106 private String name; // name
\r
107 private String sig; // signature, class: inheritance, method: signature, field: type, const: signature
\r
108 private String exc; // throws
\r
110 public int getVal(int typ) {
\r
112 return (info >> (typ*2)) & 0x3;
\r
115 public String get(int typ, boolean brief) {
\r
117 String[] vals = brief ? shortNames[typ] : names[typ];
\r
118 if (vals == null) {
\r
120 case PAK: return pack;
\r
121 case CLS: return cls;
\r
122 case NAM: return name;
\r
123 case SIG: return sig;
\r
124 case EXC: return exc;
\r
127 int val = (info >> (typ*2)) & 0x3;
\r
131 private void setType(int typ, int val) {
\r
133 info &= ~(0x3 << (typ*2));
\r
134 info |= (val&0x3) << (typ * 2);
\r
137 private void setType(int typ, String val) {
\r
139 String[] vals = shortNames[typ];
\r
140 if (vals == null) {
\r
142 case PAK: pack = val; break;
\r
143 case CLS: cls = val; break;
\r
144 case NAM: name = val; break;
\r
145 case SIG: sig = val; break;
\r
146 case EXC: exc = val; break;
\r
151 for (int i = 0; i < vals.length; ++i) {
\r
152 if (val.equalsIgnoreCase(vals[i])) {
\r
153 info &= ~(0x3 << (typ*2));
\r
154 info |= i << (typ*2);
\r
159 throw new IllegalArgumentException("unrecognized value '" + val + "' for type '" + typeNames[typ] + "'");
\r
162 public void write(BufferedWriter w, boolean brief, boolean html, boolean detail) {
\r
165 for (int i = 0; i < NUM_TYPES; ++i) {
\r
166 String s = get(i, true);
\r
173 // remove all occurrences of icu packages from the param string
\r
174 // fortunately, all the packages have 4 chars (lang, math, text, util).
\r
177 final String ICUPACK = "com.ibm.icu.";
\r
178 StringBuffer buf = new StringBuffer();
\r
179 for (int i = 0; i < sig.length();) {
\r
180 int n = sig.indexOf(ICUPACK, i);
\r
182 buf.append(sig.substring(i));
\r
185 buf.append(sig.substring(i, n));
\r
186 i = n + ICUPACK.length() + 5; // trailing 'xxxx.'
\r
188 xsig = buf.toString();
\r
191 // construct signature
\r
192 for (int i = STA; i < CAT; ++i) { // include status
\r
193 String s = get(i, false);
\r
194 if (s != null && s.length() > 0) {
\r
206 int val = getVal(CAT);
\r
209 if (sig.indexOf("extends") == -1) {
\r
210 w.write("interface ");
\r
214 if (cls.length() > 0) {
\r
232 case CAT_CONSTRUCTOR:
\r
233 int n = xsig.indexOf('(');
\r
235 w.write(xsig.substring(0, n));
\r
241 w.write(xsig.substring(n));
\r
247 catch (IOException e) {
\r
248 RuntimeException re = new RuntimeException("IO Error");
\r
254 public boolean read(BufferedReader r) {
\r
257 for (; i < NUM_TYPES; ++i) {
\r
258 setType(i, readToken(r));
\r
260 r.readLine(); // swallow line end sequence
\r
262 catch (IOException e) {
\r
263 if (i == 0) { // assume if first read returns error, we have reached end of input
\r
266 RuntimeException re = new RuntimeException("IO Error");
\r
274 public boolean read(ProgramElementDoc doc) {
\r
277 // Doc. isField, isMethod, isConstructor, isClass, isInterface
\r
278 // ProgramElementDoc. containingClass, containingPackage
\r
279 // ProgramElementDoc. isPublic, isProtected, isPrivate, isPackagePrivate
\r
280 // ProgramElementDoc. isStatic, isFinal
\r
281 // MemberDoc.isSynthetic
\r
282 // ExecutableMemberDoc isSynchronized, signature
\r
283 // Type.toString() // e.g. "String[][]"
\r
284 // ClassDoc.isAbstract, superClass, interfaces, fields, methods, constructors, innerClasses
\r
286 // ConstructorDoc qualifiedName
\r
287 // MethodDoc isAbstract, returnType
\r
291 setType(STA, tagStatus(doc));
\r
294 if (doc.isPublic()) {
\r
295 setType(VIS, VIS_PUBLIC);
\r
296 } else if (doc.isProtected()) {
\r
297 setType(VIS, VIS_PROTECTED);
\r
298 } else if (doc.isPrivate()) {
\r
299 setType(VIS, VIS_PRIVATE);
\r
301 // default is package
\r
305 if (doc.isStatic()) {
\r
306 setType(STK, STK_STATIC);
\r
308 // default is non-static
\r
312 if (doc.isFinal()) {
\r
313 setType(FIN, FIN_FINAL);
\r
315 // default is non-final
\r
319 if (doc.isField()) {
\r
320 setType(CAT, CAT_FIELD);
\r
321 } else if (doc.isMethod()) {
\r
322 setType(CAT, CAT_METHOD);
\r
323 } else if (doc.isConstructor()) {
\r
324 setType(CAT, CAT_CONSTRUCTOR);
\r
325 } else if (doc.isClass() || doc.isInterface()) {
\r
326 setType(CAT, CAT_CLASS);
\r
329 setType(PAK, doc.containingPackage().name());
\r
330 setType(CLS, (doc.isClass() || doc.isInterface() || (doc.containingClass() == null)) ? "" : doc.containingClass().name());
\r
331 setType(NAM, doc.name());
\r
333 if (doc instanceof FieldDoc) {
\r
334 FieldDoc fdoc = (FieldDoc)doc;
\r
335 setType(SIG, fdoc.type().toString());
\r
336 } else if (doc instanceof ClassDoc) {
\r
337 ClassDoc cdoc = (ClassDoc)doc;
\r
339 if (cdoc.isClass() && cdoc.isAbstract()) { // interfaces are abstract by default, don't mark them as abstract
\r
340 setType(ABS, ABS_ABSTRACT);
\r
343 StringBuffer buf = new StringBuffer();
\r
344 if (cdoc.isClass()) {
\r
345 buf.append("extends ");
\r
346 buf.append(cdoc.superclass().qualifiedName());
\r
348 ClassDoc[] imp = cdoc.interfaces();
\r
349 if (imp != null && imp.length > 0) {
\r
350 if (buf.length() > 0) {
\r
353 buf.append("implements");
\r
354 for (int i = 0; i < imp.length; ++i) {
\r
359 buf.append(imp[i].qualifiedName());
\r
362 setType(SIG, buf.toString());
\r
364 ExecutableMemberDoc emdoc = (ExecutableMemberDoc)doc;
\r
365 if (emdoc.isSynchronized()) {
\r
366 setType(SYN, SYN_SYNCHRONIZED);
\r
369 if (doc instanceof MethodDoc) {
\r
370 MethodDoc mdoc = (MethodDoc)doc;
\r
371 if (mdoc.isAbstract()) {
\r
372 setType(ABS, ABS_ABSTRACT);
\r
374 setType(SIG, mdoc.returnType().toString() + emdoc.signature());
\r
377 setType(SIG, emdoc.signature());
\r
384 public static Comparator defaultComparator() {
\r
385 final Comparator c = new Comparator() {
\r
386 public int compare(Object lhs, Object rhs) {
\r
387 Info lhi = (Info)lhs;
\r
388 Info rhi = (Info)rhs;
\r
389 int result = lhi.pack.compareTo(rhi.pack);
\r
391 result = (lhi.getVal(CAT) == CAT_CLASS ? lhi.name : lhi.cls)
\r
392 .compareTo(rhi.getVal(CAT) == CAT_CLASS ? rhi.name : rhi.cls);
\r
394 result = lhi.getVal(CAT)- rhi.getVal(CAT);
\r
396 result = lhi.name.compareTo(rhi.name);
\r
398 result = lhi.sig.compareTo(rhi.sig);
\r
409 public static Comparator changedComparator() {
\r
410 final Comparator c = new Comparator() {
\r
411 public int compare(Object lhs, Object rhs) {
\r
412 Info lhi = (Info)lhs;
\r
413 Info rhi = (Info)rhs;
\r
414 int result = lhi.pack.compareTo(rhi.pack);
\r
416 result = (lhi.getVal(CAT) == CAT_CLASS ? lhi.name : lhi.cls)
\r
417 .compareTo(rhi.getVal(CAT) == CAT_CLASS ? rhi.name : rhi.cls);
\r
419 result = lhi.getVal(CAT)- rhi.getVal(CAT);
\r
421 result = lhi.name.compareTo(rhi.name);
\r
422 if (result == 0 && lhi.getVal(CAT) != CAT_CLASS) {
\r
423 result = lhi.sig.compareTo(rhi.sig);
\r
434 public static Comparator classFirstComparator() {
\r
435 final Comparator c = new Comparator() {
\r
436 public int compare(Object lhs, Object rhs) {
\r
437 Info lhi = (Info)lhs;
\r
438 Info rhi = (Info)rhs;
\r
439 int result = lhi.pack.compareTo(rhi.pack);
\r
441 boolean lcls = lhi.getVal(CAT) == CAT_CLASS;
\r
442 boolean rcls = rhi.getVal(CAT) == CAT_CLASS;
\r
443 result = lcls == rcls ? 0 : (lcls ? -1 : 1);
\r
445 result = (lcls ? lhi.name : lhi.cls).compareTo(rcls ? rhi.name : rhi.cls);
\r
447 result = lhi.getVal(CAT)- rhi.getVal(CAT);
\r
449 result = lhi.name.compareTo(rhi.name);
\r
450 if (result == 0 && !lcls) {
\r
451 result = lhi.sig.compareTo(rhi.sig);
\r
463 private static final String[] typeNames = {
\r
464 "status", "visibility", "static", "final", "synchronized",
\r
465 "abstract", "category", "package", "class", "name", "signature"
\r
468 private static final String[][] names = {
\r
469 { "draft ", "stable ", "deprecated", "obsolete " },
\r
470 { "package", "public", "protected", "private" },
\r
473 { "", "synchronized" },
\r
474 { "", "abstract" },
\r
475 { "class", "field", "constructor", "method" },
\r
483 private static final String[][] shortNames = {
\r
484 { "DR", "ST", "DP", "OB" },
\r
485 { "PK", "PB", "PT", "PR" },
\r
490 { "L", "F", "C", "M" },
\r
498 private static void validateType(int typ) {
\r
499 if (typ < 0 || typ > NUM_TYPES) {
\r
500 throw new IllegalArgumentException("bad type index: " + typ);
\r
504 public String toString() {
\r
505 return get(NAM, true);
\r
509 static final class DeltaInfo extends APIInfo {
\r
513 DeltaInfo(Info a, Info b) {
\r
518 public int getVal(int typ) {
\r
519 return a.getVal(typ);
\r
522 public String get(int typ, boolean brief) {
\r
523 return a.get(typ, brief);
\r
526 public void write(BufferedWriter w, boolean brief, boolean html, boolean detail) {
\r
527 a.write(w, brief, html, detail);
\r
534 catch (Exception e) {
\r
536 b.write(w, brief, html, detail);
\r
539 public String toString() {
\r
540 return a.get(NAM, true);
\r
544 public static int optionLength(String option) {
\r
545 if (option.equals("-html")) {
\r
547 } else if (option.equals("-name")) {
\r
549 } else if (option.equals("-output")) {
\r
551 } else if (option.equals("-compare")) {
\r
557 public static boolean start(RootDoc root) {
\r
558 return new CheckAPI(root).run();
\r
561 CheckAPI(RootDoc root) {
\r
564 // this.compare = "c:/doug/cvsproj/icu4j/src/com/ibm/icu/dev/tool/docs/api2_8.txt";
\r
566 String[][] options = root.options();
\r
567 for (int i = 0; i < options.length; ++i) {
\r
568 String opt = options[i][0];
\r
569 if (opt.equals("-html")) {
\r
571 } else if (opt.equals("-name")) {
\r
572 this.srcName = options[i][1];
\r
573 } else if (opt.equals("-output")) {
\r
574 this.output = options[i][1];
\r
575 } else if (opt.equals("-compare")) {
\r
576 this.compare = options[i][1];
\r
580 if (compare != null) {
\r
582 // URL url = new URL(compare);
\r
583 File f = new File(compare);
\r
584 InputStream is = new FileInputStream(f);
\r
585 InputStreamReader isr = new InputStreamReader(is);
\r
586 BufferedReader br = new BufferedReader(isr);
\r
588 // read header line
\r
589 /*int version = */Integer.parseInt(readToken(br));
\r
590 // check version if we change it later, probably can just rebuild though
\r
591 this.compareName = readToken(br);
\r
595 this.compareSet = new TreeSet(Info.defaultComparator());
\r
596 for (Info info = new Info(); info.read(br); info = new Info()) {
\r
597 compareSet.add(info);
\r
600 catch (Exception e) {
\r
601 RuntimeException re = new RuntimeException("error reading " + compare);
\r
607 results = new TreeSet(Info.defaultComparator());
\r
610 private boolean run() {
\r
611 doDocs(root.classes());
\r
613 OutputStream os = System.out;
\r
614 if (output != null) {
\r
616 os = new FileOutputStream(output);
\r
618 catch (FileNotFoundException e) {
\r
619 RuntimeException re = new RuntimeException(e.getMessage());
\r
625 BufferedWriter bw = null;
\r
627 OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
\r
628 bw = new BufferedWriter(osw);
\r
630 if (compareSet == null) {
\r
631 // writing data file
\r
632 bw.write(String.valueOf(DATA_FILE_VERSION) + SEP); // header version
\r
633 bw.write(srcName + SEP); // source name
\r
635 writeResults(results, bw, true, false, false);
\r
637 // writing comparison info
\r
638 TreeSet removed = (TreeSet)compareSet.clone();
\r
639 removed.removeAll(results);
\r
641 TreeSet added = (TreeSet)results.clone();
\r
642 added.removeAll(compareSet);
\r
644 Iterator ai = added.iterator();
\r
645 Iterator ri = removed.iterator();
\r
646 ArrayList changed = new ArrayList();
\r
647 Comparator c = Info.changedComparator();
\r
648 Info a = null, r = null;
\r
649 while (ai.hasNext() && ri.hasNext()) {
\r
650 if (a == null) a = (Info)ai.next();
\r
651 if (r == null) r = (Info)ri.next();
\r
652 int result = c.compare(a, r);
\r
655 } else if (result > 0) {
\r
658 changed.add(new DeltaInfo(a, r));
\r
659 a = null; ai.remove();
\r
660 r = null; ri.remove();
\r
664 added = stripAndResort(added);
\r
665 removed = stripAndResort(removed);
\r
668 String title = "ICU4J API Comparison: " + srcName + " with " + compareName;
\r
670 bw.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
\r
672 bw.write("<html>");
\r
674 bw.write("<head>");
\r
676 bw.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
\r
678 bw.write("<title>");
\r
680 bw.write("</title>");
\r
682 bw.write("<body>");
\r
693 bw.write("Removed from " + compareName);
\r
697 if (removed.size() > 0) {
\r
698 writeResults(removed, bw, false, true, false);
\r
700 bw.write("<p>(no API removed)</p>");
\r
707 bw.write("Changed in " + srcName);
\r
711 if (changed.size() > 0) {
\r
712 writeResults(changed, bw, false, true, true);
\r
714 bw.write("<p>(no API changed)</p>");
\r
721 bw.write("Added in " + srcName);
\r
725 if (added.size() > 0) {
\r
726 writeResults(added, bw, false, true, false);
\r
728 bw.write("<p>(no API added)</p>");
\r
732 bw.write("<p><i>Contents generated by CheckAPI tool.<br/>Copyright (C) 2004, International Business Machines Corporation, All Rights Reserved.</i></p>");
\r
734 bw.write("</body>");
\r
736 bw.write("</html>");
\r
739 bw.write("Comparing " + srcName + " with " + compareName);
\r
744 bw.write("=== Removed from " + compareName + " ===");
\r
746 if (removed.size() > 0) {
\r
747 writeResults(removed, bw, false, false, false);
\r
749 bw.write("(no API removed)");
\r
754 bw.write("=== Changed in " + srcName + " ===");
\r
756 if (changed.size() > 0) {
\r
757 writeResults(changed, bw, false, false, true);
\r
759 bw.write("(no API changed)");
\r
764 bw.write("=== Added in " + srcName + " ===");
\r
766 if (added.size() > 0) {
\r
767 writeResults(added, bw, false, false, false);
\r
769 bw.write("(no API added)");
\r
776 } catch (IOException e) {
\r
777 try { bw.close(); } catch (IOException e2) {}
\r
778 RuntimeException re = new RuntimeException("write error: " + e.getMessage());
\r
786 private void doDocs(ProgramElementDoc[] docs) {
\r
787 if (docs != null && docs.length > 0) {
\r
788 for (int i = 0; i < docs.length; ++i) {
\r
794 private void doDoc(ProgramElementDoc doc) {
\r
795 if (ignore(doc)) return;
\r
797 if (doc.isClass() || doc.isInterface()) {
\r
798 ClassDoc cdoc = (ClassDoc)doc;
\r
799 doDocs(cdoc.fields());
\r
800 doDocs(cdoc.constructors());
\r
801 doDocs(cdoc.methods());
\r
802 doDocs(cdoc.innerClasses());
\r
805 Info info = new Info();
\r
806 if (info.read(doc)) {
\r
811 private boolean ignore(ProgramElementDoc doc) {
\r
812 if (doc == null) return true;
\r
813 if (doc.isPrivate() || doc.isPackagePrivate()) return true;
\r
814 if (doc instanceof ConstructorDoc && ((ConstructorDoc)doc).isSynthetic()) return true;
\r
815 if (doc.qualifiedName().indexOf(".misc") != -1) return true;
\r
816 Tag[] tags = doc.tags();
\r
817 for (int i = 0; i < tags.length; ++i) {
\r
818 if (tagKindIndex(tags[i].kind()) == INTERNAL) return true;
\r
824 private static void writeResults(Collection c, BufferedWriter w, boolean brief, boolean html, boolean detail) {
\r
825 Iterator iter = c.iterator();
\r
826 String pack = null;
\r
827 String clas = null;
\r
828 while (iter.hasNext()) {
\r
829 APIInfo info = (APIInfo)iter.next();
\r
831 info.write(w, brief, false, detail);
\r
834 String p = info.get(PAK, true);
\r
835 if (!p.equals(pack)) {
\r
838 if (clas != null) {
\r
842 if (pack != null) {
\r
847 w.write("<h3>Package ");
\r
854 w.write("Package ");
\r
865 if (info.getVal(CAT) != CAT_CLASS) {
\r
866 String name = info.get(CLS, true);
\r
867 if (!name.equals(clas)) {
\r
869 if (clas != null) {
\r
886 info.write(w, brief, html, detail);
\r
889 info.write(w, brief, html, detail);
\r
892 catch (IOException e) {
\r
893 System.err.println("IOException " + e.getMessage() + " writing " + info);
\r
899 if (clas != null) {
\r
903 if (pack != null) {
\r
908 catch (IOException e) {
\r
913 private static String readToken(BufferedReader r) throws IOException {
\r
914 char[] buf = new char[256];
\r
916 for (; i < buf.length; ++i) {
\r
919 throw new IOException("unexpected EOF");
\r
920 } else if (c == SEP) {
\r
925 if (i == buf.length) {
\r
926 throw new IOException("unterminated token" + new String(buf));
\r
929 return new String(buf, 0, i);
\r
932 private static TreeSet stripAndResort(TreeSet t) {
\r
934 TreeSet r = new TreeSet(Info.classFirstComparator());
\r
939 private static void stripClassInfo(Collection c) {
\r
940 // c is sorted with class info first
\r
941 Iterator iter = c.iterator();
\r
942 String cname = null;
\r
943 while (iter.hasNext()) {
\r
944 Info info = (Info)iter.next();
\r
945 String cls = info.get(CLS, true);
\r
946 if (cname != null) {
\r
947 if (cname.equals(cls)) {
\r
953 if (info.getVal(CAT) == CAT_CLASS) {
\r
954 cname = info.get(NAM, true);
\r
959 private static int tagStatus(final Doc doc) {
\r
962 void set(int val) { if (res != -1) throw new RuntimeException("bad doc: " + doc); res = val; }
\r
965 System.err.println("warning: no tag for " + doc);
\r
972 Tag[] tags = doc.tags();
\r
973 Result result = new Result();
\r
974 for (int i = 0; i < tags.length; ++i) {
\r
977 String kind = tag.kind();
\r
978 int ix = tagKindIndex(kind);
\r
986 result.set(STA_DRAFT);
\r
990 result.set(STA_STABLE);
\r
994 result.set(STA_DEPRECATED);
\r
998 result.set(STA_OBSOLETE);
\r
1014 throw new RuntimeException("unknown index " + ix + " for tag: " + kind);
\r
1018 return result.get();
\r
1021 private static final int UNKNOWN = -1;
\r
1022 private static final int INTERNAL = 0;
\r
1023 private static final int DRAFT = 1;
\r
1024 private static final int STABLE = 2;
\r
1025 private static final int SINCE = 3;
\r
1026 private static final int DEPRECATED = 4;
\r
1027 private static final int AUTHOR = 5;
\r
1028 private static final int SEE = 6;
\r
1029 private static final int VERSION = 7;
\r
1030 private static final int PARAM = 8;
\r
1031 private static final int RETURN = 9;
\r
1032 private static final int THROWS = 10;
\r
1033 private static final int OBSOLETE = 11;
\r
1034 private static final int EXCEPTION = 12;
\r
1035 private static final int SERIAL = 13;
\r
1037 private static int tagKindIndex(String kind) {
\r
1038 final String[] tagKinds = {
\r
1039 "@internal", "@draft", "@stable", "@since", "@deprecated", "@author", "@see", "@version",
\r
1040 "@param", "@return", "@throws", "@obsolete", "@exception", "@serial"
\r
1043 for (int i = 0; i < tagKinds.length; ++i) {
\r
1044 if (kind.equals(tagKinds[i])) {
\r