/// <summary> /// Constructs the transitive closure of outgoing dependencies starting /// from the given classes. /// </summary> /// <remarks> /// Constructs the transitive closure of outgoing dependencies starting /// from the given classes. That is, the returned collection is all the /// classes that might be needed in order to use the given classes. /// If none of the given classes are found, an empty collection is returned. /// </remarks> /// <param name="startingClassNames"> /// A Collection of Strings, each the /// fully-qualified name of a class. These are the starting elements of /// the transitive closure. /// </param> /// <returns> /// A collection of Identifiers, each representing a class, /// that are the transitive closure of the starting classes. /// </returns> public virtual ICollection <DependencyAnalyzer.Identifier> TransitiveClosure(IList <string> startingClassNames) { ICollection <DependencyAnalyzer.Identifier> closure = Generics.NewHashSet(); // The depQueue is the queue of items in the closure whose dependencies // have yet to be scanned. LinkedList <DependencyAnalyzer.Identifier> depQueue = new LinkedList <DependencyAnalyzer.Identifier>(); // add all the starting classes to the closure and the depQueue AddStartingClasses(depQueue, closure, startingClassNames); // Now work through the dependency queue, adding dependencies until // there are none left. while (!depQueue.IsEmpty()) { DependencyAnalyzer.Identifier id = depQueue.RemoveFirst(); foreach (DependencyAnalyzer.Identifier outgoingDependency in id.outgoingDependencies) { if (outgoingDependency.isClass && !closure.Contains(outgoingDependency)) { depQueue.AddLast(outgoingDependency); closure.Add(outgoingDependency); } } } return(closure); }
/// <summary>Returns the canonical Identifier with the given name.</summary> /// <param name="name">The name of an Identifier.</param> /// <returns> /// The Identifier, which will have been newly created if it /// did not already exist. /// </returns> private DependencyAnalyzer.Identifier CanonicalIdentifier(string name) { DependencyAnalyzer.Identifier ident = identifiers[name]; if (ident == null) { ident = new DependencyAnalyzer.Identifier(name); identifiers[name] = ident; } return(ident); }
/// <summary>Constructs a DependencyAnalyzer from the output of DependencyExtractor.</summary> /// <remarks> /// Constructs a DependencyAnalyzer from the output of DependencyExtractor. /// The data will be converted into a dependency tree. /// </remarks> /// <param name="filename"> /// The path of a file containing the output of a run /// of DependencyExtractor. /// </param> /// <exception cref="System.IO.IOException"/> public DependencyAnalyzer(string filename) { BufferedReader input = new BufferedReader(new FileReader(filename)); string line; DependencyAnalyzer.Identifier curPackage = null; DependencyAnalyzer.Identifier curClass = null; while ((line = input.ReadLine()) != null) { Matcher matcher = pkgLine.Matcher(line); string name; if (matcher.Matches()) { name = matcher.Group(1); curPackage = CanonicalIdentifier(name); curClass = null; } else { //log.info("Found package " + curPackage.name); matcher = classLine.Matcher(line); if (matcher.Matches()) { name = PrependPackage(curPackage.name, matcher.Group(1)); curClass = CanonicalIdentifier(name); curClass.isClass = true; } else { //curPackage.classes.add(curClass); //log.info("Found class " + curClass.name); matcher = memberLine.Matcher(line); if (matcher.Matches()) { name = curClass.name + "." + matcher.Group(1); } else { //log.info("Found member: " + name ); matcher = inDepLine.Matcher(line); if (matcher.Matches()) { name = matcher.Group(1); DependencyAnalyzer.Identifier inDep = CanonicalIdentifier(name); if (curClass != null) { curClass.ingoingDependencies.Add(inDep); } } else { //log.info("Found ingoing depedency: " + // name); matcher = outDepLine.Matcher(line); if (matcher.Matches()) { name = matcher.Group(1); DependencyAnalyzer.Identifier outDep = CanonicalIdentifier(name); if (curClass != null) { curClass.outgoingDependencies.Add(outDep); } } else { //log.info("Found outgoing dependency: " + // name); matcher = bothDepLine.Matcher(line); if (matcher.Matches()) { name = matcher.Group(1); DependencyAnalyzer.Identifier dep = CanonicalIdentifier(name); if (curClass != null) { curClass.ingoingDependencies.Add(dep); curClass.outgoingDependencies.Add(dep); } } else { log.Info("Found unmatching line: " + line); } } } } } } } // After reading the dependencies, as a post-processing step we // connect all inner classes and outer classes with each other. foreach (string className in identifiers.Keys) { DependencyAnalyzer.Identifier classId = identifiers[className]; if (!classId.isClass) { continue; } int baseIndex = className.IndexOf("$"); if (baseIndex < 0) { continue; } string baseName = Sharpen.Runtime.Substring(className, 0, baseIndex); DependencyAnalyzer.Identifier baseId = identifiers[baseName]; if (baseId == null) { continue; } baseId.ingoingDependencies.Add(classId); baseId.outgoingDependencies.Add(classId); classId.ingoingDependencies.Add(baseId); classId.outgoingDependencies.Add(baseId); } }