@opt tags within the diagram, affecting all or some elements.
+Most have a negated version by prefixing an exclamation mark.
-hide option, but can be used to include classes from foreign packages
+ in the package view (which would by default filter to only include package members).UTF-8 as the output encoding, to have guillemots correctly
appearing in the resulting SVG.
diff --git a/doc/ceg-infer.xml b/doc/ceg-infer.xml index dc8e0e9..379ecf9 100644 --- a/doc/ceg-infer.xml +++ b/doc/ceg-infer.xml @@ -20,8 +20,8 @@ class UMLOptions {} class Person { House[] houses; - List-I've used UMLgraph to generate an E-R diagram out of the DAOs we use in SQO-OSS. I've just annotated a few classes with @assoc tags, removed the super class DAObject from all entities with sed, did some tweaking by hand in the .dot output, et voila, an E-R depicting almost 30 classes in less than 30 minutes! +I've used UMLgraph to generate an E-R diagram out of the DAOs we use in Alitheia Core. I've just annotated a few classes with @assoc tags, removed the super class DAObject from all entities with sed, did some tweaking by hand in the .dot output, et voila, an E-R depicting almost 30 classes in less than 30 minutes!
diff --git a/doc/ceg-mv.xml b/doc/ceg-mv.xml
index 4e59ab6..1da7d42 100644
--- a/doc/ceg-mv.xml
+++ b/doc/ceg-mv.xml
@@ -61,7 +61,7 @@ class DataOperation extends Element {}
@opt include option can be used to include classes from
+foreign packages in the package view (unless hidden with @opt hide).@opt in package-info.java.-qualifyGenerics option to separately control the inclusion of
+package names for the class (-qualify) and its generics. In particular
+this works well with -qualify -postfixpackage (and -!qualifyGenerics).-qualify behavior, you need to add -qualifyGenerics,
+the default is off, and it will not inherit from -qualify.pkg.Outer<T>.Inner.-nodefontabstractname and -nodefontclassabstractname
+with a simple flag -nodefontabstractitalic instead.-hideprivateinner to hide all private inner classes.The packages passed as an
@@ -105,7 +107,6 @@ class ClassGraph {
this.optionProvider = optionProvider;
this.collectionClassDoc = root.classNamed("java.util.Collection");
this.mapClassDoc = root.classNamed("java.util.Map");
- this.contextDoc = contextDoc;
// to gather the packages containing specified classes, loop thru them and gather
// package definitions. User root.specifiedPackages is not safe, since the user
@@ -113,123 +114,60 @@ class ClassGraph {
rootClasses = new HashSet
@@ -458,161 +367,122 @@ class ClassGraph {
* relative links in diagrams for UMLDoc
*/
public String printClass(ClassDoc c, boolean rootClass) {
- ClassInfo ci;
- boolean toPrint;
+ ClassInfo ci = getClassInfo(c, true);
+ if(ci.nodePrinted || ci.hidden)
+ return ci.name;
Options opt = optionProvider.getOptionsFor(c);
-
+ if (c.isEnum() && !opt.showEnumerations)
+ return ci.name;
String className = c.toString();
- if ((ci = getClassInfo(className)) != null)
- toPrint = !ci.nodePrinted;
- else {
- toPrint = true;
- ci = newClassInfo(className, true, hidden(c));
- }
- if (toPrint && !hidden(c) && (!c.isEnum() || opt.showEnumerations)) {
- // Associate classname's alias
- String r = className;
- w.println("\t// " + r);
- // Create label
- w.print("\t" + ci.name + " [label=");
+ // Associate classname's alias
+ w.println(linePrefix + "// " + className);
+ // Create label
+ w.print(linePrefix + ci.name + " [label=");
- boolean showMembers =
+ boolean showMembers =
(opt.showAttributes && c.fields().length > 0) ||
(c.isEnum() && opt.showEnumConstants && c.enumConstants().length > 0) ||
(opt.showOperations && c.methods().length > 0) ||
(opt.showConstructors && c.constructors().length > 0);
-
- externalTableStart(opt, c.qualifiedName(), classToUrl(c, rootClass));
- // Calculate the number of innerTable rows we will emmit
- int nRows = 1;
- if (showMembers) {
- if (opt.showAttributes)
- nRows++;
- else if(!c.isEnum() && (opt.showConstructors || opt.showOperations))
- nRows++;
- if (c.isEnum() && opt.showEnumConstants)
- nRows++;
- if (!c.isEnum() && (opt.showConstructors || opt.showOperations))
- nRows++;
- }
+ final String url = classToUrl(c, rootClass);
+ externalTableStart(opt, c.qualifiedName(), url);
- firstInnerTableStart(opt, nRows);
- if (c.isInterface())
- tableLine(Align.CENTER, guilWrap(opt, "interface"));
- if (c.isEnum())
- tableLine(Align.CENTER, guilWrap(opt, "enumeration"));
- stereotype(opt, c, Align.CENTER);
- Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT : Font.CLASS;
- String qualifiedName = qualifiedName(opt, r);
- int startTemplate = qualifiedName.indexOf('<');
- int idx = 0;
- if(startTemplate < 0)
- idx = qualifiedName.lastIndexOf('.');
- else
- idx = qualifiedName.lastIndexOf('.', startTemplate);
- if (opt.showComment)
- tableLine(Align.LEFT, htmlNewline(escape(c.commentText())), opt, Font.CLASS);
- else if(opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) {
- String packageName = qualifiedName.substring(0, idx);
- String cn = className.substring(idx + 1);
- tableLine(Align.CENTER, escape(cn), opt, font);
- tableLine(Align.CENTER, packageName, opt, Font.PACKAGE);
- } else {
- tableLine(Align.CENTER, escape(qualifiedName), opt, font);
- }
- tagvalue(opt, c);
- firstInnerTableEnd(opt, nRows);
-
- /*
- * Warning: The boolean expressions guarding innerTableStart()
- * in this block, should match those in the code block above
- * marked: "Calculate the number of innerTable rows we will emmit"
- */
- if (showMembers) {
- if (opt.showAttributes) {
- innerTableStart();
- FieldDoc[] fields = c.fields();
- // if there are no fields, print an empty line to generate proper HTML
- if (fields.length == 0)
- tableLine(Align.LEFT, "");
- else
- attributes(opt, c.fields());
- innerTableEnd();
- } else if(!c.isEnum() && (opt.showConstructors || opt.showOperations)) {
- // show an emtpy box if we don't show attributes but
- // we show operations
- innerTableStart();
- tableLine(Align.LEFT, "");
- innerTableEnd();
- }
- if (c.isEnum() && opt.showEnumConstants) {
- innerTableStart();
- FieldDoc[] ecs = c.enumConstants();
- // if there are no constants, print an empty line to generate proper HTML
- if (ecs.length == 0) {
- tableLine(Align.LEFT, "");
- } else {
- for (FieldDoc fd : c.enumConstants()) {
- tableLine(Align.LEFT, fd.name());
- }
- }
- innerTableEnd();
- }
- if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) {
- innerTableStart();
- boolean printedLines = false;
- if (opt.showConstructors)
- printedLines |= operations(opt, c.constructors());
- if (opt.showOperations)
- printedLines |= operations(opt, c.methods());
-
- if (!printedLines)
- // if there are no operations nor constructors,
- // print an empty line to generate proper HTML
- tableLine(Align.LEFT, "");
-
- innerTableEnd();
- }
- }
- externalTableEnd();
- w.print(", URL=\"" + classToUrl(c, rootClass) + "\"");
- nodeProperties(opt);
-
- // If needed, add a note for this node
- int ni = 0;
- for (Tag t : c.tags("note")) {
- String noteName = "n" + ni + "c" + ci.name;
- w.print("\t// Note annotation\n");
- w.print("\t" + noteName + " [label=");
- externalTableStart(UmlGraph.getCommentOptions(), c.qualifiedName(), classToUrl(c, rootClass));
- innerTableStart();
- tableLine(Align.LEFT, htmlNewline(escape(t.text())), UmlGraph.getCommentOptions(), Font.CLASS);
- innerTableEnd();
- externalTableEnd();
- nodeProperties(UmlGraph.getCommentOptions());
- w.print("\t" + noteName + " -> " + relationNode(c) + "[arrowhead=none];\n");
- ni++;
- }
- ci.nodePrinted = true;
+ firstInnerTableStart(opt);
+ if (c.isInterface())
+ tableLine(Align.CENTER, guilWrap(opt, "interface"));
+ if (c.isEnum())
+ tableLine(Align.CENTER, guilWrap(opt, "enumeration"));
+ stereotype(opt, c, Align.CENTER);
+ Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT : Font.CLASS;
+ String qualifiedName = qualifiedName(opt, className);
+ int idx = splitPackageClass(qualifiedName);
+ if (opt.showComment)
+ tableLine(Align.LEFT, Font.CLASS.wrap(opt, htmlNewline(escape(c.commentText()))));
+ else if (opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) {
+ String packageName = qualifiedName.substring(0, idx);
+ String cn = qualifiedName.substring(idx + 1);
+ tableLine(Align.CENTER, font.wrap(opt, escape(cn)));
+ tableLine(Align.CENTER, Font.PACKAGE.wrap(opt, packageName));
+ } else {
+ tableLine(Align.CENTER, font.wrap(opt, escape(qualifiedName)));
}
- return ci.name;
- }
+ tagvalue(opt, c);
+ firstInnerTableEnd(opt);
- private String getNodeName(ClassDoc c) {
- String className = c.toString();
- ClassInfo ci = getClassInfo(className);
- if (ci == null)
- ci = newClassInfo(className, false, hidden(c));
- return ci.name;
- }
-
- /** Return a class's internal name */
- private String getNodeName(String c) {
- ClassInfo ci = getClassInfo(c);
+ /*
+ * Warning: The boolean expressions guarding innerTableStart()
+ * in this block, should match those in the code block above
+ * marked: "Calculate the number of innerTable rows we will emmit"
+ */
+ if (showMembers) {
+ if (opt.showAttributes) {
+ innerTableStart();
+ FieldDoc[] fields = c.fields();
+ // if there are no fields, print an empty line to generate proper HTML
+ if (fields.length == 0)
+ tableLine(Align.LEFT, "");
+ else
+ attributes(opt, c.fields());
+ innerTableEnd();
+ } else if(!c.isEnum() && (opt.showConstructors || opt.showOperations)) {
+ // show an emtpy box if we don't show attributes but
+ // we show operations
+ innerTableStart();
+ tableLine(Align.LEFT, "");
+ innerTableEnd();
+ }
+ if (c.isEnum() && opt.showEnumConstants) {
+ innerTableStart();
+ FieldDoc[] ecs = c.enumConstants();
+ // if there are no constants, print an empty line to generate proper HTML
+ if (ecs.length == 0) {
+ tableLine(Align.LEFT, "");
+ } else {
+ for (FieldDoc fd : c.enumConstants()) {
+ tableLine(Align.LEFT, fd.name());
+ }
+ }
+ innerTableEnd();
+ }
+ if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) {
+ innerTableStart();
+ boolean printedLines = false;
+ if (opt.showConstructors)
+ printedLines |= operations(opt, c.constructors());
+ if (opt.showOperations)
+ printedLines |= operations(opt, c.methods());
- if (ci == null)
- ci = newClassInfo(c, false, false);
+ if (!printedLines)
+ // if there are no operations nor constructors,
+ // print an empty line to generate proper HTML
+ tableLine(Align.LEFT, "");
+
+ innerTableEnd();
+ }
+ }
+ externalTableEnd();
+ if (url != null)
+ w.print(", URL=\"" + url + "\"");
+ nodeProperties(opt);
+
+ // If needed, add a note for this node
+ int ni = 0;
+ for (Tag t : c.tags("note")) {
+ String noteName = "n" + ni + "c" + ci.name;
+ w.print(linePrefix + "// Note annotation\n");
+ w.print(linePrefix + noteName + " [label=");
+ externalTableStart(UmlGraph.getCommentOptions(), c.qualifiedName(), url);
+ innerTableStart();
+ tableLine(Align.LEFT, Font.CLASS.wrap(UmlGraph.getCommentOptions(), htmlNewline(escape(t.text()))));
+ innerTableEnd();
+ externalTableEnd();
+ nodeProperties(UmlGraph.getCommentOptions());
+ ClassInfo ci1 = getClassInfo(c, true);
+ w.print(linePrefix + noteName + " -> " + ci1.name + "[arrowhead=none];\n");
+ ni++;
+ }
+ ci.nodePrinted = true;
return ci.name;
}
@@ -623,16 +493,15 @@ class ClassGraph {
* @param edgetype the dot edge specification
*/
private void allRelation(Options opt, RelationType rt, ClassDoc from) {
- String tagname = rt.toString().toLowerCase();
+ String tagname = rt.lower;
for (Tag tag : from.tags(tagname)) {
- String t[] = StringUtil.tokenize(tag.text()); // l-src label l-dst target
+ String t[] = tokenize(tag.text()); // l-src label l-dst target
+ t = t.length == 1 ? new String[] { "-", "-", "-", t[0] } : t; // Shorthand
if (t.length != 4) {
System.err.println("Error in " + from + "\n" + tagname + " expects four fields (l-src label l-dst target): " + tag.text());
return;
}
ClassDoc to = from.findClass(t[3]);
-
-
if (to != null) {
if(hidden(to))
continue;
@@ -654,27 +523,39 @@ class ClassGraph {
*/
private void relation(Options opt, RelationType rt, ClassDoc from, String fromName,
ClassDoc to, String toName, String tailLabel, String label, String headLabel) {
+ tailLabel = (tailLabel != null && !tailLabel.isEmpty()) ? ",taillabel=\"" + tailLabel + "\"" : "";
+ label = (label != null && !label.isEmpty()) ? ",label=\"" + guillemize(opt, label) + "\"" : "";
+ headLabel = (headLabel != null && !headLabel.isEmpty()) ? ",headlabel=\"" + headLabel + "\"" : "";
+ boolean unLabeled = tailLabel.isEmpty() && label.isEmpty() && headLabel.isEmpty();
+ ClassInfo ci1 = getClassInfo(from, fromName, true), ci2 = getClassInfo(to, toName, true);
+ String n1 = ci1.name, n2 = ci2.name;
+ // For ranking we need to output extends/implements backwards.
+ if (rt.backorder) { // Swap:
+ n1 = ci2.name;
+ n2 = ci1.name;
+ String tmp = tailLabel;
+ tailLabel = headLabel;
+ headLabel = tmp;
+ }
+ Options def = opt.getGlobalOptions();
// print relation
- String edgetype = associationMap.get(rt);
- w.println("\t// " + fromName + " " + rt.toString() + " " + toName);
- w.println("\t" + relationNode(from, fromName) + " -> " + relationNode(to, toName) + " [" +
- "taillabel=\"" + tailLabel + "\", " +
- ((label == null || label.isEmpty()) ? "label=\"\", " : "label=\"" + guillemize(opt, label) + "\", ") +
- "headlabel=\"" + headLabel + "\", " +
- "fontname=\"" + opt.edgeFontName + "\", " +
- "fontcolor=\"" + opt.edgeFontColor + "\", " +
- "fontsize=" + opt.edgeFontSize + ", " +
- "color=\"" + opt.edgeColor + "\", " +
- edgetype + "];"
- );
+ w.println(linePrefix + "// " + fromName + " " + rt.lower + " " + toName);
+ w.println(linePrefix + n1 + " -> " + n2 + " [" + rt.style +
+ (opt.edgeColor != def.edgeColor ? ",color=\"" + opt.edgeColor + "\"" : "") +
+ (unLabeled ? "" :
+ (opt.edgeFontName != def.edgeFontName ? ",fontname=\"" + opt.edgeFontName + "\"" : "") +
+ (opt.edgeFontColor != def.edgeFontColor ? ",fontcolor=\"" + opt.edgeFontColor + "\"" : "") +
+ (opt.edgeFontSize != def.edgeFontSize ? ",fontsize=" + fmt(opt.edgeFontSize) : "")) +
+ tailLabel + label + headLabel +
+ "];");
// update relation info
RelationDirection d = RelationDirection.BOTH;
if(rt == RelationType.NAVASSOC || rt == RelationType.DEPEND)
d = RelationDirection.OUT;
- getClassInfo(fromName).addRelation(toName, rt, d);
- getClassInfo(toName).addRelation(fromName, rt, d.inverse());
+ ci1.addRelation(toName, rt, d);
+ ci2.addRelation(fromName, rt, d.inverse());
}
/**
@@ -688,79 +569,33 @@ class ClassGraph {
}
- /** Return the full name of a relation's node.
- * This may involve appending the port :p for the standard nodes
- * whose outline is rendered through an inner table.
- */
- private String relationNode(ClassDoc c) {
- Options opt = optionProvider.getOptionsFor(c);
- String name = getNodeName(c);
- return name + opt.shape.landingPort();
- }
-
- /** Return the full name of a relation's node c.
- * This may involve appending the port :p for the standard nodes
- * whose outline is rendered through an inner table.
- * @param c the node's class (may be null)
- * @param cName the node's class name
- */
- private String relationNode(ClassDoc c, String cName) {
- Options opt;
- if (c == null)
- opt = optionProvider.getOptionsFor(cName);
- else
- opt = optionProvider.getOptionsFor(c);
- String name = getNodeName(cName);
- return name + opt.shape.landingPort();
- }
-
/** Print a class's relations */
public void printRelations(ClassDoc c) {
Options opt = optionProvider.getOptionsFor(c);
if (hidden(c) || c.name().equals("")) // avoid phantom classes, they may pop up when the source uses annotations
return;
- String className = c.toString();
-
// Print generalization (through the Java superclass)
Type s = c.superclassType();
- if (s != null &&
- !s.toString().equals("java.lang.Object") &&
- !c.isEnum() &&
- !hidden(s.asClassDoc())) {
- ClassDoc sc = s.asClassDoc();
- w.println("\t//" + c + " extends " + s + "\n" +
- "\t" + relationNode(sc) + " -> " + relationNode(c) + " [dir=back,arrowtail=empty];");
- getClassInfo(className).addRelation(sc.toString(), RelationType.EXTENDS, RelationDirection.OUT);
- getClassInfo(sc.toString()).addRelation(className, RelationType.EXTENDS, RelationDirection.IN);
- }
-
+ ClassDoc sc = s != null && !s.qualifiedTypeName().equals(Object.class.getName()) ? s.asClassDoc() : null;
+ if (sc != null && !c.isEnum() && !hidden(sc))
+ relation(opt, RelationType.EXTENDS, c, sc, null, null, null);
// Print generalizations (through @extends tags)
for (Tag tag : c.tags("extends"))
- if (!hidden(tag.text())) {
- ClassDoc from = c.findClass(tag.text());
- w.println("\t//" + c + " extends " + tag.text() + "\n" +
- "\t" + relationNode(from, tag.text()) + " -> " + relationNode(c) + " [dir=back,arrowtail=empty];");
- getClassInfo(className).addRelation(tag.text(), RelationType.EXTENDS, RelationDirection.OUT);
- getClassInfo(tag.text()).addRelation(className, RelationType.EXTENDS, RelationDirection.IN);
- }
+ if (!hidden(tag.text()))
+ relation(opt, RelationType.EXTENDS, c, c.findClass(tag.text()), null, null, null);
// Print realizations (Java interfaces)
for (Type iface : c.interfaceTypes()) {
ClassDoc ic = iface.asClassDoc();
- if (!hidden(ic)) {
- w.println("\t//" + c + " implements " + ic + "\n\t" +
- relationNode(ic) + " -> " + relationNode(c) + " [dir=back,arrowtail=empty,style=dashed];"
- );
- getClassInfo(className).addRelation(ic.toString(), RelationType.IMPLEMENTS, RelationDirection.OUT);
- getClassInfo(ic.toString()).addRelation(className, RelationType.IMPLEMENTS, RelationDirection.IN);
- }
+ if (!hidden(ic))
+ relation(opt, RelationType.IMPLEMENTS, c, ic, null, null, null);
}
// Print other associations
- allRelation(opt, RelationType.ASSOC, c);
- allRelation(opt, RelationType.NAVASSOC, c);
- allRelation(opt, RelationType.HAS, c);
- allRelation(opt, RelationType.NAVHAS, c);
allRelation(opt, RelationType.COMPOSED, c);
allRelation(opt, RelationType.NAVCOMPOSED, c);
+ allRelation(opt, RelationType.HAS, c);
+ allRelation(opt, RelationType.NAVHAS, c);
+ allRelation(opt, RelationType.ASSOC, c);
+ allRelation(opt, RelationType.NAVASSOC, c);
allRelation(opt, RelationType.DEPEND, c);
}
@@ -768,80 +603,69 @@ class ClassGraph {
public void printExtraClasses(RootDoc root) {
Set" into
- * "myClass"
- */
- int start = dotpos;
- while (start > 0 && Character.isJavaIdentifierPart(r.charAt(start - 1)))
- start--;
- r = r.substring(0, start) + r.substring(dotpos + 1);
+ private static String qualifiedName(Options opt, String r) {
+ if (opt.hideGenerics)
+ r = removeTemplate(r);
+ // Fast path - nothing to do:
+ if (opt.showQualified && (opt.showQualifiedGenerics || r.indexOf('<') < 0))
+ return r;
+ StringBuilder buf = new StringBuilder(r.length());
+ qualifiedNameInner(opt, r, buf, 0, !opt.showQualified);
+ return buf.toString();
+ }
+
+ private static int qualifiedNameInner(Options opt, String r, StringBuilder buf, int last, boolean strip) {
+ strip = strip && last < r.length() && Character.isLowerCase(r.charAt(last));
+ for (int i = last; i < r.length(); i++) {
+ char c = r.charAt(i);
+ if (c == '.' || c == '$') {
+ if (strip)
+ last = i + 1; // skip dot
+ strip = strip && last < r.length() && Character.isLowerCase(r.charAt(last));
+ continue;
}
+ if (Character.isJavaIdentifierPart(c))
+ continue;
+ buf.append(r, last, i);
+ last = i;
+ // Handle nesting of generics
+ if (c == '<') {
+ buf.append('<');
+ i = last = qualifiedNameInner(opt, r, buf, ++last, !opt.showQualifiedGenerics);
+ buf.append('>');
+ } else if (c == '>')
+ return i + 1;
}
- return r;
- }
-
- /**
- * Escape <, >, and & characters in the string with
- * the corresponding HTML entity code.
- */
- private String escape(String s) {
- final Pattern toEscape = Pattern.compile("[&<>]");
-
- if (toEscape.matcher(s).find()) {
- StringBuffer sb = new StringBuffer(s);
- for (int i = 0; i < sb.length();) {
- switch (sb.charAt(i)) {
- case '&':
- sb.replace(i, i + 1, "&");
- i += "&".length();
- break;
- case '<':
- sb.replace(i, i + 1, "<");
- i += "<".length();
- break;
- case '>':
- sb.replace(i, i + 1, ">");
- i += ">".length();
- break;
- default:
- i++;
- }
- }
- return sb.toString();
- } else
- return s;
- }
-
- /**
- * Convert embedded newlines into HTML line breaks
- */
- private String htmlNewline(String s) {
- if (s.indexOf('\n') == -1)
- return (s);
-
- StringBuffer sb = new StringBuffer(s);
- for (int i = 0; i < sb.length();) {
- if (sb.charAt(i) == '\n') {
- sb.replace(i, i + 1, "
");
- i += "
".length();
- } else
- i++;
- }
- return sb.toString();
- }
-
-
- /**
- * Convert < and > characters in the string to the respective guillemot characters.
- */
- private String guillemize(Options opt, String s) {
- StringBuffer r = new StringBuffer(s);
- for (int i = 0; i < r.length();)
- switch (r.charAt(i)) {
- case '<':
- r.replace(i, i + 1, opt.guilOpen);
- i += opt.guilOpen.length();
- break;
- case '>':
- r.replace(i, i + 1, opt.guilClose);
- i += opt.guilClose.length();
- break;
- default:
- i++;
- break;
- }
- return r.toString();
- }
-
- /**
- * Wraps a string in Guillemot (or an ASCII substitute) characters.
- *
- * @param str the String to be wrapped.
- * @return the wrapped String.
- */
- private String guilWrap(Options opt, String str) {
- return opt.guilOpen + str + opt.guilClose;
+ buf.append(r, last, r.length());
+ return r.length();
}
/**
@@ -237,67 +175,46 @@ class ClassGraph {
* any stereotypes
*/
private String visibility(Options opt, ProgramElementDoc e) {
- if (!opt.showVisibility)
- return " ";
- if (e.isPrivate())
- return "- ";
- else if (e.isPublic())
- return "+ ";
- else if (e.isProtected())
- return "# ";
- else if (e.isPackagePrivate())
- return "~ ";
- else
- return " ";
+ return opt.showVisibility ? Visibility.get(e).symbol : " ";
}
/** Print the method parameter p */
private String parameter(Options opt, Parameter p[]) {
- String par = "";
+ StringBuilder par = new StringBuilder(1000);
for (int i = 0; i < p.length; i++) {
- par += p[i].name() + typeAnnotation(opt, p[i].type());
+ par.append(p[i].name() + typeAnnotation(opt, p[i].type()));
if (i + 1 < p.length)
- par += ", ";
+ par.append(", ");
}
- return par;
+ return par.toString();
}
/** Print a a basic type t */
- private String type(Options opt, Type t) {
- String type = "";
- if (opt.showQualified)
- type = t.qualifiedTypeName();
- else
- type = t.typeName();
- type += typeParameters(opt, t.asParameterizedType());
- return type;
+ private String type(Options opt, Type t, boolean generics) {
+ return ((generics ? opt.showQualifiedGenerics : opt.showQualified) ? //
+ t.qualifiedTypeName() : t.typeName()) //
+ + (opt.hideGenerics ? "" : typeParameters(opt, t.asParameterizedType()));
}
/** Print the parameters of the parameterized type t */
private String typeParameters(Options opt, ParameterizedType t) {
- String tp = "";
if (t == null)
- return tp;
+ return "";
+ StringBuffer tp = new StringBuffer(1000).append("<");
Type args[] = t.typeArguments();
- tp += "<";
for (int i = 0; i < args.length; i++) {
- tp += type(opt, args[i]);
+ tp.append(type(opt, args[i], true));
if (i != args.length - 1)
- tp += ", ";
+ tp.append(", ");
}
- tp += ">";
- return tp;
+ return tp.append(">").toString();
}
/** Annotate an field/argument with its type t */
private String typeAnnotation(Options opt, Type t) {
- String ta = "";
if (t.typeName().equals("void"))
- return ta;
- ta += " : ";
- ta += type(opt, t);
- ta += t.dimension();
- return ta;
+ return "";
+ return " : " + type(opt, t, false) + t.dimension();
}
/** Print the class's attributes fd */
@@ -305,9 +222,8 @@ class ClassGraph {
for (FieldDoc f : fd) {
if (hidden(f))
continue;
- String att = "";
stereotype(opt, f, Align.LEFT);
- att = visibility(opt, f) + f.name();
+ String att = visibility(opt, f) + f.name();
if (opt.showType)
att += typeAnnotation(opt, f.type());
tableLine(Align.LEFT, att);
@@ -328,15 +244,11 @@ class ClassGraph {
if (hidden(cd))
continue;
stereotype(opt, cd, Align.LEFT);
- String cs = visibility(opt, cd) + cd.name();
- if (opt.showType) {
- cs += "(" + parameter(opt, cd.parameters()) + ")";
- } else {
- cs += "()";
- }
+ String cs = visibility(opt, cd) + cd.name() //
+ + (opt.showType ? "(" + parameter(opt, cd.parameters()) + ")" : "()");
tableLine(Align.LEFT, cs);
- printed = true;
tagvalue(opt, cd);
+ printed = true;
}
return printed;
}
@@ -351,14 +263,10 @@ class ClassGraph {
if (md.name().equals("