private void ComputeFileCollection(FileSystemTreeSnapshot snapshot)
        {
            Logger.Log("Computing list of searchable files from FileSystemTree.");
            var ssw = new ScopedStopWatch();

            var directories = FileSystemSnapshotVisitor.GetDirectories(snapshot).ToList();

            ssw.Step(sw => Logger.Log("Done flattening file system tree snapshot in {0:n0} msec.", sw.ElapsedMilliseconds));

            var directoryNames = directories
                                 .Select(x => x.Value.DirectoryName)
                                 .ToArray();

            ssw.Step(sw => Logger.Log("Done creating array of directory names in {0:n0} msec.", sw.ElapsedMilliseconds));

            var searchableFiles = directories
                                  .AsParallel()
                                  .SelectMany(x => x.Value.Files.Select(y => KeyValuePair.Create(x.Key, y)))
                                  .Select(x => new FileInfo(new FileData(x.Value, null), x.Key.IsFileSearchable(x.Value)))
                                  .ToList();

            ssw.Step(sw => Logger.Log("Done creating list of files in {0:n0} msec.", sw.ElapsedMilliseconds));

            var files = searchableFiles
                        .ToDictionary(x => x.FileData.FileName, x => x);

            ssw.Step(sw => Logger.Log("Done creating dictionary of files in {0:n0} msec.", sw.ElapsedMilliseconds));

            Logger.Log("Done computing list of searchable files from FileSystemTree.");
            Logger.LogMemoryStats();

            _files          = new FileNameDictionary <FileInfo>(files);
            _directoryNames = directoryNames;
        }
        private DirectorySnapshot ProcessProject(IFileSystemNameFactory fileNameFactory, IProject project, IProgressTracker progress)
        {
            var projectPath = fileNameFactory.CreateAbsoluteDirectoryName(project.RootPath);

            var ssw = new ScopedStopWatch();
            // Create list of pairs (DirectoryName, List[FileNames])
            var directoriesWithFiles = TraverseFileSystem(fileNameFactory, project, projectPath)
                                       .AsParallel()
                                       .WithExecutionMode(ParallelExecutionMode.ForceParallelism)
                                       .Select(traversedDirectoryEntry => {
                var directoryName = traversedDirectoryEntry.DirectoryName;
                if (progress.Step())
                {
                    progress.DisplayProgress((i, n) => string.Format("Traversing directory: {0}\\{1}", project.RootPath.FullName, directoryName.RelativePathName.RelativeName));
                }
                var entries = traversedDirectoryEntry.ChildrenNames
                              .Where(childFilename => project.FileFilter.Include(childFilename.RelativePathName.RelativeName))
                              .OrderBy(x => x.RelativePathName)
                              .ToReadOnlyCollection();

                return(KeyValuePair.Create(directoryName, entries));
            })
                                       .ToList();

            ssw.Step(sw => Logger.Log("Done traversing file system in {0:n0} msec.", sw.ElapsedMilliseconds));

            // We sort entries by directory name *descending* to make sure we process
            // directories bottom up, so that we know
            // 1) it is safe to skip DirectoryEntry instances where "Entries.Count" == 0,
            // 2) we create instances of child directories before their parent.
            directoriesWithFiles.Sort((x, y) => - x.Key.RelativePathName.CompareTo(y.Key.RelativePathName));
            ssw.Step(sw => Logger.Log("Done sorting list of directories in {0:n0} msec.", sw.ElapsedMilliseconds));

            // Build map from parent directory -> list of child directories
            var directoriesToChildDirectories = new Dictionary <DirectoryName, List <DirectoryName> >();

            directoriesWithFiles.ForAll(x => {
                var directoryName = x.Key;

                // Ignore root project directory name
                if (directoryName.IsAbsoluteName)
                {
                    return;
                }

                GetOrCreateList(directoriesToChildDirectories, directoryName.Parent).Add(directoryName);
            });
            ssw.Step(sw => Logger.Log("Done creating children directories in {0:n0} msec.", sw.ElapsedMilliseconds));

            // Build directory snapshots for each directory entry, using an
            // intermediate map to enable connecting snapshots to their parent.
            var directoriesToSnapshot = new Dictionary <DirectoryName, DirectorySnapshot>();
            var directorySnapshots    = directoriesWithFiles.Select(entry => {
                var directoryName  = entry.Key;
                var childFilenames = entry.Value;

                var childDirectories = GetOrEmptyList(directoriesToChildDirectories, directoryName)
                                       .Select(x => directoriesToSnapshot[x])
                                       .OrderBy(x => x.DirectoryName.RelativePathName)
                                       .ToReadOnlyCollection();

                // TODO(rpaquay): Not clear the lines below are a perf win, even though
                // they do not hurt correctness.
                // Remove children since we processed them
                //GetOrEmptyList(directoriesToChildDirectories, directoryName)
                //  .ForAll(x => directoriesToSnapshot.Remove(x));

                var result = new DirectorySnapshot(directoryName, childDirectories, childFilenames);
                directoriesToSnapshot.Add(directoryName, result);
                return(result);
            })
                                        .ToList();

            ssw.Step(sw => Logger.Log("Done creating directory snapshots in {0:n0} msec.", sw.ElapsedMilliseconds));

            // Since we sort directories by name descending, the last entry is always the
            // entry correcsponding to the project root.
            Debug.Assert(directorySnapshots.Count >= 1);
            Debug.Assert(directorySnapshots.Last().DirectoryName.Equals(projectPath));
            return(directorySnapshots.Last());
        }