[flutter_tools] Fix TypeError when a FileSystemException happens during flutter doctor (#133373)

Fixes https://github.com/flutter/flutter/issues/133086
diff --git a/packages/flutter_tools/lib/src/intellij/intellij_validator.dart b/packages/flutter_tools/lib/src/intellij/intellij_validator.dart
index 691d8e5..4b2b436 100644
--- a/packages/flutter_tools/lib/src/intellij/intellij_validator.dart
+++ b/packages/flutter_tools/lib/src/intellij/intellij_validator.dart
@@ -487,8 +487,11 @@
     // Remove JetBrains Toolbox link apps. These tiny apps just
     // link to the full app, will get detected elsewhere in our search.
     validators.removeWhere((DoctorValidator validator) {
+      if (validator is! IntelliJValidatorOnMac) {
+        return false;
+      }
       final String identifierKey = plistParser.getValueFromFile(
-        (validator as IntelliJValidatorOnMac).plistFile,
+        validator.plistFile,
         PlistParser.kCFBundleIdentifierKey,
       ) as String;
       return identifierKey.contains('com.jetbrains.toolbox.linkapp');
diff --git a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart
index cc8d8c2..2fca60b 100644
--- a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart
@@ -11,7 +11,6 @@
 import 'package:flutter_tools/src/base/version.dart';
 import 'package:flutter_tools/src/globals.dart' as globals;
 import 'package:flutter_tools/src/ios/plist_parser.dart';
-import 'package:path/path.dart' show Context; // flutter_ignore: package_path_import -- We only use Context as an interface.
 import 'package:test/fake.dart';
 
 import '../../src/common.dart';
diff --git a/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart b/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart
index f9fa8ef..e6363ce 100644
--- a/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart
+++ b/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart
@@ -12,7 +12,6 @@
 import 'package:flutter_tools/src/base/file_system.dart';
 import 'package:flutter_tools/src/base/io.dart';
 import 'package:flutter_tools/src/base/platform.dart';
-import 'package:path/path.dart' as p; // flutter_ignore: package_path_import
 import 'package:process/process.dart';
 import 'package:test/fake.dart';
 
@@ -1293,7 +1292,7 @@
 
 class FakeFileSystem extends Fake implements FileSystem {
   @override
-  p.Context get path => p.Context();
+  Context get path => Context();
 
   @override
   Directory get currentDirectory {
diff --git a/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart b/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart
index bd7f810..f2bc787 100644
--- a/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart
+++ b/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart
@@ -11,6 +11,7 @@
 import 'package:flutter_tools/src/doctor_validator.dart';
 import 'package:flutter_tools/src/intellij/intellij_validator.dart';
 import 'package:flutter_tools/src/ios/plist_parser.dart';
+import 'package:test/fake.dart';
 
 import '../../src/common.dart';
 import '../../src/fake_process_manager.dart';
@@ -373,6 +374,29 @@
     expect(validator.pluginsPath, '/path/to/JetBrainsToolboxApp.plugins');
   });
 
+  testWithoutContext('IntelliJValidatorOnMac.installed() handles FileSystemExceptions)', () async {
+    const FileSystemException exception = FileSystemException('cannot list');
+    final FileSystem fileSystem = _ThrowingFileSystem(exception);
+
+    final FakeProcessManager processManager = FakeProcessManager.empty();
+
+    final Iterable<DoctorValidator> validators = IntelliJValidatorOnMac.installed(
+      fileSystem: fileSystem,
+      fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: macPlatform),
+      userMessages: UserMessages(),
+      plistParser: FakePlistParser(<String, String>{
+        'JetBrainsToolboxApp': '/path/to/JetBrainsToolboxApp',
+        'CFBundleIdentifier': 'com.jetbrains.toolbox.linkapp',
+      }),
+      processManager: processManager,
+    );
+
+    expect(validators.length, 1);
+    final DoctorValidator validator = validators.first;
+    expect(validator, isA<ValidatorWithResult>());
+    expect(validator.title, 'Cannot determine if IntelliJ is installed');
+  });
+
   testWithoutContext('Remove JetBrains Toolbox', () async {
     final FileSystem fileSystem = MemoryFileSystem.test();
     final List<String> installPaths = <String>[
@@ -398,11 +422,9 @@
       ], stdout: 'skip')
     ]);
 
-    final Iterable<DoctorValidator> installed =
-    IntelliJValidatorOnMac.installed(
+    final Iterable<DoctorValidator> installed = IntelliJValidatorOnMac.installed(
       fileSystem: fileSystem,
-      fileSystemUtils:
-      FileSystemUtils(fileSystem: fileSystem, platform: macPlatform),
+      fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: macPlatform),
       userMessages: UserMessages(),
       plistParser: FakePlistParser(<String, String>{
         'JetBrainsToolboxApp': '/path/to/JetBrainsToolboxApp',
@@ -412,6 +434,7 @@
     );
 
     expect(installed.length, 0);
+    expect(processManager, hasNoRemainingExpectations);
   });
 }
 
@@ -458,7 +481,6 @@
   fileSystem.file(pluginJarPath)
     ..createSync(recursive: true)
     ..writeAsBytesSync(ZipEncoder().encode(flutterPlugins)!);
-
 }
 
 /// A helper to create a Intellij Dart plugin jar.
@@ -496,3 +518,30 @@
     ..createSync(recursive: true)
     ..writeAsBytesSync(ZipEncoder().encode(dartPlugins)!);
 }
+
+// TODO(fujino): this should use the MemoryFileSystem and a
+// FileExceptionHandler, blocked by https://github.com/google/file.dart/issues/227.
+class _ThrowingFileSystem extends Fake implements FileSystem {
+  _ThrowingFileSystem(this._exception);
+
+  final Exception _exception;
+  final MemoryFileSystem memfs = MemoryFileSystem.test();
+
+  @override
+  Context get path => memfs.path;
+
+  @override
+  Directory directory(dynamic _) => _ThrowingDirectory(_exception);
+}
+
+class _ThrowingDirectory extends Fake implements Directory {
+  _ThrowingDirectory(this._exception);
+
+  final Exception _exception;
+
+  @override
+  bool existsSync() => true;
+
+  @override
+  List<FileSystemEntity> listSync({bool recursive = false, bool followLinks = true}) => throw _exception;
+}
diff --git a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart
index 482e4ed..dd36810 100644
--- a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart
+++ b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart
@@ -7,7 +7,7 @@
 import 'package:flutter_tools/src/base/io.dart';
 
 import '../../bin/xcode_backend.dart';
-import '../src/common.dart';
+import '../src/common.dart' hide Context;
 import '../src/fake_process_manager.dart';
 
 void main() {
diff --git a/packages/flutter_tools/test/src/common.dart b/packages/flutter_tools/test/src/common.dart
index e97fb95..ca005f2 100644
--- a/packages/flutter_tools/test/src/common.dart
+++ b/packages/flutter_tools/test/src/common.dart
@@ -17,6 +17,7 @@
 import 'package:test/test.dart' as test_package show test;
 import 'package:test/test.dart' hide test;
 
+export 'package:path/path.dart' show Context; // flutter_ignore: package_path_import
 export 'package:test/test.dart' hide isInstanceOf, test;
 
 void tryToDelete(FileSystemEntity fileEntity) {