void (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { final Collection<MethodRepr> added = diff.methods().added(); if (added.isEmpty()) { return; } debug("Processing added methods: "); if (it.isAnnotation()) { debug("Class is annotation, skipping method analysis"); return; } assert myFuture != null; assert myPresent != null; assert myAffectedFiles != null; for (final MethodRepr m : added) { if (!m.isPrivate() && (it.isInterface() || it.isAbstract() || m.isAbstract())) { debug("Method: ", m.name); debug("Class is abstract, or is interface, or added non-private method is abstract => affecting all subclasses"); myFuture.affectSubclasses(it.name, myAffectedFiles, state.myAffectedUsages, state.myDependants, false, myCompiledFiles, null); break; } } if (it.isInterface()) { for (final MethodRepr m : added) { if (!m.isPrivate() && m.isAbstract()) { debug("Added non-private abstract method: ", m.name); myPresent.affectLambdaInstantiations(state, it.name); break; } } } for (final MethodRepr addedMethod : added) { debug("Method: ", addedMethod.name); final Supplier<IntSet> propagated = lazy(()-> myFuture.propagateMethodAccess(addedMethod, it.name)); if (!addedMethod.isPrivate() && addedMethod.myArgumentTypes.length > 0 && !myPresent.hasOverriddenMethods(it, MethodRepr.equalByJavaRules(addedMethod), null, it)) { debug("Conservative case on overriding methods, affecting method usages"); // do not propagate constructors access, since constructors are always concrete and not accessible via references to subclasses myFuture.affectMethodUsages(addedMethod, addedMethod.name == myInitName? null : propagated.get(), addedMethod.createMetaUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); } if (!addedMethod.isPrivate()) { if (addedMethod.isStatic()) { myFuture.affectStaticMemberOnDemandUsages(it.name, propagated.get(), state.myAffectedUsages, state.myDependants); } Predicate<MethodRepr> lessSpecificCond = myFuture.lessSpecific(addedMethod); final Collection<MethodRepr> removed = diff.methods().removed(); for (final MethodRepr lessSpecific : it.findMethods(lessSpecificCond)) { if (!lessSpecific.equals(addedMethod) && !removed.contains(lessSpecific)) { debug("Found less specific method, affecting method usages"); myFuture.affectMethodUsages(lessSpecific, propagated.get(), lessSpecific.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); } } debug("Processing overridden by specificity methods"); final Collection<Pair<MethodRepr, ClassRepr>> overridden = new HashSet<>(); myFuture.addOverriddenMethods(it, lessSpecificCond, overridden, null, it); for (final Pair<MethodRepr, ClassRepr> pair : overridden) { final MethodRepr method = pair.first; final ClassRepr methodClass = pair.second; if (methodClass == MOCK_CLASS) { continue; } debug("Method: ", method.name); debug("Class : ", methodClass.name); debug("Affecting method usages for that found"); myFuture.affectMethodUsages(method, myPresent.propagateMethodAccess(method, it.name), method.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); } debug("Processing overriding by specificity methods"); final Predicate<MethodRepr> overrides = MethodRepr.equalByJavaRules(addedMethod); final Collection<Pair<MethodRepr, ClassRepr>> overriding = new HashSet<>(); myFuture.addOverridingMethods(addedMethod, it, it, lessSpecificCond, overriding, null); for (final Pair<MethodRepr, ClassRepr> pair : overriding) { final MethodRepr method = pair.first; final ClassRepr methodClass = pair.second; debug("Method: ", method.name); debug("Class : ", methodClass.name); if (overrides.test(method)) { debug("Current method overrides the added method"); final Iterable<File> files = classToSourceFileGet(methodClass.name); if (files != null && !containsAll(myFilesToCompile, files)) { ContainerUtil.addAll(myAffectedFiles, files); if (myDebugS.isDebugEnabled()) { for (File file : files) { debug("Affecting file ", file); } } } } else { debug("Current method does not override the added method"); debug("Affecting method usages for the method"); myPresent.appendDependents(methodClass, state.myDependants); myFuture.affectMethodUsages(method, myPresent.propagateMethodAccess(method, methodClass.name), method.createUsage(myContext, methodClass.name), state.myAffectedUsages, state.myDependants); } } getAllSubclasses(it.name).forEach(subClass -> { Iterable<ClassRepr> reprs = Iterators.collect(myFuture.reprsByName(subClass, ClassRepr.class), new SmartList<>()); if (Iterators.isEmpty(reprs)) { return; } final Iterable<File> sourceFileNames = classToSourceFileGet(subClass); if (sourceFileNames != null && !containsAll(myCompiledFiles, sourceFileNames)) { for (ClassRepr outerClassRepr : Iterators.flat(Iterators.map(reprs, r -> isEmpty(r.getOuterClassName())? Collections.emptyList() : myFuture.reprsByName(r.getOuterClassName(), ClassRepr.class)))) { if (myFuture.isMethodVisible(outerClassRepr, addedMethod) || myFuture.extendsLibraryClass(outerClassRepr, null)) { ContainerUtil.addAll(myAffectedFiles, sourceFileNames); for (File sourceFileName : sourceFileNames) { debug("Affecting file due to local overriding: ", sourceFileName); } break; } } } }); } } debug("End of added methods processing"); }