Browse Source

I just committed the final round of updates to ajdoc needed for 1.2. In a nutshell it's moved forward a ways from the previous ajdoc:

- AJDT integration works
- generates documentation for all the AspectJ modules
- works on 1.3 and 1.4
- comments and Javadoc tags are properly preserved and resolved
 
Note that the hope is still for "declare" documentation to come in the form of a contribution.  

Getting it to work for our tree involved a bunch of bug fixes to deal with things like anonymous types.  To run from our tree in bootstrap mode use something like the attached batch script.  

I had to roll back some of Andy's fix to broken links: getRelativeComponent didn't work properly for internal anchor links (..html#<mumble>).  Andy, could you check this against the current thing against whatever was breaking for you, and ideally add that code patter to CoverageTestCase?

I added -XjavadocsInModel to make the addition of Javadoc strings to the ASM only happen when request it (prevent bloat of the model with strings.  The running time of ajdoc is now dominated by the compilation time.
tags/Root_ajdt_support
mkersten 20 years ago
parent
commit
213f48fcbc

+ 1
- 0
ajdoc/src/org/aspectj/tools/ajdoc/Declaration.java View File

@@ -29,6 +29,7 @@ import org.aspectj.asm.IProgramElement;

/**
* @author Mik Kersten
* @deprecated org.aspectj.asm.IProgramElement should be used instead
*/
public class Declaration implements Serializable {
private int beginLine;

+ 19
- 20
ajdoc/src/org/aspectj/tools/ajdoc/HtmlDecorator.java View File

@@ -40,7 +40,6 @@ class HtmlDecorator {
declIDTable = table;
symbolManager = sm;
for (int i = 0; i < inputFiles.length; i++) {
decorateHTMLFromDecls(symbolManager.getDeclarations(inputFiles[i].getCanonicalPath()),
rootDir.getCanonicalPath() + Config.DIR_SEP_CHAR,
docModifier,
@@ -49,7 +48,7 @@ class HtmlDecorator {
}

static void decorateHTMLFromDecls(Declaration[] decls, String base, String docModifier, boolean exceededNestingLevel) throws IOException {
if ( decls != null ) {
if ( decls != null ) {
for (int i = 0; i < decls.length; i++) {
Declaration decl = decls[i];
decorateHTMLFromDecl(decl, base, docModifier, exceededNestingLevel);
@@ -59,7 +58,7 @@ class HtmlDecorator {

/**
* Before attempting to decorate the HTML file we have to verify that it exists,
* which depends on the documentation visibility specified to javadoc.
* which depends on the documentation visibility specified to c.
*
* Depending on docModifier, can document
* - public: only public
@@ -74,11 +73,11 @@ class HtmlDecorator {
boolean nestedClass = false;
if ( decl.isType() ) {
boolean decorateFile = true;
if ( (docModifier.equals( "private" )) || // everything
(docModifier.equals( "package" ) && decl.getModifiers().indexOf( "private" ) == -1) || // package
(docModifier.equals( "protected" ) && (decl.getModifiers().indexOf( "protected" ) != -1 ||
if ( (docModifier.equals("private")) || // everything
(docModifier.equals("package") && decl.getModifiers().indexOf( "private" ) == -1) || // package
(docModifier.equals("protected") && (decl.getModifiers().indexOf( "protected" ) != -1 ||
decl.getModifiers().indexOf( "public" ) != -1 )) ||
(docModifier.equals( "public" ) && decl.getModifiers().indexOf( "public" ) != -1) ) {
(docModifier.equals("public") && decl.getModifiers().indexOf( "public" ) != -1) ) {
visibleFileList.add(decl.getSignature());
String packageName = decl.getPackageName();
String filename = "";
@@ -164,8 +163,6 @@ class HtmlDecorator {
// addAdviceDocumentation(decl, fileContents, index);
// addPointcutDocumentation(decl, fileContents, index);
addAspectDocumentation(decl, fileContents, index);
}
else {
decorateMemberDocumentation(decl, fileContents, index);
@@ -485,16 +482,16 @@ class HtmlDecorator {
+ currDecl.toLabelString()
+ ".html";
} else {
linkName = packagePath + currDecl.getParent().getName() + "." + currDecl.getName();
linkRef =
getRelativeComponent(packagePath)
+ packagePath
+ currDecl.getParent().getName()
+ ".html"
+ "#"
+ currDecl.toLabelString();
//
linkRef = currDecl.getParent().getName() + ".html" + "#" + currDecl.toLabelString();
// linkRef =
// getRelativeComponent(packagePath)
// + packagePath
// + currDecl.getParent().getName()
// + ".html"
// + "#"
// + currDecl.toLabelString();
//
// XXX: only one level of nested classes
if (currDecl.getParent().getParent().getKind().isType()) {
linkRef = currDecl.getParent().getParent().getName() + "." + linkRef;
@@ -604,11 +601,13 @@ class HtmlDecorator {
* TODO: implement formatting or linking for tags.
*/
static String getFormattedComment(IProgramElement decl) {
String formattedComment = "";

// strip the comment markers
String comment = decl.getFormalComment();
if (comment == null) return "";

String formattedComment = "";
// strip the comment markers
int startIndex = comment.indexOf("/**");
int endIndex = comment.indexOf("*/");
if ( startIndex == -1 ) {

ajdoc/src/org/aspectj/tools/ajdoc/JavadocExecutor.java → ajdoc/src/org/aspectj/tools/ajdoc/JavadocRunner.java View File

@@ -31,7 +31,8 @@ import java.util.*;
/**
* @author Mik Kersten
*/
class JavadocExecutor {
class JavadocRunner {
static boolean has14ToolsAvailable() {
Class jdMainClass = com.sun.tools.javadoc.Main.class;
try {
@@ -43,7 +44,6 @@ class JavadocExecutor {
return true;
}
static void callJavadoc( String[] javadocargs ){
final SecurityManager defaultSecurityManager = System.getSecurityManager();

@@ -78,7 +78,8 @@ class JavadocExecutor {
Class[] paramTypes = new Class[] {String[].class};
executeMethod = jdMainClass.getMethod("execute", paramTypes);
} catch (NoSuchMethodException e) {
throw new UnsupportedOperationException("ajdoc requires a tools library from JDK 1.4 or later.");
com.sun.tools.javadoc.Main.main(javadocargs);
// throw new UnsupportedOperationException("ajdoc requires a tools library from JDK 1.4 or later.");
}
try {
executeMethod.invoke(null, new Object[] {javadocargs});

+ 79
- 51
ajdoc/src/org/aspectj/tools/ajdoc/Main.java View File

@@ -39,13 +39,13 @@ public class Main implements Config {
static Vector ajcOptions = new Vector();

/** All of the files to be processed by ajdoc. */
static Vector filenames = new Vector();
static Vector filenames;

/** List of files to pass to javadoc. */
static Vector fileList= new Vector();
static Vector fileList;

/** List of packages to pass to javadoc. */
static Vector packageList = new Vector();
static Vector packageList;

/** Default to package visiblity. */
static String docModifier = "package";
@@ -59,7 +59,9 @@ public class Main implements Config {
static File rootDir = null;
static Hashtable declIDTable = new Hashtable();
static String docDir = ".";

private static boolean deleteTempFilesOnExit = true;
private static boolean aborted = false;

public static void clearState() {
@@ -80,14 +82,15 @@ public class Main implements Config {

public static void main(String[] args) {
aborted = false;
if (!JavadocExecutor.has14ToolsAvailable()) {
System.err.println("ajdoc requires a JDK 1.4 or later tools jar - exiting");
aborted = true;
return;
}
// System.err.println("> command invoked: " + Arrays.asList(args).toString());
filenames = new Vector();
fileList= new Vector();
packageList = new Vector();
// if (!JavadocRunner.has14ToolsAvailable()) {
// System.err.println("ajdoc requires a JDK 1.4 or later tools jar - exiting");
// aborted = true;
// return;
// }
// STEP 1: parse the command line and do other global setup
sourcepath.addElement("."); // add the current directory to the classapth
@@ -101,7 +104,7 @@ public class Main implements Config {
if ( !(new File( Config.WORKING_DIR ).isDirectory()) ) {
File dir = new File( Config.WORKING_DIR );
dir.mkdir();
dir.deleteOnExit();
if (deleteTempFilesOnExit) dir.deleteOnExit();
}

for (int i = 0; i < filenames.size(); i++) {
@@ -111,7 +114,7 @@ public class Main implements Config {

// PHASE 0: call ajc
ajcOptions.addElement( "-noExit" );
ajcOptions.addElement( "-emacssym" ); // TODO: wrong option to force model gen
ajcOptions.addElement( "-XjavadocsInModel" ); // TODO: wrong option to force model gen
String[] argsToCompiler = new String[ajcOptions.size() + inputFiles.length];
int i = 0;
for ( ; i < ajcOptions.size(); i++ ) {
@@ -123,7 +126,7 @@ public class Main implements Config {
i++;
}

System.out.println( "> calling ajc..." );
System.out.println( "> Calling ajc..." );
CompilerWrapper.main(argsToCompiler);
if (CompilerWrapper.hasErrors()) {
System.out.println(FAIL_MESSAGE);
@@ -145,11 +148,11 @@ public class Main implements Config {
}

// PHASE 1: generate Signature files (Java with DeclIDs and no bodies).
System.out.println( "> building signature files..." );
System.out.println( "> Building signature files..." );
StubFileGenerator.doFiles(declIDTable, symbolManager, inputFiles, signatureFiles);

// PHASE 2: let Javadoc generate HTML (with DeclIDs)
System.out.println( "> calling javadoc..." );
System.out.println( "> Calling javadoc..." );
String[] javadocargs = null;
if ( packageMode ) {
int numExtraArgs = 2;
@@ -188,7 +191,7 @@ public class Main implements Config {
}
}
JavadocExecutor.callJavadoc(javadocargs);
JavadocRunner.callJavadoc(javadocargs);
//for ( int o = 0; o < inputFiles.length; o++ ) {
// System.out.println( "file: " + inputFiles[o] );
//}
@@ -204,7 +207,8 @@ public class Main implements Config {
rootDir,
symbolManager,
inputFiles,
docModifier);
docModifier);
System.out.println( "> Removing generated tags (this may take a while)..." );
removeDeclIDsFromFile("index-all.html");
removeDeclIDsFromFile("serialized-form.html");
for (int p = 0; p < packageList.size(); p++) {
@@ -212,6 +216,7 @@ public class Main implements Config {
Config.DIR_SEP_CHAR +
"package-summary.html" );
}
System.out.println( "> Finished." );
} catch (Throwable e) {
handleInternalError(e);
exit(-2);
@@ -310,7 +315,7 @@ public class Main implements Config {
File packageDir = new File(pathName);
if ( !packageDir.exists() ) {
packageDir.mkdirs();
packageDir.deleteOnExit();
if (deleteTempFilesOnExit) packageDir.deleteOnExit();
}
//verifyPackageDirExists(packageName, null);
packageName = packageName.replace( '.','/' ); // !!!
@@ -321,7 +326,7 @@ public class Main implements Config {
filename = Config.WORKING_DIR + Config.DIR_SEP_CHAR + inputFile.getName();
}
File signatureFile = new File( filename );
signatureFile.deleteOnExit();
if (deleteTempFilesOnExit) signatureFile.deleteOnExit();
return signatureFile;
}

@@ -344,7 +349,7 @@ public class Main implements Config {
File packageDir = new File( filePath );
if ( !packageDir.exists() ) {
packageDir.mkdir();
packageDir.deleteOnExit();
if (deleteTempFilesOnExit) packageDir.deleteOnExit();
}
if ( remainingPkg != "" ) {
verifyPackageDirExists( remainingPkg, currPkgDir );
@@ -361,16 +366,45 @@ public class Main implements Config {
File packageDir = new File( filePath );
if ( !packageDir.exists() ) {
packageDir.mkdir();
packageDir.deleteOnExit();
if (deleteTempFilesOnExit) packageDir.deleteOnExit();
}
}
}

/**
* Can read Eclipse-generated single-line arg
*/
static void parseCommandLine(String[] args) {
if (args.length == 0) {
displayHelpAndExit( null );
} else if (args.length == 1 && args[0].startsWith("@")) {
System.err.println("!!!!!!!!");
String argFile = args[0].substring(1);
System.out.println("> Using arg file: " + argFile);
BufferedReader br;
try {
br = new BufferedReader(new FileReader(argFile));
String line = "";
line = br.readLine();
StringTokenizer st = new StringTokenizer(line, " ");
List argList = new ArrayList();
while(st.hasMoreElements()) {
argList.add((String)st.nextElement());
}
args = new String[argList.size()];
int counter = 0;
for (Iterator it = argList.iterator(); it.hasNext(); ) {
args[counter] = (String)it.next();
counter++;
}
} catch (FileNotFoundException e) {
System.err.println("> could not read arg file: " + argFile);
e.printStackTrace();
} catch (IOException ioe) {
System.err.println("> could not read arg file: " + argFile);
ioe.printStackTrace();
}

}
List vargs = new LinkedList(Arrays.asList(args));

@@ -467,50 +501,44 @@ public class Main implements Config {
else if (arg.startsWith("-") || addNextAsOption) {
if ( arg.equals( "-private" ) ) {
docModifier = "private";
}
else if ( arg.equals( "-package" ) ) {
}else if ( arg.equals( "-package" ) ) {
docModifier = "package";
}
else if ( arg.equals( "-protected" ) ) {
} else if ( arg.equals( "-protected" ) ) {
docModifier = "protected";
}
else if ( arg.equals( "-public" ) ) {
} else if ( arg.equals( "-public" ) ) {
docModifier = "public";
}
else if ( arg.equals( "-verbose" ) ) {
} else if ( arg.equals( "-verbose" ) ) {
verboseMode = true;
}
else if ( arg.equals( "-author" ) ) {
} else if ( arg.equals( "-author" ) ) {
authorStandardDocletSwitch = true;
}
else if ( arg.equals( "-version" ) ) {
} else if ( arg.equals( "-version" ) ) {
versionStandardDocletSwitch = true;
}
else if ( arg.equals( "-v" ) ) {
} else if ( arg.equals( "-v" ) ) {
System.out.println(getVersion());
exit(0);
}
else if ( arg.equals( "-help" ) ) {
} else if ( arg.equals( "-help" ) ) {
displayHelpAndExit( null );
}
else if ( arg.equals( "-doclet" ) || arg.equals( "-docletpath" ) ) {
} else if ( arg.equals( "-doclet" ) || arg.equals( "-docletpath" ) ) {
System.out.println( "The doclet and docletpath options are not currently supported \n" +
"since ajdoc makes assumptions about the behavior of the standard \n" +
"doclet. If you would find this option useful please email us at: \n" +
" \n" +
" asupport@aspectj.org \n" +
" aspectj-dev@eclipse.org \n" +
" \n" );
exit(0);
}
else if ( addNextAsOption ) {
// just pass through
}
else {
} else if (arg.equals("-nonavbar")
|| arg.equals("-noindex")) {
// pass through
//System.err.println("> ignoring unsupported option: " + arg);
} else if ( addNextAsOption ) {
// pass through
} else {
System.err.println("> uncrecognized arg: " + arg);
displayHelpAndExit( null );
}
}
options.addElement(arg);
addNextAsOption = false;
}
}
else {
// check if this is a file or a package
if ( arg.indexOf( ".java" ) == arg.length() - 5 ||
@@ -638,7 +666,7 @@ public class Main implements Config {
"Please copy the following text into an email message and send it,\n" +
"along with any additional information you can add to: \n" +
" \n" +
" support@aspectj.org \n" +
" aspectj-dev@eclipse.org \n" +
" \n";

static public void handleInternalError(Throwable uncaughtThrowable) {

+ 19
- 0
ajdoc/src/org/aspectj/tools/ajdoc/StructureUtil.java View File

@@ -90,4 +90,23 @@ public class StructureUtil {
return sb.toString();
}

public static boolean isAnonymous(IProgramElement node) {
boolean isIntName = true;
try {
Integer.valueOf(node.getName());
} catch (NumberFormatException nfe) {
// !!! using exceptions for logic, fix
isIntName = false;
}
// System.err.println(">>>>>>>> " + node.getName());
return isIntName || node.getName().startsWith("new ");
// return isIntName;
// if (!isIntName) {
//
// return node.getName().startsWith("new ");
// } else {
// return false;
// }
}
}

+ 41
- 27
ajdoc/src/org/aspectj/tools/ajdoc/StubFileGenerator.java View File

@@ -82,54 +82,54 @@ class StubFileGenerator {
String formalComment = addDeclID(classNode, classNode.getFormalComment());
writer.println(formalComment);
String signature = getnSourcesignature(classNode);// StructureUtil.genSignature(classNode);
String signature = genSourceSignature(classNode);// StructureUtil.genSignature(classNode);
writer.println(signature + " {" );
processMembers(classNode.getChildren(), writer, classNode.getKind().equals(IProgramElement.Kind.INTERFACE));
writer.println();
writer.println("}");
}
/**
* Translates "aspect" to "class"
*/
private static String getnSourcesignature(IProgramElement classNode) {
String signature = classNode.getSourceSignature();
int index = signature.indexOf("aspect");
if (index != -1) {
signature = signature.substring(0, index) +
"class " +
signature.substring(index + 6, signature.length());
// System.err.println("######" + signature + ", " + classNode.getName());
if (!StructureUtil.isAnonymous(classNode) && !classNode.getName().equals("<undefined>")) {
writer.println(signature + " {" );
processMembers(classNode.getChildren(), writer, classNode.getKind().equals(IProgramElement.Kind.INTERFACE));
writer.println();
writer.println("}");
}
return signature;
}
}

private static void processMembers(List/*IProgramElement*/ members, PrintWriter writer, boolean declaringTypeIsInterface) throws IOException {
for (Iterator it = members.iterator(); it.hasNext();) {
IProgramElement member = (IProgramElement) it.next();
if (member.getKind().isType()
&& !member.getParent().getKind().equals(IProgramElement.Kind.METHOD)) {
processTypeDeclaration(member, writer);
if (member.getKind().isType()) {
if (!member.getParent().getKind().equals(IProgramElement.Kind.METHOD)
&& !StructureUtil.isAnonymous(member)) {// don't print anonymous types
// System.err.println(">>>>>>>>>>>>>" + member.getName() + "<<<<" + member.getParent());
processTypeDeclaration(member, writer);
}
} else {
String formalComment = addDeclID(member, member.getFormalComment());;
writer.println(formalComment);
String signature = "";
if (!member.getKind().equals(IProgramElement.Kind.POINTCUT)
&& !member.getKind().equals(IProgramElement.Kind.ADVICE) ) {
&& !member.getKind().equals(IProgramElement.Kind.ADVICE)) {
signature = member.getSourceSignature();//StructureUtil.genSignature(member);
}
if (signature != null &&
!member.getKind().isInterTypeMember()) {
if (signature != null &&
signature != "" &&
!member.getKind().isInterTypeMember() &&
!member.getKind().equals(IProgramElement.Kind.INITIALIZER) &&
!StructureUtil.isAnonymous(member)) {
writer.print(signature);
} else {
// System.err.println(">> skipping: " + member.getKind());
}
if (member.getKind().equals(IProgramElement.Kind.METHOD) ||
member.getKind().equals(IProgramElement.Kind.CONSTRUCTOR)) {
writer.println(" { }");
if (member.getParent().getKind().equals(IProgramElement.Kind.INTERFACE) ||
signature.indexOf("abstract ") != -1) {
writer.println(";");
} else {
writer.println(" { }");
}
} else if (member.getKind().equals(IProgramElement.Kind.FIELD)) {
// writer.println(";");
@@ -138,6 +138,20 @@ class StubFileGenerator {
}
}

/**
* Translates "aspect" to "class", as long as its not ".aspect"
*/
private static String genSourceSignature(IProgramElement classNode) {
String signature = classNode.getSourceSignature();
int index = signature.indexOf("aspect");
if (index != -1 && signature.charAt(index-1) != '.') {
signature = signature.substring(0, index) +
"class " +
signature.substring(index + 6, signature.length());
}
return signature;
}
static int nextDeclID = 0;
static String addDeclID(IProgramElement decl, String formalComment) {
String declID = "" + ++nextDeclID;

+ 14
- 8
ajdoc/src/org/aspectj/tools/ajdoc/SymbolManager.java View File

@@ -50,26 +50,32 @@ public class SymbolManager {

file.walk(walker);
// System.err.println("> got: " + nodes);
return (Declaration[])nodes.toArray(new Declaration[nodes.size()]);
// return lookupDeclarations(filename);
}
/**
* Rejects anonymous kinds by checking if their name is an integer
*/
private boolean accept(IProgramElement node) {
return
!node.getKind().equals(IProgramElement.Kind.IMPORT_REFERENCE)
&& !(node.getKind().isType() &&
node.getParent().getKind().equals(IProgramElement.Kind.METHOD));
if (node.getKind().isType()) {
boolean isAnonymous = StructureUtil.isAnonymous(node);
return !node.getParent().getKind().equals(IProgramElement.Kind.METHOD)
&& !isAnonymous;
} else {
return !node.getKind().equals(IProgramElement.Kind.IMPORT_REFERENCE);
}
// && !(node.getKind().isType() &&
// node.getParent().getKind().equals(IProgramElement.Kind.METHOD));
}

private Declaration buildDecl(IProgramElement node) {
String signature = "";
String accessibility = node.getAccessibility().toString();
if (!accessibility.equals("package")) signature = accessibility + " ";
if (!accessibility.equals("package")) signature = accessibility.toString() + " ";
String modifiers = "";
if (!node.getAccessibility().equals(IProgramElement.Accessibility.PACKAGE)) modifiers += node.getAccessibility() + " ";
for (Iterator modIt = node.getModifiers().iterator(); modIt.hasNext(); ) {
modifiers += modIt.next() + " ";
}

+ 12
- 3
ajdoc/testdata/simple/foo/ClassA.java View File

@@ -5,12 +5,21 @@ import java.io.IOException;

/**
* Test class. This is a comment.
*/
*/
public abstract class ClassA implements InterfaceI {
/**
* Mumble field.
*/
public String mumble = "xxx";
public int pubfield;
private int privfield;
private String privfield = "mumble";
public IOException exception = new IOException() {
public String getMumble() { return "mumble"; }
};
/**
* Mumbo. Jumbo.
*

+ 20
- 0
ajdoc/testdata/simple/foo/PlainJava.java View File

@@ -0,0 +1,20 @@

package foo;

import java.io.*;

public class PlainJava {
public int i;
public int getI() {
new FileFilter() {
public boolean accept(File f) {
boolean accept = !(f.isDirectory() || f.getName().endsWith(".class")) ;
return accept;
}
};
return i;
}
}

Loading…
Cancel
Save