package org.jetbrains.ether.dependencyView; import org.codehaus.groovy.transform.DelegateASTTransformation; import org.jetbrains.ether.Pair; import org.jetbrains.ether.ProjectWrapper; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.lang.annotation.ElementType; import java.lang.annotation.RetentionPolicy; import java.util.*; /** * Created by IntelliJ IDEA. * User: db * Date: 28.01.11 * Time: 16:20 * To change this template use File | Settings | File Templates. */ public class Mappings { private static FoxyMap.CollectionConstructor<ClassRepr> classSetConstructor = new FoxyMap.CollectionConstructor<ClassRepr>() { public Collection<ClassRepr> create() { return new HashSet<ClassRepr>(); } }; private static FoxyMap.CollectionConstructor<UsageRepr.Usage> usageSetConstructor = new FoxyMap.CollectionConstructor<UsageRepr.Usage>() { public Collection<UsageRepr.Usage> create() { return new HashSet<UsageRepr.Usage>(); } }; private static FoxyMap.CollectionConstructor<StringCache.S> stringSetConstructor = new FoxyMap.CollectionConstructor<StringCache.S>() { public Collection<StringCache.S> create() { return new HashSet<StringCache.S>(); } }; private FoxyMap<StringCache.S, StringCache.S> classToSubclasses = new FoxyMap<StringCache.S, StringCache.S>(stringSetConstructor); private FoxyMap<StringCache.S, ClassRepr> sourceFileToClasses = new FoxyMap<StringCache.S, ClassRepr>(classSetConstructor); private Map<StringCache.S, UsageRepr.Cluster> sourceFileToUsages = new HashMap<StringCache.S, UsageRepr.Cluster>(); private FoxyMap<StringCache.S, UsageRepr.Usage> sourceFileToAnnotationUsages = new FoxyMap<StringCache.S, UsageRepr.Usage>(usageSetConstructor); private Map<StringCache.S, StringCache.S> classToSourceFile = new HashMap<StringCache.S, StringCache.S>(); private FoxyMap<StringCache.S, StringCache.S> fileToFileDependency = new FoxyMap<StringCache.S, StringCache.S>(stringSetConstructor); private FoxyMap<StringCache.S, StringCache.S> waitingForResolve = new FoxyMap<StringCache.S, StringCache.S>(stringSetConstructor); private Map<StringCache.S, StringCache.S> formToClass = new HashMap<StringCache.S, StringCache.S>(); private Map<StringCache.S, StringCache.S> classToForm = new HashMap<StringCache.S, StringCache.S>(); public void compensateRemovedContent(final Collection<StringCache.S> compiled) { for (StringCache.S name : compiled) { final Collection<ClassRepr> classes = sourceFileToClasses.foxyGet(name); if (classes == null) { sourceFileToClasses.put(name, new HashSet<ClassRepr>()); } } } private void propagateMemberAccessRec(final Collection<StringCache.S> acc, final boolean isField, final boolean root, final StringCache.S name, final StringCache.S reflcass) { final ClassRepr repr = reprByName(reflcass); if (repr != null) { if (!root) { final Collection members = isField ? repr.fields : repr.methods; for (Object o : members) { final ProtoMember m = (ProtoMember) o; if (m.name.equals(name)) { return; } } acc.add(reflcass); } final Collection<StringCache.S> subclasses = classToSubclasses.foxyGet(reflcass); if (subclasses != null) { for (StringCache.S subclass : subclasses) { propagateMemberAccessRec(acc, isField, false, name, subclass); } } } } private Collection<StringCache.S> propagateMemberAccess(final boolean isField, final StringCache.S name, final StringCache.S className) { final Set<StringCache.S> acc = new HashSet<StringCache.S>(); propagateMemberAccessRec(acc, isField, true, name, className); return acc; } private Collection<StringCache.S> propagateFieldAccess(final StringCache.S name, final StringCache.S className) { return propagateMemberAccess(true, name, className); } private Collection<StringCache.S> propagateMethodAccess(final StringCache.S name, final StringCache.S className) { return propagateMemberAccess(false, name, className); } private Collection<Pair<FieldRepr, ClassRepr>> findOverridenFields(final FieldRepr f, final ClassRepr c) { final Set<Pair<FieldRepr, ClassRepr>> result = new HashSet<Pair<FieldRepr, ClassRepr>>(); new Object() { public void run(final ClassRepr c) { final StringCache.S[] supers = c.getSupers(); for (StringCache.S succName : supers) { final ClassRepr r = reprByName(succName); if (r != null) { boolean cont = true; if (r.fields.contains(f)) { final FieldRepr ff = r.findField(f.name); if (ff != null) { if ((ff.access & Opcodes.ACC_PRIVATE) == 0) { result.add(new Pair<FieldRepr, ClassRepr>(ff, r)); cont = false; } } } if (cont) { run(r); } } } } }.run(c); return result; } private ClassRepr reprByName(final StringCache.S name) { final Collection<ClassRepr> reprs = sourceFileToClasses.foxyGet(classToSourceFile.get(name)); if (reprs != null) { for (ClassRepr repr : reprs) { if (repr.name.equals(name)) { return repr; } } } return null; } private boolean isInheritorOf(final StringCache.S who, final StringCache.S whom) { if (who.equals(whom)) { return true; } final ClassRepr repr = reprByName(who); if (repr != null) { for (StringCache.S s : repr.getSupers()) { if (isInheritorOf(s, whom)) { return true; } } } return false; } private void affectSubclasses(final StringCache.S className, final Set<StringCache.S> affectedFiles, final Set<UsageRepr.Usage> affectedUsages, final Set<StringCache.S> dependants, final boolean usages) { final StringCache.S fileName = classToSourceFile.get(className); if (usages) { affectedUsages.add(reprByName(className).createUsage()); } final Collection<StringCache.S> depFiles = fileToFileDependency.foxyGet(fileName); if (depFiles != null) { dependants.addAll(depFiles); } affectedFiles.add(fileName); final Collection<StringCache.S> directSubclasses = classToSubclasses.foxyGet(className); if (directSubclasses != null) { for (StringCache.S subClass : directSubclasses) { affectSubclasses(subClass, affectedFiles, affectedUsages, dependants, usages); } } } private void affectFieldUsages(final FieldRepr field, final Collection<StringCache.S> subclasses, final UsageRepr.Usage rootUsage, final Set<UsageRepr.Usage> affectedUsages, final Set<StringCache.S> dependents) { affectedUsages.add(rootUsage); for (StringCache.S p : subclasses) { dependents.addAll(fileToFileDependency.foxyGet(classToSourceFile.get(p))); affectedUsages.add(rootUsage instanceof UsageRepr.FieldAssignUsage ? field.createAssignUsage(p) : field.createUsage(p)); } } private void affectMethodUsages(final MethodRepr method, final Collection<StringCache.S> subclasses, final UsageRepr.Usage rootUsage, final Set<UsageRepr.Usage> affectedUsages, final Set<StringCache.S> dependents) { affectedUsages.add(rootUsage); for (StringCache.S p : subclasses) { dependents.addAll(fileToFileDependency.foxyGet(classToSourceFile.get(p))); affectedUsages.add(method.createUsage(p)); } } private void affectAll(final StringCache.S fileName, final Set<StringCache.S> affectedFiles) { final Set<StringCache.S> dependants = (Set<StringCache.S>) fileToFileDependency.foxyGet(fileName); if (dependants != null) { affectedFiles.addAll(dependants); } } private abstract class UsageConstraint { public abstract boolean checkResidence(final StringCache.S residence); } private class PackageConstraint extends UsageConstraint { public final String packageName; public PackageConstraint(final String packageName) { this.packageName = packageName; } @Override public boolean checkResidence(final StringCache.S residence) { return !ClassRepr.getPackageName(residence).equals(packageName); } } private class InheritanceConstraint extends UsageConstraint { public final StringCache.S rootClass; public InheritanceConstraint(final StringCache.S rootClass) { this.rootClass = rootClass; } @Override public boolean checkResidence(final StringCache.S residence) { return !isInheritorOf(residence, rootClass); } } private class NegationConstraint extends UsageConstraint { final UsageConstraint x; public NegationConstraint(UsageConstraint x) { this.x = x; } @Override public boolean checkResidence(final StringCache.S residence) { return !x.checkResidence(residence); } } private class IntersectionConstraint extends UsageConstraint { final UsageConstraint x; final UsageConstraint y; public IntersectionConstraint(final UsageConstraint x, final UsageConstraint y) { this.x = x; this.y = y; } @Override public boolean checkResidence(final StringCache.S residence) { return x.checkResidence(residence) && y.checkResidence(residence); } } 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; } public void integrate(final Mappings delta, final Set<StringCache.S> removed) { if (removed != null) { for (StringCache.S file : removed) { final Set<ClassRepr> classes = (Set<ClassRepr>) sourceFileToClasses.foxyGet(file); if (classes != null) { for (ClassRepr cr : classes) { classToSourceFile.remove(cr.fileName); } } sourceFileToClasses.remove(file); sourceFileToUsages.remove(file); fileToFileDependency.remove(file); } } classToSubclasses.putAll(delta.classToSubclasses); formToClass.putAll(delta.formToClass); classToForm.putAll(delta.classToForm); sourceFileToClasses.putAll(delta.sourceFileToClasses); sourceFileToUsages.putAll(delta.sourceFileToUsages); sourceFileToAnnotationUsages.putAll(delta.sourceFileToAnnotationUsages); classToSourceFile.putAll(delta.classToSourceFile); fileToFileDependency.putAll(delta.fileToFileDependency); } private void updateFormToClass(final StringCache.S formName, final StringCache.S className) { formToClass.put(formName, className); classToForm.put(className, formName); } private void updateSourceToUsages(final StringCache.S source, final UsageRepr.Cluster usages) { final UsageRepr.Cluster c = sourceFileToUsages.get(source); if (c == null) { sourceFileToUsages.put(source, usages); } else { c.updateCluster(usages); } } private void updateSourceToAnnotationUsages(final StringCache.S source, final Set<UsageRepr.Usage> usages) { sourceFileToAnnotationUsages.put(source, usages); } private void updateSourceToClasses(final StringCache.S source, final ClassRepr classRepr) { sourceFileToClasses.put(source, classRepr); } private void updateDependency(final StringCache.S a, final StringCache.S owner) { final StringCache.S sourceFile = classToSourceFile.get(owner); if (sourceFile == null) { waitingForResolve.put(owner, a); } else { fileToFileDependency.put(sourceFile, a); } } private void updateClassToSource(final StringCache.S className, final StringCache.S sourceName) { classToSourceFile.put(className, sourceName); final Set<StringCache.S> waiting = (Set<StringCache.S>) waitingForResolve.foxyGet(className); if (waiting != null) { for (StringCache.S f : waiting) { updateDependency(f, className); } waitingForResolve.remove(className); } } public Callbacks.Backend getCallback() { return new Callbacks.Backend() { public Collection<StringCache.S> getClassFiles() { return classToSourceFile.keySet(); } public void associate(final String classFileName, final Callbacks.SourceFileNameLookup sourceFileName, final ClassReader cr) { final StringCache.S classFileNameS = StringCache.get(project.getRelativePath(classFileName)); final Pair<ClassRepr, Pair<UsageRepr.Cluster, Set<UsageRepr.Usage>>> result = ClassfileAnalyzer.analyze(classFileNameS, cr); final ClassRepr repr = result.fst; final UsageRepr.Cluster localUsages = result.snd.fst; final Set<UsageRepr.Usage> localAnnotationUsages = result.snd.snd; final StringCache.S sourceFileNameS = StringCache.get(project.getRelativePath(sourceFileName.get(repr == null ? null : repr.getSourceFileName().value))); for (UsageRepr.Usage u : localUsages.getUsages()) { updateDependency(sourceFileNameS, u.getOwner()); } if (repr != null) { updateClassToSource(repr.name, sourceFileNameS); updateSourceToClasses(sourceFileNameS, repr); for (StringCache.S s : repr.getSupers()) { classToSubclasses.put(s, repr.name); } } if (!localUsages.isEmpty()) { updateSourceToUsages(sourceFileNameS, localUsages); } if (!localAnnotationUsages.isEmpty()) { updateSourceToAnnotationUsages(sourceFileNameS, localAnnotationUsages); } } public void associate(final Set<Pair<ClassRepr, Set<StringCache.S>>> classes, final Pair<UsageRepr.Cluster, Set<UsageRepr.Usage>> usages, final String sourceFileName) { final StringCache.S sourceFileNameS = StringCache.get(sourceFileName); updateSourceToUsages(sourceFileNameS, usages.fst); sourceFileToAnnotationUsages.put(sourceFileNameS, usages.snd); for (Pair<ClassRepr, Set<StringCache.S>> c : classes) { final ClassRepr r = c.fst; final Set<StringCache.S> s = c.snd; updateClassToSource(r.name, sourceFileNameS); classToSubclasses.put(r.name, s); sourceFileToClasses.put(sourceFileNameS, r); } for (UsageRepr.Usage u : usages.fst.getUsages()) { updateDependency(sourceFileNameS, u.getOwner()); } for (UsageRepr.Usage u : usages.snd) { updateDependency(sourceFileNameS, u.getOwner()); } } public void associateForm(StringCache.S formName, StringCache.S className) { updateFormToClass(formName, className); } }; } private final ProjectWrapper project; public Mappings(final ProjectWrapper p) { project = p; } public Set<ClassRepr> getClasses(final StringCache.S sourceFileName) { return (Set<ClassRepr>) sourceFileToClasses.foxyGet(sourceFileName); } public Set<StringCache.S> getSubClasses(final StringCache.S className) { return (Set<StringCache.S>) classToSubclasses.foxyGet(className); } public UsageRepr.Cluster getUsages(final StringCache.S sourceFileName) { final UsageRepr.Cluster result = sourceFileToUsages.get(sourceFileName); if (result == null) { return new UsageRepr.Cluster(); } return result; } public Set<UsageRepr.Usage> getAnnotationUsages(final StringCache.S sourceFileName) { return (Set<UsageRepr.Usage>) sourceFileToAnnotationUsages.foxyGet(sourceFileName); } public Set<StringCache.S> getFormClass(final StringCache.S formFileName) { final Set<StringCache.S> result = new HashSet<StringCache.S>(); final StringCache.S name = formToClass.get(formFileName); if (name != null) { result.add(name); } return result; } public StringCache.S getJavaByForm(final StringCache.S formFileName) { final StringCache.S classFileName = formToClass.get(formFileName); return classToSourceFile.get(classFileName); } public StringCache.S getFormByJava(final StringCache.S javaFileName) { final Set<ClassRepr> classes = getClasses(javaFileName); if (classes != null) { for (ClassRepr c : classes) { final StringCache.S formName = classToForm.get(c.name); if (formName != null) { return formName; } } } return null; } public void print() { try { final BufferedWriter w = new BufferedWriter(new FileWriter("dep.txt")); for (StringCache.S key : fileToFileDependency.keySet()) { final Set<StringCache.S> value = (Set<StringCache.S>) fileToFileDependency.foxyGet(key); w.write(key.value + " -->"); w.newLine(); if (value != null) { for (StringCache.S s : value) { if (s == null) w.write(" <null>"); else w.write(" " + s.value); w.newLine(); } } } w.close(); } catch (IOException e) { e.printStackTrace(); } } }