Merge pull request #52 from kno10/patch-qualify-generics

add -!qualifyGenerics option that strips package names only in generics
This commit is contained in:
Diomidis Spinellis 2018-10-24 12:25:55 +03:00 committed by GitHub
commit b5238b3bdc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 36 deletions

View File

@ -46,6 +46,7 @@ UMLGraph would not be in its current state without their contributions.
<li>Soraya Santana de la Fe</li> <li>Soraya Santana de la Fe</li>
<li>Jonathan R. Santos</li> <li>Jonathan R. Santos</li>
<li>Jan Schl&#252;ter</li> <li>Jan Schl&#252;ter</li>
<li>Erich Schubert</li>
<li>Sebastian Setzer</li> <li>Sebastian Setzer</li>
<li>J&#246;rn Guy S&#252;&#223;</li> <li>J&#246;rn Guy S&#252;&#223;</li>
<li>Andreas Studer</li> <li>Andreas Studer</li>

View File

@ -1,9 +1,10 @@
<?xml version="1.0" ?> <?xml version="1.0" ?>
<notes> <notes>
A number of options contol the operation of UMLGraph A number of options control the operation of UMLGraph
class diagram generator. class diagram generator.
These can be specified on the command line, and most can also These can be specified on the command line, and most can also
be specified through javadoc tags within the diagram, affecting all or some elements. be specified through javadoc <code>@opt</code> tags within the diagram, affecting all or some elements.
Most have a negated version by prefixing an exclamation mark.
<p/> <p/>
<h2>What Gets Drawn</h2> <!-- {{{1 --> <h2>What Gets Drawn</h2> <!-- {{{1 -->
<dl> <dl>
@ -32,6 +33,7 @@ be specified through javadoc tags within the diagram, affecting all or some elem
in the package view (which would by default filter to only include package members).</dd> in the package view (which would by default filter to only include package members).</dd>
<dt>-operations</dt><dd>Show class operations (Java methods) </dd> <dt>-operations</dt><dd>Show class operations (Java methods) </dd>
<dt>-qualify</dt><dd>Produce fully-qualified class names. </dd> <dt>-qualify</dt><dd>Produce fully-qualified class names. </dd>
<dt>-qualifyGenerics</dt><dd>Use fully-qualified class names in Java generics.</dd>
<dt>-types</dt><dd>Add type information to attributes and operations </dd> <dt>-types</dt><dd>Add type information to attributes and operations </dd>
<dt>-view</dt><dd>Specify the fully qualified name of a class that contains <dt>-view</dt><dd>Specify the fully qualified name of a class that contains
a view definition. Only the class diagram specified by this view will be generated. a view definition. Only the class diagram specified by this view will be generated.

View File

@ -7,6 +7,12 @@
<li>The <code>@opt include</code> option can be used to include classes from <li>The <code>@opt include</code> option can be used to include classes from
foreign packages in the package view (unless hidden with <code>@opt hide</code>).</li> foreign packages in the package view (unless hidden with <code>@opt hide</code>).</li>
<li>You can now also use <code>@opt</code> in <code>package-info.java</code>.</li> <li>You can now also use <code>@opt</code> in <code>package-info.java</code>.</li>
<li>Added <code>-qualifyGenerics</code> option to separately control the inclusion of
package names for the class (<code>-qualify</code>) and its generics. In particular
this works well with <code>-qualify -postfixpackage</code> (and <code>-!qualifyGenerics</code>).<br />
To get the old <code>-qualify</code> behavior, you need to add <code>-qualifyGenerics</code>,
the default is off, and it will not inherit from <code>-qualify</code>.</li>
<li>Better handling of complex names with generics and inner classes such as <code>pkg.Outer&lt;T&gt;.Inner</code>.</li>
</ul> </ul>
</dd> </dd>

View File

@ -129,24 +129,34 @@ class ClassGraph {
/** Return the class's name, possibly by stripping the leading path */ /** Return the class's name, possibly by stripping the leading path */
private String qualifiedName(Options opt, String r) { private static String qualifiedName(Options opt, String r) {
if (!opt.showQualified) { // Nothing to do:
// Create readable string by stripping leading path if (opt.showQualified && (opt.showQualifiedGenerics || r.indexOf('<') < 0))
for (;;) { return r;
int dotpos = r.lastIndexOf('.'); StringBuilder buf = new StringBuilder(r.length());
if (dotpos == -1) break; // Work done! int last = 0, depth = 0;
/* boolean strip = !opt.showQualified;
* Change all occurences of for (int i = 0; i < r.length();) {
* "p1.p2.myClass<S extends dummy.Otherclass>" into char c = r.charAt(i++);
* "myClass<S extends Otherclass>" // The last condition prevents losing the dot in A<V>.B
*/ if ((c == '.' || c == '$') && strip && last + 1 < i)
int start = dotpos; last = i; // skip
while (start > 0 && Character.isJavaIdentifierPart(r.charAt(start - 1))) if (Character.isJavaIdentifierPart(c))
start--; continue;
r = r.substring(0, start) + r.substring(dotpos + 1); // Handle nesting of generics
if (c == '<') {
++depth;
strip = !opt.showQualifiedGenerics;
} else if (c == '>' && --depth == 0)
strip = !opt.showQualified;
if (last < i) {
buf.append(r, last, i);
last = i;
} }
} }
return r; if (last < r.length())
buf.append(r, last, r.length());
return buf.toString();
} }
/** /**
@ -263,9 +273,9 @@ class ClassGraph {
} }
/** Print a a basic type t */ /** Print a a basic type t */
private String type(Options opt, Type t) { private String type(Options opt, Type t, boolean generics) {
String type; String type;
if (opt.showQualified) if (generics ? opt.showQualifiedGenerics : opt.showQualified)
type = t.qualifiedTypeName(); type = t.qualifiedTypeName();
else else
type = t.typeName(); type = t.typeName();
@ -281,7 +291,7 @@ class ClassGraph {
Type args[] = t.typeArguments(); Type args[] = t.typeArguments();
tp += "&lt;"; tp += "&lt;";
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
tp += type(opt, args[i]); tp += type(opt, args[i], true);
if (i != args.length - 1) if (i != args.length - 1)
tp += ", "; tp += ", ";
} }
@ -291,11 +301,10 @@ class ClassGraph {
/** Annotate an field/argument with its type t */ /** Annotate an field/argument with its type t */
private String typeAnnotation(Options opt, Type t) { private String typeAnnotation(Options opt, Type t) {
String ta = "";
if (t.typeName().equals("void")) if (t.typeName().equals("void"))
return ta; return "";
ta += " : "; String ta = " : ";
ta += type(opt, t); ta += type(opt, t, false);
ta += t.dimension(); ta += t.dimension();
return ta; return ta;
} }
@ -506,16 +515,12 @@ class ClassGraph {
Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT : Font.CLASS; Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT : Font.CLASS;
String qualifiedName = qualifiedName(opt, r); String qualifiedName = qualifiedName(opt, r);
int startTemplate = qualifiedName.indexOf('<'); int startTemplate = qualifiedName.indexOf('<');
int idx; int idx = qualifiedName.lastIndexOf('.', startTemplate < 0 ? qualifiedName.length() - 1 : startTemplate);
if(startTemplate < 0)
idx = qualifiedName.lastIndexOf('.');
else
idx = qualifiedName.lastIndexOf('.', startTemplate);
if (opt.showComment) if (opt.showComment)
tableLine(Align.LEFT, htmlNewline(escape(c.commentText())), opt, Font.CLASS); tableLine(Align.LEFT, htmlNewline(escape(c.commentText())), opt, Font.CLASS);
else if(opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { else if(opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) {
String packageName = qualifiedName.substring(0, idx); String packageName = qualifiedName.substring(0, idx);
String cn = className.substring(idx + 1); String cn = qualifiedName.substring(idx + 1);
tableLine(Align.CENTER, escape(cn), opt, font); tableLine(Align.CENTER, escape(cn), opt, font);
tableLine(Align.CENTER, packageName, opt, Font.PACKAGE); tableLine(Align.CENTER, packageName, opt, Font.PACKAGE);
} else { } else {
@ -781,14 +786,16 @@ class ClassGraph {
w.print("\t" + info.name + "[label="); w.print("\t" + info.name + "[label=");
externalTableStart(opt, className, classToUrl(className)); externalTableStart(opt, className, classToUrl(className));
innerTableStart(); innerTableStart();
int idx = className.lastIndexOf("."); String qualifiedName = qualifiedName(opt, className);
if(opt.postfixPackage && idx > 0 && idx < (className.length() - 1)) { int startTemplate = qualifiedName.indexOf('<');
String packageName = className.substring(0, idx); int idx = qualifiedName.lastIndexOf('.', startTemplate < 0 ? qualifiedName.length() - 1 : startTemplate);
String cn = className.substring(idx + 1); if(opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) {
String packageName = qualifiedName.substring(0, idx);
String cn = qualifiedName.substring(idx + 1);
tableLine(Align.CENTER, escape(cn), opt, Font.CLASS); tableLine(Align.CENTER, escape(cn), opt, Font.CLASS);
tableLine(Align.CENTER, packageName, opt, Font.PACKAGE); tableLine(Align.CENTER, packageName, opt, Font.PACKAGE);
} else { } else {
tableLine(Align.CENTER, escape(className), opt, Font.CLASS); tableLine(Align.CENTER, escape(qualifiedName), opt, Font.CLASS);
} }
innerTableEnd(); innerTableEnd();
externalTableEnd(); externalTableEnd();

View File

@ -71,6 +71,7 @@ public class Options implements Cloneable, OptionProvider {
List<Pattern> hidePatterns; List<Pattern> hidePatterns;
List<Pattern> includePatterns; List<Pattern> includePatterns;
boolean showQualified; boolean showQualified;
boolean showQualifiedGenerics;
boolean showAttributes; boolean showAttributes;
boolean showEnumerations; boolean showEnumerations;
boolean showEnumConstants; boolean showEnumConstants;
@ -141,6 +142,7 @@ public class Options implements Cloneable, OptionProvider {
Options() { Options() {
showQualified = false; showQualified = false;
showQualifiedGenerics = false;
showAttributes = false; showAttributes = false;
showEnumConstants = false; showEnumConstants = false;
showOperations = false; showOperations = false;
@ -303,6 +305,10 @@ public class Options implements Cloneable, OptionProvider {
showQualified = true; showQualified = true;
} else if (opt[0].equals("-!qualify")) { } else if (opt[0].equals("-!qualify")) {
showQualified = false; showQualified = false;
} else if(opt[0].equals("-qualifyGenerics")) {
showQualifiedGenerics = true;
} else if (opt[0].equals("-!qualifyGenerics")) {
showQualifiedGenerics = false;
} else if(opt[0].equals("-horizontal")) { } else if(opt[0].equals("-horizontal")) {
horizontal = true; horizontal = true;
} else if (opt[0].equals("-!horizontal")) { } else if (opt[0].equals("-!horizontal")) {