private void processRemovedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
      final Collection<MethodRepr> removed = diff.methods().removed();
      if (removed.isEmpty()) {
        return;
      }
      assert myFuture != null;
      assert myPresent != null;
      assert myAffectedFiles != null;
      assert myCompiledFiles != null;

      debug("Processing removed methods:");

      for (final MethodRepr removedMethod : removed) {
        debug("Method ", removedMethod.name);

        final Collection<Pair<MethodRepr, ClassRepr>> overriddenMethods = myFuture.findOverriddenMethods(removedMethod, it);
        final Supplier<IntSet> propagated = lazy(()-> myFuture.propagateMethodAccess(removedMethod, it.name));

        if (!removedMethod.isPrivate() && removedMethod.isStatic()) {
          debug("The method was static --- affecting static method import usages");
          myFuture.affectStaticMemberImportUsages(removedMethod.name, it.name, propagated.get(), state.myAffectedUsages, state.myDependants);
        }

        if (removedMethod.isPackageLocal()) {
          // Sometimes javac cannot find an overridden package local method in superclasses, when superclasses are defined in different packages.
          // This results in compilation error when the code is compiled from the very beginning.
          // So even if we correctly find a corresponding overridden method and the bytecode compatibility remains,
          // we still need to affect package local method usages to behave similar to javac.
          debug("Removed method is package-local, affecting method usages");
          myFuture.affectMethodUsages(removedMethod, propagated.get(), removedMethod.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants);
        }
        else if (overriddenMethods.isEmpty()) {
          debug("No overridden methods found, affecting method usages");
          myFuture.affectMethodUsages(removedMethod, propagated.get(), removedMethod.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants);
        }
        else {
          boolean clearlyOverridden = isEmpty(removedMethod.signature) && Iterators.isEmpty(
            Iterators.filter(overriddenMethods, p -> p.first == MOCK_METHOD || !p.first.myType.equals(removedMethod.myType) || !isEmpty(p.first.signature) || removedMethod.isMoreAccessibleThan(p.first))
          );

          if (!clearlyOverridden) {
            debug("No clearly overridden methods found, affecting method usages");
            myFuture.affectMethodUsages(removedMethod, propagated.get(), removedMethod.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants);
          }
        }

        final Collection<Pair<MethodRepr, ClassRepr>> overridingMethods = new HashSet<>();
        myFuture.addOverridingMethods(removedMethod, it, it, MethodRepr.equalByJavaRules(removedMethod), overridingMethods, null);

        for (final Pair<MethodRepr, ClassRepr> p : overridingMethods) {
          final Iterable<File> fNames = classToSourceFileGet(p.second.name);
          if (fNames != null && !containsAll(myFilesToCompile, fNames)) {
            ContainerUtil.addAll(myAffectedFiles, fNames);
            if (myDebugS.isDebugEnabled()) {
              for (File fName : fNames) {
                debug("Affecting file by overriding: ", fName);
              }
            }
          }
        }

        if (!removedMethod.isAbstract() && !removedMethod.isStatic()) {
          propagated.get().forEach(p -> {
            if (p != it.name) {
              for (ClassRepr subClass : myFuture.reprsByName(p, ClassRepr.class)) {
                final Collection<Pair<MethodRepr, ClassRepr>> overriddenInSubclass = myFuture.findOverriddenMethods(removedMethod, subClass);

                overriddenInSubclass.addAll(overriddenMethods);

                boolean allAbstract = true;
                boolean visited = false;

                for (final Pair<MethodRepr, ClassRepr> pp : overriddenInSubclass) {
                  final ClassRepr cc = pp.second;

                  if (cc == MOCK_CLASS) {
                    visited = true;
                    continue;
                  }

                  if (!pp.first.isAbstract() && !pp.first.equals(removedMethod) /*need exact match for non-abstract methods*/) {
                    continue;
                  }

                  visited = true;
                  allAbstract = pp.first.isAbstract() || cc.isInterface();

                  if (!allAbstract) {
                    break;
                  }
                }

                if (allAbstract && visited) {
                  final Iterable<File> sources = classToSourceFileGet(p);
                  if (sources != null && !containsAll(myFilesToCompile, sources)) {
                    ContainerUtil.addAll(myAffectedFiles, sources);
                    debug("Removed method is not abstract & overrides some abstract method which is not then over-overridden in subclass ", p);
                    for (File source : sources) {
                      debug("Affecting subclass source file ", source);
                    }
                  }
                  break; // classReprs
                }
              }
            }
          });
        }
      }
      debug("End of removed methods processing");
    }
private void processRemovedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it)