Support an sdk-path option in dart analyze

Bug: https://github.com/dart-lang/sdk/issues/48959
Change-Id: I4c386f1f7c474c1ff809d15d597d3f8f2de0418a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243847
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
diff --git a/pkg/dartdev/lib/src/commands/analyze.dart b/pkg/dartdev/lib/src/commands/analyze.dart
index 10d97e2..5dc3ae7 100644
--- a/pkg/dartdev/lib/src/commands/analyze.dart
+++ b/pkg/dartdev/lib/src/commands/analyze.dart
@@ -74,6 +74,12 @@
         help: 'The path to the package resolution configuration file, which '
             'supplies a mapping of package names\ninto paths.',
         hide: !verbose,
+      )
+      ..addOption(
+        'sdk-path',
+        valueHelp: 'path',
+        help: 'The path to the Dart SDK.',
+        hide: !verbose,
       );
   }
 
@@ -110,9 +116,30 @@
     var progress =
         machineFormat ? null : log.progress('Analyzing $targetsNames');
 
+    io.Directory sdkPath;
+    if (args.wasParsed('sdk-path')) {
+      sdkPath = io.Directory(args['sdk-path'] as String);
+      if (!sdkPath.existsSync()) {
+        usageException('Invalid Dart SDK path: $sdkPath');
+      }
+      final snapshotPath = path.join(
+        sdkPath.path,
+        'bin',
+        'snapshots',
+        'analysis_server.dart.snapshot',
+      );
+      if (!io.File(snapshotPath).existsSync()) {
+        usageException(
+            'Invalid Dart SDK path has no analysis_server.dart.snapshot file: '
+            '$sdkPath');
+      }
+    } else {
+      sdkPath = io.Directory(sdk.sdkPath);
+    }
+
     final AnalysisServer server = AnalysisServer(
       _packagesFile(),
-      io.Directory(sdk.sdkPath),
+      sdkPath,
       targets,
       cacheDirectoryPath: args['cache'],
       commandName: 'analyze',
diff --git a/pkg/dartdev/test/commands/analyze_test.dart b/pkg/dartdev/test/commands/analyze_test.dart
index 2ca1456..0513849 100644
--- a/pkg/dartdev/test/commands/analyze_test.dart
+++ b/pkg/dartdev/test/commands/analyze_test.dart
@@ -5,6 +5,7 @@
 import 'package:cli_util/cli_logging.dart';
 import 'package:dartdev/src/analysis_server.dart';
 import 'package:dartdev/src/commands/analyze.dart';
+import 'package:dartdev/src/sdk.dart';
 import 'package:test/test.dart';
 
 import '../utils.dart';
@@ -355,6 +356,25 @@
     expect(result.stdout, contains('1 issue found.'));
   });
 
+  test('--sdk-path value does not exist', () async {
+    p = project();
+    var result = await p.run(['analyze', '--sdk-path=bad']);
+
+    expect(result.exitCode, 64);
+    expect(result.stderr, contains('Invalid Dart SDK path: bad'));
+    expect(result.stderr, contains(_analyzeUsageText));
+  });
+
+  test('--sdk-path', () async {
+    var sdkPath = sdk.sdkPath;
+    p = project();
+    var result = await p.run(['analyze', '--sdk-path=$sdkPath']);
+
+    expect(result.exitCode, 0);
+    expect(result.stdout, contains('No issues found!'));
+    expect(result.stderr, isEmpty);
+  });
+
   test('--verbose', () async {
     p = project(mainSrc: '''
 int f() {