boolean (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { final Collection<Pair<FieldRepr, Difference>> changed = diff.fields().changed(); if (changed.isEmpty()) { return true; } debug("Processing changed fields:"); assert myFuture != null; assert myPresent != null; for (final Pair<FieldRepr, Difference> f : changed) { final Difference d = f.second; final FieldRepr field = f.first; debug("Field: ", field.name); final Supplier<IntSet> propagated = lazy(()-> myFuture.propagateFieldAccess(field.name, it.name)); // only if the field was a compile-time constant if (!field.isPrivate() && (field.access & INLINABLE_FIELD_MODIFIERS_MASK) == INLINABLE_FIELD_MODIFIERS_MASK && d.hadValue()) { final int changedModifiers = d.addedModifiers() | d.removedModifiers(); final boolean harmful = (changedModifiers & (Opcodes.ACC_STATIC | Opcodes.ACC_FINAL)) != 0; final boolean valueChanged = (d.base() & Difference.VALUE) != 0; if (harmful || valueChanged || d.accessRestricted()) { if (myProcessConstantsIncrementally) { debug("Potentially inlined field changed its access or value => affecting field usages and static member import usages"); myFuture.affectFieldUsages(field, propagated.get(), field.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); myFuture.affectStaticMemberImportUsages(field.name, it.name, propagated.get(), state.myAffectedUsages, state.myDependants); } else { debug("Potentially inlined field changed its access or value => a switch to non-incremental mode requested"); if (!incrementalDecision(it.name, field, myAffectedFiles, myFilesToCompile, myFilter)) { debug("End of Differentiate, returning false"); return false; } } } } if (d.base() != Difference.NONE) { if ((d.base() & Difference.TYPE) != 0 || (d.base() & Difference.SIGNATURE) != 0) { debug("Type or signature changed --- affecting field usages"); myFuture.affectFieldUsages( field, propagated.get(), field.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants ); } else if ((d.base() & Difference.ACCESS) != 0) { if ((d.addedModifiers() & Opcodes.ACC_STATIC) != 0 || (d.removedModifiers() & Opcodes.ACC_STATIC) != 0 || (d.addedModifiers() & Opcodes.ACC_PRIVATE) != 0 || (d.addedModifiers() & Opcodes.ACC_VOLATILE) != 0) { debug("Added/removed static modifier or added private/volatile modifier --- affecting field usages"); myFuture.affectFieldUsages( field, propagated.get(), field.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants ); if (!field.isPrivate()) { if ((d.addedModifiers() & Opcodes.ACC_STATIC) != 0) { 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) { debug("Removed static modifier --- affecting static field import usages"); myFuture.affectStaticMemberImportUsages(field.name, it.name, propagated.get(), state.myAffectedUsages, state.myDependants); } } } else { final Set<UsageRepr.Usage> usages = new HashSet<>(); if ((d.addedModifiers() & Opcodes.ACC_FINAL) != 0) { debug("Added final modifier --- affecting field assign usages"); myFuture.affectFieldUsages(field, propagated.get(), field.createAssignUsage(myContext, it.name), usages, state.myDependants); state.myAffectedUsages.addAll(usages); } if ((d.removedModifiers() & Opcodes.ACC_PUBLIC) != 0) { debug("Removed public modifier, affecting field usages with appropriate constraint"); myFuture.affectFieldUsages(field, propagated.get(), field.createUsage(myContext, it.name), usages, state.myDependants); state.myAffectedUsages.addAll(usages); for (final UsageRepr.Usage usage : usages) { if ((d.addedModifiers() & Opcodes.ACC_PROTECTED) != 0) { state.myUsageConstraints.put(usage, myFuture.new InheritanceConstraint(it)); } else { state.myUsageConstraints.put(usage, myFuture.new PackageConstraint(it.getPackageName())); } } } else if ((d.removedModifiers() & Opcodes.ACC_PROTECTED) != 0 && d.accessRestricted()) { debug("Removed protected modifier and the field became less accessible, affecting field usages with package constraint"); myFuture.affectFieldUsages(field, propagated.get(), field.createUsage(myContext, it.name), usages, state.myDependants); state.myAffectedUsages.addAll(usages); for (final UsageRepr.Usage usage : usages) { state.myUsageConstraints.put(usage, myFuture.new PackageConstraint(it.getPackageName())); } } } } 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> res = extension.fieldAnnotationsChanged(myContext, (ProtoFieldEntity)field, d.annotations()); if (res.contains(AnnotationsChangeTracker.Recompile.USAGES)) { debug("Extension "+extension.getClass().getName()+" requested recompilation because of changes in annotations list --- affecting field usages"); } if (res.contains(AnnotationsChangeTracker.Recompile.SUBCLASSES)) { debug("Extension "+extension.getClass().getName()+" requested recompilation because of changes in field annotations list --- affecting subclasses"); } toRecompile.addAll(res); } if (toRecompile.contains(AnnotationsChangeTracker.Recompile.USAGES)) { final Set<UsageRepr.Usage> usages = new HashSet<>(); myFuture.affectFieldUsages(field, propagated.get(), field.createUsage(myContext, it.name), usages, state.myDependants); state.myAffectedUsages.addAll(usages); // remove any constraints to ensure all field usages 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); } } } } debug("End of changed fields processing"); return true; }