Eliminate accidental multiple snapshot creation and update analyzer to 0.34 (#1862)

* test printouts to debug crashes

* Move individual snapshot creation status into its own class and out of ToolDefinition

* Strip print statements and tracing

* Clean up output

* Rebuild test package docs

* reorder travis to put long running bots first again
diff --git a/.travis.yml b/.travis.yml
index d8c41e7..c7ca622 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,11 +4,11 @@
   - stable
   - "dev/raw/latest"
 env:
-  - DARTDOC_BOT=flutter
   - DARTDOC_BOT=sdk-analyzer
   - DARTDOC_BOT=main
-  - DARTDOC_BOT=sdk-docs
+  - DARTDOC_BOT=flutter
   - DARTDOC_BOT=packages
+  - DARTDOC_BOT=sdk-docs
 script: ./tool/travis.sh
 
 os:
diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart
index a199ff6..2f409fb 100644
--- a/lib/src/dartdoc_options.dart
+++ b/lib/src/dartdoc_options.dart
@@ -168,6 +168,53 @@
   }
 }
 
+/// Manages the creation of a single snapshot file in a context where multiple
+/// async functions could be trying to use and/or create it.
+///
+/// To use:
+///
+/// var s = new Snapshot(...);
+///
+/// if (s.needsSnapshot) {
+///   // create s.snapshotFile, then call:
+///   s.snapshotCompleted();
+/// } else {
+///   await snapshotValid();
+///   // use existing s.snapshotFile;
+/// }
+///
+class Snapshot {
+  File _snapshotFile;
+  File get snapshotFile => _snapshotFile;
+  final Completer _snapshotCompleter = Completer();
+
+  Snapshot(Directory snapshotCache, String toolPath, int serial) {
+    if (toolPath.endsWith('.snapshot')) {
+      _needsSnapshot = false;
+      _snapshotFile = File(toolPath);
+      snapshotCompleted();
+    } else {
+      _snapshotFile =
+          File(pathLib.join(snapshotCache.absolute.path, 'snapshot_$serial'));
+    }
+  }
+
+  bool _needsSnapshot = true;
+
+  /// Will return true precisely once, unless [toolPath] was already a snapshot.
+  /// In that case, will always return false.
+  bool get needsSnapshot {
+    if (_needsSnapshot == true) {
+      _needsSnapshot = false;
+      return true;
+    }
+    return _needsSnapshot;
+  }
+
+  Future<void> snapshotValid() => _snapshotCompleter.future;
+  void snapshotCompleted() => _snapshotCompleter.complete();
+}
+
 /// A singleton that keeps track of cached snapshot files. The [dispose]
 /// function must be called before process exit to clean up snapshots in the
 /// cache.
@@ -175,7 +222,7 @@
   static SnapshotCache _instance;
 
   Directory snapshotCache;
-  final Map<String, File> snapshots = {};
+  final Map<String, Snapshot> snapshots = {};
   int _serial = 0;
 
   SnapshotCache._()
@@ -187,15 +234,13 @@
     return _instance;
   }
 
-  File getSnapshot(String toolPath) {
+  Snapshot getSnapshot(String toolPath) {
     if (snapshots.containsKey(toolPath)) {
       return snapshots[toolPath];
     }
-    File snapshot =
-        File(pathLib.join(snapshotCache.absolute.path, 'snapshot_$_serial'));
+    snapshots[toolPath] = new Snapshot(snapshotCache, toolPath, _serial);
     _serial++;
-    snapshots[toolPath] = snapshot;
-    return snapshot;
+    return snapshots[toolPath];
   }
 
   void dispose() {
@@ -217,43 +262,26 @@
     assert(args[0] == command.first);
     // Set up flags to create a new snapshot, if needed, and use the first run as the training
     // run.
-    File snapshotFile = await getSnapshotFile();
-    if (snapshotFile.existsSync()) {
-      // replace the first argument with the path to the snapshot.
-      args[0] = snapshotFile.absolute.path;
-    } else {
+    Snapshot snapshot = SnapshotCache.instance.getSnapshot(command.first);
+    File snapshotFile = snapshot.snapshotFile;
+    bool needsSnapshot = snapshot.needsSnapshot;
+    if (needsSnapshot) {
       args.insertAll(0, [
         '--snapshot=${snapshotFile.absolute.path}',
         '--snapshot_kind=app-jit'
       ]);
+    } else {
+      await snapshot.snapshotValid();
+      // replace the first argument with the path to the snapshot.
+      args[0] = snapshotFile.absolute.path;
     }
     return new Tuple2(Platform.resolvedExecutable,
-        _snapshotCompleter.isCompleted ? null : _snapshotCompleter.complete);
+        needsSnapshot ? snapshot.snapshotCompleted : null);
   }
 
   DartToolDefinition(
       List<String> command, List<String> setupCommand, String description)
-      : super(command, setupCommand, description) {
-    // If the dart tool is already a snapshot, then we just use that.
-    if (command[0].endsWith('.snapshot')) {
-      _snapshotPath = File(command[0]);
-      _snapshotCompleter.complete();
-    }
-  }
-
-  final Completer _snapshotCompleter = new Completer();
-
-  /// If the tool has a pre-built snapshot, it will be stored here.
-  File _snapshotPath;
-
-  Future<File> getSnapshotFile() async {
-    if (_snapshotPath == null) {
-      _snapshotPath = SnapshotCache.instance.getSnapshot(command.first);
-    } else {
-      await _snapshotCompleter.future;
-    }
-    return _snapshotPath;
-  }
+      : super(command, setupCommand, description);
 }
 
 /// A configuration class that can interpret [ToolDefinition]s from a YAML map.
