boolean (DifferentiateContext context, JvmClass changedClass, Iterable<Difference.Change<JvmField, JvmField.Diff>> changed, Utils future, Utils present) { if (Iterators.isEmpty(changed)) { return true; } debug("Processing changed fields:"); for (Difference.Change<JvmField, JvmField.Diff> change : changed) { JvmField changedField = change.getPast(); JvmField.Diff diff = change.getDiff(); if (diff.unchanged()) { continue; } debug("Field: ", changedField.getName()); Iterable<JvmNodeReferenceID> propagated = Iterators.lazy(() -> future.collectSubclassesWithoutField(changedClass.getReferenceID(), changedField.getName())); JVMFlags addedFlags = diff.getAddedFlags(); JVMFlags removedFlags = diff.getRemovedFlags(); if (!changedField.isPrivate() && changedField.isInlinable() && changedField.getValue() != null) { // if the field was a compile-time constant boolean harmful = !Iterators.isEmpty(Iterators.filter(List.of(addedFlags, removedFlags), f -> f.isStatic() || f.isFinal())); if (harmful || diff.valueChanged() || diff.accessRestricted()) { if (context.getParams().isProcessConstantsIncrementally()) { debug("Potentially inlined field changed its access or value => affecting field usages and static member import usages"); affectMemberUsages(context, changedClass.getReferenceID(), changedField, propagated); affectStaticMemberImportUsages(context, changedClass.getReferenceID(), changedField.getName(), propagated); } else { debug("Potentially inlined field changed its access or value => a switch to non-incremental mode requested"); if (!affectOnNonIncrementalChange(context, changedClass.getReferenceID(), changedField, present)) { debug("End of Differentiate, returning false"); return false; } } } } if (diff.typeChanged() || diff.signatureChanged()) { debug("Type or signature changed --- affecting field usages"); affectMemberUsages(context, changedClass.getReferenceID(), changedField, propagated); } else if (diff.flagsChanged()) { if (addedFlags.isStatic() || removedFlags.isStatic() || addedFlags.isPrivate() || addedFlags.isVolatile()) { debug("Added/removed static modifier or added private/volatile modifier --- affecting field usages"); affectMemberUsages(context, changedClass.getReferenceID(), changedField, propagated); if (!changedField.isPrivate()) { if (addedFlags.isStatic()) { debug("Added static modifier --- affecting static member on-demand import usages"); affectStaticMemberOnDemandUsages(context, changedClass.getReferenceID(), propagated); } else if (removedFlags.isStatic()) { debug("Removed static modifier --- affecting static field import usages"); affectStaticMemberImportUsages(context, changedClass.getReferenceID(), changedField.getName(), propagated); } } } else { Predicate<Node<?, ?>> constraint = null; if (removedFlags.isPublic()) { debug("Removed public modifier, affecting field usages with appropriate constraint"); constraint = addedFlags.isProtected()? new InheritanceConstraint(future, changedClass) : new PackageConstraint(changedClass.getPackageName()); affectMemberUsages(context, changedClass.getReferenceID(), changedField, propagated, constraint); } else if (removedFlags.isProtected() && diff.accessRestricted()){ debug("Removed protected modifier and the field became less accessible, affecting field usages with package constraint"); constraint = new PackageConstraint(changedClass.getPackageName()); affectMemberUsages(context, changedClass.getReferenceID(), changedField, propagated, constraint); } if (addedFlags.isFinal()) { debug("Added final modifier --- affecting field assign usages"); affectUsages(context, "field assign", Iterators.flat(Iterators.asIterable(changedClass.getReferenceID()), propagated), id -> changedField.createAssignUsage(id.getNodeName()), constraint); } } } if (!diff.annotations().unchanged()) { // todo: AnnotationsTracker handling } } debug("End of changed fields processing"); return true; }