de.unkrig.commons.doclet.Docs Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of de-unkrig-commons Show documentation
Show all versions of de-unkrig-commons Show documentation
A versatile Java(TM) library that implements many useful container and utility classes.
/*
* de.unkrig.commons.doclet - Writing doclets made easy
*
* Copyright (c) 2015, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package de.unkrig.commons.doclet;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.ConstructorDoc;
import com.sun.javadoc.Doc;
import com.sun.javadoc.FieldDoc;
import com.sun.javadoc.MemberDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.ProgramElementDoc;
import com.sun.javadoc.RootDoc;
import com.sun.javadoc.Type;
import de.unkrig.commons.io.LineUtil;
import de.unkrig.commons.lang.AssertionUtil;
import de.unkrig.commons.lang.protocol.Longjump;
import de.unkrig.commons.nullanalysis.Nullable;
/**
* Utility methods related to doclet tags.
*/
public final
class Docs {
static { AssertionUtil.enableAssertionsForThisClass(); }
private Docs() {}
/**
* @param from The 'reference' for {@code s}, e.g. the {@link MethodDoc} if this is a method doc comment
* @param to E.g. "pkg.MyClass" or "MyClass#meth" or "MyClass#meth(String)"
* @return The {@link Doc} specified by {@code s}, relative to {@code ref}, or {@code null} iff a doc cannot
* be found
*/
@Nullable public static Doc
findDoc(Doc from, String to, RootDoc rootDoc) throws Longjump {
String where, what;
{
int hashPos = to.indexOf('#');
if (hashPos == -1) {
where = to;
what = null;
} else
if (hashPos == 0) {
where = null;
what = to.substring(1);
} else
{
where = to.substring(0, hashPos);
what = to.substring(hashPos + 1);
}
}
ClassDoc classScope;
if (from instanceof MemberDoc) {
classScope = ((MemberDoc) from).containingClass();
} else
if (from instanceof ClassDoc) {
classScope = (ClassDoc) from;
} else
{
classScope = null;
}
ClassDoc referencedClass = null;
// Current class?
if (where == null) {
if (classScope == null) {
rootDoc.printError(from.position(), "\"" + to + "\": No type declaration in scope");
throw new Longjump();
}
referencedClass = classScope;
} else
if (classScope != null) {
// Find the specified class or interface within the context of this class doc. Search order:
// 1) qualified name,
// 2) nested in this class or interface,
// 3) in this package,
// 4) in the class imports,
// 5) in the package imports
// See http://docs.oracle.com/javase/7/docs/jdk/api/javadoc/doclet/com/sun/javadoc/ClassDoc.html#findClass%28java.lang.String%29 // SUPPRESS CHECKSTYLE LineLength
referencedClass = classScope.findClass(where);
// "ImportedClass.NestedClass" is NOT covered by the previous call.
int firstDot = where.indexOf('.');
if (referencedClass == null && firstDot != -1) {
ClassDoc c = classScope.findClass(where.substring(0, firstDot));
if (c != null) referencedClass = c.findClass(where.substring(firstDot + 1));
}
} else
if (from instanceof PackageDoc) {
// It is not clearly documented, but (hopefully) this method searches the following places:
// 1) qualified name,
// 2) in this package,
// 3) in the class imports,
// 4) in the package imports
// See http://docs.oracle.com/javase/7/docs/jdk/api/javadoc/doclet/com/sun/javadoc/PackageDoc.html#findClass(java.lang.String) // SUPPRESS CHECKSTYLE LineLength
referencedClass = ((PackageDoc) from).findClass(where);
} else
{
// See http://docs.oracle.com/javase/7/docs/jdk/api/javadoc/doclet/com/sun/javadoc/RootDoc.html#classNamed(java.lang.String) // SUPPRESS CHECKSTYLE LineLength
referencedClass = rootDoc.classNamed(where);
}
// Type in same package?
if (referencedClass == null && classScope != null) {
String relativePath = classScope.containingPackage().name() + "/" + where;
for (;;) {
Matcher m = Pattern.compile("\\w+/\\.\\./").matcher(relativePath);
if (!m.find()) break;
relativePath = relativePath.substring(0, m.start()) + relativePath.substring(m.end());
}
referencedClass = rootDoc.classNamed(relativePath);
}
// Package?
if (referencedClass == null) {
PackageDoc referencedPackage = rootDoc.packageNamed(where);
if (referencedPackage != null) {
if (what != null) {
rootDoc.printError(from.position(), "Cannot use '#' on package");
}
}
}
if (referencedClass == null) {
return null;
}
where = referencedClass.qualifiedName();
if (what == null) return referencedClass;
{
// Parse method name and (optional) parameter types.
int op = what.indexOf('(');
String methodName;
List