Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Copyright (c) 2000, 2013 IBM Corporation and others. All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html Contributors: IBM Corporation - initial API and implementation /
 
 package org.eclipse.jdt.internal.core.builder;
 
 import  org.eclipse.core.resources.*;
 import  org.eclipse.core.runtime.*;
 
 
 import java.io.*;
 import java.net.URI;
 import java.util.*;

The incremental image builder
 
 public class IncrementalImageBuilder extends AbstractImageBuilder {
 
 protected ArrayList sourceFiles;
 protected StringSet simpleStrings;
 protected StringSet rootStrings;
 protected boolean hasStructuralChanges;
 protected int compileLoop;
 protected boolean makeOutputFolderConsistent;
 
 public static int MaxCompileLoop = 5; // perform a full build if it takes more than ? incremental compile loops
 
 protected IncrementalImageBuilder(JavaBuilder javaBuilderState buildState) {
 	super(javaBuildertruebuildState);
 }
 
 protected IncrementalImageBuilder(JavaBuilder javaBuilder) {
 	this(javaBuildernull);
 	this..copyFrom(javaBuilder.lastState);
 }
 
 protected IncrementalImageBuilder(BatchImageBuilder batchBuilder) {
 	this(batchBuilder.javaBuilderbatchBuilder.newState);
 }
 
 public boolean build(SimpleLookupTable deltas) {
 	// 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
 
 		..println("INCREMENTAL build"); //$NON-NLS-1$
 
 	try {
 
 			// if a mssing class file was detected in the last build, a build state was saved since its no longer fatal
 			// but we need to rebuild every source file since problems were not recorded
 			// AND to avoid the infinite build scenario if this project is involved in a cycle, see bug 160550
 			// we need to avoid unnecessary deltas caused by doing a full build in this case
 				..println("COMPILING all source files since the buildpath has errors "); //$NON-NLS-1$
 			this...deleteMarkers(.false, IResource.DEPTH_ZERO);
 		} else {
 			IResourceDelta sourceDelta = (IResourceDelta) deltas.get(this..);
 			if (sourceDelta != null)
 				if (!findSourceFiles(sourceDelta)) return false;
 
 			Object[] keyTable = deltas.keyTable;
			Object[] valueTable = deltas.valueTable;
			for (int i = 0, l = valueTable.lengthi < li++) {
				IResourceDelta delta = (IResourceDelta) valueTable[i];
				if (delta != null) {
					IProject p = (IProject) keyTable[i];
					if (classFoldersAndJars != null)
						if (!findAffectedSourceFiles(deltaclassFoldersAndJarsp)) return false;
				}
			}
		}
		this. = 0;
		float increment = 0.40f;
		while (this..size() > 0) { // added to in acceptResult
			if (++this. > ) {
					..println("ABORTING incremental build... exceeded loop count"); //$NON-NLS-1$
				return false;
			}
			SourceFile[] allSourceFiles = new SourceFile[this..size()];
			this..toArray(allSourceFiles);
			this..addAll(allSourceFiles);
			this..setProgressPerCompilationUnit(increment / allSourceFiles.length);
			increment = increment / 2;
			compile(allSourceFiles);
		}
		// abort the incremental build and let the batch builder handle the problem
			..println("ABORTING incremental build... problem with " + e.qualifiedTypeName + //$NON-NLS-1$
				". Likely renamed inside its existing source file."); //$NON-NLS-1$
		return false;
catch (CoreException e) {
finally {
	}
	return true;
protected void buildAfterBatchBuild() {
	// called from a batch builder once all source files have been compiled AND some changes
	// need to be propagated incrementally (annotations, missing secondary types)
		..println("INCREMENTAL build after batch build @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
	// this is a copy of the incremental build loop
	try {
		while (this..size() > 0) {
			SourceFile[] allSourceFiles = new SourceFile[this..size()];
			this..toArray(allSourceFiles);
			this..setProgressPerCompilationUnit(0.08f / allSourceFiles.length);
			this..addAll(allSourceFiles);
			compile(allSourceFiles);
		}
catch (CoreException e) {
finally {
	}
protected void addAffectedSourceFiles() {
	if (this.. == 0 && this.. == 0) return;
protected void addAffectedSourceFiles(StringSet qualifiedSetStringSet simpleSetStringSet rootSetStringSet affectedTypes) {
	// the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
	char[][][] internedQualifiedNames = ReferenceCollection.internQualifiedNames(qualifiedSet);
	// if a well known qualified name was found then we can skip over these
	if (internedQualifiedNames.length < qualifiedSet.elementSize)
		internedQualifiedNames = null;
	char[][] internedSimpleNames = ReferenceCollection.internSimpleNames(simpleSettrue);
	// if a well known name was found then we can skip over these
	if (internedSimpleNames.length < simpleSet.elementSize)
		internedSimpleNames = null;
	char[][] internedRootNames = ReferenceCollection.internSimpleNames(rootSetfalse);
	Object[] keyTable = this...;
	Object[] valueTable = this...;
	next : for (int i = 0, l = valueTable.lengthi < li++) {
		String typeLocator = (StringkeyTable[i];
		if (typeLocator != null) {
			if (affectedTypes != null && !affectedTypes.includes(typeLocator)) continue next;
			ReferenceCollection refs = (ReferenceCollectionvalueTable[i];
			if (refs.includes(internedQualifiedNamesinternedSimpleNamesinternedRootNames)) {
				IFile file = this...getFile(typeLocator);
				SourceFile sourceFile = findSourceFile(filetrue);
				if (sourceFile == nullcontinue next;
				if (this..contains(sourceFile)) continue next;
				if (this. && this. != null && this..contains(sourceFile))
					continue next; // can skip previously compiled files since already saw hierarchy related problems
					..println("  adding affected source file " + typeLocator); //$NON-NLS-1$
				this..add(sourceFile);
			}
		}
	}
protected void addDependentsOf(IPath pathboolean isStructuralChange) {
	addDependentsOf(pathisStructuralChangethis.this.this.);
protected void addDependentsOf(IPath pathboolean isStructuralChangeStringSet qualifiedNamesStringSet simpleNamesStringSet rootNames) {
	path = path.setDevice(null);
	if (isStructuralChange) {
		String last = path.lastSegment();
			if (CharOperation.equals(last.toCharArray(), .)) {
				path = path.removeLastSegments(1); // the package-info file has changed so blame the package itself
				/* https://bugs.eclipse.org/bugs/show_bug.cgi?id=323785, in the case of default package,
				   there is no need to blame the package itself as there can be no annotations or documentation
				   comment tags in the package-info file that can influence the rest of the package. Just bail out
				   so we don't touch null objects below.
				 */
				if (path.isEmpty())
					return;
			}
	}
	if (isStructuralChange && !this.) {
		this. = true;
	}
	// the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
	rootNames.add(path.segment(0));
	String packageName = path.removeLastSegments(1).toString();
	boolean wasNew = qualifiedNames.add(packageName);
	String typeName = path.lastSegment();
	int memberIndex = typeName.indexOf('$');
	if (memberIndex > 0)
		typeName = typeName.substring(0, memberIndex);
	wasNew = simpleNames.add(typeName) | wasNew;
	if (wasNew && .)
		..println("  will look for dependents of " //$NON-NLS-1$
typeName + " in " + packageName); //$NON-NLS-1$
protected boolean checkForClassFileChanges(IResourceDelta binaryDeltaClasspathMultiDirectory mdint segmentCountthrows CoreException {
	IResource resource = binaryDelta.getResource();
	// remember that if inclusion & exclusion patterns change then a full build is done
	boolean isExcluded = (md.exclusionPatterns != null || md.inclusionPatterns != null)
		&& Util.isExcluded(resourcemd.inclusionPatternsmd.exclusionPatterns);
	switch(resource.getType()) {
		case IResource.FOLDER :
			if (isExcluded && md.inclusionPatterns == null)
		        return true// no need to go further with this delta since its children cannot be included
			IResourceDelta[] children = binaryDelta.getAffectedChildren();
			for (int i = 0, l = children.length; i < li++)
				if (!checkForClassFileChanges(children[i], mdsegmentCount))
					return false;
			return true;
		case IResource.FILE :
			if (!isExcluded && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(resource.getName())) {
				// perform full build if a managed class file has been changed
				IPath typePath = resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension();
				if (this..isKnownType(typePath.toString())) {
						..println("MUST DO FULL BUILD. Found change to class file " + typePath); //$NON-NLS-1$
					return false;
				}
				return true;
			}
	}
	return true;
protected void cleanUp() {
	super.cleanUp();
	this. = null;
	this. = null;
	this. = null;
	this. = null;
	this. = null;
	this. = false;
	this. = 0;
protected void compile(SourceFile[] unitsSourceFile[] additionalUnitsboolean compilingFirstGroup) {
	if (compilingFirstGroup && additionalUnits != null) {
		// add any source file from additionalUnits to units if it defines secondary types
		// otherwise its possible during testing with MAX_AT_ONCE == 1 that a secondary type
		// can cause an infinite loop as it alternates between not found and defined, see bug 146324
		ArrayList extras = null;
		for (int i = 0, l = additionalUnits.lengthi < li++) {
			SourceFile unit = additionalUnits[i];
			if (unit != null && this..getDefinedTypeNamesFor(unit.typeLocator()) != null) {
					..println("About to compile file with secondary types "unit.typeLocator()); //$NON-NLS-1$
				if (extras == null)
					extras = new ArrayList(3);
				extras.add(unit);
			}
		}
		if (extras != null) {
			int oldLength = units.length;
			int toAdd = extras.size();
			System.arraycopy(units, 0, units = new SourceFile[oldLength + toAdd], 0, oldLength);
			for (int i = 0; i < toAddi++)
				units[oldLength++] = (SourceFileextras.get(i);
		}
	}
	super.compile(unitsadditionalUnitscompilingFirstGroup);
protected void deleteGeneratedFiles(IFile[] deletedGeneratedFiles) {
	// delete generated files and recompile any affected source files
	try {
		for (int j = deletedGeneratedFiles.length; --j >= 0;) {
			IFile deletedFile = deletedGeneratedFiles[j];
			if (deletedFile.exists()) continue// only delete .class files for source files that were actually deleted
			SourceFile sourceFile = findSourceFile(deletedFilefalse);
			String typeLocator = sourceFile.typeLocator();
			int mdSegmentCount = sourceFile.sourceLocation.sourceFolder.getFullPath().segmentCount();
			IPath typePath = sourceFile.resource.getFullPath().removeFirstSegments(mdSegmentCount).removeFileExtension();
			addDependentsOf(typePathtrue); // add dependents of the source file since its now deleted
			this. = null// existing source files did not see it as deleted since they were compiled before it was
			char[][] definedTypeNames = this..getDefinedTypeNamesFor(typeLocator);
			if (definedTypeNames == null) { // defined a single type matching typePath
				removeClassFile(typePathsourceFile.sourceLocation.binaryFolder);
else {
				if (definedTypeNames.length > 0) { // skip it if it failed to successfully define a type
					IPath packagePath = typePath.removeLastSegments(1);
					for (int d = 0, l = definedTypeNames.lengthd < ld++)
						removeClassFile(packagePath.append(new String(definedTypeNames[d])), sourceFile.sourceLocation.binaryFolder);
				}
			}
			this..removeLocator(typeLocator);
		}
catch (CoreException e) {
		// must continue with compile loop so just log the CoreException
		Util.log(e"JavaBuilder logging CompilationParticipant's CoreException to help debugging"); //$NON-NLS-1$
	}
protected boolean findAffectedSourceFiles(IResourceDelta deltaClasspathLocation[] classFoldersAndJars, IProject prereqProject) {
	for (int i = 0, l = classFoldersAndJars.lengthi < li++) {
		ClasspathLocation bLocation = classFoldersAndJars[i];
		// either a .class file folder or a zip/jar file
		if (bLocation != null) { // skip unchanged output folder
			IPath p = bLocation.getProjectRelativePath();
			if (p != null) {
				IResourceDelta binaryDelta = delta.findMember(p);
				if (binaryDelta != null) {
					if (bLocation instanceof ClasspathJar) {
							..println("ABORTING incremental build... found delta to jar/zip file"); //$NON-NLS-1$
						return false// do full build since jar file was changed (added/removed were caught as classpath change)
					}
					if (binaryDelta.getKind() == IResourceDelta.ADDED || binaryDelta.getKind() == IResourceDelta.REMOVED) {
							..println("ABORTING incremental build... found added/removed binary folder"); //$NON-NLS-1$
						return false// added/removed binary folder should not make it here (classpath change), but handle anyways
					}
					int segmentCount = binaryDelta.getFullPath().segmentCount();
					IResourceDelta[] children = binaryDelta.getAffectedChildren(); // .class files from class folder
					StringSet structurallyChangedTypes = null;
					if (bLocation.isOutputFolder())
						structurallyChangedTypes = this..getStructurallyChangedTypes(this..getLastState(prereqProject));
					for (int j = 0, m = children.length; j < mj++)
						findAffectedSourceFiles(children[j], segmentCountstructurallyChangedTypes);
				}
			}
		}
	}
	return true;
protected void findAffectedSourceFiles(IResourceDelta binaryDeltaint segmentCountStringSet structurallyChangedTypes) {
	// When a package becomes a type or vice versa, expect 2 deltas,
	// one on the folder & one on the class file
	IResource resource = binaryDelta.getResource();
	switch(resource.getType()) {
		case IResource.FOLDER :
			switch (binaryDelta.getKind()) {
				case IResourceDelta.ADDED :
				case IResourceDelta.REMOVED :
					IPath packagePath = resource.getFullPath().removeFirstSegments(segmentCount);
					String packageName = packagePath.toString();
					if (binaryDelta.getKind() == IResourceDelta.ADDED) {
						// see if any known source file is from the same package... classpath already includes new package
						if (!this..isKnownPackage(packageName)) {
								..println("Found added package " + packageName); //$NON-NLS-1$
							addDependentsOf(packagePathfalse);
							return;
						}
							..println("Skipped dependents of added package " + packageName); //$NON-NLS-1$
else {
						// see if the package still exists on the classpath
						if (!this..isPackage(packageName)) {
								..println("Found removed package " + packageName); //$NON-NLS-1$
							addDependentsOf(packagePathfalse);
							return;
						}
							..println("Skipped dependents of removed package " + packageName); //$NON-NLS-1$
					}
					//$FALL-THROUGH$ traverse the sub-packages and .class files
				case IResourceDelta.CHANGED :
					IResourceDelta[] children = binaryDelta.getAffectedChildren();
					for (int i = 0, l = children.length; i < li++)
						findAffectedSourceFiles(children[i], segmentCountstructurallyChangedTypes);
			}
			return;
		case IResource.FILE :
			if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(resource.getName())) {
				IPath typePath = resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension();
				switch (binaryDelta.getKind()) {
					case IResourceDelta.ADDED :
					case IResourceDelta.REMOVED :
							..println("Found added/removed class file " + typePath); //$NON-NLS-1$
						addDependentsOf(typePathfalse);
						return;
					case IResourceDelta.CHANGED :
						if ((binaryDelta.getFlags() & IResourceDelta.CONTENT) == 0)
							return// skip it since it really isn't changed
						if (structurallyChangedTypes != null && !structurallyChangedTypes.includes(typePath.toString()))
							return// skip since it wasn't a structural change
							..println("Found changed class file " + typePath); //$NON-NLS-1$
						addDependentsOf(typePathfalse);
				}
				return;
			}
	}
protected boolean findSourceFiles(IResourceDelta deltathrows CoreException {
	ArrayList visited = this. ? new ArrayList(this..length) : null;
	for (int i = 0, l = this..lengthi < li++) {
		if (this. && md.hasIndependentOutputFolder && !visited.contains(md.binaryFolder)) {
			// even a project which acts as its own source folder can have an independent/nested output folder
			visited.add(md.binaryFolder);
			IResourceDelta binaryDelta = delta.findMember(md.binaryFolder.getProjectRelativePath());
			if (binaryDelta != null) {
				int segmentCount = binaryDelta.getFullPath().segmentCount();
				IResourceDelta[] children = binaryDelta.getAffectedChildren();
				for (int j = 0, m = children.length; j < mj++)
					if (!checkForClassFileChanges(children[j], mdsegmentCount))
						return false;
			}
		}
		if (md.sourceFolder.equals(this..)) {
			// skip nested source & output folders when the project is a source folder
			int segmentCount = delta.getFullPath().segmentCount();
			IResourceDelta[] children = delta.getAffectedChildren();
			for (int j = 0, m = children.length; j < mj++)
				if (!isExcludedFromProject(children[j].getFullPath()))
					if (!findSourceFiles(children[j], mdsegmentCount))
						return false;
else {
			IResourceDelta sourceDelta = delta.findMember(md.sourceFolder.getProjectRelativePath());
			if (sourceDelta != null) {
				if (sourceDelta.getKind() == IResourceDelta.REMOVED) {
						..println("ABORTING incremental build... found removed source folder"); //$NON-NLS-1$
					return false// removed source folder should not make it here, but handle anyways (ADDED is supported)
				}
				int segmentCount = sourceDelta.getFullPath().segmentCount();
				IResourceDelta[] children = sourceDelta.getAffectedChildren();
				try {
					for (int j = 0, m = children.length; j < mj++)
						if (!findSourceFiles(children[j], mdsegmentCount))
							return false;
catch (CoreException e) {
					// catch the case that a package has been renamed and collides on disk with an as-yet-to-be-deleted package
					if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
							..println("ABORTING incremental build... found renamed package"); //$NON-NLS-1$
						return false;
					}
					throw e// rethrow
				}
			}
		}
	}
	return true;
protected boolean findSourceFiles(IResourceDelta sourceDeltaClasspathMultiDirectory mdint segmentCountthrows CoreException {
	// When a package becomes a type or vice versa, expect 2 deltas,
	// one on the folder & one on the source file
	IResource resource = sourceDelta.getResource();
	// remember that if inclusion & exclusion patterns change then a full build is done
	boolean isExcluded = (md.exclusionPatterns != null || md.inclusionPatterns != null)
		&& Util.isExcluded(resourcemd.inclusionPatternsmd.exclusionPatterns);
	switch(resource.getType()) {
		case IResource.FOLDER :
			if (isExcluded && md.inclusionPatterns == null)
		        return true// no need to go further with this delta since its children cannot be included
			switch (sourceDelta.getKind()) {
				case IResourceDelta.ADDED :
				    if (!isExcluded) {
						IPath addedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount);
						createFolder(addedPackagePathmd.binaryFolder); // ensure package exists in the output folder
						// see if any known source file is from the same package... classpath already includes new package
						if (this..length > 1 && this..isKnownPackage(addedPackagePath.toString())) {
								..println("Skipped dependents of added package " + addedPackagePath); //$NON-NLS-1$
else {
								..println("Found added package " + addedPackagePath); //$NON-NLS-1$
							addDependentsOf(addedPackagePathtrue);
						}
				    }
					//$FALL-THROUGH$ collect all the source files
				case IResourceDelta.CHANGED :
					IResourceDelta[] children = sourceDelta.getAffectedChildren();
					for (int i = 0, l = children.length; i < li++)
						if (!findSourceFiles(children[i], mdsegmentCount))
							return false;
					return true;
				case IResourceDelta.REMOVED :
				    if (isExcluded) {
				    	// since this folder is excluded then there is nothing to delete (from this md), but must walk any included subfolders
						children = sourceDelta.getAffectedChildren();
						for (int i = 0, l = children.length; i < li++)
							if (!findSourceFiles(children[i], mdsegmentCount))
								return false;
						return true;
				    }
					IPath removedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount);
					if (this..length > 1) {
						for (int i = 0, l = this..lengthi < li++) {
							if (this.[i]..getFolder(removedPackagePath).exists()) {
								// only a package fragment was removed, same as removing multiple source files
								if (md.hasIndependentOutputFolder)
									createFolder(removedPackagePathmd.binaryFolder); // ensure package exists in the output folder
								IResourceDelta[] removedChildren = sourceDelta.getAffectedChildren();
								for (int j = 0, m = removedChildren.length; j < mj++)
									if (!findSourceFiles(removedChildren[j], mdsegmentCount))
										return false;
								return true;
							}
						}
					}
					if ((sourceDelta.getFlags() & IResourceDelta.MOVED_TO) != 0) {
						// same idea as moving a source file
						// see bug 163200
						IResource movedFolder = this...getFolder(sourceDelta.getMovedToPath());
						JavaBuilder.removeProblemsAndTasksFor(movedFolder);
					}
					IFolder removedPackageFolder = md.binaryFolder.getFolder(removedPackagePath);
					if (removedPackageFolder.exists())
						removedPackageFolder.delete(IResource.FORCE, null);
					// add dependents even when the package thinks it does not exist to be on the safe side
						..println("Found removed package " + removedPackagePath); //$NON-NLS-1$
					addDependentsOf(removedPackagePathtrue);
					this..removePackage(sourceDelta);
			}
			return true;
		case IResource.FILE :
			if (isExcludedreturn true;
			String resourceName = resource.getName();
			if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(resourceName)) {
				IPath typePath = resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension();
				String typeLocator = resource.getProjectRelativePath().toString();
				switch (sourceDelta.getKind()) {
					case IResourceDelta.ADDED :
							..println("Compile this added source file " + typeLocator); //$NON-NLS-1$
						this..add(new SourceFile((IFile) resourcemdtrue));
						String typeName = typePath.toString();
						if (!this..isDuplicateLocator(typeNametypeLocator)) { // adding dependents results in 2 duplicate errors
								..println("Found added source file " + typeName); //$NON-NLS-1$
							addDependentsOf(typePathtrue);
						}
						return true;
					case IResourceDelta.REMOVED :
						char[][] definedTypeNames = this..getDefinedTypeNamesFor(typeLocator);
						if (definedTypeNames == null) { // defined a single type matching typePath
							removeClassFile(typePathmd.binaryFolder);
							if ((sourceDelta.getFlags() & IResourceDelta.MOVED_TO) != 0) {
								// remove problems and tasks for a compilation unit that is being moved (to another package or renamed)
								// if the target file is a compilation unit, the new cu will be recompiled
								// if the target file is a non-java resource, then markers are removed
								// see bug 2857
								IResource movedFile = this...getFile(sourceDelta.getMovedToPath());
								JavaBuilder.removeProblemsAndTasksFor(movedFile);
							}
else {
								..println("Found removed source file " + typePath.toString()); //$NON-NLS-1$
							addDependentsOf(typePathtrue); // add dependents of the source file since it may be involved in a name collision
							if (definedTypeNames.length > 0) { // skip it if it failed to successfully define a type
								IPath packagePath = typePath.removeLastSegments(1);
								for (int i = 0, l = definedTypeNames.lengthi < li++)
									removeClassFile(packagePath.append(new String(definedTypeNames[i])), md.binaryFolder);
							}
						}
						this..removeLocator(typeLocator);
						return true;
					case IResourceDelta.CHANGED :
						if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0
								&& (sourceDelta.getFlags() & IResourceDelta.ENCODING) == 0)
							return true// skip it since it really isn't changed
							..println("Compile this changed source file " + typeLocator); //$NON-NLS-1$
						this..add(new SourceFile((IFile) resourcemdtrue));
				}
				return true;
else if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(resourceName)) {
				// perform full build if a managed class file has been changed
					IPath typePath = resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension();
					if (this..isKnownType(typePath.toString())) {
							..println("MUST DO FULL BUILD. Found change to class file " + typePath); //$NON-NLS-1$
						return false;
					}
				}
				return true;
else if (md.hasIndependentOutputFolder) {
				if (this..filterExtraResource(resource)) return true;
				// copy all other resource deltas to the output folder
				IPath resourcePath = resource.getFullPath().removeFirstSegments(segmentCount);
				IResource outputFile = md.binaryFolder.getFile(resourcePath);
				switch (sourceDelta.getKind()) {
					case IResourceDelta.ADDED :
						if (outputFile.exists()) {
								..println("Deleting existing file " + resourcePath); //$NON-NLS-1$
							outputFile.delete(IResource.FORCE, null);
						}
							..println("Copying added file " + resourcePath); //$NON-NLS-1$
						createFolder(resourcePath.removeLastSegments(1), md.binaryFolder); // ensure package exists in the output folder
						copyResource(resourceoutputFile);
						return true;
					case IResourceDelta.REMOVED :
						if (outputFile.exists()) {
								..println("Deleting removed file " + resourcePath); //$NON-NLS-1$
							outputFile.delete(IResource.FORCE, null);
						}
						return true;
					case IResourceDelta.CHANGED :
						if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0
								&& (sourceDelta.getFlags() & IResourceDelta.ENCODING) == 0)
							return true// skip it since it really isn't changed
						if (outputFile.exists()) {
								..println("Deleting existing file " + resourcePath); //$NON-NLS-1$
							outputFile.delete(IResource.FORCE, null);
						}
							..println("Copying changed file " + resourcePath); //$NON-NLS-1$
						createFolder(resourcePath.removeLastSegments(1), md.binaryFolder); // ensure package exists in the output folder
						copyResource(resourceoutputFile);
				}
				return true;
			}
	}
	return true;
protected void finishedWith(String sourceLocatorCompilationResult resultchar[] mainTypeNameArrayList definedTypeNamesArrayList duplicateTypeNames) {
	char[][] previousTypeNames = this..getDefinedTypeNamesFor(sourceLocator);
	if (previousTypeNames == null)
		previousTypeNames = new char[][] {mainTypeName};
	IPath packagePath = null;
	next : for (int i = 0, l = previousTypeNames.lengthi < li++) {
		char[] previous = previousTypeNames[i];
		for (int j = 0, m = definedTypeNames.size(); j < mj++)
			if (CharOperation.equals(previous, (char[]) definedTypeNames.get(j)))
				continue next;
		SourceFile sourceFile = (SourceFileresult.getCompilationUnit();
		if (packagePath == null) {
			int count = sourceFile.sourceLocation.sourceFolder.getFullPath().segmentCount();
			packagePath = sourceFile.resource.getFullPath().removeFirstSegments(count).removeLastSegments(1);
		}
		if (this. == null)
		ArrayList types = (ArrayListthis..get(sourceFile.sourceLocation.binaryFolder);
		if (types == null)
			types = new ArrayList(definedTypeNames.size());
		types.add(packagePath.append(new String(previous)));
		this..put(sourceFile.sourceLocation.binaryFoldertypes);
	}
	super.finishedWith(sourceLocatorresultmainTypeNamedefinedTypeNamesduplicateTypeNames);
	for (int i = results.length; --i >= 0;) {
		CompilationParticipantResult result = results[i];
		if (result == nullcontinue;
		IFile[] deletedGeneratedFiles = result.deletedFiles;
		if (deletedGeneratedFiles != null)
			deleteGeneratedFiles(deletedGeneratedFiles);
		IFile[] addedGeneratedFiles = result.addedFiles;
		if (addedGeneratedFiles != null) {
			for (int j = addedGeneratedFiles.length; --j >= 0;) {
				SourceFile sourceFile = findSourceFile(addedGeneratedFiles[j], true);
				if (sourceFile != null && !this..contains(sourceFile))
					this..add(sourceFile);
			}
		}
	}
protected void removeClassFile(IPath typePath, IContainer outputFolderthrows CoreException {
	if (typePath.lastSegment().indexOf('$') == -1) { // is not a nested type
		this..removeQualifiedTypeName(typePath.toString());
		// add dependents even when the type thinks it does not exist to be on the safe side
			..println("Found removed type " + typePath); //$NON-NLS-1$
		addDependentsOf(typePathtrue); // when member types are removed, their enclosing type is structurally changed
	}
	IFile classFile = outputFolder.getFile(typePath.addFileExtension(.));
	if (classFile.exists()) {
			..println("Deleting class file of removed type " + typePath); //$NON-NLS-1$
		classFile.delete(IResource.FORCE, null);
	}
protected void removeSecondaryTypes() throws CoreException {
	if (this. != null) { // delayed deleting secondary types until the end of the compile loop
		for (int i = 0, l = keyTable.lengthi < li++) {
			IContainer outputFolder = (IContainer) keyTable[i];
			if (outputFolder != null) {
				ArrayList paths = (ArrayListvalueTable[i];
				for (int j = 0, m = paths.size(); j < mj++)
					removeClassFile((IPath) paths.get(j), outputFolder);
			}
		}
		if (this. != null)
			this. = null// cannot optimize recompile case when a secondary type is deleted, see 181269
	}
protected void resetCollections() {
	if (this. == null) {
		this. = new ArrayList(33);
		this. = null;
		this. = new StringSet(3);
		this. = new StringSet(3);
		this. = new StringSet(3);
		this. = false;
		this. = 0;
else {
		this. = this..isEmpty() ? null : (ArrayListthis..clone();
	}
protected void updateProblemsFor(SourceFile sourceFileCompilationResult resultthrows CoreException {
	if (CharOperation.equals(sourceFile.getMainTypeName(), .)) {
		IResource pkgResource = sourceFile.resource.getParent();
		pkgResource.deleteMarkers(.false, IResource.DEPTH_ZERO);
	}
	IMarker[] markers = JavaBuilder.getProblemsFor(sourceFile.resource);
	CategorizedProblem[] problems = result.getProblems();
	if (problems == null && markers.length == 0) return;
	this..updateProblemCounts(markersproblems);
	JavaBuilder.removeProblemsFor(sourceFile.resource);
	storeProblemsFor(sourceFileproblems);
protected void updateTasksFor(SourceFile sourceFileCompilationResult resultthrows CoreException {
	IMarker[] markers = JavaBuilder.getTasksFor(sourceFile.resource);
	CategorizedProblem[] tasks = result.getTasks();
	if (tasks == null && markers.length == 0) return;
	JavaBuilder.removeTasksFor(sourceFile.resource);
	storeTasksFor(sourceFiletasks);

See also:
org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.writeClassFileContents(org.eclipse.jdt.internal.compiler.ClassFile, org.eclipse.core.resources.IFile, java.lang.String, boolean, org.eclipse.jdt.internal.core.builder.SourceFile)
protected void writeClassFileContents(ClassFile classfile, IFile fileString qualifiedFileNameboolean isTopLevelTypeSourceFile compilationUnitthrows CoreException {
	// Before writing out the class file, compare it to the previous file
	// If structural changes occurred then add dependent source files
	byte[] bytes = classfile.getBytes();
	if (file.exists()) {
		if (writeClassFileCheck(filequalifiedFileNamebytes) || compilationUnit.updateClassFile) { // see 46093
				..println("Writing changed class file " + file.getName());//$NON-NLS-1$
			if (!file.isDerived())
				file.setDerived(truenull);
			file.setContents(new ByteArrayInputStream(bytes), truefalsenull);
else if (.) {
			..println("Skipped over unchanged class file " + file.getName());//$NON-NLS-1$
		}
else {
		if (isTopLevelType)
			addDependentsOf(new Path(qualifiedFileName), true); // new type
			..println("Writing new class file " + file.getName());//$NON-NLS-1$
		try {
			file.create(new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null);
catch (CoreException e) {
			if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
				IStatus status = e.getStatus();
				if (status instanceof IResourceStatus) {
					IPath oldFilePath = ((IResourceStatus) status).getPath();
					char[] oldTypeName = oldFilePath.removeFileExtension().lastSegment().toCharArray();
					char[][] previousTypeNames = this..getDefinedTypeNamesFor(compilationUnit.typeLocator());
					boolean fromSameFile = false;
					if (previousTypeNames == null) {
						fromSameFile = CharOperation.equals(compilationUnit.getMainTypeName(), oldTypeName);
else {
						for (int i = 0, l = previousTypeNames.lengthi < li++) {
							if (CharOperation.equals(previousTypeNames[i], oldTypeName)) {
								fromSameFile = true;
								break;
							}
						}
					}
					if (fromSameFile) {
						// file is defined by the same compilationUnit, but won't be deleted until later so do it now
						IFile collision = file.getParent().getFile(new Path(oldFilePath.lastSegment()));
						collision.delete(truefalsenull);
						boolean success = false;
						try {
							file.create(new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null);
							success = true;
catch (CoreException ignored) {
							// ignore the second exception
						}
						if (successreturn;
					}
				}
				// catch the case that a type has been renamed and collides on disk with an as-yet-to-be-deleted type
				throw new AbortCompilation(truenew AbortIncrementalBuildException(qualifiedFileName));
			}
			throw e// rethrow
		}
	}
protected boolean writeClassFileCheck(IFile fileString fileNamebyte[] newBytesthrows CoreException {
	try {
		byte[] oldBytes = Util.getResourceContentsAsByteArray(file);
		notEqual : if (newBytes.length == oldBytes.length) {
			for (int i = newBytes.length; --i >= 0;)
				if (newBytes[i] != oldBytes[i]) break notEqual;
			return false// bytes are identical so skip them
		}
		URI location = file.getLocationURI();
		if (location == nullreturn false// unable to determine location of this class file
		String filePath = location.getSchemeSpecificPart();
		ClassFileReader reader = new ClassFileReader(oldBytesfilePath.toCharArray());
		// ignore local types since they're only visible inside a single method
		if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) {
				..println("Type has structural changes " + fileName); //$NON-NLS-1$
			addDependentsOf(new Path(fileName), true);
		}
catch (ClassFormatException e) {
		addDependentsOf(new Path(fileName), true);
	}
	return true;
public String toString() {
	return "incremental image builder for:\n\tnew state: " + this.//$NON-NLS-1$
/* Debug helper
static void dump(IResourceDelta delta) {
	StringBuffer buffer = new StringBuffer();
	IPath path = delta.getFullPath();
	for (int i = path.segmentCount(); --i > 0;)
		buffer.append("  ");
	switch (delta.getKind()) {
		case IResourceDelta.ADDED:
			buffer.append('+');
			break;
		case IResourceDelta.REMOVED:
			buffer.append('-');
			break;
		case IResourceDelta.CHANGED:
			buffer.append('*');
			break;
		case IResourceDelta.NO_CHANGE:
			buffer.append('=');
			break;
		default:
			buffer.append('?');
			break;
	}
	buffer.append(path);
	System.out.println(buffer.toString());
	IResourceDelta[] children = delta.getAffectedChildren();
	for (int i = 0, l = children.length; i < l; i++)
		dump(children[i]);
*/