mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 22:44:49 +00:00
ICU-3574 prototype tool to compare APIs between releases of ICU4J
X-SVN-Rev: 14505
This commit is contained in:
parent
6870d527dc
commit
2a417cd56e
1 changed files with 974 additions and 0 deletions
974
icu4j/src/com/ibm/icu/dev/tool/docs/CheckAPI.java
Normal file
974
icu4j/src/com/ibm/icu/dev/tool/docs/CheckAPI.java
Normal file
|
@ -0,0 +1,974 @@
|
|||
/**
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2004, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*
|
||||
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/dev/tool/docs/CheckAPI.java,v $
|
||||
* $Date: 2004/02/13 00:10:32 $
|
||||
* $Revision: 1.1 $
|
||||
*
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generate a list of ICU's public APIs, sorted by qualified name and signature
|
||||
* public APIs are all non-internal, non-package apis in com.ibm.icu.[lang|math|text|util].
|
||||
* For each API, list
|
||||
* - public, package, protected, or private (PB PK PT PR)
|
||||
* - static or non-static (STK NST)
|
||||
* - final or non-final (FN NF)
|
||||
* - synchronized or non-synchronized (SYN NSY)
|
||||
* - stable, draft, deprecated, obsolete (ST DR DP OB)
|
||||
* - abstract or non-abstract (AB NA)
|
||||
* - constructor, member, field (C M F)
|
||||
*
|
||||
* Requires JDK 1.4.2 or later
|
||||
*
|
||||
* Sample invocation:
|
||||
* c:/j2sdk1.4.2/bin/javadoc
|
||||
* -classpath c:/jd2sk1.4.2/lib/tools.jar
|
||||
* -doclet com.ibm.icu.dev.tool.docs.CheckAPI
|
||||
* -docletpath c:/doug/cvsproj/icu4j/src
|
||||
* -sourcepath c:/eclipse2.1/workspace2/icu4j/src
|
||||
* -compare c:/doug/cvsproj/icu4j/src/com/ibm/icu/dev/tool/docs/api2_6_1.txt
|
||||
* -output foo
|
||||
* com.ibm.icu.text
|
||||
*/
|
||||
|
||||
package com.ibm.icu.dev.tool.docs;
|
||||
|
||||
import com.sun.javadoc.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
public class CheckAPI {
|
||||
RootDoc root;
|
||||
String compare; // file
|
||||
String compareName;
|
||||
TreeSet compareSet;
|
||||
TreeSet results;
|
||||
boolean html;
|
||||
String srcName = "Current"; // default source name
|
||||
String output;
|
||||
|
||||
private static final int DATA_FILE_VERSION = 1;
|
||||
private static final char SEP = ';';
|
||||
|
||||
private static final int STA = 0, STA_DRAFT = 0, STA_STABLE = 1, STA_DEPRECATED = 2, STA_OBSOLETE = 3;
|
||||
private static final int VIS = 1, VIS_PACKAGE = 0, VIS_PUBLIC= 1, VIS_PROTECTED = 2, VIS_PRIVATE = 3;
|
||||
private static final int STK = 2, STK_STATIC = 1;
|
||||
private static final int FIN = 3, FIN_FINAL = 1;
|
||||
private static final int SYN = 4, SYN_SYNCHRONIZED = 1;
|
||||
private static final int ABS = 5, ABS_ABSTRACT = 1;
|
||||
private static final int CAT = 6, CAT_CLASS = 0, CAT_FIELD = 1, CAT_CONSTRUCTOR = 2, CAT_METHOD = 3;
|
||||
private static final int PAK = 7;
|
||||
private static final int CLS = 8;
|
||||
private static final int NAM = 9;
|
||||
private static final int SIG = 10;
|
||||
private static final int EXC = 11;
|
||||
private static final int NUM_TYPES = 11;
|
||||
|
||||
final static class Info {
|
||||
private int info;
|
||||
private String pack; // package
|
||||
private String cls; // enclosing class
|
||||
private String name; // name
|
||||
private String sig; // signature, class: inheritance, method: signature, field: type, const: signature
|
||||
private String exc; // throws
|
||||
|
||||
public int getVal(int typ) {
|
||||
validateType(typ);
|
||||
return (info >> (typ*2)) & 0x3;
|
||||
}
|
||||
|
||||
public String get(int typ, boolean brief) {
|
||||
validateType(typ);
|
||||
String[] vals = brief ? shortNames[typ] : names[typ];
|
||||
if (vals == null) {
|
||||
switch (typ) {
|
||||
case PAK: return pack;
|
||||
case CLS: return cls;
|
||||
case NAM: return name;
|
||||
case SIG: return sig;
|
||||
case EXC: return exc;
|
||||
}
|
||||
}
|
||||
int val = (info >> (typ*2)) & 0x3;
|
||||
return vals[val];
|
||||
}
|
||||
|
||||
private void setType(int typ, int val) {
|
||||
validateType(typ);
|
||||
info &= ~(0x3 << (typ*2));
|
||||
info |= (val&0x3) << (typ * 2);
|
||||
}
|
||||
|
||||
private void setType(int typ, String val) {
|
||||
validateType(typ);
|
||||
String[] vals = shortNames[typ];
|
||||
if (vals == null) {
|
||||
switch (typ) {
|
||||
case PAK: pack = val; break;
|
||||
case CLS: cls = val; break;
|
||||
case NAM: name = val; break;
|
||||
case SIG: sig = val; break;
|
||||
case EXC: exc = val; break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < vals.length; ++i) {
|
||||
if (val.equalsIgnoreCase(vals[i])) {
|
||||
info &= ~(0x3 << (typ*2));
|
||||
info |= i << (typ*2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("unrecognized value '" + val + "' for type '" + typeNames[typ] + "'");
|
||||
}
|
||||
|
||||
public void write(BufferedWriter w, boolean brief) {
|
||||
try {
|
||||
if (brief) {
|
||||
for (int i = 0; i < NUM_TYPES; ++i) {
|
||||
String s = get(i, true);
|
||||
if (s != null) {
|
||||
w.write(s);
|
||||
}
|
||||
w.write(SEP);
|
||||
}
|
||||
} else {
|
||||
// remove all occurrences of icu packages from the param string
|
||||
// fortunately, all the packages have 4 chars (lang, math, text, util).
|
||||
final String ICUPACK = "com.ibm.icu.";
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < sig.length();) {
|
||||
int n = sig.indexOf(ICUPACK, i);
|
||||
if (n == -1) {
|
||||
buf.append(sig.substring(i));
|
||||
break;
|
||||
}
|
||||
buf.append(sig.substring(i, n));
|
||||
i = n + ICUPACK.length() + 5; // trailing 'xxxx.'
|
||||
}
|
||||
String xsig = buf.toString();
|
||||
|
||||
// construct signature
|
||||
for (int i = VIS; i < CAT; ++i) { // omit status
|
||||
String s = get(i, false);
|
||||
if (s != null && s.length() > 0) {
|
||||
w.write(s);
|
||||
w.write(' ');
|
||||
}
|
||||
}
|
||||
|
||||
int val = getVal(CAT);
|
||||
switch (val) {
|
||||
case CAT_CLASS:
|
||||
if (sig.indexOf("extends") == -1) {
|
||||
w.write("interface ");
|
||||
} else {
|
||||
w.write("class ");
|
||||
}
|
||||
if (cls.length() > 0) {
|
||||
w.write(cls);
|
||||
w.write('.');
|
||||
}
|
||||
w.write(name);
|
||||
break;
|
||||
|
||||
case CAT_FIELD:
|
||||
w.write(xsig);
|
||||
w.write(' ');
|
||||
// if (cls.length() > 0) {
|
||||
// w.write(cls);
|
||||
// w.write('.');
|
||||
// }
|
||||
w.write(name);
|
||||
break;
|
||||
|
||||
case CAT_METHOD:
|
||||
case CAT_CONSTRUCTOR:
|
||||
int n = xsig.indexOf('(');
|
||||
if (n > 0) {
|
||||
w.write(xsig.substring(0, n));
|
||||
w.write(' ');
|
||||
} else {
|
||||
n = 0;
|
||||
}
|
||||
// if (val != CAT_METHOD) {
|
||||
// if (cls.length() > 0) {
|
||||
// w.write(cls);
|
||||
// w.write('.');
|
||||
// }
|
||||
// }
|
||||
w.write(name);
|
||||
w.write(xsig.substring(n));
|
||||
break;
|
||||
}
|
||||
}
|
||||
w.newLine();
|
||||
}
|
||||
catch (IOException e) {
|
||||
RuntimeException re = new RuntimeException("IO Error");
|
||||
re.initCause(e);
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean read(BufferedReader r) {
|
||||
int i = 0;
|
||||
try {
|
||||
for (; i < NUM_TYPES; ++i) {
|
||||
setType(i, readToken(r));
|
||||
}
|
||||
r.readLine(); // swallow line end sequence
|
||||
}
|
||||
catch (IOException e) {
|
||||
if (i == 0) { // assume if first read returns error, we have reached end of input
|
||||
return false;
|
||||
}
|
||||
RuntimeException re = new RuntimeException("IO Error");
|
||||
re.initCause(e);
|
||||
throw re;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean read(ProgramElementDoc doc) {
|
||||
|
||||
// Doc. name
|
||||
// Doc. isField, isMethod, isConstructor, isClass, isInterface
|
||||
// ProgramElementDoc. containingClass, containingPackage
|
||||
// ProgramElementDoc. isPublic, isProtected, isPrivate, isPackagePrivate
|
||||
// ProgramElementDoc. isStatic, isFinal
|
||||
// MemberDoc.isSynthetic
|
||||
// ExecutableMemberDoc isSynchronized, signature
|
||||
// Type.toString() // e.g. "String[][]"
|
||||
// ClassDoc.isAbstract, superClass, interfaces, fields, methods, constructors, innerClasses
|
||||
// FieldDoc type
|
||||
// ConstructorDoc qualifiedName
|
||||
// MethodDoc isAbstract, returnType
|
||||
|
||||
|
||||
// status
|
||||
setType(STA, tagStatus(doc));
|
||||
|
||||
// visibility
|
||||
if (doc.isPublic()) {
|
||||
setType(VIS, VIS_PUBLIC);
|
||||
} else if (doc.isProtected()) {
|
||||
setType(VIS, VIS_PROTECTED);
|
||||
} else if (doc.isPrivate()) {
|
||||
setType(VIS, VIS_PRIVATE);
|
||||
} else {
|
||||
// default is package
|
||||
}
|
||||
|
||||
// static
|
||||
if (doc.isStatic()) {
|
||||
setType(STK, STK_STATIC);
|
||||
} else {
|
||||
// default is non-static
|
||||
}
|
||||
|
||||
// final
|
||||
if (doc.isFinal()) {
|
||||
setType(FIN, FIN_FINAL);
|
||||
} else {
|
||||
// default is non-final
|
||||
}
|
||||
|
||||
// type
|
||||
if (doc.isField()) {
|
||||
setType(CAT, CAT_FIELD);
|
||||
} else if (doc.isMethod()) {
|
||||
setType(CAT, CAT_METHOD);
|
||||
} else if (doc.isConstructor()) {
|
||||
setType(CAT, CAT_CONSTRUCTOR);
|
||||
} else if (doc.isClass() || doc.isInterface()) {
|
||||
setType(CAT, CAT_CLASS);
|
||||
}
|
||||
|
||||
setType(PAK, doc.containingPackage().name());
|
||||
setType(CLS, (doc.isClass() || doc.isInterface() || (doc.containingClass() == null)) ? "" : doc.containingClass().name());
|
||||
setType(NAM, doc.name());
|
||||
|
||||
if (doc instanceof FieldDoc) {
|
||||
FieldDoc fdoc = (FieldDoc)doc;
|
||||
setType(SIG, fdoc.type().toString());
|
||||
} else if (doc instanceof ClassDoc) {
|
||||
ClassDoc cdoc = (ClassDoc)doc;
|
||||
|
||||
if (cdoc.isClass() && cdoc.isAbstract()) { // interfaces are abstract by default, don't mark them as abstract
|
||||
setType(ABS, ABS_ABSTRACT);
|
||||
}
|
||||
|
||||
StringBuffer buf = new StringBuffer();
|
||||
if (cdoc.isClass()) {
|
||||
buf.append("extends ");
|
||||
buf.append(cdoc.superclass().qualifiedName());
|
||||
}
|
||||
ClassDoc[] imp = cdoc.interfaces();
|
||||
if (imp != null && imp.length > 0) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append(" ");
|
||||
}
|
||||
buf.append("implements");
|
||||
for (int i = 0; i < imp.length; ++i) {
|
||||
if (i != 0) {
|
||||
buf.append(",");
|
||||
}
|
||||
buf.append(" ");
|
||||
buf.append(imp[i].qualifiedName());
|
||||
}
|
||||
}
|
||||
setType(SIG, buf.toString());
|
||||
} else {
|
||||
ExecutableMemberDoc emdoc = (ExecutableMemberDoc)doc;
|
||||
if (emdoc.isSynchronized()) {
|
||||
setType(SYN, SYN_SYNCHRONIZED);
|
||||
}
|
||||
|
||||
if (doc instanceof MethodDoc) {
|
||||
MethodDoc mdoc = (MethodDoc)doc;
|
||||
if (mdoc.isAbstract()) {
|
||||
setType(ABS, ABS_ABSTRACT);
|
||||
}
|
||||
setType(SIG, mdoc.returnType().toString() + emdoc.signature());
|
||||
} else {
|
||||
// constructor
|
||||
setType(SIG, emdoc.signature());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Comparator defaultComparator() {
|
||||
final Comparator c = new Comparator() {
|
||||
public int compare(Object lhs, Object rhs) {
|
||||
Info lhi = (Info)lhs;
|
||||
Info rhi = (Info)rhs;
|
||||
int result = lhi.pack.compareTo(rhi.pack);
|
||||
if (result == 0) {
|
||||
result = (lhi.getVal(CAT) == CAT_CLASS ? lhi.name : lhi.cls)
|
||||
.compareTo(rhi.getVal(CAT) == CAT_CLASS ? rhi.name : rhi.cls);
|
||||
if (result == 0) {
|
||||
result = lhi.getVal(CAT)- rhi.getVal(CAT);
|
||||
if (result == 0) {
|
||||
result = lhi.name.compareTo(rhi.name);
|
||||
if (result == 0) {
|
||||
result = lhi.sig.compareTo(rhi.sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
return c;
|
||||
}
|
||||
|
||||
public static Comparator changedComparator() {
|
||||
final Comparator c = new Comparator() {
|
||||
public int compare(Object lhs, Object rhs) {
|
||||
Info lhi = (Info)lhs;
|
||||
Info rhi = (Info)rhs;
|
||||
int result = lhi.pack.compareTo(rhi.pack);
|
||||
if (result == 0) {
|
||||
result = (lhi.getVal(CAT) == CAT_CLASS ? lhi.name : lhi.cls)
|
||||
.compareTo(rhi.getVal(CAT) == CAT_CLASS ? rhi.name : rhi.cls);
|
||||
if (result == 0) {
|
||||
result = lhi.getVal(CAT)- rhi.getVal(CAT);
|
||||
if (result == 0) {
|
||||
result = lhi.name.compareTo(rhi.name);
|
||||
if (result == 0 && lhi.getVal(CAT) != CAT_CLASS) {
|
||||
result = lhi.sig.compareTo(rhi.sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
return c;
|
||||
}
|
||||
|
||||
public static Comparator classFirstComparator() {
|
||||
final Comparator c = new Comparator() {
|
||||
public int compare(Object lhs, Object rhs) {
|
||||
Info lhi = (Info)lhs;
|
||||
Info rhi = (Info)rhs;
|
||||
int result = lhi.pack.compareTo(rhi.pack);
|
||||
if (result == 0) {
|
||||
boolean lcls = lhi.getVal(CAT) == CAT_CLASS;
|
||||
boolean rcls = rhi.getVal(CAT) == CAT_CLASS;
|
||||
result = lcls == rcls ? 0 : (lcls ? -1 : 1);
|
||||
if (result == 0) {
|
||||
result = (lcls ? lhi.name : lhi.cls).compareTo(rcls ? rhi.name : rhi.cls);
|
||||
if (result == 0) {
|
||||
result = lhi.getVal(CAT)- rhi.getVal(CAT);
|
||||
if (result == 0) {
|
||||
result = lhi.name.compareTo(rhi.name);
|
||||
if (result == 0 && !lcls) {
|
||||
result = lhi.sig.compareTo(rhi.sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
return c;
|
||||
}
|
||||
|
||||
private static final String[] typeNames = {
|
||||
"status", "visibility", "static", "final", "synchronized",
|
||||
"abstract", "category", "package", "class", "name", "signature"
|
||||
};
|
||||
|
||||
private static final String[][] names = {
|
||||
{ "draft ", "stable ", "deprecated", "obsolete " },
|
||||
{ "package", "public", "protected", "private" },
|
||||
{ "", "static" },
|
||||
{ "", "final" },
|
||||
{ "", "synchronized" },
|
||||
{ "", "abstract" },
|
||||
{ "class", "field", "constructor", "method" },
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
};
|
||||
|
||||
private static final String[][] shortNames = {
|
||||
{ "DR", "ST", "DP", "OB" },
|
||||
{ "PK", "PB", "PT", "PR" },
|
||||
{ "NS", "ST" },
|
||||
{ "NF", "FN" },
|
||||
{ "NS", "SY" },
|
||||
{ "NA", "AB" },
|
||||
{ "L", "F", "C", "M" },
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
};
|
||||
|
||||
private static void validateType(int typ) {
|
||||
if (typ < 0 || typ > NUM_TYPES) {
|
||||
throw new IllegalArgumentException("bad type index: " + typ);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
public static int optionLength(String option) {
|
||||
if (option.equals("-html")) {
|
||||
return 1;
|
||||
} else if (option.equals("-name")) {
|
||||
return 2;
|
||||
} else if (option.equals("-output")) {
|
||||
return 2;
|
||||
} else if (option.equals("-compare")) {
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static boolean start(RootDoc root) {
|
||||
return new CheckAPI(root).run();
|
||||
}
|
||||
|
||||
CheckAPI(RootDoc root) {
|
||||
this.root = root;
|
||||
|
||||
// this.compare = "c:/doug/cvsproj/icu4j/src/com/ibm/icu/dev/tool/docs/api2_8.txt";
|
||||
|
||||
String[][] options = root.options();
|
||||
for (int i = 0; i < options.length; ++i) {
|
||||
String opt = options[i][0];
|
||||
if (opt.equals("-html")) {
|
||||
this.html = true;
|
||||
} else if (opt.equals("-name")) {
|
||||
this.srcName = options[i][1];
|
||||
} else if (opt.equals("-output")) {
|
||||
this.output = options[i][1];
|
||||
} else if (opt.equals("-compare")) {
|
||||
this.compare = options[i][1];
|
||||
}
|
||||
}
|
||||
|
||||
if (compare != null) {
|
||||
try {
|
||||
// URL url = new URL(compare);
|
||||
File f = new File(compare);
|
||||
InputStream is = new FileInputStream(f);
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
|
||||
// read header line
|
||||
int version = Integer.parseInt(readToken(br));
|
||||
// check version if we change it later, probably can just rebuild though
|
||||
this.compareName = readToken(br);
|
||||
br.readLine();
|
||||
|
||||
// read data
|
||||
this.compareSet = new TreeSet(Info.defaultComparator());
|
||||
for (Info info = new Info(); info.read(br); info = new Info()) {
|
||||
compareSet.add(info);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
RuntimeException re = new RuntimeException("error reading " + compare);
|
||||
re.initCause(e);
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
results = new TreeSet(Info.defaultComparator());
|
||||
}
|
||||
|
||||
private boolean run() {
|
||||
doDocs(root.classes());
|
||||
|
||||
OutputStream os = System.out;
|
||||
if (output != null) {
|
||||
try {
|
||||
os = new FileOutputStream(output);
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
RuntimeException re = new RuntimeException(e.getMessage());
|
||||
re.initCause(e);
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
BufferedWriter bw = null;
|
||||
try {
|
||||
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
|
||||
bw = new BufferedWriter(osw);
|
||||
|
||||
if (compareSet == null) {
|
||||
// writing data file
|
||||
bw.write(String.valueOf(DATA_FILE_VERSION) + SEP); // header version
|
||||
bw.write(srcName + SEP); // source name
|
||||
bw.newLine();
|
||||
writeResults(results, bw, true, false);
|
||||
} else {
|
||||
// writing comparison info
|
||||
TreeSet removed = (TreeSet)compareSet.clone();
|
||||
removed.removeAll(results);
|
||||
|
||||
TreeSet added = (TreeSet)results.clone();
|
||||
added.removeAll(compareSet);
|
||||
|
||||
Iterator ai = added.iterator();
|
||||
Iterator ri = removed.iterator();
|
||||
ArrayList changed = new ArrayList();
|
||||
Comparator c = Info.changedComparator();
|
||||
Info a = null, r = null;
|
||||
while (ai.hasNext() && ri.hasNext()) {
|
||||
if (a == null) a = (Info)ai.next();
|
||||
if (r == null) r = (Info)ri.next();
|
||||
int result = c.compare(a, r);
|
||||
if (result < 0) {
|
||||
a = null;
|
||||
} else if (result > 0) {
|
||||
r = null;
|
||||
} else {
|
||||
changed.add(a);
|
||||
a = null; ai.remove();
|
||||
r = null; ri.remove();
|
||||
}
|
||||
}
|
||||
|
||||
added = stripAndResort(added);
|
||||
removed = stripAndResort(removed);
|
||||
|
||||
if (html) {
|
||||
String title = "API Comparison: " + srcName + " with " + compareName;
|
||||
|
||||
bw.write("<html>");
|
||||
bw.newLine();
|
||||
bw.write("<head>");
|
||||
bw.newLine();
|
||||
bw.write("<title>");
|
||||
bw.write(title);
|
||||
bw.write("</title>");
|
||||
bw.newLine();
|
||||
bw.write("<body>");
|
||||
bw.newLine();
|
||||
|
||||
bw.write("<h1>");
|
||||
bw.write(title);
|
||||
bw.write("</h1>");
|
||||
bw.newLine();
|
||||
|
||||
bw.write("<hr/>");
|
||||
bw.newLine();
|
||||
bw.write("<h2>");
|
||||
bw.write("Removed from " + compareName);
|
||||
bw.write("</h2>");
|
||||
bw.newLine();
|
||||
|
||||
if (removed.size() > 0) {
|
||||
writeResults(removed, bw, false, true);
|
||||
} else {
|
||||
bw.write("<p>(no API removed)</p>");
|
||||
}
|
||||
bw.newLine();
|
||||
|
||||
bw.write("<hr/>");
|
||||
bw.newLine();
|
||||
bw.write("<h2>");
|
||||
bw.write("Changed in " + srcName);
|
||||
bw.write("</h2>");
|
||||
bw.newLine();
|
||||
|
||||
if (changed.size() > 0) {
|
||||
writeResults(changed, bw, false, true);
|
||||
} else {
|
||||
bw.write("<p>(no API changed)</p>");
|
||||
}
|
||||
bw.newLine();
|
||||
|
||||
bw.write("<hr/>");
|
||||
bw.newLine();
|
||||
bw.write("<h2>");
|
||||
bw.write("Added in " + srcName);
|
||||
bw.write("</h2>");
|
||||
bw.newLine();
|
||||
|
||||
if (added.size() > 0) {
|
||||
writeResults(added, bw, false, true);
|
||||
} else {
|
||||
bw.write("<p>(no API added)</p>");
|
||||
}
|
||||
bw.write("<hr/>");
|
||||
bw.newLine();
|
||||
bw.write("<p><i>Contents generated by CheckAPI tool.<br/>Copyright (C) 2004, International Business Machines Corporation, All Rights Reserved.</i></p>");
|
||||
bw.newLine();
|
||||
bw.write("</body>");
|
||||
bw.newLine();
|
||||
bw.write("</html>");
|
||||
bw.newLine();
|
||||
} else {
|
||||
bw.write("Comparing " + srcName + " with " + compareName);
|
||||
bw.newLine();
|
||||
bw.newLine();
|
||||
|
||||
bw.newLine();
|
||||
bw.write("=== Removed from " + compareName + " ===");
|
||||
bw.newLine();
|
||||
if (removed.size() > 0) {
|
||||
writeResults(removed, bw, false, false);
|
||||
} else {
|
||||
bw.write("(no API removed)");
|
||||
}
|
||||
bw.newLine();
|
||||
|
||||
bw.newLine();
|
||||
bw.write("=== Changed in " + srcName + " ===");
|
||||
bw.newLine();
|
||||
if (changed.size() > 0) {
|
||||
writeResults(changed, bw, false, false);
|
||||
} else {
|
||||
bw.write("(no API changed)");
|
||||
}
|
||||
bw.newLine();
|
||||
|
||||
bw.newLine();
|
||||
bw.write("=== Added in " + srcName + " ===");
|
||||
bw.newLine();
|
||||
if (added.size() > 0) {
|
||||
writeResults(added, bw, false, false);
|
||||
} else {
|
||||
bw.write("(no API added)");
|
||||
}
|
||||
bw.newLine();
|
||||
}
|
||||
}
|
||||
|
||||
bw.close();
|
||||
} catch (IOException e) {
|
||||
try { bw.close(); } catch (IOException e2) {}
|
||||
RuntimeException re = new RuntimeException("write error: " + e.getMessage());
|
||||
re.initCause(e);
|
||||
throw re;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void doDocs(ProgramElementDoc[] docs) {
|
||||
if (docs != null && docs.length > 0) {
|
||||
for (int i = 0; i < docs.length; ++i) {
|
||||
doDoc(docs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doDoc(ProgramElementDoc doc) {
|
||||
if (ignore(doc)) return;
|
||||
|
||||
if (doc.isClass() || doc.isInterface()) {
|
||||
ClassDoc cdoc = (ClassDoc)doc;
|
||||
doDocs(cdoc.fields());
|
||||
doDocs(cdoc.constructors());
|
||||
doDocs(cdoc.methods());
|
||||
doDocs(cdoc.innerClasses());
|
||||
}
|
||||
|
||||
Info info = new Info();
|
||||
if (info.read(doc)) {
|
||||
results.add(info);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ignore(ProgramElementDoc doc) {
|
||||
if (doc == null) return true;
|
||||
if (doc.isPrivate() || doc.isPackagePrivate()) return true;
|
||||
if (doc instanceof ConstructorDoc && ((ConstructorDoc)doc).isSynthetic()) return true;
|
||||
if (doc.qualifiedName().indexOf(".misc") != -1) return true;
|
||||
Tag[] tags = doc.tags();
|
||||
for (int i = 0; i < tags.length; ++i) {
|
||||
if (tagKindIndex(tags[i].kind()) == INTERNAL) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void writeResults(Collection c, BufferedWriter w, boolean brief, boolean html) {
|
||||
Iterator iter = c.iterator();
|
||||
String pack = null;
|
||||
String clas = null;
|
||||
while (iter.hasNext()) {
|
||||
Info info = (Info)iter.next();
|
||||
if (brief) {
|
||||
info.write(w, brief);
|
||||
} else {
|
||||
try {
|
||||
String p = info.get(PAK, true);
|
||||
if (!p.equals(pack)) {
|
||||
w.newLine();
|
||||
if (html) {
|
||||
if (clas != null) {
|
||||
w.write("</ul>");
|
||||
w.newLine();
|
||||
}
|
||||
if (pack != null) {
|
||||
w.write("</ul>");
|
||||
w.newLine();
|
||||
}
|
||||
|
||||
w.write("<h3>Package ");
|
||||
w.write(p);
|
||||
w.write("</h3>");
|
||||
w.newLine();
|
||||
w.write("<ul>");
|
||||
w.newLine();
|
||||
} else {
|
||||
w.write("Package ");
|
||||
w.write(p);
|
||||
w.write(':');
|
||||
}
|
||||
w.newLine();
|
||||
w.newLine();
|
||||
|
||||
pack = p;
|
||||
clas = null;
|
||||
}
|
||||
|
||||
if (info.getVal(CAT) != CAT_CLASS) {
|
||||
String name = info.get(CLS, true);
|
||||
if (!name.equals(clas)) {
|
||||
if (html) {
|
||||
if (clas != null) {
|
||||
w.write("</ul>");
|
||||
}
|
||||
w.write("<li>");
|
||||
w.write(name);
|
||||
w.newLine();
|
||||
w.write("<ul>");
|
||||
} else {
|
||||
w.write(name);
|
||||
w.newLine();
|
||||
}
|
||||
clas = name;
|
||||
}
|
||||
w.write(" ");
|
||||
}
|
||||
if (html) {
|
||||
w.write("<li>");
|
||||
info.write(w, brief);
|
||||
w.write("</li>");
|
||||
} else {
|
||||
info.write(w, brief);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
System.err.println("IOException " + e.getMessage() + " writing " + info.get(NAM, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (html) {
|
||||
try {
|
||||
if (clas != null) {
|
||||
w.write("</ul>");
|
||||
w.newLine();
|
||||
}
|
||||
if (pack != null) {
|
||||
w.write("</ul>");
|
||||
w.newLine();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String readToken(BufferedReader r) throws IOException {
|
||||
char[] buf = new char[256];
|
||||
int i = 0;
|
||||
for (; i < buf.length; ++i) {
|
||||
int c = r.read();
|
||||
if (c == -1) {
|
||||
throw new IOException("unexpected EOF");
|
||||
} else if (c == SEP) {
|
||||
break;
|
||||
}
|
||||
buf[i] = (char)c;
|
||||
}
|
||||
if (i == buf.length) {
|
||||
throw new IOException("unterminated token" + new String(buf));
|
||||
}
|
||||
|
||||
return new String(buf, 0, i);
|
||||
}
|
||||
|
||||
private static TreeSet stripAndResort(TreeSet t) {
|
||||
stripClassInfo(t);
|
||||
TreeSet r = new TreeSet(Info.classFirstComparator());
|
||||
r.addAll(t);
|
||||
return r;
|
||||
}
|
||||
private static void stripClassInfo(Collection c) {
|
||||
// c is sorted with class info first
|
||||
Iterator iter = c.iterator();
|
||||
String cname = null;
|
||||
while (iter.hasNext()) {
|
||||
Info info = (Info)iter.next();
|
||||
String cls = info.get(CLS, true);
|
||||
if (cname != null) {
|
||||
if (cname.equals(cls)) {
|
||||
iter.remove();
|
||||
continue;
|
||||
}
|
||||
cname = null;
|
||||
}
|
||||
if (info.getVal(CAT) == CAT_CLASS) {
|
||||
cname = info.get(NAM, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int tagStatus(final Doc doc) {
|
||||
class Result {
|
||||
int res = -1;
|
||||
void set(int val) { if (res != -1) throw new RuntimeException("bad doc: " + doc); res = val; }
|
||||
int get() {
|
||||
if (res == -1) {
|
||||
System.err.println("warning: no tag for " + doc);
|
||||
return 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
Tag[] tags = doc.tags();
|
||||
Result result = new Result();
|
||||
for (int i = 0; i < tags.length; ++i) {
|
||||
Tag tag = tags[i];
|
||||
|
||||
String kind = tag.kind();
|
||||
int ix = tagKindIndex(kind);
|
||||
|
||||
switch (ix) {
|
||||
case INTERNAL:
|
||||
result.set(-2);
|
||||
break;
|
||||
|
||||
case DRAFT:
|
||||
result.set(STA_DRAFT);
|
||||
break;
|
||||
|
||||
case STABLE:
|
||||
result.set(STA_STABLE);
|
||||
break;
|
||||
|
||||
case DEPRECATED:
|
||||
result.set(STA_DEPRECATED);
|
||||
break;
|
||||
|
||||
case OBSOLETE:
|
||||
result.set(STA_OBSOLETE);
|
||||
break;
|
||||
|
||||
case SINCE:
|
||||
case EXCEPTION:
|
||||
case VERSION:
|
||||
case UNKNOWN:
|
||||
case AUTHOR:
|
||||
case SEE:
|
||||
case PARAM:
|
||||
case RETURN:
|
||||
case THROWS:
|
||||
case SERIAL:
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("unknown index " + ix + " for tag: " + kind);
|
||||
}
|
||||
}
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private static final int UNKNOWN = -1;
|
||||
private static final int INTERNAL = 0;
|
||||
private static final int DRAFT = 1;
|
||||
private static final int STABLE = 2;
|
||||
private static final int SINCE = 3;
|
||||
private static final int DEPRECATED = 4;
|
||||
private static final int AUTHOR = 5;
|
||||
private static final int SEE = 6;
|
||||
private static final int VERSION = 7;
|
||||
private static final int PARAM = 8;
|
||||
private static final int RETURN = 9;
|
||||
private static final int THROWS = 10;
|
||||
private static final int OBSOLETE = 11;
|
||||
private static final int EXCEPTION = 12;
|
||||
private static final int SERIAL = 13;
|
||||
|
||||
private static int tagKindIndex(String kind) {
|
||||
final String[] tagKinds = {
|
||||
"@internal", "@draft", "@stable", "@since", "@deprecated", "@author", "@see", "@version",
|
||||
"@param", "@return", "@throws", "@obsolete", "@exception", "@serial"
|
||||
};
|
||||
|
||||
for (int i = 0; i < tagKinds.length; ++i) {
|
||||
if (kind.equals(tagKinds[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue