ensure messages are associated with source wherever possibletags/Root_ajdt_support
/******************************************************************************* | |||||
* 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; | |||||
} | |||||
} |
/* ******************************************************************* | |||||
* 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; | |||||
// } | |||||
// } | |||||
// | |||||
//} |
/******************************************************************************* | |||||
* 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); | |||||
} | |||||
} | |||||
} | |||||
} |
/******************************************************************************* | |||||
* 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; | |||||
} | |||||
} |
/******************************************************************************* | |||||
* 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); | |||||
} |
/******************************************************************************* | |||||
* 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); | |||||
} |
/******************************************************************************* | |||||
* 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(); | |||||
} | |||||
} |
/******************************************************************************* | |||||
* 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); | |||||
} | |||||
} | |||||
} |
/******************************************************************************* | |||||
* 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>Preferences>Java>Code Generation>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; | |||||
} | |||||
} | |||||
this.startPos = startPos; | this.startPos = startPos; | ||||
this.endPos = endPos; | this.endPos = endPos; | ||||
} | } | ||||
public CompilationResult getCompilationResult() { | |||||
return result; | |||||
} | |||||
public int getStartPos() { | |||||
return startPos; | |||||
} | |||||
public int getEndPos() { | |||||
return endPos; | |||||
} | |||||
public File getSourceFile() { | public File getSourceFile() { | ||||
if (null == file) { | if (null == file) { |
} | } | ||||
public boolean isExposedToWeaver() { | public boolean isExposedToWeaver() { | ||||
return delegate.isExposedToWeaver(); //??? where does this belong | |||||
return (delegate == null) || delegate.isExposedToWeaver(); //??? where does this belong | |||||
} | } | ||||
public WeaverStateInfo getWeaverState() { | public WeaverStateInfo getWeaverState() { | ||||
public static abstract class ConcreteName { | public static abstract class ConcreteName { | ||||
//protected ISourceContext sourceContext; | //protected ISourceContext sourceContext; | ||||
protected boolean exposedToWeaver; | protected boolean exposedToWeaver; | ||||
ResolvedTypeX.Name resolvedTypeX; | |||||
protected ResolvedTypeX.Name resolvedTypeX; | |||||
public ConcreteName(ResolvedTypeX.Name resolvedTypeX, boolean exposedToWeaver) { | public ConcreteName(ResolvedTypeX.Name resolvedTypeX, boolean exposedToWeaver) { |
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.WeakHashMap; | |||||
import org.aspectj.asm.IHierarchy; | import org.aspectj.asm.IHierarchy; | ||||
import org.aspectj.bridge.IMessageHandler; | import org.aspectj.bridge.IMessageHandler; | ||||
protected IMessageHandler messageHandler = IMessageHandler.SYSTEM_ERR; | protected IMessageHandler messageHandler = IMessageHandler.SYSTEM_ERR; | ||||
protected ICrossReferenceHandler xrefHandler = null; | 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); | protected CrosscuttingMembersSet crosscuttingMembersSet = new CrosscuttingMembersSet(this); | ||||
public ResolvedTypeX resolve(TypeX ty, boolean allowMissing) { | public ResolvedTypeX resolve(TypeX ty, boolean allowMissing) { | ||||
//System.out.println("resolve: " + ty + " world " + typeMap.keySet()); | //System.out.println("resolve: " + ty + " world " + typeMap.keySet()); | ||||
String signature = ty.getSignature(); | String signature = ty.getSignature(); | ||||
ResolvedTypeX ret = (ResolvedTypeX)typeMap.get(signature); | |||||
ResolvedTypeX ret = typeMap.get(signature); | |||||
if (ret != null) return ret; | if (ret != null) return ret; | ||||
if (ty.isArray()) { | if (ty.isArray()) { | ||||
return ret; | 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()) | |||||
); | |||||
} | |||||
} | |||||
} | } |
// ---- | // ---- | ||||
public boolean weave() { | public boolean weave() { | ||||
if (clazz.isWoven() && !clazz.isReweavable()) { | if (clazz.isWoven() && !clazz.isReweavable()) { | ||||
world.showMessage(IMessage.ERROR, | world.showMessage(IMessage.ERROR, | ||||
"class \'" + clazz.getType().getName() + "\' is already woven and has not been built with -Xreweavable", | "class \'" + clazz.getType().getName() + "\' is already woven and has not been built with -Xreweavable", | ||||
// we want to "touch" all aspects | // we want to "touch" all aspects | ||||
if (clazz.getType().isAspect()) isChanged = true; | if (clazz.getType().isAspect()) isChanged = true; | ||||
// start by munging all typeMungers | // start by munging all typeMungers | ||||
for (Iterator i = typeMungers.iterator(); i.hasNext(); ) { | for (Iterator i = typeMungers.iterator(); i.hasNext(); ) { | ||||
Object o = i.next(); | Object o = i.next(); | ||||
if (addedSuperInitializersAsList == null) { | if (addedSuperInitializersAsList == null) { | ||||
throw new BCException("circularity in inter-types"); | throw new BCException("circularity in inter-types"); | ||||
} | } | ||||
// this will create a static initializer if there isn't one | // this will create a static initializer if there isn't one | ||||
// this is in just as bad taste as NOPs | // this is in just as bad taste as NOPs | ||||
LazyMethodGen staticInit = clazz.getStaticInitializer(); | LazyMethodGen staticInit = clazz.getStaticInitializer(); | ||||
staticInit.getBody().insert(genInitInstructions(addedClassInitializers, true)); | staticInit.getBody().insert(genInitInstructions(addedClassInitializers, true)); | ||||
// now go through each method, and match against each method. This | // now go through each method, and match against each method. This | ||||
// sets up each method's {@link LazyMethodGen#matchedShadows} field, | // sets up each method's {@link LazyMethodGen#matchedShadows} field, | ||||
// and it also possibly adds to {@link #initializationShadows}. | // and it also possibly adds to {@link #initializationShadows}. | ||||
} | } | ||||
if (! isChanged) return false; | if (! isChanged) return false; | ||||
// now we weave all but the initialization shadows | // now we weave all but the initialization shadows | ||||
for (Iterator i = methodGens.iterator(); i.hasNext();) { | for (Iterator i = methodGens.iterator(); i.hasNext();) { | ||||
LazyMethodGen mg = (LazyMethodGen)i.next(); | LazyMethodGen mg = (LazyMethodGen)i.next(); | ||||
List shadowAccumulator = new ArrayList(); | List shadowAccumulator = new ArrayList(); | ||||
// we want to match ajsynthetic constructors... | // we want to match ajsynthetic constructors... | ||||
if (mg.getName().equals("<init>")) { | 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()) { | } else if (!shouldWeaveBody(mg)) { //.isAjSynthetic()) { | ||||
return false; | return false; | ||||
} else { | } else { | ||||
} | } | ||||
} | } | ||||
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) { | private boolean shouldWeaveBody(LazyMethodGen mg) { | ||||
if (mg.isAjSynthetic()) return mg.getName().equals("<clinit>"); | if (mg.isAjSynthetic()) return mg.getName().equals("<clinit>"); | ||||
AjAttribute.EffectiveSignatureAttribute a = mg.getEffectiveSignature(); | AjAttribute.EffectiveSignatureAttribute a = mg.getEffectiveSignature(); |
isObject = (javaClass.getSuperclassNameIndex() == 0); | isObject = (javaClass.getSuperclassNameIndex() == 0); | ||||
unpackAspectAttributes(); | 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() { | public WeaverStateInfo getWeaverState() { | ||||
return weaverState; | return weaverState; | ||||
} | } |
package org.aspectj.weaver.bcel; | package org.aspectj.weaver.bcel; | ||||
import java.io.BufferedOutputStream; | |||||
import java.io.ByteArrayInputStream; | import java.io.ByteArrayInputStream; | ||||
import java.io.File; | import java.io.File; | ||||
import java.io.FileFilter; | import java.io.FileFilter; | ||||
import org.aspectj.util.FileUtil; | import org.aspectj.util.FileUtil; | ||||
import org.aspectj.weaver.ConcreteTypeMunger; | import org.aspectj.weaver.ConcreteTypeMunger; | ||||
import org.aspectj.weaver.CrosscuttingMembersSet; | import org.aspectj.weaver.CrosscuttingMembersSet; | ||||
import org.aspectj.weaver.IClassFileProvider; | |||||
import org.aspectj.weaver.IWeaveRequestor; | |||||
import org.aspectj.weaver.IWeaver; | import org.aspectj.weaver.IWeaver; | ||||
import org.aspectj.weaver.NewParentTypeMunger; | import org.aspectj.weaver.NewParentTypeMunger; | ||||
import org.aspectj.weaver.ResolvedTypeMunger; | import org.aspectj.weaver.ResolvedTypeMunger; | ||||
private double progressPerClassFile; | private double progressPerClassFile; | ||||
private boolean inReweavableMode = false; | private boolean inReweavableMode = false; | ||||
private boolean compressReweavableAttributes = false; | |||||
public BcelWeaver(BcelWorld world) { | public BcelWeaver(BcelWorld world) { | ||||
super(); | super(); | ||||
} | } | ||||
// ---- fields | // ---- fields | ||||
private Map sourceJavaClasses = new HashMap(); /* String -> UnwovenClassFile */ | |||||
// private Map sourceJavaClasses = new HashMap(); /* String -> UnwovenClassFile */ | |||||
private List addedClasses = new ArrayList(); /* List<UnovenClassFile> */ | private List addedClasses = new ArrayList(); /* List<UnovenClassFile> */ | ||||
private List deletedTypenames = new ArrayList(); /* List<String> */ | private List deletedTypenames = new ArrayList(); /* List<String> */ | ||||
private Map resources = new HashMap(); /* String -> UnwovenClassFile */ | private Map resources = new HashMap(); /* String -> UnwovenClassFile */ | ||||
// The ANT copy task should be used to copy resources across. | // The ANT copy task should be used to copy resources across. | ||||
private final static boolean CopyResourcesFromInpathDirectoriesToOutput=false; | 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 | * 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. | * 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) | // Get a list of all files (i.e. everything that isnt a directory) | ||||
File[] files = FileUtil.listFiles(inFile,new FileFilter() { | File[] files = FileUtil.listFiles(inFile,new FileFilter() { | ||||
if (filename.endsWith(".class")) { | if (filename.endsWith(".class")) { | ||||
// System.err.println("BCELWeaver: processing class from input directory "+classFile); | // System.err.println("BCELWeaver: processing class from input directory "+classFile); | ||||
this.addClassFile(classFile); | this.addClassFile(classFile); | ||||
addedClassFiles.add(classFile); | |||||
} else { | } else { | ||||
if (CopyResourcesFromInpathDirectoriesToOutput) { | if (CopyResourcesFromInpathDirectoriesToOutput) { | ||||
// System.err.println("BCELWeaver: processing resource from input directory "+filename); | // System.err.println("BCELWeaver: processing resource from input directory "+filename); | ||||
fis.close(); | fis.close(); | ||||
} | } | ||||
return addedClassFiles; | |||||
} | } | ||||
/** Adds all class files in the jar | /** 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 + ")"); | // System.err.println("? addJarFile(" + inFile + ", " + outDir + ")"); | ||||
List addedClassFiles = new ArrayList(); | |||||
needToReweaveWorld = true; | needToReweaveWorld = true; | ||||
// Is this a directory we are looking at? | // Is this a directory we are looking at? | ||||
if (inFile.isDirectory() && canBeDirectory) { | if (inFile.isDirectory() && canBeDirectory) { | ||||
addDirectoryContents(inFile,outDir); | |||||
addedClassFiles.addAll(addDirectoryContents(inFile,outDir)); | |||||
} else { | } else { | ||||
ZipInputStream inStream = new ZipInputStream(new FileInputStream(inFile)); //??? buffered | ZipInputStream inStream = new ZipInputStream(new FileInputStream(inFile)); //??? buffered | ||||
if (filename.endsWith(".class")) { | if (filename.endsWith(".class")) { | ||||
this.addClassFile(classFile); | this.addClassFile(classFile); | ||||
addedClassFiles.add(classFile); | |||||
} | } | ||||
else if (!entry.isDirectory()) { | else if (!entry.isDirectory()) { | ||||
} | } | ||||
inStream.close(); | inStream.close(); | ||||
} | } | ||||
return addedClassFiles; | |||||
} | } | ||||
public void addResource(String name, File inPath, File outDir) throws IOException { | public void addResource(String name, File inPath, File outDir) throws IOException { | ||||
addResource(name,resourceFile); | addResource(name,resourceFile); | ||||
} | } | ||||
} | } | ||||
public boolean needToReweaveWorld() { | |||||
return needToReweaveWorld; | |||||
} | |||||
/** Should be addOrReplace | /** Should be addOrReplace | ||||
*/ | */ | ||||
public void addClassFile(UnwovenClassFile classFile) { | public void addClassFile(UnwovenClassFile classFile) { | ||||
addedClasses.add(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()); | world.addSourceObjectType(classFile.getJavaClass()); | ||||
} | } | ||||
public void deleteClassFile(String typename) { | public void deleteClassFile(String typename) { | ||||
deletedTypenames.add(typename); | deletedTypenames.add(typename); | ||||
sourceJavaClasses.remove(typename); | |||||
// sourceJavaClasses.remove(typename); | |||||
world.deleteSourceObjectType(TypeX.forName(typename)); | world.deleteSourceObjectType(TypeX.forName(typename)); | ||||
} | } | ||||
}); | }); | ||||
} | } | ||||
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 { | public void dumpResourcesToOutPath() throws IOException { | ||||
// System.err.println("? dumpResourcesToOutPath() resources=" + resources.keySet()); | // System.err.println("? dumpResourcesToOutPath() resources=" + resources.keySet()); | ||||
UnwovenClassFile res = (UnwovenClassFile)resources.get(i.next()); | UnwovenClassFile res = (UnwovenClassFile)resources.get(i.next()); | ||||
dumpUnchanged(res); | dumpUnchanged(res); | ||||
} | } | ||||
//resources = new HashMap(); | |||||
} | } | ||||
/* BUG #40943 */ | /* BUG #40943 */ | ||||
UnwovenClassFile res = (UnwovenClassFile)resources.get(name); | UnwovenClassFile res = (UnwovenClassFile)resources.get(name); | ||||
writeZipEntry(name,res.getBytes()); | 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 | // ---- weaving | ||||
// Used by some test cases... | |||||
public Collection weave(File file) throws IOException { | public Collection weave(File file) throws IOException { | ||||
OutputStream os = FileUtil.makeOutputStream(file); | OutputStream os = FileUtil.makeOutputStream(file); | ||||
this.zipOutputStream = new ZipOutputStream(os); | 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*/ | /* BUG 40943*/ | ||||
dumpResourcesToOutJar(); | dumpResourcesToOutJar(); | ||||
zipOutputStream.close(); //this flushes and closes the acutal file | zipOutputStream.close(); //this flushes and closes the acutal file | ||||
return c; | 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(); | 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 | // 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 | // 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 | // 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) { | public void weave(ResolvedTypeX onType) { | ||||
onType.clearInterTypeMungers(); | onType.clearInterTypeMungers(); | ||||
public void setReweavableMode(boolean mode,boolean compress) { | public void setReweavableMode(boolean mode,boolean compress) { | ||||
inReweavableMode = mode; | inReweavableMode = mode; | ||||
compressReweavableAttributes = compress; | |||||
WeaverStateInfo.setReweavableModeDefaults(mode,compress); | WeaverStateInfo.setReweavableModeDefaults(mode,compress); | ||||
BcelClassWeaver.setReweavableMode(mode,compress); | BcelClassWeaver.setReweavableMode(mode,compress); | ||||
} | } | ||||
public boolean isReweavable() { | |||||
return inReweavableMode; | |||||
} | |||||
} | } |
/******************************************************************************* | |||||
* 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(); | |||||
} | |||||
} |