| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package org.apache.royale.compiler.internal.projects; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.locks.ReadWriteLock; |
| import java.util.concurrent.locks.ReentrantReadWriteLock; |
| |
| import org.apache.royale.compiler.common.DependencyType; |
| import org.apache.royale.compiler.common.DependencyTypeSet; |
| import org.apache.royale.compiler.exceptions.CircularDependencyException; |
| import org.apache.royale.compiler.internal.graph.Graph; |
| import org.apache.royale.compiler.internal.graph.GraphEdge; |
| import org.apache.royale.compiler.internal.graph.TopologicalSort; |
| import org.apache.royale.compiler.internal.units.CompilationUnitBase; |
| import org.apache.royale.compiler.internal.units.EmbedCompilationUnit; |
| import org.apache.royale.compiler.internal.units.InvisibleCompilationUnit; |
| import org.apache.royale.compiler.units.ICompilationUnit; |
| import com.google.common.base.Function; |
| import com.google.common.collect.Collections2; |
| |
| /** |
| * Class to track dependencies in a {@link CompilerProject}. |
| * <p> |
| * There are four types of dependency that may exist from one |
| * {@link ICompilationUnit} to another {@link ICompilationUnit}. |
| * <dl> |
| * <dt>Inheritance Dependency</dt> |
| * <dd>If {@link ICompilationUnit} A contains a definition that extends a class |
| * or implements an interface defined in {@link ICompilationUnit} B, then there |
| * is an inheritance dependency from A to B.</dd> |
| * <dt>Signature Dependency</dt> |
| * <dd>If any of: |
| * <ul> |
| * <li>class member variable ( or constant ) type annotation expression</li> |
| * <li>class method return type annotation expression</li> |
| * <li>class method parameter type annotation expression</li> |
| * <li>script variable ( or constant ) type annotation expression</li> |
| * <li>script function return type annotation expression</li> |
| * <li>script function parameter type annotation expression</li> |
| * </ul> |
| * in {@link ICompilationUnit} A refers to a definition from |
| * {@link ICompilationUnit} B, then there is a signature dependency from A to B. |
| * </dd> |
| * <dt>Namespace Dependency</dt> |
| * <dd>If {@link ICompilationUnit} A depends on a namespace definition from |
| * {@link ICompilationUnit} B, then there is a namespace dependency from A to B. |
| * </dd> |
| * </dl> |
| * <dt>Expression Dependency</dt> |
| * <dd>If {@link ICompilationUnit} A contains any reference to |
| * {@link ICompilationUnit} B that does not result in any other type of |
| * dependency, then there exists an expression dependency from A to B.</dd> |
| * </dl> |
| * <p> |
| * The code in this class intends to make adding or updating a dependency edge |
| * very fast and thread safe. |
| */ |
| public final class DependencyGraph |
| { |
| public static final class Dependency implements Comparable<Dependency> |
| { |
| public String qname; |
| public DependencyType type; |
| |
| public Dependency(String qname, DependencyType type) |
| { |
| this.qname = qname; |
| this.type = type; |
| } |
| |
| @Override |
| public int compareTo(Dependency o) |
| { |
| return qname.compareTo(o.qname); |
| } |
| |
| @Override |
| public boolean equals(Object o) |
| { |
| if(o instanceof Dependency) |
| { |
| Dependency other = (Dependency)o; |
| return other.qname.equals(qname); |
| } |
| else |
| { |
| return super.equals(o); |
| } |
| } |
| |
| @Override |
| public int hashCode() |
| { |
| return qname.hashCode(); |
| } |
| } |
| |
| /** |
| * Class to hold information about an edge in the DependencyGraph. |
| */ |
| static final class Edge extends GraphEdge<ICompilationUnit> implements Comparable<Edge> |
| { |
| private Map<String, DependencyTypeSet> dependencies; |
| private DependencyTypeSet dependencySet; |
| |
| /** |
| * @param referencingCompilationUnit |
| * @param declaringCompilationUnit |
| */ |
| |
| private Edge(ICompilationUnit referencingCompilationUnit, ICompilationUnit declaringCompilationUnit) |
| { |
| super(referencingCompilationUnit, declaringCompilationUnit); |
| |
| assert (!(referencingCompilationUnit instanceof InvisibleCompilationUnit)) : "InvisibleCompilationUnit should never have an edge"; |
| assert (!(declaringCompilationUnit instanceof InvisibleCompilationUnit)): "InvisibleCompilationUnit should never have an edge"; |
| |
| this.dependencySet = DependencyTypeSet.noneOf(); |
| this.dependencies = new HashMap<String, DependencyTypeSet>(); |
| } |
| |
| /** |
| */ |
| public boolean getIsInheritanceDependency() |
| { |
| return dependencySet.contains(DependencyType.INHERITANCE); |
| } |
| |
| /** |
| */ |
| public boolean getIsSignatureDependency() |
| { |
| return dependencySet.contains(DependencyType.SIGNATURE); |
| } |
| |
| /** |
| */ |
| public boolean getIsNamespaceDependency() |
| { |
| return dependencySet.contains(DependencyType.NAMESPACE); |
| } |
| |
| /** |
| */ |
| public boolean getIsExpressionDependency() |
| { |
| return dependencySet.contains(DependencyType.EXPRESSION); |
| } |
| /** |
| * @param set A set of dependencies |
| * @return True if any of the union of the parameter set and this Edge's dependencySet is non-null. |
| * |
| */ |
| public boolean typeInSet(DependencyTypeSet set) |
| { |
| for (DependencyType t : set) |
| { |
| if (dependencySet.contains(t)) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Adds a dependency of a {@link DependencyType} on a definition |
| * with qname to this Edge. |
| * |
| * @param qname The definition qualified name that is depended on |
| * @param types {@link DependencyType}'s to add to this edge. |
| */ |
| private void addDependency(String qname, DependencyTypeSet types) |
| { |
| DependencyTypeSet typeSet = dependencies.get(qname); |
| if(typeSet != null) |
| { |
| DependencyTypeSet newTypeSet = DependencyTypeSet.copyOf(typeSet); |
| newTypeSet.addAll(types); |
| this.dependencies.put(qname, newTypeSet); |
| } |
| else |
| { |
| this.dependencies.put(qname, DependencyTypeSet.copyOf(types)); |
| } |
| dependencySet.addAll(types); |
| } |
| |
| /** |
| * Adds a dependency of a {@link DependencyType} on a definition |
| * with qname to this Edge. |
| * |
| * @param qname The definition qualified name that is depended on |
| * @param type {@link DependencyType} to add to this edge. |
| */ |
| private void addDependency(String qname, DependencyType type) |
| { |
| DependencyTypeSet typeSet = dependencies.get(qname); |
| if (typeSet != null) |
| { |
| DependencyTypeSet newTypeSet = DependencyTypeSet.copyOf(typeSet); |
| newTypeSet.add(type); |
| this.dependencies.put(qname, newTypeSet); |
| } |
| else |
| { |
| this.dependencies.put(qname, DependencyTypeSet.of(type)); |
| } |
| dependencySet.add(type); |
| } |
| |
| /** |
| * Adds an anonymous dependency of a {@link DependencyType} on a definition |
| * to this Edge. |
| * @param type {@link DependencyType}'s to add to this edge. |
| */ |
| private void addDependency(DependencyType type) |
| { |
| dependencySet.add(type); |
| } |
| |
| // Adding toString method for debugging. |
| @Override |
| public String toString() |
| { |
| String result = getFrom().getName() + " -> " + getTo().getName() + " [ "; |
| if (getIsInheritanceDependency()) |
| result += "inheritance "; |
| if (getIsSignatureDependency()) |
| result += "signature "; |
| if (getIsNamespaceDependency()) |
| result += "namespace "; |
| if (getIsExpressionDependency()) |
| result += "expression "; |
| result += "]"; |
| return result; |
| } |
| |
| /** |
| * @return A map of all named dependee qnames of this edge to the |
| * {@link DependencyType} that they depend on. |
| */ |
| |
| public Map<String, DependencyTypeSet> getNamedDependencies() |
| { |
| return this.dependencies; |
| } |
| |
| @Override |
| public int compareTo(Edge edge2) |
| { |
| // First compare the names of the "from" compilation units. |
| int fromCompare = getFrom().getName().compareTo(edge2.getFrom().getName()); |
| if (fromCompare == 0) |
| { |
| // Then compare the names of the "to" compilation units. |
| return getTo().getName().compareTo(edge2.getTo().getName()); |
| } |
| else |
| { |
| return fromCompare; |
| } |
| } |
| |
| public DependencyTypeSet getAllDependencies() |
| { |
| return dependencySet; |
| } |
| } |
| |
| private Edge getEdge(ICompilationUnit referencingCompilationUnit, ICompilationUnit declaringCompilationUnit) |
| { |
| Edge result = graph.getEdge(referencingCompilationUnit, declaringCompilationUnit); |
| if (result == null) |
| { |
| result = new Edge(referencingCompilationUnit, declaringCompilationUnit); |
| graph.setEdge(result); |
| } |
| return result; |
| } |
| |
| /** |
| * Default constructor |
| */ |
| public DependencyGraph() |
| { |
| graph = new Graph<ICompilationUnit, Edge>(); |
| lock = new ReentrantReadWriteLock(); |
| } |
| |
| private final Graph<ICompilationUnit, Edge> graph; |
| private final ReadWriteLock lock; |
| |
| /** |
| * Adds a dependency to the dependency graph. |
| * |
| * @param depender {@link ICompilationUnit} with a reference to a definition |
| * defined by the other {@link ICompilationUnit}. |
| * @param dependee {@link ICompilationUnit} with a definition referred to by |
| * the other {@link ICompilationUnit}. |
| * @param dt The dependency types to add from the "depender" to the "dependee". |
| * @param targetQName A qname of the definition of the dependee that the depender depends on |
| */ |
| public void addDependency(ICompilationUnit depender, |
| ICompilationUnit dependee, |
| DependencyTypeSet dt, String targetQName) |
| { |
| // The compiler does not record self references in the same compilation unit. |
| if (depender == dependee) |
| return; |
| |
| assert !dependee.isInvisible() |
| : "invisible units do not export symbols to the project scope, so nothing should depend one them."; |
| |
| assert (!(depender instanceof InvisibleCompilationUnit)) |
| : "depender should only ever be an InvisibleCompilationUnit delegate, never an InvisibleCompilationUnit"; |
| |
| lock.writeLock().lock(); |
| try |
| { |
| Edge e = getEdge(depender, dependee); |
| e.addDependency(targetQName, dt); |
| } |
| finally |
| { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * Adds a dependency to the dependency graph. |
| * |
| * @param depender {@link ICompilationUnit} with a reference to a definition |
| * defined by the other {@link ICompilationUnit}. |
| * @param dependee {@link ICompilationUnit} with a definition referred to by |
| * the other {@link ICompilationUnit}. |
| * @param dt The type of dependency to add from the "depender" to the "dependee". |
| * @param targetQName A qname of the definition of the dependee that the depender depends on |
| */ |
| public void addDependency(ICompilationUnit depender, |
| ICompilationUnit dependee, |
| DependencyType dt, String targetQName) |
| { |
| // The compiler does not record self references in the same compilation unit. |
| if (depender == dependee) |
| return; |
| |
| assert !dependee.isInvisible() |
| : "invisible units do not export symbols to the project scope, so nothing should depend one them."; |
| |
| if (depender instanceof InvisibleCompilationUnit) |
| depender = ((InvisibleCompilationUnit)depender).getDelegate(); |
| |
| lock.writeLock().lock(); |
| try |
| { |
| Edge e = getEdge(depender, dependee); |
| e.addDependency(targetQName, dt); |
| } |
| finally |
| { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * Adds an anonymous dependency to the dependency graph. |
| * |
| * @param depender {@link ICompilationUnit} with a reference to a definition |
| * defined by the other {@link ICompilationUnit}. |
| * @param dependee {@link ICompilationUnit} with a definition referred to by |
| * the other {@link ICompilationUnit}. |
| * @param dt The type of dependency to add from the "depender" to the "dependee". |
| */ |
| public void addDependency(ICompilationUnit depender, |
| ICompilationUnit dependee, |
| DependencyType dt) |
| { |
| // The compiler does not record self references in the same compilation unit. |
| if (depender == dependee) |
| return; |
| |
| assert !dependee.isInvisible() |
| : "invisible units do not export symbols to the project scope, so nothing should depend one them."; |
| |
| if (depender instanceof InvisibleCompilationUnit) |
| depender = ((InvisibleCompilationUnit)depender).getDelegate(); |
| |
| lock.writeLock().lock(); |
| try |
| { |
| Edge e = getEdge(depender, dependee); |
| e.addDependency(dt); |
| } |
| finally |
| { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * Remove all of the outgoing dependencies on a compilation unit. |
| * |
| * @param cu The compilation to remove dependencies from. |
| */ |
| public void removeDependencies(ICompilationUnit cu) |
| { |
| Set<Edge> edges = getOutgoingEdges(cu); |
| for (final Edge edge : edges) |
| { |
| removeDependency(cu, edge.getTo()); |
| } |
| } |
| |
| /** |
| * Remove a dependency in the dependency graph. |
| * |
| * @param depender {@link ICompilationUnit} with a reference to a definition |
| * defined by the other {@link ICompilationUnit}. |
| * @param dependee {@link ICompilationUnit} with a definition referred to by |
| * the other {@link ICompilationUnit}. |
| */ |
| private void removeDependency(ICompilationUnit depender, |
| ICompilationUnit dependee) |
| { |
| // The compiler does not record self references in the same compilation unit. |
| if (depender == dependee) |
| return; |
| |
| assert !dependee.isInvisible() |
| : "invisible units do not export symbols to the project scope, so nothing should depend one them."; |
| |
| if (depender instanceof InvisibleCompilationUnit) |
| depender = ((InvisibleCompilationUnit)depender).getDelegate(); |
| |
| lock.writeLock().lock(); |
| try |
| { |
| Edge e = getEdge(depender, dependee); |
| graph.removeEdge(e); |
| } |
| finally |
| { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * Computes the list of all {@link ICompilationUnit}'s that the specified |
| * collection of {@link ICompilationUnit}'s depends directly or indirectly. |
| * {@link ICompilationUnit}'s that contain definitions that extend or |
| * implement definitions from other {@link ICompilationUnit}'s will occur in |
| * the list after the {@link ICompilationUnit}'s that contains the |
| * definitions that are extended or implemented. |
| * |
| * In cases where {@link ICompilationUnit}s have no real dependencies between |
| * them this function employs a lexical sort on the {@link ICompilationUnit}'s |
| * name. |
| * |
| * @param roots Collection of {@link ICompilationUnit}'s that will be in the |
| * returned List along with any {@link ICompilationUnit}'s they depend on |
| * directly or indirectly. |
| * @return List of all {@link ICompilationUnit}'s that the specified |
| * collection of {@link ICompilationUnit}'s depends directly or indirectly. |
| */ |
| public List<ICompilationUnit> topologicalSort(Collection<ICompilationUnit> roots) |
| { |
| return topologicalSort(roots, new Comparator<ICompilationUnit>() |
| { |
| @Override |
| public int compare(ICompilationUnit o1, ICompilationUnit o2) |
| { |
| return o1.getName().compareTo(o2.getName()); |
| } |
| }); |
| } |
| |
| /** |
| * Computes the list of all {@link ICompilationUnit}'s that the specified |
| * collection of {@link ICompilationUnit}'s depends directly or indirectly. |
| * {@link ICompilationUnit}'s that contain definitions that extend or |
| * implement definitions from other {@link ICompilationUnit}'s will occur in |
| * the list after the {@link ICompilationUnit}'s that contains the |
| * definitions that are extended or implemented. |
| * |
| * @param roots Collection of {@link ICompilationUnit}'s that will be in the |
| * returned List along with any {@link ICompilationUnit}'s they depend on |
| * directly or indirectly. |
| * @param comparator The comparator of last resort used to order |
| * {@link ICompilationUnit}s when there are no real dependencies between them. |
| * @return List of all {@link ICompilationUnit}'s that the specified |
| * collection of {@link ICompilationUnit}'s depends directly or indirectly. |
| */ |
| public List<ICompilationUnit> topologicalSort(Collection<ICompilationUnit> roots, final Comparator<ICompilationUnit> comparator) |
| { |
| lock.readLock().lock(); |
| try |
| { |
| final ArrayList<ICompilationUnit> sortedList = new ArrayList<ICompilationUnit>(graph.getVertices().size()); |
| TopologicalSort.IVisitor<ICompilationUnit, Edge> visitor = |
| new TopologicalSort.IVisitor<ICompilationUnit, Edge>() |
| { |
| @Override |
| public void visit(ICompilationUnit v) |
| { |
| assert v != null; // this might mean there was some race condidition... |
| sortedList.add(v); |
| } |
| |
| @Override |
| public boolean isTopologicalEdge(Edge e) |
| { |
| return e.getIsInheritanceDependency(); |
| } |
| |
| @Override |
| public int compare(ICompilationUnit a, ICompilationUnit b) |
| { |
| return comparator.compare(a, b); |
| } |
| }; |
| try |
| { |
| TopologicalSort.sort(graph, roots, visitor); |
| } |
| catch (CircularDependencyException e1) |
| { |
| assert false : "CircularDependencyException"; |
| } |
| return sortedList; |
| } |
| finally |
| { |
| lock.readLock().unlock(); |
| } |
| } |
| |
| /** |
| * Computes the set of {@link ICompilationUnit}'s that should be cleaned |
| * given a collection of {@link ICompilationUnit}'s that are known to need |
| * cleaning. |
| * <p> |
| * This method is not thread safe and must not be called while any |
| * compilation is occurring in any project in the workspace associated with |
| * the specified compilation units. |
| * |
| * @param roots {@link ICompilationUnit}'s that are known to need cleaning |
| * @return Set of {@link ICompilationUnit}'s that should be cleaned. |
| */ |
| public static Set<ICompilationUnit> computeInvalidationSet(Iterable<ICompilationUnit> roots) |
| { |
| |
| HashSet<ICompilationUnit> result = new HashSet<ICompilationUnit>(); |
| LinkedList<Edge> workList = new LinkedList<Edge>(); |
| for (ICompilationUnit unit : roots) |
| { |
| assert unit instanceof CompilationUnitBase; |
| CompilationUnitBase compilationUnit = (CompilationUnitBase)unit; |
| boolean alreadyVisited = !result.add(compilationUnit); |
| if (!alreadyVisited) |
| workList.addAll(compilationUnit.getProject().getDependencyGraph().getIncomingEdges(compilationUnit)); |
| } |
| DependencyTypeSet recursiveInvalidationSet = DependencyTypeSet.of(DependencyType.INHERITANCE, DependencyType.SIGNATURE, DependencyType.NAMESPACE); |
| HashSet<Edge> visitedEdges = new HashSet<Edge>(); |
| while (!workList.isEmpty()) |
| { |
| Edge currentEdge = workList.pop(); |
| if (visitedEdges.add(currentEdge)) |
| { |
| assert currentEdge.getFrom() instanceof CompilationUnitBase; |
| CompilationUnitBase dependentUnit = (CompilationUnitBase)currentEdge.getFrom(); |
| result.add(dependentUnit); |
| if (currentEdge.typeInSet(recursiveInvalidationSet)) |
| workList.addAll(dependentUnit.getProject().getDependencyGraph().getIncomingEdges(dependentUnit)); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Add a {@link ICompilationUnit} to the dependency graph. |
| * @param cu {@link ICompilationUnit} to add to the dependency graph |
| */ |
| public void addCompilationUnit(ICompilationUnit cu) |
| { |
| if (cu instanceof InvisibleCompilationUnit) |
| cu = ((InvisibleCompilationUnit)cu).getDelegate(); |
| |
| lock.writeLock().lock(); |
| try |
| { |
| graph.addVertex(cu); |
| } |
| finally |
| { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * Add a Collection of {@link ICompilationUnit}'s to the dependency graph. |
| * @param c Collection of {@link ICompilationUnit}'s to add to the dependency graph |
| */ |
| public void addCompilationUnits(Collection<ICompilationUnit> c) |
| { |
| Collection<ICompilationUnit> transformed = Collections2.transform(c, new Function<ICompilationUnit, ICompilationUnit>() { |
| @Override |
| public ICompilationUnit apply(ICompilationUnit input) |
| { |
| if (input instanceof InvisibleCompilationUnit) |
| return ((InvisibleCompilationUnit)input).getDelegate(); |
| else |
| return input; |
| }}); |
| |
| lock.writeLock().lock(); |
| try |
| { |
| graph.addVertices(transformed); |
| } |
| finally |
| { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * Removes an {@link ICompilationUnit} from the dependency graph. |
| */ |
| public void removeCompilationUnit(ICompilationUnit cu) |
| { |
| if (cu instanceof InvisibleCompilationUnit) |
| cu = ((InvisibleCompilationUnit)cu).getDelegate(); |
| |
| lock.writeLock().lock(); |
| try |
| { |
| graph.removeVertex(cu); |
| } |
| finally |
| { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| Set<Edge> getOutgoingEdges(ICompilationUnit cu) |
| { |
| if (cu instanceof InvisibleCompilationUnit) |
| cu = ((InvisibleCompilationUnit)cu).getDelegate(); |
| |
| lock.readLock().lock(); |
| try |
| { |
| Set<Edge> edges = graph.getOutgoingEdges(cu); |
| return edges; |
| } |
| finally |
| { |
| lock.readLock().unlock(); |
| } |
| } |
| |
| Set<Edge> getIncomingEdges(ICompilationUnit cu) |
| { |
| if (cu instanceof InvisibleCompilationUnit) |
| cu = ((InvisibleCompilationUnit)cu).getDelegate(); |
| |
| lock.readLock().lock(); |
| try |
| { |
| Set<Edge> edges = graph.getIncomingEdges(cu); |
| return edges; |
| } |
| finally |
| { |
| lock.readLock().unlock(); |
| } |
| } |
| |
| /** |
| * Get the Set of {@link ICompilationUnit}'s depended on directly by the specified {@link ICompilationUnit}. |
| * @param cu {@link ICompilationUnit} whose set of direct dependencies will be returned. |
| * @return A new Set of {@link ICompilationUnit}'s that the specified {@link ICompilationUnit} directly depends on. |
| */ |
| public Set<ICompilationUnit> getDirectDependencies(ICompilationUnit cu) |
| { |
| Set<Edge> outgoingEdges = getOutgoingEdges(cu); |
| Set<ICompilationUnit> result = new HashSet<ICompilationUnit>(outgoingEdges.size()); |
| for (Edge e : outgoingEdges) |
| { |
| result.add(e.getTo()); |
| } |
| return result; |
| } |
| |
| /** |
| * Get the Set of {@link ICompilationUnit}'s that directly depended on the specified {@link ICompilationUnit}. |
| * @param cu A compilation unit. |
| * @param types Set of dependency types used to filter the returned set of {@link ICompilationUnit}'s. |
| * @return A new Set of {@link ICompilationUnit}'s that directly depend on the |
| * specified {@link ICompilationUnit}. |
| */ |
| public Set<ICompilationUnit> getDirectReverseDependencies(ICompilationUnit cu, DependencyTypeSet types) |
| { |
| Set<Edge> incomingEdges = getIncomingEdges(cu); |
| Set<ICompilationUnit> result = new HashSet<ICompilationUnit>(incomingEdges.size()); |
| for (Edge e : incomingEdges) |
| { |
| if (e.typeInSet(types)) |
| result.add(e.getFrom()); |
| } |
| return result; |
| } |
| |
| /** |
| * Adds an {@link EmbedCompilationUnit} to the dependency graph. |
| * This is just like adding any other compilation unit, except |
| * for the fact that we may be in the middle of compiling a project. |
| * Thus, when we add an embed compilation unit we grab the dependency graph |
| * write lock. |
| * @param unit The embed compilation unit to be added. |
| */ |
| public void addEmbedCompilationUnit(EmbedCompilationUnit unit) |
| { |
| assert !unit.isInvisible(); |
| lock.writeLock().lock(); |
| try |
| { |
| addCompilationUnit(unit); |
| } |
| finally |
| { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * @param unit An {@link ICompilationUnit} to be checked |
| * @return True if the {@link ICompilationUnit} unit exists in this {@link DependencyGraph} |
| */ |
| public boolean contains(ICompilationUnit unit) |
| { |
| return graph.getVertices().contains(unit); |
| } |
| |
| /** |
| * Finds the named dependencies between two compilation unit |
| * @param from The depender {@link ICompilationUnit} |
| * @param to The dependee {@link ICompilationUnit} |
| * @return A copied non-synchronous {@link Map} from definition qname {@link String} to a {@link DependencyTypeSet}, |
| * representing the dependencies between two {@link ICompilationUnit} |
| */ |
| public Map<String, DependencyTypeSet> getDependencySet(ICompilationUnit from, ICompilationUnit to) |
| { |
| assert !to.isInvisible() |
| : "invisible compilation units must not be in the dependency graph"; |
| return new HashMap<String, DependencyTypeSet>(getEdge(from, to).getNamedDependencies()); |
| } |
| |
| /** |
| * Finds the dependencies between two {@link ICompilationUnit}s |
| * @param from The depender {@link ICompilationUnit} |
| * @param to The dependee {@link ICompilationUnit} |
| * @return A copy of an {@link DependencyTypeSet} that is active between the two compilation units |
| */ |
| public DependencyTypeSet getDependencyTypes(ICompilationUnit from, ICompilationUnit to) |
| { |
| assert !to.isInvisible() |
| : "invisible compilation units must not be in the dependency graph"; |
| return DependencyTypeSet.copyOf(getEdge(from, to).getAllDependencies()); |
| } |
| |
| /** |
| * @return An unmodifiable view of all the compilation units in the dependency graph. |
| */ |
| public Collection<ICompilationUnit> getCompilationUnits() |
| { |
| return graph.getVertices(); |
| } |
| |
| } |