1 11 package org.eclipse.jdt.internal.core.builder; 12 13 import org.eclipse.core.resources.*; 14 import org.eclipse.core.runtime.*; 15 16 import org.eclipse.jdt.core.*; 17 import org.eclipse.jdt.core.compiler.*; 18 import org.eclipse.jdt.internal.compiler.*; 19 import org.eclipse.jdt.internal.compiler.classfmt.*; 20 import org.eclipse.jdt.internal.compiler.problem.*; 21 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable; 22 import org.eclipse.jdt.internal.compiler.util.SuffixConstants; 23 import org.eclipse.jdt.internal.core.util.Messages; 24 import org.eclipse.jdt.internal.core.util.Util; 25 26 import java.io.*; 27 import java.net.URI ; 28 import java.util.*; 29 30 33 public class IncrementalImageBuilder extends AbstractImageBuilder { 34 35 protected ArrayList sourceFiles; 36 protected ArrayList previousSourceFiles; 37 protected StringSet qualifiedStrings; 38 protected StringSet simpleStrings; 39 protected SimpleLookupTable secondaryTypesToRemove; 40 protected boolean hasStructuralChanges; 41 protected int compileLoop; 42 protected boolean makeOutputFolderConsistent; 43 44 public static int MaxCompileLoop = 5; 46 protected IncrementalImageBuilder(JavaBuilder javaBuilder, State buildState) { 47 super(javaBuilder, true, buildState); 48 this.nameEnvironment.isIncrementalBuild = true; 49 this.makeOutputFolderConsistent = JavaCore.ENABLED.equals( 50 javaBuilder.javaProject.getOption(JavaCore.CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER, true)); 51 } 52 53 protected IncrementalImageBuilder(JavaBuilder javaBuilder) { 54 this(javaBuilder, null); 55 this.newState.copyFrom(javaBuilder.lastState); 56 } 57 58 protected IncrementalImageBuilder(BatchImageBuilder batchBuilder) { 59 this(batchBuilder.javaBuilder, batchBuilder.newState); 60 resetCollections(); 61 } 62 63 public boolean build(SimpleLookupTable deltas) { 64 74 if (JavaBuilder.DEBUG) 75 System.out.println("INCREMENTAL build"); 77 try { 78 resetCollections(); 79 80 notifier.subTask(Messages.build_analyzingDeltas); 81 if (javaBuilder.hasBuildpathErrors()) { 82 javaBuilder.currentProject.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); 87 addAllSourceFiles(sourceFiles); 88 notifier.updateProgressDelta(0.25f); 89 } else { 90 IResourceDelta sourceDelta = (IResourceDelta) deltas.get(javaBuilder.currentProject); 91 if (sourceDelta != null) 92 if (!findSourceFiles(sourceDelta)) return false; 93 notifier.updateProgressDelta(0.10f); 94 95 Object [] keyTable = deltas.keyTable; 96 Object [] valueTable = deltas.valueTable; 97 for (int i = 0, l = valueTable.length; i < l; i++) { 98 IResourceDelta delta = (IResourceDelta) valueTable[i]; 99 if (delta != null) { 100 IProject p = (IProject) keyTable[i]; 101 ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[]) javaBuilder.binaryLocationsPerProject.get(p); 102 if (classFoldersAndJars != null) 103 if (!findAffectedSourceFiles(delta, classFoldersAndJars, p)) return false; 104 } 105 } 106 notifier.updateProgressDelta(0.10f); 107 108 notifier.subTask(Messages.build_analyzingSources); 109 addAffectedSourceFiles(); 110 notifier.updateProgressDelta(0.05f); 111 } 112 113 this.compileLoop = 0; 114 float increment = 0.40f; 115 while (sourceFiles.size() > 0) { if (++this.compileLoop > MaxCompileLoop) { 117 if (JavaBuilder.DEBUG) 118 System.out.println("ABORTING incremental build... exceeded loop count"); return false; 120 } 121 notifier.checkCancel(); 122 123 SourceFile[] allSourceFiles = new SourceFile[sourceFiles.size()]; 124 sourceFiles.toArray(allSourceFiles); 125 resetCollections(); 126 127 workQueue.addAll(allSourceFiles); 128 notifier.setProgressPerCompilationUnit(increment / allSourceFiles.length); 129 increment = increment / 2; 130 compile(allSourceFiles); 131 removeSecondaryTypes(); 132 addAffectedSourceFiles(); 133 } 134 if (this.hasStructuralChanges && javaBuilder.javaProject.hasCycleMarker()) 135 javaBuilder.mustPropagateStructuralChanges(); 136 } catch (AbortIncrementalBuildException e) { 137 if (JavaBuilder.DEBUG) 139 System.out.println("ABORTING incremental build... problem with " + e.qualifiedTypeName + ". Likely renamed inside its existing source file."); return false; 142 } catch (CoreException e) { 143 throw internalException(e); 144 } finally { 145 cleanUp(); 146 } 147 return true; 148 } 149 150 protected void buildAfterBatchBuild() { 151 154 if (JavaBuilder.DEBUG) 155 System.out.println("INCREMENTAL build after batch build @ " + new Date(System.currentTimeMillis())); 157 try { 159 addAffectedSourceFiles(); 160 while (this.sourceFiles.size() > 0) { 161 notifier.checkCancel(); 162 SourceFile[] allSourceFiles = new SourceFile[this.sourceFiles.size()]; 163 this.sourceFiles.toArray(allSourceFiles); 164 resetCollections(); 165 notifier.setProgressPerCompilationUnit(0.08f / allSourceFiles.length); 166 this.workQueue.addAll(allSourceFiles); 167 compile(allSourceFiles); 168 removeSecondaryTypes(); 169 addAffectedSourceFiles(); 170 } 171 } catch (CoreException e) { 172 throw internalException(e); 173 } finally { 174 cleanUp(); 175 } 176 } 177 178 protected void addAffectedSourceFiles() { 179 if (qualifiedStrings.elementSize == 0 && simpleStrings.elementSize == 0) return; 180 181 addAffectedSourceFiles(qualifiedStrings, simpleStrings, null); 182 } 183 184 protected void addAffectedSourceFiles(StringSet qualifiedSet, StringSet simpleSet, StringSet affectedTypes) { 185 char[][][] internedQualifiedNames = ReferenceCollection.internQualifiedNames(qualifiedSet); 187 if (internedQualifiedNames.length < qualifiedSet.elementSize) 189 internedQualifiedNames = null; 190 char[][] internedSimpleNames = ReferenceCollection.internSimpleNames(simpleSet); 191 if (internedSimpleNames.length < simpleSet.elementSize) 193 internedSimpleNames = null; 194 195 Object [] keyTable = newState.references.keyTable; 196 Object [] valueTable = newState.references.valueTable; 197 next : for (int i = 0, l = valueTable.length; i < l; i++) { 198 String typeLocator = (String ) keyTable[i]; 199 if (typeLocator != null) { 200 if (affectedTypes != null && !affectedTypes.includes(typeLocator)) continue next; 201 ReferenceCollection refs = (ReferenceCollection) valueTable[i]; 202 if (refs.includes(internedQualifiedNames, internedSimpleNames)) { 203 IFile file = javaBuilder.currentProject.getFile(typeLocator); 204 SourceFile sourceFile = findSourceFile(file, true); 205 if (sourceFile == null) continue next; 206 if (sourceFiles.contains(sourceFile)) continue next; 207 if (compiledAllAtOnce && previousSourceFiles != null && previousSourceFiles.contains(sourceFile)) 208 continue next; 210 if (JavaBuilder.DEBUG) 211 System.out.println(" adding affected source file " + typeLocator); sourceFiles.add(sourceFile); 213 } 214 } 215 } 216 } 217 218 protected void addDependentsOf(IPath path, boolean isStructuralChange) { 219 if (isStructuralChange && !this.hasStructuralChanges) { 220 newState.tagAsStructurallyChanged(); 221 this.hasStructuralChanges = true; 222 } 223 path = path.setDevice(null); 225 String packageName = path.removeLastSegments(1).toString(); 226 qualifiedStrings.add(packageName); 227 String typeName = path.lastSegment(); 228 int memberIndex = typeName.indexOf('$'); 229 if (memberIndex > 0) 230 typeName = typeName.substring(0, memberIndex); 231 if (simpleStrings.add(typeName) && JavaBuilder.DEBUG) 232 System.out.println(" will look for dependents of " + typeName + " in " + packageName); } 235 236 protected boolean checkForClassFileChanges(IResourceDelta binaryDelta, ClasspathMultiDirectory md, int segmentCount) throws CoreException { 237 IResource resource = binaryDelta.getResource(); 238 boolean isExcluded = (md.exclusionPatterns != null || md.inclusionPatterns != null) 240 && Util.isExcluded(resource, md.inclusionPatterns, md.exclusionPatterns); 241 switch(resource.getType()) { 242 case IResource.FOLDER : 243 if (isExcluded && md.inclusionPatterns == null) 244 return true; 246 IResourceDelta[] children = binaryDelta.getAffectedChildren(); 247 for (int i = 0, l = children.length; i < l; i++) 248 if (!checkForClassFileChanges(children[i], md, segmentCount)) 249 return false; 250 return true; 251 case IResource.FILE : 252 if (!isExcluded && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(resource.getName())) { 253 IPath typePath = resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension(); 255 if (newState.isKnownType(typePath.toString())) { 256 if (JavaBuilder.DEBUG) 257 System.out.println("MUST DO FULL BUILD. Found change to class file " + typePath); return false; 259 } 260 return true; 261 } 262 } 263 return true; 264 } 265 266 protected void cleanUp() { 267 super.cleanUp(); 268 269 this.sourceFiles = null; 270 this.previousSourceFiles = null; 271 this.qualifiedStrings = null; 272 this.simpleStrings = null; 273 this.secondaryTypesToRemove = null; 274 this.hasStructuralChanges = false; 275 this.compileLoop = 0; 276 } 277 278 protected void compile(SourceFile[] units, SourceFile[] additionalUnits, boolean compilingFirstGroup) { 279 if (compilingFirstGroup && additionalUnits != null) { 280 ArrayList extras = null; 284 for (int i = 0, l = additionalUnits.length; i < l; i++) { 285 SourceFile unit = additionalUnits[i]; 286 if (unit != null && newState.getDefinedTypeNamesFor(unit.typeLocator()) != null) { 287 if (JavaBuilder.DEBUG) 288 System.out.println("About to compile file with secondary types "+ unit.typeLocator()); if (extras == null) 290 extras = new ArrayList(3); 291 extras.add(unit); 292 } 293 } 294 if (extras != null) { 295 int oldLength = units.length; 296 int toAdd = extras.size(); 297 System.arraycopy(units, 0, units = new SourceFile[oldLength + toAdd], 0, oldLength); 298 for (int i = 0; i < toAdd; i++) 299 units[oldLength++] = (SourceFile) extras.get(i); 300 } 301 } 302 super.compile(units, additionalUnits, compilingFirstGroup); 303 } 304 305 protected void deleteGeneratedFiles(IFile[] deletedGeneratedFiles) { 306 try { 308 for (int j = deletedGeneratedFiles.length; --j >= 0;) { 309 IFile deletedFile = deletedGeneratedFiles[j]; 310 if (deletedFile.exists()) continue; 312 SourceFile sourceFile = findSourceFile(deletedFile, false); 313 String typeLocator = sourceFile.typeLocator(); 314 int mdSegmentCount = sourceFile.sourceLocation.sourceFolder.getFullPath().segmentCount(); 315 IPath typePath = sourceFile.resource.getFullPath().removeFirstSegments(mdSegmentCount).removeFileExtension(); 316 addDependentsOf(typePath, true); previousSourceFiles = null; char[][] definedTypeNames = newState.getDefinedTypeNamesFor(typeLocator); 319 if (definedTypeNames == null) { removeClassFile(typePath, sourceFile.sourceLocation.binaryFolder); 321 } else { 322 if (definedTypeNames.length > 0) { IPath packagePath = typePath.removeLastSegments(1); 324 for (int d = 0, l = definedTypeNames.length; d < l; d++) 325 removeClassFile(packagePath.append(new String (definedTypeNames[d])), sourceFile.sourceLocation.binaryFolder); 326 } 327 } 328 this.newState.removeLocator(typeLocator); 329 } 330 } catch (CoreException e) { 331 e.printStackTrace(); 333 } 334 } 335 336 protected boolean findAffectedSourceFiles(IResourceDelta delta, ClasspathLocation[] classFoldersAndJars, IProject prereqProject) { 337 for (int i = 0, l = classFoldersAndJars.length; i < l; i++) { 338 ClasspathLocation bLocation = classFoldersAndJars[i]; 339 if (bLocation != null) { IPath p = bLocation.getProjectRelativePath(); 342 if (p != null) { 343 IResourceDelta binaryDelta = delta.findMember(p); 344 if (binaryDelta != null) { 345 if (bLocation instanceof ClasspathJar) { 346 if (JavaBuilder.DEBUG) 347 System.out.println("ABORTING incremental build... found delta to jar/zip file"); return false; } 350 if (binaryDelta.getKind() == IResourceDelta.ADDED || binaryDelta.getKind() == IResourceDelta.REMOVED) { 351 if (JavaBuilder.DEBUG) 352 System.out.println("ABORTING incremental build... found added/removed binary folder"); return false; } 355 int segmentCount = binaryDelta.getFullPath().segmentCount(); 356 IResourceDelta[] children = binaryDelta.getAffectedChildren(); StringSet structurallyChangedTypes = null; 358 if (bLocation.isOutputFolder()) 359 structurallyChangedTypes = this.newState.getStructurallyChangedTypes(javaBuilder.getLastState(prereqProject)); 360 for (int j = 0, m = children.length; j < m; j++) 361 findAffectedSourceFiles(children[j], segmentCount, structurallyChangedTypes); 362 notifier.checkCancel(); 363 } 364 } 365 } 366 } 367 return true; 368 } 369 370 protected void findAffectedSourceFiles(IResourceDelta binaryDelta, int segmentCount, StringSet structurallyChangedTypes) { 371 IResource resource = binaryDelta.getResource(); 374 switch(resource.getType()) { 375 case IResource.FOLDER : 376 switch (binaryDelta.getKind()) { 377 case IResourceDelta.ADDED : 378 case IResourceDelta.REMOVED : 379 IPath packagePath = resource.getFullPath().removeFirstSegments(segmentCount); 380 String packageName = packagePath.toString(); 381 if (binaryDelta.getKind() == IResourceDelta.ADDED) { 382 if (!newState.isKnownPackage(packageName)) { 384 if (JavaBuilder.DEBUG) 385 System.out.println("Found added package " + packageName); addDependentsOf(packagePath, false); 387 return; 388 } 389 if (JavaBuilder.DEBUG) 390 System.out.println("Skipped dependents of added package " + packageName); } else { 392 if (!nameEnvironment.isPackage(packageName)) { 394 if (JavaBuilder.DEBUG) 395 System.out.println("Found removed package " + packageName); addDependentsOf(packagePath, false); 397 return; 398 } 399 if (JavaBuilder.DEBUG) 400 System.out.println("Skipped dependents of removed package " + packageName); } 402 case IResourceDelta.CHANGED : 404 IResourceDelta[] children = binaryDelta.getAffectedChildren(); 405 for (int i = 0, l = children.length; i < l; i++) 406 findAffectedSourceFiles(children[i], segmentCount, structurallyChangedTypes); 407 } 408 return; 409 case IResource.FILE : 410 if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(resource.getName())) { 411 IPath typePath = resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension(); 412 switch (binaryDelta.getKind()) { 413 case IResourceDelta.ADDED : 414 case IResourceDelta.REMOVED : 415 if (JavaBuilder.DEBUG) 416 System.out.println("Found added/removed class file " + typePath); addDependentsOf(typePath, false); 418 return; 419 case IResourceDelta.CHANGED : 420 if ((binaryDelta.getFlags() & IResourceDelta.CONTENT) == 0) 421 return; if (structurallyChangedTypes != null && !structurallyChangedTypes.includes(typePath.toString())) 423 return; if (JavaBuilder.DEBUG) 425 System.out.println("Found changed class file " + typePath); addDependentsOf(typePath, false); 427 } 428 return; 429 } 430 } 431 } 432 433 protected boolean findSourceFiles(IResourceDelta delta) throws CoreException { 434 ArrayList visited = this.makeOutputFolderConsistent ? new ArrayList(sourceLocations.length) : null; 435 for (int i = 0, l = sourceLocations.length; i < l; i++) { 436 ClasspathMultiDirectory md = sourceLocations[i]; 437 if (this.makeOutputFolderConsistent && md.hasIndependentOutputFolder && !visited.contains(md.binaryFolder)) { 438 visited.add(md.binaryFolder); 440 IResourceDelta binaryDelta = delta.findMember(md.binaryFolder.getProjectRelativePath()); 441 if (binaryDelta != null) { 442 int segmentCount = binaryDelta.getFullPath().segmentCount(); 443 IResourceDelta[] children = binaryDelta.getAffectedChildren(); 444 for (int j = 0, m = children.length; j < m; j++) 445 if (!checkForClassFileChanges(children[j], md, segmentCount)) 446 return false; 447 } 448 } 449 if (md.sourceFolder.equals(javaBuilder.currentProject)) { 450 int segmentCount = delta.getFullPath().segmentCount(); 452 IResourceDelta[] children = delta.getAffectedChildren(); 453 for (int j = 0, m = children.length; j < m; j++) 454 if (!isExcludedFromProject(children[j].getFullPath())) 455 if (!findSourceFiles(children[j], md, segmentCount)) 456 return false; 457 } else { 458 IResourceDelta sourceDelta = delta.findMember(md.sourceFolder.getProjectRelativePath()); 459 if (sourceDelta != null) { 460 if (sourceDelta.getKind() == IResourceDelta.REMOVED) { 461 if (JavaBuilder.DEBUG) 462 System.out.println("ABORTING incremental build... found removed source folder"); return false; } 465 int segmentCount = sourceDelta.getFullPath().segmentCount(); 466 IResourceDelta[] children = sourceDelta.getAffectedChildren(); 467 try { 468 for (int j = 0, m = children.length; j < m; j++) 469 if (!findSourceFiles(children[j], md, segmentCount)) 470 return false; 471 } catch (CoreException e) { 472 if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) { 474 if (JavaBuilder.DEBUG) 475 System.out.println("ABORTING incremental build... found renamed package"); return false; 477 } 478 throw e; } 480 } 481 } 482 notifier.checkCancel(); 483 } 484 return true; 485 } 486 487 protected boolean findSourceFiles(IResourceDelta sourceDelta, ClasspathMultiDirectory md, int segmentCount) throws CoreException { 488 IResource resource = sourceDelta.getResource(); 491 boolean isExcluded = (md.exclusionPatterns != null || md.inclusionPatterns != null) 493 && Util.isExcluded(resource, md.inclusionPatterns, md.exclusionPatterns); 494 switch(resource.getType()) { 495 case IResource.FOLDER : 496 if (isExcluded && md.inclusionPatterns == null) 497 return true; 499 switch (sourceDelta.getKind()) { 500 case IResourceDelta.ADDED : 501 if (!isExcluded) { 502 IPath addedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount); 503 createFolder(addedPackagePath, md.binaryFolder); if (JavaBuilder.DEBUG) 506 System.out.println("Found added package " + addedPackagePath); addDependentsOf(addedPackagePath, true); 508 } 509 case IResourceDelta.CHANGED : 511 IResourceDelta[] children = sourceDelta.getAffectedChildren(); 512 for (int i = 0, l = children.length; i < l; i++) 513 if (!findSourceFiles(children[i], md, segmentCount)) 514 return false; 515 return true; 516 case IResourceDelta.REMOVED : 517 if (isExcluded) { 518 children = sourceDelta.getAffectedChildren(); 520 for (int i = 0, l = children.length; i < l; i++) 521 if (!findSourceFiles(children[i], md, segmentCount)) 522 return false; 523 return true; 524 } 525 IPath removedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount); 526 if (sourceLocations.length > 1) { 527 for (int i = 0, l = sourceLocations.length; i < l; i++) { 528 if (sourceLocations[i].sourceFolder.getFolder(removedPackagePath).exists()) { 529 createFolder(removedPackagePath, md.binaryFolder); IResourceDelta[] removedChildren = sourceDelta.getAffectedChildren(); 532 for (int j = 0, m = removedChildren.length; j < m; j++) 533 if (!findSourceFiles(removedChildren[j], md, segmentCount)) 534 return false; 535 return true; 536 } 537 } 538 } 539 IFolder removedPackageFolder = md.binaryFolder.getFolder(removedPackagePath); 540 if (removedPackageFolder.exists()) 541 removedPackageFolder.delete(IResource.FORCE, null); 542 if (JavaBuilder.DEBUG) 544 System.out.println("Found removed package " + removedPackagePath); addDependentsOf(removedPackagePath, true); 546 newState.removePackage(sourceDelta); 547 } 548 return true; 549 case IResource.FILE : 550 if (isExcluded) return true; 551 552 String resourceName = resource.getName(); 553 if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(resourceName)) { 554 IPath typePath = resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension(); 555 String typeLocator = resource.getProjectRelativePath().toString(); 556 switch (sourceDelta.getKind()) { 557 case IResourceDelta.ADDED : 558 if (JavaBuilder.DEBUG) 559 System.out.println("Compile this added source file " + typeLocator); sourceFiles.add(new SourceFile((IFile) resource, md, true)); 561 String typeName = typePath.toString(); 562 if (!newState.isDuplicateLocator(typeName, typeLocator)) { if (JavaBuilder.DEBUG) 564 System.out.println("Found added source file " + typeName); addDependentsOf(typePath, true); 566 } 567 return true; 568 case IResourceDelta.REMOVED : 569 char[][] definedTypeNames = newState.getDefinedTypeNamesFor(typeLocator); 570 if (definedTypeNames == null) { removeClassFile(typePath, md.binaryFolder); 572 if ((sourceDelta.getFlags() & IResourceDelta.MOVED_TO) != 0) { 573 IResource movedFile = javaBuilder.workspaceRoot.getFile(sourceDelta.getMovedToPath()); 578 JavaBuilder.removeProblemsAndTasksFor(movedFile); 579 } 580 } else { 581 if (JavaBuilder.DEBUG) 582 System.out.println("Found removed source file " + typePath.toString()); addDependentsOf(typePath, true); if (definedTypeNames.length > 0) { IPath packagePath = typePath.removeLastSegments(1); 586 for (int i = 0, l = definedTypeNames.length; i < l; i++) 587 removeClassFile(packagePath.append(new String (definedTypeNames[i])), md.binaryFolder); 588 } 589 } 590 newState.removeLocator(typeLocator); 591 return true; 592 case IResourceDelta.CHANGED : 593 if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0 594 && (sourceDelta.getFlags() & IResourceDelta.ENCODING) == 0) 595 return true; if (JavaBuilder.DEBUG) 597 System.out.println("Compile this changed source file " + typeLocator); sourceFiles.add(new SourceFile((IFile) resource, md, true)); 599 } 600 return true; 601 } else if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(resourceName)) { 602 if (this.makeOutputFolderConsistent) { 604 IPath typePath = resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension(); 605 if (newState.isKnownType(typePath.toString())) { 606 if (JavaBuilder.DEBUG) 607 System.out.println("MUST DO FULL BUILD. Found change to class file " + typePath); return false; 609 } 610 } 611 return true; 612 } else if (md.hasIndependentOutputFolder) { 613 if (javaBuilder.filterExtraResource(resource)) return true; 614 615 IPath resourcePath = resource.getFullPath().removeFirstSegments(segmentCount); 617 IResource outputFile = md.binaryFolder.getFile(resourcePath); 618 switch (sourceDelta.getKind()) { 619 case IResourceDelta.ADDED : 620 if (outputFile.exists()) { 621 if (JavaBuilder.DEBUG) 622 System.out.println("Deleting existing file " + resourcePath); outputFile.delete(IResource.FORCE, null); 624 } 625 if (JavaBuilder.DEBUG) 626 System.out.println("Copying added file " + resourcePath); createFolder(resourcePath.removeLastSegments(1), md.binaryFolder); resource.copy(outputFile.getFullPath(), IResource.FORCE | IResource.DERIVED, null); 629 Util.setReadOnly(outputFile, false); return true; 631 case IResourceDelta.REMOVED : 632 if (outputFile.exists()) { 633 if (JavaBuilder.DEBUG) 634 System.out.println("Deleting removed file " + resourcePath); outputFile.delete(IResource.FORCE, null); 636 } 637 return true; 638 case IResourceDelta.CHANGED : 639 if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0 640 && (sourceDelta.getFlags() & IResourceDelta.ENCODING) == 0) 641 return true; if (outputFile.exists()) { 643 if (JavaBuilder.DEBUG) 644 System.out.println("Deleting existing file " + resourcePath); outputFile.delete(IResource.FORCE, null); 646 } 647 if (JavaBuilder.DEBUG) 648 System.out.println("Copying changed file " + resourcePath); createFolder(resourcePath.removeLastSegments(1), md.binaryFolder); resource.copy(outputFile.getFullPath(), IResource.FORCE | IResource.DERIVED, null); 651 Util.setReadOnly(outputFile, false); } 653 return true; 654 } 655 } 656 return true; 657 } 658 659 protected void finishedWith(String sourceLocator, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) { 660 char[][] previousTypeNames = newState.getDefinedTypeNamesFor(sourceLocator); 661 if (previousTypeNames == null) 662 previousTypeNames = new char[][] {mainTypeName}; 663 IPath packagePath = null; 664 next : for (int i = 0, l = previousTypeNames.length; i < l; i++) { 665 char[] previous = previousTypeNames[i]; 666 for (int j = 0, m = definedTypeNames.size(); j < m; j++) 667 if (CharOperation.equals(previous, (char[]) definedTypeNames.get(j))) 668 continue next; 669 670 SourceFile sourceFile = (SourceFile) result.getCompilationUnit(); 671 if (packagePath == null) { 672 int count = sourceFile.sourceLocation.sourceFolder.getFullPath().segmentCount(); 673 packagePath = sourceFile.resource.getFullPath().removeFirstSegments(count).removeLastSegments(1); 674 } 675 if (secondaryTypesToRemove == null) 676 this.secondaryTypesToRemove = new SimpleLookupTable(); 677 ArrayList types = (ArrayList) secondaryTypesToRemove.get(sourceFile.sourceLocation.binaryFolder); 678 if (types == null) 679 types = new ArrayList(definedTypeNames.size()); 680 types.add(packagePath.append(new String (previous))); 681 secondaryTypesToRemove.put(sourceFile.sourceLocation.binaryFolder, types); 682 } 683 super.finishedWith(sourceLocator, result, mainTypeName, definedTypeNames, duplicateTypeNames); 684 } 685 686 protected void processAnnotationResults(CompilationParticipantResult[] results) { 687 for (int i = results.length; --i >= 0;) { 688 CompilationParticipantResult result = results[i]; 689 if (result == null) continue; 690 691 IFile[] deletedGeneratedFiles = result.deletedFiles; 692 if (deletedGeneratedFiles != null) 693 deleteGeneratedFiles(deletedGeneratedFiles); 694 695 IFile[] addedGeneratedFiles = result.addedFiles; 696 if (addedGeneratedFiles != null) { 697 for (int j = addedGeneratedFiles.length; --j >= 0;) { 698 SourceFile sourceFile = findSourceFile(addedGeneratedFiles[j], true); 699 if (sourceFile != null && !sourceFiles.contains(sourceFile)) 700 this.sourceFiles.add(sourceFile); 701 } 702 } 703 704 recordParticipantResult(result); 705 } 706 } 707 708 protected void removeClassFile(IPath typePath, IContainer outputFolder) throws CoreException { 709 if (typePath.lastSegment().indexOf('$') == -1) { newState.removeQualifiedTypeName(typePath.toString()); 711 if (JavaBuilder.DEBUG) 713 System.out.println("Found removed type " + typePath); addDependentsOf(typePath, true); } 716 IFile classFile = outputFolder.getFile(typePath.addFileExtension(SuffixConstants.EXTENSION_class)); 717 if (classFile.exists()) { 718 if (JavaBuilder.DEBUG) 719 System.out.println("Deleting class file of removed type " + typePath); classFile.delete(IResource.FORCE, null); 721 } 722 } 723 724 protected void removeSecondaryTypes() throws CoreException { 725 if (secondaryTypesToRemove != null) { Object [] keyTable = secondaryTypesToRemove.keyTable; 727 Object [] valueTable = secondaryTypesToRemove.valueTable; 728 for (int i = 0, l = keyTable.length; i < l; i++) { 729 IContainer outputFolder = (IContainer) keyTable[i]; 730 if (outputFolder != null) { 731 ArrayList paths = (ArrayList) valueTable[i]; 732 for (int j = 0, m = paths.size(); j < m; j++) 733 removeClassFile((IPath) paths.get(j), outputFolder); 734 } 735 } 736 this.secondaryTypesToRemove = null; 737 if (previousSourceFiles != null) 738 this.previousSourceFiles = null; } 740 } 741 742 protected void resetCollections() { 743 if (this.sourceFiles == null) { 744 this.sourceFiles = new ArrayList(33); 745 this.previousSourceFiles = null; 746 this.qualifiedStrings = new StringSet(3); 747 this.simpleStrings = new StringSet(3); 748 this.hasStructuralChanges = false; 749 this.compileLoop = 0; 750 } else { 751 this.previousSourceFiles = this.sourceFiles.isEmpty() ? null : (ArrayList) this.sourceFiles.clone(); 752 753 this.sourceFiles.clear(); 754 this.qualifiedStrings.clear(); 755 this.simpleStrings.clear(); 756 this.workQueue.clear(); 757 } 758 } 759 760 protected void updateProblemsFor(SourceFile sourceFile, CompilationResult result) throws CoreException { 761 IMarker[] markers = JavaBuilder.getProblemsFor(sourceFile.resource); 762 CategorizedProblem[] problems = result.getProblems(); 763 if (problems == null && markers.length == 0) return; 764 765 notifier.updateProblemCounts(markers, problems); 766 JavaBuilder.removeProblemsFor(sourceFile.resource); 767 storeProblemsFor(sourceFile, problems); 768 } 769 770 protected void updateTasksFor(SourceFile sourceFile, CompilationResult result) throws CoreException { 771 IMarker[] markers = JavaBuilder.getTasksFor(sourceFile.resource); 772 CategorizedProblem[] tasks = result.getTasks(); 773 if (tasks == null && markers.length == 0) return; 774 775 JavaBuilder.removeTasksFor(sourceFile.resource); 776 storeTasksFor(sourceFile, tasks); 777 } 778 779 protected void writeClassFileBytes(byte[] bytes, IFile file, String qualifiedFileName, boolean isTopLevelType, SourceFile compilationUnit) throws CoreException { 780 if (file.exists()) { 783 if (writeClassFileCheck(file, qualifiedFileName, bytes) || compilationUnit.updateClassFile) { if (JavaBuilder.DEBUG) 785 System.out.println("Writing changed class file " + file.getName()); if (!file.isDerived()) 787 file.setDerived(true); 788 file.setContents(new ByteArrayInputStream(bytes), true, false, null); 789 } else if (JavaBuilder.DEBUG) { 790 System.out.println("Skipped over unchanged class file " + file.getName()); } 792 } else { 793 if (isTopLevelType) 794 addDependentsOf(new Path(qualifiedFileName), true); if (JavaBuilder.DEBUG) 796 System.out.println("Writing new class file " + file.getName()); try { 798 file.create(new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null); 799 } catch (CoreException e) { 800 if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) { 801 IStatus status = e.getStatus(); 802 if (status instanceof IResourceStatus) { 803 IPath oldFilePath = ((IResourceStatus) status).getPath(); 804 char[] oldTypeName = oldFilePath.removeFileExtension().lastSegment().toCharArray(); 805 char[][] previousTypeNames = newState.getDefinedTypeNamesFor(compilationUnit.typeLocator()); 806 boolean fromSameFile = false; 807 if (previousTypeNames == null) { 808 fromSameFile = CharOperation.equals(compilationUnit.getMainTypeName(), oldTypeName); 809 } else { 810 for (int i = 0, l = previousTypeNames.length; i < l; i++) { 811 if (CharOperation.equals(previousTypeNames[i], oldTypeName)) { 812 fromSameFile = true; 813 break; 814 } 815 } 816 } 817 if (fromSameFile) { 818 IFile collision = file.getParent().getFile(new Path(oldFilePath.lastSegment())); 820 collision.delete(true, false, null); 821 boolean success = false; 822 try { 823 file.create(new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null); 824 success = true; 825 } catch (CoreException ignored) { 826 } 828 if (success) return; 829 } 830 } 831 throw new AbortCompilation(true, new AbortIncrementalBuildException(qualifiedFileName)); 833 } 834 throw e; } 836 } 837 } 838 839 protected boolean writeClassFileCheck(IFile file, String fileName, byte[] newBytes) throws CoreException { 840 try { 841 byte[] oldBytes = Util.getResourceContentsAsByteArray(file); 842 notEqual : if (newBytes.length == oldBytes.length) { 843 for (int i = newBytes.length; --i >= 0;) 844 if (newBytes[i] != oldBytes[i]) break notEqual; 845 return false; } 847 URI location = file.getLocationURI(); 848 if (location == null) return false; String filePath = location.getSchemeSpecificPart(); 850 ClassFileReader reader = new ClassFileReader(oldBytes, filePath.toCharArray()); 851 if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) { 853 if (JavaBuilder.DEBUG) 854 System.out.println("Type has structural changes " + fileName); addDependentsOf(new Path(fileName), true); 856 this.newState.wasStructurallyChanged(fileName); 857 } 858 } catch (ClassFormatException e) { 859 addDependentsOf(new Path(fileName), true); 860 this.newState.wasStructurallyChanged(fileName); 861 } 862 return true; 863 } 864 865 public String toString() { 866 return "incremental image builder for:\n\tnew state: " + newState; } 868 869 870 901 } 902 | Popular Tags |