void (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"); }