aboutsummaryrefslogtreecommitdiffstats
path: root/ajdoc/src
diff options
context:
space:
mode:
authormkersten <mkersten>2004-02-18 16:12:54 +0000
committermkersten <mkersten>2004-02-18 16:12:54 +0000
commit83198dbf96b93058941fe3d2f054d7cc42848172 (patch)
treeb271f8da64231abbf1268d6ea99241b925c3ef0d /ajdoc/src
parent0d5096c9b943aa294b663890bd90423a8becfef2 (diff)
downloadaspectj-83198dbf96b93058941fe3d2f054d7cc42848172.tar.gz
aspectj-83198dbf96b93058941fe3d2f054d7cc42848172.zip
Lightweight ajdoc prototype.
Diffstat (limited to 'ajdoc/src')
-rw-r--r--ajdoc/src/org/aspectj/tools/ajdoc/Config.java43
-rw-r--r--ajdoc/src/org/aspectj/tools/ajdoc/Declaration.java293
-rw-r--r--ajdoc/src/org/aspectj/tools/ajdoc/Main.java700
-rw-r--r--ajdoc/src/org/aspectj/tools/ajdoc/Phase1.java229
-rw-r--r--ajdoc/src/org/aspectj/tools/ajdoc/Phase2.java66
-rw-r--r--ajdoc/src/org/aspectj/tools/ajdoc/Phase3.java731
-rw-r--r--ajdoc/src/org/aspectj/tools/ajdoc/SourceLine.java54
-rw-r--r--ajdoc/src/org/aspectj/tools/ajdoc/SymbolManager.java390
8 files changed, 2506 insertions, 0 deletions
diff --git a/ajdoc/src/org/aspectj/tools/ajdoc/Config.java b/ajdoc/src/org/aspectj/tools/ajdoc/Config.java
new file mode 100644
index 000000000..4224ed783
--- /dev/null
+++ b/ajdoc/src/org/aspectj/tools/ajdoc/Config.java
@@ -0,0 +1,43 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * Mik Kersten port to AspectJ 1.1+ code base
+ * ******************************************************************/
+
+package org.aspectj.tools.ajdoc;
+
+interface Config {
+ static final String DECL_ID_STRING = "__AJDECLID:";
+ static final String DECL_ID_TERMINATOR = ":__";
+ static final String WORKING_DIR = "ajdocworkingdir";
+ static final String DIR_SEP_CHAR = "/";
+ static final String VERSION = "ajdoc version 0.8beta4";
+ static final String USAGE =
+ "Usage: ajdoc <options> <source files>\n" +
+ "\n" +
+ "where <options> includes:\n"+
+ " -public Show only public classes and members\n"+
+ " -protected Show protected/public classes and members\n"+
+ " -package Show package/protected/public classes and members\n" + // default
+ " -private Show all classes and members\n" +
+ " -help Display command line options\n" +
+ " -sourcepath <pathlist> Specify where to find source files\n" +
+ " -classpath <pathlist> Specify where to find user class files\n" +
+ " -bootclasspath <pathlist> Override location of class files loaded\n" +
+ " -d <directory> Destination directory for output files\n" +
+ " -argfile <file> the file is a line-delimted list of arguments" +
+ " -verbose Output messages about what Javadoc is doing\n" +
+ " -v Print out the version of ajdoc" +
+ "\n"+
+ "If an argument is of the form @<filename>, the file will be interpreted as\n"+
+ "a line delimited set of arguments to insert into the argument list.";
+
+}
diff --git a/ajdoc/src/org/aspectj/tools/ajdoc/Declaration.java b/ajdoc/src/org/aspectj/tools/ajdoc/Declaration.java
new file mode 100644
index 000000000..a68ad3be7
--- /dev/null
+++ b/ajdoc/src/org/aspectj/tools/ajdoc/Declaration.java
@@ -0,0 +1,293 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * Mik Kersten port to AspectJ 1.1+ code base
+ * ******************************************************************/
+
+package org.aspectj.tools.ajdoc;
+import java.util.Enumeration;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+
+import java.util.*;
+
+// Make sure that references to Vector use the standard version
+// This lets us generate serialized files which interoperate with other code better
+import java.util.Vector;
+
+public class Declaration implements Serializable {
+ private int beginLine;
+ private int endLine;
+ private int beginColumn;
+ private int endColumn;
+
+ private String modifiers;
+ private String fullSignature;
+ private String signature;
+ private String crosscutDesignator;
+
+ private String packageName;
+
+ private String kind;
+ private String declaringType;
+
+ private String filename;
+ private String formalComment;
+
+ private Declaration[] declarations;
+
+ private Handle crosscutDeclarationHandle;
+ private Handle[] pointedToByHandles;
+ private Handle[] pointsToHandles;
+
+ transient private Declaration crosscutDeclaration;
+ transient private Declaration[] pointedToBy = null;
+ transient private Declaration[] pointsTo = null;
+
+ private Declaration parentDeclaration = null;
+
+ public Declaration(int beginLine, int endLine, int beginColumn, int endColumn,
+ String modifiers, String signature, String fullSignature,
+ String crosscutDesignator,
+ String declaringType, String kind,
+ String filename, String formalComment,
+ String packageName)
+ {
+ this.beginLine = beginLine;
+ this.endLine = endLine;
+ this.beginColumn = beginColumn;
+ this.endColumn = endColumn;
+
+ this.modifiers = modifiers;
+ this.signature = signature;
+ this.fullSignature = fullSignature;
+
+ this.crosscutDesignator = crosscutDesignator;
+
+ this.declaringType = declaringType;
+ this.kind = kind;
+
+ this.filename = filename;
+ this.formalComment = formalComment;
+
+ this.packageName = packageName;
+
+ this.pointedToByHandles = new Handle[0];
+ this.pointsToHandles = new Handle[0];
+ //???
+ this.declarations = new Declaration[0];
+ }
+
+ public int getBeginLine() { return beginLine; }
+ public int getEndLine() { return endLine; }
+ public int getBeginColumn() { return beginColumn; }
+ public int getEndColumn() { return endColumn; }
+
+ public String getModifiers() { return modifiers; }
+ public String getFullSignature() { return fullSignature; }
+ public String getSignature() { return signature; }
+
+ public String getPackageName() { return packageName; }
+
+ public String getCrosscutDesignator() { return crosscutDesignator; }
+
+ public Declaration getParentDeclaration() { return parentDeclaration; }
+
+ public Declaration getCrosscutDeclaration() {
+ if (crosscutDeclaration == null && crosscutDeclarationHandle != null) {
+ crosscutDeclaration = crosscutDeclarationHandle.resolve();
+ }
+ return crosscutDeclaration;
+ }
+
+ public void setCrosscutDeclaration(Declaration _crosscutDeclaration) {
+ crosscutDeclaration = _crosscutDeclaration;
+ }
+
+ public String getDeclaringType() { return declaringType; }
+ public String getKind() {
+ if (kind.startsWith("introduced-")) {
+ return kind.substring(11);
+ } else {
+ return kind;
+ }
+ }
+
+ public String getFilename() { return filename; }
+ public String getFormalComment() { return formalComment; }
+
+ public Declaration[] getDeclarations() {
+ return declarations;
+ }
+ public void setDeclarations(Declaration[] decs) {
+ declarations = decs;
+ if (decs != null) {
+ for (int i = 0; i < decs.length; i++) {
+ decs[i].parentDeclaration = this;
+ }
+ }
+ }
+ public void setPointedToBy(Declaration[] decs) { pointedToBy = decs; }
+ public void setPointsTo(Declaration[] decs) { pointsTo = decs; }
+
+
+ public Declaration[] getPointedToBy() {
+ if (pointedToBy == null) {
+ pointedToBy = resolveHandles(pointedToByHandles);
+ }
+ return pointedToBy; //.elements();
+ }
+
+ public Declaration[] getPointsTo() {
+ if (pointsTo == null) {
+ pointsTo = resolveHandles(pointsToHandles);
+ }
+ return pointsTo; //.elements();
+ }
+
+ private Declaration[] filterTypes(Declaration[] a_decs) {
+ List decs = new LinkedList(Arrays.asList(a_decs));
+ for(Iterator i = decs.iterator(); i.hasNext(); ) {
+ Declaration dec = (Declaration)i.next();
+ if (!dec.isType()) i.remove();
+ }
+ return (Declaration[])decs.toArray(new Declaration[decs.size()]);
+ }
+
+
+ public Declaration[] getTargets() {
+ Declaration[] pointsTo = getPointsTo();
+
+ if (kind.equals("advice")) {
+ return pointsTo;
+ } else if (kind.equals("introduction")) {
+ return filterTypes(pointsTo);
+ } else {
+ return new Declaration[0];
+ }
+ }
+
+ // Handles are used to deal with dependencies between Declarations in different files
+ private Handle getHandle() {
+ return new Handle(filename, beginLine, beginColumn);
+ }
+
+ private Declaration[] resolveHandles(Handle[] handles) {
+ Declaration[] declarations = new Declaration[handles.length];
+ int missed = 0;
+ for(int i=0; i<handles.length; i++) {
+ //if (handles[i] == null) continue;
+ declarations[i] = handles[i].resolve();
+ if (declarations[i] == null) missed++;
+ }
+ if (missed > 0) {
+ Declaration[] decs = new Declaration[declarations.length - missed];
+ for (int i=0, j=0; i < declarations.length; i++) {
+ if (declarations[i] != null) decs[j++] = declarations[i];
+ }
+ declarations = decs;
+ }
+ return declarations;
+ }
+
+ private Handle[] getHandles(Declaration[] declarations) {
+ Handle[] handles = new Handle[declarations.length];
+ for(int i=0; i<declarations.length; i++) {
+ //if (declarations[i] == null) continue;
+ handles[i] = declarations[i].getHandle();
+ }
+ return handles;
+ }
+
+ // Make sure that all decs are convertted to handles before serialization
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ pointedToByHandles = getHandles(getPointedToBy());
+ pointsToHandles = getHandles(getPointsTo());
+ if (crosscutDeclaration != null) {
+ crosscutDeclarationHandle = crosscutDeclaration.getHandle();
+ }
+ out.defaultWriteObject();
+ }
+
+ // support functions
+ public Declaration[] getCrosscutDeclarations() {
+ return getDeclarationsHelper("pointcut");
+ }
+
+ public Declaration[] getAdviceDeclarations() {
+ return getDeclarationsHelper("advice");
+ }
+
+ public Declaration[] getIntroductionDeclarations() {
+ return getDeclarationsHelper("introduction");
+ }
+
+ private Declaration[] getDeclarationsHelper(String kind) {
+ Declaration[] decls = getDeclarations();
+ List result = new ArrayList();
+ for ( int i = 0; i < decls.length; i++ ) {
+ Declaration decl = decls[i];
+ if ( decl.getKind().equals(kind) ) {
+ result.add(decl);
+ }
+ }
+ return (Declaration[])result.toArray(new Declaration[result.size()]);
+ }
+
+
+ public boolean isType() {
+ return getKind().equals("interface") || getKind().equals("class");
+ }
+
+ public boolean hasBody() {
+ String kind = getKind();
+ return kind.equals("class") || kind.endsWith("constructor") ||
+ (kind.endsWith("method") && getModifiers().indexOf("abstract") == -1 &&
+ getModifiers().indexOf("native") == -1);
+ }
+
+ public boolean isIntroduced() {
+ return kind.startsWith("introduced-");
+ }
+
+ public boolean hasSignature() {
+ String kind = getKind();
+ if ( kind.equals( "class" ) ||
+ kind.equals( "interface" ) ||
+ kind.equals( "initializer" ) ||
+ kind.equals( "field" ) ||
+ kind.equals( "constructor" ) ||
+ kind.equals( "method" ) ) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ private static class Handle implements Serializable {
+ public String filename;
+ public int line, column;
+
+ public Handle(String filename, int line, int column) {
+ this.filename = filename;
+ this.line = line;
+ this.column = column;
+ }
+
+ public Declaration resolve() {
+ SymbolManager manager = SymbolManager.getDefault();
+ return manager.getDeclarationAtPoint(filename, line, column);
+ }
+ }
+}
diff --git a/ajdoc/src/org/aspectj/tools/ajdoc/Main.java b/ajdoc/src/org/aspectj/tools/ajdoc/Main.java
new file mode 100644
index 000000000..25612ff5c
--- /dev/null
+++ b/ajdoc/src/org/aspectj/tools/ajdoc/Main.java
@@ -0,0 +1,700 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * Mik Kersten port to AspectJ 1.1+ code base
+ * ******************************************************************/
+
+package org.aspectj.tools.ajdoc;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.BufferedWriter;
+import java.io.PrintWriter;
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.StringReader;
+import java.io.FilenameFilter;
+
+import java.util.*;
+
+/**
+ * This is an old implementation of ajdoc that does not use an OO style. However, it
+ * does the job, and should serve to evolve a lightweight ajdoc implementation until
+ * we can make a properly extended javadoc implementation.
+ *
+ * @author Mik Kersten
+ */
+public class Main implements Config {
+
+ static SymbolManager symbolManager = null;
+
+ /** Command line options. */
+ static Vector options = new Vector();
+
+ /** Options to pass to ajc. */
+ static Vector ajcOptions = new Vector();
+
+ /** All of the files to be processed by ajdoc. */
+ static Vector filenames = new Vector();
+
+ /** List of files to pass to javadoc. */
+ static Vector fileList= new Vector();
+
+ /** List of packages to pass to javadoc. */
+ static Vector packageList = new Vector();
+
+ /** Default to package visiblity. */
+ static String docModifier = "package";
+
+ static Vector sourcepath = new Vector();
+
+ static boolean verboseMode = false;
+ static boolean packageMode = false;
+ static boolean authorStandardDocletSwitch = false;
+ static boolean versionStandardDocletSwitch = false;
+ static File rootDir = null;
+ static Hashtable declIDTable = new Hashtable();
+ static String docDir = ".";
+
+ public static void clearState() {
+ symbolManager = null;
+ options = new Vector();
+ ajcOptions = new Vector();
+ filenames = new Vector();
+ fileList= new Vector();
+ packageList = new Vector();
+ docModifier = "package";
+ sourcepath = new Vector();
+ verboseMode = false;
+ packageMode = false;
+ rootDir = null;
+ declIDTable = new Hashtable();
+ docDir = ".";
+ }
+
+ public static void main(String[] args) {
+
+ // STEP 1: parse the command line and do other global setup
+ sourcepath.addElement("."); // add the current directory to the classapth
+ parseCommandLine(args);
+ rootDir = getRootDir();
+ symbolManager = SymbolManager.getDefault();
+ File[] inputFiles = new File[filenames.size()];
+ File[] signatureFiles = new File[filenames.size()];
+ try {
+ // create the workingdir if it doesn't exist
+ if ( !(new File( Config.WORKING_DIR ).isDirectory()) ) {
+ File dir = new File( Config.WORKING_DIR );
+ dir.mkdir();
+ dir.deleteOnExit();
+ }
+
+ for (int i = 0; i < filenames.size(); i++) {
+ inputFiles[i] = findFile((String)filenames.elementAt(i));
+ //signatureFiles[i] = createSignatureFile(inputFiles[i]);
+ }
+
+ // PHASE 0: call ajc
+ ajcOptions.addElement( "-noExit" );
+ ajcOptions.addElement( "-emacssym" ); // TODO: wrong option to force model gen
+ String[] argsToCompiler = new String[ajcOptions.size() + inputFiles.length];
+ int i = 0;
+ for ( ; i < ajcOptions.size(); i++ ) {
+ argsToCompiler[i] = (String)ajcOptions.elementAt(i);
+ //System.out.println(">>> ajc: " + argsToCompiler[i]);
+ }
+ for ( int j = 0; j < inputFiles.length; j++) {
+ argsToCompiler[i] = inputFiles[j].getAbsolutePath();
+ //System.out.println(">> file to ajc: " + inputFiles[j].getAbsolutePath());
+ i++;
+ }
+
+ System.out.println( "> calling ajc..." );
+
+ try {
+ (new org.aspectj.tools.ajc.Main() {
+ public void exit(int status) {
+ if (status != 0) {
+ System.out.println( "> compile failed, exiting ajdoc" );
+ System.exit( -1 );
+ }
+ }
+ }).main(argsToCompiler);
+ }
+ catch ( SecurityException se ) {
+ System.exit( -1 );
+ }
+/*
+ for (int ii = 0; ii < inputFiles.length; ii++) {
+ String tempFP = inputFiles[ii].getAbsolutePath();
+ tempFP = tempFP.substring(0, tempFP.length()-4);
+ tempFP += "ajsym";
+ System.out.println( ">> checking: " + tempFP);
+ File tempF = new File(tempFP);
+ if ( !tempF.exists() ) System.out.println( ">>> doesn't exist!" );
+ }
+*/
+ for (int ii = 0; ii < filenames.size(); ii++) {
+ signatureFiles[ii] = createSignatureFile(inputFiles[ii]);
+ }
+
+ // PHASE 1: generate Signature files (Java with DeclIDs and no bodies).
+ System.out.println( "> building signature files..." );
+ Phase1.doFiles(declIDTable, symbolManager, inputFiles, signatureFiles);
+
+ // PHASE 2: let Javadoc generate HTML (with DeclIDs)
+ System.out.println( "> calling javadoc..." );
+ String[] javadocargs = null;
+ if ( packageMode ) {
+ int numExtraArgs = 2;
+ if (authorStandardDocletSwitch) numExtraArgs++;
+ if (versionStandardDocletSwitch) numExtraArgs++;
+ javadocargs = new String[numExtraArgs + options.size() + packageList.size() +
+ fileList.size() ];
+ javadocargs[0] = "-sourcepath";
+ javadocargs[1] = Config.WORKING_DIR;
+ int argIndex = 2;
+ if (authorStandardDocletSwitch) {
+ javadocargs[argIndex] = "-author";
+ argIndex++;
+ }
+ if (versionStandardDocletSwitch) {
+ javadocargs[argIndex] = "-version";
+ }
+ //javadocargs[1] = getSourcepathAsString();
+ for (int k = 0; k < options.size(); k++) {
+ javadocargs[numExtraArgs+k] = (String)options.elementAt(k);
+ }
+ for (int k = 0; k < packageList.size(); k++) {
+ javadocargs[numExtraArgs+options.size() + k] = (String)packageList.elementAt(k);
+ }
+ for (int k = 0; k < fileList.size(); k++) {
+ javadocargs[numExtraArgs+options.size() + packageList.size() + k] = (String)fileList.elementAt(k);
+ }
+ }
+ else {
+ javadocargs = new String[options.size() + signatureFiles.length];
+ for (int k = 0; k < options.size(); k++) {
+ javadocargs[k] = (String)options.elementAt(k);
+ }
+ for (int k = 0; k < signatureFiles.length; k++) {
+ javadocargs[options.size() + k] = signatureFiles[k].getCanonicalPath();
+ }
+ }
+ Phase2.callJavadoc(javadocargs);
+
+ //for ( int o = 0; o < inputFiles.length; o++ ) {
+ // System.out.println( "file: " + inputFiles[o] );
+ //}
+
+ // PHASE 3: add AspectDoc specific stuff to the HTML (and remove the DeclIDS).
+ /** We start with the known HTML files (the ones that correspond directly to the
+ * input files.) As we go along, we may learn that Javadoc split one .java file
+ * into multiple .html files to handle inner classes or local classes. The html
+ * file decorator picks that up.
+ */
+ System.out.println( "> Decorating html files..." );
+ Phase3.decorateHTMLFromInputFiles(declIDTable,
+ rootDir,
+ symbolManager,
+ inputFiles,
+ docModifier);
+ removeDeclIDsFromFile("index-all.html");
+ removeDeclIDsFromFile("serialized-form.html");
+ for (int p = 0; p < packageList.size(); p++) {
+ removeDeclIDsFromFile(((String)packageList.elementAt(p)).replace('.','/') +
+ Config.DIR_SEP_CHAR +
+ "package-summary.html" );
+ }
+ } catch (Throwable e) {
+ handleInternalError(e);
+ exit(-2);
+ }
+ }
+
+ static void removeDeclIDsFromFile(String filename) {
+ // Remove the decl ids from "index-all.html"
+ File indexFile = new File( docDir + Config.DIR_SEP_CHAR + filename );
+ try {
+ if ( indexFile.exists() ) {
+ BufferedReader indexFileReader = new BufferedReader( new FileReader( indexFile ) );
+ String indexFileBuffer = "";
+ String line = indexFileReader.readLine();
+ while ( line != null ) {
+ int indexStart = line.indexOf( Config.DECL_ID_STRING );
+ int indexEnd = line.indexOf( Config.DECL_ID_TERMINATOR );
+ if ( indexStart != -1 && indexEnd != -1 ) {
+ line = line.substring( 0, indexStart ) +
+ line.substring( indexEnd+Config.DECL_ID_TERMINATOR.length() );
+ }
+ indexFileBuffer += line;
+ line = indexFileReader.readLine();
+ }
+ FileOutputStream fos = new FileOutputStream( indexFile );
+ fos.write( indexFileBuffer.getBytes() );
+ }
+ }
+ catch (IOException ioe) {
+ // be siltent
+ }
+ }
+
+ static void callAJC( String[] ajcargs ) {
+ final SecurityManager defaultSecurityManager = System.getSecurityManager();
+
+ System.setSecurityManager( new SecurityManager() {
+ public void checkExit(int status) {
+ System.setSecurityManager( defaultSecurityManager );
+ //throw new SecurityException( "status code: " + status );
+ //System.exit( -1 );
+ }
+ public void checkPermission( java.security.Permission permission ) {
+ if ( defaultSecurityManager != null )
+ defaultSecurityManager.checkPermission( permission );
+ }
+ public void checkPermission( java.security.Permission permission,
+ Object context ) {
+ if ( defaultSecurityManager != null )
+ defaultSecurityManager.checkPermission( permission, context );
+ }
+ } );
+
+ try {
+ org.aspectj.tools.ajc.Main.main( ajcargs );
+ }
+ catch ( SecurityException se ) {
+ // Do nothing since we expect it to be thrown
+ //System.out.println( ">> se: " + se.getMessage() );
+ } catch ( IOException ioe ) {
+ System.out.println( ">> io error: " + ioe.getMessage() );
+ }
+ // Set the security manager back
+ System.setSecurityManager( defaultSecurityManager );
+ }
+
+
+ /**
+ * If the file doesn't exist on the specified path look for it in all the other
+ * paths specified by the "sourcepath" option.
+ */
+ static File findFile( String filename ) throws IOException {
+
+ return new File( filename );
+ /*
+ File file = new File(filename);
+ if (file.exists()) {
+ return file;
+ }
+ else {
+ for ( int i = 0; i < sourcePath.size(); i++ ) {
+ File currPath = new File((String)sourcePath.elementAt(i));
+ File currFile = new File(currPath + "/" + filename); // !!!
+ if ( file.exists()) {
+ return file;
+ }
+ }
+ }
+ throw new IOException("couldn't find source file: " + filename);
+ */
+ }
+
+ static Vector getSourcePath() {
+ Vector sourcePath = new Vector();
+ boolean found = false;
+ for ( int i = 0; i < options.size(); i++ ) {
+ String currOption = (String)options.elementAt(i);
+ if (found && !currOption.startsWith("-")) {
+ sourcePath.add(currOption);
+ }
+ if (currOption.equals("-sourcepath")) {
+ found = true;
+ }
+ }
+ return sourcePath;
+ }
+
+ static File getRootDir() {
+ File rootDir = new File( "." );
+ for ( int i = 0; i < options.size(); i++ ) {
+ if ( ((String)options.elementAt(i)).equals( "-d" ) ) {
+ rootDir = new File((String)options.elementAt(i+1));
+ if ( !rootDir.exists() ) {
+ System.out.println( "Destination directory not found: " +
+ (String)options.elementAt(i+1) );
+ System.exit( -1 );
+ }
+ }
+ }
+ return rootDir;
+ }
+
+ static File createSignatureFile(File inputFile) throws IOException {
+ Declaration[] decls = symbolManager.getDeclarations(inputFile.getAbsolutePath());
+ Declaration decl = null;
+ String packageName = null;
+ if ( decls != null && decls[0] != null ) {
+ decl = decls[0];
+ packageName = decl.getPackageName();
+ }
+ String filename = "";
+ if ( packageName != null ) {
+ //System.err.println(">> creating: " + packageName);
+ String pathName = Config.WORKING_DIR + '/' + packageName.replace('.', '/');
+ //System.err.println(">> pathName: " + pathName);
+ File packageDir = new File(pathName);
+ if ( !packageDir.exists() ) {
+ packageDir.mkdirs();
+ //packageDir.deleteOnExit();
+ }
+ //verifyPackageDirExists(packageName, null);
+ packageName = packageName.replace( '.','/' ); // !!!
+ filename = Config.WORKING_DIR + Config.DIR_SEP_CHAR + packageName +
+ Config.DIR_SEP_CHAR + inputFile.getName();
+ }
+ else {
+ filename = Config.WORKING_DIR + Config.DIR_SEP_CHAR + inputFile.getName();
+ }
+ File signatureFile = new File( filename );
+ //signatureFile.deleteOnExit();
+ return signatureFile;
+ }
+
+
+ static void verifyPackageDirExists( String packageName, String offset ) {
+ System.err.println(">>> name: " + packageName + ", offset: " + offset);
+ if ( packageName.indexOf( "." ) != -1 ) {
+ File tempFile = new File("c:/aspectj-test/d1/d2/d3");
+ tempFile.mkdirs();
+ String currPkgDir = packageName.substring( 0, packageName.indexOf( "." ) );
+ String remainingPkg = packageName.substring( packageName.indexOf( "." )+1 );
+ String filePath = null;
+ if ( offset != null ) {
+ filePath = Config.WORKING_DIR + Config.DIR_SEP_CHAR +
+ offset + Config.DIR_SEP_CHAR + currPkgDir ;
+ }
+ else {
+ filePath = Config.WORKING_DIR + Config.DIR_SEP_CHAR + currPkgDir;
+ }
+ File packageDir = new File( filePath );
+ if ( !packageDir.exists() ) {
+ packageDir.mkdir();
+ packageDir.deleteOnExit();
+ }
+ if ( remainingPkg != "" ) {
+ verifyPackageDirExists( remainingPkg, currPkgDir );
+ }
+ }
+ else {
+ String filePath = null;
+ if ( offset != null ) {
+ filePath = Config.WORKING_DIR + Config.DIR_SEP_CHAR + offset + Config.DIR_SEP_CHAR + packageName;
+ }
+ else {
+ filePath = Config.WORKING_DIR + Config.DIR_SEP_CHAR + packageName;
+ }
+ File packageDir = new File( filePath );
+ if ( !packageDir.exists() ) {
+ packageDir.mkdir();
+ packageDir.deleteOnExit();
+ }
+ }
+ }
+
+ static void parseCommandLine(String[] args) {
+ if (args.length == 0) {
+ displayHelpAndExit( null );
+ }
+ List vargs = new LinkedList(Arrays.asList(args));
+
+ parseArgs(vargs, new File( "." )); // !!!
+
+ if (filenames.size() == 0) {
+ displayHelpAndExit( "ajdoc: No packages or classes specified" );
+ }
+ }
+
+ static void setSourcepath(String arg) {
+ sourcepath.clear();
+ arg = arg + ";"; // makes things easier for ourselves
+ StringTokenizer tokenizer = new StringTokenizer(arg, ";");
+ while (tokenizer.hasMoreElements()) {
+ sourcepath.addElement(tokenizer.nextElement());
+ }
+ }
+
+ static String getSourcepathAsString() {
+ String cPath = "";
+ for (int i = 0; i < sourcepath.size(); i++) {
+ cPath += (String)sourcepath.elementAt(i) + Config.DIR_SEP_CHAR + Config.WORKING_DIR;
+ if (i != sourcepath.size()-1) {
+ cPath += ";";
+ }
+ }
+ return cPath;
+ }
+
+ static void parseArgs(List vargs, File currentWorkingDir) {
+ boolean addNextAsOption = false;
+ boolean addNextAsArgFile = false;
+ boolean addNextToAJCOptions = false;
+ boolean addNextAsDocDir = false;
+ boolean addNextAsClasspath = false;
+ boolean ignoreArg = false; // used for discrepancy betwen class/sourcepath in ajc/javadoc
+ boolean addNextAsSourcePath = false;
+ if ( vargs.size() == 0 ) {
+ displayHelpAndExit( null );
+ }
+ for (int i = 0; i < vargs.size() ; i++) {
+ String arg = (String)vargs.get(i);
+ ignoreArg = false;
+ if ( addNextToAJCOptions ) {
+ ajcOptions.addElement( arg );
+ addNextToAJCOptions = false;
+ }
+ if ( addNextAsDocDir ) {
+ docDir = arg;
+ addNextAsDocDir = false;
+ }
+ if ( addNextAsClasspath ) {
+ addNextAsClasspath = false;
+ }
+ if ( addNextAsSourcePath ) {
+ setSourcepath( arg );
+ addNextAsSourcePath = false;
+ ignoreArg = true;
+ }
+ if ( arg.startsWith("@") ) {
+ expandAtSignFile(arg.substring(1), currentWorkingDir);
+ }
+ else if ( arg.equals( "-argfile" ) ) {
+ addNextAsArgFile = true;
+ }
+ else if ( addNextAsArgFile ) {
+ expandAtSignFile(arg, currentWorkingDir);
+ addNextAsArgFile = false;
+ }
+ else if (arg.equals("-d") ) {
+ addNextAsOption = true;
+ options.addElement(arg);
+ addNextAsDocDir = true;
+ }
+ else if ( arg.equals( "-bootclasspath" ) ) {
+ addNextAsOption = true;
+ addNextToAJCOptions = true;
+ options.addElement( arg );
+ ajcOptions.addElement( arg );
+ }
+ else if ( arg.equals( "-classpath" ) ) {
+ addNextAsOption = true;
+ addNextToAJCOptions = true;
+ addNextAsClasspath = true;
+ options.addElement( arg );
+ ajcOptions.addElement( arg );
+ }
+ else if ( arg.equals( "-sourcepath" ) ) {
+ addNextAsSourcePath = true;
+ //options.addElement( arg );
+ //ajcOptions.addElement( arg );
+ }
+ else if (arg.startsWith("-") || addNextAsOption) {
+ if ( arg.equals( "-private" ) ) {
+ docModifier = "private";
+ }
+ else if ( arg.equals( "-package" ) ) {
+ docModifier = "package";
+ }
+ else if ( arg.equals( "-protected" ) ) {
+ docModifier = "protected";
+ }
+ else if ( arg.equals( "-public" ) ) {
+ docModifier = "public";
+ }
+ else if ( arg.equals( "-verbose" ) ) {
+ verboseMode = true;
+ }
+ else if ( arg.equals( "-author" ) ) {
+ authorStandardDocletSwitch = true;
+ }
+ else if ( arg.equals( "-version" ) ) {
+ versionStandardDocletSwitch = true;
+ }
+ else if ( arg.equals( "-v" ) ) {
+ printVersion();
+ exit(0);
+ }
+ else if ( arg.equals( "-help" ) ) {
+ displayHelpAndExit( null );
+ }
+ 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" +
+ " \n" );
+ exit(0);
+ }
+ else if ( addNextAsOption ) {
+ // just pass through
+ }
+ else {
+ displayHelpAndExit( null );
+ }
+ options.addElement(arg);
+ addNextAsOption = false;
+ }
+ else {
+ // check if this is a file or a package
+ if ( arg.indexOf( ".java" ) == arg.length() - 5 ||
+ arg.indexOf( ".lst" ) == arg.length() - 4 &&
+ arg != null ) {
+ File f = new File(arg);
+ if (f.isAbsolute()) {
+ filenames.addElement(arg);
+ }
+ else {
+ filenames.addElement( currentWorkingDir + Config.DIR_SEP_CHAR + arg );
+ }
+ fileList.addElement( arg );
+ }
+
+ // PACKAGE MODE STUFF
+ else if (!ignoreArg) {
+ packageMode = true;
+ packageList.addElement( arg );
+ arg = arg.replace( '.', '/' ); // !!!
+
+ // do this for every item in the classpath
+ for ( int c = 0; c < sourcepath.size(); c++ ) {
+ String path = (String)sourcepath.elementAt(c) + Config.DIR_SEP_CHAR + arg;
+ File pkg = new File(path);
+ if ( pkg.isDirectory() ) {
+ String[] files = pkg.list( new FilenameFilter() {
+ public boolean accept( File dir, String name ) {
+ int index1 = name.lastIndexOf( "." );
+ int index2 = name.length();
+ if ( (index1 >= 0 && index2 >= 0 ) &&
+ (name.substring(index1, index2).equals( ".java" ) ) ) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ } );
+ for ( int j = 0; j < files.length; j++ ) {
+ filenames.addElement( (String)sourcepath.elementAt(c) +
+ Config.DIR_SEP_CHAR +
+ arg + Config.DIR_SEP_CHAR + files[j] );
+ }
+ }
+ else if (c == sourcepath.size() ) { // last element on classpath
+ System.out.println( "ajdoc: No package, class, or source file " +
+ "found named " + arg + "." );
+ }
+ else {
+ // didn't find it on that element of the classpath but that's ok
+ }
+ }
+ }
+ }
+ }
+ // set the default visibility as an option to javadoc option
+ if ( !options.contains( "-private" ) &&
+ !options.contains( "-package" ) &&
+ !options.contains( "-protected" ) &&
+ !options.contains( "-public" ) ) {
+ options.addElement( "-package" );
+ }
+
+ }
+
+ static void expandAtSignFile(String filename, File currentWorkingDir) {
+ List result = new LinkedList();
+
+ File atFile = qualifiedFile(filename, currentWorkingDir);
+ String atFileParent = atFile.getParent();
+ File myWorkingDir = null;
+ if (atFileParent != null) myWorkingDir = new File(atFileParent);
+
+ try {
+ BufferedReader stream = new BufferedReader(new FileReader(atFile));
+ String line = null;
+ while ( (line = stream.readLine()) != null) {
+ // strip out any comments of the form # to end of line
+ int commentStart = line.indexOf("//");
+ if (commentStart != -1) {
+ line = line.substring(0, commentStart);
+ }
+
+ // remove extra whitespace that might have crept in
+ line = line.trim();
+ // ignore blank lines
+ if (line.length() == 0) continue;
+ result.add(line);
+ }
+ } catch (IOException e) {
+ System.err.println("Error while reading the @ file " + atFile.getPath() + ".\n"
+ + e);
+ System.exit( -1 );
+ }
+
+ parseArgs(result, myWorkingDir);
+ }
+
+ static File qualifiedFile(String name, File currentWorkingDir) {
+ name = name.replace('/', File.separatorChar);
+ File file = new File(name);
+ if (!file.isAbsolute() && currentWorkingDir != null) {
+ file = new File(currentWorkingDir, name);
+ }
+ return file;
+ }
+
+
+ static void displayHelpAndExit(String message) {
+ if (message != null) System.err.println(message);
+ System.err.println();
+ System.err.println(Config.USAGE);
+ exit(0);
+ }
+
+ static protected void exit(int value) {
+ System.out.flush();
+ System.err.flush();
+ System.exit(value);
+ }
+
+ /* This section of code handles errors that occur during compilation */
+ static final String internalErrorMessage =
+ "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" +
+ " \n";
+
+ static public void handleInternalError(Throwable uncaughtThrowable) {
+ System.err.println("An internal error occured in ajdoc");
+ System.err.println(internalErrorMessage);
+ System.err.println(uncaughtThrowable.toString());
+ uncaughtThrowable.printStackTrace();
+ System.err.println();
+ }
+
+ static void printVersion() {
+ System.out.println( Config.VERSION );
+ }
+
+}
+
+
diff --git a/ajdoc/src/org/aspectj/tools/ajdoc/Phase1.java b/ajdoc/src/org/aspectj/tools/ajdoc/Phase1.java
new file mode 100644
index 000000000..2c36403a3
--- /dev/null
+++ b/ajdoc/src/org/aspectj/tools/ajdoc/Phase1.java
@@ -0,0 +1,229 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * Mik Kersten port to AspectJ 1.1+ code base
+ * ******************************************************************/
+
+package org.aspectj.tools.ajdoc;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.BufferedWriter;
+import java.io.PrintWriter;
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.StringReader;
+import java.util.StringTokenizer;
+
+import java.util.*;
+
+class Phase1 {
+
+ static Hashtable declIDTable = null;
+
+ static void doFiles(Hashtable table,
+ SymbolManager symbolManager,
+ File[] inputFiles,
+ File[] signatureFiles) {
+ declIDTable = table;
+ for (int i = 0; i < inputFiles.length; i++) {
+ doFile(symbolManager, inputFiles[i], signatureFiles[i]);
+ }
+ }
+
+ static void doFile(SymbolManager symbolManager, File inputFile, File signatureFile) {
+ try {
+
+ Declaration[] decls = symbolManager.getDeclarations(inputFile.getCanonicalPath());
+
+ PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(signatureFile.getCanonicalPath())));
+
+ // write the package info
+ if ( decls != null && decls[0] != null && decls[0].getPackageName() != null ) {
+ writer.println( "package " + decls[0].getPackageName() + ";" );
+ }
+
+ if (decls != null) {
+ doDecls(decls, writer, false);
+ }
+ writer.close(); //this isn't in a finally, because if we got an
+ //error we don't really want the contents anyways
+ }
+ catch (IOException e) {
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ static void doDecls (Declaration[] decls,
+ PrintWriter writer,
+ boolean declaringDeclIsInterface) throws IOException {
+ for (int i = 0; i < decls.length; i++) {
+ Declaration decl = decls[i];
+ //System.out.println( ">> sig: " + decl.getSignature() );
+ doDecl(decl, writer, declaringDeclIsInterface);
+ }
+ }
+
+ static void doDecl(Declaration decl,
+ PrintWriter writer,
+ boolean declaringDeclIsInterface) throws IOException {
+ String formalComment = decl.getFormalComment();
+ String fullSignature = decl.getFullSignature();
+ System.err.println("> full: " + fullSignature);
+ Declaration[] ptbs = decl.getPointedToBy();
+ Declaration[] subs = decl.getDeclarations();
+ if (decl.hasSignature()) {
+ formalComment = addDeclID(decl, formalComment);
+
+ writer.println(formalComment);
+
+ // HACK: this should be in Declaration
+ int implementsClauseIndex = fullSignature.indexOf(" implements");
+ if (implementsClauseIndex != -1) {
+ String newSignature = "";
+ StringTokenizer st = new StringTokenizer(fullSignature.substring(implementsClauseIndex, fullSignature.length()));
+ for (String element = (String)st.nextElement(); st.hasMoreElements(); element = (String)st.nextElement()) {
+ if (element.indexOf("$MightHaveAspect") != -1
+ && element.indexOf("implements") != -1) {
+ newSignature += element;
+ }
+ }
+ if (!newSignature.equals("")) {
+ writer.print(fullSignature.substring(0, implementsClauseIndex)
+ + " implements " + newSignature + " " );
+ } else {
+ writer.print(fullSignature.substring(0, implementsClauseIndex) + " " );
+ }
+ } else {
+ writer.print(fullSignature + " " );
+ }
+
+ if ((!decl.hasBody() && !decl.getKind().equals( "interface" ) ||
+ (decl.getKind().equals( "method" ) && declaringDeclIsInterface)) && // !!! bug in Jim's API?
+ !(decl.getKind().equals("initializer") && decl.getModifiers().indexOf("static") != -1 ) ) {
+
+ System.err.println(">>>> kind: " + decl.getKind());
+
+ if (decl.getModifiers().indexOf("static final") != -1) {
+ String fullSig = decl.getFullSignature().trim();
+ String stripped = fullSig.substring(0, fullSig.lastIndexOf(' '));
+ //System.err.println(">>> " + fullSig);
+ String type = stripped.substring(stripped.lastIndexOf(' '), stripped.length());
+ //System.err.println("> type: " + type);
+
+ if (type.equals("boolean")) {
+ writer.println(" = false");
+ } else if (type.equals("char")) {
+ writer.println(" = '0'");
+ } else if (type.equals("byte")) {
+ writer.println(" = 0");
+ } else if (type.equals("short")) {
+ writer.println(" = 0");
+ } else if (type.equals("int")) {
+ writer.println(" = 0");
+ } else if (type.equals("long")) {
+ writer.println(" = 0");
+ } else if (type.equals("float")) {
+ writer.println(" = 0");
+ } else if (type.equals("double")) {
+ writer.println(" = 0");
+ } else if (type.equals("String")) {
+ writer.println(" = \"\"");
+ } else {
+ writer.println(" = null");
+ }
+ }
+ writer.println(";");
+// } else if ((!decl.hasBody() && !decl.getKind().equals( "interface" ) ||
+// (decl.getKind().equals( "method" ) && declaringDeclIsInterface)) && // !!! bug in Jim's API?
+// !(decl.getKind().equals("initializer") && decl.getModifiers().indexOf("static") != -1 ) ) {
+//
+// writer.println(";");
+
+ } else {
+ if (subs != null) {
+ if ( decl.getKind().equals( "interface" ) ) {
+ declaringDeclIsInterface = true;
+ }
+ writer.println("{");
+ doDecls(subs, writer, declaringDeclIsInterface);
+ writer.println("}");
+ }
+ }
+ writer.println();
+ }
+ }
+
+ static int nextDeclID = 0;
+ static String addDeclID(Declaration decl, String formalComment) {
+ String declID = "" + ++nextDeclID;
+ declIDTable.put(declID, decl);
+ return addToFormal(formalComment, Config.DECL_ID_STRING + declID + Config.DECL_ID_TERMINATOR);
+ }
+
+ /**
+ * We want to go:
+ * just before the first period
+ * just before the first @
+ * just before the end of the comment
+ *
+ * Adds a place holder for the period ('#') if one will need to be
+ * replaced.
+ */
+ static String addToFormal(String formalComment, String string) {
+ boolean appendPeriod = true;
+ if ( (formalComment == null) || formalComment.equals("")) {
+ //formalComment = "/**\n * . \n */\n";
+ formalComment = "/**\n * \n */\n";
+ appendPeriod = false;
+ }
+ formalComment = formalComment.trim();
+
+ int atsignPos = formalComment.indexOf('@');
+ int endPos = formalComment.indexOf("*/");
+ int periodPos = formalComment.indexOf("/**")+2;
+ //if ( atsignPos == -1 ) {
+ // periodPos = formalComment.lastIndexOf(".");
+ //} else {
+ // periodPos = formalComment.substring(0, atsignPos).lastIndexOf(".");
+ //}
+ int position = 0;
+ String periodPlaceHolder = "";
+ if ( periodPos != -1 ) {
+ position = periodPos+1;
+ //if ( appendPeriod ) {
+ //periodPlaceHolder = "#";
+ //}
+ }
+ else if ( atsignPos != -1 ) {
+ string = string + "\n * ";
+ position = atsignPos;
+ }
+ else if ( endPos != -1 ) {
+ string = "* " + string + "\n";
+ position = endPos;
+ }
+ else {
+ // !!! perhaps this error should not be silent
+ throw new Error("Failed to append to formal comment for comment: " +
+ formalComment );
+ }
+
+ return
+ formalComment.substring(0, position) + periodPlaceHolder +
+ string +
+ formalComment.substring(position);
+ }
+
+}
diff --git a/ajdoc/src/org/aspectj/tools/ajdoc/Phase2.java b/ajdoc/src/org/aspectj/tools/ajdoc/Phase2.java
new file mode 100644
index 000000000..303b74cc4
--- /dev/null
+++ b/ajdoc/src/org/aspectj/tools/ajdoc/Phase2.java
@@ -0,0 +1,66 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * Mik Kersten port to AspectJ 1.1+ code base
+ * ******************************************************************/
+
+package org.aspectj.tools.ajdoc;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.BufferedWriter;
+import java.io.PrintWriter;
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.StringReader;
+
+import java.util.*;
+
+class Phase2 {
+ static void callJavadoc( String[] javadocargs ) {
+ final SecurityManager defaultSecurityManager = System.getSecurityManager();
+
+ System.setSecurityManager( new SecurityManager() {
+ public void checkExit(int status) {
+ if (status == 0) {
+ throw new SecurityException();
+ }
+ else {
+ System.setSecurityManager(defaultSecurityManager);
+ //System.out.println("Error: javadoc exited unexpectedly");
+ System.exit(0);
+ throw new SecurityException();
+ }
+ }
+ public void checkPermission( java.security.Permission permission ) {
+ if ( defaultSecurityManager != null )
+ defaultSecurityManager.checkPermission( permission );
+ }
+ public void checkPermission( java.security.Permission permission,
+ Object context ) {
+ if ( defaultSecurityManager != null )
+ defaultSecurityManager.checkPermission( permission, context );
+ }
+ } );
+
+ try {
+ com.sun.tools.javadoc.Main.main( javadocargs );
+ }
+ catch ( SecurityException se ) {
+ // Do nothing since we expect it to be thrown
+ //System.out.println( ">> se: " + se.getMessage() );
+ }
+ // Set the security manager back
+ System.setSecurityManager( defaultSecurityManager );
+ }
+}
diff --git a/ajdoc/src/org/aspectj/tools/ajdoc/Phase3.java b/ajdoc/src/org/aspectj/tools/ajdoc/Phase3.java
new file mode 100644
index 000000000..09d3e95c2
--- /dev/null
+++ b/ajdoc/src/org/aspectj/tools/ajdoc/Phase3.java
@@ -0,0 +1,731 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * Mik Kersten port to AspectJ 1.1+ code base
+ * ******************************************************************/
+
+package org.aspectj.tools.ajdoc;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.BufferedWriter;
+import java.io.PrintWriter;
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.StringReader;
+
+import java.util.*;
+
+class Phase3 {
+
+ static List visibleFileList = new ArrayList();
+ static Hashtable declIDTable = null;
+ static SymbolManager symbolManager = null;
+ static File rootDir = null;
+
+ static void decorateHTMLFromInputFiles(Hashtable table,
+ File newRootDir,
+ SymbolManager sm,
+ File[] inputFiles,
+ String docModifier ) throws IOException {
+ rootDir = newRootDir;
+ 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,
+ false);
+ }
+ }
+
+ static void decorateHTMLFromDecls(Declaration[] decls, String base, String docModifier, boolean exceededNestingLevel) throws IOException {
+ if ( decls != null ) {
+ for (int i = 0; i < decls.length; i++) {
+ Declaration decl = decls[i];
+ decorateHTMLFromDecl(decl, base, docModifier, exceededNestingLevel);
+ }
+ }
+ }
+
+ /**
+ * Before attempting to decorate the HTML file we have to verify that it exists,
+ * which depends on the documentation visibility specified to javadoc.
+ *
+ * Depending on docModifier, can document
+ * - public: only public
+ * - protected: protected and public (default)
+ * - package: package protected and public
+ * - private: everything
+ */
+ static void decorateHTMLFromDecl(Declaration decl,
+ String base,
+ String docModifier,
+ boolean exceededNestingLevel ) throws IOException {
+ 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 ||
+ decl.getModifiers().indexOf( "public" ) != -1 )) ||
+ (docModifier.equals( "public" ) && decl.getModifiers().indexOf( "public" ) != -1) ) {
+ visibleFileList.add( getName( decl ) );
+ String packageName = decl.getPackageName();
+ String filename = "";
+ //System.out.println(">>>" + decl.getDeclaringType() + ", " + base);
+ if ( packageName != null ) {
+ int index1 = base.lastIndexOf(Config.DIR_SEP_CHAR);
+ int index2 = base.lastIndexOf(".");
+ String currFileClass = "";
+ if (index1 > -1 && index2 > 0 && index1 < index2) {
+ currFileClass = base.substring(index1+1, index2);
+ }
+ if (currFileClass.equals(decl.getDeclaringType())) {
+ // !!! hack for inner class !!!
+ packageName = packageName.replace( '.','/' );
+ String newBase = "";
+ if ( base.lastIndexOf(Config.DIR_SEP_CHAR) > 0 ) {
+ newBase = base.substring(0, base.lastIndexOf(Config.DIR_SEP_CHAR));
+ }
+ filename = newBase + Config.DIR_SEP_CHAR + packageName +
+ Config.DIR_SEP_CHAR + currFileClass + "." +
+ getName(decl) + ".html";
+ nestedClass = true;
+ }
+ else {
+ packageName = packageName.replace( '.','/' ); // !!!
+ filename = base + packageName + Config.DIR_SEP_CHAR + getName(decl) + ".html";
+ }
+ }
+ else {
+ filename = base + getName(decl) + ".html";
+ }
+ if (!exceededNestingLevel) {
+ decorateHTMLFile(new File(filename));
+ decorateHTMLFromDecls(decl.getDeclarations(),
+ base + getName(decl) + ".",
+ docModifier,
+ nestedClass);
+ }
+ else {
+ System.out.println("Warning: can not generate documentation for nested " +
+ "inner class: " + getName(decl) );
+ }
+ }
+ }
+ }
+
+ static void decorateHTMLFile(File file) throws IOException {
+ System.out.println( "> Decorating " + file.getCanonicalPath() + "..." );
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ StringBuffer fileContents = new StringBuffer();
+ String line = reader.readLine();
+ while( line != null ) {
+ fileContents.append(line + "\n");
+ line = reader.readLine();
+ }
+
+ boolean isSecond = false;
+ int index = 0;
+ Declaration decl;
+ while ( true ) {
+
+ //---this next part is an inlined procedure that returns two values---
+ //---the next declaration and the index at which that declaration's---
+ //---DeclID sits in the .html file ---
+ String contents = fileContents.toString();
+ int start = contents.indexOf( Config.DECL_ID_STRING, index);
+ int end = contents.indexOf( Config.DECL_ID_TERMINATOR, index );
+ if ( start == -1 )
+ decl = null;
+ else if ( end == -1 )
+ throw new Error("Malformed DeclID.");
+ else {
+ String tid = contents.substring(start + Config.DECL_ID_STRING.length(), end);
+ decl = (Declaration)declIDTable.get(tid);
+ index = start;
+ }
+ //--- ---
+ //--- ---
+
+ if ( decl == null ) break;
+ fileContents.delete(start, end + Config.DECL_ID_TERMINATOR.length());
+ if ( decl.isType() ) {
+ isSecond = true;
+ goAddIntroductions(decl, fileContents, index);
+ goAddAdvice(decl, fileContents, index);
+ goAddCrosscuts(decl, fileContents, index);
+ }
+ else {
+ decorateMemberDocumentation(decl, fileContents, index);
+ }
+ }
+
+ // Change "Class" to "Aspect", HACK: depends on "affects:"
+ if (fileContents.toString().indexOf("affects: ") != -1) {
+ int classStartIndex = fileContents.toString().indexOf("<BR>\nClass ");
+ int classEndIndex = fileContents.toString().indexOf("</H2>", classStartIndex);
+ if (classStartIndex != -1 && classEndIndex != -1) {
+ String classLine = fileContents.toString().substring(classStartIndex, classEndIndex);
+ String aspectLine = "<BR>\n" + "Aspect" + classLine.substring(11, classLine.length());
+ fileContents.delete(classStartIndex, classEndIndex);
+ fileContents.insert(classStartIndex, aspectLine);
+ }
+ }
+
+ file.delete();
+ FileOutputStream fos = new FileOutputStream( file );
+ fos.write( fileContents.toString().getBytes() );
+ }
+
+ static void goAddCrosscuts(Declaration decl, StringBuffer fileBuffer, int index ) {
+ Declaration[] crosscuts = decl.getCrosscutDeclarations();
+ if ( crosscuts.length > 0 ) {
+ insertDeclarationsSummary(fileBuffer, crosscuts, "Pointcut Summary", index);
+ insertDeclarationsDetails(fileBuffer, crosscuts, "Pointcut Detail", index);
+ }
+ }
+
+ static void goAddAdvice(Declaration decl, StringBuffer fileBuffer, int index ) {
+ Declaration[] advice = decl.getAdviceDeclarations();
+ if ( advice.length > 0 ) {
+ insertDeclarationsSummary(fileBuffer, advice, "Advice Summary", index);
+ insertDeclarationsDetails(fileBuffer, advice, "Advice Detail", index);
+ }
+ }
+
+ static void goAddIntroductions(Declaration decl,
+ StringBuffer fileBuffer,
+ int index ) {
+ Declaration[] introductions = decl.getIntroductionDeclarations();
+ if ( introductions.length > 0 ) {
+ insertDeclarationsSummary(fileBuffer,
+ introductions,
+ "Introduction Summary",
+ index);
+ insertDeclarationsDetails(fileBuffer,
+ introductions,
+ "Introduction Detail",
+ index);
+ }
+ }
+
+ static void insertDeclarationsSummary(StringBuffer fileBuffer,
+ Declaration[] decls,
+ String kind,
+ int index) {
+ int insertIndex = findSummaryIndex(fileBuffer, index);
+
+ // insert the head of the table
+ String tableHead =
+ "<!-- ======== " + kind.toUpperCase() + " ======= -->\n\n" +
+ "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"1\"" +
+ "CELLSPACING=\"0\"><TR><TD COLSPAN=2 BGCOLOR=\"#CCCCFF\">" +
+ "<FONT SIZE=\"+2\"><B>" + kind + "</B></FONT></TD></TR>\n";
+ fileBuffer.insert(insertIndex, tableHead);
+ insertIndex += tableHead.length();
+
+ // insert the body of the table
+ for ( int i = 0; i < decls.length; i++ ) {
+ Declaration decl = decls[i];
+
+ // insert the table row accordingly
+ String comment = generateSummaryComment(decl);
+ String entry = "";
+ if ( kind.equals( "Advice Summary" ) ) {
+ entry +=
+ "<TR><TD>" +
+ "<A HREF=\"#" + generateHREFName(decl) + "\">" +
+ "<TT>advice " + decl.getCrosscutDesignator() + "</TT></A><BR><TT>" +
+ generateAdviceSignatures(decl) + "</TT><BR>&nbsp;";
+ if (!comment.equals("")) {
+ entry += comment + "<P>";
+ }
+ entry +=
+ generateAffects(decl, false) + "</TD>" +
+ "</TR><TD>\n";
+ }
+ else if ( kind.equals( "Pointcut Summary" ) ) {
+ entry +=
+ "<TR><TD WIDTH=\"1%\">" +
+ "<FONT SIZE=-1><TT>" + decl.getModifiers() + "</TT></FONT>" +
+ "</TD>\n" +
+ "<TD>" +
+ "<TT><A HREF=\"#" + generateHREFName(decl) + "\">" +
+ decl.getSignature() + "</A></TT><BR>&nbsp;";
+ if (!comment.equals("")) {
+ entry += comment + "<P>";
+ }
+ entry +=
+ "</TR></TD>\n";
+ }
+ else if ( kind.equals( "Introduction Summary" ) ) {
+ entry +=
+ "<TR><TD WIDTH=\"1%\">" +
+ "<FONT SIZE=-1><TT>" + decl.getModifiers() + "</TT></FONT>" +
+ "</TD>" +
+ "<TD>" +
+ "<A HREF=\"#" + generateHREFName(decl) + "\">" +
+ "<TT>introduction " + decl.getCrosscutDesignator() + "</TT></A><P>" +
+ generateIntroductionSignatures(decl, false) +
+ generateAffects(decl, true);
+ }
+
+ // insert the entry
+ fileBuffer.insert(insertIndex, entry);
+ insertIndex += entry.length();
+ }
+
+ // insert the end of the table
+ String tableTail = "</TABLE><P>&nbsp;\n";
+ fileBuffer.insert(insertIndex, tableTail);
+ insertIndex += tableTail.length();
+ }
+
+ static void insertDeclarationsDetails(StringBuffer fileBuffer,
+ Declaration[] decls,
+ String kind,
+ int index) {
+ int insertIndex = findDetailsIndex(fileBuffer, index);
+
+ // insert the table heading
+ String detailsHeading
+ = "<P>&nbsp;\n" +
+ "<!-- ======== " + kind.toUpperCase() + " SUMMARY ======= -->\n\n" +
+ "<TABLE BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\" WIDTH=\"100%\">\n" +
+ "<TR BGCOLOR=\"#CCCCFF\" CLASS=\"TableHeadingColor\">\n" +
+ "<TD COLSPAN=1><FONT SIZE=\"+2\">\n" +
+ "<B>" + kind + "</B></FONT></TD>\n" +
+ "</TR>\n" +
+ "</TABLE>";
+ fileBuffer.insert(insertIndex, detailsHeading);
+ insertIndex += detailsHeading.length();
+
+ // insert the details
+ for ( int i = 0; i < decls.length; i++ ) {
+ Declaration decl = decls[i];
+ String entry = "";
+
+ // insert the table row accordingly
+ entry += "<A NAME=\"" + generateHREFName(decl) + "\"><!-- --></A>\n";
+ if ( kind.equals( "Advice Detail" ) ) {
+ String designatorHREFLink = generateDesignatorHREFLink(decl);
+ if (designatorHREFLink != null) {
+ entry +=
+ "<H3>advice " + designatorHREFLink + "</H3><P>";
+ }
+ else {
+ entry +=
+ "<H3>advice " + decl.getCrosscutDesignator() + "</H3><P>";
+ }
+ entry +=
+ "<TT>" +
+ generateAdviceSignatures(decl) + "</TT>\n" + "<P>" +
+ generateDetailsComment(decl) + "<P>" +
+ generateAffects(decl, false);
+ }
+ else if (kind.equals("Pointcut Detail")) {
+ entry +=
+ "<H3>" +
+ decl.getSignature() +
+ "</H3><P>" +
+ generateDetailsComment(decl);
+ }
+ else if (kind.equals("Introduction Detail")) {
+ //String designatorHREFLink = generateDesignatorHREFLink(decl);
+ //if (designatorHREFLink != null) {
+ // entry +=
+ // "<H3>introduction " + designatorHREFLink + "</H3><P>";
+ //}
+ //else {
+ entry +=
+ "<H3>introduction " + decl.getCrosscutDesignator() + "</H3><P>";
+ //}
+ entry +=
+ generateIntroductionSignatures(decl, true) +
+ generateAffects(decl, true) +
+ generateDetailsComment(decl);
+ }
+
+ // insert the entry
+ if (i != decls.length-1) {
+ entry += "<P><HR>\n";
+ }
+ else {
+ entry += "<P>";
+ }
+ fileBuffer.insert(insertIndex, entry);
+ insertIndex += entry.length();
+ }
+ }
+
+ /**
+ * TODO: don't place the summary first.
+ */
+ static int findSummaryIndex(StringBuffer fileBuffer, int index) {
+ String fbs = fileBuffer.toString();
+ String MARKER_1 = "<!-- =========== FIELD SUMMARY =========== -->";
+ String MARKER_2 = "<!-- ======== CONSTRUCTOR SUMMARY ======== -->";
+ int index1 = fbs.indexOf(MARKER_1, index);
+ int index2 = fbs.indexOf(MARKER_2, index);
+ if (index1 < index2) {
+ return index1;
+ }
+ else {
+ return index2;
+ }
+ }
+
+ static int findDetailsIndex(StringBuffer fileBuffer, int index) {
+ String fbs = fileBuffer.toString();
+ String MARKER_1 = "<!-- ========= CONSTRUCTOR DETAIL ======== -->";
+ String MARKER_2 = "<!-- ============ FIELD DETAIL =========== -->";
+ String MARKER_3 = "<!-- ============ METHOD DETAIL ========== -->";
+ int index1 = fbs.indexOf(MARKER_1, index);
+ int index2 = fbs.indexOf(MARKER_2, index);
+ int index3 = fbs.indexOf(MARKER_3, index);
+ if (index1 < index2 && index1 < index3) {
+ return index1;
+ }
+ else if (index2 < index1 && index2 < index3) {
+ return index2;
+ }
+ else {
+ return index3;
+ }
+ }
+
+ static void decorateMemberDocumentation( Declaration decl,
+ StringBuffer fileContentsBuffer,
+ int index ) {
+ if (decl.isIntroduced()) {
+ // !!! HACK, THIS HAS TO BE CHANGED WITH THE SYMBOL MANAGER
+ String fname = decl.getFilename();
+ int index1 = fname.lastIndexOf('\\');
+ int index2 = fname.lastIndexOf(".java");
+ String introducingType = fname;
+ if (index1 != -1 && index2 != -1) {
+ introducingType = fname.substring(index1+1, index2);
+ }
+ //System.out.println( "decl: " + decl.getSignature() + ", ptb: " + decl.getFilename());
+ String hrefName = "";
+ if (decl.getPackageName() != null ) {
+ hrefName = decl.getPackageName().replace('.', '/') + Config.DIR_SEP_CHAR +
+ introducingType;
+ }
+ else {
+ hrefName = introducingType;
+ }
+ String hrefLink = generateAffectsHREFLink( hrefName );
+ fileContentsBuffer.insert( index,
+ "<BR><B><FONT COLOR=CC6699>Introduced by: </FONT></B>" +
+ "<A HREF=\"" + hrefLink + "\">" +
+ hrefName.replace('/', '.') + "</A>" ); // !!! don't replace
+ return;
+ }
+ Declaration[] ptb = decl.getPointedToBy();
+ if ( ptb.length > 0 ) {
+ String prevName = "";
+ String adviceDoc = "<BR><B><FONT COLOR=CC6699>Advised by: </FONT></B>";
+ for ( int i = 0; i < ptb.length; i++ ) {
+ Declaration currDecl = ptb[i];
+ String hrefName = "";
+ if (currDecl.getPackageName() != null ) {
+ hrefName = currDecl.getPackageName().replace('.', '/') + Config.DIR_SEP_CHAR +
+ currDecl.getDeclaringType();
+ }
+ else {
+ hrefName = currDecl.getDeclaringType();
+ }
+ String hrefLink = generateAffectsHREFLink( hrefName );
+ if (!hrefName.equals(prevName)) { // !!! eliminates dupilcates since it's ordered
+ //if ( currDecl.getKind().equals( "introduction" ) ) {
+ // fileContentsBuffer.insert( index,
+ // "<BR><B><FONT COLOR=CC6699>Introduced by: </FONT></B>" +
+ // "<A HREF=\"" + hrefLink + "\">" +
+ // hrefName.replace('/', '.') + "</A>" ); // !!! don't replace
+ // return;
+ //}
+ if ( currDecl.getKind().equals( "advice" ) ) {
+ if ( i > 0 ) {
+ adviceDoc = adviceDoc + ", ";
+ }
+ adviceDoc = adviceDoc +
+ "<A HREF=\"" + hrefLink + "\">"
+ + hrefName.replace('/', '.') + "</A>"; // !!! don't replace
+ }
+ }
+ prevName = hrefName;
+ }
+ //adviceDoc += "<BR>&nbsp;";
+ fileContentsBuffer.insert( index, adviceDoc );
+ //return lineHead + adviceDoc + lineTail;
+ }
+ else {
+ ;// nop return lineHead + lineTail;
+ }
+ }
+
+ /**
+ * TODO: probably want to make this the same for intros and advice.
+ */
+ static String generateAffects( Declaration decl, boolean isIntroduction) {
+ Declaration[] decls = null;
+ if ( isIntroduction ) {
+ decls = decl.getTargets(); // !!!
+ }
+ else {
+ decls = decl.getPointsTo();
+ }
+ List addedDecls = new ArrayList();
+ List packageList = new ArrayList();
+ for ( int i = 0; i < decls.length; i++ ) {
+ Declaration currDecl = decls[i];
+ //if ( currDecl.getDeclaringType().equals( "not$found" ) ) {
+ // System.out.println( "!!!!!! " + currDecl.getSignature() );
+ //}
+ if ( currDecl != null ) {
+ String extendedName = "";
+ String packageName = currDecl.getPackageName();
+
+ // !!! HACK FOR INNER CLASSES, ONLY WORKS FOR 1 LEVEL OF NESTING !!!
+ String declaringType = currDecl.getDeclaringType();
+ if (packageName != null && !packageName.equals("")) {
+ if (currDecl.isType() && declaringType != null && !declaringType.equals("not$found")) {
+ extendedName = packageName.replace('.', '/') + Config.DIR_SEP_CHAR + declaringType + ".";
+ }
+ else {
+ extendedName = packageName.replace('.', '/') + Config.DIR_SEP_CHAR;
+ }
+ }
+
+ //System.out.println("extendedName: " + extendedName);
+ if ( isIntroduction ) {
+ if ( !addedDecls.contains(currDecl.getSignature() ) ) {
+ //addedDecls.add(currDecl.getPackageName() + "." + currDecl.getSignature());
+ addedDecls.add(extendedName + currDecl.getSignature());
+ }
+ }
+ else if ( !addedDecls.contains(currDecl.getDeclaringType() ) ) {
+ //addedDecls.add(currDecl.getPackageName() + "." + currDecl.getDeclaringType());
+ addedDecls.add(extendedName + currDecl.getDeclaringType());
+ }
+ }
+ }
+ Collections.sort(addedDecls,
+ new Comparator() {
+ public int compare(Object o1, Object o2) {
+ String s1 = (String)o1;
+ String s2 = (String)o2;
+ return s1.compareTo(s2);
+ }
+ }
+ );
+
+ String entry
+ = "<TABLE WIDTH=\"100%\" BGCOLOR=#FFFFFF><TR><TD WIDTH=\"20\">&nbsp;</TD>" +
+ "<TD><FONT SIZE=-1>affects: ";
+ String prevType = "";
+ for ( int j = 0; j < addedDecls.size(); j++ ) {
+ String currType = (String)addedDecls.get(j);
+ // don't add duplicates
+ if ( !currType.equals( prevType ) && currType.indexOf("not$found") == -1 ) { //!!!
+ if ( j > 0 ) {
+ entry += ", ";
+ }
+ if ( generateAffectsHREFLink(currType) != "" ) {
+ entry += "<A HREF=\"" + generateAffectsHREFLink(currType) +
+ "\">" + currType.replace('/', '.') + "</A>"; // !!! don't replace
+ }
+ else {
+ entry += currType;
+ }
+ }
+ prevType = currType;
+ }
+ entry += "</FONT></TD></TR></TABLE>\n</TR></TD>\n";
+ return entry;
+ }
+
+ static String generateIntroductionSignatures(Declaration decl, boolean isDetails) {
+ Declaration[] decls = decl.getDeclarations();
+ String entry = "";
+ for ( int j = 0; j < decls.length; j++ ) {
+ Declaration currDecl = decls[j];
+ if ( currDecl != null ) {
+ entry +=
+ "<TT><B>" +
+ currDecl.getSignature() +
+ "</B></TT><BR>";
+ }
+ if (isDetails) {
+ entry += generateDetailsComment(currDecl) + "<P>";
+ }
+ else {
+ entry += generateSummaryComment(currDecl) + "<P>";
+ }
+ }
+ return entry;
+ }
+
+ static String generateAdviceSignatures( Declaration decl ) {
+ return "<B>" + decl.getSignature() + "</B>";
+ }
+
+ static String generateSummaryComment(Declaration decl) {
+ String COMMENT_INDENT = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"; // !!!
+ String formattedComment = getFormattedComment(decl);
+ int periodIndex = formattedComment.indexOf( '.' );
+ if (formattedComment.equals("")) {
+ return "";
+ }
+ else if ( periodIndex != -1 ) {
+ return COMMENT_INDENT + formattedComment.substring( 0, periodIndex+1 ) ;
+ }
+ else {
+ return COMMENT_INDENT + formattedComment;
+ }
+ }
+
+ static String generateDetailsComment(Declaration decl) {
+ return getFormattedComment(decl);
+ }
+
+ static String generateHREFName(Declaration decl) {
+ String hrefLink = decl.getSignature(); // !!!
+ return hrefLink;
+ }
+
+
+ /**
+ * Figure out the link relative to the package.
+ */
+ static String generateAffectsHREFLink(String declaringType) {
+ //String offset = rootDir.getAbsolutePath() + "/" + declaringType.replace('.', '/') + ".html";
+ String link = rootDir.getAbsolutePath() + "/" + declaringType + ".html";
+ //System.out.println(">>" + link);
+ return link;
+ }
+
+ /**
+ * This formats a comment according to the rules in the Java Langauge Spec:
+ * <I>The text of a docuemntation comment consists of the characters between
+ * the /** that begins the comment and the 'star-slash' that ends it. The text is
+ * devided into one or more lines. On each of these lines, the leading *
+ * characters are ignored; for lines other than the first, blanks and
+ * tabs preceding the initial * characters are also discarded.</I>
+ *
+ * TODO: implement formatting or linking for tags.
+ */
+ static String getFormattedComment(Declaration decl) {
+ String formattedComment = "";
+
+ // strip the comment markers
+ String comment = decl.getFormalComment();
+
+ int startIndex = comment.indexOf("/**");
+ int endIndex = comment.indexOf("*/");
+ if ( startIndex == -1 ) {
+ startIndex = 0;
+ }
+ else {
+ startIndex += 3;
+ }
+ if ( endIndex == -1 ) {
+ endIndex = comment.length();
+ }
+ comment = comment.substring( startIndex, endIndex );
+
+ // string the leading whitespace and '*' characters at the beginning of each line
+ BufferedReader reader
+ = new BufferedReader( new StringReader( comment ) );
+ try {
+ for (String line = reader.readLine(); line != null; line = reader.readLine()) {
+ line = line.trim();
+ for (int i = 0; i < line.length(); i++ ) {
+ if ( line.charAt(0) == '*' ) {
+ line = line.substring(1, line.length());
+ }
+ else {
+ break;
+ }
+ }
+ // !!! remove any @see and @link tags from the line
+ //int seeIndex = line.indexOf("@see");
+ //int linkIndex = line.indexOf("@link");
+ //if ( seeIndex != -1 ) {
+ // line = line.substring(0, seeIndex) + line.substring(seeIndex);
+ //}
+ //if ( linkIndex != -1 ) {
+ // line = line.substring(0, linkIndex) + line.substring(linkIndex);
+ //}
+ formattedComment += line;
+ }
+ } catch ( IOException ioe ) {
+ throw new Error( "Couldn't format comment for declaration: " +
+ decl.getSignature() );
+ }
+ return formattedComment;
+ }
+
+ static String generateDesignatorHREFLink(Declaration decl) {
+ Declaration ccutDecl = decl.getCrosscutDeclaration();
+ if (ccutDecl != null) {
+ // !!! the following stuff should use ccutDecl
+ return
+ "<A HREF=" +
+ ccutDecl.getDeclaringType() + ".html#" + generateHREFName(ccutDecl) + ">" +
+ ccutDecl.getSignature() + "</A>";
+ }
+ else {
+ //String link = decl.getCrosscutDesignator();
+ //System.out.println(">> link: " + link);
+ //return
+ // "<A HREF=\"TransportAspect.html#" + generateHREFName( decl ) + "\">" +
+ // decl.getCrosscutDesignator() + "</A>";
+ //return null;
+ return null;
+ }
+ }
+
+
+ // *************************************************************************** //
+ // ** This stuff should be in Declaration ** //
+ // *************************************************************************** //
+
+ static Declaration getCrosscutDeclaration(Declaration decl) {
+ //String filename = "D:\\Projects\\AJDoc\\apples\\TransportAspect.java";
+ //Declaration[] decls = symbolManager.getDeclarations(filename);
+ //decls = decls[0].getDeclarations();
+ //return decls[decls.length-2]; !!!
+ return null;
+ }
+
+ static String getName(Declaration decl) {
+ return decl.getSignature();
+ }
+}
+
+
+ //
+ // !!! this stub only guaranteed to work for classes or interfaces
+ //
+ /*
+ static String getFullyQualifiedName(Declaration decl) {
+ if ( decl.getDeclaringType() == null )
+ return getName(decl);
+ else
+ return getFullyQualifiedName(decl.getDeclaringType()) + "$" + getName(decl);
+ }
+ */ \ No newline at end of file
diff --git a/ajdoc/src/org/aspectj/tools/ajdoc/SourceLine.java b/ajdoc/src/org/aspectj/tools/ajdoc/SourceLine.java
new file mode 100644
index 000000000..76a11c585
--- /dev/null
+++ b/ajdoc/src/org/aspectj/tools/ajdoc/SourceLine.java
@@ -0,0 +1,54 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * Mik Kersten port to AspectJ 1.1+ code base
+ * ******************************************************************/
+
+package org.aspectj.tools.ajdoc;
+import java.io.Serializable;
+import java.io.File;
+
+public class SourceLine implements Serializable {
+ public int line;
+ public String filename;
+ //boolean hasBody;
+
+ public SourceLine(String filename, int line) {
+ this.line = line;
+ this.filename = filename;
+ }
+
+ public String getDirectory() {
+ return new File(filename).getParent();
+ }
+
+ public int hashCode() {
+ return filename.hashCode() ^ line;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof SourceLine)) return false;
+
+ SourceLine otherLine = (SourceLine)other;
+
+ return otherLine.line == line && otherLine.filename.equals(filename);
+ }
+
+ public String toString() {
+ return filename + "::" + line;
+ }
+
+ /**
+ * @return true when the method has a corresponding signature in the source code
+ * @return false otherwise
+ */
+ //public boolean hasBody() { return hasBody; }
+}
diff --git a/ajdoc/src/org/aspectj/tools/ajdoc/SymbolManager.java b/ajdoc/src/org/aspectj/tools/ajdoc/SymbolManager.java
new file mode 100644
index 000000000..48fc339d5
--- /dev/null
+++ b/ajdoc/src/org/aspectj/tools/ajdoc/SymbolManager.java
@@ -0,0 +1,390 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * Mik Kersten port to AspectJ 1.1+ code base
+ * ******************************************************************/
+
+package org.aspectj.tools.ajdoc;
+
+
+import java.util.*;
+
+import org.aspectj.asm.*;
+
+
+
+
+public class SymbolManager {
+
+// public static File mapFilenameToSymbolFile(String filename) {
+// return mapFilenameToNewExtensionFile(filename, SYMBOL_FILE_EXTENSION);
+// }
+//
+// public static File mapFilenameToSourceLinesFile(String filename) {
+// return mapFilenameToNewExtensionFile(filename, SOURCE_LINES_FILE_EXTENSION);
+// }
+//
+// public static File getSourceToOutputFile(String dirname) {
+// return new File(dirname, ".ajsline");
+// }
+//
+// public static File getOutputToSourceFile(String dirname) {
+// return new File(dirname, ".ajoline");
+// }
+
+//
+// private static File mapFilenameToNewExtensionFile(String filename, String ext) {
+// int lastDot = filename.lastIndexOf('.');
+// String basename = filename;
+// if (lastDot != -1) {
+// basename = basename.substring(0, lastDot);
+// }
+//
+// return new File(basename+ext);
+// }
+
+ private static SymbolManager INSTANCE = new SymbolManager();
+
+ public static SymbolManager getDefault() {
+ return INSTANCE;
+ }
+
+ /**
+ * @param filePath the full path to the preprocessed source file
+ * @param lineNumber line number in the preprocessed source file
+ * @return the <CODE>SourceLine</CODE> corresponding to the original file/line
+ * @see SourceLine
+ */
+ public SourceLine mapToSourceLine(String filePath, int lineNumber) {
+ System.err.println("> mapping: " + filePath);
+ return null;
+// Map map = lookupOutputToSource(filePath);
+//
+// if (map == null) return null;
+//
+// return (SourceLine)map.get(new SourceLine(filePath, lineNumber));
+ }
+
+
+ /**
+ * @param filePath the full path to the original source file
+ * @param lineNumber line number in the original source file
+ * @return the <CODE>SourceLine</CODE> corresponding to the preprocessed file/line
+ * @see SourceLine
+ */
+ public SourceLine mapToOutputLine(String filePath, int lineNumber) {
+ return null;
+// Map map = lookupSourceToOutput(filePath);
+//
+// if (map == null) return null;
+//
+// return (SourceLine)map.get(new SourceLine(filePath, lineNumber));
+ }
+
+
+
+ /****
+ public int mapToOutputLine(String filename, int line) {
+ Vector sourceLines = lookupSourceLines(filename);
+
+ // do linear search here
+ if (sourceLines == null) return -1;
+
+ for(int outputLine = 0; outputLine < sourceLines.size(); outputLine++) {
+ SourceLine sl = (SourceLine)sourceLines.elementAt(outputLine);
+
+ if (sl == null) continue;
+ if (sl.line == line) {
+ String outputRoot = new File(filename).getName();
+ String sourceRoot = new File(sl.filename).getName();
+ if (outputRoot.equals(sourceRoot)) return outputLine + 1;
+ }
+ }
+
+ return -1;
+ }
+ ****/
+
+
+ /**
+ * TODO: only works for one class
+ */
+ public Declaration[] getDeclarations(String filename) {
+ IProgramElement file = (IProgramElement)AsmManager.getDefault().getHierarchy().findElementForSourceFile(filename);
+ IProgramElement node = (IProgramElement)file.getChildren().get(0);
+
+// Declaration[] decls = new Declaration[node.getChildren().size()+1];
+ final List nodes = new ArrayList();
+ HierarchyWalker walker = new HierarchyWalker() {
+ public void preProcess(IProgramElement node) {
+ IProgramElement p = (IProgramElement)node;
+ nodes.add(buildDecl(p));
+ }
+ };
+
+ file.walk(walker);
+
+ return (Declaration[])nodes.toArray(new Declaration[nodes.size()]);
+// return lookupDeclarations(filename);
+ }
+
+ private Declaration buildDecl(IProgramElement node) {
+ System.err.println("> getting decs: " + node);
+
+ String modifiers = "";
+ for (Iterator modIt = node.getModifiers().iterator(); modIt.hasNext(); ) {
+ modifiers += modIt.next() + " ";
+ }
+// Declaration dec = new Declaration(
+// node.getSourceLocation().getLine(),
+// node.getSourceLocation().getEndLine(),
+// node.getSourceLocation().getColumn(),
+// -1,
+// modifiers,
+// node.getName(),
+// node.getFullSignature(),
+// "",
+// node.getDeclaringType(),
+// node.getKind(),
+// node.getSourceLocation().getSourceFile().getAbsolutePath(),
+// node.getFormalComment(),
+// node.getPackageName()
+// );
+// return dec;
+ return null;
+ }
+
+
+
+
+// // In the unusual case that there are multiple declarations on a single line
+// // This will return a random one
+// public Declaration getDeclarationAtLine(String filename, int line) {
+// return getDeclarationAtPoint(filename, line, -1);
+// }
+
+ public Declaration getDeclarationAtPoint(String filename, int line, int column) {
+
+ Declaration[] declarations = lookupDeclarations(filename);
+ //System.out.println("getting "+filename+", "+line+":"+column);
+ //System.out.println("decs: "+declarations);
+ return getDeclarationAtPoint(declarations, line, column);
+ }
+
+ public Declaration getDeclarationAtPoint(Declaration[] declarations, int line, int column) {
+ //!!! when we care about the performance of this method
+ //!!! these should be guaranteed to be sorted and a binary search used here
+ //!!! for now we use the simple (and reliable) linear search
+ if (declarations == null) return null;
+
+ for(int i=0; i<declarations.length; i++) {
+ Declaration dec = declarations[i];
+ if (dec.getBeginLine() == line) { // && dec.getEndLine() >= line) {
+ if (column == -1) return dec;
+ if (dec.getBeginColumn() == column) { // && dec.getEndColumn() >= column) {
+ return dec;
+ }
+ }
+ Declaration[] enclosedDecs = dec.getDeclarations();
+ if (enclosedDecs.length == 0) continue;
+
+ Declaration dec1 = getDeclarationAtPoint(enclosedDecs, line, column);
+ if (dec1 != null) return dec1;
+ }
+
+ //??? what should be returned for no declaration found
+ return null;
+ }
+
+// private Hashtable symbolFileEntryCache = new Hashtable();
+
+ private Declaration[] lookupDeclarations(String filename) {
+ System.err.println("> looking up: " + filename);
+ return null;
+// CorrFileEntry entry = lookup(filename, mapFilenameToSymbolFile(filename),
+// symbolFileEntryCache);
+// return (Declaration[])entry.data;
+ }
+
+// private Hashtable sourceToOutputCache = new Hashtable();
+// private Hashtable outputToSourceCache = new Hashtable();
+
+// private Map lookupSourceToOutput(String filename) {
+// CorrFileEntry entry = lookup(filename,
+// getSourceToOutputFile(new File(filename).getParent()),
+// sourceToOutputCache);
+// return (Map)entry.data;
+// }
+
+// private Map lookupOutputToSource(String filename) {
+// CorrFileEntry entry = lookup(filename,
+// getOutputToSourceFile(new File(filename).getParent()),
+// outputToSourceCache);
+// return (Map)entry.data;
+// }
+
+ /* generic code for dealing with correlation files, serialization, and caching */
+// private static class CorrFileEntry {
+// public long lastModified;
+// public Object data;
+//
+// public CorrFileEntry(long lastModified, Object data) {
+// this.lastModified = lastModified;
+// this.data = data;
+// }
+// }
+
+// private CorrFileEntry lookup(String filename, File file, Hashtable cache) {
+// CorrFileEntry entry = (CorrFileEntry)cache.get(filename);
+// if (entry != null && entry.lastModified == file.lastModified()) {
+// return entry;
+// }
+//
+// entry = createCorrFileEntry(file);
+// cache.put(filename, entry);
+// return entry;
+// }
+
+// private CorrFileEntry createCorrFileEntry(File file) {
+// if (!file.exists()) {
+// return new CorrFileEntry(0l, null);
+// }
+//
+// try {
+// long lastModified = file.lastModified();
+// ObjectInputStream stream =
+// new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)));
+// Object data = stream.readObject();
+// stream.close();
+// return new CorrFileEntry(lastModified, data);
+// } catch (IOException ioe) {
+// //System.err.println("ERROR!!!");
+// //ioe.printStackTrace();
+// return new CorrFileEntry(0l, null);
+// } catch (ClassNotFoundException cce) {
+// //System.err.println("ERROR!!!");
+// //cce.printStackTrace();
+// return new CorrFileEntry(0l, null);
+// }
+// }
+
+
+ /**
+ * @param methodName method name without type or parameter list
+ * @return method name with ajc-specific name mangling removed,
+ * unchanged if there's not ajc name mangling present
+ */
+ public static String translateMethodName(String methodName) {
+ int firstDollar = methodName.indexOf('$');
+
+ if (firstDollar == -1) return methodName;
+
+ String baseName = methodName.substring(firstDollar);
+
+ if (methodName.indexOf("ajc") != -1) {
+ return "<" + baseName + " advice>";
+ } else {
+ return baseName;
+ }
+ }
+
+
+ /************************************************************************
+ The rest of the code in this file is just for testing purposes
+ ************************************************************************/
+
+// private static final void printIndentation(int indent, String prefix) {
+// for(int i=0; i< indent; i++) System.out.print(" ");
+// System.out.print(prefix);
+// }
+//
+//
+// private static final void printDeclaration(Declaration dec, int indent, String prefix) {
+// printIndentation(indent, prefix);
+// if (dec == null) {
+// System.out.println("null");
+// return;
+// }
+//
+// System.out.println(dec.getKind()+": "+dec.getDeclaringType()+": "+
+// dec.getModifiers()+": "+dec.getSignature()+": " +
+// //dec.getFullSignature()+": "+
+// dec.getCrosscutDesignator()+
+// ": "+dec.isIntroduced()+": "+dec.getPackageName()+": "+dec.getBeginLine()+":"+dec.getBeginColumn()
+// );
+//
+// //printIndentation(indent, "\"\"\"");
+// //System.out.println(dec.getFormalComment());
+// /*
+// if (dec.getParentDeclaration() != null) {
+// printDeclaration(dec.getParentDeclaration(), indent+INDENT, "PARENT ");
+// }
+// if (dec.getCrosscutDeclaration() != null) {
+// printDeclaration(dec.getCrosscutDeclaration(), indent+INDENT, "XC ");
+// }
+// */
+// if (prefix.equals("")) {
+// printDeclarations(dec.getTargets(), indent+INDENT, "T> ");
+// printDeclarations(dec.getPointsTo(), indent+INDENT, ">> ");
+// printDeclarations(dec.getPointedToBy(), indent+INDENT, "<< ");
+// printDeclarations(dec.getDeclarations(), indent+INDENT, "");
+// }
+// }
+
+// private static final void printDeclarations(Declaration[] decs, int indent, String prefix) {
+// for(int i=0; i<decs.length; i++) {
+// printDeclaration(decs[i], indent, prefix);
+// }
+// }
+
+// private static final int INDENT = 2;
+
+// static void printLines(String filename, Map baseMap) throws IOException {
+// if (baseMap == null) return;
+//
+// String fullName = new File(filename).getCanonicalPath();
+// java.util.TreeMap map = new java.util.TreeMap();
+//
+// for (Iterator i = baseMap.entrySet().iterator(); i.hasNext(); ) {
+// Map.Entry entry = (Map.Entry)i.next();
+// SourceLine keyLine = (SourceLine)entry.getKey();
+// if (!keyLine.filename.equals(fullName)) continue;
+//
+// map.put(new Integer(keyLine.line), entry.getValue());
+// }
+//
+// for (java.util.Iterator j = map.entrySet().iterator(); j.hasNext(); ) {
+// java.util.Map.Entry entry = (java.util.Map.Entry)j.next();
+//
+// System.out.println(entry.getKey() + ":\t" + entry.getValue());
+// }
+// }
+
+// public static void main(String[] args) throws IOException {
+// for(int i=0; i<args.length; i++) {
+// String filename = args[i];
+// System.out.println(filename);
+//
+// System.out.println("declaration mappings");
+// System.out.println("kind: declaringType: modifiers: signature: fullSignature: crosscutDesignator: isIntroduced: packageName: parentDeclaration");
+//
+// Declaration[] declarations = getSymbolManager().getDeclarations(filename);
+// if (declarations != null) {
+// printDeclarations(declarations, INDENT, "");
+// }
+//
+// System.out.println("source to output");
+// printLines(filename, getSymbolManager().lookupSourceToOutput(filename));
+// System.out.println("output to source");
+// printLines(filename, getSymbolManager().lookupOutputToSource(filename));
+// }
+// }
+}