diff --git a/pubspec.yaml b/pubspec.yaml
index 9c6b6df..a5e7482 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -8,7 +8,7 @@
   sdk: '>=2.1.0-dev.9.4 <3.0.0'
 
 dependencies:
-  analyzer: ^0.33.6
+  analyzer: ^0.34.0
   args: '>=1.4.1 <2.0.0'
   collection: ^1.2.0
   crypto: ^2.0.6
diff --git a/testing/test_package_docs/ex/deprecated-constant.html b/testing/test_package_docs/ex/deprecated-constant.html
index b1d4ff2..2c3624e 100644
--- a/testing/test_package_docs/ex/deprecated-constant.html
+++ b/testing/test_package_docs/ex/deprecated-constant.html
@@ -115,7 +115,7 @@
     <section class="multi-line-signature">
       const <span class="name ">deprecated</span>
       =
-      <span class="constant-value">const <a href="ex/Deprecated/Deprecated.html">Deprecated</a>(&#39;next release&#39;)</span>
+      <span class="constant-value">const <a href="ex/Deprecated/Deprecated.html">Deprecated</a>(&quot;next release&quot;)</span>
       
     </section>
 
diff --git a/testing/test_package_docs/ex/ex-library.html b/testing/test_package_docs/ex/ex-library.html
index ee9f555..b1bf3db 100644
--- a/testing/test_package_docs/ex/ex-library.html
+++ b/testing/test_package_docs/ex/ex-library.html
@@ -316,7 +316,7 @@
           
           
   <div>
-            <span class="signature"><code>const <a href="ex/Deprecated/Deprecated.html">Deprecated</a>(&#39;next release&#39;)</code></span>
+            <span class="signature"><code>const <a href="ex/Deprecated/Deprecated.html">Deprecated</a>(&quot;next release&quot;)</code></span>
           </div>
         </dd>
         <dt id="incorrectDocReference" class="constant">
diff --git a/testing/test_package_docs_dev/ex/deprecated-constant.html b/testing/test_package_docs_dev/ex/deprecated-constant.html
index b1d4ff2..2c3624e 100644
--- a/testing/test_package_docs_dev/ex/deprecated-constant.html
+++ b/testing/test_package_docs_dev/ex/deprecated-constant.html
@@ -115,7 +115,7 @@
     <section class="multi-line-signature">
       const <span class="name ">deprecated</span>
       =
-      <span class="constant-value">const <a href="ex/Deprecated/Deprecated.html">Deprecated</a>(&#39;next release&#39;)</span>
+      <span class="constant-value">const <a href="ex/Deprecated/Deprecated.html">Deprecated</a>(&quot;next release&quot;)</span>
       
     </section>
 
diff --git a/testing/test_package_docs_dev/ex/ex-library.html b/testing/test_package_docs_dev/ex/ex-library.html
index ee9f555..b1bf3db 100644
--- a/testing/test_package_docs_dev/ex/ex-library.html
+++ b/testing/test_package_docs_dev/ex/ex-library.html
@@ -316,7 +316,7 @@
           
           
   <div>
-            <span class="signature"><code>const <a href="ex/Deprecated/Deprecated.html">Deprecated</a>(&#39;next release&#39;)</code></span>
+            <span class="signature"><code>const <a href="ex/Deprecated/Deprecated.html">Deprecated</a>(&quot;next release&quot;)</code></span>
           </div>
         </dd>
         <dt id="incorrectDocReference" class="constant">