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