]> source.dussan.org Git - aspectj.git/commitdiff
Lightweight ajdoc prototype.
authormkersten <mkersten>
Wed, 18 Feb 2004 16:12:54 +0000 (16:12 +0000)
committermkersten <mkersten>
Wed, 18 Feb 2004 16:12:54 +0000 (16:12 +0000)
23 files changed:
ajdoc/.classpath [new file with mode: 0644]
ajdoc/.project [new file with mode: 0644]
ajdoc/src/org/aspectj/tools/ajdoc/Config.java [new file with mode: 0644]
ajdoc/src/org/aspectj/tools/ajdoc/Declaration.java [new file with mode: 0644]
ajdoc/src/org/aspectj/tools/ajdoc/Main.java [new file with mode: 0644]
ajdoc/src/org/aspectj/tools/ajdoc/Phase1.java [new file with mode: 0644]
ajdoc/src/org/aspectj/tools/ajdoc/Phase2.java [new file with mode: 0644]
ajdoc/src/org/aspectj/tools/ajdoc/Phase3.java [new file with mode: 0644]
ajdoc/src/org/aspectj/tools/ajdoc/SourceLine.java [new file with mode: 0644]
ajdoc/src/org/aspectj/tools/ajdoc/SymbolManager.java [new file with mode: 0644]
ajdoc/testdata/figures-demo/.cvsignore [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures.lst [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures/Box.java [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures/Canvas.java [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures/ColorControl.java [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures/Enforcement.java [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures/FigureElement.java [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures/Group.java [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures/Line.java [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures/Log.java [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures/Point.java [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures/ShapeFigureElement.java [new file with mode: 0644]
ajdoc/testdata/figures-demo/figures/SlothfulPoint.java [new file with mode: 0644]

diff --git a/ajdoc/.classpath b/ajdoc/.classpath
new file mode 100644 (file)
index 0000000..bb44554
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+       <classpathentry kind="src" path="/asm"/>
+       <classpathentry kind="src" path="/org.aspectj.ajdt.core"/>
+       <classpathentry kind="src" path="/bridge"/>
+       <classpathentry kind="src" path="/util"/>
+       <classpathentry kind="lib" path="C:/Apps/j2sdk1.4.2/lib/tools.jar"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/ajdoc/.project b/ajdoc/.project
new file mode 100644 (file)
index 0000000..96913d3
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>ajdoc</name>
+       <comment></comment>
+       <projects>
+               <project>asm</project>
+               <project>bridge</project>
+               <project>org.aspectj.ajdt.core</project>
+               <project>util</project>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/ajdoc/src/org/aspectj/tools/ajdoc/Config.java b/ajdoc/src/org/aspectj/tools/ajdoc/Config.java
new file mode 100644 (file)
index 0000000..4224ed7
--- /dev/null
@@ -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 (file)
index 0000000..a68ad3b
--- /dev/null
@@ -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 (file)
index 0000000..25612ff
--- /dev/null
@@ -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 (file)
index 0000000..2c36403
--- /dev/null
@@ -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 (file)
index 0000000..303b74c
--- /dev/null
@@ -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 (file)
index 0000000..09d3e95
--- /dev/null
@@ -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 (file)
index 0000000..76a11c5
--- /dev/null
@@ -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 (file)
index 0000000..48fc339
--- /dev/null
@@ -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));
+//        }
+//    }
+}
diff --git a/ajdoc/testdata/figures-demo/.cvsignore b/ajdoc/testdata/figures-demo/.cvsignore
new file mode 100644 (file)
index 0000000..ad69a1a
--- /dev/null
@@ -0,0 +1 @@
+figures-demo-all.ajsym
diff --git a/ajdoc/testdata/figures-demo/figures.lst b/ajdoc/testdata/figures-demo/figures.lst
new file mode 100644 (file)
index 0000000..9e12310
--- /dev/null
@@ -0,0 +1,3 @@
+figures/*.java\r
+figures/support/*.java\r
+figures/gui/*.java\r
diff --git a/ajdoc/testdata/figures-demo/figures/Box.java b/ajdoc/testdata/figures-demo/figures/Box.java
new file mode 100644 (file)
index 0000000..4db7f43
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Box extends ShapeFigureElement {
+    private Point _p0;
+    private Point _p1;
+    private Point _p2;
+    private Point _p3;
+
+    public Box(int x0, int y0, int width, int height) {
+        _p0 = new Point(x0, y0);
+        _p1 = new Point(x0+width, y0);
+        _p2 = new Point(x0+width, y0+height);
+        _p3 = new Point(x0, y0+height);
+    }
+
+    public Point getP0() { return _p0; }
+    public Point getP1() { return _p1; }
+    public Point getP2() { return _p2; }
+    public Point getP3() { return _p3; }
+
+    public void move(int dx, int dy) {
+        _p0.move(dx, dy);
+        _p1.move(dx, dy);
+        _p2.move(dx, dy);
+        _p3.move(dx, dy);
+    }
+
+    public void checkBoxness() {
+        if ((_p0.getX() == _p3.getX()) &&
+            (_p1.getX() == _p2.getX()) &&
+            (_p0.getY() == _p1.getY()) &&
+            (_p2.getY() == _p3.getY()))
+          return;
+        throw new IllegalStateException("This is not a square.");
+    }
+
+    public String toString() {
+        return "Box(" + _p0 + ", " + _p1 + ", " + _p2 + ", " + _p3 + ")";
+    }
+
+    public Shape getShape() {
+        return new Rectangle(getP1().getX(),
+                             getP1().getY(),
+                             getP3().getX() - getP1().getX(),
+                             getP3().getY() - getP1().getY());
+    }
+}
+
diff --git a/ajdoc/testdata/figures-demo/figures/Canvas.java b/ajdoc/testdata/figures-demo/figures/Canvas.java
new file mode 100644 (file)
index 0000000..e5491d7
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+package figures;
+
+public class Canvas {
+       public static void updateHistory() {
+               // not implemented      
+       }
+}
diff --git a/ajdoc/testdata/figures-demo/figures/ColorControl.java b/ajdoc/testdata/figures-demo/figures/ColorControl.java
new file mode 100644 (file)
index 0000000..46d1ba4
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.Color;
+import figures.FigureElement;
+
+public aspect ColorControl {
+    public static void setFillColor(FigureElement fe, Color color) {
+       // fill in here
+    }
+
+    public static void setLineColor(FigureElement fe, Color color) {
+       // fill in here
+    }
+
+    // fill in here
+}
diff --git a/ajdoc/testdata/figures-demo/figures/Enforcement.java b/ajdoc/testdata/figures-demo/figures/Enforcement.java
new file mode 100644 (file)
index 0000000..95ea2e7
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * (c) Copyright 2001 MyCorporation.
+ * All Rights Reserved.
+ */
+package figures;
+
+public aspect Enforcement {
+
+       before(int newValue): set(int Point.*) && args(newValue) {
+               if (newValue < 0) {
+                               throw new IllegalArgumentException("> val: " + newValue + " is too small");
+               }       
+       }
+
+       declare warning: call(void Canvas.updateHistory(..)) && !within(Enforcement): "";
+
+       after() returning: call(void FigureElement+.set*(..)) {
+               //Canvas.updateHistory();       
+       }
+
+       declare error: 
+               set(private * FigureElement+.*) &&
+               !(withincode(* FigureElement+.set*(..)) || withincode(FigureElement+.new(..))):
+                       "should only assign to fileds from set methods";
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//     before(int newValue): set(int Point.*) && args(newValue) {
+//             if (newValue < 0) {
+//                     throw new IllegalArgumentException("> value: " + newValue + " too small");
+//             }
+//     }
+//
+//     declare warning: call(void Canvas.updateHistory(..)) && !within(Enforcement): 
+//             "found call";
+//
+//     after() returning: call(void FigureElement+.set*(..)) {
+//                     Canvas.updateHistory();
+//     }
+//     
+//     declare error: 
+//             set(private * FigureElement+.*) &&
+//             !(withincode(* FigureElement+.set*(..)) || withincode(FigureElement+.new(..))):
+//             "should only assign to fields from set methods";
diff --git a/ajdoc/testdata/figures-demo/figures/FigureElement.java b/ajdoc/testdata/figures-demo/figures/FigureElement.java
new file mode 100644 (file)
index 0000000..ae06c13
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public interface FigureElement {
+    public static final int MIN_VALUE = 0;
+    public static final int MAX_VALUE = 500;
+
+    public abstract void move(int dx, int dy);
+
+    public abstract Rectangle getBounds();
+
+    public abstract boolean contains(Point2D p);
+
+    public abstract void paint(Graphics2D g2);
+}
diff --git a/ajdoc/testdata/figures-demo/figures/Group.java b/ajdoc/testdata/figures-demo/figures/Group.java
new file mode 100644 (file)
index 0000000..59c1a17
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Group implements FigureElement {
+    private Collection _members;
+    private String _identifier;
+
+    public Group(FigureElement first) {
+        this._members = new ArrayList();
+        add(first);
+    }
+
+    public void add(FigureElement fe) {
+        _members.add(fe);
+    }
+
+    public Iterator members() {
+        return _members.iterator();
+    }
+
+    public void move(int dx, int dy) {
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            fe.move(dx, dy);
+        }
+    }
+
+    public void resetIdentifier(String identifier) {
+        resetIdentifier(identifier);
+    }
+
+    public String toString() {
+        if (_identifier != null) {
+            return _identifier;
+        }
+
+        StringBuffer buf = new StringBuffer("Group(");
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            buf.append(i.next().toString());
+            if (i.hasNext()) {
+                buf.append(", ");
+            }
+        }
+        buf.append(")");
+        return buf.toString();
+    }
+
+    public Rectangle getBounds() {
+        Rectangle previous = null;
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            Rectangle rect = fe.getBounds();
+            if (previous != null) {
+                previous = previous.union(rect);
+            } else {
+                previous = rect;
+            }
+        }
+        return previous;
+    }
+
+    public boolean contains(Point2D p) {
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            if (fe.contains(p)) return true;
+        }
+        return false;
+    }
+
+    public void paint(Graphics2D g2) {
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            fe.paint(g2);
+        }
+    }
+
+    public int size() {
+        return _members.size();
+    }
+}
+
diff --git a/ajdoc/testdata/figures-demo/figures/Line.java b/ajdoc/testdata/figures-demo/figures/Line.java
new file mode 100644 (file)
index 0000000..4532464
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Line extends ShapeFigureElement {
+    private Point _p1;
+    private Point _p2;
+
+    public Line(Point p1, Point p2) {
+        _p1 = p1;
+        _p2 = p2;
+    }
+
+    public Point getP1() { 
+       return _p1; 
+    }
+
+       public void setP1(Point p1) {
+               _p1 = p1;       
+               Canvas.updateHistory();
+       }
+    
+    public Point getP2() { 
+       return _p2; 
+    }
+
+       public void setP2(Point p2) {
+               _p2 = p2;       
+               Canvas.updateHistory();
+       }
+
+    public void move(int dx, int dy) {
+       //_x = dx;
+       //_y = dy;
+
+        //_p1.move(dx, dy);
+        //_p2.move(dx, dy);
+    }
+
+    public String toString() {
+        return "Line(" + _p1 + ", " + _p2 + ")";
+    }
+
+    /**
+     * Used to determine if this line {@link contains(Point2D)} a point.
+     */
+    final static int THRESHHOLD = 5;
+
+    /**
+     * Returns <code>true</code> if the point segment distance is less than
+     * {@link THRESHHOLD}.
+     */
+    public boolean contains(Point2D p) {
+        return getLine2D().ptLineDist(p) < THRESHHOLD;
+    }
+
+    private Line2D getLine2D() {
+       return new Line2D.Float((float)getP1().getX(),
+                                (float)getP1().getY(),
+                                (float)getP2().getX(),
+                                (float)getP2().getY());
+    }
+
+    public Shape getShape() {
+        return getLine2D();
+    }
+}
+
diff --git a/ajdoc/testdata/figures-demo/figures/Log.java b/ajdoc/testdata/figures-demo/figures/Log.java
new file mode 100644 (file)
index 0000000..ed6e061
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+public class Log {
+    private static StringBuffer data = new StringBuffer();
+
+    public static void traceObject(Object o) {
+        throw new UnsupportedOperationException();
+    }
+
+    public static void log(String s) {
+        data.append(s);
+        data.append(';');
+    }
+
+    public static void logClassName(Class _class) {
+        String name = _class.getName();
+        int dot = name.lastIndexOf('.');
+        if (dot == -1) {
+            log(name);
+        } else {
+            log(name.substring(dot+1, name.length()));
+        }
+    }
+
+    public static String getString() {
+        return data.toString();
+    }
+
+    public static void clear() {
+        data.setLength(0);
+    }
+}
diff --git a/ajdoc/testdata/figures-demo/figures/Point.java b/ajdoc/testdata/figures-demo/figures/Point.java
new file mode 100644 (file)
index 0000000..e8783a5
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Point extends ShapeFigureElement {
+    private int _x;
+    private int _y;
+
+    public Point(int x, int y) {
+        _x = x;
+        _y = y;
+    }
+
+    public int getX() { 
+       return _x; 
+    }
+
+    public void setX(int x) { 
+       _x = x; 
+               //Canvas.updateHistory();
+    }
+
+    public int getY() { 
+       return _y; 
+    }
+
+    public void setY(int y) { 
+       _y = y; 
+       //Canvas.updateHistory();
+    }
+
+    public void move(int dx, int dy) {
+        setX(_x + dx);
+        setY(_y + dy);
+    }
+
+    public String toString() {
+        return "Point(" + _x + ", " + _y + ")";
+    }
+
+    /** The height of displayed {@link Point}s. */
+    private final static int HEIGHT = 10;
+
+    /** The width of displayed {@link Point}s. -- same as {@link HEIGHT}. */
+    private final static int WIDTH  = Point.HEIGHT;
+
+    public Shape getShape() {
+       return new Ellipse2D.Float((float)getX()-Point.WIDTH/2,
+                                   (float)getY()-Point.HEIGHT/2,
+                                   (float)Point.HEIGHT,
+                                   (float)Point.WIDTH);
+    }
+}
+
diff --git a/ajdoc/testdata/figures-demo/figures/ShapeFigureElement.java b/ajdoc/testdata/figures-demo/figures/ShapeFigureElement.java
new file mode 100644 (file)
index 0000000..29a4a89
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public abstract class ShapeFigureElement implements FigureElement {
+    public abstract void move(int dx, int dy);
+
+    public abstract Shape getShape();
+
+    public Rectangle getBounds() {
+        return getShape().getBounds();
+    }
+
+    public boolean contains(Point2D p) {
+        return getShape().contains(p);
+    }
+
+    public Color getLineColor() {
+        return Color.black;
+    }
+
+    public Color getFillColor() {
+        return Color.red;
+    }
+
+    public final void paint(Graphics2D g2) {
+        Shape shape = getShape();
+        g2.setPaint(getFillColor());
+        g2.fill(shape);
+        g2.setPaint(getLineColor());
+        g2.draw(shape);
+    }
+}
diff --git a/ajdoc/testdata/figures-demo/figures/SlothfulPoint.java b/ajdoc/testdata/figures-demo/figures/SlothfulPoint.java
new file mode 100644 (file)
index 0000000..35c8fb6
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+/**
+ * This class makes mistakes to be caught by invariant checkers.
+ */
+public class SlothfulPoint extends ShapeFigureElement {
+    private int _x;
+    private int _y;
+
+    public SlothfulPoint(int x, int y) {
+    }
+
+    public void setX(int x) { 
+       _x = x; 
+    }
+    
+    public void setY(int y) { 
+       _y = y; 
+    }
+
+    public void move(int dx, int dy) {
+       //_x += dx;
+       //_y += dy;
+    }
+
+    public String toString() {
+        return "SlothfulPoint";
+    }
+
+    public Shape getShape() {
+       return new Ellipse2D.Float((float)_x,
+                                   (float)_y, 1.0f, 1.0f);
+    }
+}
+