in src/org/jetbrains/ether/dependencyView/Mappings.java [283:612]
public boolean differentiate(final Mappings delta, final Set<StringCache.S> removed, final Set<StringCache.S> compiledFiles, final Set<StringCache.S> affectedFiles, final Set<StringCache.S> safeFiles) {
if (removed != null) {
for (StringCache.S file : removed) {
affectAll(file, affectedFiles);
}
}
for (StringCache.S fileName : delta.sourceFileToClasses.keySet()) {
if (safeFiles.contains(fileName)) {
continue;
}
final Set<ClassRepr> classes = (Set<ClassRepr>) delta.sourceFileToClasses.foxyGet(fileName);
final Set<ClassRepr> pastClasses = (Set<ClassRepr>) sourceFileToClasses.foxyGet(fileName);
final Set<StringCache.S> dependants = (Set<StringCache.S>) fileToFileDependency.foxyGet(fileName);
final Set<UsageRepr.Usage> affectedUsages = new HashSet<UsageRepr.Usage>();
final Set<UsageRepr.AnnotationUsage> annotationQuery = new HashSet<UsageRepr.AnnotationUsage>();
final Map<UsageRepr.Usage, UsageConstraint> usageConstraints = new HashMap<UsageRepr.Usage, UsageConstraint>();
final Difference.Specifier<ClassRepr> classDiff = Difference.make(pastClasses, classes);
for (Pair<ClassRepr, Difference> changed : classDiff.changed()) {
final ClassRepr it = changed.fst;
final ClassRepr.Diff diff = (ClassRepr.Diff) changed.snd;
final int addedModifiers = diff.addedModifiers();
final int removedModifiers = diff.removedModifiers();
final boolean superClassChanged = (diff.base() & Difference.SUPERCLASS) > 0;
final boolean interfacesChanged = !diff.interfaces().unchanged();
final boolean signatureChanged = (diff.base() & Difference.SIGNATURE) > 0;
if (superClassChanged || interfacesChanged || signatureChanged) {
final boolean extendsChanged = superClassChanged && !diff.extendsAdded();
final boolean interfacesRemoved = interfacesChanged && !diff.interfaces().removed().isEmpty();
affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, extendsChanged || interfacesRemoved || signatureChanged);
}
if ((diff.addedModifiers() & Opcodes.ACC_INTERFACE) > 0 ||
(diff.removedModifiers() & Opcodes.ACC_INTERFACE) > 0) {
affectedUsages.add(it.createUsage());
}
if (it.isAnnotation() && it.policy == RetentionPolicy.SOURCE) {
return false;
}
if ((addedModifiers & Opcodes.ACC_PROTECTED) > 0) {
final UsageRepr.Usage usage = it.createUsage();
affectedUsages.add(usage);
usageConstraints.put(usage, new InheritanceConstraint(it.name));
}
if (diff.packageLocalOn()) {
final UsageRepr.Usage usage = it.createUsage();
affectedUsages.add(usage);
usageConstraints.put(usage, new PackageConstraint(it.getPackageName()));
}
if ((addedModifiers & Opcodes.ACC_FINAL) > 0 ||
(addedModifiers & Opcodes.ACC_PRIVATE) > 0) {
affectedUsages.add(it.createUsage());
}
if ((addedModifiers & Opcodes.ACC_ABSTRACT) > 0) {
affectedUsages.add(UsageRepr.createClassNewUsage(it.name));
}
if ((addedModifiers & Opcodes.ACC_STATIC) > 0 ||
(removedModifiers & Opcodes.ACC_STATIC) > 0 ||
(addedModifiers & Opcodes.ACC_ABSTRACT) > 0
) {
affectedUsages.add(UsageRepr.createClassNewUsage(it.name));
}
if (it.isAnnotation()) {
if (diff.retentionChanged()) {
affectedUsages.add(it.createUsage());
} else {
final Collection<ElementType> removedtargets = diff.targets().removed();
if (removedtargets.contains(ElementType.LOCAL_VARIABLE)) {
return false;
}
if (!removedtargets.isEmpty()) {
annotationQuery.add((UsageRepr.AnnotationUsage) UsageRepr.createAnnotationUsage(TypeRepr.createClassType(it.name), null, removedtargets));
}
for (MethodRepr m : diff.methods().added()) {
if (!m.hasValue()) {
affectedUsages.add(it.createUsage());
}
}
}
}
for (MethodRepr m : diff.methods().added()) {
if ((it.access & Opcodes.ACC_INTERFACE) > 0 || (m.access & Opcodes.ACC_ABSTRACT) > 0) {
affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, false);
}
}
for (MethodRepr m : diff.methods().removed()) {
final Collection<StringCache.S> propagated = propagateMethodAccess(m.name, it.name);
affectMethodUsages(m, propagated, m.createUsage(it.name), affectedUsages, dependants);
affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, false);
}
for (Pair<MethodRepr, Difference> mr : diff.methods().changed()) {
final MethodRepr m = mr.fst;
final MethodRepr.Diff d = (MethodRepr.Diff) mr.snd;
final boolean throwsChanged = (d.exceptions().added().size() > 0) || (d.exceptions().changed().size() > 0);
if (it.isAnnotation()) {
if (d.defaultRemoved()) {
final List<StringCache.S> l = new LinkedList<StringCache.S>();
l.add(m.name);
annotationQuery.add((UsageRepr.AnnotationUsage) UsageRepr.createAnnotationUsage(TypeRepr.createClassType(it.name), l, null));
}
} else if (d.base() != Difference.NONE || throwsChanged) {
if (d.packageLocalOn()) {
final UsageRepr.Usage usage = m.createUsage(it.name);
affectedUsages.add(usage);
usageConstraints.put(usage, new PackageConstraint(it.getPackageName()));
}
final Collection<StringCache.S> propagated = propagateMethodAccess(m.name, it.name);
if ((d.base() & Difference.TYPE) > 0 || (d.base() & Difference.SIGNATURE) > 0 || throwsChanged) {
affectMethodUsages(m, propagated, m.createUsage(it.name), affectedUsages, dependants);
} 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) {
affectMethodUsages(m, propagated, m.createUsage(it.name), affectedUsages, dependants);
if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0) {
affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, false);
}
} else {
if ((d.addedModifiers() & Opcodes.ACC_FINAL) > 0 ||
(d.addedModifiers() & Opcodes.ACC_PUBLIC) > 0 ||
(d.addedModifiers() & Opcodes.ACC_ABSTRACT) > 0) {
affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, false);
}
if ((d.addedModifiers() & Opcodes.ACC_PROTECTED) > 0 && !((d.removedModifiers() & Opcodes.ACC_PRIVATE) > 0)) {
final Set<UsageRepr.Usage> usages = new HashSet<UsageRepr.Usage>();
affectMethodUsages(m, propagated, m.createUsage(it.name), usages, dependants);
for (UsageRepr.Usage u : usages) {
usageConstraints.put(u, new InheritanceConstraint(it.name));
}
affectedUsages.addAll(usages);
}
}
}
}
}
final int mask = Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
for (FieldRepr f : diff.fields().added()) {
final boolean fPrivate = (f.access & Opcodes.ACC_PRIVATE) > 0;
final boolean fProtected = (f.access & Opcodes.ACC_PROTECTED) > 0;
final boolean fPublic = (f.access & Opcodes.ACC_PUBLIC) > 0;
final boolean fPLocal = !fPrivate && !fProtected && !fPublic;
if (!fPrivate) {
final Collection<Pair<FieldRepr, ClassRepr>> overriden = findOverridenFields(f, it);
for (Pair<FieldRepr, ClassRepr> p : overriden) {
final FieldRepr ff = p.fst;
final ClassRepr cc = p.snd;
final boolean ffPrivate = (ff.access & Opcodes.ACC_PRIVATE) > 0;
final boolean ffProtected = (ff.access & Opcodes.ACC_PROTECTED) > 0;
final boolean ffPublic = (ff.access & Opcodes.ACC_PUBLIC) > 0;
final boolean ffPLocal = !ffPrivate && !ffProtected && !ffPublic;
if (!ffPrivate) {
final Collection<StringCache.S> propagated = propagateFieldAccess(ff.name, cc.name);
final Set<UsageRepr.Usage> localUsages = new HashSet<UsageRepr.Usage>();
affectFieldUsages(ff, propagated, ff.createUsage(cc.name), localUsages, dependants);
if ((fPublic && (ffPublic || ffPLocal)) || (fProtected && ffProtected) || (fPLocal && ffPLocal)) {
} else {
UsageConstraint constaint;
if ((ffProtected && fPublic) || (fProtected && ffPublic) || (ffPLocal && fProtected)) {
constaint = new NegationConstraint(new InheritanceConstraint(cc.name));
} else if (ffPublic && ffPLocal) {
constaint = new NegationConstraint(new PackageConstraint(cc.getPackageName()));
} else {
constaint = new IntersectionConstraint(
new NegationConstraint(new InheritanceConstraint(cc.name)),
new NegationConstraint(new PackageConstraint(cc.getPackageName()))
);
}
for (UsageRepr.Usage u : localUsages) {
usageConstraints.put(u, constaint);
}
}
affectedUsages.addAll(localUsages);
}
}
}
}
for (FieldRepr f : diff.fields().removed()) {
if ((f.access & mask) == mask && f.hasValue()) {
return false;
}
final Collection<StringCache.S> propagated = propagateFieldAccess(f.name, it.name);
affectFieldUsages(f, propagated, f.createUsage(it.name), affectedUsages, dependants);
}
for (Pair<FieldRepr, Difference> f : diff.fields().changed()) {
final Difference d = f.snd;
final FieldRepr field = f.fst;
if ((field.access & mask) == mask) {
if ((d.base() & Difference.ACCESS) > 0 || (d.base() & Difference.VALUE) > 0) {
return false;
}
}
if (d.base() != Difference.NONE) {
final Collection<StringCache.S> propagated = propagateFieldAccess(field.name, it.name);
if ((d.base() & Difference.TYPE) > 0 || (d.base() & Difference.SIGNATURE) > 0) {
affectFieldUsages(field, propagated, field.createUsage(it.name), affectedUsages, dependants);
} 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) {
affectFieldUsages(field, propagated, field.createUsage(it.name), affectedUsages, dependants);
} else {
if ((d.addedModifiers() & Opcodes.ACC_FINAL) > 0) {
affectFieldUsages(field, propagated, field.createAssignUsage(it.name), affectedUsages, dependants);
}
if ((d.addedModifiers() & Opcodes.ACC_PROTECTED) > 0 && (d.removedModifiers() & Opcodes.ACC_PUBLIC) > 0) {
final Set<UsageRepr.Usage> usages = new HashSet<UsageRepr.Usage>();
affectFieldUsages(field, propagated, field.createUsage(it.name), usages, dependants);
for (UsageRepr.Usage u : usages) {
usageConstraints.put(u, new InheritanceConstraint(it.name));
}
affectedUsages.addAll(usages);
}
}
}
}
}
}
for (ClassRepr c : classDiff.removed()) {
affectedUsages.add(c.createUsage());
}
if (dependants != null) {
dependants.removeAll(compiledFiles);
filewise:
for (StringCache.S depFile : dependants) {
if (affectedFiles.contains(depFile)) {
continue filewise;
}
final UsageRepr.Cluster depCluster = sourceFileToUsages.get(depFile);
final Set<UsageRepr.Usage> depUsages = depCluster.getUsages();
if (depUsages != null) {
final Set<UsageRepr.Usage> usages = new HashSet<UsageRepr.Usage>(depUsages);
usages.retainAll(affectedUsages);
if (!usages.isEmpty()) {
for (UsageRepr.Usage usage : usages) {
final UsageConstraint constraint = usageConstraints.get(usage);
if (constraint == null) {
affectedFiles.add(depFile);
continue filewise;
} else {
final Set<StringCache.S> residenceClasses = depCluster.getResidence(usage);
for (StringCache.S residentName : residenceClasses) {
if (constraint.checkResidence(residentName)) {
affectedFiles.add(depFile);
continue filewise;
}
}
}
}
}
if (annotationQuery.size() > 0) {
final Collection<UsageRepr.Usage> annotationUsages = sourceFileToAnnotationUsages.foxyGet(depFile);
for (UsageRepr.Usage usage : annotationUsages) {
for (UsageRepr.AnnotationUsage query : annotationQuery) {
if (query.satisfies(usage)) {
affectedFiles.add(depFile);
continue filewise;
}
}
}
}
}
}
}
}
return true;
}