Browse Source

re-implementing support for incremental compilation after move to 2.1

this time we're doing it all ourselves rather than using the Builders which
have steadily come to depend more on having an actual eclipse 
workbench running
tags/V1_1_0_RC2
jhugunin 21 years ago
parent
commit
ac764de72c

+ 7
- 2
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java View File

@@ -18,7 +18,6 @@ import java.util.*;
import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration;
import org.aspectj.bridge.IMessage;
import org.aspectj.weaver.*;
import org.aspectj.weaver.bcel.BcelTypeMunger;
import org.aspectj.weaver.patterns.*;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
@@ -155,6 +154,12 @@ public class AjLookupEnvironment extends LookupEnvironment {
private void weaveInterTypeDeclarations(SourceTypeBinding sourceType, Collection typeMungers, Collection declareParents, boolean skipInners) {
// if (new String(sourceType.sourceName()).equals("Target")) {
// Thread.currentThread().dumpStack();
// }
//
// System.out.println("weaving types: " + new String(sourceType.sourceName()));
// System.out.println(" mungers: " + typeMungers);
ResolvedTypeX onType = factory.fromEclipse(sourceType);
onType.clearInterTypeMungers();
@@ -171,7 +176,7 @@ public class AjLookupEnvironment extends LookupEnvironment {
for (Iterator i = onType.getInterTypeMungers().iterator(); i.hasNext();) {
EclipseTypeMunger munger = (EclipseTypeMunger) i.next();
//System.err.println("applying: " + munger + " to " + new String(sourceType.sourceName));
//System.out.println("applying: " + munger + " to " + new String(sourceType.sourceName));
munger.munge(sourceType);
}

+ 19
- 5
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseFactory.java View File

@@ -140,21 +140,35 @@ public class EclipseFactory {
public void finishTypeMungers() {
// make sure that type mungers are
finishedTypeMungers = new ArrayList();
Collection ret = new ArrayList();
Collection baseTypeMungers =
getWorld().getCrosscuttingMembersSet().getTypeMungers();
for (Iterator i = baseTypeMungers.iterator(); i.hasNext(); ) {
ConcreteTypeMunger munger = (ConcreteTypeMunger) i.next();
EclipseTypeMunger etm = makeEclipseTypeMunger(munger);
if (etm != null) finishedTypeMungers.add(etm);
}
if (etm != null) ret.add(etm);
}
finishedTypeMungers = ret;
}
public EclipseTypeMunger makeEclipseTypeMunger(ConcreteTypeMunger concrete) {
if (concrete instanceof EclipseTypeMunger) return (EclipseTypeMunger)concrete;
//System.err.println("make munger: " + concrete);
//!!! can't do this if we want incremental to work right
//if (concrete instanceof EclipseTypeMunger) return (EclipseTypeMunger)concrete;
//System.err.println(" was not eclipse");
if (concrete.getMunger() != null && EclipseTypeMunger.supportsKind(concrete.getMunger().getKind())) {
return new EclipseTypeMunger(this, concrete.getMunger(), concrete.getAspectType(), null);
AbstractMethodDeclaration method = null;
if (concrete instanceof EclipseTypeMunger) {
method = ((EclipseTypeMunger)concrete).getSourceMethod();
}
EclipseTypeMunger ret =
new EclipseTypeMunger(this, concrete.getMunger(), concrete.getAspectType(), method);
if (ret.getSourceLocation() == null) {
ret.setSourceLocation(concrete.getSourceLocation());
}
return ret;
} else {
return null;
}

+ 28
- 7
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseTypeMunger.java View File

@@ -31,9 +31,12 @@ import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;


public class EclipseTypeMunger extends ConcreteTypeMunger {
protected ReferenceBinding targetBinding = null;
private ResolvedTypeX targetTypeX;
//protected ReferenceBinding targetBinding = null;
private AbstractMethodDeclaration sourceMethod;
private EclipseFactory world;
private ISourceLocation sourceLocation;

public EclipseTypeMunger(EclipseFactory world, ResolvedTypeMunger munger, ResolvedTypeX aspectType,
AbstractMethodDeclaration sourceMethod)
@@ -41,8 +44,13 @@ public class EclipseTypeMunger extends ConcreteTypeMunger {
super(munger, aspectType);
this.world = world;
this.sourceMethod = sourceMethod;
TypeX targetTypeX = munger.getSignature().getDeclaringType();
targetBinding = (ReferenceBinding)world.makeTypeBinding(targetTypeX);
if (sourceMethod != null) {
this.sourceLocation =
new EclipseSourceLocation(sourceMethod.compilationResult,
sourceMethod.sourceStart, sourceMethod.sourceEnd);
}
targetTypeX = munger.getSignature().getDeclaringType().resolve(world.getWorld());
//targetBinding = (ReferenceBinding)world.makeTypeBinding(targetTypeX);
}
public static boolean supportsKind(ResolvedTypeMunger.Kind kind) {
@@ -60,7 +68,10 @@ public class EclipseTypeMunger extends ConcreteTypeMunger {
* i.e. adds Method|FieldBindings, plays with inheritance, ...
*/
public boolean munge(SourceTypeBinding sourceType) {
if (sourceType != targetBinding) return false; //??? move this test elsewhere
if (!world.fromEclipse(sourceType).equals(targetTypeX)) return false; //??? move this test elsewhere
//System.out.println("munging: " + sourceType);
// System.out.println("match: " + world.fromEclipse(sourceType) +
// " with " + targetTypeX);
if (munger.getKind() == ResolvedTypeMunger.Field) {
mungeNewField(sourceType, (NewFieldTypeMunger)munger);
} else if (munger.getKind() == ResolvedTypeMunger.Method) {
@@ -100,7 +111,7 @@ public class EclipseTypeMunger extends ConcreteTypeMunger {
}

private void mungeNewField(SourceTypeBinding sourceType, NewFieldTypeMunger munger) {
if (shouldTreatAsPublic() && !targetBinding.isInterface()) {
if (shouldTreatAsPublic() && !targetTypeX.isInterface()) {
FieldBinding binding = world.makeFieldBinding(munger.getSignature());
findOrCreateInterTypeMemberFinder(sourceType).addInterTypeField(binding);
//classScope.referenceContext.binding.addField(binding);
@@ -132,8 +143,18 @@ public class EclipseTypeMunger extends ConcreteTypeMunger {
}
public ISourceLocation getSourceLocation() {
return new EclipseSourceLocation(sourceMethod.compilationResult,
sourceMethod.sourceStart, sourceMethod.sourceEnd);
return sourceLocation;
}

public void setSourceLocation(ISourceLocation sourceLocation) {
this.sourceLocation = sourceLocation;
}

/**
* @return AbstractMethodDeclaration
*/
public AbstractMethodDeclaration getSourceMethod() {
return sourceMethod;
}

}

+ 1
- 0
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/InterTypeFieldBinding.java View File

@@ -50,6 +50,7 @@ public class InterTypeFieldBinding extends FieldBinding {
}
public boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) {
scope.compilationUnitScope().recordTypeReference(declaringClass);
//System.err.println("canBeSeenBy: " + this + ", " + isPublic());
if (isPublic()) return true;

+ 2
- 0
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/InterTypeMethodBinding.java View File

@@ -59,6 +59,8 @@ public class InterTypeMethodBinding extends MethodBinding {

//XXX this is identical to InterTypeFieldBinding
public boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) {
scope.compilationUnitScope().recordTypeReference(declaringClass);
if (isPublic()) return true;
SourceTypeBinding invocationType = scope.invocationType();

+ 301
- 301
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/parser/AjParser.java
File diff suppressed because it is too large
View File


+ 92
- 98
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java View File

@@ -17,6 +17,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
@@ -71,19 +72,14 @@ public class AjBuildManager {
private StructureModel structureModel;
public AjBuildConfig buildConfig;
AjState state = new AjState(this);
private BcelWeaver bcelWeaver;
BcelWeaver bcelWeaver;
public BcelWorld bcelWorld;
public CountingMessageHandler handler;

long lastStructuralBuildTime;

Set addedFiles;
Set deletedFiles;
List addedClassFiles;

public AjBuildManager(IMessageHandler holder) {
super();
this.handler = CountingMessageHandler.makeCountingMessageHandler(holder);
@@ -102,6 +98,7 @@ public class AjBuildManager {
try {
setBuildConfig(buildConfig);
state.prepareForNextBuild(buildConfig);
String check = checkRtJar(buildConfig);
if (check != null) {
@@ -115,27 +112,22 @@ public class AjBuildManager {
if (handler.hasErrors()) {
return false;
}
// initJavaBuilder(counter);
// if (counter.hasErrors()) {
// return false;
// }

if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
bcelWorld.setModel(StructureModelManager.INSTANCE.getStructureModel());
}
performCompilation();
// BatchBuilder builder = new BatchBuilder(javaBuilder, counter);
// State newState = builder.run();
performCompilation(buildConfig.getFiles());

if (buildConfig.isEmacsSymMode()) {
new org.aspectj.ajdt.internal.core.builder.EmacsStructureModelManager().externalizeModel();
}
// System.err.println("check error: " + counter + ", " +
// counter.numMessages(IMessage.ERROR) + ", " + counter.numMessages(IMessage.FAIL, false));

if (handler.hasErrors()) {
return false;
}
state.successfulCompile(buildConfig); //!!! a waste of time when not incremental

boolean weaved = weaveAndGenerateClassFiles();
@@ -169,8 +161,61 @@ public class AjBuildManager {
}

//XXX fake incremental
public boolean incrementalBuild(AjBuildConfig buildConfig, IMessageHandler messageHandler) throws IOException {
return batchBuild(buildConfig, messageHandler);
public boolean incrementalBuild(AjBuildConfig buildConfig, IMessageHandler baseHandler) throws IOException {
if (!state.prepareForNextBuild(buildConfig)) {
return batchBuild(buildConfig, baseHandler);
}
//!!! too much cut-and-paste from batchBuild
this.handler = CountingMessageHandler.makeCountingMessageHandler(baseHandler);
try {
setBuildConfig(buildConfig);

//setupModel();
// initBcelWorld(handler);
// if (handler.hasErrors()) {
// return false;
// }

// if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
// bcelWorld.setModel(StructureModelManager.INSTANCE.getStructureModel());
// }
int count = 0;
List filesToCompile;
while ( !(filesToCompile = state.getFilesToCompile(count == 0)).isEmpty() ) {
//if (count > 0) return batchBuild(buildConfig, baseHandler); //??? only 1 try
performCompilation(filesToCompile);
if (handler.hasErrors()) return false;
if (count++ > 5) {
return batchBuild(buildConfig, baseHandler);
}
}
//System.err.println("built in " + count + " cycles");

// if (buildConfig.isEmacsSymMode()) {
// new org.aspectj.ajdt.internal.core.builder.EmacsStructureModelManager().externalizeModel();
// }

if (handler.hasErrors()) {
return false;
}
state.successfulCompile(buildConfig);

boolean weaved = weaveAndGenerateClassFiles();
if (buildConfig.isGenerateModelMode()) {
StructureModelManager.INSTANCE.fireModelUpdated();
}
return !handler.hasErrors();
} finally {
handler = null;
}
}

// if (javaBuilder == null || javaBuilder.currentProject == null || javaBuilder.lastState == null) {
@@ -211,20 +256,7 @@ public class AjBuildManager {
// currentHandler = null;
// }
//
// }

void updateBuildConfig(AjBuildConfig newBuildConfig) {
Set oldFiles = new HashSet(buildConfig.getFiles());
Set newFiles = new HashSet(newBuildConfig.getFiles());
addedFiles = new HashSet(newFiles);
addedFiles.removeAll(oldFiles);
deletedFiles = new HashSet(oldFiles);
deletedFiles.removeAll(newFiles);
setBuildConfig(newBuildConfig);
}
// }
private void initBcelWorld(IMessageHandler handler) throws IOException {
bcelWorld = new BcelWorld(buildConfig.getClasspath(), handler);
@@ -259,25 +291,18 @@ public class AjBuildManager {
return bcelWorld;
}
void addAspectClassFilesToWeaver() throws IOException {
//System.out.println("added or changed: " + classFileCache.getAddedOrChanged());
void addAspectClassFilesToWeaver(List addedClassFiles) throws IOException {
for (Iterator i = addedClassFiles.iterator(); i.hasNext(); ) {
UnwovenClassFile classFile = (UnwovenClassFile) i.next();
bcelWeaver.addClassFile(classFile);
}
// for (Iterator i = classFileCache.getDeleted().iterator(); i.hasNext(); ) {
// UnwovenClassFile classFile = (UnwovenClassFile) i.next();
// bcelWeaver.deleteClassFile(classFile.getClassName());
// classFile.deleteRealFile();
// }
}

public boolean weaveAndGenerateClassFiles() throws IOException {
handler.handleMessage(MessageUtil.info("weaving"));
if (progressListener != null) progressListener.setText("weaving aspects");
//!!! doesn't provide intermediate progress during weaving
addAspectClassFilesToWeaver();
addAspectClassFilesToWeaver(state.addedClassFiles);
if (buildConfig.isNoWeave()) {
if (buildConfig.getOutputJar() != null) {
bcelWeaver.dumpUnwoven(buildConfig.getOutputJar());
@@ -320,6 +345,7 @@ public class AjBuildManager {
defaultEncoding = null; //$NON-NLS-1$

for (int i = 0; i < fileCount; i++) {
// these tests are performed for AjBuildConfig
// char[] charName = filenames[i].toCharArray();
// if (knownFileNames.get(charName) != null) {
// MessageUtil.error(handler, "duplicate file " + filenames[i]);
@@ -330,7 +356,6 @@ public class AjBuildManager {
// if (!file.exists()) {
// MessageUtil.error(handler, "missing file " + filenames[i]);
// }
// these tests are performed for AjBuildConfig
String encoding = encodings[i];
if (encoding == null)
encoding = defaultEncoding;
@@ -353,17 +378,12 @@ public class AjBuildManager {
}
public void performCompilation() {
List files = buildConfig.getFiles();
public void performCompilation(List files) {
if (progressListener != null) {
compiledCount = 0;
sourceFileCount = files.size();
progressListener.setText("compiling source files");
}

//System.err.println("got files: " + files);
String[] filenames = new String[files.size()];
String[] encodings = new String[files.size()];
@@ -381,6 +401,10 @@ public class AjBuildManager {
//System.out.println("compiling");
INameEnvironment environment = getLibraryAccess(classpaths, filenames);
if (!state.classesFromName.isEmpty()) {
environment = new StatefulNameEnvironment(environment, state.classesFromName);
}
// Compiler batchCompiler =
// new Compiler(
// environment,
@@ -421,11 +445,7 @@ public class AjBuildManager {

CompilerOptions options = compiler.options;

// set the non-externally configurable options.
//options.setVerboseMode(verbose);
//TODO: options.produceReferenceInfo(produceRefInfo);
addedClassFiles = new ArrayList();
options.produceReferenceInfo(true); //TODO turn off when not needed
compiler.compile(getCompilationUnits(filenames, encodings));
@@ -463,8 +483,11 @@ public class AjBuildManager {
}

public void outputClassFiles(CompilationResult unitResult) {
//System.err.println("writing: " + new String(unitResult.fileName));
if (!((unitResult == null) || (unitResult.hasErrors() && !proceedOnError()))) {
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();
@@ -477,41 +500,28 @@ public class AjBuildManager {
}
filename = new File(destinationPath, filename).getPath();
//System.out.println("classfile: " + filename);
addedClassFiles.add(new UnwovenClassFile(filename, classFile.getBytes()));
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;
handler.reset();
}
private Collection getModifiedFiles() {
return getModifiedFiles(lastStructuralBuildTime);
}

Collection getModifiedFiles(long lastBuildTime) {
List ret = new ArrayList();
//not our job to account for new and deleted files
for (Iterator i = buildConfig.getFiles().iterator(); i.hasNext(); ) {
File file = (File)i.next();
long modTime = file.lastModified();
//System.out.println("check: " + file + " mod " + modTime + " build " + lastBuildTime);
if (modTime > lastBuildTime) {
ret.add(file);
}
}
return ret;
}
String makeClasspathString() {
if (buildConfig == null || buildConfig.getClasspath() == null) return "";
StringBuffer buf = new StringBuffer();
@@ -597,20 +607,6 @@ public class AjBuildManager {
public StructureModel getStructureModel() {
return structureModel;
}

// public void setBuildNotifier(BuildNotifier notifier) {
// buildNotifier = notifier;
// }
/** callback for builders used only during build */
private boolean handleProblem(ICompilationUnit unit, IProblem problem) {
if (handler == null) {
throw new IllegalStateException("no current handler when handling "
+ problem + " in " + unit);
}
IMessage message = EclipseAdapterUtils.makeMessage(unit, problem);
return handler.handleMessage(message);
}
public IProgressListener getProgressListener() {
return progressListener;
@@ -619,7 +615,5 @@ public class AjBuildManager {
public void setProgressListener(IProgressListener progressListener) {
this.progressListener = progressListener;
}


} // class AjBuildManager


+ 309
- 0
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjState.java View File

@@ -0,0 +1,309 @@
/* *******************************************************************
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Common Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* PARC initial implementation
* ******************************************************************/


package org.aspectj.ajdt.internal.core.builder;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.aspectj.weaver.bcel.UnwovenClassFile;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.core.builder.ReferenceCollection;


/**
* Holds state needed for incremental compilation
*/
public class AjState {
AjBuildManager buildManager;
long lastSuccessfulBuildTime = -1;
long currentBuildTime = -1;
AjBuildConfig buildConfig;
AjBuildConfig newBuildConfig;
Map/*<File, List<UnwovenClassFile>*/ classesFromFile = new HashMap();
Map/*<File, ReferenceCollection>*/ references = new HashMap();
Map/*<String, UnwovenClassFile>*/ classesFromName = new HashMap();
ArrayList/*<String>*/ qualifiedStrings;
ArrayList/*<String>*/ simpleStrings;
Set addedFiles;
Set deletedFiles;
List addedClassFiles;
public AjState(AjBuildManager buildManager) {
this.buildManager = buildManager;
}
void successfulCompile(AjBuildConfig config) {
buildConfig = config;
lastSuccessfulBuildTime = currentBuildTime;
}
/**
* Returns false if a batch build is needed.
*/
boolean prepareForNextBuild(AjBuildConfig newBuildConfig) {
currentBuildTime = System.currentTimeMillis();
addedClassFiles = new ArrayList();
if (lastSuccessfulBuildTime == -1 || buildConfig == null) {
return false;
}
simpleStrings = new ArrayList();
qualifiedStrings = new ArrayList();
Set oldFiles = new HashSet(buildConfig.getFiles());
Set newFiles = new HashSet(newBuildConfig.getFiles());
addedFiles = new HashSet(newFiles);
addedFiles.removeAll(oldFiles);
deletedFiles = new HashSet(oldFiles);
deletedFiles.removeAll(newFiles);
this.newBuildConfig = newBuildConfig;
return true;
}
private Collection getModifiedFiles() {
return getModifiedFiles(lastSuccessfulBuildTime);
}

Collection getModifiedFiles(long lastBuildTime) {
List ret = new ArrayList();
//not our job to account for new and deleted files
for (Iterator i = buildConfig.getFiles().iterator(); i.hasNext(); ) {
File file = (File)i.next();
if (!file.exists()) continue;
long modTime = file.lastModified();
//System.out.println("check: " + file + " mod " + modTime + " build " + lastBuildTime);
if (modTime >= lastBuildTime) {
ret.add(file);
}
}
return ret;
}


public List getFilesToCompile(boolean firstPass) {
List sourceFiles = new ArrayList();
if (firstPass) {
Collection modifiedFiles = getModifiedFiles();
//System.out.println("modified: " + modifiedFiles);
sourceFiles.addAll(modifiedFiles);
//??? eclipse IncrementalImageBuilder appears to do this
// for (Iterator i = modifiedFiles.iterator(); i.hasNext();) {
// File file = (File) i.next();
// addDependentsOf(file);
// }
sourceFiles.addAll(addedFiles);
deleteClassFiles();
addAffectedSourceFiles(sourceFiles);
} else {
addAffectedSourceFiles(sourceFiles);
}
return sourceFiles;
}

private void deleteClassFiles() {
for (Iterator i = deletedFiles.iterator(); i.hasNext(); ) {
File deletedFile = (File)i.next();
//System.out.println("deleting: " + deletedFile);
addDependentsOf(deletedFile);
List unwovenClassFiles = (List)classesFromFile.get(deletedFile);
classesFromFile.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);
}
}
}

private void deleteClassFile(UnwovenClassFile classFile) {
classesFromName.remove(classFile.getClassName());
buildManager.bcelWeaver.deleteClassFile(classFile.getClassName());
try {
classFile.deleteRealFile();
} catch (IOException e) {
//!!! might be okay to ignore
}
}

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);
}

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;
}
protected void addAffectedSourceFiles(List sourceFiles) {
if (qualifiedStrings.isEmpty() && simpleStrings.isEmpty()) return;

// the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
char[][][] qualifiedNames = ReferenceCollection.internQualifiedNames(qualifiedStrings);
// if a well known qualified name was found then we can skip over these
if (qualifiedNames.length < qualifiedStrings.size())
qualifiedNames = null;
char[][] simpleNames = ReferenceCollection.internSimpleNames(simpleStrings);
// if a well known name was found then we can skip over these
if (simpleNames.length < simpleStrings.size())
simpleNames = null;

//System.err.println("simple: " + simpleStrings);
//System.err.println("qualif: " + qualifiedStrings);

for (Iterator i = references.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
ReferenceCollection refs = (ReferenceCollection)entry.getValue();
if (refs != null && refs.includes(qualifiedNames, simpleNames)) {
File file = (File)entry.getKey();
if (file.exists()) {
if (!sourceFiles.contains(file)) { //??? O(n**2)
sourceFiles.add(file);
}
}
}
}
qualifiedStrings.clear();
simpleStrings.clear();
}

protected void addDependentsOf(String qualifiedTypeName) {
int lastDot = qualifiedTypeName.lastIndexOf('.');
String typeName;
if (lastDot != -1) {
String packageName = qualifiedTypeName.substring(0,lastDot).replace('.', '/');
if (!qualifiedStrings.contains(packageName)) { //??? O(n**2)
qualifiedStrings.add(packageName);
}
typeName = qualifiedTypeName.substring(lastDot+1);
} else {
qualifiedStrings.add("");
typeName = qualifiedTypeName;
}

int memberIndex = typeName.indexOf('$');
if (memberIndex > 0)
typeName = typeName.substring(0, memberIndex);
if (!simpleStrings.contains(typeName)) { //??? O(n**2)
simpleStrings.add(typeName);
}
//System.err.println("adding: " + qualifiedTypeName);
}

protected void addDependentsOf(File sourceFile) {
List l = (List)classesFromFile.get(sourceFile);
if (l == null) return;
for (Iterator i = l.iterator(); i.hasNext();) {
UnwovenClassFile cf = (UnwovenClassFile) i.next();
addDependentsOf(cf.getClassName());
}
}
}

+ 72
- 0
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/StatefulNameEnvironment.java View File

@@ -0,0 +1,72 @@
/* *******************************************************************
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Common Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* PARC initial implementation
* ******************************************************************/


package org.aspectj.ajdt.internal.core.builder;

import java.util.Map;

import org.aspectj.weaver.bcel.UnwovenClassFile;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;


public class StatefulNameEnvironment implements INameEnvironment {
Map classesFromName;
INameEnvironment baseEnvironment;
public StatefulNameEnvironment(INameEnvironment baseEnvironment, Map classesFromName) {
this.classesFromName = classesFromName;
this.baseEnvironment = baseEnvironment;
}

public void cleanup() {
baseEnvironment.cleanup();
}

private NameEnvironmentAnswer findType(String name) {
UnwovenClassFile cf = (UnwovenClassFile)classesFromName.get(name);
if (cf == null) return null;

try {
//System.out.println("from cache: " + name);
return new NameEnvironmentAnswer(new ClassFileReader(cf.getBytes(), cf.getFilename().toCharArray()));
} catch (ClassFormatException e) {
return null; //!!! seems to match FileSystem behavior
}
}

public NameEnvironmentAnswer findType(
char[] typeName,
char[][] packageName)
{
NameEnvironmentAnswer ret = findType(new String(CharOperation.concatWith(packageName, typeName, '.')));
if (ret != null) return ret;
return baseEnvironment.findType(typeName, packageName);
}

public NameEnvironmentAnswer findType(char[][] compoundName) {
NameEnvironmentAnswer ret = findType(new String(CharOperation.concatWith(compoundName, '.')));
if (ret != null) return ret;
return baseEnvironment.findType(compoundName);
}

public boolean isPackage(char[][] parentPackageName, char[] packageName) {
//!!! need to use cache here too
return baseEnvironment.isPackage(parentPackageName, packageName);

}

}

+ 108
- 108
org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjBuildManagerTest.java View File

@@ -95,114 +95,114 @@ public class AjBuildManagerTest extends TestCase {

//XXX add test for resource deltas
public void testUpdateBuildConfig() {
final File FILE_1 = new File("testdata/testclasses/Temp1.java");
final File FILE_2 = new File("testdata/testclasses/Temp2.java");
final File FILE_3 = new File("testdata/testclasses/Temp3.java");
List files = new ArrayList();
files.add(FILE_1);
files.add(FILE_2);
AjBuildManager manager = new AjBuildManager(messageWriter);
AjBuildConfig buildConfig = new AjBuildConfig();
manager.buildConfig = buildConfig;
buildConfig.setFiles(files);
manager.updateBuildConfig(buildConfig);
assertTrue("no change", manager.deletedFiles.isEmpty());
AjBuildConfig newConfig = new AjBuildConfig();
newConfig.getFiles().add(FILE_1);
newConfig.getFiles().add(FILE_2);
newConfig.getFiles().add(FILE_3);
manager.updateBuildConfig(newConfig);
assertTrue("added file", manager.deletedFiles.isEmpty());
assertTrue(manager.addedFiles.size() == 1);
assertTrue(manager.addedFiles.contains(FILE_3));
newConfig = new AjBuildConfig();
newConfig.getFiles().add(FILE_3);
manager.updateBuildConfig(newConfig);
assertTrue("deleted 2 files", manager.addedFiles.isEmpty());
assertTrue(manager.deletedFiles.size() == 2);
assertTrue(manager.deletedFiles.contains(FILE_1));
newConfig = new AjBuildConfig();
newConfig.getFiles().add(FILE_2);
manager.updateBuildConfig(newConfig);
assertTrue("added file", manager.addedFiles.size() == 1);
assertTrue("deleted file", manager.deletedFiles.size() == 1);
assertTrue(manager.deletedFiles.size() == 1);
assertTrue(manager.addedFiles.contains(FILE_2));
assertTrue(manager.deletedFiles.contains(FILE_3));
}
/**
* Pretends that the files 'have been' modified in the future and waits.
* Tests:
* 1) no change,
* 2) added file,
* 3) removed file
*
* XXX should just test modified
*/
public void testGetModifiedFiles() throws IOException, InterruptedException {
final File TEMP_1 = new File("testdata/testclasses/TempChanged.java");
final File EXISTS_2 = new File("testdata/testclasses/p1/Foo.java");
final File NEW = new File("testdata/testclasses/TempNew.java");
NEW.delete();
touch(TEMP_1, false);
List files = new ArrayList();
files.add(TEMP_1);
files.add(EXISTS_2);
assertTrue("input files", TEMP_1.exists() && EXISTS_2.exists());
assertTrue("new file", !NEW.exists());
Thread.sleep(100);
long lastBuildTime = System.currentTimeMillis();
AjBuildManager manager = new AjBuildManager(messageWriter);
manager.buildConfig = new AjBuildConfig();
manager.buildConfig.setFiles(files);
Collection changedFiles = manager.getModifiedFiles(lastBuildTime);
assertTrue("nothing changed: " + changedFiles, changedFiles.isEmpty());
lastBuildTime = System.currentTimeMillis();
Thread.sleep(100);
touch(NEW, false);
//NEW.createNewFile();
files.add(NEW);
changedFiles = manager.getModifiedFiles(lastBuildTime);
assertTrue("new file: " + changedFiles, changedFiles.contains(NEW));
lastBuildTime = System.currentTimeMillis();
Thread.sleep(100);
files.remove(NEW);
changedFiles = manager.getModifiedFiles(lastBuildTime);
assertTrue("nothing changed", changedFiles.isEmpty());
lastBuildTime = System.currentTimeMillis();
Thread.sleep(100);
touch(TEMP_1, true);
changedFiles = manager.getModifiedFiles(lastBuildTime);
assertTrue("touched file: " + changedFiles, changedFiles.contains(TEMP_1));
lastBuildTime = System.currentTimeMillis();
Thread.sleep(100);
files.remove(NEW);
changedFiles = manager.getModifiedFiles(lastBuildTime);
assertTrue("nothing changed", changedFiles.isEmpty());
TEMP_1.delete();
NEW.delete();
}
//
// public void testUpdateBuildConfig() {
// final File FILE_1 = new File("testdata/testclasses/Temp1.java");
// final File FILE_2 = new File("testdata/testclasses/Temp2.java");
// final File FILE_3 = new File("testdata/testclasses/Temp3.java");
// List files = new ArrayList();
// files.add(FILE_1);
// files.add(FILE_2);
//
// AjBuildManager manager = new AjBuildManager(messageWriter);
// AjBuildConfig buildConfig = new AjBuildConfig();
// manager.buildConfig = buildConfig;
// buildConfig.setFiles(files);
//
// manager.updateBuildConfig(buildConfig);
// assertTrue("no change", manager.deletedFiles.isEmpty());
//
// AjBuildConfig newConfig = new AjBuildConfig();
// newConfig.getFiles().add(FILE_1);
// newConfig.getFiles().add(FILE_2);
// newConfig.getFiles().add(FILE_3);
// manager.updateBuildConfig(newConfig);
// assertTrue("added file", manager.deletedFiles.isEmpty());
// assertTrue(manager.addedFiles.size() == 1);
// assertTrue(manager.addedFiles.contains(FILE_3));
//
// newConfig = new AjBuildConfig();
// newConfig.getFiles().add(FILE_3);
// manager.updateBuildConfig(newConfig);
// assertTrue("deleted 2 files", manager.addedFiles.isEmpty());
// assertTrue(manager.deletedFiles.size() == 2);
// assertTrue(manager.deletedFiles.contains(FILE_1));
//
// newConfig = new AjBuildConfig();
// newConfig.getFiles().add(FILE_2);
// manager.updateBuildConfig(newConfig);
// assertTrue("added file", manager.addedFiles.size() == 1);
// assertTrue("deleted file", manager.deletedFiles.size() == 1);
// assertTrue(manager.deletedFiles.size() == 1);
// assertTrue(manager.addedFiles.contains(FILE_2));
// assertTrue(manager.deletedFiles.contains(FILE_3));
// }
//
// /**
// * Pretends that the files 'have been' modified in the future and waits.
// * Tests:
// * 1) no change,
// * 2) added file,
// * 3) removed file
// *
// * XXX should just test modified
// */
// public void testGetModifiedFiles() throws IOException, InterruptedException {
// final File TEMP_1 = new File("testdata/testclasses/TempChanged.java");
// final File EXISTS_2 = new File("testdata/testclasses/p1/Foo.java");
// final File NEW = new File("testdata/testclasses/TempNew.java");
// NEW.delete();
// touch(TEMP_1, false);
// List files = new ArrayList();
// files.add(TEMP_1);
// files.add(EXISTS_2);
//
// assertTrue("input files", TEMP_1.exists() && EXISTS_2.exists());
// assertTrue("new file", !NEW.exists());
//
// Thread.sleep(100);
// long lastBuildTime = System.currentTimeMillis();
//
// AjBuildManager manager = new AjBuildManager(messageWriter);
// manager.buildConfig = new AjBuildConfig();
// manager.buildConfig.setFiles(files);
// Collection changedFiles = manager.getModifiedFiles(lastBuildTime);
// assertTrue("nothing changed: " + changedFiles, changedFiles.isEmpty());
//
// lastBuildTime = System.currentTimeMillis();
// Thread.sleep(100);
//
// touch(NEW, false);
//
// //NEW.createNewFile();
// files.add(NEW);
// changedFiles = manager.getModifiedFiles(lastBuildTime);
// assertTrue("new file: " + changedFiles, changedFiles.contains(NEW));
//
// lastBuildTime = System.currentTimeMillis();
// Thread.sleep(100);
//
// files.remove(NEW);
// changedFiles = manager.getModifiedFiles(lastBuildTime);
// assertTrue("nothing changed", changedFiles.isEmpty());
//
// lastBuildTime = System.currentTimeMillis();
// Thread.sleep(100);
//
// touch(TEMP_1, true);
// changedFiles = manager.getModifiedFiles(lastBuildTime);
// assertTrue("touched file: " + changedFiles, changedFiles.contains(TEMP_1));
//
// lastBuildTime = System.currentTimeMillis();
// Thread.sleep(100);
//
// files.remove(NEW);
// changedFiles = manager.getModifiedFiles(lastBuildTime);
// assertTrue("nothing changed", changedFiles.isEmpty());
//
// TEMP_1.delete();
// NEW.delete();
// }
// don't do delta's anymore
// public void testMakeDeltas() throws IOException, InterruptedException {

Loading…
Cancel
Save