Use known FileState from FileSystemState directly.

We check all known files now, so we don't need looking up FileState(s)
by paths. It is expensive when we do it for thousand files in multiple
drivers.

Stopwatch is also not free, so now we check it every 100 files.

This makes _FilesReferencingNameTask about 4 times faster.
In total search of an element in a priority file is 2 times faster.

R=brianwilkerson@google.com

Change-Id: I2738df8035f84d20a8b7e1b6d3040d4461c2609d
Reviewed-on: https://dart-review.googlesource.com/58141
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 9dd6142..763beda 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -2430,15 +2430,18 @@
  * file.
  */
 class _FilesReferencingNameTask {
+  static const int _WORK_FILES = 100;
   static const int _MS_WORK_INTERVAL = 5;
 
   final AnalysisDriver driver;
   final String name;
   final Completer<List<String>> completer = new Completer<List<String>>();
 
+  int fileStamp = -1;
+  List<FileState> filesToCheck;
+  int filesToCheckIndex;
+
   final List<String> referencingFiles = <String>[];
-  final Set<String> checkedFiles = new Set<String>();
-  final List<String> filesToCheck = <String>[];
 
   _FilesReferencingNameTask(this.driver, this.name);
 
@@ -2453,31 +2456,33 @@
    * overall and keep quick enough response time.
    */
   bool perform() {
-    Stopwatch timer = new Stopwatch()..start();
-    while (timer.elapsedMilliseconds < _MS_WORK_INTERVAL) {
-      // Prepare files to check.
-      if (filesToCheck.isEmpty) {
-        Set<String> newFiles = driver.knownFiles.difference(checkedFiles);
-        filesToCheck.addAll(newFiles);
-      }
-
-      // If no more files to check, complete and done.
-      if (filesToCheck.isEmpty) {
-        completer.complete(referencingFiles);
-        return true;
-      }
-
-      // Check the next file.
-      String path = filesToCheck.removeLast();
-      FileState file = driver._fsState.getFileForPath(path);
-      if (file.referencedNames.contains(name)) {
-        referencingFiles.add(path);
-      }
-      checkedFiles.add(path);
+    if (driver._fsState.fileStamp != fileStamp) {
+      filesToCheck = null;
+      referencingFiles.clear();
     }
 
-    // We're not done yet.
-    return false;
+    // Prepare files to check.
+    if (filesToCheck == null) {
+      fileStamp = driver._fsState.fileStamp;
+      filesToCheck = driver._fsState.knownFiles;
+      filesToCheckIndex = 0;
+    }
+
+    Stopwatch timer = new Stopwatch()..start();
+    while (filesToCheckIndex < filesToCheck.length) {
+      if (filesToCheckIndex % _WORK_FILES == 0 &&
+          timer.elapsedMilliseconds > _MS_WORK_INTERVAL) {
+        return false;
+      }
+      FileState file = filesToCheck[filesToCheckIndex++];
+      if (file.referencedNames.contains(name)) {
+        referencingFiles.add(file.path);
+      }
+    }
+
+    // If no more files to check, complete and done.
+    completer.complete(referencingFiles);
+    return true;
   }
 }
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index d775100..ee5df1f 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -743,6 +743,11 @@
   final Map<FileState, List<FileState>> _partToLibraries = {};
 
   /**
+   * The value of this field is incremented when the set of files is updated.
+   */
+  int fileStamp = 0;
+
+  /**
    * The [FileState] instance that correspond to an unresolved URI.
    */
   FileState _unresolvedFile;
@@ -923,6 +928,7 @@
       knownFilePaths.add(path);
       files = <FileState>[];
       _pathToFiles[path] = files;
+      fileStamp++;
     }
     files.add(file);
   }