boolean (final DiffState state) { final Collection<Pair<ClassRepr, ClassRepr.Diff>> changedClasses = state.myClassDiff.changed(); if (!changedClasses.isEmpty()) { debug("Processing changed classes:"); assert myFuture != null; assert myPresent != null; final Util.FileFilterConstraint fileFilterConstraint = myFilter != null? myPresent.new FileFilterConstraint(myFilter) : null; for (final Pair<ClassRepr, ClassRepr.Diff> changed : changedClasses) { final ClassRepr changedClass = changed.first; final ClassRepr.Diff diff = changed.second; myDelta.addChangedClass(changedClass.name); debug("Changed: ", changedClass.name); final int addedModifiers = diff.addedModifiers(); final boolean superClassChanged = (diff.base() & Difference.SUPERCLASS) != 0; final boolean interfacesChanged = !diff.interfaces().unchanged(); final boolean signatureChanged = (diff.base() & Difference.SIGNATURE) != 0; if (superClassChanged) { myDelta.registerRemovedSuperClass(changedClass.name, changedClass.getSuperClass().className); for (ClassRepr newClass : myDelta.getReprsByName(changedClass.name, ClassRepr.class)) { myDelta.registerAddedSuperClass(changedClass.name, newClass.getSuperClass().className); } } if (interfacesChanged) { for (final TypeRepr.ClassType typ : diff.interfaces().removed()) { myDelta.registerRemovedSuperClass(changedClass.name, typ.className); } for (final TypeRepr.ClassType typ : diff.interfaces().added()) { myDelta.registerAddedSuperClass(changedClass.name, typ.className); } } if (myEasyMode) { continue; } final IntSet directDeps = myPresent.appendDependents(changedClass, state.myDependants); if (superClassChanged || interfacesChanged || signatureChanged) { debug("Superclass changed: ", superClassChanged); debug("Interfaces changed: ", interfacesChanged); debug("Signature changed ", signatureChanged); final boolean extendsChanged = superClassChanged && !diff.extendsAdded(); final boolean interfacesRemoved = interfacesChanged && !diff.interfaces().removed().isEmpty(); debug("Extends changed: ", extendsChanged); debug("Interfaces removed: ", interfacesRemoved); myFuture.affectSubclasses(changedClass.name, myAffectedFiles, state.myAffectedUsages, state.myDependants, extendsChanged || interfacesRemoved || signatureChanged, myCompiledFiles, null); if (extendsChanged && directDeps != null) { final TypeRepr.ClassType excClass = TypeRepr.createClassType(myContext, changedClass.name); directDeps.forEach(depClass -> { for (ClassRepr depClassRepr : myPresent.reprsByName(depClass, ClassRepr.class)) { myPresent.affectMethodUsagesThrowing(depClassRepr, excClass, state.myAffectedUsages, state.myDependants); } }); } if (!changedClass.isAnonymous()) { final IntSet parents = new IntOpenHashSet(); myPresent.collectSupersRecursively(changedClass.name, parents); final IntSet futureParents = new IntOpenHashSet(); myFuture.collectSupersRecursively(changedClass.name, futureParents); parents.removeAll(futureParents); parents.remove(myObjectClassName); if (!parents.isEmpty()) { parents.forEach(className -> { debug("Affecting usages in generic type parameter bounds of class: ", className); final UsageRepr.Usage usage = UsageRepr.createClassAsGenericBoundUsage(myContext, className); state.myAffectedUsages.add(usage); if (fileFilterConstraint != null) { state.myUsageConstraints.put(usage, fileFilterConstraint); } myPresent.appendDependents(className, state.myDependants); }); } } } if ((diff.addedModifiers() & Opcodes.ACC_INTERFACE) != 0 || (diff.removedModifiers() & Opcodes.ACC_INTERFACE) != 0) { debug("Class-to-interface or interface-to-class conversion detected, added class usage to affected usages"); state.myAffectedUsages.add(changedClass.createUsage()); } if (changedClass.isAnnotation() && changedClass.getRetentionPolicy() == RetentionPolicy.SOURCE) { debug("Annotation, retention policy = SOURCE => a switch to non-incremental mode requested"); if (!incrementalDecision(changedClass.getOuterClassName(), changedClass, myAffectedFiles, myFilesToCompile, myFilter)) { debug("End of Differentiate, returning false"); return false; } } if ((addedModifiers & Opcodes.ACC_PROTECTED) != 0) { debug("Introduction of 'protected' modifier detected, adding class usage + inheritance constraint to affected usages"); final UsageRepr.Usage usage = changedClass.createUsage(); state.myAffectedUsages.add(usage); state.myUsageConstraints.put(usage, myFuture.new InheritanceConstraint(changedClass)); } if (diff.packageLocalOn()) { debug("Introduction of 'package-private' access detected, adding class usage + package constraint to affected usages"); final UsageRepr.Usage usage = changedClass.createUsage(); state.myAffectedUsages.add(usage); state.myUsageConstraints.put(usage, myFuture.new PackageConstraint(changedClass.getPackageName())); } if ((addedModifiers & Opcodes.ACC_FINAL) != 0 || (addedModifiers & Opcodes.ACC_PRIVATE) != 0) { debug("Introduction of 'private' or 'final' modifier(s) detected, adding class usage to affected usages"); state.myAffectedUsages.add(changedClass.createUsage()); } if ((addedModifiers & Opcodes.ACC_ABSTRACT) != 0 || (addedModifiers & Opcodes.ACC_STATIC) != 0) { debug("Introduction of 'abstract' or 'static' modifier(s) detected, adding class new usage to affected usages"); state.myAffectedUsages.add(UsageRepr.createClassNewUsage(myContext, changedClass.name)); } if (!changedClass.isAnonymous() && !isEmpty(changedClass.getOuterClassName()) && !changedClass.isPrivate()) { if (addedModifiers != 0 || diff.removedModifiers() != 0) { debug("Some modifiers (access flags) were changed for non-private inner class, adding class usage to affected usages"); state.myAffectedUsages.add(changedClass.createUsage()); } } if (changedClass.isAnnotation()) { debug("Class is annotation, performing annotation-specific analysis"); if (diff.retentionChanged()) { debug("Retention policy change detected, adding class usage to affected usages"); state.myAffectedUsages.add(changedClass.createUsage()); } else if (diff.targetAttributeCategoryMightChange()) { debug("Annotation's attribute category in bytecode might be affected because of TYPE_USE or RECORD_COMPONENT target, adding class usage to affected usages"); state.myAffectedUsages.add(changedClass.createUsage()); } else { final Collection<ElemType> removedtargets = diff.targets().removed(); if (removedtargets.contains(ElemType.LOCAL_VARIABLE)) { debug("Removed target contains LOCAL_VARIABLE => a switch to non-incremental mode requested"); if (!incrementalDecision(changedClass.getOuterClassName(), changedClass, myAffectedFiles, myFilesToCompile, myFilter)) { debug("End of Differentiate, returning false"); return false; } } if (!removedtargets.isEmpty()) { debug("Removed some annotation targets, adding annotation query"); state.myAnnotationQuery.add((UsageRepr.AnnotationUsage)UsageRepr.createAnnotationUsage( myContext, TypeRepr.createClassType(myContext, changedClass.name), null, EnumSet.copyOf(removedtargets) )); } for (final MethodRepr m : diff.methods().added()) { if (!m.hasValue()) { debug("Added method with no default value: ", m.name); debug("Adding class usage to affected usages"); state.myAffectedUsages.add(changedClass.createUsage()); } } } debug("End of annotation-specific analysis"); } processAddedMethods(state, diff, changedClass); processRemovedMethods(state, diff, changedClass); processChangedMethods(state, diff, changedClass); if (!processAddedFields(state, diff, changedClass)) { return false; } if (!processRemovedFields(state, diff, changedClass)) { return false; } if (!processChangedFields(state, diff, changedClass)) { return false; } if ((diff.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.classAnnotationsChanged(myContext, changedClass, diff.annotations()); if (res.contains(AnnotationsChangeTracker.Recompile.USAGES)) { debug("Extension "+extension.getClass().getName()+" requested class usages recompilation because of changes in annotations list --- adding class usage to affected usages"); } if (res.contains(AnnotationsChangeTracker.Recompile.SUBCLASSES)) { debug("Extension "+extension.getClass().getName()+" requested subclasses recompilation because of changes in annotations list --- adding subclasses to affected usages"); } toRecompile.addAll(res); } final boolean recompileUsages = toRecompile.contains(AnnotationsChangeTracker.Recompile.USAGES); if (recompileUsages) { state.myAffectedUsages.add(changedClass.createUsage()); } if (toRecompile.contains(AnnotationsChangeTracker.Recompile.SUBCLASSES)) { myFuture.affectSubclasses(changedClass.name, myAffectedFiles, state.myAffectedUsages, state.myDependants, recompileUsages, myCompiledFiles, null); } } } debug("End of changed classes processing"); } return !myEasyMode; }