protected void finishedWith(
      String sourceLocator,
      CompilationResult result,
      char[] mainTypeName,
      ArrayList definedTypeNames,
      ArrayList duplicateTypeNames) {
    char[][] previousTypeNames = this.newState.getDefinedTypeNamesFor(sourceLocator);
    if (previousTypeNames == null) previousTypeNames = new char[][] {mainTypeName};
    IPath packagePath = null;
    next:
    for (int i = 0, l = previousTypeNames.length; i < l; i++) {
      char[] previous = previousTypeNames[i];
      for (int j = 0, m = definedTypeNames.size(); j < m; j++)
        if (CharOperation.equals(previous, (char[]) definedTypeNames.get(j))) continue next;

      SourceFile sourceFile = (SourceFile) result.getCompilationUnit();
      if (packagePath == null) {
        int count = sourceFile.sourceLocation.sourceFolder.getFullPath().segmentCount();
        packagePath =
            sourceFile.resource.getFullPath().removeFirstSegments(count).removeLastSegments(1);
      }
      if (this.secondaryTypesToRemove == null)
        this.secondaryTypesToRemove = new SimpleLookupTable();
      ArrayList types =
          (ArrayList) this.secondaryTypesToRemove.get(sourceFile.sourceLocation.binaryFolder);
      if (types == null) types = new ArrayList(definedTypeNames.size());
      types.add(packagePath.append(new String(previous)));
      this.secondaryTypesToRemove.put(sourceFile.sourceLocation.binaryFolder, types);
    }
    super.finishedWith(sourceLocator, result, mainTypeName, definedTypeNames, duplicateTypeNames);
  }
  public void resolveReceiver() {
    if (this.receiver == null) return;

    if (this.receiver.modifiers != 0) {
      this.scope
          .problemReporter()
          .illegalModifiers(
              this.receiver.declarationSourceStart, this.receiver.declarationSourceEnd);
    }

    TypeBinding resolvedReceiverType = this.receiver.type.resolvedType;
    if (this.binding == null
        || resolvedReceiverType == null
        || !resolvedReceiverType.isValidBinding()) {
      return;
    }

    ReferenceBinding declaringClass = this.binding.declaringClass;
    /* neither static methods nor methods in anonymous types can have explicit 'this' */
    if (this.isStatic() || declaringClass.isAnonymousType()) {
      this.scope.problemReporter().disallowedThisParameter(this.receiver);
      return; // No need to do further validation
    }

    ReferenceBinding enclosingReceiver = this.scope.enclosingReceiverType();
    if (this.isConstructor()) {
      /* Only non static member types or local types can declare explicit 'this' params in constructors */
      if (declaringClass.isStatic()
          || (declaringClass.tagBits & (TagBits.IsLocalType | TagBits.IsMemberType)) == 0) {
          /* neither member nor local type */
        this.scope.problemReporter().disallowedThisParameter(this.receiver);
        return; // No need to do further validation
      }
      enclosingReceiver = enclosingReceiver.enclosingType();
    }

    char[][] tokens =
        (this.receiver.qualifyingName == null) ? null : this.receiver.qualifyingName.getName();
    if (this.isConstructor()) {
      if (tokens == null
          || tokens.length > 1
          || !CharOperation.equals(enclosingReceiver.sourceName(), tokens[0])) {
        this.scope
            .problemReporter()
            .illegalQualifierForExplicitThis(this.receiver, enclosingReceiver);
        this.receiver.qualifyingName = null;
      }
    } else if (tokens != null && tokens.length > 0) {
      this.scope.problemReporter().illegalQualifierForExplicitThis2(this.receiver);
      this.receiver.qualifyingName = null;
    }

    if (TypeBinding.notEquals(enclosingReceiver, resolvedReceiverType)) {
      this.scope.problemReporter().illegalTypeForExplicitThis(this.receiver, enclosingReceiver);
    }

    if (this.receiver.type.hasNullTypeAnnotation(AnnotationPosition.ANY)) {
      this.scope.problemReporter().nullAnnotationUnsupportedLocation(this.receiver.type);
    }
  }
  /** Record the thrown exception type bindings in the corresponding type references. */
  public void bindThrownExceptions() {

    if (this.thrownExceptions != null
        && this.binding != null
        && this.binding.thrownExceptions != null) {
      int thrownExceptionLength = this.thrownExceptions.length;
      int length = this.binding.thrownExceptions.length;
      if (length == thrownExceptionLength) {
        for (int i = 0; i < length; i++) {
          this.thrownExceptions[i].resolvedType = this.binding.thrownExceptions[i];
        }
      } else {
        int bindingIndex = 0;
        for (int i = 0; i < thrownExceptionLength && bindingIndex < length; i++) {
          TypeReference thrownException = this.thrownExceptions[i];
          ReferenceBinding thrownExceptionBinding = this.binding.thrownExceptions[bindingIndex];
          char[][] bindingCompoundName = thrownExceptionBinding.compoundName;
          if (bindingCompoundName == null) continue; // skip problem case
          if (thrownException instanceof SingleTypeReference) {
            // single type reference
            int lengthName = bindingCompoundName.length;
            char[] thrownExceptionTypeName = thrownException.getTypeName()[0];
            if (CharOperation.equals(
                thrownExceptionTypeName, bindingCompoundName[lengthName - 1])) {
              thrownException.resolvedType = thrownExceptionBinding;
              bindingIndex++;
            }
          } else {
            // qualified type reference
            if (CharOperation.equals(thrownException.getTypeName(), bindingCompoundName)) {
              thrownException.resolvedType = thrownExceptionBinding;
              bindingIndex++;
            }
          }
        }
      }
    }
  }
  protected void addDependentsOf(
      IPath path,
      boolean isStructuralChange,
      StringSet qualifiedNames,
      StringSet simpleNames,
      StringSet rootNames) {
    path = path.setDevice(null);
    if (isStructuralChange) {
      String last = path.lastSegment();
      if (last.length() == TypeConstants.PACKAGE_INFO_NAME.length)
        if (CharOperation.equals(last.toCharArray(), TypeConstants.PACKAGE_INFO_NAME)) {
          path =
              path.removeLastSegments(
                  1); // the package-info file has changed so blame the package itself
          /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=323785, in the case of default package,
            there is no need to blame the package itself as there can be no annotations or documentation
            comment tags in the package-info file that can influence the rest of the package. Just bail out
            so we don't touch null objects below.
          */
          if (path.isEmpty()) return;
        }
    }

    if (isStructuralChange && !this.hasStructuralChanges) {
      this.newState.tagAsStructurallyChanged();
      this.hasStructuralChanges = true;
    }
    // the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
    rootNames.add(path.segment(0));
    String packageName = path.removeLastSegments(1).toString();
    boolean wasNew = qualifiedNames.add(packageName);
    String typeName = path.lastSegment();
    int memberIndex = typeName.indexOf('$');
    if (memberIndex > 0) typeName = typeName.substring(0, memberIndex);
    wasNew = simpleNames.add(typeName) | wasNew;
    if (wasNew && JavaBuilder.DEBUG)
      System.out.println(
          "  will look for dependents of " //$NON-NLS-1$
              + typeName
              + " in "
              + packageName); //$NON-NLS-1$
  }
 /**
  * @see
  *     org.eclipse.jdt.internal.core.builder.AbstractImageBuilder#writeClassFileContents(org.eclipse.jdt.internal.compiler.ClassFile,
  *     org.eclipse.core.resources.IFile, java.lang.String, boolean,
  *     org.eclipse.jdt.internal.core.builder.SourceFile)
  */
 protected void writeClassFileContents(
     ClassFile classfile,
     IFile file,
     String qualifiedFileName,
     boolean isTopLevelType,
     SourceFile compilationUnit)
     throws CoreException {
   // Before writing out the class file, compare it to the previous file
   // If structural changes occurred then add dependent source files
   byte[] bytes = classfile.getBytes();
   if (file.exists()) {
     if (writeClassFileCheck(file, qualifiedFileName, bytes)
         || compilationUnit.updateClassFile) { // see 46093
       if (JavaBuilder.DEBUG)
         System.out.println("Writing changed class file " + file.getName()); // $NON-NLS-1$
       if (!file.isDerived()) file.setDerived(true, null);
       file.setContents(new ByteArrayInputStream(bytes), true, false, null);
     } else if (JavaBuilder.DEBUG) {
       System.out.println("Skipped over unchanged class file " + file.getName()); // $NON-NLS-1$
     }
   } else {
     if (isTopLevelType) addDependentsOf(new Path(qualifiedFileName), true); // new type
     if (JavaBuilder.DEBUG)
       System.out.println("Writing new class file " + file.getName()); // $NON-NLS-1$
     try {
       file.create(new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null);
     } catch (CoreException e) {
       if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
         IStatus status = e.getStatus();
         if (status instanceof IResourceStatus) {
           IPath oldFilePath = ((IResourceStatus) status).getPath();
           char[] oldTypeName = oldFilePath.removeFileExtension().lastSegment().toCharArray();
           char[][] previousTypeNames =
               this.newState.getDefinedTypeNamesFor(compilationUnit.typeLocator());
           boolean fromSameFile = false;
           if (previousTypeNames == null) {
             fromSameFile = CharOperation.equals(compilationUnit.getMainTypeName(), oldTypeName);
           } else {
             for (int i = 0, l = previousTypeNames.length; i < l; i++) {
               if (CharOperation.equals(previousTypeNames[i], oldTypeName)) {
                 fromSameFile = true;
                 break;
               }
             }
           }
           if (fromSameFile) {
             // file is defined by the same compilationUnit, but won't be deleted until later so do
             // it now
             IFile collision = file.getParent().getFile(new Path(oldFilePath.lastSegment()));
             collision.delete(true, false, null);
             boolean success = false;
             try {
               file.create(
                   new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null);
               success = true;
             } catch (CoreException ignored) {
               // ignore the second exception
             }
             if (success) return;
           }
         }
         // catch the case that a type has been renamed and collides on disk with an
         // as-yet-to-be-deleted type
         throw new AbortCompilation(true, new AbortIncrementalBuildException(qualifiedFileName));
       }
       throw e; // rethrow
     }
   }
 }