diff options
-rw-r--r-- | docs/developer/amcDesignNotes.txt | 388 | ||||
-rw-r--r-- | org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java | 348 | ||||
-rw-r--r-- | org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjState.java | 211 | ||||
-rw-r--r-- | org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseAdapterUtils.java | 28 | ||||
-rw-r--r-- | org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java | 12 | ||||
-rw-r--r-- | org.eclipse.jdt.core/jdtcore-for-aspectj-src.zip | bin | 3413286 -> 3393122 bytes | |||
-rw-r--r-- | org.eclipse.jdt.core/jdtcore-for-aspectj.jar | bin | 3831151 -> 3805780 bytes | |||
-rw-r--r-- | tests/ajcTests.xml | 12 | ||||
-rw-r--r-- | tests/incremental/initialTests/aspectSourceAdded/Detour.20.java | 7 | ||||
-rw-r--r-- | tests/incremental/initialTests/aspectSourceAdded/Main.java | 9 | ||||
-rw-r--r-- | tests/incremental/initialTests/suite.xml | 11 | ||||
-rw-r--r-- | util/src/org/aspectj/util/FileUtil.java | 12 | ||||
-rw-r--r-- | weaver/src/org/aspectj/weaver/IClassFileProvider.java | 36 | ||||
-rw-r--r-- | weaver/src/org/aspectj/weaver/IWeaveRequestor.java | 38 |
14 files changed, 923 insertions, 189 deletions
diff --git a/docs/developer/amcDesignNotes.txt b/docs/developer/amcDesignNotes.txt new file mode 100644 index 000000000..981fd3ae8 --- /dev/null +++ b/docs/developer/amcDesignNotes.txt @@ -0,0 +1,388 @@ + +How Compilation Progresses in the JDT: +====================================== + +Compiler.compile(ICompilationUnit[] sourceUnits) { + + foreach sourceUnit + create a new CompilationUnitResult + CompilationUnitDeclaration = parser.parse(sourceUnit, result) + remember CompilationUnitDeclaration (holds ref to result) in + "unitsToProcess" + end + + foreach unitToProcess + resolve + analyse + generateCode + puts class files (plural) into CompilationUnitResult + + unit.cleanup (discards AST info etc.) + requestor.acceptResult(result) -- each requestor does there own thing + discard CompilationUnitDeclaration + end +} + +Some portions of the JDT call the resolve method instead of compile, +this works the same way except that there is only a single sourceUnit +passed to the compiler, and the code generation phase is optional +(controlled by flag passed by caller). + + +How (batch) Compilation Progresses in AspectJ 1.1.x +=================================================== + +AjBuildManager.doBuild() { + + init phase + ---------- + new AjState().prepareForNextBuild() + builds empty lists to hold classes etc. + + setUpModel() // this stage should be omitted unless s.one wants it + + new BcelWorld(classpath) + new BcelWeaver(world) + + add all aspectpath entries to weaver + add all injars to weaver + add all inpath entries to weaver + add all source path *resources* to weaver + + compile phase + ------------- + build name environment, lookup environment, problem reporter and + compiler + + compiler.compile() + proceeds as above, we pass in a requestor that adds the + resulting class files in the result into a list of addedClassFiles + in AjState + + weave phase + ----------- + add the addedClassFiles to the weaver + + pass over all class files known to weaver, building xcut set + pass over all types, adding interTypeMungers to them + pass over all aspects, weave them + pass over all classes, weave them + + write out any resources added to weaver +} + +How we want (batch) compilation to proceed in AspectJ 1.2 +========================================================= + +The key design goal is to do all the work inside the compile method of +the compiler (this makes life much easier for integration with the +rest of the JDT that, quite reasonably, expects the class files to be +ready for action once a compile has completed). The second design goal +is that it should be up to the requestor passed into the compiler +whether or not the class files actually get written out to disk +(different parts of the JDT pass in many different kinds of requestors +that do different things). + +This simple model ignores aspectpath, inpath, injars, outjar, +sourceDirs for now. + +Compiler.compile(ICompilationUnit[] sourceUnits) { + + initial parse phase + ------------------- + foreach sourceUnit + create a new CompilationUnitResult + CompilationUnitDeclaration = parser.parse(sourceUnit, result) + remember CompilationUnitDeclaration (holds ref to result) in + "unitsToProcess" + end + + generate phase + -------------- + foreach unitToProcess + resolve + analyse + generateCode + puts class files (plural) into CompilationUnitResult + + unit.cleanup (discards AST info etc.) + + // up to this point we are identical to JDT current behaviour, + // from now on we deviate + resultsPendingWeave.add(result) + discard CompilationUnitDeclaration + end + + weave phase + ----------- + //createWorldAndWeaver(classpath) + //the world and weaver have to be passed into the compiler, to + //support incremental use cases. + + buildXCutSet(resultsPendingWeave) + addTypeMungers(resultsPendingWeave) + weaveAspects(resultsPendingWeave) + weaveClasses(resultsPendingWeave) + + completion phase + ---------------- + foreach resultPendingWeave + requestor.acceptResult(result) -- each requestor does their own + thing + end + + // note : movement of any resouces is moved to outside of compile + // altogether. In eclipse, the xxxImageBuilders handle this. +} + + +buildXCutSet(resultsPendingWeave) { + foreach resultPendingWeave + foreach classfile + resolve + if aspect, add to xcut set. + end + end +} + +addTypeMungers(resultsPendingWeave) { + foreach resultPendingWeave + foreach classfile + resolve + addTypeMungers + end + end +} + +weaveAspect(resultsPendingWeave) { + foreach resultPendingWeave + foreach classfile + get corresponding BcelObjectType + weave + update classfile held in result + end + end +} + +weaveClass(resultsPendingWeave) { + foreach resultPendingWeave + foreach classfile + get corresponding BcelObjectType + weave + update classfile held in result + end + end +} + + +Note on createWorldAndWeaver(classpath) + - we can probably avoid having to turn the Eclipse nameEnvironment + into an externalized classpath by extending + weaver.bcel.ClasspathManager to cope with "third party" managed + classpath entries. On the eclipse side we can implement some + interface and map it back into a call to INameEnvironment.findType - + will need to cast returned IBinaryType into ClassFileReader, this is + the only nasty. Much better than doing classpath nonsense though. + +Note on handling the outjar option: + - this will be addressed by the requestor, if they want the results + to go into an outjar, they can do so when accepting results. It will + also have to be known by the piece of logic that moves resources (but + that is outside of compile anyway). + +Note on handling sourceDirs: + - this is a command-line option only, and is handled by adding all + the source files in the directories to the list of sourceUnits passed + into compile. + +Note on handling aspectpath: + - this is a list of directories and jar files containing class files + to be added to the list of aspects. These class files will be added + to the weaver's list of added aspects at the start of the weave phase + +Note on handling injars, inpath: + - these contain a set of class files that were not generated via + parsing source, but instead are read directly from disk. We build a + dummy CompilationResult in which getClassFiles() returns ClassFile + objects for each of the class files. (Note, may need to define a + ClassFile subclass with that just takes byte[] - this is a horrid + hack but contained, and keeps the rest of the design clean). + +Note on handling -XnoWeave: + - just skip the weave phase! + + +Handling Batch Compiles From Eclipse Using the New Model +======================================================== + +Eclipse is responsible for building the name enviroment and list of +ICompilationUnits to be compiled (does this already today). Eclipse is +also responsible for creating and passing in the desired requestor +(does this already today too). + +We will add a new BcelWorld constructor that takes an +org.aspectj.weaver.IManagedClasspath or similar in place of a +List of String classpath entries. ClasspathManager will be extended to +do the right thing with this, and on the Eclipse side we will +implement the interface backed by an INameEnvironment as discussed in +the notes above. + +The AspectJ specific options (aspectpath etc) are stored in an +extension of IJavaProject, IAspectJProject, and persisted in .ajpath +(analagous to .classpath) in the AspectJ project. + +The AbstractImageBuilder handles resource copying, and we don't need +to change this logic in any way. + +That's all folks! + +Handling Batch Compiles From ajc Using the New Model +==================================================== + +AjBuildManager creates the list of ICompilationUnits to be compiled in +the same way that it does today. + +It could obtain a classpath to give to the weaver from AjBuildConfig +in the same way that it does today - but it might be simpler and more +consistent to pass across an IManagedClasspath built from the +FileSystem (INameEnvironment) built from the classpath - this will +give consistency across inside and outside Eclipse compiles. + +The compiler is constructed with a requestor that writes class files +in CompilationUnitResults out to disk at the output location (or jar +file) in the AjBuildConfig. + +The AspectJ specific options (aspectpath etc) are obtained from +AjBuildConfig as today. + +Resource copying will ideally be handled outside of the weaver (from +source dirs and inpath dirs only) inside AjBuildManager. + +How Incremental Compilation Works in the JDT +============================================ + +Incremental compilation begins in the JavaBuilder with a request to +perform an incremental build. If the classpath of the project has +changed, or a binary project member (jar or .class file) has changed, +it reverts to a full build. + +An IncrementalImageBuilder is then created and asked to build the +deltas since the last build. If this succeeds the new build state is +recorded for the next compile, otherwise we revert to a full build. + +The IncrementalImageBuilder algorithm proceeds as follows: + // initialize builder + // walk this project's deltas, find changed source files + // walk prereq projects' deltas, find changed class files & add + affected source files + // use the build state # to skip the deltas for certain prereq projects + // ignore changed zip/jar files since they caused a full build + // compile the source files & acceptResult() + // compare the produced class files against the existing ones on disk + // recompile all dependent source files of any type with structural + changes or new/removed secondary type + // keep a loop counter to abort & perform a full build (after 5 attempts) + + + +How Incremental Compilation Works in AspectJ 1.1.x +================================================== + +As per batch building, except that: + +* if previous built state (AjState) exists, we do not create a new + bcelWorld (will use existing one). +* create list of source files to compile by looking at all source + files modified since last build date +* delete any class files that resulted from now deleted files, tell + the weaver about them +* extend list of source files to compile with files containing types + that reference types defined in modified source files +* ask the compiler to compile the source files +* find the list of source files that refer to things we changed, if + its non-empty, defer to a batch build (this is like the eclipse + algorithm, but with a loop count of 1). + +now hand-off to weaver... + +* tell the weaver about every class file we wrote +* weaver determines whether or not it needs to reweave everything by + looking at added and deleted classes and searching for aspects + (slight simplification) +* weave proceeds as before, weaving either only the added classes, or + everything, as required. + +How we want Incremental Compilation to proceed in AspectJ 1.2 +============================================================= + +This is harder to get right than batch (surprise). We still want the +same two statements to hold at the end of the compilation of an +individual source file: +1) all the class files have been written out and are ready to be used +2) all errors in any type defined in the file have been reported + +In both cases, the real 'incremental' logic is outside of the Compiler +itself (in IncrementalImageBuilder and in AjBuildManager). In the +current ajc case though, all compilation iterations have completed +before entering a single back-end weave phase. Pushing weaving inside +compile (as outlined in the proposal for batch building) makes this +design harder to accomplish in the new world. We are saved by the fact +that the current AspectJ incremental implementation currently only +supports one go round the loop before bailing out to a full build, and +we can mimic that behaviour easily. + +The logic in AjState that currently updates the weaver with +addedClassFiles as compilation results are produced will have to be +moved into the compiler (adaptor), to occur between the intermediate +class file generation and the weaving phase. + +Incremental AspectJ Compilation in Eclipse +========================================== + +The JavaBuilder (one per project) will be responsible for managing the +bcelWorld and bcelWeaver. These will be passed to the Compiler +(Adaptor) prior to calling compile. The incremental build manager +which processes deltas will be responsible for informing the weaver of +deleted class files. Added class files are determined as compilation +progresses. Weaving will happen inside the compile method, as +described for batch, with the twist that the whole world may be +rewoven if the weaver feels this is necessary. To keep things +initially as close to the current AspectJ implementation as possible, +we will set the maximum loop limit to 1 in the IncrementalImageBuilder +so that we bail out to a full build if we don't compile everything we +need in the first go. With a suitable test suite in place, there's no +conceptual reason why we couldn't put that back up to 5 (the JDT +default) as far as I can see right now. + When performing a whole world weave, the compiler may end up asking +requestors to acceptResult()s that they didn't request to be compiled, +but this is no different to the dependency analysis done on +referencing types that may then get added into subsequent incremental +loops in the JDT today. + +Incremental AspectJ Compilation in ajc +====================================== + +AjBuildManager manages the bcelWorld and weaver as it does today, and +passes them to the compiler adaptor for it to call the weave method +rather than AjBuildManager calling weave directly as it does +today. + + +Note on handling aspectpath: +If the JavaBuilder detects that the aspectpath itself has changed in +any way, it will request a full build. If delta analysis during the +first phase of incremental compilation detects that a jar or class +file in an aspectpath has changed, it will bail out to a full build. + +Note on handling injars, inpath: +We must make sure that the delta analysis allows a project with only +an inpath change to proceed to building (rather than thinking that +there is nothing to do). Any changed jars or class files will have +their classes added to the weaver, and the weaver will be notified of +deletions too. We need to ensure that we still continue on to +compilation even when there are no "source files" in the work queue - +will need some design. + +For tomorrow: start looking at refactoring AspectJ codebase itself to +fit the new shape, ahead of trying to do ImageBuilder integration at +the same time (in AspectJ, I have the test harness to guide me).
\ No newline at end of file diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java index 93cad315d..4b128b17c 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java @@ -16,14 +16,20 @@ package org.aspectj.ajdt.internal.core.builder; import java.io.*; import java.util.*; import java.util.jar.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; -import org.aspectj.ajdt.internal.compiler.AjCompiler; +import org.aspectj.ajdt.internal.compiler.AjCompilerAdapter; +import org.aspectj.ajdt.internal.compiler.IIntermediateResultsRequestor; +import org.aspectj.ajdt.internal.compiler.IOutputClassFileNameProvider; +import org.aspectj.ajdt.internal.compiler.InterimCompilationResult; import org.aspectj.ajdt.internal.compiler.lookup.*; import org.aspectj.ajdt.internal.compiler.problem.AjProblemReporter; import org.aspectj.asm.*; //import org.aspectj.asm.internal.*; import org.aspectj.asm.internal.ProgramElement; import org.aspectj.bridge.*; +import org.aspectj.util.FileUtil; import org.aspectj.weaver.World; import org.aspectj.weaver.bcel.*; import org.eclipse.jdt.core.compiler.*; @@ -36,12 +42,17 @@ import org.eclipse.jdt.internal.compiler.parser.Parser; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; //import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; -public class AjBuildManager { +public class AjBuildManager implements IOutputClassFileNameProvider,ICompilerAdapterFactory { + private static final String CANT_WRITE_RESULT = "unable to write compilation result"; static final boolean FAIL_IF_RUNTIME_NOT_FOUND = false; private IProgressListener progressListener = null; private int compiledCount; private int sourceFileCount; + + private ZipOutputStream zos; + private boolean batchCompile = true; + private INameEnvironment environment; private IHierarchy structureModel; public AjBuildConfig buildConfig; @@ -84,6 +95,8 @@ public class AjBuildManager { IMessageHandler baseHandler, boolean batch) throws IOException, AbortException { + batchCompile = batch; + try { if (batch) { this.state = new AjState(this); @@ -108,7 +121,11 @@ public class AjBuildManager { // if (batch) { setBuildConfig(buildConfig); //} - setupModel(); +// if (batch) { +// if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) { + setupModel(); +// } +// } if (batch) { initBcelWorld(handler); } @@ -116,6 +133,11 @@ public class AjBuildManager { return false; } + if (buildConfig.getOutputJar() != null) { + OutputStream os = FileUtil.makeOutputStream(buildConfig.getOutputJar()); + zos = new ZipOutputStream(os); + } + if (batch) { // System.err.println("XXXX batch: " + buildConfig.getFiles()); if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) { @@ -153,7 +175,8 @@ public class AjBuildManager { // have to tell state we succeeded or next is not incremental state.successfulCompile(buildConfig); - /*boolean weaved = */weaveAndGenerateClassFiles(); + copyResourcesToDestination(); + /*boolean weaved = *///weaveAndGenerateClassFiles(); // if not weaved, then no-op build, no model changes // but always returns true // XXX weaved not in Mik's incremental @@ -162,9 +185,20 @@ public class AjBuildManager { } return !handler.hasErrors(); } finally { + if (zos != null) { + zos.close(); + } handler = null; } } + + private void copyResourcesToDestination() throws IOException { + if (buildConfig.getOutputJar() != null) { + bcelWeaver.dumpResourcesToOutJar(zos); + } else { + bcelWeaver.dumpResourcesToOutPath(); + } + } /** * Responsible for managing the ASM model between builds. Contains the policy for @@ -172,8 +206,8 @@ public class AjBuildManager { * * TODO: implement incremental policy. */ - private void setupModel() { - String rootLabel = "<root>"; + private void setupModel() { + String rootLabel = "<root>"; IHierarchy model = AsmManager.getDefault().getHierarchy(); AsmManager.getDefault().getRelationshipMap().clear(); @@ -197,6 +231,7 @@ public class AjBuildManager { bcelWorld.setXnoInline(buildConfig.isXnoInline()); bcelWorld.setXlazyTjp(buildConfig.isXlazyTjp()); bcelWeaver = new BcelWeaver(bcelWorld); + state.binarySourceFiles = new HashMap(); for (Iterator i = buildConfig.getAspectpath().iterator(); i.hasNext();) { File f = (File) i.next(); @@ -218,12 +253,14 @@ public class AjBuildManager { //??? incremental issues for (Iterator i = buildConfig.getInJars().iterator(); i.hasNext(); ) { File inJar = (File)i.next(); - bcelWeaver.addJarFile(inJar, buildConfig.getOutputDir(),false); + List unwovenClasses = bcelWeaver.addJarFile(inJar, buildConfig.getOutputDir(),false); + state.binarySourceFiles.put(inJar.getPath(), unwovenClasses); } for (Iterator i = buildConfig.getInpath().iterator(); i.hasNext(); ) { File inPathElement = (File)i.next(); - bcelWeaver.addJarFile(inPathElement,buildConfig.getOutputDir(),true); + List unwovenClasses = bcelWeaver.addJarFile(inPathElement,buildConfig.getOutputDir(),true); + state.binarySourceFiles.put(inPathElement.getPath(),unwovenClasses); // good enough for ajc to lump these together } if (buildConfig.getSourcePathResources() != null) { @@ -252,32 +289,32 @@ public class AjBuildManager { } } - public boolean weaveAndGenerateClassFiles() throws IOException { - handler.handleMessage(MessageUtil.info("weaving")); - if (progressListener != null) progressListener.setText("weaving aspects"); - bcelWeaver.setProgressListener(progressListener, 0.5, 0.5/state.addedClassFiles.size()); - //!!! doesn't provide intermediate progress during weaving - // XXX add all aspects even during incremental builds? - addAspectClassFilesToWeaver(state.addedClassFiles); - if (buildConfig.isNoWeave()) { - if (buildConfig.getOutputJar() != null) { - bcelWeaver.dumpUnwoven(buildConfig.getOutputJar()); - } else { - bcelWeaver.dumpUnwoven(); - bcelWeaver.dumpResourcesToOutPath(); - } - } else { - if (buildConfig.getOutputJar() != null) { - bcelWeaver.weave(buildConfig.getOutputJar()); - } else { - bcelWeaver.weave(); - bcelWeaver.dumpResourcesToOutPath(); - } - } - if (progressListener != null) progressListener.setProgress(1.0); - return true; - //return messageAdapter.getErrorCount() == 0; //!javaBuilder.notifier.anyErrors(); - } +// public boolean weaveAndGenerateClassFiles() throws IOException { +// handler.handleMessage(MessageUtil.info("weaving")); +// if (progressListener != null) progressListener.setText("weaving aspects"); +// bcelWeaver.setProgressListener(progressListener, 0.5, 0.5/state.addedClassFiles.size()); +// //!!! doesn't provide intermediate progress during weaving +// // XXX add all aspects even during incremental builds? +// addAspectClassFilesToWeaver(state.addedClassFiles); +// if (buildConfig.isNoWeave()) { +// if (buildConfig.getOutputJar() != null) { +// bcelWeaver.dumpUnwoven(buildConfig.getOutputJar()); +// } else { +// bcelWeaver.dumpUnwoven(); +// bcelWeaver.dumpResourcesToOutPath(); +// } +// } else { +// if (buildConfig.getOutputJar() != null) { +// bcelWeaver.weave(buildConfig.getOutputJar()); +// } else { +// bcelWeaver.weave(); +// bcelWeaver.dumpResourcesToOutPath(); +// } +// } +// if (progressListener != null) progressListener.setProgress(1.0); +// return true; +// //return messageAdapter.getErrorCount() == 0; //!javaBuilder.notifier.anyErrors(); +// } public FileSystem getLibraryAccess(String[] classpaths, String[] filenames) { String defaultEncoding = (String) buildConfig.getJavaOptions().get(CompilerOptions.OPTION_Encoding); @@ -352,42 +389,20 @@ public class AjBuildManager { } //System.out.println("compiling"); - INameEnvironment environment = getLibraryAccess(classpaths, filenames); + environment = getLibraryAccess(classpaths, filenames); if (!state.classesFromName.isEmpty()) { environment = new StatefulNameEnvironment(environment, state.classesFromName); } - AjCompiler compiler = new AjCompiler( - environment, - DefaultErrorHandlingPolicies.proceedWithAllProblems(), - buildConfig.getJavaOptions(), - getBatchRequestor(), - getProblemFactory()); - - - AjProblemReporter pr = - new AjProblemReporter(DefaultErrorHandlingPolicies.proceedWithAllProblems(), - compiler.options, getProblemFactory()); - - compiler.problemReporter = pr; - - AjLookupEnvironment le = - new AjLookupEnvironment(compiler, compiler.options, pr, environment); - EclipseFactory factory = new EclipseFactory(le); -// ew.setLint(bcelWorld.getLint()); -// ew.setXnoInline(buildConfig.isXnoInline()); - le.factory = factory; - pr.factory = factory; - le.factory.buildManager = this; - - compiler.lookupEnvironment = le; + org.eclipse.jdt.internal.compiler.Compiler.setCompilerAdapterFactory(this); + org.eclipse.jdt.internal.compiler.Compiler compiler = + new org.eclipse.jdt.internal.compiler.Compiler(environment, + DefaultErrorHandlingPolicies.proceedWithAllProblems(), + buildConfig.getJavaOptions(), + getBatchRequestor(), + getProblemFactory()); - compiler.parser = - new Parser( - pr, - compiler.options.parseLiteralExpressionsAsConstants); - CompilerOptions options = compiler.options; options.produceReferenceInfo(true); //TODO turn off when not needed @@ -396,75 +411,138 @@ public class AjBuildManager { // cleanup environment.cleanup(); + environment = null; } /* * Answer the component to which will be handed back compilation results from the compiler */ - public ICompilerRequestor getBatchRequestor() { - return new ICompilerRequestor() { + public IIntermediateResultsRequestor getInterimResultRequestor() { + return new IIntermediateResultsRequestor() { int lineDelta = 0; - public void acceptResult(CompilationResult compilationResult) { + public void acceptResult(InterimCompilationResult result) { if (progressListener != null) { compiledCount++; progressListener.setProgress((compiledCount/2.0)/sourceFileCount); - progressListener.setText("compiled: " + new String(compilationResult.getFileName())); + progressListener.setText("compiled: " + result.fileName()); + } + state.noteResult(result); + } + }; + } + + public ICompilerRequestor getBatchRequestor() { + return new ICompilerRequestor() { + + public void acceptResult(CompilationResult unitResult) { + // end of compile, must now write the results to the output destination + // this is either a jar file or a file in a directory + if (!(unitResult.hasErrors() && !proceedOnError())) { + Enumeration classFiles = unitResult.compiledTypes.elements(); + while (classFiles.hasMoreElements()) { + ClassFile classFile = (ClassFile) classFiles.nextElement(); + String filename = new String(classFile.fileName()); + filename = filename.replace('/', File.separatorChar) + ".class"; + try { + if (buildConfig.getOutputJar() == null) { + writeDirectoryEntry(unitResult, classFile,filename); + } else { + writeZipEntry(classFile,filename); + } + } catch (IOException ex) { + IMessage message = EclipseAdapterUtils.makeErrorMessage( + unitResult.compilationUnit, + CANT_WRITE_RESULT, + ex); + handler.handleMessage(message); + } + + } } - if (compilationResult.hasProblems() || compilationResult.hasTasks()) { - IProblem[] problems = compilationResult.getAllProblems(); + if (unitResult.hasProblems() || unitResult.hasTasks()) { + IProblem[] problems = unitResult.getAllProblems(); for (int i=0; i < problems.length; i++) { IMessage message = - EclipseAdapterUtils.makeMessage(compilationResult.compilationUnit, problems[i]); + EclipseAdapterUtils.makeMessage(unitResult.compilationUnit, problems[i]); handler.handleMessage(message); } } - outputClassFiles(compilationResult); - } - }; - } - - private boolean proceedOnError() { - return true; //??? - } - public void outputClassFiles(CompilationResult unitResult) { - if (unitResult == null) return; - - String sourceFileName = new String(unitResult.fileName); - if (!(unitResult.hasErrors() && !proceedOnError())) { - List unwovenClassFiles = new ArrayList(); - Enumeration classFiles = unitResult.compiledTypes.elements(); - while (classFiles.hasMoreElements()) { - ClassFile classFile = (ClassFile) classFiles.nextElement(); - String filename = new String(classFile.fileName()); - filename = filename.replace('/', File.separatorChar) + ".class"; - + } + + private void writeDirectoryEntry( + CompilationResult unitResult, + ClassFile classFile, + String filename) + throws IOException { File destinationPath = buildConfig.getOutputDir(); + String outFile; if (destinationPath == null) { - filename = new File(filename).getName(); - filename = new File(extractDestinationPathFromSourceFile(unitResult), filename).getPath(); + outFile = new File(filename).getName(); + outFile = new File(extractDestinationPathFromSourceFile(unitResult), outFile).getPath(); } else { - filename = new File(destinationPath, filename).getPath(); + outFile = new File(destinationPath, filename).getPath(); } + BufferedOutputStream os = + FileUtil.makeOutputStream(new File(outFile)); + os.write(classFile.getBytes()); + os.close(); + } + + private void writeZipEntry(ClassFile classFile, String name) + throws IOException { + name = name.replace(File.separatorChar,'/'); + ZipEntry newEntry = new ZipEntry(name); //??? get compression scheme right - //System.out.println("classfile: " + filename); - unwovenClassFiles.add(new UnwovenClassFile(filename, classFile.getBytes())); + zos.putNextEntry(newEntry); + zos.write(classFile.getBytes()); + zos.closeEntry(); } - state.noteClassesFromFile(unitResult, sourceFileName, unwovenClassFiles); -// System.out.println("file: " + sourceFileName); -// for (int i=0; i < unitResult.simpleNameReferences.length; i++) { -// System.out.println("simple: " + new String(unitResult.simpleNameReferences[i])); -// } -// for (int i=0; i < unitResult.qualifiedReferences.length; i++) { -// System.out.println("qualified: " + -// new String(CharOperation.concatWith(unitResult.qualifiedReferences[i], '/'))); -// } - } else { - state.noteClassesFromFile(null, sourceFileName, Collections.EMPTY_LIST); - } + }; } - + + protected boolean proceedOnError() { + return true; //??? + } + +// public void noteClassFiles(AjCompiler.InterimResult result) { +// if (result == null) return; +// CompilationResult unitResult = result.result; +// String sourceFileName = result.fileName(); +// if (!(unitResult.hasErrors() && !proceedOnError())) { +// List unwovenClassFiles = new ArrayList(); +// Enumeration classFiles = unitResult.compiledTypes.elements(); +// while (classFiles.hasMoreElements()) { +// ClassFile classFile = (ClassFile) classFiles.nextElement(); +// String filename = new String(classFile.fileName()); +// filename = filename.replace('/', File.separatorChar) + ".class"; +// +// File destinationPath = buildConfig.getOutputDir(); +// if (destinationPath == null) { +// filename = new File(filename).getName(); +// filename = new File(extractDestinationPathFromSourceFile(unitResult), filename).getPath(); +// } else { +// filename = new File(destinationPath, filename).getPath(); +// } +// +// //System.out.println("classfile: " + filename); +// unwovenClassFiles.add(new UnwovenClassFile(filename, classFile.getBytes())); +// } +// state.noteClassesFromFile(unitResult, sourceFileName, unwovenClassFiles); +//// System.out.println("file: " + sourceFileName); +//// for (int i=0; i < unitResult.simpleNameReferences.length; i++) { +//// System.out.println("simple: " + new String(unitResult.simpleNameReferences[i])); +//// } +//// for (int i=0; i < unitResult.qualifiedReferences.length; i++) { +//// System.out.println("qualified: " + +//// new String(CharOperation.concatWith(unitResult.qualifiedReferences[i], '/'))); +//// } +// } else { +// state.noteClassesFromFile(null, sourceFileName, Collections.EMPTY_LIST); +// } +// } +// private void setBuildConfig(AjBuildConfig buildConfig) { this.buildConfig = buildConfig; @@ -564,5 +642,57 @@ public class AjBuildManager { public void setProgressListener(IProgressListener progressListener) { this.progressListener = progressListener; } + + + /* (non-Javadoc) + * @see org.aspectj.ajdt.internal.compiler.AjCompiler.IOutputClassFileNameProvider#getOutputClassFileName(char[]) + */ + public String getOutputClassFileName(char[] eclipseClassFileName, CompilationResult result) { + String filename = new String(eclipseClassFileName); + filename = filename.replace('/', File.separatorChar) + ".class"; + File destinationPath = buildConfig.getOutputDir(); + String outFile; + if (destinationPath == null) { + outFile = new File(filename).getName(); + outFile = new File(extractDestinationPathFromSourceFile(result), outFile).getPath(); + } else { + outFile = new File(destinationPath, filename).getPath(); + } + return outFile; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ICompilerAdapterFactory#getAdapter(org.eclipse.jdt.internal.compiler.Compiler) + */ + public ICompilerAdapter getAdapter(org.eclipse.jdt.internal.compiler.Compiler forCompiler) { + // complete compiler config and return a suitable adapter... + AjProblemReporter pr = + new AjProblemReporter(DefaultErrorHandlingPolicies.proceedWithAllProblems(), + forCompiler.options, getProblemFactory()); + + forCompiler.problemReporter = pr; + + AjLookupEnvironment le = + new AjLookupEnvironment(forCompiler, forCompiler.options, pr, environment); + EclipseFactory factory = new EclipseFactory(le); + le.factory = factory; + pr.factory = factory; + le.factory.buildManager = this; + + forCompiler.lookupEnvironment = le; + + forCompiler.parser = + new Parser( + pr, + forCompiler.options.parseLiteralExpressionsAsConstants); + + return new AjCompilerAdapter(forCompiler,batchCompile,bcelWorld,bcelWeaver, + factory, + getInterimResultRequestor(),this, + state.binarySourceFiles, + state.resultsFromFile.values(), + buildConfig.isNoWeave()); + } + } // class AjBuildManager diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjState.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjState.java index db7ea2ab0..206bcec1a 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjState.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjState.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.aspectj.ajdt.internal.compiler.InterimCompilationResult; import org.aspectj.weaver.bcel.UnwovenClassFile; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; @@ -43,9 +44,10 @@ public class AjState { AjBuildConfig buildConfig; AjBuildConfig newBuildConfig; - Map/*<File, List<UnwovenClassFile>*/ classesFromFile = new HashMap(); +// Map/*<File, List<UnwovenClassFile>*/ classesFromFile = new HashMap(); + Map/*<File, CompilationResult*/ resultsFromFile = new HashMap(); Map/*<File, ReferenceCollection>*/ references = new HashMap(); - + Map/*File, List<UnwovenClassFile>*/ binarySourceFiles = new HashMap(); Map/*<String, UnwovenClassFile>*/ classesFromName = new HashMap(); ArrayList/*<String>*/ qualifiedStrings; @@ -143,13 +145,12 @@ public class AjState { File deletedFile = (File)i.next(); //System.out.println("deleting: " + deletedFile); addDependentsOf(deletedFile); - List unwovenClassFiles = (List)classesFromFile.get(deletedFile); - classesFromFile.remove(deletedFile); + InterimCompilationResult intRes = (InterimCompilationResult) resultsFromFile.get(deletedFile); + resultsFromFile.remove(deletedFile); //System.out.println("deleting: " + unwovenClassFiles); - if (unwovenClassFiles == null) continue; - for (Iterator j = unwovenClassFiles.iterator(); j.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)j.next(); - deleteClassFile(classFile); + if (intRes == null) continue; + for (int j=0; j<intRes.unwovenClassFiles().length; j++ ) { + deleteClassFile(intRes.unwovenClassFiles()[j]); } } } @@ -164,82 +165,151 @@ public class AjState { //!!! might be okay to ignore } } + + public void noteResult(InterimCompilationResult result) { + File sourceFile = new File(result.fileName()); + CompilationResult cr = result.result(); - public void noteClassesFromFile(CompilationResult result, String sourceFileName, List unwovenClassFiles) { - File sourceFile = new File(sourceFileName); - if (result != null) { - references.put(sourceFile, new ReferenceCollection(result.qualifiedReferences, result.simpleNameReferences)); + references.put(sourceFile, new ReferenceCollection(cr.qualifiedReferences, cr.simpleNameReferences)); } - - List previous = (List)classesFromFile.get(sourceFile); - List newClassFiles = new ArrayList(); - for (Iterator i = unwovenClassFiles.iterator(); i.hasNext();) { - UnwovenClassFile cf = (UnwovenClassFile) i.next(); - cf = writeClassFile(cf, findAndRemoveClassFile(cf.getClassName(), previous)); - newClassFiles.add(cf); - classesFromName.put(cf.getClassName(), cf); + + InterimCompilationResult previous = (InterimCompilationResult) resultsFromFile.get(sourceFile); + UnwovenClassFile[] unwovenClassFiles = result.unwovenClassFiles(); + for (int i = 0; i < unwovenClassFiles.length; i++) { + UnwovenClassFile lastTimeRound = removeFromPreviousIfPresent(unwovenClassFiles[i],previous); + recordClassFile(unwovenClassFiles[i],lastTimeRound); + classesFromName.put(unwovenClassFiles[i].getClassName(),unwovenClassFiles[i]); } - - if (previous != null && !previous.isEmpty()) { - for (Iterator i = previous.iterator(); i.hasNext();) { - UnwovenClassFile cf = (UnwovenClassFile) i.next(); - deleteClassFile(cf); + + if (previous != null) { + for (int i = 0; i < previous.unwovenClassFiles().length; i++) { + if (previous.unwovenClassFiles()[i] != null) { + deleteClassFile(previous.unwovenClassFiles()[i]); + } } } + resultsFromFile.put(sourceFile, result); - classesFromFile.put(sourceFile, newClassFiles); } - - private UnwovenClassFile findAndRemoveClassFile(String name, List previous) { + + private UnwovenClassFile removeFromPreviousIfPresent(UnwovenClassFile cf, InterimCompilationResult previous) { if (previous == null) return null; - for (Iterator i = previous.iterator(); i.hasNext();) { - UnwovenClassFile cf = (UnwovenClassFile) i.next(); - if (cf.getClassName().equals(name)) { - i.remove(); - return cf; - } + UnwovenClassFile[] unwovenClassFiles = previous.unwovenClassFiles(); + for (int i = 0; i < unwovenClassFiles.length; i++) { + UnwovenClassFile candidate = unwovenClassFiles[i]; + if ((candidate != null) && candidate.getFilename().equals(cf.getFilename())) { + unwovenClassFiles[i] = null; + return candidate; + } } return null; } + + private void recordClassFile(UnwovenClassFile thisTime, UnwovenClassFile lastTime) { + if (simpleStrings == null) return; // batch build - private UnwovenClassFile writeClassFile(UnwovenClassFile cf, UnwovenClassFile previous) { - if (simpleStrings == null) { // batch build - addedClassFiles.add(cf); - return cf; + if (lastTime == null) { + addDependentsOf(thisTime.getClassName()); + return; } - - try { - if (previous == null) { - addedClassFiles.add(cf); - addDependentsOf(cf.getClassName()); - return cf; - } - - byte[] oldBytes = previous.getBytes(); - byte[] newBytes = cf.getBytes(); - //if (this.compileLoop > 1) { // only optimize files which were recompiled during the dependent pass, see 33990 - notEqual : if (newBytes.length == oldBytes.length) { - for (int i = newBytes.length; --i >= 0;) { - if (newBytes[i] != oldBytes[i]) break notEqual; - } - //addedClassFiles.add(previous); //!!! performance wasting - buildManager.bcelWorld.addSourceObjectType(previous.getJavaClass()); - return previous; // bytes are identical so skip them + + byte[] newBytes = thisTime.getBytes(); + byte[] oldBytes = lastTime.getBytes(); + boolean bytesEqual = (newBytes.length == oldBytes.length); + for (int i = 0; (i < oldBytes.length) && bytesEqual; i++) { + if (newBytes[i] != oldBytes[i]) bytesEqual = false; + } + if (!bytesEqual) { + try { + ClassFileReader reader = new ClassFileReader(oldBytes, lastTime.getFilename().toCharArray()); + // ignore local types since they're only visible inside a single method + if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) { + addDependentsOf(lastTime.getClassName()); } - //} - ClassFileReader reader = new ClassFileReader(oldBytes, previous.getFilename().toCharArray()); - // ignore local types since they're only visible inside a single method - if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) { - addDependentsOf(cf.getClassName()); - } - } catch (ClassFormatException e) { - addDependentsOf(cf.getClassName()); + } catch (ClassFormatException e) { + addDependentsOf(lastTime.getClassName()); + } } - addedClassFiles.add(cf); - return cf; } + +// public void noteClassesFromFile(CompilationResult result, String sourceFileName, List unwovenClassFiles) { +// File sourceFile = new File(sourceFileName); +// +// if (result != null) { +// references.put(sourceFile, new ReferenceCollection(result.qualifiedReferences, result.simpleNameReferences)); +// } +// +// List previous = (List)classesFromFile.get(sourceFile); +// List newClassFiles = new ArrayList(); +// for (Iterator i = unwovenClassFiles.iterator(); i.hasNext();) { +// UnwovenClassFile cf = (UnwovenClassFile) i.next(); +// cf = writeClassFile(cf, findAndRemoveClassFile(cf.getClassName(), previous)); +// newClassFiles.add(cf); +// classesFromName.put(cf.getClassName(), cf); +// } +// +// if (previous != null && !previous.isEmpty()) { +// for (Iterator i = previous.iterator(); i.hasNext();) { +// UnwovenClassFile cf = (UnwovenClassFile) i.next(); +// deleteClassFile(cf); +// } +// } +// +// classesFromFile.put(sourceFile, newClassFiles); +// resultsFromFile.put(sourceFile, result); +// } +// +// private UnwovenClassFile findAndRemoveClassFile(String name, List previous) { +// if (previous == null) return null; +// for (Iterator i = previous.iterator(); i.hasNext();) { +// UnwovenClassFile cf = (UnwovenClassFile) i.next(); +// if (cf.getClassName().equals(name)) { +// i.remove(); +// return cf; +// } +// } +// return null; +// } +// +// private UnwovenClassFile writeClassFile(UnwovenClassFile cf, UnwovenClassFile previous) { +// if (simpleStrings == null) { // batch build +// addedClassFiles.add(cf); +// return cf; +// } +// +// try { +// if (previous == null) { +// addedClassFiles.add(cf); +// addDependentsOf(cf.getClassName()); +// return cf; +// } +// +// byte[] oldBytes = previous.getBytes(); +// byte[] newBytes = cf.getBytes(); +// //if (this.compileLoop > 1) { // only optimize files which were recompiled during the dependent pass, see 33990 +// notEqual : if (newBytes.length == oldBytes.length) { +// for (int i = newBytes.length; --i >= 0;) { +// if (newBytes[i] != oldBytes[i]) break notEqual; +// } +// //addedClassFiles.add(previous); //!!! performance wasting +// buildManager.bcelWorld.addSourceObjectType(previous.getJavaClass()); +// return previous; // bytes are identical so skip them +// } +// //} +// ClassFileReader reader = new ClassFileReader(oldBytes, previous.getFilename().toCharArray()); +// // ignore local types since they're only visible inside a single method +// if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) { +// addDependentsOf(cf.getClassName()); +// } +// } catch (ClassFormatException e) { +// addDependentsOf(cf.getClassName()); +// } +// addedClassFiles.add(cf); +// return cf; +// } + private static StringSet makeStringSet(List strings) { StringSet ret = new StringSet(strings.size()); for (Iterator iter = strings.iterator(); iter.hasNext();) { @@ -309,12 +379,11 @@ public class AjState { } protected void addDependentsOf(File sourceFile) { - List l = (List)classesFromFile.get(sourceFile); - if (l == null) return; + InterimCompilationResult intRes = (InterimCompilationResult)resultsFromFile.get(sourceFile); + if (intRes == null) return; - for (Iterator i = l.iterator(); i.hasNext();) { - UnwovenClassFile cf = (UnwovenClassFile) i.next(); - addDependentsOf(cf.getClassName()); + for (int i = 0; i < intRes.unwovenClassFiles().length; i++) { + addDependentsOf(intRes.unwovenClassFiles()[i].getClassName()); } } } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseAdapterUtils.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseAdapterUtils.java index d93d6e8cf..e75143db5 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseAdapterUtils.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseAdapterUtils.java @@ -21,7 +21,6 @@ import org.aspectj.bridge.Message; import org.aspectj.bridge.SourceLocation; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.util.Util; /** * @@ -42,7 +41,8 @@ public class EclipseAdapterUtils { if ((startPosition > endPosition) || ((startPosition <= 0) && (endPosition <= 0))) - return Util.bind("problem.noSourceInformation"); //$NON-NLS-1$ + //return Util.bind("problem.noSourceInformation"); //$NON-NLS-1$ + return "(no source information available)"; final char SPACE = '\u0020'; final char MARK = '^'; @@ -99,7 +99,7 @@ public class EclipseAdapterUtils { } } //mark the error position - for (int i = startPosition; + for (int i = startPosition + trimLeftIndex; // AMC if we took stuff off the start, take it into account! i <= (endPosition >= source.length ? source.length - 1 : endPosition); i++) underneath[pos++] = MARK; @@ -127,9 +127,29 @@ public class EclipseAdapterUtils { */ public static IMessage makeMessage(ICompilationUnit unit, IProblem problem) { ISourceLocation sourceLocation = makeSourceLocation(unit, problem); - return new Message(problem.getMessage(), sourceLocation, problem.isError()); + IProblem[] seeAlso = problem.seeAlso(); + ISourceLocation[] seeAlsoLocations = new ISourceLocation[seeAlso.length]; + for (int i = 0; i < seeAlso.length; i++) { + seeAlsoLocations[i] = new SourceLocation(new File(new String(seeAlso[i].getOriginatingFileName())), + seeAlso[i].getSourceLineNumber()); + + } + IMessage msg = new Message(problem.getMessage(), + problem.getSupplementaryMessageInfo(), + problem.isError() ? IMessage.ERROR : IMessage.WARNING, + sourceLocation, + null, + seeAlsoLocations); + return msg; } + public static IMessage makeErrorMessage(ICompilationUnit unit, String text, Exception ex) { + ISourceLocation loc = new SourceLocation(new File(new String(unit.getFileName())), + 0,0,0,""); + IMessage msg = new Message(text,IMessage.ERROR,ex,loc); + return msg; + } + private EclipseAdapterUtils() { } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java b/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java index e77a9f5a6..9d1fe890f 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java @@ -425,7 +425,9 @@ public class Main { String name = file.getName(); if (!toString || (-1 == text.indexOf(name))) { sb.append(FileUtil.getBestPath(file)); - sb.append(":" + loc.getLine()); + if (loc.getLine() > 0) { + sb.append(":" + loc.getLine()); + } int col = loc.getColumn(); if (0 < col) { sb.append(":" + col); @@ -435,6 +437,14 @@ public class Main { } context = loc.getContext(); } + + // per Wes' suggestion on dev... + if (message.getKind() == IMessage.ERROR) { + sb.append("error "); + } else if (message.getKind() == IMessage.WARNING) { + sb.append("warning "); + } + sb.append(text); if (null != context) { sb.append(LangUtil.EOL); diff --git a/org.eclipse.jdt.core/jdtcore-for-aspectj-src.zip b/org.eclipse.jdt.core/jdtcore-for-aspectj-src.zip Binary files differindex ee6b9bead..7ae98a7d5 100644 --- a/org.eclipse.jdt.core/jdtcore-for-aspectj-src.zip +++ b/org.eclipse.jdt.core/jdtcore-for-aspectj-src.zip diff --git a/org.eclipse.jdt.core/jdtcore-for-aspectj.jar b/org.eclipse.jdt.core/jdtcore-for-aspectj.jar Binary files differindex 5f74eec43..43f25273a 100644 --- a/org.eclipse.jdt.core/jdtcore-for-aspectj.jar +++ b/org.eclipse.jdt.core/jdtcore-for-aspectj.jar diff --git a/tests/ajcTests.xml b/tests/ajcTests.xml index 1897a556b..6aa96ee2e 100644 --- a/tests/ajcTests.xml +++ b/tests/ajcTests.xml @@ -7275,4 +7275,16 @@ <run class="SuperClosure" /> </ajc-test> + <ajc-test dir="incremental/initialTests/aspectSourceAdded" + title="add aspect source file and check world is rewoven" + keywords="incremental-test" > + <compile staging="true" + options="-incremental" + sourceroots="."/> + <inc-compile tag="20"> + <dir-changes added="Detour"/> + </inc-compile> + <run class="Main"/> + </ajc-test> + </suite> diff --git a/tests/incremental/initialTests/aspectSourceAdded/Detour.20.java b/tests/incremental/initialTests/aspectSourceAdded/Detour.20.java new file mode 100644 index 000000000..4cc707b99 --- /dev/null +++ b/tests/incremental/initialTests/aspectSourceAdded/Detour.20.java @@ -0,0 +1,7 @@ +public aspect Detour { + + void around() : execution(* Main.main(..)) { + System.out.println("Main class successfully woven"); + } + +}
\ No newline at end of file diff --git a/tests/incremental/initialTests/aspectSourceAdded/Main.java b/tests/incremental/initialTests/aspectSourceAdded/Main.java new file mode 100644 index 000000000..7c85f90c2 --- /dev/null +++ b/tests/incremental/initialTests/aspectSourceAdded/Main.java @@ -0,0 +1,9 @@ +import org.aspectj.testing.Tester; + +public class Main { + + public static void main(String[] args) { + Tester.checkFailed("Incremental compilation did not appear to (re)weave Main"); + } + +}
\ No newline at end of file diff --git a/tests/incremental/initialTests/suite.xml b/tests/incremental/initialTests/suite.xml index b6b568384..95e52be1f 100644 --- a/tests/incremental/initialTests/suite.xml +++ b/tests/incremental/initialTests/suite.xml @@ -105,5 +105,16 @@ <run class="Main"/> </ajc-test> + <ajc-test dir="aspectSourceAdded" + title="add aspect source file and check world is rewoven" + keywords="incremental-test" > + <compile staging="true" + options="-incremental" + sourceroots="."/> + <inc-compile tag="20"> + <dir-changes added="Detour"/> + </inc-compile> + <run class="Main"/> + </ajc-test> </suite> diff --git a/util/src/org/aspectj/util/FileUtil.java b/util/src/org/aspectj/util/FileUtil.java index c7663ae63..34bf103a9 100644 --- a/util/src/org/aspectj/util/FileUtil.java +++ b/util/src/org/aspectj/util/FileUtil.java @@ -341,10 +341,14 @@ public class FileUtil { */ public static String getBestPath(File file) { LangUtil.throwIaxIfNull(file, "file"); - try { - return file.getCanonicalPath(); - } catch (IOException e) { - return file.getAbsolutePath(); + if (file.exists()) { + try { + return file.getCanonicalPath(); + } catch (IOException e) { + return file.getAbsolutePath(); + } + } else { + return file.getPath(); } } diff --git a/weaver/src/org/aspectj/weaver/IClassFileProvider.java b/weaver/src/org/aspectj/weaver/IClassFileProvider.java new file mode 100644 index 000000000..73700e0bb --- /dev/null +++ b/weaver/src/org/aspectj/weaver/IClassFileProvider.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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; + +import java.util.Iterator; + +/** + * @author colyer + * + * Clients implementing the IClassFileProvider can have a set of class files under + * their control woven by a weaver, by calling the weave(IClassFileProvider source) method. + * The contract is that a call to getRequestor().acceptResult() is providing a result for + * the class file most recently returned from the getClassFileIterator(). + */ +public interface IClassFileProvider { + + /** + * Answer an iterator that can be used to iterate over a set of UnwovenClassFiles to + * be woven. During a weave, this method may be called multiple times. + * @return iterator over UnwovenClassFiles. + */ + Iterator getClassFileIterator(); + + /** + * The client to which the woven results should be returned. + */ + IWeaveRequestor getRequestor(); +} diff --git a/weaver/src/org/aspectj/weaver/IWeaveRequestor.java b/weaver/src/org/aspectj/weaver/IWeaveRequestor.java new file mode 100644 index 000000000..f61a9793e --- /dev/null +++ b/weaver/src/org/aspectj/weaver/IWeaveRequestor.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * 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; + +import org.aspectj.weaver.bcel.UnwovenClassFile; + +/** + * @author colyer + * + * This interface is implemented by clients driving weaving through the + * IClassFileProvider interface. It is used by the weaver to return woven + * class file results back to the client. The client can correlate weave + * results with inputs since it knows the last UnwovenClassFile returned by + * its iterator. + */ +public interface IWeaveRequestor { + + /* + * A class file resulting from a weave (yes, even though the type name + * says "unwoven"...). + */ + void acceptResult(UnwovenClassFile result); + + // various notifications to the requestor about our progress... + void processingReweavableState(); + void addingTypeMungers(); + void weavingAspects(); + void weavingClasses(); + void weaveCompleted(); +} |