private void processChangedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
      final Collection<Pair<MethodRepr, MethodRepr.Diff>> changed = diff.methods().changed();
      if (changed.isEmpty()) {
        return;
      }
      debug("Processing changed methods:");

      assert myPresent != null;
      assert myFuture != null;
      assert myAffectedFiles != null;

      if (it.isInterface()) {
        for (final Pair<MethodRepr, MethodRepr.Diff> mr : changed) {
          if ((mr.second.removedModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
            debug("Method became non-abstract: ", mr.first.name);
            myPresent.affectLambdaInstantiations(state, it.name);
            break;
          }
        }
      }

      final List<Pair<MethodRepr, MethodRepr.Diff>> moreAccessible = new ArrayList<>();

      for (final Pair<MethodRepr, MethodRepr.Diff> mr : changed) {
        final MethodRepr m = mr.first;
        final MethodRepr.Diff d = mr.second;
        final boolean throwsChanged = !d.exceptions().unchanged();

        debug("Method: ", m.name);

        if (d.accessExpanded()) {
          moreAccessible.add(mr);
        }
        
        if (it.isAnnotation()) {
          if (d.defaultRemoved()) {
            debug("Class is annotation, default value is removed => adding annotation query");
            IntSet l = new IntOpenHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR);
            l.add(m.name);
            final UsageRepr.AnnotationUsage annotationUsage = (UsageRepr.AnnotationUsage)UsageRepr
              .createAnnotationUsage(myContext, TypeRepr.createClassType(myContext, it.name), l, null);
            state.myAnnotationQuery.add(annotationUsage);
          }
        }
        else if (d.base() != Difference.NONE || throwsChanged) {
          final Supplier<IntSet> propagated = lazy(()-> myFuture.propagateMethodAccess(m, it.name));

          boolean affected = false;
          boolean constrained = false;

          final Set<UsageRepr.Usage> usages = new HashSet<>();

          if (d.packageLocalOn()) {
            debug("Method became package-private, affecting method usages outside the package");
            myFuture.affectMethodUsages(m, propagated.get(), m.createUsage(myContext, it.name), usages, state.myDependants);

            for (final UsageRepr.Usage usage : usages) {
              state.myUsageConstraints.put(usage, myFuture.new PackageConstraint(it.getPackageName()));
            }

            state.myAffectedUsages.addAll(usages);
            affected = true;
            constrained = true;
          }

          if ((d.base() & Difference.TYPE) != 0 || (d.base() & Difference.SIGNATURE) != 0 || throwsChanged) {
            if (!affected) {
              debug("Return type, throws list or signature changed --- affecting method usages");
              myFuture.affectMethodUsages(m, propagated.get(), m.createUsage(myContext, it.name), usages, state.myDependants);

              final List<Pair<MethodRepr, ClassRepr>> overridingMethods = new LinkedList<>();

              myFuture.addOverridingMethods(m, it, it, MethodRepr.equalByJavaRules(m), overridingMethods, null);

              for(final Pair<MethodRepr, ClassRepr> p : overridingMethods) {
                final ClassRepr aClass = p.getSecond();

                if (aClass != MOCK_CLASS) {
                  final Iterable<File> fileNames = classToSourceFileGet(aClass.name);
                  if (fileNames != null) {
                    ContainerUtil.addAll(myAffectedFiles, fileNames);
                  }
                }
              }

              state.myAffectedUsages.addAll(usages);
              affected = true;
            }
          }
          else if ((d.base() & Difference.ACCESS) != 0) {
            if ((d.addedModifiers() & (Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_BRIDGE)) != 0 ||
                (d.removedModifiers() & Opcodes.ACC_STATIC) != 0) {

              // When synthetic or bridge flags are added, this effectively means that explicitly written in the code
              // method with the same signature and return type has been removed and a bridge method has been generated instead.
              // In some cases (e.g. using raw types) the presence of such synthetic methods in the bytecode is ignored by the compiler
              // so that the code that called such method via raw type reference might not compile anymore => to be on the safe side
              // we should recompile all places where the method was used

              if (!affected) {
                debug("Added {static | private | synthetic | bridge} specifier or removed static specifier --- affecting method usages");
                myFuture.affectMethodUsages(m, propagated.get(), m.createUsage(myContext, it.name), usages, state.myDependants);
                state.myAffectedUsages.addAll(usages);
                affected = true;
              }

              if ((d.addedModifiers() & Opcodes.ACC_STATIC) != 0) {
                debug("Added static specifier --- affecting subclasses");
                myFuture.affectSubclasses(it.name, myAffectedFiles, state.myAffectedUsages, state.myDependants, false, myCompiledFiles, null);

                if (!m.isPrivate()) {
                  debug("Added static modifier --- affecting static member on-demand import usages");
                  myFuture.affectStaticMemberOnDemandUsages(it.name, propagated.get(), state.myAffectedUsages, state.myDependants);
                }
              }
              else if ((d.removedModifiers() & Opcodes.ACC_STATIC) != 0) {
                if (!m.isPrivate()) {
                  debug("Removed static modifier --- affecting static method import usages");
                  myFuture.affectStaticMemberImportUsages(m.name, it.name, propagated.get(), state.myAffectedUsages, state.myDependants);
                }
              }
            }
            else {
              if ((d.addedModifiers() & (Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT)) != 0) {
                debug("Added final, public or abstract specifier --- affecting subclasses");
                myFuture.affectSubclasses(it.name, myAffectedFiles, state.myAffectedUsages, state.myDependants, false, myCompiledFiles, null);
                if (it.isInterface() && (d.addedModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
                  myPresent.affectLambdaInstantiations(state, it.name);
                }
              }

              if ((d.addedModifiers() & Opcodes.ACC_PROTECTED) != 0 && (d.removedModifiers() & Opcodes.ACC_PRIVATE) == 0) {
                debug("Added public or package-private method became protected --- affect method usages with protected constraint");
                if (!affected) {
                  myFuture.affectMethodUsages(m, propagated.get(), m.createUsage(myContext, it.name), usages, state.myDependants);
                  state.myAffectedUsages.addAll(usages);
                  affected = true;
                }

                for (final UsageRepr.Usage usage : usages) {
                  state.myUsageConstraints.put(usage, myFuture.new InheritanceConstraint(it));
                }
                constrained = true;
              }
            }
          }

          if ((d.base() & Difference.ANNOTATIONS) != 0) {
            final Set<AnnotationsChangeTracker.Recompile> toRecompile = EnumSet.noneOf(AnnotationsChangeTracker.Recompile.class);
            for (AnnotationsChangeTracker extension : myAnnotationChangeTracker) {
              if (toRecompile.containsAll(AnnotationsChangeTracker.RECOMPILE_ALL)) {
                break;
              }
              final Set<AnnotationsChangeTracker.Recompile> actions = extension.methodAnnotationsChanged(myContext, (ProtoMethodEntity)m, d.annotations(), d.parameterAnnotations());
              if (actions.contains(AnnotationsChangeTracker.Recompile.USAGES)) {
                debug("Extension "+extension.getClass().getName()+" requested recompilation because of changes in annotations list --- affecting method usages");
              }
              if (actions.contains(AnnotationsChangeTracker.Recompile.SUBCLASSES)) {
                debug("Extension "+extension.getClass().getName()+" requested recompilation because of changes in method annotations or method parameter annotations list --- affecting subclasses");
              }
              toRecompile.addAll(actions);
            }

            if (toRecompile.contains(AnnotationsChangeTracker.Recompile.USAGES)) {
              myFuture.affectMethodUsages(m, propagated.get(), m.createUsage(myContext, it.name), usages, state.myDependants);
              if (m.isAbstract()) {
                final Collection<Pair<MethodRepr, ClassRepr>> overriding = new HashSet<>();
                myFuture.addOverridingMethods(m, it, it, MethodRepr.equalByJavaRules(m), overriding, null);
                for (Pair<MethodRepr, ClassRepr> p : overriding) {
                  usages.add(p.getFirst().createUsage(myContext, p.getSecond().name));
                  myFuture.appendDependents(p.getSecond(), state.myDependants);
                }
              }
              state.myAffectedUsages.addAll(usages);
              if (constrained) {
                // remove any constraints so that all usages of this method are recompiled
                for (UsageRepr.Usage usage : usages) {
                  state.myUsageConstraints.remove(usage);
                }
              }
            }
            if (toRecompile.contains(AnnotationsChangeTracker.Recompile.SUBCLASSES)) {
              myFuture.affectSubclasses(it.name, myAffectedFiles, state.myAffectedUsages, state.myDependants, false, myCompiledFiles, null);
            }

          }
        }
      }

      if (!moreAccessible.isEmpty()) {
        final Iterable<OverloadDescriptor> allOverloads = myFuture.findAllOverloads(it, mr -> {
          Integer result = null;
          for (Pair<MethodRepr, MethodRepr.Diff> pair : moreAccessible) {
            MethodRepr m = pair.first;
            MethodRepr.Diff d = pair.second;
            if (mr.name == m.name && !m.equals(mr)) {
              int newAccess = m.access & (~d.removedModifiers()) | d.addedModifiers();
              if (result == null || Difference.weakerAccess(result, newAccess)) {
                result = newAccess;
              }
            }
          }
          return result;
        });
        for (OverloadDescriptor descr : allOverloads) {

          debug("Method became more accessible --- affect usages of overloading methods: ", descr.overloadMethod.name);

          final Set<UsageRepr.Usage> overloadsUsages = new HashSet<>();
          myFuture.affectMethodUsages(
            descr.overloadMethod, myFuture.propagateMethodAccess(descr.overloadMethod, descr.overloadMethodOwner.name), descr.overloadMethod.createUsage(myContext, descr.overloadMethodOwner.name), overloadsUsages, state.myDependants
          );
          state.myAffectedUsages.addAll(overloadsUsages);
          final UsageConstraint constr = Difference.isPackageLocal(descr.accessScope)? myFuture.new PackageConstraint(it.getPackageName()).negate() :
                                         Difference.isProtected(descr.accessScope)? myFuture.new InheritanceConstraint(it).negate() : null;
          if (constr != null) {
            for (final UsageRepr.Usage usage : overloadsUsages) {
              state.myUsageConstraints.put(usage, constr);
            }
          }
        }
      }
      
      debug("End of changed methods processing");
    }
private void processChangedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it)