summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/developer/amcDesignNotes.txt388
-rw-r--r--org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java348
-rw-r--r--org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjState.java211
-rw-r--r--org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseAdapterUtils.java28
-rw-r--r--org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java12
-rw-r--r--org.eclipse.jdt.core/jdtcore-for-aspectj-src.zipbin3413286 -> 3393122 bytes
-rw-r--r--org.eclipse.jdt.core/jdtcore-for-aspectj.jarbin3831151 -> 3805780 bytes
-rw-r--r--tests/ajcTests.xml12
-rw-r--r--tests/incremental/initialTests/aspectSourceAdded/Detour.20.java7
-rw-r--r--tests/incremental/initialTests/aspectSourceAdded/Main.java9
-rw-r--r--tests/incremental/initialTests/suite.xml11
-rw-r--r--util/src/org/aspectj/util/FileUtil.java12
-rw-r--r--weaver/src/org/aspectj/weaver/IClassFileProvider.java36
-rw-r--r--weaver/src/org/aspectj/weaver/IWeaveRequestor.java38
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
index ee6b9bead..7ae98a7d5 100644
--- a/org.eclipse.jdt.core/jdtcore-for-aspectj-src.zip
+++ b/org.eclipse.jdt.core/jdtcore-for-aspectj-src.zip
Binary files differ
diff --git a/org.eclipse.jdt.core/jdtcore-for-aspectj.jar b/org.eclipse.jdt.core/jdtcore-for-aspectj.jar
index 5f74eec43..43f25273a 100644
--- a/org.eclipse.jdt.core/jdtcore-for-aspectj.jar
+++ b/org.eclipse.jdt.core/jdtcore-for-aspectj.jar
Binary files differ
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();
+}