void (final DiffState state, File fileName) { final Difference.Specifier<ModuleRepr, ModuleRepr.Diff> modulesDiff = state.myModulesDiff; if (modulesDiff.unchanged()) { return; } for (ModuleRepr moduleRepr : modulesDiff.added()) { myDelta.addChangedClass(moduleRepr.name); // need this for integrate // after module has been added, the whole target should be rebuilt // because necessary 'require' directives may be missing from the newly added module-info file myFuture.affectModule(moduleRepr, myAffectedFiles); } for (ModuleRepr removedModule : modulesDiff.removed()) { myDelta.addDeletedClass(removedModule, fileName); // need this for integrate myPresent.affectDependentModules(state, removedModule.name, null, true); } for (Pair<ModuleRepr, ModuleRepr.Diff> pair : modulesDiff.changed()) { final ModuleRepr moduleRepr = pair.first; final ModuleRepr.Diff d = pair.second; boolean affectSelf = false; boolean affectDeps = false; UsageConstraint constraint = null; myDelta.addChangedClass(moduleRepr.name); // need this for integrate if (d.versionChanged()) { final int version = moduleRepr.getVersion(); myPresent.affectDependentModules(state, moduleRepr.name, new UsageConstraint() { @Override public boolean checkResidence(int dep) { for (ModuleRequiresRepr requires : Iterators.flat(Iterators.map(myPresent.reprsByName(dep, ModuleRepr.class), depModule -> depModule.getRequires()))) { if (requires.name == moduleRepr.name && requires.getVersion() == version) { return true; } } return false; } }, false); } final Difference.Specifier<ModuleRequiresRepr, ModuleRequiresRepr.Diff> requiresDiff = d.requires(); for (ModuleRequiresRepr removed : requiresDiff.removed()) { affectSelf = true; if (removed.isTransitive()) { affectDeps = true; constraint = UsageConstraint.ANY; break; } } for (Pair<ModuleRequiresRepr, ModuleRequiresRepr.Diff> changed : requiresDiff.changed()) { affectSelf |= changed.second.versionChanged(); if (changed.second.becameNonTransitive()) { affectDeps = true; // we could have created more precise constraint here: analyze if required module (recursively) // has only qualified exports that include given module's name. But this seems to be excessive since // in most cases module's exports are unqualified, so that any other module can access the exported API. constraint = UsageConstraint.ANY; } } final Difference.Specifier<ModulePackageRepr, ModulePackageRepr.Diff> exportsDiff = d.exports(); if (!affectDeps) { for (ModulePackageRepr removedPackage : exportsDiff.removed()) { affectDeps = true; if (!removedPackage.isQualified()) { constraint = UsageConstraint.ANY; break; } for (Integer name : removedPackage.getModuleNames()) { final UsageConstraint matchName = UsageConstraint.exactMatch(name); if (constraint == null) { constraint = matchName; } else { constraint = constraint.or(matchName); } } } } if (!affectDeps || constraint != UsageConstraint.ANY) { for (Pair<ModulePackageRepr, ModulePackageRepr.Diff> p : exportsDiff.changed()) { final Collection<Integer> removedModuleNames = p.second.targetModules().removed(); affectDeps |= !removedModuleNames.isEmpty(); if (affectDeps) { for (Integer name : removedModuleNames) { final UsageConstraint matchName = UsageConstraint.exactMatch(name); if (constraint == null) { constraint = matchName; } else { constraint = constraint.or(matchName); } } } } } if (affectSelf) { myPresent.affectModule(moduleRepr, myAffectedFiles); } if (affectDeps) { myPresent.affectDependentModules(state, moduleRepr.name, constraint, true); } } }