/* *******************************************************************
* 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.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.aspectj.ajdt.internal.compiler.InterimCompilationResult;
import org.aspectj.asm.IHierarchy;
import org.aspectj.asm.IRelationshipMap;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.Message;
import org.aspectj.bridge.SourceLocation;
import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.aspectj.org.eclipse.jdt.internal.core.builder.ReferenceCollection;
import org.aspectj.org.eclipse.jdt.internal.core.builder.StringSet;
import org.aspectj.util.FileUtil;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.bcel.BcelWeaver;
import org.aspectj.weaver.bcel.BcelWorld;
import org.aspectj.weaver.bcel.UnwovenClassFile;
/**
* Holds state needed for incremental compilation
*/
public class AjState {
AjBuildManager buildManager;
// SECRETAPI static so beware of multi-threading bugs...
public static IStateListener stateListener = null;
private IHierarchy structureModel;
private IRelationshipMap relmap;
private long lastSuccessfulFullBuildTime = -1;
private Hashtable /* File, long */ structuralChangesSinceLastFullBuild = new Hashtable();
private long lastSuccessfulBuildTime = -1;
private long currentBuildTime = -1;
AjBuildConfig buildConfig;
AjBuildConfig newBuildConfig;
// 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();
List/*File*/ compiledSourceFiles = new ArrayList();
List/*String*/ resources = new ArrayList();
ArrayList/*<String>*/ qualifiedStrings;
ArrayList/*<String>*/ simpleStrings;
Set addedFiles;
Set deletedFiles;
Set /*BinarySourceFile*/addedBinaryFiles;
Set /*BinarySourceFile*/deletedBinaryFiles;
private BcelWeaver weaver;
private BcelWorld world;
List addedClassFiles;
public AjState(AjBuildManager buildManager) {
this.buildManager = buildManager;
}
void successfulCompile(AjBuildConfig config,boolean wasFullBuild) {
buildConfig = config;
lastSuccessfulBuildTime = currentBuildTime;
if (stateListener!=null) stateListener.buildSuccessful(wasFullBuild);
if (wasFullBuild) lastSuccessfulFullBuildTime = currentBuildTime;
}
/**
* Returns false if a batch build is needed.
*/
boolean prepareForNextBuild(AjBuildConfig newBuildConfig) {
currentBuildTime = System.currentTimeMillis();
addedClassFiles = new ArrayList();
if (lastSuccessfulBuildTime == -1 || buildConfig == null) {
structuralChangesSinceLastFullBuild.clear();
return false;
}
// we don't support incremental with an outjar yet
if (newBuildConfig.getOutputJar() != null) {
structuralChangesSinceLastFullBuild.clear();
return false;
}
// we can't do an incremental build if one of our paths
// has changed, or a jar on a path has been modified
if (pathChange(buildConfig,newBuildConfig)) {
// last time we built, .class files and resource files from jars on the
// inpath will have been copied to the output directory.
// these all need to be deleted in preparation for the clean build that is
// coming - otherwise a file that has been deleted from an inpath jar
// since the last build will not be deleted from the output directory.
removeAllResultsOfLastBuild();
if (stateListener!=null) stateListener.pathChangeDetected();
structuralChangesSinceLastFullBuild.clear();
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);
Set oldBinaryFiles = new HashSet(buildConfig.getBinaryFiles());
Set newBinaryFiles = new HashSet(newBuildConfig.getBinaryFiles());
addedBinaryFiles = new HashSet(newBinaryFiles);
addedBinaryFiles.removeAll(oldBinaryFiles);
deletedBinaryFiles = new HashSet(oldBinaryFiles);
deletedBinaryFiles.removeAll(newBinaryFiles);
boolean couldStillBeIncremental = processDeletedFiles(deletedFiles);
if (!couldStillBeIncremental) return false;
this.newBuildConfig = newBuildConfig;
return true;
}
/**
* Checks if any of the files in the set passed in contains an aspect declaration. If one is found
* then we start the process of batch building, i.e. we remove all the results of the last build,
* call any registered listener to tell them whats happened and return false.
*
* @return false if we discovered an aspect declaration
*/
private boolean processDeletedFiles(Set deletedFiles) {
for (Iterator iter = deletedFiles.iterator(); iter.hasNext();) {
File aDeletedFile = (File ) iter.next();
InterimCompilationResult cr = (InterimCompilationResult)resultsFromFile.get(aDeletedFile);
if (cr!=null) {
Map compiledTypes = cr.result().compiledTypes;
if (compiledTypes!=null) {
for (Iterator iterator = compiledTypes.keySet().iterator(); iterator.hasNext();) {
char[] className = (char[])iterator.next();
ResolvedType rt = world.resolve(new String(className).replace('/','.'));
if (rt.isAspect()) {
removeAllResultsOfLastBuild();
if (stateListener!=null) stateListener.detectedAspectDeleted(aDeletedFile);
return false;
}
}
}
}
}
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);
// need to add 1000 since lastModTime is only accurate to a second on some (all?) platforms
if (modTime + 1000 > lastBuildTime) {
ret.add(file);
}
}
return ret;
}
private Collection getModifiedBinaryFiles() {
return getModifiedBinaryFiles(lastSuccessfulBuildTime);
}
Collection getModifiedBinaryFiles(long lastBuildTime) {
List ret = new ArrayList();
//not our job to account for new and deleted files
for (Iterator i = buildConfig.getBinaryFiles().iterator(); i.hasNext(); ) {
AjBuildConfig.BinarySourceFile bsfile = (AjBuildConfig.BinarySourceFile)i.next();
File file = bsfile.binSrc;
if (!file.exists()) continue;
long modTime = file.lastModified();
//System.out.println("check: " + file + " mod " + modTime + " build " + lastBuildTime);
// need to add 1000 since lastModTime is only accurate to a second on some (all?) platforms
if (modTime + 1000 >= lastBuildTime) {
ret.add(bsfile);
}
}
return ret;
}
private boolean classFileChangedInDirSinceLastBuild(File dir) {
// Is another process building into that directory?
AjState state = IncrementalStateManager.findStateManagingOutputLocation(dir);
File[] classFiles = FileUtil.listFiles(dir, new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".class");
}
});
for (int i = 0; i < classFiles.length; i++) {
long modTime = classFiles[i].lastModified();
if ((modTime+1000)>=lastSuccessfulBuildTime) {
// so the class on disk has changed since our last successful build
// To work out if it is a real change we should ask any state
// object managing this output location whether the file has
// structurally changed or not
if (state!=null) {
boolean realChange = state.hasStructuralChangedSince(classFiles[i],lastSuccessfulBuildTime);
if (realChange) return true;
} else {
// FIXME asc you should ask Eclipse project state here...
return true; // no state object to ask so it must have changed
}
}
}
return false;
}
/**
* Determine if a file has changed since a given time, using the local information
* recorded in the structural changes data structure.
*
* file is the file we are wondering about
* lastSBT is the last build time for the state asking the question
*/
private boolean hasStructuralChangedSince(File file,long lastSuccessfulBuildTime) {
long lastModTime = file.lastModified();
Long l = (Long)structuralChangesSinceLastFullBuild.get(file.getAbsolutePath());
long strucModTime = -1;
if (l!=null) strucModTime = l.longValue();
else strucModTime = this.lastSuccessfulFullBuildTime;
// we now have:
// 'strucModTime'-> the last time the class was structurally changed
return (strucModTime>lastSuccessfulBuildTime);
}
private boolean pathChange(AjBuildConfig oldConfig, AjBuildConfig newConfig) {
boolean changed = false;
List oldClasspath = oldConfig.getClasspath();
List newClasspath = newConfig.getClasspath();
if (stateListener!=null) stateListener.aboutToCompareClasspaths(oldClasspath,newClasspath);
if (changed(oldClasspath,newClasspath,true,oldConfig.getOutputDir())) return true;
List oldAspectpath = oldConfig.getAspectpath();
List newAspectpath = newConfig.getAspectpath();
if (changed(oldAspectpath,newAspectpath,true,oldConfig.getOutputDir())) return true;
List oldInJars = oldConfig.getInJars();
List newInJars = newConfig.getInJars();
if (changed(oldInJars,newInJars,false,oldConfig.getOutputDir())) return true;
List oldInPath = oldConfig.getInpath();
List newInPath = newConfig.getInpath();
if (changed(oldInPath, newInPath,false,oldConfig.getOutputDir())) return true;
return changed;
}
private boolean changed(List oldPath, List newPath, boolean checkClassFiles, File oldOutputLocation) {
if (oldPath == null) oldPath = new ArrayList();
if (newPath == null) newPath = new ArrayList();
try {
if (oldOutputLocation != null) {
oldOutputLocation = oldOutputLocation.getCanonicalFile();
}
} catch(IOException ex) { /* we did our best...*/ }
if (oldPath.size() != newPath.size()) {
return true;
}
for (int i = 0; i < oldPath.size(); i++) {
if (!oldPath.get(i).equals(newPath.get(i))) {
return true;
}
Object o = oldPath.get(i); // String on classpath, File on other paths
File f = null;
if (o instanceof String) {
f = new File((String)o);
} else {
f = (File) o;
}
if (f.exists() && !f.isDirectory() && (f.lastModified() >= lastSuccessfulBuildTime)) {
return true;
}
if (f.exists() && f.isDirectory() && checkClassFiles && !(f.equals(oldOutputLocation))) {
boolean b= classFileChangedInDirSinceLastBuild(f);
if (b && stateListener!=null) stateListener.detectedClassChangeInThisDir(f);
if (b) return true;
}
}
return false;
}
public List getFilesToCompile(boolean firstPass) {
List thisTime = new ArrayList();
if (firstPass) {
compiledSourceFiles = new ArrayList();
Collection modifiedFiles = getModifiedFiles();
//System.out.println("modified: " + modifiedFiles);
thisTime.addAll(modifiedFiles);
//??? eclipse IncrementalImageBuilder appears to do this
// for (Iterator i = modifiedFiles.iterator(); i.hasNext();) {
// File file = (File) i.next();
// addDependentsOf(file);
// }
thisTime.addAll(addedFiles);
deleteClassFiles();
deleteResources();
addAffectedSourceFiles(thisTime,thisTime);
} else {
addAffectedSourceFiles(thisTime,compiledSourceFiles);
}
compiledSourceFiles = thisTime;
return thisTime;
}
public Map /* String -> List<ucf> */ getBinaryFilesToCompile(boolean firstTime) {
if (lastSuccessfulBuildTime == -1 || buildConfig == null) {
return binarySourceFiles;
}
// else incremental...
Map toWeave = new HashMap();
if (firstTime) {
List addedOrModified = new ArrayList();
addedOrModified.addAll(addedBinaryFiles);
addedOrModified.addAll(getModifiedBinaryFiles());
for (Iterator iter = addedOrModified.iterator(); iter.hasNext();) {
AjBuildConfig.BinarySourceFile bsf = (AjBuildConfig.BinarySourceFile) iter.next();
UnwovenClassFile ucf = createUnwovenClassFile(bsf);
if (ucf == null) continue;
List ucfs = new ArrayList();
ucfs.add(ucf);
addDependentsOf(ucf.getClassName());
binarySourceFiles.put(bsf.binSrc.getPath(),ucfs);
toWeave.put(bsf.binSrc.getPath(),ucfs);
}
deleteBinaryClassFiles();
} else {
// return empty set... we've already done our bit.
}
return toWeave;
}
/**
* Called when a path change is about to trigger a full build, but
* we haven't cleaned up from the last incremental build...
*/
private void removeAllResultsOfLastBuild() {
// remove all binarySourceFiles, and all classesFromName...
for (Iterator iter = binarySourceFiles.values().iterator(); iter.hasNext();) {
List ucfs = (List) iter.next();
for (Iterator iterator = ucfs.iterator(); iterator.hasNext();) {
UnwovenClassFile ucf = (UnwovenClassFile) iterator.next();
try {
ucf.deleteRealFile();
} catch (IOException ex) { /* we did our best here */ }
}
}
for (Iterator iterator = classesFromName.values().iterator(); iterator.hasNext();) {
UnwovenClassFile ucf = (UnwovenClassFile) iterator.next();
try {
ucf.deleteRealFile();
} catch (IOException ex) { /* we did our best here */ }
}
for (Iterator iter = resources.iterator(); iter.hasNext();) {
String resource = (String) iter.next();
new File(buildConfig.getOutputDir(),resource).delete();
}
}
private void deleteClassFiles() {
for (Iterator i = deletedFiles.iterator(); i.hasNext(); ) {
File deletedFile = (File)i.next();
//System.out.println("deleting: " + deletedFile);
addDependentsOf(deletedFile);
InterimCompilationResult intRes = (InterimCompilationResult) resultsFromFile.get(deletedFile);
resultsFromFile.remove(deletedFile);
//System.out.println("deleting: " + unwovenClassFiles);
if (intRes == null) continue;
for (int j=0; j<intRes.unwovenClassFiles().length; j++ ) {
deleteClassFile(intRes.unwovenClassFiles()[j]);
}
}
}
private void deleteBinaryClassFiles() {
// range of bsf is ucfs, domain is files (.class and jars) in inpath/jars
for (Iterator iter = deletedBinaryFiles.iterator(); iter.hasNext();) {
AjBuildConfig.BinarySourceFile deletedFile = (AjBuildConfig.BinarySourceFile) iter.next();
List ucfs = (List) binarySourceFiles.get(deletedFile.binSrc.getPath());
binarySourceFiles.remove(deletedFile.binSrc.getPath());
deleteClassFile((UnwovenClassFile)ucfs.get(0));
}
}
private void deleteResources() {
List oldResources = new ArrayList();
oldResources.addAll(resources);
// note - this deliberately ignores resources in jars as we don't yet handle jar changes
// with incremental compilation
for (Iterator i = buildConfig.getInpath().iterator(); i.hasNext(); ) {
File inPathElement = (File)i.next();
if (inPathElement.isDirectory() && AjBuildManager.COPY_INPATH_DIR_RESOURCES) {
deleteResourcesFromDirectory(inPathElement,oldResources);
}
}
if (buildConfig.getSourcePathResources() != null) {
for (Iterator i = buildConfig.getSourcePathResources().keySet().iterator(); i.hasNext(); ) {
String resource = (String)i.next();
maybeDeleteResource(resource, oldResources);
}
}
// oldResources need to be deleted...
for (Iterator iter = oldResources.iterator(); iter.hasNext();) {
String victim = (String) iter.next();
File f = new File(buildConfig.getOutputDir(),victim);
if (f.exists()) {
f.delete();
}
resources.remove(victim);
}
}
private void maybeDeleteResource(String resName, List oldResources) {
if (resources.contains(resName)) {
oldResources.remove(resName);
File source = new File(buildConfig.getOutputDir(),resName);
if ((source != null) && (source.exists()) &&
(source.lastModified() >= lastSuccessfulBuildTime)) {
resources.remove(resName); // will ensure it is re-copied
}
}
}
private void deleteResourcesFromDirectory(File dir, List oldResources) {
File[] files = FileUtil.listFiles(dir,new FileFilter() {
public boolean accept(File f) {
boolean accept = !(f.isDirectory() || f.getName().endsWith(".class")) ;
return accept;
}
});
// For each file, add it either as a real .class file or as a resource
for (int i = 0; i < files.length; i++) {
// ASSERT: files[i].getAbsolutePath().startsWith(inFile.getAbsolutePath()
// or we are in trouble...
String filename = files[i].getAbsolutePath().substring(
dir.getAbsolutePath().length()+1);
maybeDeleteResource(filename, oldResources);
}
}
private void deleteClassFile(UnwovenClassFile classFile) {
classesFromName.remove(classFile.getClassName());
weaver.deleteClassFile(classFile.getClassName());
try {
classFile.deleteRealFile();
} catch (IOException e) {
//!!! might be okay to ignore
}
}
private UnwovenClassFile createUnwovenClassFile(AjBuildConfig.BinarySourceFile bsf) {
UnwovenClassFile ucf = null;
try {
ucf = weaver.addClassFile(bsf.binSrc, bsf.fromInPathDirectory, buildConfig.getOutputDir());
} catch(IOException ex) {
IMessage msg = new Message("can't read class file " + bsf.binSrc.getPath(),
new SourceLocation(bsf.binSrc,0),false);
buildManager.handler.handleMessage(msg);
}
return ucf;
}
public void noteResult(InterimCompilationResult result) {
File sourceFile = new File(result.fileName());
CompilationResult cr = result.result();
if (result != null) {
references.put(sourceFile, new ReferenceCollection(cr.qualifiedReferences, cr.simpleNameReferences));
}
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) {
for (int i = 0; i < previous.unwovenClassFiles().length; i++) {
if (previous.unwovenClassFiles()[i] != null) {
deleteClassFile(previous.unwovenClassFiles()[i]);
}
}
}
resultsFromFile.put(sourceFile, result);
}
private UnwovenClassFile removeFromPreviousIfPresent(UnwovenClassFile cf, InterimCompilationResult previous) {
if (previous == null) return null;
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
if (lastTime == null) {
addDependentsOf(thisTime.getClassName());
return;
}
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)) {
structuralChangesSinceLastFullBuild.put(thisTime.getFilename(),new Long(currentBuildTime));
addDependentsOf(lastTime.getClassName());
}
} catch (ClassFormatException e) {
addDependentsOf(lastTime.getClassName());
}
}
}
// 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();) {
String element = (String) iter.next();
ret.add(element);
}
return ret;
}
protected void addAffectedSourceFiles(List addTo, List lastTimeSources) {
if (qualifiedStrings.isEmpty() && simpleStrings.isEmpty()) return;
// the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
char[][][] qualifiedNames = ReferenceCollection.internQualifiedNames(makeStringSet(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(makeStringSet(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 (!lastTimeSources.contains(file)) { //??? O(n**2)
addTo.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) {
InterimCompilationResult intRes = (InterimCompilationResult)resultsFromFile.get(sourceFile);
if (intRes == null) return;
for (int i = 0; i < intRes.unwovenClassFiles().length; i++) {
addDependentsOf(intRes.unwovenClassFiles()[i].getClassName());
}
}
public void setStructureModel(IHierarchy model) {
structureModel = model;
}
public IHierarchy getStructureModel() {
return structureModel;
}
public void setWeaver(BcelWeaver bw) { weaver=bw;}
public BcelWeaver getWeaver() {return weaver;}
public void setWorld(BcelWorld bw) {world=bw;}
public BcelWorld getBcelWorld() {return world; }
public void setRelationshipMap(IRelationshipMap irm) { relmap = irm;}
public IRelationshipMap getRelationshipMap() { return relmap;}
public int getNumberOfStructuralChangesSinceLastFullBuild() {
return structuralChangesSinceLastFullBuild.size();
}
/** Returns last time we did a full or incremental build. */
public long getLastBuildTime() {
return lastSuccessfulBuildTime;
}
/** Returns last time we did a full build */
public long getLastFullBuildTime() {
return lastSuccessfulFullBuildTime;
}
}