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