]> source.dussan.org Git - aspectj.git/commitdiff
move weaving to inside of the compiler.compile loop.
authoracolyer <acolyer>
Mon, 15 Mar 2004 15:10:46 +0000 (15:10 +0000)
committeracolyer <acolyer>
Mon, 15 Mar 2004 15:10:46 +0000 (15:10 +0000)
ensure messages are associated with source wherever possible

16 files changed:
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjClassFile.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompiler.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ClassFileBasedByteCodeProvider.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IIntermediateResultsRequestor.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IOutputClassFileNameProvider.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/InterimCompilationResult.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverAdapter.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverMessageHandler.java [new file with mode: 0644]
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceLocation.java
weaver/src/org/aspectj/weaver/ResolvedTypeX.java
weaver/src/org/aspectj/weaver/World.java
weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java
weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java
weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java
weaver/src/org/aspectj/weaver/bcel/UnwovenClassFileWithThirdPartyManagedBytecode.java [new file with mode: 0644]

diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjClassFile.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjClassFile.java
new file mode 100644 (file)
index 0000000..ef4a4a4
--- /dev/null
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+import org.eclipse.jdt.internal.compiler.ClassFile;
+
+/**
+ * @author colyer
+ *
+ * XXX lightweight subclass of ClassFile that only genuinely supports fileName and getBytes
+ * operations. This nasty hack enables us to keep the rest of the implementation much simpler.
+ */
+public class AjClassFile extends ClassFile {
+       char[] filename;
+       byte[] bytes;
+
+       public AjClassFile(char[] fileName, byte[] byteCodes) {
+               this.filename = fileName;
+               bytes = byteCodes;
+       }
+       
+       public char[] fileName() {
+               return filename;
+       }
+
+       public byte[] getBytes() {
+               return bytes;
+       }
+}
index 2fce1117f07a942c85b0a87d021ca8b825f9cae3..fef05581cff84d643ec8a6d26a7149673637989b 100644 (file)
-/* *******************************************************************
- * Copyright (c) 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: 
- *     PARC     initial implementation 
- * ******************************************************************/
-
-
-package org.aspectj.ajdt.internal.compiler;
-
-import java.util.Map;
-
-import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
-import org.aspectj.bridge.IMessage;
-import org.eclipse.jdt.internal.compiler.Compiler;
-import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
-import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
-import org.eclipse.jdt.internal.compiler.IProblemFactory;
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
-
-
-public class AjCompiler extends Compiler {
-
-       public AjCompiler(
-               INameEnvironment environment,
-               IErrorHandlingPolicy policy,
-               Map settings,
-               ICompilerRequestor requestor,
-               IProblemFactory problemFactory) {
-               super(environment, policy, settings, requestor, problemFactory);
-       }
-
-       public AjCompiler(
-               INameEnvironment environment,
-               IErrorHandlingPolicy policy,
-               Map settings,
-               ICompilerRequestor requestor,
-               IProblemFactory problemFactory,
-               boolean parseLiteralExpressionsAsConstants) {
-               super(
-                       environment,
-                       policy,
-                       settings,
-                       requestor,
-                       problemFactory,
-                       parseLiteralExpressionsAsConstants);
-       }
-       
-       /**
-        * In addition to processing each compilation unit in the normal ways, 
-        * we also need to do weaving for inter-type declarations.  This
-        * must be done before we use the signatures of these types to do any
-        * name binding.
-        */
-       public void process(CompilationUnitDeclaration unit, int i) {
-               EclipseFactory world = 
-                       EclipseFactory.fromLookupEnvironment(lookupEnvironment);
-               world.showMessage(IMessage.INFO, "compiling " + new String(unit.getFileName()), null, null);
-               super.process(unit, i);
-                               
-               world.finishedCompilationUnit(unit);
-       }
-}
+///* *******************************************************************
+// * Copyright (c) 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: 
+// *     PARC     initial implementation 
+// * ******************************************************************/
+//
+//
+//package org.aspectj.ajdt.internal.compiler;
+//
+//import java.io.IOException;
+//import java.util.ArrayList;
+//import java.util.Collection;
+//import java.util.Collections;
+//import java.util.Enumeration;
+//import java.util.Hashtable;
+//import java.util.Iterator;
+//import java.util.List;
+//import java.util.Map;
+//
+//import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
+//import org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceLocation;
+//import org.aspectj.bridge.AbortException;
+//import org.aspectj.bridge.IMessage;
+//import org.aspectj.bridge.IMessageHandler;
+//import org.aspectj.bridge.ISourceLocation;
+//import org.aspectj.bridge.IMessage.Kind;
+//import org.aspectj.weaver.IClassFileProvider;
+//import org.aspectj.weaver.IWeaveRequestor;
+//import org.aspectj.weaver.bcel.BcelWeaver;
+//import org.aspectj.weaver.bcel.BcelWorld;
+//import org.aspectj.weaver.bcel.Pause;
+//import org.aspectj.weaver.bcel.UnwovenClassFile;
+//import org.aspectj.weaver.bcel.UnwovenClassFileWithThirdPartyManagedBytecode;
+//import org.eclipse.jdt.core.compiler.IProblem;
+//import org.eclipse.jdt.internal.compiler.ClassFile;
+//import org.eclipse.jdt.internal.compiler.CompilationResult;
+//import org.eclipse.jdt.internal.compiler.Compiler;
+//import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
+//import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
+//import org.eclipse.jdt.internal.compiler.IProblemFactory;
+//import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+//import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+//import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+//import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+//import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
+//import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
+//
+//
+//public class AjCompiler extends Compiler {
+//     
+//     private List /*InterimResult*/ resultsPendingWeave = new ArrayList();
+//     private BcelWorld bcelWorld;
+//     private BcelWeaver bcelWeaver;
+//     private IIntermediateResultsRequestor intermediateResultRequestor;
+//     private IOutputClassFileNameProvider nameProvider;
+//     private List /*<InterimResult>*/ binarySources = new ArrayList();
+//     private boolean skipTheWeavePhase = false;
+//     private boolean reportedErrors = false;
+//     private WeaverMessageHandler wmHandler;
+//     private boolean isBatchCompile = false;
+//     private Collection /*InterimResult*/ resultSetForFullWeave = Collections.EMPTY_LIST;
+//     
+//     public interface IIntermediateResultsRequestor {
+//             void acceptResult(InterimResult intRes);
+//     }
+//     
+//     public interface IOutputClassFileNameProvider {
+//             String getOutputClassFileName(char[] eclipseClassFileName, CompilationResult result);
+//     }
+//     
+//     public AjCompiler(
+//             INameEnvironment environment,
+//             IErrorHandlingPolicy policy,
+//             Map settings,
+//             ICompilerRequestor requestor,
+//             IProblemFactory problemFactory) {
+//             super(environment, policy, settings, requestor, problemFactory);
+//     }
+//
+//     public AjCompiler(
+//             INameEnvironment environment,
+//             IErrorHandlingPolicy policy,
+//             Map settings,
+//             ICompilerRequestor requestor,
+//             IProblemFactory problemFactory,
+//             boolean parseLiteralExpressionsAsConstants) {
+//             super(
+//                     environment,
+//                     policy,
+//                     settings,
+//                     requestor,
+//                     problemFactory,
+//                     parseLiteralExpressionsAsConstants);
+//     }
+//     
+//             
+//     public void setWeaver(BcelWeaver weaver) {
+//             this.bcelWeaver = weaver;
+//     }
+//
+//     public void setWorld(BcelWorld world) {
+//             this.bcelWorld = world;
+//             IMessageHandler msgHandler = world.getMessageHandler();
+//             wmHandler = new WeaverMessageHandler(msgHandler);
+//             world.setMessageHandler(wmHandler);
+//     }
+//
+//     public void prepareForBatchCompilation() {
+//             isBatchCompile = true;
+//     }
+//     
+//     public void setIntermediateResultsRequestor(IIntermediateResultsRequestor intReq) {
+//             this.intermediateResultRequestor = intReq;
+//     }
+//     
+//     public void setNoWeave(boolean noWeave) {
+//             skipTheWeavePhase = noWeave;
+//     }
+//     
+//     public void setFullWeaveResults(Collection compilationResults) {
+//             resultSetForFullWeave = compilationResults;
+//     }
+//     
+//     public void setOutputFileNameProvider(IOutputClassFileNameProvider p) {
+//             this.nameProvider = p;
+//     }
+//     
+//     public void addBinarySourceFiles(Map binarySourceEntries) {
+//             // Map is fileName |-> List<UnwovenClassFile>
+//             for (Iterator binIter = binarySourceEntries.keySet().iterator(); binIter.hasNext();) {
+//                     String sourceFileName = (String) binIter.next();
+//                     List unwovenClassFiles = (List) binarySourceEntries.get(sourceFileName);
+//                     
+//                     CompilationResult result = new CompilationResult(sourceFileName.toCharArray(),0,0,20);
+//                     result.noSourceAvailable();
+//                     InterimResult binarySource = new InterimResult(result,nameProvider);
+//                     binarySource.unwovenClassFiles = new UnwovenClassFile[unwovenClassFiles.size()];
+//                     int index = 0;
+//                     for (Iterator iter = unwovenClassFiles.iterator(); iter.hasNext();) {
+//                             UnwovenClassFile element = (UnwovenClassFile) iter.next();
+//                             binarySource.unwovenClassFiles[index] = element;
+//                             AjClassFile ajcf = new AjClassFile(element.getClassName().replace('.', '/').toCharArray(),
+//                                                                                                element.getBytes());
+//                             result.record(ajcf.fileName(),ajcf); 
+//                             index++;
+//                     }
+//                     binarySources.add(binarySource);
+//             }
+//     }
+//     
+//     
+//     /**
+//      * In addition to processing each compilation unit in the normal ways, 
+//      * we also need to do weaving for inter-type declarations.  This
+//      * must be done before we use the signatures of these types to do any
+//      * name binding.
+//      */
+//     public void process(CompilationUnitDeclaration unit, int i) {
+//             EclipseFactory world = 
+//                     EclipseFactory.fromLookupEnvironment(lookupEnvironment);
+//             world.showMessage(IMessage.INFO, "compiling " + new String(unit.getFileName()), null, null);
+//             super.process(unit, i);
+//                             
+//             world.finishedCompilationUnit(unit);
+//     }
+//     
+//     
+//     /* (non-Javadoc)
+//      * @see org.eclipse.jdt.internal.compiler.Compiler#compile(org.eclipse.jdt.internal.compiler.env.ICompilationUnit[])
+//      * We override this method to defer handing of results to the caller until the weave phase has 
+//      * completed too. That way the class files are in final form and all error messages relating to the
+//      * compilation unit have been reported (which is the contract the JDT expects from this method).
+//      */
+//     public void compile(ICompilationUnit[] sourceUnits) {
+//             try {
+//                     resultsPendingWeave = new ArrayList();
+//                     reportedErrors = false;
+//                     super.compile(sourceUnits);
+//                     Pause.pause("After super compile");
+//                     try {
+//                             if (!(skipTheWeavePhase || reportedErrors))  {
+//                                     weaveResults();
+//                                     Pause.pause("After weave");
+//                             } else {
+//                                     notifyRequestor();  // weaver notifies as it goes along...
+//                             }
+//                     } catch (IOException ex) {
+//                             // TODO
+//                             ex.printStackTrace();
+//                     }
+//             } finally {
+//                     cleanup();
+//             }
+//     }
+//     
+//     
+//     /* (non-Javadoc)
+//      * @see org.eclipse.jdt.internal.compiler.Compiler#registerCompilationResult(org.eclipse.jdt.internal.compiler.CompilationResult)
+//      */
+//     protected void registerCompilationResult(int index, CompilationResult result) {
+//             InterimResult intRes = new InterimResult(result,nameProvider);
+//             resultsPendingWeave.add(intRes);
+//             if (result.hasErrors()) reportedErrors = true;
+//             if (intermediateResultRequestor != null) {
+//                     intermediateResultRequestor.acceptResult(intRes);
+//             }
+//     }
+//     
+//     /* (non-Javadoc)
+//      * @see org.eclipse.jdt.internal.compiler.Compiler#reset()
+//      * Super does this too early for us...
+//      */
+//     public void reset() {
+//             // no-op, super calls this too early for us...
+//     }
+//     
+//     /* (non-Javadoc)
+//      * @see org.eclipse.jdt.internal.compiler.Compiler#resolve(org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration, org.eclipse.jdt.internal.compiler.env.ICompilationUnit, boolean, boolean, boolean)
+//      */
+//     public CompilationUnitDeclaration resolve(CompilationUnitDeclaration unit,
+//                     ICompilationUnit sourceUnit, boolean verifyMethods,
+//                     boolean analyzeCode, boolean generateCode) {
+//             // TODO include weave phase in resolution too...
+//             return super.resolve(unit, sourceUnit, verifyMethods, analyzeCode,
+//                             generateCode);
+//     }
+//     
+//     
+//     // AspectJ helper methods, called from compile...
+//     private void weaveResults() throws IOException {
+//             // ensure weaver state is set up correctly
+//             for (Iterator iter = resultsPendingWeave.iterator(); iter.hasNext();) {
+//                     InterimResult iresult = (InterimResult) iter.next();
+//                     for (int i = 0; i < iresult.unwovenClassFiles.length; i++) {
+//                             bcelWeaver.addClassFile(iresult.unwovenClassFiles[i]);
+//                     }                       
+//             }
+//             Pause.pause("After adding class files to weaver");
+//             bcelWeaver.prepareForWeave();
+//             Pause.pause("After preparing for weave");
+//             if (isBatchCompile) {
+//                     resultsPendingWeave.addAll(binarySources);  
+//                     // passed into the compiler, the set of classes in injars and inpath...
+//             } else if (bcelWeaver.needToReweaveWorld()) {
+//                     addAllKnownClassesToWeaveList();
+//             }
+//             Pause.pause("After adding binary sources to weaver");
+//             bcelWeaver.weave(new WeaverAdaptor(this));
+//     }
+//     
+//     private void notifyRequestor() {
+//             for (Iterator iter = resultsPendingWeave.iterator(); iter.hasNext();) {
+//                     InterimResult iresult = (InterimResult) iter.next();
+//                     requestor.acceptResult(iresult.result.tagAsAccepted());
+//             }
+//     }
+//     
+//     private void cleanup() {
+//             resultsPendingWeave = null;
+//             isBatchCompile = false;
+//             binarySources = new ArrayList();
+//             resultSetForFullWeave = Collections.EMPTY_LIST;
+//             super.reset();
+//             Pause.pause("After notify and cleanup");
+//     }
+//     
+//     private void addAllKnownClassesToWeaveList() {
+//             // results pending weave already has some results from this (incremental) compile
+//             // add in results from any other source
+//             for (Iterator iter = resultSetForFullWeave.iterator(); iter.hasNext();) {
+//                     InterimResult ir = (InterimResult) iter.next();
+//                     if (!resultsPendingWeave.contains(ir)) {  // equality based on source file name...
+//                             ir.result.hasBeenAccepted = false;  // it may have been accepted before, start again
+//                             resultsPendingWeave.add(ir);
+//                     }                       
+//             }
+//     }
+//     
+//     // Helper class that feeds input to the weaver, and accepts results
+//     // =======================================================================================
+//     private static class WeaverAdaptor implements IClassFileProvider, IWeaveRequestor, Iterator {
+//             
+//             private AjCompiler compiler;
+//             private Iterator resultIterator;
+//             private int classFileIndex = 0;
+//             private InterimResult nowProcessing;
+//             private InterimResult lastReturnedResult;
+////           private CompilationResult lastAcceptedResult;
+//             private boolean finalPhase = false;
+//             
+//             
+//             public WeaverAdaptor(AjCompiler forCompiler) { this.compiler = forCompiler; }
+//             
+//             /* (non-Javadoc)
+//              * @see org.aspectj.weaver.IClassFileProvider#getClassFileIterator()
+//              */
+//             public Iterator getClassFileIterator() {
+//                     classFileIndex = 0;
+//                     nowProcessing = null;
+//                     lastReturnedResult = null;
+//                     resultIterator = compiler.resultsPendingWeave.iterator();
+//                     return this;
+//             }
+//             /* (non-Javadoc)
+//              * @see org.aspectj.weaver.IClassFileProvider#getRequestor()
+//              */
+//             public IWeaveRequestor getRequestor() {
+//                     return this;
+//             }
+//             /* (non-Javadoc)
+//              * @see org.aspectj.weaver.IWeaveRequestor#acceptResult(org.aspectj.weaver.bcel.UnwovenClassFile)
+//              */
+//             public void acceptResult(UnwovenClassFile result) {
+//                     char[] key = result.getClassName().replace('.','/').toCharArray();
+//                     removeFromHashtable(lastReturnedResult.result.compiledTypes,key);
+//                     String className = result.getClassName().replace('.', '/');
+//                     AjClassFile ajcf = new AjClassFile(className.toCharArray(),
+//                                                                                        result.getBytes());
+//                     lastReturnedResult.result.record(ajcf.fileName(),ajcf);
+////                   if ( f(lastAcceptedResult != null) && (lastReturnedResult.result != lastAcceptedResult)) {
+////                           // we've got everything we need for lastAcceptedResult, push the result out
+////                           // and free up the memory.
+////                           finishedWith(lastAcceptedResult);
+////                   }
+////                   lastAcceptedResult = lastReturnedResult.result;
+//             }
+//             
+//             private void finishedWith(InterimResult result) {
+//                     compiler.requestor.acceptResult(result.result.tagAsAccepted());
+//                     for (int i = 0; i < compiler.unitsToProcess.length; i++) {
+//                             if (compiler.unitsToProcess[i] != null) {
+//                                     if (compiler.unitsToProcess[i].compilationResult == result.result) {
+//                                             compiler.unitsToProcess[i] = null;
+//                                     }
+//                             }
+//                     }
+//             }
+//             
+//             /* (non-Javadoc)
+//              * @see java.util.Iterator#hasNext()
+//              */
+//             public boolean hasNext() {
+//                     if (nowProcessing == null) {
+//                             if (!resultIterator.hasNext()) return false;
+//                             nowProcessing = (InterimResult) resultIterator.next();
+//                             classFileIndex = 0;
+//                     }
+//                     while (nowProcessing.unwovenClassFiles.length == 0 ) {
+//                             if (!resultIterator.hasNext()) return false;
+//                             nowProcessing = (InterimResult) resultIterator.next();
+//                     }
+//                     if (classFileIndex < nowProcessing.unwovenClassFiles.length) {
+//                             return true;
+//                     } else {
+//                             classFileIndex = 0;
+//                             if (!resultIterator.hasNext()) return false;
+//                             nowProcessing = (InterimResult) resultIterator.next();
+//                             while (nowProcessing.unwovenClassFiles.length == 0 ) {
+//                                     if (!resultIterator.hasNext()) return false;
+//                                     nowProcessing = (InterimResult) resultIterator.next();
+//                             } 
+//                     }
+//                     return true;
+//             }
+//             /* (non-Javadoc)
+//              * @see java.util.Iterator#next()
+//              */
+//             public Object next() {
+//                     if (!hasNext()) return null;  // sets up indices correctly
+//                     if (finalPhase) {
+//                             if ((lastReturnedResult != null) && (lastReturnedResult != nowProcessing)) {
+//                                     // we're done with the lastReturnedResult
+//                                     finishedWith(lastReturnedResult);
+//                             }
+//                     }
+//                     lastReturnedResult = nowProcessing;
+//                     compiler.wmHandler.setCurrentResult(nowProcessing.result);
+//                     return nowProcessing.unwovenClassFiles[classFileIndex++];
+//             }
+//             /* (non-Javadoc)
+//              * @see java.util.Iterator#remove()
+//              */
+//             public void remove() {
+//                     throw new UnsupportedOperationException();
+//             }
+//             
+//             public void processingReweavableState() {}
+//             public void addingTypeMungers() {}
+//             public void weavingAspects() {}
+//             public void weavingClasses() {finalPhase = true;}
+//             public void weaveCompleted() {
+//                     if ((lastReturnedResult != null) && (!lastReturnedResult.result.hasBeenAccepted)) {
+//                             finishedWith(lastReturnedResult);
+//                     }
+//             }
+//             
+//             private void removeFromHashtable(Hashtable table, char[] key) {
+//                     // jdt uses char[] as a key in the hashtable, which is not very useful as equality is based on being
+//                     // the same array, not having the same content.
+//                     String skey = new String(key);
+//                     char[] victim = null;
+//                     for (Enumeration iter = table.keys(); iter.hasMoreElements();) {
+//                             char[] thisKey = (char[]) iter.nextElement();
+//                             if (skey.equals(new String(thisKey))) {
+//                                     victim = thisKey;
+//                                     break;
+//                             }
+//                     }
+//                     if (victim != null) {
+//                             table.remove(victim);
+//                     }
+//             }
+//}
+//     
+//     // Holder for intermediate form (class files)
+//     // =======================================================================================
+//     public static class InterimResult {
+//       public CompilationResult result;
+//       public UnwovenClassFile[] unwovenClassFiles;  // longer term would be nice not to have two copies of
+//                                                     // the byte codes, one in result.classFiles and another
+//                                                     // in unwovenClassFiles;
+//       private AjCompiler.IOutputClassFileNameProvider nameGen;
+////     public String[] classNames;  // entry at index i is the name of the class at unwovenClassFiles[i]
+////     public BcelObjectType[] classTypes; // entry at i is the resolved type of the class at unwovenClassFiles[i]
+//       public InterimResult(CompilationResult cr, AjCompiler.IOutputClassFileNameProvider np) {
+//             result = cr;
+//             nameGen = np;
+//             unwovenClassFiles = ClassFileBasedByteCodeProvider.unwovenClassFilesFor(result,nameGen);
+//       }
+//       
+//       public String fileName() {
+//             return new String(result.fileName);
+//       }
+//       
+//      public boolean equals(Object other) {
+//                     if( other == null || !(other instanceof InterimResult)) {
+//                             return false;
+//                     }
+//                     InterimResult ir = (InterimResult) other;
+//                     return fileName().equals(ir.fileName());
+//       }
+//       public int hashCode() {
+//                     return fileName().hashCode();
+//       }
+//     };
+//     
+//     
+//     
+//     // XXX lightweight subclass of ClassFile that only genuinely supports fileName and getBytes
+//     // operations.
+//     // =========================================================================================
+//     private static class AjClassFile extends ClassFile {
+//             
+//             char[] filename;
+//             byte[] bytes;
+//     
+//             public AjClassFile(char[] fileName, byte[] byteCodes) {
+//                     this.filename = fileName;
+//                     bytes = byteCodes;
+//             }
+//             
+//             public char[] fileName() {
+//                     return filename;
+//             }
+//
+//             public byte[] getBytes() {
+//                     return bytes;
+//             }
+//     };
+//     
+//     
+//     // Adaptor for ClassFiles that lets them act as the bytecode repository
+//     // for UnwovenClassFiles (asking a ClassFile for its bytes causes a 
+//     // copy to be made).
+//     private static class ClassFileBasedByteCodeProvider 
+//                    implements UnwovenClassFileWithThirdPartyManagedBytecode.IByteCodeProvider {
+//             private ClassFile cf;
+//             
+//             public ClassFileBasedByteCodeProvider(ClassFile cf) {
+//                     this.cf = cf;
+//             }
+//             
+//             public byte[] getBytes() {
+//                     return cf.getBytes();
+//             }
+//             
+//             public static UnwovenClassFile[] unwovenClassFilesFor(CompilationResult result, 
+//                                                                                     AjCompiler.IOutputClassFileNameProvider nameProvider) {
+//                     ClassFile[] cfs = result.getClassFiles();
+//                     UnwovenClassFile[] ret = new UnwovenClassFile[cfs.length];
+//                     for (int i = 0; i < ret.length; i++) {
+//                             ClassFileBasedByteCodeProvider p = new ClassFileBasedByteCodeProvider(cfs[i]);
+//                             String fileName = nameProvider.getOutputClassFileName(cfs[i].fileName(), result);
+//                             ret[i] = new UnwovenClassFileWithThirdPartyManagedBytecode(fileName,p);
+//                     }
+//                     return ret;
+//             }
+//             
+//     }
+//     
+//     // Inner class for handling messages produced by the weaver
+//     // ==========================================================
+//     
+//     private class WeaverMessageHandler implements IMessageHandler {
+//             IMessageHandler sink;
+//             CompilationResult currentlyWeaving;
+//             
+//             public WeaverMessageHandler(IMessageHandler handler) {
+//                     this.sink = handler;
+//             }
+//             
+//             public void setCurrentResult(CompilationResult result) {
+//                     currentlyWeaving = result;
+//             }
+//
+//             public boolean handleMessage(IMessage message) throws AbortException {
+//                     if (! (message.isError() || message.isWarning()) ) return sink.handleMessage(message);
+//                     // we only care about warnings and errors here...
+//                     ISourceLocation sLoc = message.getSourceLocation();
+//                     CompilationResult problemSource = currentlyWeaving;
+//                     if (problemSource == null) {
+//                             // must be a problem found during completeTypeBindings phase of begin to compile
+//                             if (sLoc instanceof EclipseSourceLocation) {
+//                                     problemSource = ((EclipseSourceLocation)sLoc).getCompilationResult();
+//                             }
+//                             if (problemSource == null) {
+//                                     // XXX this is ok for ajc, will have to do better for AJDT in time...
+//                                     return sink.handleMessage(message);
+//                             }
+//                     }
+//                     int startPos = getStartPos(sLoc,problemSource);
+//                     int endPos = getEndPos(sLoc,problemSource);
+//                     int severity = message.isError() ? ProblemSeverities.Error : ProblemSeverities.Warning;
+//                     char[] filename = problemSource.fileName;
+//                     boolean usedBinarySourceFileName = false;
+//                     if (problemSource.isFromBinarySource()) {
+//                             if (sLoc != null) {
+//                                     filename = sLoc.getSourceFile().getPath().toCharArray();
+//                                     usedBinarySourceFileName = true;
+//                             }
+//                     }
+//                     ReferenceContext referenceContext = findReferenceContextFor(problemSource);
+//                     IProblem problem = problemReporter.createProblem(
+//                                                                     filename,
+//                                                                     IProblem.Unclassified,
+//                                                                     new String[0],
+//                                                                     new String[] {message.getMessage()},
+//                                                                     severity,
+//                                                                     startPos,
+//                                                                     endPos,
+//                                                                     sLoc != null ? sLoc.getLine() : 1,
+//                                                                     referenceContext,
+//                                                                     problemSource
+//                                                                     );
+//                     IProblem[] seeAlso = buildSeeAlsoProblems(message.getExtraSourceLocations(),
+//                                                                                                       problemSource,        
+//                                                                                                       usedBinarySourceFileName);
+//                     problem.setSeeAlsoProblems(seeAlso);
+//                     if (message.getDetails() != null) {
+//                             problem.setSupplementaryMessageInfo(message.getDetails());
+//                     }
+//                     problemReporter.record(problem, problemSource, referenceContext);
+//                     return true;
+////                   if (weavingPhase) {
+////                           return sink.handleMessage(message); 
+////                   } else {
+////                           return true;  // message will be reported back in compilation result later...
+////                   }
+//             }
+//
+//             public boolean isIgnoring(Kind kind) {
+//                     return sink.isIgnoring(kind);
+//             }
+//             
+//             private int getStartPos(ISourceLocation sLoc,CompilationResult result) {
+//                     int pos = 0;
+//                     if (sLoc == null) return 0;
+//                     int line = sLoc.getLine();
+//                     if (sLoc instanceof EclipseSourceLocation) {
+//                             pos = ((EclipseSourceLocation)sLoc).getStartPos();
+//                     } else {
+//                             if (line <= 1) return 0;
+//                             if (result != null) {
+//                                     if ((result.lineSeparatorPositions != null) && 
+//                                             (result.lineSeparatorPositions.length >= (line-1))) {
+//                                             pos = result.lineSeparatorPositions[line-2] + 1;
+//                                     }
+//                             }
+//                     }
+//                     return pos;
+//             }
+//
+//             private int getEndPos(ISourceLocation sLoc,CompilationResult result) {
+//                     int pos = 0;
+//                     if (sLoc == null) return 0;
+//                     int line = sLoc.getLine();
+//                     if (line <= 0) line = 1;
+//                     if (sLoc instanceof EclipseSourceLocation) {
+//                             pos = ((EclipseSourceLocation)sLoc).getEndPos();
+//                     } else {
+//                             if (result != null) {
+//                                     if ((result.lineSeparatorPositions != null) && 
+//                                             (result.lineSeparatorPositions.length >= line)) {
+//                                             pos = result.lineSeparatorPositions[line -1] -1;
+//                                     }
+//                             }
+//                     }
+//                     return pos;
+//             }
+//     
+//             private ReferenceContext findReferenceContextFor(CompilationResult result) {
+//                     ReferenceContext context = null;
+//                     if (unitsToProcess == null) return null;
+//                     for (int i = 0; i < unitsToProcess.length; i++) {
+//                             if ((unitsToProcess[i] != null) &&
+//                                 (unitsToProcess[i].compilationResult == result)) {
+//                                     context = unitsToProcess[i];
+//                                     break;
+//                             }                               
+//                     }
+//                     return context;
+//             }
+//             
+//             private IProblem[] buildSeeAlsoProblems(List sourceLocations,
+//                                                                                             CompilationResult problemSource,
+//                                                                                             boolean usedBinarySourceFileName) {
+//                     int probLength = sourceLocations.size();
+//                     if (usedBinarySourceFileName) probLength++;
+//                     IProblem[] ret = new IProblem[probLength];
+//                     for (int i = 0; i < sourceLocations.size(); i++) {
+//                             ISourceLocation loc = (ISourceLocation) sourceLocations.get(i);
+//                             ret[i] = new DefaultProblem(loc.getSourceFile().getPath().toCharArray(),
+//                                                                                     "see also",
+//                                                                                     0,
+//                                                                                     new String[] {},
+//                                                                                     ProblemSeverities.Ignore,
+//                                                                                     getStartPos(loc,null),
+//                                                                                     getEndPos(loc,null),
+//                                                                                     loc.getLine());
+//                     }
+//                     if (usedBinarySourceFileName) {
+//                             ret[ret.length -1] = new DefaultProblem(problemSource.fileName,"see also",0,new String[] {},
+//                                                                                                             ProblemSeverities.Ignore,0,
+//                                                                                                             0,0);
+//                     }
+//                     return ret;
+//             }
+//     }
+//     
+//}
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java
new file mode 100644 (file)
index 0000000..ab3cebd
--- /dev/null
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.weaver.bcel.BcelWeaver;
+import org.aspectj.weaver.bcel.BcelWorld;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.ICompilerAdapter;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
+
+/**
+ * @author colyer
+ *
+ * Adapts standard JDT Compiler to add in AspectJ specific behaviours.
+ */
+public class AjCompilerAdapter implements ICompilerAdapter {
+
+       private Compiler compiler;
+       private BcelWeaver weaver;
+       private EclipseFactory eWorld;
+       private boolean isBatchCompile;
+       private boolean reportedErrors;
+       private boolean isXNoWeave;
+       private IIntermediateResultsRequestor intermediateResultsRequestor;
+       private IOutputClassFileNameProvider outputFileNameProvider;
+       private WeaverMessageHandler weaverMessageHandler;
+       private List /* InterimCompilationResult */ binarySources = new ArrayList();
+       private Collection /*InterimCompilationResult*/ resultSetForFullWeave = Collections.EMPTY_LIST;
+
+       
+       List /*InterimResult*/ resultsPendingWeave = new ArrayList();
+
+       /**
+        * Create an adapter, and tell it everything it needs to now to drive the AspectJ
+        * parts of a compile cycle.
+        * @param compiler      the JDT compiler that produces class files from source
+        * @param isBatchCompile  true if this is a full build (non-incremental)
+        * @param world  the bcelWorld used for type resolution during weaving
+        * @param weaver the weaver
+        * @param intRequestor  recipient of interim compilation results from compiler (pre-weave)
+        * @param outputFileNameProvider implementor of a strategy providing output file names for results
+        * @param binarySourceEntries binary source that we didn't compile, but that we need to weave
+        * @param resultSetForFullWeave if we are doing an incremental build, and the weaver determines
+        *                              that we need to weave the world, this is the set of intermediate
+        *                              results that will be passed to the weaver.
+        * @param isXNoWeave
+        */
+       public AjCompilerAdapter(Compiler compiler,
+                                                        boolean isBatchCompile,
+                                                        BcelWorld world,
+                                                        BcelWeaver weaver,
+                                                        EclipseFactory eFactory,
+                                                        IIntermediateResultsRequestor intRequestor,
+                                                        IOutputClassFileNameProvider outputFileNameProvider,
+                                                        Map binarySourceEntries, /* fileName |-> List<UnwovenClassFile> */
+                                                        Collection /* InterimCompilationResult */ resultSetForFullWeave,
+                                                        boolean isXNoWeave) {
+               this.compiler = compiler;
+               this.isBatchCompile = isBatchCompile;
+               this.weaver = weaver;
+               this.intermediateResultsRequestor = intRequestor;
+               this.outputFileNameProvider = outputFileNameProvider;
+               this.isXNoWeave = isXNoWeave;
+               this.resultSetForFullWeave = resultSetForFullWeave;
+               this.eWorld = eFactory;
+               
+               IMessageHandler msgHandler = world.getMessageHandler();
+               weaverMessageHandler = new WeaverMessageHandler(msgHandler, compiler);
+               world.setMessageHandler(weaverMessageHandler);
+               
+               addBinarySource(binarySourceEntries);
+       }
+       
+       public void beforeCompiling(ICompilationUnit[] sourceUnits) {
+               resultsPendingWeave = new ArrayList();
+               reportedErrors = false;         
+       }
+
+       public void afterCompiling() {
+               try {
+                       if (isXNoWeave || reportedErrors) {
+                               // no point weaving... just tell the requestor we're done
+                               notifyRequestor();
+                       } else {
+                               weave();  // notification happens as weave progresses...
+                       }
+               } catch (IOException ex) {
+                       AbortCompilation ac = new AbortCompilation();
+                       ac.initCause(ex);
+                       throw ac;
+               } 
+       }
+
+       public void beforeProcessing(CompilationUnitDeclaration unit) {
+               eWorld.showMessage(IMessage.INFO, "compiling " + new String(unit.getFileName()), null, null);
+       }
+
+       public void afterProcessing(CompilationUnitDeclaration unit, int unitIndex) {
+               eWorld.finishedCompilationUnit(unit);
+               InterimCompilationResult intRes = new InterimCompilationResult(unit.compilationResult,outputFileNameProvider);
+               if (unit.compilationResult.hasErrors()) reportedErrors = true;
+               
+               if (intermediateResultsRequestor != null) {
+                       intermediateResultsRequestor.acceptResult(intRes);
+               }
+               
+               if (isXNoWeave) {
+                       acceptResult(unit.compilationResult);
+               } else {
+                       resultsPendingWeave.add(intRes);
+               }
+       }
+       
+       public void beforeResolving(CompilationUnitDeclaration unit, ICompilationUnit sourceUnit, boolean verifyMethods, boolean analyzeCode, boolean generateCode) {
+               resultsPendingWeave = new ArrayList();
+               reportedErrors = false;         
+       }
+
+       public void afterResolving(CompilationUnitDeclaration unit, ICompilationUnit sourceUnit, boolean verifyMethods, boolean analyzeCode, boolean generateCode) {
+               InterimCompilationResult intRes = new InterimCompilationResult(unit.compilationResult,outputFileNameProvider);
+               if (unit.compilationResult.hasErrors()) reportedErrors = true;
+               if (isXNoWeave || !generateCode) {
+                       acceptResult(unit.compilationResult);
+               } else if (generateCode){
+                       resultsPendingWeave.add(intRes);
+                       try {
+                         weave();
+                       } catch (IOException ex) {
+                               AbortCompilation ac = new AbortCompilation();
+                               ac.initCause(ex);
+                               throw ac;
+                       } 
+               }
+       }
+       
+       // helper methods...
+       // ==================================================================================
+       
+       /*
+        * Called from the weaverAdapter once it has finished weaving the class files
+        * associated with a given compilation result.
+        */
+       public void acceptResult(CompilationResult result) {
+               compiler.requestor.acceptResult(result.tagAsAccepted());
+               if (compiler.unitsToProcess != null) {
+                       for (int i = 0; i < compiler.unitsToProcess.length; i++) {
+                               if (compiler.unitsToProcess[i] != null) {
+                                       if (compiler.unitsToProcess[i].compilationResult == result) {
+                                               compiler.unitsToProcess[i] = null;
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       private void addBinarySource(Map binarySourceEntries) {
+               // Map is fileName |-> List<UnwovenClassFile>
+               for (Iterator binIter = binarySourceEntries.keySet().iterator(); binIter.hasNext();) {
+                       String sourceFileName = (String) binIter.next();
+                       List unwovenClassFiles = (List) binarySourceEntries.get(sourceFileName);
+                       
+                       CompilationResult result = new CompilationResult(sourceFileName.toCharArray(),0,0,20);
+                       result.noSourceAvailable();
+                       InterimCompilationResult binarySource = 
+                               new InterimCompilationResult(result,unwovenClassFiles);
+                       binarySources.add(binarySource);
+               }
+       }
+       
+       private void notifyRequestor() {
+               for (Iterator iter = resultsPendingWeave.iterator(); iter.hasNext();) {
+                       InterimCompilationResult iresult = (InterimCompilationResult) iter.next();
+                       compiler.requestor.acceptResult(iresult.result().tagAsAccepted());
+               }
+       }
+               
+       private void weave() throws IOException {
+               // ensure weaver state is set up correctly
+               for (Iterator iter = resultsPendingWeave.iterator(); iter.hasNext();) {
+                       InterimCompilationResult iresult = (InterimCompilationResult) iter.next();
+                       for (int i = 0; i < iresult.unwovenClassFiles().length; i++) {
+                               weaver.addClassFile(iresult.unwovenClassFiles()[i]);
+                       }                       
+               }
+
+               weaver.prepareForWeave();
+
+               if (isBatchCompile) {
+                       resultsPendingWeave.addAll(binarySources);  
+                       // passed into the compiler, the set of classes in injars and inpath...
+               } else if (weaver.needToReweaveWorld()) {
+                       addAllKnownClassesToWeaveList();
+               }
+
+               weaver.weave(new WeaverAdapter(this,weaverMessageHandler));
+       }
+       
+       private void addAllKnownClassesToWeaveList() {
+               // results pending weave already has some results from this (incremental) compile
+               // add in results from any other source
+               for (Iterator iter = resultSetForFullWeave.iterator(); iter.hasNext();) {
+                       InterimCompilationResult ir = (InterimCompilationResult) iter.next();
+                       if (!resultsPendingWeave.contains(ir)) {  // equality based on source file name...
+                               ir.result().hasBeenAccepted = false;  // it may have been accepted before, start again
+                               resultsPendingWeave.add(ir);
+                       }                       
+               }
+       }
+}
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ClassFileBasedByteCodeProvider.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ClassFileBasedByteCodeProvider.java
new file mode 100644 (file)
index 0000000..57a64a8
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+import org.aspectj.weaver.bcel.UnwovenClassFile;
+import org.aspectj.weaver.bcel.UnwovenClassFileWithThirdPartyManagedBytecode;
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+
+/**
+ * @author colyer
+ *
+ *     Adaptor for ClassFiles that lets them act as the bytecode repository
+ *     for UnwovenClassFiles (asking a ClassFile for its bytes causes a 
+ *     copy to be made).
+ */
+public class ClassFileBasedByteCodeProvider 
+          implements UnwovenClassFileWithThirdPartyManagedBytecode.IByteCodeProvider{
+       
+       private ClassFile cf;
+               
+       public ClassFileBasedByteCodeProvider(ClassFile cf) {
+               this.cf = cf;
+       }
+               
+       public byte[] getBytes() {
+               return cf.getBytes();
+       }
+               
+       public static UnwovenClassFile[] unwovenClassFilesFor(CompilationResult result, 
+                                                                                           IOutputClassFileNameProvider nameProvider) {
+               ClassFile[] cfs = result.getClassFiles();
+               UnwovenClassFile[] ret = new UnwovenClassFile[cfs.length];
+               for (int i = 0; i < ret.length; i++) {
+                       ClassFileBasedByteCodeProvider p = new ClassFileBasedByteCodeProvider(cfs[i]);
+                       String fileName = nameProvider.getOutputClassFileName(cfs[i].fileName(), result);
+                       ret[i] = new UnwovenClassFileWithThirdPartyManagedBytecode(fileName,p);
+               }
+               return ret;
+       }
+               
+}
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IIntermediateResultsRequestor.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IIntermediateResultsRequestor.java
new file mode 100644 (file)
index 0000000..c97c20d
--- /dev/null
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+/**
+ * @author colyer
+ *
+ * Receives intermediate results from the compiler (post java-compile, but
+ * before weaving).
+ */
+public interface IIntermediateResultsRequestor {
+       void acceptResult(InterimCompilationResult intRes);
+}
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IOutputClassFileNameProvider.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/IOutputClassFileNameProvider.java
new file mode 100644 (file)
index 0000000..125d9ce
--- /dev/null
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+
+/**
+ * @author colyer
+ * 
+ * Implementors of this interface know how to create an output destination name
+ * for a given compilation result and class file. This interface capures the variation
+ * in strategy between ajc command-line compiles and an AJDT driven compilation.
+ */
+public interface IOutputClassFileNameProvider {
+       String getOutputClassFileName(char[] eclipseClassFileName, CompilationResult result);
+}
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/InterimCompilationResult.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/InterimCompilationResult.java
new file mode 100644 (file)
index 0000000..3e72d7c
--- /dev/null
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+import java.util.List;
+
+import org.aspectj.weaver.bcel.UnwovenClassFile;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+
+/**
+ * Holds a compilation result produced by the Java compilation phase,
+ * ready for weaving in the weave phase.
+ * NOTE: This class defines equality based solely on the fileName 
+ * of the compiled file (not the bytecodes produced for example)
+ */
+public class InterimCompilationResult {
+       
+         private CompilationResult result;
+         private UnwovenClassFile[] unwovenClassFiles;  // longer term would be nice not to have two copies of
+                                                       // the byte codes, one in result.classFiles and another
+                                                       // in unwovenClassFiles;
+
+         public InterimCompilationResult(CompilationResult cr, 
+                                                                         IOutputClassFileNameProvider np) {
+               result = cr;
+               unwovenClassFiles = ClassFileBasedByteCodeProvider.unwovenClassFilesFor(result,np);
+         }
+         
+         public InterimCompilationResult(CompilationResult cr, List ucfList) {
+               result = cr;
+               unwovenClassFiles = new UnwovenClassFile[ucfList.size()];
+               for (int i=0; i < ucfList.size(); i++) {
+                       UnwovenClassFile element = (UnwovenClassFile) ucfList.get(i);
+                       unwovenClassFiles[i] = element;
+                       AjClassFile ajcf = new AjClassFile(element.getClassName().replace('.', '/').toCharArray(),
+                                                                                          element.getBytes());
+                       result.record(ajcf.fileName(),ajcf); 
+               }               
+         }
+         
+         public CompilationResult result() { return result; }
+         
+         public UnwovenClassFile[] unwovenClassFiles() { return unwovenClassFiles; }
+         
+         public String fileName() {
+               return new String(result.fileName);
+         }
+         
+      public boolean equals(Object other) {
+                       if( other == null || !(other instanceof InterimCompilationResult)) {
+                               return false;
+                       }
+                       InterimCompilationResult ir = (InterimCompilationResult) other;
+                       return fileName().equals(ir.fileName());
+         }
+         public int hashCode() {
+                       return fileName().hashCode();
+         }
+               
+}
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverAdapter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverAdapter.java
new file mode 100644 (file)
index 0000000..6eead00
--- /dev/null
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import org.aspectj.weaver.IClassFileProvider;
+import org.aspectj.weaver.IWeaveRequestor;
+import org.aspectj.weaver.bcel.UnwovenClassFile;
+
+/**
+ * @author colyer
+ * This class provides the weaver with a source of class files to weave (via the 
+ * iterator and IClassFileProvider interfaces). It receives results back from the
+ * weaver via the IWeaveRequestor interface.
+ */
+public class WeaverAdapter implements IClassFileProvider, IWeaveRequestor, Iterator {
+       
+       private AjCompilerAdapter compilerAdapter;
+       private Iterator resultIterator;
+       private int classFileIndex = 0;
+       private InterimCompilationResult nowProcessing;
+       private InterimCompilationResult lastReturnedResult;
+       private WeaverMessageHandler weaverMessageHandler;
+       private boolean finalPhase = false;
+       
+       
+       public WeaverAdapter(AjCompilerAdapter forCompiler,
+                                                WeaverMessageHandler weaverMessageHandler) { 
+               this.compilerAdapter = forCompiler; 
+               this.weaverMessageHandler = weaverMessageHandler;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.IClassFileProvider#getClassFileIterator()
+        */
+       public Iterator getClassFileIterator() {
+               classFileIndex = 0;
+               nowProcessing = null;
+               lastReturnedResult = null;
+               resultIterator = compilerAdapter.resultsPendingWeave.iterator();
+               return this;
+       }
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.IClassFileProvider#getRequestor()
+        */
+       public IWeaveRequestor getRequestor() {
+               return this;
+       }
+       
+       // Iteration
+       // ================================================================
+       
+       /* (non-Javadoc)
+        * @see java.util.Iterator#hasNext()
+        */
+       public boolean hasNext() {
+               if (nowProcessing == null) {
+                       if (!resultIterator.hasNext()) return false;
+                       nowProcessing = (InterimCompilationResult) resultIterator.next();
+                       classFileIndex = 0;
+               }
+               while (nowProcessing.unwovenClassFiles().length == 0 ) {
+                       if (!resultIterator.hasNext()) return false;
+                       nowProcessing = (InterimCompilationResult) resultIterator.next();
+               }
+               if (classFileIndex < nowProcessing.unwovenClassFiles().length) {
+                       return true;
+               } else {
+                       classFileIndex = 0;
+                       if (!resultIterator.hasNext()) return false;
+                       nowProcessing = (InterimCompilationResult) resultIterator.next();
+                       while (nowProcessing.unwovenClassFiles().length == 0 ) {
+                               if (!resultIterator.hasNext()) return false;
+                               nowProcessing = (InterimCompilationResult) resultIterator.next();
+                       } 
+               }
+               return true;
+       }
+       /* (non-Javadoc)
+        * @see java.util.Iterator#next()
+        */
+       public Object next() {
+               if (!hasNext()) return null;  // sets up indices correctly
+               if (finalPhase) {
+                       if ((lastReturnedResult != null) && (lastReturnedResult != nowProcessing)) {
+                               // we're done with the lastReturnedResult
+                               finishedWith(lastReturnedResult);
+                       }
+               }
+               lastReturnedResult = nowProcessing;
+               weaverMessageHandler.setCurrentResult(nowProcessing.result());
+               return nowProcessing.unwovenClassFiles()[classFileIndex++];
+       }
+       /* (non-Javadoc)
+        * @see java.util.Iterator#remove()
+        */
+       public void remove() {
+               throw new UnsupportedOperationException();
+       }
+       
+       
+       // IWeaveRequestor
+       // =====================================================================================
+       
+       // weave phases as indicated by bcelWeaver...
+       public void processingReweavableState() {}
+       public void addingTypeMungers() {}
+       public void weavingAspects() {}
+       public void weavingClasses() {finalPhase = true;}
+       
+       public void weaveCompleted() {
+               if ((lastReturnedResult != null) && (!lastReturnedResult.result().hasBeenAccepted)) {
+                       finishedWith(lastReturnedResult);
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.IWeaveRequestor#acceptResult(org.aspectj.weaver.bcel.UnwovenClassFile)
+        */
+       public void acceptResult(UnwovenClassFile result) {
+               char[] key = result.getClassName().replace('.','/').toCharArray();
+               removeFromHashtable(lastReturnedResult.result().compiledTypes,key);
+               String className = result.getClassName().replace('.', '/');
+               AjClassFile ajcf = new AjClassFile(className.toCharArray(),
+                                                                                  result.getBytes());
+               lastReturnedResult.result().record(ajcf.fileName(),ajcf);
+       }
+
+       // helpers...
+       // =================================================================
+       
+       private void finishedWith(InterimCompilationResult result) {
+               compilerAdapter.acceptResult(result.result());
+       }
+       
+       private void removeFromHashtable(Hashtable table, char[] key) {
+               // jdt uses char[] as a key in the hashtable, which is not very useful as equality is based on being
+               // the same array, not having the same content.
+               String skey = new String(key);
+               char[] victim = null;
+               for (Enumeration iter = table.keys(); iter.hasMoreElements();) {
+                       char[] thisKey = (char[]) iter.nextElement();
+                       if (skey.equals(new String(thisKey))) {
+                               victim = thisKey;
+                               break;
+                       }
+               }
+               if (victim != null) {
+                       table.remove(victim);
+               }
+       }
+}
\ No newline at end of file
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverMessageHandler.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/WeaverMessageHandler.java
new file mode 100644 (file)
index 0000000..399eddc
--- /dev/null
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.ajdt.internal.compiler;
+
+import java.util.List;
+
+import org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceLocation;
+import org.aspectj.bridge.AbortException;
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.bridge.ISourceLocation;
+import org.aspectj.bridge.IMessage.Kind;
+import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
+import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
+
+/**
+ * @author colyer
+ *
+ * To change the template for this generated type comment go to
+ * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
+ */
+public class WeaverMessageHandler implements IMessageHandler {
+       private IMessageHandler sink;
+       private CompilationResult currentlyWeaving;
+       private Compiler compiler;
+       
+       public WeaverMessageHandler(IMessageHandler handler, Compiler compiler) {
+               this.sink = handler;
+               this.compiler = compiler;
+       }
+       
+       public void setCurrentResult(CompilationResult result) {
+               currentlyWeaving = result;
+       }
+
+       public boolean handleMessage(IMessage message) throws AbortException {
+               if (! (message.isError() || message.isWarning()) ) return sink.handleMessage(message);
+               // we only care about warnings and errors here...
+               ISourceLocation sLoc = message.getSourceLocation();
+               CompilationResult problemSource = currentlyWeaving;
+               if (problemSource == null) {
+                       // must be a problem found during completeTypeBindings phase of begin to compile
+                       if (sLoc instanceof EclipseSourceLocation) {
+                               problemSource = ((EclipseSourceLocation)sLoc).getCompilationResult();
+                       }
+                       if (problemSource == null) {
+                               // XXX this is ok for ajc, will have to do better for AJDT in time...
+                               return sink.handleMessage(message);
+                       }
+               }
+               int startPos = getStartPos(sLoc,problemSource);
+               int endPos = getEndPos(sLoc,problemSource);
+               int severity = message.isError() ? ProblemSeverities.Error : ProblemSeverities.Warning;
+               char[] filename = problemSource.fileName;
+               boolean usedBinarySourceFileName = false;
+               if (problemSource.isFromBinarySource()) {
+                       if (sLoc != null) {
+                               filename = sLoc.getSourceFile().getPath().toCharArray();
+                               usedBinarySourceFileName = true;
+                       }
+               }
+               ReferenceContext referenceContext = findReferenceContextFor(problemSource);
+               IProblem problem = compiler.problemReporter.createProblem(
+                                                               filename,
+                                                               IProblem.Unclassified,
+                                                               new String[0],
+                                                               new String[] {message.getMessage()},
+                                                               severity,
+                                                               startPos,
+                                                               endPos,
+                                                               sLoc != null ? sLoc.getLine() : 1,
+                                                               referenceContext,
+                                                               problemSource
+                                                               );
+               IProblem[] seeAlso = buildSeeAlsoProblems(message.getExtraSourceLocations(),
+                                                                                                 problemSource,        
+                                                                                                 usedBinarySourceFileName);
+               problem.setSeeAlsoProblems(seeAlso);
+               if (message.getDetails() != null) {
+                       problem.setSupplementaryMessageInfo(message.getDetails());
+               }
+               compiler.problemReporter.record(problem, problemSource, referenceContext);
+               return true;
+       }
+
+       public boolean isIgnoring(Kind kind) {
+               return sink.isIgnoring(kind);
+       }
+       
+       private int getStartPos(ISourceLocation sLoc,CompilationResult result) {
+               int pos = 0;
+               if (sLoc == null) return 0;
+               int line = sLoc.getLine();
+               if (sLoc instanceof EclipseSourceLocation) {
+                       pos = ((EclipseSourceLocation)sLoc).getStartPos();
+               } else {
+                       if (line <= 1) return 0;
+                       if (result != null) {
+                               if ((result.lineSeparatorPositions != null) && 
+                                       (result.lineSeparatorPositions.length >= (line-1))) {
+                                       pos = result.lineSeparatorPositions[line-2] + 1;
+                               }
+                       }
+               }
+               return pos;
+       }
+
+       private int getEndPos(ISourceLocation sLoc,CompilationResult result) {
+               int pos = 0;
+               if (sLoc == null) return 0;
+               int line = sLoc.getLine();
+               if (line <= 0) line = 1;
+               if (sLoc instanceof EclipseSourceLocation) {
+                       pos = ((EclipseSourceLocation)sLoc).getEndPos();
+               } else {
+                       if (result != null) {
+                               if ((result.lineSeparatorPositions != null) && 
+                                       (result.lineSeparatorPositions.length >= line)) {
+                                       pos = result.lineSeparatorPositions[line -1] -1;
+                               }
+                       }
+               }
+               return pos;
+       }
+
+       private ReferenceContext findReferenceContextFor(CompilationResult result) {
+               ReferenceContext context = null;
+               if (compiler.unitsToProcess == null) return null;
+               for (int i = 0; i < compiler.unitsToProcess.length; i++) {
+                       if ((compiler.unitsToProcess[i] != null) &&
+                           (compiler.unitsToProcess[i].compilationResult == result)) {
+                               context = compiler.unitsToProcess[i];
+                               break;
+                       }                               
+               }
+               return context;
+       }
+       
+       private IProblem[] buildSeeAlsoProblems(List sourceLocations,
+                                                                                       CompilationResult problemSource,
+                                                                                       boolean usedBinarySourceFileName) {
+               int probLength = sourceLocations.size();
+               if (usedBinarySourceFileName) probLength++;
+               IProblem[] ret = new IProblem[probLength];
+               for (int i = 0; i < sourceLocations.size(); i++) {
+                       ISourceLocation loc = (ISourceLocation) sourceLocations.get(i);
+                       ret[i] = new DefaultProblem(loc.getSourceFile().getPath().toCharArray(),
+                                                                               "see also",
+                                                                               0,
+                                                                               new String[] {},
+                                                                               ProblemSeverities.Ignore,
+                                                                               getStartPos(loc,null),
+                                                                               getEndPos(loc,null),
+                                                                               loc.getLine());
+               }
+               if (usedBinarySourceFileName) {
+                       ret[ret.length -1] = new DefaultProblem(problemSource.fileName,"see also",0,new String[] {},
+                                                                                                       ProblemSeverities.Ignore,0,
+                                                                                                       0,0);
+               }
+               return ret;
+       }
+}
+
index 43f2b8ee3988ad6b6e742b73cbfddefd16fdd844..377f90474ff3890047a41a5aa0f2c025bef19168 100644 (file)
@@ -39,6 +39,18 @@ public class EclipseSourceLocation implements ISourceLocation {
                this.startPos = startPos;
                this.endPos = endPos;
        }
+       
+       public CompilationResult getCompilationResult() {
+               return result;
+       }
+       
+       public int getStartPos() {
+               return startPos;
+       }
+       
+       public int getEndPos() {
+               return endPos;
+       }
 
        public File getSourceFile() {
                if (null == file) {
index 81327819ea6ab989aade3fd93601a4e2aed5f4c9..15c86bdbb6ed24b11151031e264ec1a9ed422f91 100644 (file)
@@ -577,7 +577,7 @@ public abstract class ResolvedTypeX extends TypeX {
                }
 
                public boolean isExposedToWeaver() {
-                       return delegate.isExposedToWeaver();  //??? where does this belong
+                       return (delegate == null) || delegate.isExposedToWeaver();  //??? where does this belong
                }
                
                public WeaverStateInfo getWeaverState() {
@@ -652,7 +652,7 @@ public abstract class ResolvedTypeX extends TypeX {
     public static abstract class ConcreteName {
        //protected ISourceContext sourceContext;
        protected boolean exposedToWeaver;
-       ResolvedTypeX.Name resolvedTypeX;
+       protected ResolvedTypeX.Name resolvedTypeX;
        
 
         public ConcreteName(ResolvedTypeX.Name resolvedTypeX, boolean exposedToWeaver) {
index 4817785328c990a3827c4187c16fa42a98b42095..0d019fd1c8362ae8753ba62b01d72493a1092582 100644 (file)
@@ -18,6 +18,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.WeakHashMap;
 
 import org.aspectj.asm.IHierarchy;
 import org.aspectj.bridge.IMessageHandler;
@@ -32,7 +33,7 @@ public abstract class World {
        protected IMessageHandler messageHandler = IMessageHandler.SYSTEM_ERR;
        protected ICrossReferenceHandler xrefHandler = null;
 
-    protected Map typeMap = new HashMap(); // Signature to ResolvedType
+    protected TypeMap typeMap = new TypeMap(); // Signature to ResolvedType
     
     protected CrosscuttingMembersSet crosscuttingMembersSet = new CrosscuttingMembersSet(this);
     
@@ -72,7 +73,7 @@ public abstract class World {
     public ResolvedTypeX resolve(TypeX ty, boolean allowMissing) {
        //System.out.println("resolve: " + ty + " world " + typeMap.keySet());
         String signature = ty.getSignature();
-        ResolvedTypeX ret = (ResolvedTypeX)typeMap.get(signature);
+        ResolvedTypeX ret = typeMap.get(signature);
         if (ret != null) return ret;
         
         if (ty.isArray()) {
@@ -387,5 +388,75 @@ public abstract class World {
         
                return ret;
        }
-
+       
+//     public void clearUnexposed() {
+//             List toRemove = new ArrayList();
+//             for (Iterator iter = typeMap.keySet().iterator(); iter.hasNext();) {
+//                     String sig = (String) iter.next();
+//                     ResolvedTypeX x = (ResolvedTypeX) typeMap.get(sig);
+//                     if (!x.isExposedToWeaver() && (!x.isPrimitive())) toRemove.add(sig);
+//             }               
+//             for (Iterator iter = toRemove.iterator(); iter.hasNext();) {
+//                     typeMap.remove(iter.next());            
+//             }
+//     }
+//     
+//     // for testing...
+//     public void dumpTypeMap() {
+//             int exposed = 0;
+//             for (Iterator iter = typeMap.keySet().iterator(); iter.hasNext();) {
+//                     String sig = (String) iter.next();
+//                     ResolvedTypeX x = (ResolvedTypeX) typeMap.get(sig);
+//                     if (x.isExposedToWeaver()) exposed++;
+//             }
+//             System.out.println("type map contains " + typeMap.size() + " entries, " + exposed + " exposed to weaver");
+//     }
+//     
+//     public void deepDumpTypeMap() {
+//             for (Iterator iter = typeMap.keySet().iterator(); iter.hasNext();) {
+//                     String sig = (String) iter.next();
+//                     ResolvedTypeX x = (ResolvedTypeX) typeMap.get(sig);
+//                     if (! (x instanceof ResolvedTypeX.Name)) {
+//                             System.out.println(sig + " -> " + x.getClass().getName() + ", " + x.getClassName());
+//                     } else {
+//                             ResolvedTypeX.ConcreteName cname = ((ResolvedTypeX.Name)x).getDelegate();
+//                             System.out.println(sig + " -> " + cname.getClass().getName() + ", " + cname.toString());
+//                     }
+//             }
+//             
+//     }
+       
+       // Map of types in the world, with soft links to expendable ones
+       protected static class TypeMap {
+               private Map tMap = new HashMap();
+               private Map expendableMap = new WeakHashMap();
+                                       
+               public ResolvedTypeX put(String key, ResolvedTypeX type) {
+                       if (isExpendable(type))  {
+                               return (ResolvedTypeX) expendableMap.put(key,type);
+                       } else {
+                               return (ResolvedTypeX) tMap.put(key,type);
+                       }
+               }
+               
+               public ResolvedTypeX get(String key) {
+                       ResolvedTypeX ret = (ResolvedTypeX) tMap.get(key);
+                       if (ret == null) ret = (ResolvedTypeX) expendableMap.get(key);
+                       return ret;
+               }
+               
+               public ResolvedTypeX remove(String key) {
+                       ResolvedTypeX ret = (ResolvedTypeX) tMap.remove(key);
+                       if (ret == null) ret = (ResolvedTypeX) expendableMap.remove(key);
+                       return ret;
+               }
+               
+               private boolean isExpendable(ResolvedTypeX type) {
+                       return (
+                                         (type != null) &&
+                                         (!type.isExposedToWeaver()) &&
+                                         (!type.isPrimitive())
+                                       );
+               }
+       }       
 }
index 7c6ddb9fd8e8728bc785a47b23a71d433b146a0a..e0997573ae2c586a66383b54adcbb1298c5ee654 100644 (file)
@@ -285,7 +285,7 @@ class BcelClassWeaver implements IClassWeaver {
     // ----
     
     public boolean weave() {
-               
+
         if (clazz.isWoven() && !clazz.isReweavable()) {
                world.showMessage(IMessage.ERROR, 
                                "class \'" + clazz.getType().getName() + "\' is already woven and has not been built with -Xreweavable",
@@ -301,8 +301,7 @@ class BcelClassWeaver implements IClassWeaver {
         
         // we want to "touch" all aspects
         if (clazz.getType().isAspect()) isChanged = true;
-        
-        
+                
         // start by munging all typeMungers
         for (Iterator i = typeMungers.iterator(); i.hasNext(); ) {
                Object o = i.next();
@@ -327,13 +326,12 @@ class BcelClassWeaver implements IClassWeaver {
         if (addedSuperInitializersAsList == null) {
                throw new BCException("circularity in inter-types");
         }
-        
+      
         // this will create a static initializer if there isn't one
         // this is in just as bad taste as NOPs
         LazyMethodGen staticInit = clazz.getStaticInitializer();
         staticInit.getBody().insert(genInitInstructions(addedClassInitializers, true));
         
-        
         // now go through each method, and match against each method.  This
         // sets up each method's {@link LazyMethodGen#matchedShadows} field, 
         // and it also possibly adds to {@link #initializationShadows}.
@@ -351,6 +349,7 @@ class BcelClassWeaver implements IClassWeaver {
         }
         if (! isChanged) return false;
         
+        
         // now we weave all but the initialization shadows
                for (Iterator i = methodGens.iterator(); i.hasNext();) {
                        LazyMethodGen mg = (LazyMethodGen)i.next();
@@ -785,72 +784,7 @@ class BcelClassWeaver implements IClassWeaver {
                List shadowAccumulator = new ArrayList();
                // we want to match ajsynthetic constructors...
                if (mg.getName().equals("<init>")) {
-                       // XXX the enclosing join point is wrong for things before ignoreMe.
-                       InstructionHandle superOrThisCall = findSuperOrThisCall(mg);
-
-                       // we don't walk bodies of things where it's a wrong constructor thingie
-                       if (superOrThisCall == null) return false;
-
-                       enclosingShadow = BcelShadow.makeConstructorExecution(world, mg, superOrThisCall);
-                       
-                       // walk the body
-                       boolean beforeSuperOrThisCall = true;
-                       if (shouldWeaveBody(mg)) {
-                               if (canMatchBodyShadows) {
-                                       for (InstructionHandle h = mg.getBody().getStart();
-                                               h != null;
-                                               h = h.getNext()) {
-                                               if (h == superOrThisCall) {
-                                                       beforeSuperOrThisCall = false;
-                                                       continue;
-                                               }
-                                               match(mg, h, beforeSuperOrThisCall ? null : enclosingShadow, shadowAccumulator);
-                                       }
-                               }
-                               match(enclosingShadow, shadowAccumulator);
-                       }
-                       
-                       // XXX we don't do pre-inits of interfaces
-                       
-                       // now add interface inits
-                       if (superOrThisCall != null && ! isThisCall(superOrThisCall)) {
-                               InstructionHandle curr = enclosingShadow.getRange().getStart();
-                               for (Iterator i = addedSuperInitializersAsList.iterator(); i.hasNext(); ) {
-                                       IfaceInitList l = (IfaceInitList) i.next();
-
-                                       Member ifaceInitSig = AjcMemberMaker.interfaceConstructor(l.onType);
-                                       
-                                       BcelShadow initShadow =
-                                               BcelShadow.makeIfaceInitialization(world, mg, ifaceInitSig);
-                                       
-                                       // insert code in place
-                                       InstructionList inits = genInitInstructions(l.list, false);
-                                       if (match(initShadow, shadowAccumulator) || !inits.isEmpty()) {
-                                               initShadow.initIfaceInitializer(curr);
-                                               initShadow.getRange().insert(inits, Range.OutsideBefore);
-                                       }
-                               }
-                               
-                               // now we add our initialization code
-                               InstructionList inits = genInitInstructions(addedThisInitializers, false);
-                               enclosingShadow.getRange().insert(inits, Range.OutsideBefore);                          
-                       }
-
-                       // actually, you only need to inline the self constructors that are 
-                       // in a particular group (partition the constructors into groups where members
-                       // call or are called only by those in the group).  Then only inline 
-                       // constructors
-                       // in groups where at least one initialization jp matched.  Future work.
-                       boolean addedInitialization = 
-                               match(
-                                       BcelShadow.makeUnfinishedInitialization(world, mg), 
-                                       initializationShadows);
-                       addedInitialization |=
-                               match(
-                                       BcelShadow.makeUnfinishedPreinitialization(world, mg),
-                                       initializationShadows);
-                       mg.matchedShadows = shadowAccumulator;
-                       return addedInitialization || !shadowAccumulator.isEmpty();
+                       return matchInit(mg, shadowAccumulator);
                } else if (!shouldWeaveBody(mg)) { //.isAjSynthetic()) {
                        return false;                   
                } else {
@@ -890,6 +824,76 @@ class BcelClassWeaver implements IClassWeaver {
                }
        }
 
+       private boolean matchInit(LazyMethodGen mg, List shadowAccumulator) {
+               BcelShadow enclosingShadow;
+               // XXX the enclosing join point is wrong for things before ignoreMe.
+               InstructionHandle superOrThisCall = findSuperOrThisCall(mg);
+
+               // we don't walk bodies of things where it's a wrong constructor thingie
+               if (superOrThisCall == null) return false;
+
+               enclosingShadow = BcelShadow.makeConstructorExecution(world, mg, superOrThisCall);
+               
+               // walk the body
+               boolean beforeSuperOrThisCall = true;
+               if (shouldWeaveBody(mg)) {
+                       if (canMatchBodyShadows) {
+                               for (InstructionHandle h = mg.getBody().getStart();
+                                       h != null;
+                                       h = h.getNext()) {
+                                       if (h == superOrThisCall) {
+                                               beforeSuperOrThisCall = false;
+                                               continue;
+                                       }
+                                       match(mg, h, beforeSuperOrThisCall ? null : enclosingShadow, shadowAccumulator);
+                               }
+                       }
+                       match(enclosingShadow, shadowAccumulator);
+               }
+               
+               // XXX we don't do pre-inits of interfaces
+               
+               // now add interface inits
+               if (superOrThisCall != null && ! isThisCall(superOrThisCall)) {
+                       InstructionHandle curr = enclosingShadow.getRange().getStart();
+                       for (Iterator i = addedSuperInitializersAsList.iterator(); i.hasNext(); ) {
+                               IfaceInitList l = (IfaceInitList) i.next();
+
+                               Member ifaceInitSig = AjcMemberMaker.interfaceConstructor(l.onType);
+                               
+                               BcelShadow initShadow =
+                                       BcelShadow.makeIfaceInitialization(world, mg, ifaceInitSig);
+                               
+                               // insert code in place
+                               InstructionList inits = genInitInstructions(l.list, false);
+                               if (match(initShadow, shadowAccumulator) || !inits.isEmpty()) {
+                                       initShadow.initIfaceInitializer(curr);
+                                       initShadow.getRange().insert(inits, Range.OutsideBefore);
+                               }
+                       }
+                       
+                       // now we add our initialization code
+                       InstructionList inits = genInitInstructions(addedThisInitializers, false);
+                       enclosingShadow.getRange().insert(inits, Range.OutsideBefore);                          
+               }
+
+               // actually, you only need to inline the self constructors that are 
+               // in a particular group (partition the constructors into groups where members
+               // call or are called only by those in the group).  Then only inline 
+               // constructors
+               // in groups where at least one initialization jp matched.  Future work.
+               boolean addedInitialization = 
+                       match(
+                               BcelShadow.makeUnfinishedInitialization(world, mg), 
+                               initializationShadows);
+               addedInitialization |=
+                       match(
+                               BcelShadow.makeUnfinishedPreinitialization(world, mg),
+                               initializationShadows);
+               mg.matchedShadows = shadowAccumulator;
+               return addedInitialization || !shadowAccumulator.isEmpty();
+       }
+
        private boolean shouldWeaveBody(LazyMethodGen mg) {     
                if (mg.isAjSynthetic()) return mg.getName().equals("<clinit>");
                AjAttribute.EffectiveSignatureAttribute a = mg.getEffectiveSignature();
index 1c8a44c0cb79ec0077f218b76d3f958d1efaf348..553e7c72dea038230037f59c7dce5e03a83ea8af 100644 (file)
@@ -216,7 +216,22 @@ public class BcelObjectType extends ResolvedTypeX.ConcreteName {
        isObject = (javaClass.getSuperclassNameIndex() == 0);
         unpackAspectAttributes();
     }
-
+    
+    public void finishedWith() {
+       // memory usage experiments....
+//             this.interfaces = null;
+//     this.superClass = null;
+//     this.fields = null;
+//     this.methods = null;
+//     this.pointcuts = null;
+//     this.perClause = null;
+//     this.weaverState = null;
+//     this.lazyClassGen = null;
+       // this next line frees up memory, but need to understand incremental implications
+       // before leaving it in.
+//     getResolvedTypeX().setSourceContext(null);
+    }
+    
        public WeaverStateInfo getWeaverState() {
                return weaverState;
        }
index 5d92584af4115ef3ac7ceadccc052c754453b2e3..e71707caea1d330f4d2d1827a3350a75fdbe3aa9 100644 (file)
@@ -13,7 +13,7 @@
 
 package org.aspectj.weaver.bcel;
 
-import java.io.BufferedOutputStream;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileFilter;
@@ -41,6 +41,8 @@ import org.aspectj.bridge.IProgressListener;
 import org.aspectj.util.FileUtil;
 import org.aspectj.weaver.ConcreteTypeMunger;
 import org.aspectj.weaver.CrosscuttingMembersSet;
+import org.aspectj.weaver.IClassFileProvider;
+import org.aspectj.weaver.IWeaveRequestor;
 import org.aspectj.weaver.IWeaver;
 import org.aspectj.weaver.NewParentTypeMunger;
 import org.aspectj.weaver.ResolvedTypeMunger;
@@ -59,7 +61,6 @@ public class BcelWeaver implements IWeaver {
     private double progressPerClassFile;
     
     private boolean inReweavableMode = false;
-    private boolean compressReweavableAttributes = false;
     
     public BcelWeaver(BcelWorld world) {
         super();
@@ -72,7 +73,7 @@ public class BcelWeaver implements IWeaver {
     }
 
        // ---- fields  
-    private Map  sourceJavaClasses = new HashMap();   /* String -> UnwovenClassFile */
+//    private Map  sourceJavaClasses = new HashMap();   /* String -> UnwovenClassFile */
     private List addedClasses      = new ArrayList(); /* List<UnovenClassFile> */
     private List deletedTypenames  = new ArrayList(); /* List<String> */
     private Map  resources         = new HashMap(); /* String -> UnwovenClassFile */ 
@@ -139,13 +140,15 @@ public class BcelWeaver implements IWeaver {
 
        // The ANT copy task should be used to copy resources across.
        private final static boolean CopyResourcesFromInpathDirectoriesToOutput=false;
+       private Set alreadyConfirmedReweavableState;
        
        /**
         * Add any .class files in the directory to the outdir.  Anything other than .class files in
         * the directory (or its subdirectories) are considered resources and are also copied. 
         *  
         */
-       public void addDirectoryContents(File inFile,File outDir) throws IOException {
+       public List addDirectoryContents(File inFile,File outDir) throws IOException {
+               List addedClassFiles = new ArrayList();
                
                // Get a list of all files (i.e. everything that isnt a directory)
                File[] files = FileUtil.listFiles(inFile,new FileFilter() {
@@ -170,6 +173,7 @@ public class BcelWeaver implements IWeaver {
                        if (filename.endsWith(".class")) {
                                // System.err.println("BCELWeaver: processing class from input directory "+classFile);
                                this.addClassFile(classFile);
+                               addedClassFiles.add(classFile);
                        } else {
                          if (CopyResourcesFromInpathDirectoriesToOutput) {
                                // System.err.println("BCELWeaver: processing resource from input directory "+filename);
@@ -179,18 +183,20 @@ public class BcelWeaver implements IWeaver {
                        fis.close();
                }
                
+               return addedClassFiles;
        }
 
 
        /** Adds all class files in the jar
         */
-       public void addJarFile(File inFile, File outDir, boolean canBeDirectory) throws IOException {
+       public List addJarFile(File inFile, File outDir, boolean canBeDirectory) throws IOException {
 //             System.err.println("? addJarFile(" + inFile + ", " + outDir + ")");
+               List addedClassFiles = new ArrayList();
                needToReweaveWorld = true;
                
                // Is this a directory we are looking at?
                if (inFile.isDirectory() && canBeDirectory) {
-                       addDirectoryContents(inFile,outDir);
+                       addedClassFiles.addAll(addDirectoryContents(inFile,outDir));
                } else {
                
                        ZipInputStream inStream = new ZipInputStream(new FileInputStream(inFile)); //??? buffered
@@ -205,6 +211,7 @@ public class BcelWeaver implements IWeaver {
 
                                if (filename.endsWith(".class")) {
                                        this.addClassFile(classFile);
+                                       addedClassFiles.add(classFile);
                                }
                                else if (!entry.isDirectory()) {
 
@@ -216,6 +223,8 @@ public class BcelWeaver implements IWeaver {
                        }
                        inStream.close();
                }
+               
+               return addedClassFiles;
        }
 
        public void addResource(String name, File inPath, File outDir) throws IOException {
@@ -232,21 +241,25 @@ public class BcelWeaver implements IWeaver {
                        addResource(name,resourceFile);
                }
        }
-    
+
+       public boolean needToReweaveWorld() {
+               return needToReweaveWorld;
+       }
+       
     /** Should be addOrReplace
      */
     public void addClassFile(UnwovenClassFile classFile) {
        addedClasses.add(classFile);
-       if (null != sourceJavaClasses.put(classFile.getClassName(), classFile)) {
-//             throw new RuntimeException(classFile.getClassName());
-       }
+//     if (null != sourceJavaClasses.put(classFile.getClassName(), classFile)) {
+////                   throw new RuntimeException(classFile.getClassName());
+//     }
        world.addSourceObjectType(classFile.getJavaClass());
     }
 
 
     public void deleteClassFile(String typename) {
        deletedTypenames.add(typename);
-       sourceJavaClasses.remove(typename);
+//     sourceJavaClasses.remove(typename);
        world.deleteSourceObjectType(TypeX.forName(typename));
     }
 
@@ -297,23 +310,23 @@ public class BcelWeaver implements IWeaver {
                        });
     }
     
-    public void dumpUnwoven(File file) throws IOException {
-       BufferedOutputStream os = FileUtil.makeOutputStream(file);
-       this.zipOutputStream = new ZipOutputStream(os);
-       dumpUnwoven();
-               /* BUG 40943*/
-               dumpResourcesToOutJar();
-       zipOutputStream.close();  //this flushes and closes the acutal file
-    }
-    
-    
-    public void dumpUnwoven() throws IOException {
-       Collection filesToDump = new HashSet(sourceJavaClasses.values());
-       for (Iterator i = filesToDump.iterator(); i.hasNext(); ) {
-            UnwovenClassFile classFile = (UnwovenClassFile)i.next();
-            dumpUnchanged(classFile);
-               }
-    }
+//    public void dumpUnwoven(File file) throws IOException {
+//     BufferedOutputStream os = FileUtil.makeOutputStream(file);
+//     this.zipOutputStream = new ZipOutputStream(os);
+//     dumpUnwoven();
+//             /* BUG 40943*/
+//             dumpResourcesToOutJar();
+//     zipOutputStream.close();  //this flushes and closes the acutal file
+//    }
+//    
+//    
+//    public void dumpUnwoven() throws IOException {
+//     Collection filesToDump = new HashSet(sourceJavaClasses.values());
+//     for (Iterator i = filesToDump.iterator(); i.hasNext(); ) {
+//            UnwovenClassFile classFile = (UnwovenClassFile)i.next();
+//            dumpUnchanged(classFile);
+//             }
+//    }
     
        public void dumpResourcesToOutPath() throws IOException {
 //             System.err.println("? dumpResourcesToOutPath() resources=" + resources.keySet());
@@ -322,6 +335,7 @@ public class BcelWeaver implements IWeaver {
                        UnwovenClassFile res = (UnwovenClassFile)resources.get(i.next());
                        dumpUnchanged(res);
                }
+               //resources = new HashMap();
        }
 
        /* BUG #40943 */
@@ -333,127 +347,248 @@ public class BcelWeaver implements IWeaver {
                        UnwovenClassFile res = (UnwovenClassFile)resources.get(name);
                        writeZipEntry(name,res.getBytes());
                }
+               //resources = new HashMap();
+    }
+    
+    // halfway house for when the jar is managed outside of the weaver, but the resources
+    // to be copied are known in the weaver.
+    public void dumpResourcesToOutJar(ZipOutputStream zos) throws IOException {
+       this.zipOutputStream = zos;
+       dumpResourcesToOutJar();
     }
     
     // ---- weaving
 
+    // Used by some test cases...
     public Collection weave(File file) throws IOException {
        OutputStream os = FileUtil.makeOutputStream(file);
        this.zipOutputStream = new ZipOutputStream(os);
-       Collection c = weave();
+       prepareForWeave();
+       Collection c = weave( new IClassFileProvider() {
+
+                       public Iterator getClassFileIterator() {
+                               return addedClasses.iterator();
+                       }
+
+                       public IWeaveRequestor getRequestor() {
+                               return new IWeaveRequestor() {
+                                       public void acceptResult(UnwovenClassFile result) {}
+                                       public void processingReweavableState() {}
+                                       public void addingTypeMungers() {}
+                                       public void weavingAspects() {}
+                                       public void weavingClasses() {}
+                                       public void weaveCompleted() {}
+                               };
+                       }
+               });
        /* BUG 40943*/
        dumpResourcesToOutJar();
        zipOutputStream.close();  //this flushes and closes the acutal file
        return c;
     }
     
-    public Collection weave() throws IOException {
-       prepareForWeave();
-       Collection filesToWeave;
-       
-       if (needToReweaveWorld) {
-               filesToWeave = sourceJavaClasses.values();
-       } else {
-               filesToWeave = addedClasses;
-       }
-       
+//    public Collection weave() throws IOException {
+//     prepareForWeave();
+//     Collection filesToWeave;
+//     
+//     if (needToReweaveWorld) {
+//             filesToWeave = sourceJavaClasses.values();
+//     } else {
+//             filesToWeave = addedClasses;
+//     }
+//     
+//     Collection wovenClassNames = new ArrayList();
+//     world.showMessage(IMessage.INFO, "might need to weave " + filesToWeave + 
+//                                     "(world=" + needToReweaveWorld + ")", null, null);
+//     
+//     
+//     //System.err.println("typeMungers: " + typeMungerList);
+//     
+//     prepareToProcessReweavableState();
+//             // clear all state from files we'll be reweaving
+//        for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
+//            UnwovenClassFile classFile = (UnwovenClassFile)i.next();
+//             String className = classFile.getClassName();
+//            BcelObjectType classType = getClassType(className);                                  
+//                     processReweavableStateIfPresent(className, classType);
+//        }
+//     
+//     
+//     
+//     //XXX this isn't quite the right place for this...
+//     for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
+//            UnwovenClassFile classFile = (UnwovenClassFile)i.next();
+//            String className = classFile.getClassName();
+//            addTypeMungers(className);
+//        }
+//     
+//             // first weave into aspects
+//        for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
+//            UnwovenClassFile classFile = (UnwovenClassFile)i.next();
+//             String className = classFile.getClassName();
+//            BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
+//            if (classType.isAspect()) {
+//                 weave(classFile, classType);
+//                 wovenClassNames.add(className);
+//            }
+//        }
+//
+//             // then weave into non-aspects
+//             for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
+//            UnwovenClassFile classFile = (UnwovenClassFile)i.next();
+//             String className = classFile.getClassName();
+//            BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
+//            if (! classType.isAspect()) {
+//                 weave(classFile, classType);
+//                 wovenClassNames.add(className);
+//            }
+//        }
+//        
+//        if (zipOutputStream != null && !needToReweaveWorld) {
+//             Collection filesToDump = new HashSet(sourceJavaClasses.values());
+//             filesToDump.removeAll(filesToWeave);
+//             for (Iterator i = filesToDump.iterator(); i.hasNext(); ) {
+//                UnwovenClassFile classFile = (UnwovenClassFile)i.next();
+//                dumpUnchanged(classFile);
+//             }
+//        }
+//        
+//        addedClasses = new ArrayList();
+//     deletedTypenames = new ArrayList();
+//             
+//        return wovenClassNames;
+//    }
+    
+    // variation of "weave" that sources class files from an external source.
+    public Collection weave(IClassFileProvider input) throws IOException {
        Collection wovenClassNames = new ArrayList();
-       world.showMessage(IMessage.INFO, "might need to weave " + filesToWeave + 
-                                       "(world=" + needToReweaveWorld + ")", null, null);
-       
-       
-       //System.err.println("typeMungers: " + typeMungerList);
-       
+       IWeaveRequestor requestor = input.getRequestor();
 
-               if (inReweavableMode)
-                       world.showMessage(IMessage.INFO, "weaver operating in reweavable mode.  Need to verify any required types exist.", null, null);
-               
-       
-       Set alreadyConfirmedOK = new HashSet();
+       requestor.processingReweavableState();
+               prepareToProcessReweavableState();
                // clear all state from files we'll be reweaving
-        for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
-            UnwovenClassFile classFile = (UnwovenClassFile)i.next();
-               String className = classFile.getClassName();
-            BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
+               for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
+                   UnwovenClassFile classFile = (UnwovenClassFile)i.next();
+                       String className = classFile.getClassName();
+                   BcelObjectType classType = getClassType(className);                             
+                       processReweavableStateIfPresent(className, classType);
+               }
+                                                               
+               requestor.addingTypeMungers();
+               //XXX this isn't quite the right place for this...
+               for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
+                   UnwovenClassFile classFile = (UnwovenClassFile)i.next();
+                   String className = classFile.getClassName();
+                   addTypeMungers(className);
+               }
 
-                       
-            // If the class is marked reweavable, check any aspects around when it was built are in this world
-                       WeaverStateInfo wsi = classType.getWeaverState();               
-                       if (wsi!=null && wsi.isReweavable()) { // Check all necessary types are around!
-                               world.showMessage(IMessage.INFO,"processing reweavable type "+className+": "+classType.getSourceLocation().getSourceFile(),null,null);
-                       Set aspectsPreviouslyInWorld = wsi.getAspectsAffectingType();
-                               if (aspectsPreviouslyInWorld!=null) {
-                                       for (Iterator iter = aspectsPreviouslyInWorld.iterator(); iter.hasNext();) {
-                                               String requiredTypeName = (String) iter.next();
-                                               if (!alreadyConfirmedOK.contains(requiredTypeName)) {
-                                                       ResolvedTypeX rtx = world.resolve(TypeX.forName(requiredTypeName),true);
-                                                       boolean exists = rtx!=ResolvedTypeX.MISSING;
-                                                       if (!exists) {
-                                                               world.showMessage(IMessage.ERROR, "type " + requiredTypeName + 
-                                                                       " is needed by reweavable type " + className,
-                                                                       classType.getSourceLocation(), null);
-                                                       } else {
-                                                               if (!world.getMessageHandler().isIgnoring(IMessage.INFO))
-                                                                 world.showMessage(IMessage.INFO,"successfully verified type "+requiredTypeName+
-                                    " exists.  Originates from "+rtx.getSourceLocation().getSourceFile(),null,null);
-                                                               alreadyConfirmedOK.add(requiredTypeName);
-                                                       }
-                                               }               
-                                       }
-                               }
-                               classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData()));
-                       } else {
-               classType.resetState();
-                       }
-        }
-       
-       
-       
-       //XXX this isn't quite the right place for this...
-       for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
-            UnwovenClassFile classFile = (UnwovenClassFile)i.next();
-            String className = classFile.getClassName();
-            ResolvedTypeX onType = world.resolve(className);
-            weave(onType);
-        }
-       
+               requestor.weavingAspects();
                // first weave into aspects
-        for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
-            UnwovenClassFile classFile = (UnwovenClassFile)i.next();
-               String className = classFile.getClassName();
-            BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
-            if (classType.isAspect()) {
-                   weave(classFile, classType);
-                   wovenClassNames.add(className);
-            }
-        }
+               for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
+                   UnwovenClassFile classFile = (UnwovenClassFile)i.next();
+                       String className = classFile.getClassName();
+                   BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
+                   if (classType.isAspect()) {
+                       weaveAndNotify(classFile, classType,requestor);
+                       wovenClassNames.add(className);
+                   }
+               }
 
+               requestor.weavingClasses();
                // then weave into non-aspects
-               for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
-            UnwovenClassFile classFile = (UnwovenClassFile)i.next();
-               String className = classFile.getClassName();
-            BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
-            if (! classType.isAspect()) {
-                   weave(classFile, classType);
-                   wovenClassNames.add(className);
-            }
-        }
-        
-        if (zipOutputStream != null && !needToReweaveWorld) {
-               Collection filesToDump = new HashSet(sourceJavaClasses.values());
-               filesToDump.removeAll(filesToWeave);
-               for (Iterator i = filesToDump.iterator(); i.hasNext(); ) {
-                UnwovenClassFile classFile = (UnwovenClassFile)i.next();
-                dumpUnchanged(classFile);
-               }
-        }
-        
-        addedClasses = new ArrayList();
-       deletedTypenames = new ArrayList();
+               for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
+                   UnwovenClassFile classFile = (UnwovenClassFile)i.next();
+                       String className = classFile.getClassName();
+                   BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
+                   if (! classType.isAspect()) {
+                       weaveAndNotify(classFile, classType, requestor);
+                       wovenClassNames.add(className);
+                   }
+               }
                
-        return wovenClassNames;
+               addedClasses = new ArrayList();
+               deletedTypenames = new ArrayList();
+               requestor.weaveCompleted();
+               
+       return wovenClassNames;
+    }
+    
+    public void prepareToProcessReweavableState() {
+               if (inReweavableMode)
+                       world.showMessage(IMessage.INFO, "weaver operating in reweavable mode.  Need to verify any required types exist.", null, null);
+                       
+       alreadyConfirmedReweavableState = new HashSet();
+    }
+    
+    public void processReweavableStateIfPresent(String className, BcelObjectType classType) {
+               // If the class is marked reweavable, check any aspects around when it was built are in this world
+               WeaverStateInfo wsi = classType.getWeaverState();               
+               if (wsi!=null && wsi.isReweavable()) { // Check all necessary types are around!
+                       world.showMessage(IMessage.INFO,"processing reweavable type "+className+": "+classType.getSourceLocation().getSourceFile(),null,null);
+                       Set aspectsPreviouslyInWorld = wsi.getAspectsAffectingType();
+                       if (aspectsPreviouslyInWorld!=null) {
+                               for (Iterator iter = aspectsPreviouslyInWorld.iterator(); iter.hasNext();) {
+                                       String requiredTypeName = (String) iter.next();
+                                       if (!alreadyConfirmedReweavableState.contains(requiredTypeName)) {
+                                               ResolvedTypeX rtx = world.resolve(TypeX.forName(requiredTypeName),true);
+                                               boolean exists = rtx!=ResolvedTypeX.MISSING;
+                                               if (!exists) {
+                                                       world.showMessage(IMessage.ERROR, "type " + requiredTypeName + 
+                                                               " is needed by reweavable type " + className,
+                                                               classType.getSourceLocation(), null);
+                                               } else {
+                                                       if (!world.getMessageHandler().isIgnoring(IMessage.INFO))
+                                                         world.showMessage(IMessage.INFO,"successfully verified type "+requiredTypeName+
+                                       " exists.  Originates from "+rtx.getSourceLocation().getSourceFile(),null,null);
+                                                       alreadyConfirmedReweavableState.add(requiredTypeName);
+                                               }
+                                       }               
+                               }
+                       }
+                       classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData()));
+               } else {
+                       classType.resetState();
+               }
+       }
+
+    private void weaveAndNotify(UnwovenClassFile classFile, BcelObjectType classType,
+                                   IWeaveRequestor requestor) throws IOException {
+       LazyClassGen clazz = weaveWithoutDump(classFile,classType);
+       classType.finishedWith();
+               //clazz is null if the classfile was unchanged by weaving...
+               if (clazz != null) {
+                       UnwovenClassFile[] newClasses = getClassFilesFor(clazz);
+                       for (int i = 0; i < newClasses.length; i++) {
+                               requestor.acceptResult(newClasses[i]);
+                       }
+               } else {
+                       requestor.acceptResult(classFile);
+               }
+    }
+    
+       // helper method
+    public BcelObjectType getClassType(String forClass) {
+        return BcelWorld.getBcelObjectType(world.resolve(forClass));           
+    }
+    
+    public void addTypeMungers(String typeName) {
+       weave(world.resolve(typeName));
     }
 
+    public UnwovenClassFile[] getClassFilesFor(LazyClassGen clazz) {
+       List childClasses = clazz.getChildClasses(world);
+       UnwovenClassFile[] ret = new UnwovenClassFile[1 + childClasses.size()];         
+       ret[0] = new UnwovenClassFile(clazz.getFileName(),clazz.getJavaClass(world).getBytes());
+       int index = 1;
+       for (Iterator iter = childClasses.iterator(); iter.hasNext();) {
+                       UnwovenClassFile.ChildClass element = (UnwovenClassFile.ChildClass) iter.next();
+                       UnwovenClassFile childClass = new UnwovenClassFile(clazz.getFileName() + "$" + element.name, element.bytes);
+                       ret[index++] = childClass;
+               }
+       return ret;
+    }
+    
        public void weave(ResolvedTypeX onType) {
                onType.clearInterTypeMungers();
                
@@ -622,9 +757,11 @@ public class BcelWeaver implements IWeaver {
 
        public void setReweavableMode(boolean mode,boolean compress) {
                inReweavableMode = mode;
-               compressReweavableAttributes = compress;
                WeaverStateInfo.setReweavableModeDefaults(mode,compress);
                BcelClassWeaver.setReweavableMode(mode,compress);
        }
 
+       public boolean isReweavable() {
+               return inReweavableMode;
+       }
 }
diff --git a/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFileWithThirdPartyManagedBytecode.java b/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFileWithThirdPartyManagedBytecode.java
new file mode 100644 (file)
index 0000000..d7e6c96
--- /dev/null
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.weaver.bcel;
+
+/**
+ * @author colyer
+ * This subclass of UnwovenClassFile allows a third-party to
+ * manage the actual bytes that comprise the class. This means
+ * the third party can return a reference to an existing array,
+ * or create the bytes on demand, or apply any other strategy 
+ * that makes sense. By refering to bytes held elsewhere, the
+ * goal is to reduce the overall memory consumption by not holding
+ * a copy.
+ */
+public class UnwovenClassFileWithThirdPartyManagedBytecode
+               extends UnwovenClassFile {
+       
+       IByteCodeProvider provider;
+       
+       public interface IByteCodeProvider {
+               byte[] getBytes();
+       }
+       
+       public UnwovenClassFileWithThirdPartyManagedBytecode(String filename,
+                       IByteCodeProvider provider) {
+               super(filename,null);
+               this.provider = provider;
+       }
+       
+       public byte[] getBytes() {
+               return provider.getBytes();
+       }
+}