Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 1699 Details for
Bug 21606
ImageBuilder deletes & adds rather than overwriting
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
A possible fix in Eclipse patch format. (patch.txt)
patch.txt (text/plain), 85.50 KB, created by
Jed Anderson
on 2002-07-15 19:50:09 EDT
(
hide
)
Description:
A possible fix in Eclipse patch format. (patch.txt)
Filename:
MIME Type:
Creator:
Jed Anderson
Created:
2002-07-15 19:50:09 EDT
Size:
85.50 KB
patch
obsolete
>Index: model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java >=================================================================== >RCS file: /home/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java,v >retrieving revision 1.23 >diff -u -r1.23 AbstractImageBuilder.java >--- model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java 28 May 2002 11:37:09 -0000 1.23 >+++ model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java 15 Jul 2002 23:45:26 -0000 >@@ -1,412 +1,417 @@ >-/******************************************************************************* >- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Common Public License v0.5 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/cpl-v05.html >- * >- * Contributors: >- * IBM Corporation - initial API and implementation >- ******************************************************************************/ >-package org.eclipse.jdt.internal.core.builder; >- >-import org.eclipse.core.runtime.*; >-import org.eclipse.core.resources.*; >- >-import org.eclipse.jdt.core.*; >-import org.eclipse.jdt.core.compiler.IProblem; >-import org.eclipse.jdt.internal.compiler.*; >-import org.eclipse.jdt.internal.compiler.ClassFile; >-import org.eclipse.jdt.internal.compiler.Compiler; >-import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; >-import org.eclipse.jdt.internal.compiler.problem.*; >-import org.eclipse.jdt.internal.compiler.util.CharOperation; >-import org.eclipse.jdt.internal.core.*; >- >-import java.io.*; >-import java.util.*; >- >-/** >- * The abstract superclass of image builders. >- * Provides the building and compilation mechanism >- * in common with the batch and incremental builders. >- */ >-public abstract class AbstractImageBuilder implements ICompilerRequestor { >- >-protected JavaBuilder javaBuilder; >-protected State newState; >- >-// local copies >-protected IContainer outputFolder; >-protected IContainer[] sourceFolders; >-protected BuildNotifier notifier; >- >-protected boolean hasSeparateOutputFolder; >-protected NameEnvironment nameEnvironment; >-protected Compiler compiler; >-protected WorkQueue workQueue; >-protected ArrayList problemTypeLocations; >-protected boolean compiledAllAtOnce; >- >-private boolean inCompiler; >- >-public static int MAX_AT_ONCE = 1000; >- >-protected AbstractImageBuilder(JavaBuilder javaBuilder) { >- this.javaBuilder = javaBuilder; >- this.newState = new State(javaBuilder); >- >- // local copies >- this.outputFolder = javaBuilder.outputFolder; >- this.sourceFolders = javaBuilder.sourceFolders; >- this.notifier = javaBuilder.notifier; >- >- // only perform resource copying if the output location does not match a source folder >- // corresponds to: project == src == bin, or several source folders are contributing resources, >- // but one is the output location too (and would get populated with other source folder resources). >- IPath outputPath = outputFolder.getFullPath(); >- int index = sourceFolders.length; >- if (index == 0) { >- // handle case of the last source folder is removed... so no source folders exist but the output folder must still be scrubbed >- this.hasSeparateOutputFolder = !outputPath.equals(javaBuilder.currentProject.getFullPath()); >- } else { >- this.hasSeparateOutputFolder = true; >- while (this.hasSeparateOutputFolder && --index >= 0) >- this.hasSeparateOutputFolder = !outputPath.equals(sourceFolders[index].getFullPath()); >- } >- >- this.nameEnvironment = new NameEnvironment(javaBuilder.classpath); >- this.compiler = newCompiler(); >- this.workQueue = new WorkQueue(); >- this.problemTypeLocations = new ArrayList(3); >-} >- >-public void acceptResult(CompilationResult result) { >- // In Batch mode, we write out the class files, hold onto the dependency info >- // & additional types and report problems. >- >- // In Incremental mode, when writing out a class file we need to compare it >- // against the previous file, remembering if structural changes occured. >- // Before reporting the new problems, we need to update the problem count & >- // remove the old problems. Plus delete additional class files that no longer exist. >- >- // only need to find resource for the sourceLocation when problems need to be reported against it >- String sourceLocation = new String(result.getFileName()); // the full filesystem path "d:/xyz/eclipse/src1/Test/p1/p2/A.java" >- if (!workQueue.isCompiled(sourceLocation)) { >- try { >- workQueue.finished(sourceLocation); >- updateProblemsFor(sourceLocation, result); // record compilation problems before potentially adding duplicate errors >- >- ICompilationUnit compilationUnit = result.getCompilationUnit(); >- ClassFile[] classFiles = result.getClassFiles(); >- int length = classFiles.length; >- ArrayList duplicateTypeNames = null; >- ArrayList definedTypeNames = new ArrayList(length); >- for (int i = 0; i < length; i++) { >- ClassFile classFile = classFiles[i]; >- char[][] compoundName = classFile.getCompoundName(); >- char[] typeName = compoundName[compoundName.length - 1]; >- boolean isNestedType = CharOperation.contains('$', typeName); >- >- // Look for a possible collision, if one exists, report an error but do not write the class file >- if (isNestedType) { >- String qualifiedTypeName = new String(classFile.outerMostEnclosingClassFile().fileName()); >- if (newState.isDuplicateLocation(qualifiedTypeName, sourceLocation)) >- continue; >- } else { >- String qualifiedTypeName = new String(classFile.fileName()); // the qualified type name "p1/p2/A" >- if (newState.isDuplicateLocation(qualifiedTypeName, sourceLocation)) { >- if (duplicateTypeNames == null) >- duplicateTypeNames = new ArrayList(); >- duplicateTypeNames.add(compoundName); >- createErrorFor(resourceForLocation(sourceLocation), Util.bind("build.duplicateClassFile", new String(typeName))); //$NON-NLS-1$ >- continue; >- } >- newState.recordLocationForType(qualifiedTypeName, sourceLocation); >- } >- definedTypeNames.add(writeClassFile(classFile, !isNestedType)); >- } >- >- finishedWith(sourceLocation, result, compilationUnit.getMainTypeName(), definedTypeNames, duplicateTypeNames); >- notifier.compiled(compilationUnit); >- } catch (CoreException e) { >- Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$ >- createErrorFor(resourceForLocation(sourceLocation), Util.bind("build.inconsistentClassFile")); //$NON-NLS-1$ >- } >- } >-} >- >-protected void cleanUp() { >- this.nameEnvironment.cleanup(); >- >- this.javaBuilder = null; >- this.outputFolder = null; >- this.sourceFolders = null; >- this.notifier = null; >- this.compiler = null; >- this.nameEnvironment = null; >- this.workQueue = null; >- this.problemTypeLocations = null; >-} >- >-/* Compile the given elements, adding more elements to the work queue >-* if they are affected by the changes. >-*/ >-protected void compile(String[] filenames, String[] initialTypeNames) { >- int toDo = filenames.length; >- if (this.compiledAllAtOnce = toDo <= MAX_AT_ONCE) { >- // do them all now >- SourceFile[] toCompile = new SourceFile[toDo]; >- for (int i = 0; i < toDo; i++) { >- String filename = filenames[i]; >- if (JavaBuilder.DEBUG) >- System.out.println("About to compile " + filename); //$NON-NLS-1$ >- toCompile[i] = new SourceFile(filename, initialTypeNames[i]); >- } >- compile(toCompile, initialTypeNames, null); >- } else { >- int i = 0; >- boolean compilingFirstGroup = true; >- while (i < toDo) { >- int doNow = toDo < MAX_AT_ONCE ? toDo : MAX_AT_ONCE; >- int index = 0; >- SourceFile[] toCompile = new SourceFile[doNow]; >- String[] initialNamesInLoop = new String[doNow]; >- while (i < toDo && index < doNow) { >- String filename = filenames[i]; >- // Although it needed compiling when this method was called, it may have >- // already been compiled when it was referenced by another unit. >- if (compilingFirstGroup || workQueue.isWaiting(filename)) { >- if (JavaBuilder.DEBUG) >- System.out.println("About to compile " + filename);//$NON-NLS-1$ >- String initialTypeName = initialTypeNames[i]; >- initialNamesInLoop[index] = initialTypeName; >- toCompile[index++] = new SourceFile(filename, initialTypeName); >- } >- i++; >- } >- if (index < doNow) { >- System.arraycopy(toCompile, 0, toCompile = new SourceFile[index], 0, index); >- System.arraycopy(initialNamesInLoop, 0, initialNamesInLoop = new String[index], 0, index); >- } >- String[] additionalFilenames = new String[toDo - i]; >- System.arraycopy(filenames, i, additionalFilenames, 0, additionalFilenames.length); >- compilingFirstGroup = false; >- compile(toCompile, initialNamesInLoop, additionalFilenames); >- } >- } >-} >- >-void compile(SourceFile[] units, String[] initialTypeNames, String[] additionalFilenames) { >- if (units.length == 0) return; >- notifier.aboutToCompile(units[0]); // just to change the message >- >- // extend additionalFilenames with all hierarchical problem types found during this entire build >- if (!problemTypeLocations.isEmpty()) { >- int toAdd = problemTypeLocations.size(); >- int length = additionalFilenames == null ? 0 : additionalFilenames.length; >- if (length == 0) >- additionalFilenames = new String[toAdd]; >- else >- System.arraycopy(additionalFilenames, 0, additionalFilenames = new String[length + toAdd], 0, length); >- for (int i = 0; i < toAdd; i++) >- additionalFilenames[length + i] = (String) problemTypeLocations.get(i); >- } >- nameEnvironment.setNames(initialTypeNames, additionalFilenames); >- notifier.checkCancel(); >- try { >- inCompiler = true; >- compiler.compile(units); >- } finally { >- inCompiler = false; >- } >- // Check for cancel immediately after a compile, because the compiler may >- // have been cancelled but without propagating the correct exception >- notifier.checkCancel(); >-} >- >-protected void createErrorFor(IResource resource, String message) { >- try { >- IMarker marker = resource.createMarker(JavaBuilder.ProblemMarkerTag); >- marker.setAttributes( >- new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.CHAR_START, IMarker.CHAR_END}, >- new Object[] {message, new Integer(IMarker.SEVERITY_ERROR), new Integer(0), new Integer(1)}); >- } catch (CoreException e) { >- throw internalException(e); >- } >-} >- >-protected String extractTypeNameFrom(String sourceLocation) { >- for (int j = 0, k = sourceFolders.length; j < k; j++) { >- String folderLocation = sourceFolders[j].getLocation().addTrailingSeparator().toString(); >- if (sourceLocation.startsWith(folderLocation)) >- return sourceLocation.substring(folderLocation.length(), sourceLocation.length() - 5); // length of ".java" >- } >- return sourceLocation; // should not reach here >-} >- >-protected void finishedWith(String sourceLocation, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) throws CoreException { >- if (duplicateTypeNames == null) { >- newState.record(sourceLocation, result.qualifiedReferences, result.simpleNameReferences, mainTypeName, definedTypeNames); >- return; >- } >- >- char[][][] qualifiedRefs = result.qualifiedReferences; >- char[][] simpleRefs = result.simpleNameReferences; >- // for each duplicate type p1.p2.A, add the type name A (package was already added) >- next : for (int i = 0, dLength = duplicateTypeNames.size(); i < dLength; i++) { >- char[][] compoundName = (char[][]) duplicateTypeNames.get(i); >- char[] typeName = compoundName[compoundName.length - 1]; >- int sLength = simpleRefs.length; >- for (int j = 0; j < sLength; j++) >- if (CharOperation.equals(simpleRefs[j], typeName)) >- continue next; >- System.arraycopy(simpleRefs, 0, simpleRefs = new char[sLength + 1][], 0, sLength); >- simpleRefs[sLength] = typeName; >- } >- newState.record(sourceLocation, qualifiedRefs, simpleRefs, mainTypeName, definedTypeNames); >-} >- >-protected IContainer getOutputFolder(IPath packagePath) throws CoreException { >- IFolder folder = outputFolder.getFolder(packagePath); >- if (!folder.exists()) { >- getOutputFolder(packagePath.removeLastSegments(1)); >- folder.create(true, true, null); >- folder.setDerived(true); >- } >- return folder; >-} >- >-protected RuntimeException internalException(CoreException t) { >- ImageBuilderInternalException imageBuilderException = new ImageBuilderInternalException(t); >- if (inCompiler) >- return new AbortCompilation(true, imageBuilderException); >- return imageBuilderException; >-} >- >-protected Compiler newCompiler() { >- // called once when the builder is initialized... can override if needed >- return new Compiler( >- nameEnvironment, >- DefaultErrorHandlingPolicies.proceedWithAllProblems(), >- JavaCore.getOptions(), >- this, >- ProblemFactory.getProblemFactory(Locale.getDefault())); >-} >- >-protected IResource resourceForLocation(String sourceLocation) { >- return javaBuilder.workspaceRoot.getFileForLocation(new Path(sourceLocation)); >-} >- >-/** >- * Creates a marker from each problem and adds it to the resource. >- * The marker is as follows: >- * - its type is T_PROBLEM >- * - its plugin ID is the JavaBuilder's plugin ID >- * - its message is the problem's message >- * - its priority reflects the severity of the problem >- * - its range is the problem's range >- * - it has an extra attribute "ID" which holds the problem's id >- */ >-protected void storeProblemsFor(IResource resource, IProblem[] problems) throws CoreException { >- if (resource == null || problems == null || problems.length == 0) return; >- >- String missingClassFile = null; >- for (int i = 0, length = problems.length; i < length; i++) { >- IProblem problem = problems[i]; >- int id = problem.getID(); >- switch (id) { >- case IProblem.IsClassPathCorrect : >- JavaBuilder.removeProblemsFor(javaBuilder.currentProject); // make this the only problem for this project >- String[] args = problem.getArguments(); >- missingClassFile = args[0]; >- break; >- case IProblem.SuperclassMustBeAClass : >- case IProblem.SuperInterfaceMustBeAnInterface : >- case IProblem.HierarchyCircularitySelfReference : >- case IProblem.HierarchyCircularity : >- case IProblem.HierarchyHasProblems : >- case IProblem.SuperclassNotFound : >- case IProblem.SuperclassNotVisible : >- case IProblem.SuperclassAmbiguous : >- case IProblem.SuperclassInternalNameProvided : >- case IProblem.SuperclassInheritedNameHidesEnclosingName : >- case IProblem.InterfaceNotFound : >- case IProblem.InterfaceNotVisible : >- case IProblem.InterfaceAmbiguous : >- case IProblem.InterfaceInternalNameProvided : >- case IProblem.InterfaceInheritedNameHidesEnclosingName : >- // ensure that this file is always retrieved from source for the rest of the build >- String fileLocation = resource.getLocation().toString(); >- if (!problemTypeLocations.contains(fileLocation)) >- problemTypeLocations.add(fileLocation); >- } >- >- IMarker marker = resource.createMarker(JavaBuilder.ProblemMarkerTag); >- marker.setAttributes( >- new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.ID, IMarker.CHAR_START, IMarker.CHAR_END, IMarker.LINE_NUMBER, IJavaModelMarker.ARGUMENTS}, >- new Object[] { >- problem.getMessage(), >- new Integer(problem.isError() ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING), >- new Integer(id), >- new Integer(problem.getSourceStart()), >- new Integer(problem.getSourceEnd() + 1), >- new Integer(problem.getSourceLineNumber()), >- Util.getProblemArgumentsForMarker(problem.getArguments()) >- }); >- >- // compute a user-friendly location >- IJavaElement element = JavaCore.create(resource); >- if (element instanceof org.eclipse.jdt.core.ICompilationUnit) { // try to find a finer grain element >- org.eclipse.jdt.core.ICompilationUnit unit = (org.eclipse.jdt.core.ICompilationUnit) element; >- IJavaElement fragment = unit.getElementAt(problem.getSourceStart()); >- if (fragment != null) element = fragment; >- } >- String location = null; >- if (element instanceof JavaElement) >- location = ((JavaElement) element).readableName(); >- if (location != null) >- marker.setAttribute(IMarker.LOCATION, location); >- if (missingClassFile != null) >- throw new MissingClassFileException(missingClassFile); >- } >-} >- >-protected void updateProblemsFor(String sourceLocation, CompilationResult result) throws CoreException { >- IProblem[] problems = result.getProblems(); >- if (problems == null || problems.length == 0) return; >- >- notifier.updateProblemCounts(problems); >- storeProblemsFor(resourceForLocation(sourceLocation), problems); >-} >- >-protected char[] writeClassFile(ClassFile classFile, boolean isSecondaryType) throws CoreException { >- // Before writing out the class file, compare it to the previous file >- // If structural changes occured then add dependent source files >- String fileName = new String(classFile.fileName()); // the qualified type name "p1/p2/A" >- IPath filePath = new Path(fileName); >- IContainer container = outputFolder; >- if (filePath.segmentCount() > 1) { >- container = getOutputFolder(filePath.removeLastSegments(1)); >- filePath = new Path(filePath.lastSegment()); >- } >- >- IFile file = container.getFile(filePath.addFileExtension(JavaBuilder.CLASS_EXTENSION)); >- byte[] bytes = classFile.getBytes(); >- if (writeClassFileCheck(file, fileName, bytes, isSecondaryType)) { >- if (JavaBuilder.DEBUG) >- System.out.println("Writing class file " + file.getName());//$NON-NLS-1$ >- file.create(new ByteArrayInputStream(bytes), IResource.FORCE, null); >- file.setDerived(true); >- } else if (JavaBuilder.DEBUG) { >- System.out.println("Skipped over unchanged class file " + file.getName());//$NON-NLS-1$ >- } >- // answer the name of the class file as in Y or Y$M >- return filePath.lastSegment().toCharArray(); >-} >- >-protected boolean writeClassFileCheck(IFile file, String fileName, byte[] bytes, boolean isSecondaryType) throws CoreException { >- // In Incremental mode, compare the bytes against the previous file for structural changes >- return true; >-} >+/******************************************************************************* >+ * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Common Public License v0.5 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/cpl-v05.html >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ ******************************************************************************/ >+package org.eclipse.jdt.internal.core.builder; >+ >+import org.eclipse.core.runtime.*; >+import org.eclipse.core.resources.*; >+ >+import org.eclipse.jdt.core.*; >+import org.eclipse.jdt.core.compiler.IProblem; >+import org.eclipse.jdt.internal.compiler.*; >+import org.eclipse.jdt.internal.compiler.ClassFile; >+import org.eclipse.jdt.internal.compiler.Compiler; >+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; >+import org.eclipse.jdt.internal.compiler.problem.*; >+import org.eclipse.jdt.internal.compiler.util.CharOperation; >+import org.eclipse.jdt.internal.core.*; >+ >+import java.io.*; >+import java.util.*; >+ >+/** >+ * The abstract superclass of image builders. >+ * Provides the building and compilation mechanism >+ * in common with the batch and incremental builders. >+ */ >+public abstract class AbstractImageBuilder implements ICompilerRequestor { >+ >+protected JavaBuilder javaBuilder; >+protected State newState; >+ >+// local copies >+protected IContainer outputFolder; >+protected IContainer[] sourceFolders; >+protected BuildNotifier notifier; >+ >+protected boolean hasSeparateOutputFolder; >+protected NameEnvironment nameEnvironment; >+protected Compiler compiler; >+protected WorkQueue workQueue; >+protected ArrayList problemTypeLocations; >+protected boolean compiledAllAtOnce; >+ >+private boolean inCompiler; >+ >+public static int MAX_AT_ONCE = 1000; >+ >+protected AbstractImageBuilder(JavaBuilder javaBuilder) { >+ this.javaBuilder = javaBuilder; >+ this.newState = new State(javaBuilder); >+ >+ // local copies >+ this.outputFolder = javaBuilder.outputFolder; >+ this.sourceFolders = javaBuilder.sourceFolders; >+ this.notifier = javaBuilder.notifier; >+ >+ // only perform resource copying if the output location does not match a source folder >+ // corresponds to: project == src == bin, or several source folders are contributing resources, >+ // but one is the output location too (and would get populated with other source folder resources). >+ IPath outputPath = outputFolder.getFullPath(); >+ int index = sourceFolders.length; >+ if (index == 0) { >+ // handle case of the last source folder is removed... so no source folders exist but the output folder must still be scrubbed >+ this.hasSeparateOutputFolder = !outputPath.equals(javaBuilder.currentProject.getFullPath()); >+ } else { >+ this.hasSeparateOutputFolder = true; >+ while (this.hasSeparateOutputFolder && --index >= 0) >+ this.hasSeparateOutputFolder = !outputPath.equals(sourceFolders[index].getFullPath()); >+ } >+ >+ this.nameEnvironment = new NameEnvironment(javaBuilder.classpath); >+ this.compiler = newCompiler(); >+ this.workQueue = new WorkQueue(); >+ this.problemTypeLocations = new ArrayList(3); >+} >+ >+public void acceptResult(CompilationResult result) { >+ // In Batch mode, we write out the class files, hold onto the dependency info >+ // & additional types and report problems. >+ >+ // In Incremental mode, when writing out a class file we need to compare it >+ // against the previous file, remembering if structural changes occured. >+ // Before reporting the new problems, we need to update the problem count & >+ // remove the old problems. Plus delete additional class files that no longer exist. >+ >+ // only need to find resource for the sourceLocation when problems need to be reported against it >+ String sourceLocation = new String(result.getFileName()); // the full filesystem path "d:/xyz/eclipse/src1/Test/p1/p2/A.java" >+ if (!workQueue.isCompiled(sourceLocation)) { >+ try { >+ workQueue.finished(sourceLocation); >+ updateProblemsFor(sourceLocation, result); // record compilation problems before potentially adding duplicate errors >+ >+ ICompilationUnit compilationUnit = result.getCompilationUnit(); >+ ClassFile[] classFiles = result.getClassFiles(); >+ int length = classFiles.length; >+ ArrayList duplicateTypeNames = null; >+ ArrayList definedTypeNames = new ArrayList(length); >+ for (int i = 0; i < length; i++) { >+ ClassFile classFile = classFiles[i]; >+ char[][] compoundName = classFile.getCompoundName(); >+ char[] typeName = compoundName[compoundName.length - 1]; >+ boolean isNestedType = CharOperation.contains('$', typeName); >+ >+ // Look for a possible collision, if one exists, report an error but do not write the class file >+ if (isNestedType) { >+ String qualifiedTypeName = new String(classFile.outerMostEnclosingClassFile().fileName()); >+ if (newState.isDuplicateLocation(qualifiedTypeName, sourceLocation)) >+ continue; >+ } else { >+ String qualifiedTypeName = new String(classFile.fileName()); // the qualified type name "p1/p2/A" >+ if (newState.isDuplicateLocation(qualifiedTypeName, sourceLocation)) { >+ if (duplicateTypeNames == null) >+ duplicateTypeNames = new ArrayList(); >+ duplicateTypeNames.add(compoundName); >+ createErrorFor(resourceForLocation(sourceLocation), Util.bind("build.duplicateClassFile", new String(typeName))); //$NON-NLS-1$ >+ continue; >+ } >+ newState.recordLocationForType(qualifiedTypeName, sourceLocation); >+ } >+ definedTypeNames.add(writeClassFile(classFile, !isNestedType)); >+ } >+ >+ finishedWith(sourceLocation, result, compilationUnit.getMainTypeName(), definedTypeNames, duplicateTypeNames); >+ notifier.compiled(compilationUnit); >+ } catch (CoreException e) { >+ Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$ >+ createErrorFor(resourceForLocation(sourceLocation), Util.bind("build.inconsistentClassFile")); //$NON-NLS-1$ >+ } >+ } >+} >+ >+protected void cleanUp() { >+ this.nameEnvironment.cleanup(); >+ >+ this.javaBuilder = null; >+ this.outputFolder = null; >+ this.sourceFolders = null; >+ this.notifier = null; >+ this.compiler = null; >+ this.nameEnvironment = null; >+ this.workQueue = null; >+ this.problemTypeLocations = null; >+} >+ >+/* Compile the given elements, adding more elements to the work queue >+* if they are affected by the changes. >+*/ >+protected void compile(String[] filenames, String[] initialTypeNames) { >+ int toDo = filenames.length; >+ if (this.compiledAllAtOnce = toDo <= MAX_AT_ONCE) { >+ // do them all now >+ SourceFile[] toCompile = new SourceFile[toDo]; >+ for (int i = 0; i < toDo; i++) { >+ String filename = filenames[i]; >+ if (JavaBuilder.DEBUG) >+ System.out.println("About to compile " + filename); //$NON-NLS-1$ >+ toCompile[i] = new SourceFile(filename, initialTypeNames[i]); >+ } >+ compile(toCompile, initialTypeNames, null); >+ } else { >+ int i = 0; >+ boolean compilingFirstGroup = true; >+ while (i < toDo) { >+ int doNow = toDo < MAX_AT_ONCE ? toDo : MAX_AT_ONCE; >+ int index = 0; >+ SourceFile[] toCompile = new SourceFile[doNow]; >+ String[] initialNamesInLoop = new String[doNow]; >+ while (i < toDo && index < doNow) { >+ String filename = filenames[i]; >+ // Although it needed compiling when this method was called, it may have >+ // already been compiled when it was referenced by another unit. >+ if (compilingFirstGroup || workQueue.isWaiting(filename)) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("About to compile " + filename);//$NON-NLS-1$ >+ String initialTypeName = initialTypeNames[i]; >+ initialNamesInLoop[index] = initialTypeName; >+ toCompile[index++] = new SourceFile(filename, initialTypeName); >+ } >+ i++; >+ } >+ if (index < doNow) { >+ System.arraycopy(toCompile, 0, toCompile = new SourceFile[index], 0, index); >+ System.arraycopy(initialNamesInLoop, 0, initialNamesInLoop = new String[index], 0, index); >+ } >+ String[] additionalFilenames = new String[toDo - i]; >+ System.arraycopy(filenames, i, additionalFilenames, 0, additionalFilenames.length); >+ compilingFirstGroup = false; >+ compile(toCompile, initialNamesInLoop, additionalFilenames); >+ } >+ } >+} >+ >+void compile(SourceFile[] units, String[] initialTypeNames, String[] additionalFilenames) { >+ if (units.length == 0) return; >+ notifier.aboutToCompile(units[0]); // just to change the message >+ >+ // extend additionalFilenames with all hierarchical problem types found during this entire build >+ if (!problemTypeLocations.isEmpty()) { >+ int toAdd = problemTypeLocations.size(); >+ int length = additionalFilenames == null ? 0 : additionalFilenames.length; >+ if (length == 0) >+ additionalFilenames = new String[toAdd]; >+ else >+ System.arraycopy(additionalFilenames, 0, additionalFilenames = new String[length + toAdd], 0, length); >+ for (int i = 0; i < toAdd; i++) >+ additionalFilenames[length + i] = (String) problemTypeLocations.get(i); >+ } >+ nameEnvironment.setNames(initialTypeNames, additionalFilenames); >+ notifier.checkCancel(); >+ try { >+ inCompiler = true; >+ compiler.compile(units); >+ } finally { >+ inCompiler = false; >+ } >+ // Check for cancel immediately after a compile, because the compiler may >+ // have been cancelled but without propagating the correct exception >+ notifier.checkCancel(); >+} >+ >+protected void createErrorFor(IResource resource, String message) { >+ try { >+ IMarker marker = resource.createMarker(JavaBuilder.ProblemMarkerTag); >+ marker.setAttributes( >+ new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.CHAR_START, IMarker.CHAR_END}, >+ new Object[] {message, new Integer(IMarker.SEVERITY_ERROR), new Integer(0), new Integer(1)}); >+ } catch (CoreException e) { >+ throw internalException(e); >+ } >+} >+ >+protected String extractTypeNameFrom(String sourceLocation) { >+ for (int j = 0, k = sourceFolders.length; j < k; j++) { >+ String folderLocation = sourceFolders[j].getLocation().addTrailingSeparator().toString(); >+ if (sourceLocation.startsWith(folderLocation)) >+ return sourceLocation.substring(folderLocation.length(), sourceLocation.length() - 5); // length of ".java" >+ } >+ return sourceLocation; // should not reach here >+} >+ >+protected void finishedWith(String sourceLocation, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) throws CoreException { >+ if (duplicateTypeNames == null) { >+ newState.record(sourceLocation, result.qualifiedReferences, result.simpleNameReferences, mainTypeName, definedTypeNames); >+ return; >+ } >+ >+ char[][][] qualifiedRefs = result.qualifiedReferences; >+ char[][] simpleRefs = result.simpleNameReferences; >+ // for each duplicate type p1.p2.A, add the type name A (package was already added) >+ next : for (int i = 0, dLength = duplicateTypeNames.size(); i < dLength; i++) { >+ char[][] compoundName = (char[][]) duplicateTypeNames.get(i); >+ char[] typeName = compoundName[compoundName.length - 1]; >+ int sLength = simpleRefs.length; >+ for (int j = 0; j < sLength; j++) >+ if (CharOperation.equals(simpleRefs[j], typeName)) >+ continue next; >+ System.arraycopy(simpleRefs, 0, simpleRefs = new char[sLength + 1][], 0, sLength); >+ simpleRefs[sLength] = typeName; >+ } >+ newState.record(sourceLocation, qualifiedRefs, simpleRefs, mainTypeName, definedTypeNames); >+} >+ >+protected IContainer getOutputFolder(IPath packagePath) throws CoreException { >+ IFolder folder = outputFolder.getFolder(packagePath); >+ if (!folder.exists()) { >+ getOutputFolder(packagePath.removeLastSegments(1)); >+ folder.create(true, true, null); >+ folder.setDerived(true); >+ } >+ return folder; >+} >+ >+protected RuntimeException internalException(CoreException t) { >+ ImageBuilderInternalException imageBuilderException = new ImageBuilderInternalException(t); >+ if (inCompiler) >+ return new AbortCompilation(true, imageBuilderException); >+ return imageBuilderException; >+} >+ >+protected Compiler newCompiler() { >+ // called once when the builder is initialized... can override if needed >+ return new Compiler( >+ nameEnvironment, >+ DefaultErrorHandlingPolicies.proceedWithAllProblems(), >+ JavaCore.getOptions(), >+ this, >+ ProblemFactory.getProblemFactory(Locale.getDefault())); >+} >+ >+protected IResource resourceForLocation(String sourceLocation) { >+ return javaBuilder.workspaceRoot.getFileForLocation(new Path(sourceLocation)); >+} >+ >+/** >+ * Creates a marker from each problem and adds it to the resource. >+ * The marker is as follows: >+ * - its type is T_PROBLEM >+ * - its plugin ID is the JavaBuilder's plugin ID >+ * - its message is the problem's message >+ * - its priority reflects the severity of the problem >+ * - its range is the problem's range >+ * - it has an extra attribute "ID" which holds the problem's id >+ */ >+protected void storeProblemsFor(IResource resource, IProblem[] problems) throws CoreException { >+ if (resource == null || problems == null || problems.length == 0) return; >+ >+ String missingClassFile = null; >+ for (int i = 0, length = problems.length; i < length; i++) { >+ IProblem problem = problems[i]; >+ int id = problem.getID(); >+ switch (id) { >+ case IProblem.IsClassPathCorrect : >+ JavaBuilder.removeProblemsFor(javaBuilder.currentProject); // make this the only problem for this project >+ String[] args = problem.getArguments(); >+ missingClassFile = args[0]; >+ break; >+ case IProblem.SuperclassMustBeAClass : >+ case IProblem.SuperInterfaceMustBeAnInterface : >+ case IProblem.HierarchyCircularitySelfReference : >+ case IProblem.HierarchyCircularity : >+ case IProblem.HierarchyHasProblems : >+ case IProblem.SuperclassNotFound : >+ case IProblem.SuperclassNotVisible : >+ case IProblem.SuperclassAmbiguous : >+ case IProblem.SuperclassInternalNameProvided : >+ case IProblem.SuperclassInheritedNameHidesEnclosingName : >+ case IProblem.InterfaceNotFound : >+ case IProblem.InterfaceNotVisible : >+ case IProblem.InterfaceAmbiguous : >+ case IProblem.InterfaceInternalNameProvided : >+ case IProblem.InterfaceInheritedNameHidesEnclosingName : >+ // ensure that this file is always retrieved from source for the rest of the build >+ String fileLocation = resource.getLocation().toString(); >+ if (!problemTypeLocations.contains(fileLocation)) >+ problemTypeLocations.add(fileLocation); >+ } >+ >+ IMarker marker = resource.createMarker(JavaBuilder.ProblemMarkerTag); >+ marker.setAttributes( >+ new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.ID, IMarker.CHAR_START, IMarker.CHAR_END, IMarker.LINE_NUMBER, IJavaModelMarker.ARGUMENTS}, >+ new Object[] { >+ problem.getMessage(), >+ new Integer(problem.isError() ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING), >+ new Integer(id), >+ new Integer(problem.getSourceStart()), >+ new Integer(problem.getSourceEnd() + 1), >+ new Integer(problem.getSourceLineNumber()), >+ Util.getProblemArgumentsForMarker(problem.getArguments()) >+ }); >+ >+ // compute a user-friendly location >+ IJavaElement element = JavaCore.create(resource); >+ if (element instanceof org.eclipse.jdt.core.ICompilationUnit) { // try to find a finer grain element >+ org.eclipse.jdt.core.ICompilationUnit unit = (org.eclipse.jdt.core.ICompilationUnit) element; >+ IJavaElement fragment = unit.getElementAt(problem.getSourceStart()); >+ if (fragment != null) element = fragment; >+ } >+ String location = null; >+ if (element instanceof JavaElement) >+ location = ((JavaElement) element).readableName(); >+ if (location != null) >+ marker.setAttribute(IMarker.LOCATION, location); >+ if (missingClassFile != null) >+ throw new MissingClassFileException(missingClassFile); >+ } >+} >+ >+protected void updateProblemsFor(String sourceLocation, CompilationResult result) throws CoreException { >+ IProblem[] problems = result.getProblems(); >+ if (problems == null || problems.length == 0) return; >+ >+ notifier.updateProblemCounts(problems); >+ storeProblemsFor(resourceForLocation(sourceLocation), problems); >+} >+ >+protected char[] writeClassFile(ClassFile classFile, boolean isSecondaryType) throws CoreException { >+ // Before writing out the class file, compare it to the previous file >+ // If structural changes occured then add dependent source files >+ String fileName = new String(classFile.fileName()); // the qualified type name "p1/p2/A" >+ IPath filePath = new Path(fileName); >+ IContainer container = outputFolder; >+ if (filePath.segmentCount() > 1) { >+ container = getOutputFolder(filePath.removeLastSegments(1)); >+ filePath = new Path(filePath.lastSegment()); >+ } >+ >+ IFile file = container.getFile(filePath.addFileExtension(JavaBuilder.CLASS_EXTENSION)); >+ byte[] bytes = classFile.getBytes(); >+ boolean exists= file.exists(); >+ if (writeClassFileCheck(file, fileName, bytes, isSecondaryType, exists)) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("Writing class file " + file.getName());//$NON-NLS-1$ >+ if (!exists) { >+ file.create(new ByteArrayInputStream(bytes), IResource.FORCE, null); >+ } else { >+ file.setContents(new ByteArrayInputStream(bytes), true, false, null); >+ } >+ file.setDerived(true); >+ } else if (JavaBuilder.DEBUG) { >+ System.out.println("Skipped over unchanged class file " + file.getName());//$NON-NLS-1$ >+ } >+ // answer the name of the class file as in Y or Y$M >+ return filePath.lastSegment().toCharArray(); >+} >+ >+protected boolean writeClassFileCheck(IFile file, String fileName, byte[] bytes, boolean isSecondaryType, boolean exists) throws CoreException { >+ // In Incremental mode, compare the bytes against the previous file for structural changes >+ return true; >+} > } >Index: model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java >=================================================================== >RCS file: /home/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java,v >retrieving revision 1.25 >diff -u -r1.25 IncrementalImageBuilder.java >--- model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java 10 Jun 2002 18:44:16 -0000 1.25 >+++ model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java 15 Jul 2002 23:45:26 -0000 >@@ -1,569 +1,569 @@ >-/******************************************************************************* >- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Common Public License v0.5 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/cpl-v05.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 org.eclipse.jdt.core.compiler.IProblem; >-import org.eclipse.jdt.internal.compiler.*; >-import org.eclipse.jdt.internal.compiler.classfmt.*; >-import org.eclipse.jdt.internal.compiler.util.CharOperation; >-import org.eclipse.jdt.internal.core.Util; >- >-import java.util.*; >- >-/** >- * The incremental image builder >- */ >-public class IncrementalImageBuilder extends AbstractImageBuilder { >- >-protected ArrayList locations; >-protected ArrayList previousLocations; >-protected ArrayList typeNames; >-protected ArrayList qualifiedStrings; >-protected ArrayList simpleStrings; >-protected ArrayList secondaryTypesToRemove; >- >-public static int MaxCompileLoop = 5; // perform a full build if it takes more than ? incremental compile loops >- >-protected IncrementalImageBuilder(JavaBuilder javaBuilder) { >- super(javaBuilder); >- this.nameEnvironment.tagAsIncrementalBuild(); >- this.newState.copyFrom(javaBuilder.lastState); >- >- this.locations = new ArrayList(33); >- this.previousLocations = null; >- this.typeNames = new ArrayList(33); >- this.qualifiedStrings = new ArrayList(33); >- this.simpleStrings = new ArrayList(33); >-} >- >-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 >- >- if (JavaBuilder.DEBUG) >- System.out.println("INCREMENTAL build"); //$NON-NLS-1$ >- >- try { >- resetCollections(); >- >- notifier.subTask(Util.bind("build.analyzingDeltas")); //$NON-NLS-1$ >- IResourceDelta sourceDelta = (IResourceDelta) deltas.get(javaBuilder.currentProject); >- if (sourceDelta != null) >- if (!findSourceFiles(sourceDelta)) return false; >- notifier.updateProgressDelta(0.10f); >- >- Object[] keyTable = deltas.keyTable; >- Object[] valueTable = deltas.valueTable; >- for (int i = 0, l = keyTable.length; i < l; i++) { >- IResourceDelta delta = (IResourceDelta) valueTable[i]; >- if (delta != null) { >- IResource[] binaryResources = (IResource[]) javaBuilder.binaryResources.get(keyTable[i]); >- if (binaryResources != null) >- if (!findAffectedSourceFiles(delta, binaryResources)) return false; >- } >- } >- notifier.updateProgressDelta(0.10f); >- >- notifier.subTask(Util.bind("build.analyzingSources")); //$NON-NLS-1$ >- addAffectedSourceFiles(); >- notifier.updateProgressDelta(0.05f); >- >- int compileLoop = 0; >- float increment = 0.40f; >- while (locations.size() > 0) { // added to in acceptResult >- if (++compileLoop > MaxCompileLoop) { >- if (JavaBuilder.DEBUG) >- System.out.println("ABORTING incremental build... exceeded loop count"); //$NON-NLS-1$ >- return false; >- } >- notifier.checkCancel(); >- >- String[] allSourceFiles = new String[locations.size()]; >- locations.toArray(allSourceFiles); >- String[] initialTypeStrings = new String[typeNames.size()]; >- typeNames.toArray(initialTypeStrings); >- resetCollections(); >- >- workQueue.addAll(allSourceFiles); >- notifier.setProgressPerCompilationUnit(increment / allSourceFiles.length); >- increment = increment / 2; >- compile(allSourceFiles, initialTypeStrings); >- removeSecondaryTypes(); >- addAffectedSourceFiles(); >- } >- } catch (AbortIncrementalBuildException e) { >- // abort the incremental build and let the batch builder handle the problem >- if (JavaBuilder.DEBUG) >- System.out.println("ABORTING incremental build... cannot find " + e.qualifiedTypeName + //$NON-NLS-1$ >- ". Could have been renamed inside its existing source file."); //$NON-NLS-1$ >- return false; >- } catch (CoreException e) { >- throw internalException(e); >- } finally { >- cleanUp(); >- } >- return true; >-} >- >-protected void addAffectedSourceFiles() { >- 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; >- >- Object[] keyTable = newState.references.keyTable; >- Object[] valueTable = newState.references.valueTable; >- next : for (int i = 0, l = keyTable.length; i < l; i++) { >- String sourceLocation = (String) keyTable[i]; >- if (sourceLocation != null && !locations.contains(sourceLocation)) { >- if (compiledAllAtOnce && previousLocations != null && previousLocations.contains(sourceLocation)) >- continue next; // can skip previously compiled locations since already saw hierarchy related problems >- >- ReferenceCollection refs = (ReferenceCollection) valueTable[i]; >- if (refs.includes(qualifiedNames, simpleNames)) { >- // check that the file still exists... the file or its package may have been deleted >- IResource affectedFile = resourceForLocation(sourceLocation); >- if (affectedFile != null && affectedFile.exists()) { >- if (JavaBuilder.DEBUG) >- System.out.println(" adding affected source file " + sourceLocation); //$NON-NLS-1$ >- locations.add(sourceLocation); >- typeNames.add(extractTypeNameFrom(sourceLocation)); >- } >- } >- } >- } >-} >- >-protected void addDependentsOf(IPath path, boolean hasStructuralChanges) { >- if (hasStructuralChanges) >- newState.tagAsStructurallyChanged(); >- // the qualifiedStrings are of the form 'p1/p1' & the simpleStrings are just 'X' >- path = path.setDevice(null); >- String packageName = path.uptoSegment(path.segmentCount() - 1).toString(); >- if (!qualifiedStrings.contains(packageName)) >- qualifiedStrings.add(packageName); >- String typeName = path.lastSegment(); >- int memberIndex = typeName.indexOf('$'); >- if (memberIndex > 0) >- typeName = typeName.substring(0, memberIndex); >- if (!simpleStrings.contains(typeName)) { >- if (JavaBuilder.DEBUG) >- System.out.println(" adding dependents of " //$NON-NLS-1$ >- + typeName + " in " + packageName); //$NON-NLS-1$ >- simpleStrings.add(typeName); >- } >-} >- >-protected void cleanUp() { >- super.cleanUp(); >- >- this.locations = null; >- this.previousLocations = null; >- this.typeNames = null; >- this.qualifiedStrings = null; >- this.simpleStrings = null; >-} >- >-protected boolean findAffectedSourceFiles(IResourceDelta delta, IResource[] binaryResources) { >- for (int j = 0, k = binaryResources.length; j < k; j++) { >- IResource binaryResource = binaryResources[j]; >- // either a .class file folder or a zip/jar file >- if (binaryResource != null) { // skip unchanged output folder >- IResourceDelta binaryDelta = delta.findMember(binaryResource.getProjectRelativePath()); >- if (binaryDelta != null) { >- if (binaryResource instanceof IFile) { >- if (JavaBuilder.DEBUG) >- System.out.println("ABORTING incremental build... found delta to jar/zip file"); //$NON-NLS-1$ >- return false; // do full build since jar file was added/removed/changed >- } >- if (binaryDelta.getKind() == IResourceDelta.ADDED || binaryDelta.getKind() == IResourceDelta.REMOVED) { >- if (JavaBuilder.DEBUG) >- System.out.println("ABORTING incremental build... found added/removed binary folder"); //$NON-NLS-1$ >- return false; // added/removed binary folder should not make it here, but handle anyways >- } >- int segmentCount = binaryResource.getLocation().segmentCount(); >- IResourceDelta[] children = binaryDelta.getAffectedChildren(); // .class files from class folder >- for (int i = 0, length = children.length; i < length; ++i) >- findAffectedSourceFiles(children[i], segmentCount); >- notifier.checkCancel(); >- } >- } >- } >- return true; >-} >- >-protected void findAffectedSourceFiles(IResourceDelta binaryDelta, int segmentCount) { >- // 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(); >- IPath location = resource.getLocation(); >- switch(resource.getType()) { >- case IResource.PROJECT : >- case IResource.FOLDER : >- switch (binaryDelta.getKind()) { >- case IResourceDelta.ADDED : >- case IResourceDelta.REMOVED : >- IPath packagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null); >- 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 (!newState.isKnownPackage(packageName)) { >- if (JavaBuilder.DEBUG) >- System.out.println("Add dependents of added package " + packageName); //$NON-NLS-1$ >- addDependentsOf(packagePath, false); >- return; >- } >- if (JavaBuilder.DEBUG) >- System.out.println("Skipped dependents of added package " + packageName); //$NON-NLS-1$ >- } else { >- // see if the package still exists on the classpath >- if (!nameEnvironment.isPackage(packageName)) { >- if (JavaBuilder.DEBUG) >- System.out.println("Add dependents of removed package " + packageName); //$NON-NLS-1$ >- addDependentsOf(packagePath, false); >- return; >- } >- if (JavaBuilder.DEBUG) >- System.out.println("Skipped dependents of removed package " + packageName); //$NON-NLS-1$ >- } >- // fall thru & traverse the sub-packages and .class files >- case IResourceDelta.CHANGED : >- IResourceDelta[] children = binaryDelta.getAffectedChildren(); >- for (int i = 0, length = children.length; i < length; i++) >- findAffectedSourceFiles(children[i], segmentCount); >- } >- return; >- case IResource.FILE : >- if (JavaBuilder.CLASS_EXTENSION.equalsIgnoreCase(location.getFileExtension())) { >- IPath typePath = location.removeFirstSegments(segmentCount).removeFileExtension().makeRelative().setDevice(null); >- switch (binaryDelta.getKind()) { >- case IResourceDelta.ADDED : >- case IResourceDelta.REMOVED : >- if (JavaBuilder.DEBUG) >- System.out.println("Add dependents of added/removed class file " + typePath); //$NON-NLS-1$ >- addDependentsOf(typePath, false); >- return; >- case IResourceDelta.CHANGED : >- if ((binaryDelta.getFlags() & IResourceDelta.CONTENT) == 0) >- return; // skip it since it really isn't changed >- if (JavaBuilder.DEBUG) >- System.out.println("Add dependents of changed class file " + typePath); //$NON-NLS-1$ >- addDependentsOf(typePath, false); >- } >- return; >- } >- } >-} >- >-protected boolean findSourceFiles(IResourceDelta delta) throws CoreException { >- for (int i = 0, length = sourceFolders.length; i < length; i++) { >- IResourceDelta sourceDelta = delta.findMember(sourceFolders[i].getProjectRelativePath()); >- if (sourceDelta != null) { >- if (sourceDelta.getKind() == IResourceDelta.REMOVED) { >- if (JavaBuilder.DEBUG) >- System.out.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 = sourceFolders[i].getLocation().segmentCount(); >- IResourceDelta[] children = sourceDelta.getAffectedChildren(); >- for (int c = 0, clength = children.length; c < clength; c++) >- findSourceFiles(children[c], segmentCount); >- notifier.checkCancel(); >- } >- } >- return true; >-} >- >-protected void findSourceFiles(IResourceDelta sourceDelta, int segmentCount) throws 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(); >- IPath location = resource.getLocation(); >- switch(resource.getType()) { >- case IResource.PROJECT : >- case IResource.FOLDER : >- switch (sourceDelta.getKind()) { >- case IResourceDelta.ADDED : >- IPath addedPackagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null); >- getOutputFolder(addedPackagePath); // ensure package exists in the output folder >- // add dependents even when the package thinks it exists to be on the safe side >- if (JavaBuilder.DEBUG) >- System.out.println("Add dependents of added package " + addedPackagePath); //$NON-NLS-1$ >- addDependentsOf(addedPackagePath, true); >- // fall thru & collect all the source files >- case IResourceDelta.CHANGED : >- IResourceDelta[] children = sourceDelta.getAffectedChildren(); >- for (int i = 0, length = children.length; i < length; i++) >- findSourceFiles(children[i], segmentCount); >- return; >- case IResourceDelta.REMOVED : >- IPath removedPackagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null); >- for (int i = 0, length = sourceFolders.length; i < length; i++) { >- if (sourceFolders[i].findMember(removedPackagePath) != null) { >- // only a package fragment was removed, same as removing multiple source files >- getOutputFolder(removedPackagePath); // ensure package exists in the output folder >- IResourceDelta[] removedChildren = sourceDelta.getAffectedChildren(); >- for (int j = 0, rlength = removedChildren.length; j < rlength; j++) >- findSourceFiles(removedChildren[j], segmentCount); >- return; >- } >- } >- IFolder removedPackageFolder = outputFolder.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 >- if (JavaBuilder.DEBUG) >- System.out.println("Add dependents of removed package " + removedPackagePath); //$NON-NLS-1$ >- addDependentsOf(removedPackagePath, true); >- newState.removePackage(sourceDelta); >- } >- return; >- case IResource.FILE : >- String extension = location.getFileExtension(); >- if (JavaBuilder.JAVA_EXTENSION.equalsIgnoreCase(extension)) { >- IPath typePath = location.removeFirstSegments(segmentCount).removeFileExtension().makeRelative().setDevice(null); >- String sourceLocation = location.toString(); >- switch (sourceDelta.getKind()) { >- case IResourceDelta.ADDED : >- if (JavaBuilder.DEBUG) >- System.out.println("Compile this added source file " + sourceLocation); //$NON-NLS-1$ >- locations.add(sourceLocation); >- String typeName = typePath.toString(); >- typeNames.add(typeName); >- if (!newState.isDuplicateLocation(typeName, sourceLocation)) { // adding dependents results in 2 duplicate errors >- if (JavaBuilder.DEBUG) >- System.out.println("Add dependents of added source file " + typeName); //$NON-NLS-1$ >- addDependentsOf(typePath, true); >- } >- return; >- case IResourceDelta.REMOVED : >- char[][] definedTypeNames = newState.getDefinedTypeNamesFor(sourceLocation); >- if (definedTypeNames == null) { // defined a single type matching typePath >- removeClassFile(typePath); >- } else { >- if (JavaBuilder.DEBUG) >- System.out.println("Add dependents of removed source file " + typePath.toString()); //$NON-NLS-1$ >- addDependentsOf(typePath, true); // 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, length = definedTypeNames.length; i < length; i++) >- removeClassFile(packagePath.append(new String(definedTypeNames[i]))); >- } >- } >- newState.remove(sourceLocation); >- return; >- case IResourceDelta.CHANGED : >- if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0) >- return; // skip it since it really isn't changed >- if (JavaBuilder.DEBUG) >- System.out.println("Compile this changed source file " + sourceLocation); //$NON-NLS-1$ >- locations.add(sourceLocation); >- typeNames.add(typePath.toString()); >- } >- return; >- } else if (JavaBuilder.CLASS_EXTENSION.equalsIgnoreCase(extension)) { >- return; // skip class files >- } else if (hasSeparateOutputFolder) { >- if (javaBuilder.filterResource(resource)) return; >- >- // copy all other resource deltas to the output folder >- IPath resourcePath = location.removeFirstSegments(segmentCount).makeRelative(); >- IResource outputFile = outputFolder.getFile(resourcePath); >- switch (sourceDelta.getKind()) { >- case IResourceDelta.ADDED : >- if (outputFile.exists()) { >- if (JavaBuilder.DEBUG) >- System.out.println("Deleting existing file " + resourcePath); //$NON-NLS-1$ >- outputFile.delete(IResource.FORCE, null); >- } >- if (JavaBuilder.DEBUG) >- System.out.println("Copying added file " + resourcePath); //$NON-NLS-1$ >- getOutputFolder(resourcePath.removeLastSegments(1)); // ensure package exists in the output folder >- resource.copy(outputFile.getFullPath(), IResource.FORCE, null); >- outputFile.setDerived(true); >- return; >- case IResourceDelta.REMOVED : >- if (outputFile.exists()) { >- if (JavaBuilder.DEBUG) >- System.out.println("Deleting removed file " + resourcePath); //$NON-NLS-1$ >- outputFile.delete(IResource.FORCE, null); >- } >- return; >- case IResourceDelta.CHANGED : >- if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0) >- return; // skip it since it really isn't changed >- if (outputFile.exists()) { >- if (JavaBuilder.DEBUG) >- System.out.println("Deleting existing file " + resourcePath); //$NON-NLS-1$ >- outputFile.delete(IResource.FORCE, null); >- } >- if (JavaBuilder.DEBUG) >- System.out.println("Copying changed file " + resourcePath); //$NON-NLS-1$ >- getOutputFolder(resourcePath.removeLastSegments(1)); // ensure package exists in the output folder >- resource.copy(outputFile.getFullPath(), IResource.FORCE, null); >- outputFile.setDerived(true); >- } >- return; >- } >- } >-} >- >-protected void finishedWith(String sourceLocation, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) throws CoreException { >- char[][] previousTypeNames = newState.getDefinedTypeNamesFor(sourceLocation); >- if (previousTypeNames == null) >- previousTypeNames = new char[][] {mainTypeName}; >- IPath packagePath = null; >- next : for (int i = 0, x = previousTypeNames.length; i < x; i++) { >- char[] previous = previousTypeNames[i]; >- for (int j = 0, y = definedTypeNames.size(); j < y; j++) >- if (CharOperation.equals(previous, (char[]) definedTypeNames.get(j))) >- continue next; >- >- if (packagePath == null) >- packagePath = new Path(extractTypeNameFrom(sourceLocation)).removeLastSegments(1); >- if (secondaryTypesToRemove == null) >- this.secondaryTypesToRemove = new ArrayList(); >- secondaryTypesToRemove.add(packagePath.append(new String(previous))); >- } >- super.finishedWith(sourceLocation, result, mainTypeName, definedTypeNames, duplicateTypeNames); >-} >- >-protected void removeClassFile(IPath typePath) throws CoreException { >- if (typePath.lastSegment().indexOf('$') == -1) { // is not a nested type >- newState.removeTypeLocation(typePath.toString()); >- // add dependents even when the type thinks it does not exist to be on the safe side >- if (JavaBuilder.DEBUG) >- System.out.println("Add dependents of removed type " + typePath); //$NON-NLS-1$ >- addDependentsOf(typePath, true); // when member types are removed, their enclosing type is structurally changed >- } >- IFile classFile = outputFolder.getFile(typePath.addFileExtension(JavaBuilder.CLASS_EXTENSION)); >- if (classFile.exists()) { >- if (JavaBuilder.DEBUG) >- System.out.println("Deleting class file of removed type " + typePath); //$NON-NLS-1$ >- classFile.delete(IResource.FORCE, null); >- } >-} >- >-protected void removeSecondaryTypes() throws CoreException { >- if (secondaryTypesToRemove != null) { // delayed deleting secondary types until the end of the compile loop >- for (int i = 0, length = secondaryTypesToRemove.size(); i < length; i++) >- removeClassFile((IPath) secondaryTypesToRemove.get(i)); >- this.secondaryTypesToRemove = null; >- if (previousLocations != null && previousLocations.size() > 1) >- this.previousLocations = null; // cannot optimize recompile case when a secondary type is deleted >- } >-} >- >-protected void resetCollections() { >- previousLocations = locations.isEmpty() ? null : (ArrayList) locations.clone(); >- >- locations.clear(); >- typeNames.clear(); >- qualifiedStrings.clear(); >- simpleStrings.clear(); >- workQueue.clear(); >-} >- >-protected void updateProblemsFor(String sourceLocation, CompilationResult result) throws CoreException { >- IResource resource = resourceForLocation(sourceLocation); >- IMarker[] markers = JavaBuilder.getProblemsFor(resource); >- IProblem[] problems = result.getProblems(); >- if (problems == null || problems.length == 0) >- if (markers.length == 0) return; >- >- notifier.updateProblemCounts(markers, problems); >- JavaBuilder.removeProblemsFor(resource); >- storeProblemsFor(resource, problems); >-} >- >-protected boolean writeClassFileCheck(IFile file, String fileName, byte[] newBytes, boolean isSecondaryType) throws CoreException { >- // Before writing out the class file, compare it to the previous file >- // If structural changes occured then add dependent source files >- if (file.exists()) { >- 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 >- } >- ClassFileReader reader = new ClassFileReader(oldBytes, file.getLocation().toString().toCharArray()); >- // ignore local types since they're only visible inside a single method >- if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) { >- if (JavaBuilder.DEBUG) >- System.out.println("Type has structural changes " + fileName); //$NON-NLS-1$ >- addDependentsOf(new Path(fileName), true); >- } >- } catch (ClassFormatException e) { >- addDependentsOf(new Path(fileName), true); >- } >- >- file.delete(IResource.FORCE, null); >- } else if (isSecondaryType) { >- addDependentsOf(new Path(fileName), true); // new secondary type >- } >- return true; >-} >- >-public String toString() { >- return "incremental image builder for:\n\tnew state: " + newState; //$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, length = children.length; i < length; ++i) >- dump(children[i]); >-} >-*/ >+/******************************************************************************* >+ * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Common Public License v0.5 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/cpl-v05.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 org.eclipse.jdt.core.compiler.IProblem; >+import org.eclipse.jdt.internal.compiler.*; >+import org.eclipse.jdt.internal.compiler.classfmt.*; >+import org.eclipse.jdt.internal.compiler.util.CharOperation; >+import org.eclipse.jdt.internal.core.Util; >+ >+import java.util.*; >+ >+/** >+ * The incremental image builder >+ */ >+public class IncrementalImageBuilder extends AbstractImageBuilder { >+ >+protected ArrayList locations; >+protected ArrayList previousLocations; >+protected ArrayList typeNames; >+protected ArrayList qualifiedStrings; >+protected ArrayList simpleStrings; >+protected ArrayList secondaryTypesToRemove; >+ >+public static int MaxCompileLoop = 5; // perform a full build if it takes more than ? incremental compile loops >+ >+protected IncrementalImageBuilder(JavaBuilder javaBuilder) { >+ super(javaBuilder); >+ this.nameEnvironment.tagAsIncrementalBuild(); >+ this.newState.copyFrom(javaBuilder.lastState); >+ >+ this.locations = new ArrayList(33); >+ this.previousLocations = null; >+ this.typeNames = new ArrayList(33); >+ this.qualifiedStrings = new ArrayList(33); >+ this.simpleStrings = new ArrayList(33); >+} >+ >+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 >+ >+ if (JavaBuilder.DEBUG) >+ System.out.println("INCREMENTAL build"); //$NON-NLS-1$ >+ >+ try { >+ resetCollections(); >+ >+ notifier.subTask(Util.bind("build.analyzingDeltas")); //$NON-NLS-1$ >+ IResourceDelta sourceDelta = (IResourceDelta) deltas.get(javaBuilder.currentProject); >+ if (sourceDelta != null) >+ if (!findSourceFiles(sourceDelta)) return false; >+ notifier.updateProgressDelta(0.10f); >+ >+ Object[] keyTable = deltas.keyTable; >+ Object[] valueTable = deltas.valueTable; >+ for (int i = 0, l = keyTable.length; i < l; i++) { >+ IResourceDelta delta = (IResourceDelta) valueTable[i]; >+ if (delta != null) { >+ IResource[] binaryResources = (IResource[]) javaBuilder.binaryResources.get(keyTable[i]); >+ if (binaryResources != null) >+ if (!findAffectedSourceFiles(delta, binaryResources)) return false; >+ } >+ } >+ notifier.updateProgressDelta(0.10f); >+ >+ notifier.subTask(Util.bind("build.analyzingSources")); //$NON-NLS-1$ >+ addAffectedSourceFiles(); >+ notifier.updateProgressDelta(0.05f); >+ >+ int compileLoop = 0; >+ float increment = 0.40f; >+ while (locations.size() > 0) { // added to in acceptResult >+ if (++compileLoop > MaxCompileLoop) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("ABORTING incremental build... exceeded loop count"); //$NON-NLS-1$ >+ return false; >+ } >+ notifier.checkCancel(); >+ >+ String[] allSourceFiles = new String[locations.size()]; >+ locations.toArray(allSourceFiles); >+ String[] initialTypeStrings = new String[typeNames.size()]; >+ typeNames.toArray(initialTypeStrings); >+ resetCollections(); >+ >+ workQueue.addAll(allSourceFiles); >+ notifier.setProgressPerCompilationUnit(increment / allSourceFiles.length); >+ increment = increment / 2; >+ compile(allSourceFiles, initialTypeStrings); >+ removeSecondaryTypes(); >+ addAffectedSourceFiles(); >+ } >+ } catch (AbortIncrementalBuildException e) { >+ // abort the incremental build and let the batch builder handle the problem >+ if (JavaBuilder.DEBUG) >+ System.out.println("ABORTING incremental build... cannot find " + e.qualifiedTypeName + //$NON-NLS-1$ >+ ". Could have been renamed inside its existing source file."); //$NON-NLS-1$ >+ return false; >+ } catch (CoreException e) { >+ throw internalException(e); >+ } finally { >+ cleanUp(); >+ } >+ return true; >+} >+ >+protected void addAffectedSourceFiles() { >+ 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; >+ >+ Object[] keyTable = newState.references.keyTable; >+ Object[] valueTable = newState.references.valueTable; >+ next : for (int i = 0, l = keyTable.length; i < l; i++) { >+ String sourceLocation = (String) keyTable[i]; >+ if (sourceLocation != null && !locations.contains(sourceLocation)) { >+ if (compiledAllAtOnce && previousLocations != null && previousLocations.contains(sourceLocation)) >+ continue next; // can skip previously compiled locations since already saw hierarchy related problems >+ >+ ReferenceCollection refs = (ReferenceCollection) valueTable[i]; >+ if (refs.includes(qualifiedNames, simpleNames)) { >+ // check that the file still exists... the file or its package may have been deleted >+ IResource affectedFile = resourceForLocation(sourceLocation); >+ if (affectedFile != null && affectedFile.exists()) { >+ if (JavaBuilder.DEBUG) >+ System.out.println(" adding affected source file " + sourceLocation); //$NON-NLS-1$ >+ locations.add(sourceLocation); >+ typeNames.add(extractTypeNameFrom(sourceLocation)); >+ } >+ } >+ } >+ } >+} >+ >+protected void addDependentsOf(IPath path, boolean hasStructuralChanges) { >+ if (hasStructuralChanges) >+ newState.tagAsStructurallyChanged(); >+ // the qualifiedStrings are of the form 'p1/p1' & the simpleStrings are just 'X' >+ path = path.setDevice(null); >+ String packageName = path.uptoSegment(path.segmentCount() - 1).toString(); >+ if (!qualifiedStrings.contains(packageName)) >+ qualifiedStrings.add(packageName); >+ String typeName = path.lastSegment(); >+ int memberIndex = typeName.indexOf('$'); >+ if (memberIndex > 0) >+ typeName = typeName.substring(0, memberIndex); >+ if (!simpleStrings.contains(typeName)) { >+ if (JavaBuilder.DEBUG) >+ System.out.println(" adding dependents of " //$NON-NLS-1$ >+ + typeName + " in " + packageName); //$NON-NLS-1$ >+ simpleStrings.add(typeName); >+ } >+} >+ >+protected void cleanUp() { >+ super.cleanUp(); >+ >+ this.locations = null; >+ this.previousLocations = null; >+ this.typeNames = null; >+ this.qualifiedStrings = null; >+ this.simpleStrings = null; >+} >+ >+protected boolean findAffectedSourceFiles(IResourceDelta delta, IResource[] binaryResources) { >+ for (int j = 0, k = binaryResources.length; j < k; j++) { >+ IResource binaryResource = binaryResources[j]; >+ // either a .class file folder or a zip/jar file >+ if (binaryResource != null) { // skip unchanged output folder >+ IResourceDelta binaryDelta = delta.findMember(binaryResource.getProjectRelativePath()); >+ if (binaryDelta != null) { >+ if (binaryResource instanceof IFile) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("ABORTING incremental build... found delta to jar/zip file"); //$NON-NLS-1$ >+ return false; // do full build since jar file was added/removed/changed >+ } >+ if (binaryDelta.getKind() == IResourceDelta.ADDED || binaryDelta.getKind() == IResourceDelta.REMOVED) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("ABORTING incremental build... found added/removed binary folder"); //$NON-NLS-1$ >+ return false; // added/removed binary folder should not make it here, but handle anyways >+ } >+ int segmentCount = binaryResource.getLocation().segmentCount(); >+ IResourceDelta[] children = binaryDelta.getAffectedChildren(); // .class files from class folder >+ for (int i = 0, length = children.length; i < length; ++i) >+ findAffectedSourceFiles(children[i], segmentCount); >+ notifier.checkCancel(); >+ } >+ } >+ } >+ return true; >+} >+ >+protected void findAffectedSourceFiles(IResourceDelta binaryDelta, int segmentCount) { >+ // 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(); >+ IPath location = resource.getLocation(); >+ switch(resource.getType()) { >+ case IResource.PROJECT : >+ case IResource.FOLDER : >+ switch (binaryDelta.getKind()) { >+ case IResourceDelta.ADDED : >+ case IResourceDelta.REMOVED : >+ IPath packagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null); >+ 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 (!newState.isKnownPackage(packageName)) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("Add dependents of added package " + packageName); //$NON-NLS-1$ >+ addDependentsOf(packagePath, false); >+ return; >+ } >+ if (JavaBuilder.DEBUG) >+ System.out.println("Skipped dependents of added package " + packageName); //$NON-NLS-1$ >+ } else { >+ // see if the package still exists on the classpath >+ if (!nameEnvironment.isPackage(packageName)) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("Add dependents of removed package " + packageName); //$NON-NLS-1$ >+ addDependentsOf(packagePath, false); >+ return; >+ } >+ if (JavaBuilder.DEBUG) >+ System.out.println("Skipped dependents of removed package " + packageName); //$NON-NLS-1$ >+ } >+ // fall thru & traverse the sub-packages and .class files >+ case IResourceDelta.CHANGED : >+ IResourceDelta[] children = binaryDelta.getAffectedChildren(); >+ for (int i = 0, length = children.length; i < length; i++) >+ findAffectedSourceFiles(children[i], segmentCount); >+ } >+ return; >+ case IResource.FILE : >+ if (JavaBuilder.CLASS_EXTENSION.equalsIgnoreCase(location.getFileExtension())) { >+ IPath typePath = location.removeFirstSegments(segmentCount).removeFileExtension().makeRelative().setDevice(null); >+ switch (binaryDelta.getKind()) { >+ case IResourceDelta.ADDED : >+ case IResourceDelta.REMOVED : >+ if (JavaBuilder.DEBUG) >+ System.out.println("Add dependents of added/removed class file " + typePath); //$NON-NLS-1$ >+ addDependentsOf(typePath, false); >+ return; >+ case IResourceDelta.CHANGED : >+ if ((binaryDelta.getFlags() & IResourceDelta.CONTENT) == 0) >+ return; // skip it since it really isn't changed >+ if (JavaBuilder.DEBUG) >+ System.out.println("Add dependents of changed class file " + typePath); //$NON-NLS-1$ >+ addDependentsOf(typePath, false); >+ } >+ return; >+ } >+ } >+} >+ >+protected boolean findSourceFiles(IResourceDelta delta) throws CoreException { >+ for (int i = 0, length = sourceFolders.length; i < length; i++) { >+ IResourceDelta sourceDelta = delta.findMember(sourceFolders[i].getProjectRelativePath()); >+ if (sourceDelta != null) { >+ if (sourceDelta.getKind() == IResourceDelta.REMOVED) { >+ if (JavaBuilder.DEBUG) >+ System.out.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 = sourceFolders[i].getLocation().segmentCount(); >+ IResourceDelta[] children = sourceDelta.getAffectedChildren(); >+ for (int c = 0, clength = children.length; c < clength; c++) >+ findSourceFiles(children[c], segmentCount); >+ notifier.checkCancel(); >+ } >+ } >+ return true; >+} >+ >+protected void findSourceFiles(IResourceDelta sourceDelta, int segmentCount) throws 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(); >+ IPath location = resource.getLocation(); >+ switch(resource.getType()) { >+ case IResource.PROJECT : >+ case IResource.FOLDER : >+ switch (sourceDelta.getKind()) { >+ case IResourceDelta.ADDED : >+ IPath addedPackagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null); >+ getOutputFolder(addedPackagePath); // ensure package exists in the output folder >+ // add dependents even when the package thinks it exists to be on the safe side >+ if (JavaBuilder.DEBUG) >+ System.out.println("Add dependents of added package " + addedPackagePath); //$NON-NLS-1$ >+ addDependentsOf(addedPackagePath, true); >+ // fall thru & collect all the source files >+ case IResourceDelta.CHANGED : >+ IResourceDelta[] children = sourceDelta.getAffectedChildren(); >+ for (int i = 0, length = children.length; i < length; i++) >+ findSourceFiles(children[i], segmentCount); >+ return; >+ case IResourceDelta.REMOVED : >+ IPath removedPackagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null); >+ for (int i = 0, length = sourceFolders.length; i < length; i++) { >+ if (sourceFolders[i].findMember(removedPackagePath) != null) { >+ // only a package fragment was removed, same as removing multiple source files >+ getOutputFolder(removedPackagePath); // ensure package exists in the output folder >+ IResourceDelta[] removedChildren = sourceDelta.getAffectedChildren(); >+ for (int j = 0, rlength = removedChildren.length; j < rlength; j++) >+ findSourceFiles(removedChildren[j], segmentCount); >+ return; >+ } >+ } >+ IFolder removedPackageFolder = outputFolder.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 >+ if (JavaBuilder.DEBUG) >+ System.out.println("Add dependents of removed package " + removedPackagePath); //$NON-NLS-1$ >+ addDependentsOf(removedPackagePath, true); >+ newState.removePackage(sourceDelta); >+ } >+ return; >+ case IResource.FILE : >+ String extension = location.getFileExtension(); >+ if (JavaBuilder.JAVA_EXTENSION.equalsIgnoreCase(extension)) { >+ IPath typePath = location.removeFirstSegments(segmentCount).removeFileExtension().makeRelative().setDevice(null); >+ String sourceLocation = location.toString(); >+ switch (sourceDelta.getKind()) { >+ case IResourceDelta.ADDED : >+ if (JavaBuilder.DEBUG) >+ System.out.println("Compile this added source file " + sourceLocation); //$NON-NLS-1$ >+ locations.add(sourceLocation); >+ String typeName = typePath.toString(); >+ typeNames.add(typeName); >+ if (!newState.isDuplicateLocation(typeName, sourceLocation)) { // adding dependents results in 2 duplicate errors >+ if (JavaBuilder.DEBUG) >+ System.out.println("Add dependents of added source file " + typeName); //$NON-NLS-1$ >+ addDependentsOf(typePath, true); >+ } >+ return; >+ case IResourceDelta.REMOVED : >+ char[][] definedTypeNames = newState.getDefinedTypeNamesFor(sourceLocation); >+ if (definedTypeNames == null) { // defined a single type matching typePath >+ removeClassFile(typePath); >+ } else { >+ if (JavaBuilder.DEBUG) >+ System.out.println("Add dependents of removed source file " + typePath.toString()); //$NON-NLS-1$ >+ addDependentsOf(typePath, true); // 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, length = definedTypeNames.length; i < length; i++) >+ removeClassFile(packagePath.append(new String(definedTypeNames[i]))); >+ } >+ } >+ newState.remove(sourceLocation); >+ return; >+ case IResourceDelta.CHANGED : >+ if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0) >+ return; // skip it since it really isn't changed >+ if (JavaBuilder.DEBUG) >+ System.out.println("Compile this changed source file " + sourceLocation); //$NON-NLS-1$ >+ locations.add(sourceLocation); >+ typeNames.add(typePath.toString()); >+ } >+ return; >+ } else if (JavaBuilder.CLASS_EXTENSION.equalsIgnoreCase(extension)) { >+ return; // skip class files >+ } else if (hasSeparateOutputFolder) { >+ if (javaBuilder.filterResource(resource)) return; >+ >+ // copy all other resource deltas to the output folder >+ IPath resourcePath = location.removeFirstSegments(segmentCount).makeRelative(); >+ IResource outputFile = outputFolder.getFile(resourcePath); >+ switch (sourceDelta.getKind()) { >+ case IResourceDelta.ADDED : >+ if (outputFile.exists()) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("Deleting existing file " + resourcePath); //$NON-NLS-1$ >+ outputFile.delete(IResource.FORCE, null); >+ } >+ if (JavaBuilder.DEBUG) >+ System.out.println("Copying added file " + resourcePath); //$NON-NLS-1$ >+ getOutputFolder(resourcePath.removeLastSegments(1)); // ensure package exists in the output folder >+ resource.copy(outputFile.getFullPath(), IResource.FORCE, null); >+ outputFile.setDerived(true); >+ return; >+ case IResourceDelta.REMOVED : >+ if (outputFile.exists()) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("Deleting removed file " + resourcePath); //$NON-NLS-1$ >+ outputFile.delete(IResource.FORCE, null); >+ } >+ return; >+ case IResourceDelta.CHANGED : >+ if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0) >+ return; // skip it since it really isn't changed >+ if (outputFile.exists()) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("Deleting existing file " + resourcePath); //$NON-NLS-1$ >+ outputFile.delete(IResource.FORCE, null); >+ } >+ if (JavaBuilder.DEBUG) >+ System.out.println("Copying changed file " + resourcePath); //$NON-NLS-1$ >+ getOutputFolder(resourcePath.removeLastSegments(1)); // ensure package exists in the output folder >+ resource.copy(outputFile.getFullPath(), IResource.FORCE, null); >+ outputFile.setDerived(true); >+ } >+ return; >+ } >+ } >+} >+ >+protected void finishedWith(String sourceLocation, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) throws CoreException { >+ char[][] previousTypeNames = newState.getDefinedTypeNamesFor(sourceLocation); >+ if (previousTypeNames == null) >+ previousTypeNames = new char[][] {mainTypeName}; >+ IPath packagePath = null; >+ next : for (int i = 0, x = previousTypeNames.length; i < x; i++) { >+ char[] previous = previousTypeNames[i]; >+ for (int j = 0, y = definedTypeNames.size(); j < y; j++) >+ if (CharOperation.equals(previous, (char[]) definedTypeNames.get(j))) >+ continue next; >+ >+ if (packagePath == null) >+ packagePath = new Path(extractTypeNameFrom(sourceLocation)).removeLastSegments(1); >+ if (secondaryTypesToRemove == null) >+ this.secondaryTypesToRemove = new ArrayList(); >+ secondaryTypesToRemove.add(packagePath.append(new String(previous))); >+ } >+ super.finishedWith(sourceLocation, result, mainTypeName, definedTypeNames, duplicateTypeNames); >+} >+ >+protected void removeClassFile(IPath typePath) throws CoreException { >+ if (typePath.lastSegment().indexOf('$') == -1) { // is not a nested type >+ newState.removeTypeLocation(typePath.toString()); >+ // add dependents even when the type thinks it does not exist to be on the safe side >+ if (JavaBuilder.DEBUG) >+ System.out.println("Add dependents of removed type " + typePath); //$NON-NLS-1$ >+ addDependentsOf(typePath, true); // when member types are removed, their enclosing type is structurally changed >+ } >+ IFile classFile = outputFolder.getFile(typePath.addFileExtension(JavaBuilder.CLASS_EXTENSION)); >+ if (classFile.exists()) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("Deleting class file of removed type " + typePath); //$NON-NLS-1$ >+ classFile.delete(IResource.FORCE, null); >+ } >+} >+ >+protected void removeSecondaryTypes() throws CoreException { >+ if (secondaryTypesToRemove != null) { // delayed deleting secondary types until the end of the compile loop >+ for (int i = 0, length = secondaryTypesToRemove.size(); i < length; i++) >+ removeClassFile((IPath) secondaryTypesToRemove.get(i)); >+ this.secondaryTypesToRemove = null; >+ if (previousLocations != null && previousLocations.size() > 1) >+ this.previousLocations = null; // cannot optimize recompile case when a secondary type is deleted >+ } >+} >+ >+protected void resetCollections() { >+ previousLocations = locations.isEmpty() ? null : (ArrayList) locations.clone(); >+ >+ locations.clear(); >+ typeNames.clear(); >+ qualifiedStrings.clear(); >+ simpleStrings.clear(); >+ workQueue.clear(); >+} >+ >+protected void updateProblemsFor(String sourceLocation, CompilationResult result) throws CoreException { >+ IResource resource = resourceForLocation(sourceLocation); >+ IMarker[] markers = JavaBuilder.getProblemsFor(resource); >+ IProblem[] problems = result.getProblems(); >+ if (problems == null || problems.length == 0) >+ if (markers.length == 0) return; >+ >+ notifier.updateProblemCounts(markers, problems); >+ JavaBuilder.removeProblemsFor(resource); >+ storeProblemsFor(resource, problems); >+} >+ >+protected boolean writeClassFileCheck(IFile file, String fileName, byte[] newBytes, boolean isSecondaryType, boolean exists) throws CoreException { >+ // Before writing out the class file, compare it to the previous file >+ // If structural changes occured then add dependent source files >+ if (exists) { >+ 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 >+ } >+ ClassFileReader reader = new ClassFileReader(oldBytes, file.getLocation().toString().toCharArray()); >+ // ignore local types since they're only visible inside a single method >+ if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) { >+ if (JavaBuilder.DEBUG) >+ System.out.println("Type has structural changes " + fileName); //$NON-NLS-1$ >+ addDependentsOf(new Path(fileName), true); >+ } >+ } catch (ClassFormatException e) { >+ addDependentsOf(new Path(fileName), true); >+ } >+ >+// file.delete(IResource.FORCE, null); >+ } else if (isSecondaryType) { >+ addDependentsOf(new Path(fileName), true); // new secondary type >+ } >+ return true; >+} >+ >+public String toString() { >+ return "incremental image builder for:\n\tnew state: " + newState; //$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, length = children.length; i < length; ++i) >+ dump(children[i]); >+} >+*/ > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 21606
: 1699