public boolean differentiate()

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;
    }