Fix crash on vswhere search from flutter doctor (#40263)

Fixes a crash introduced on #40011 due to an incorrect type in the vswhere search

Fixes #40238
diff --git a/packages/flutter_tools/lib/src/windows/visual_studio.dart b/packages/flutter_tools/lib/src/windows/visual_studio.dart
index 31fd027..60b693b 100644
--- a/packages/flutter_tools/lib/src/windows/visual_studio.dart
+++ b/packages/flutter_tools/lib/src/windows/visual_studio.dart
@@ -35,10 +35,6 @@
   String get displayVersion =>
       _bestVisualStudioDetails[_catalogKey][_catalogDisplayVersionKey];
 
-  /// True if the Visual Studio installation is as pre-release version.
-  bool get isPrerelease =>
-      _bestVisualStudioDetails[_catalogKey][_isPrereleaseKey];
-
   /// The directory where Visual Studio is installed.
   String get installLocation => _bestVisualStudioDetails[_installationPathKey];
 
@@ -47,14 +43,21 @@
   /// For instance: "15.4.27004.2002".
   String get fullVersion => _bestVisualStudioDetails[_fullVersionKey];
 
+  // Properties that determine the status of the installation. There might be
+  // Visual Studio versions that don't include them, so default to a "valid" value to
+  // avoid false negatives.
+
   /// True there is complete installation of Visual Studio.
-  bool get isComplete => _bestVisualStudioDetails[_isCompleteKey];
+  bool get isComplete => _bestVisualStudioDetails[_isCompleteKey] ?? false;
 
   /// True if Visual Studio is launchable.
-  bool get isLaunchable => _bestVisualStudioDetails[_isLaunchableKey];
+  bool get isLaunchable => _bestVisualStudioDetails[_isLaunchableKey] ?? false;
+
+    /// True if the Visual Studio installation is as pre-release version.
+  bool get isPrerelease => _bestVisualStudioDetails[_isPrereleaseKey] ?? false;
 
   /// True if a reboot is required to complete the Visual Studio installation.
-  bool get isRebootRequired => _bestVisualStudioDetails[_isRebootRequiredKey];
+  bool get isRebootRequired => _bestVisualStudioDetails[_isRebootRequiredKey] ?? false;
 
   /// The name of the recommended Visual Studio installer workload.
   String get workloadDescription => 'Desktop development with C++';
@@ -141,16 +144,14 @@
   /// The 'catalog' entry containing more details.
   static const String _catalogKey = 'catalog';
 
+  /// The key for a pre-release version.
+  static const String _isPrereleaseKey = 'isPrerelease';
+
   /// The user-friendly version.
   ///
   /// This key is under the 'catalog' entry.
   static const String _catalogDisplayVersionKey = 'productDisplayVersion';
 
-  /// The key for a pre-release version.
-  ///
-  /// This key is under the 'catalog' entry.
-  static const String _isPrereleaseKey = 'productMilestoneIsPreRelease';
-
   /// vswhere argument keys
   static const String _prereleaseKey = '-prerelease';
 
@@ -189,15 +190,24 @@
   }
 
   /// Checks if the given installation has issues that the user must resolve.
+  ///
+  /// Returns false if the required information is missing since older versions
+  /// of Visual Studio might not include them.
   bool installationHasIssues(Map<String, dynamic>installationDetails) {
     assert(installationDetails != null);
-    assert(installationDetails[_isCompleteKey] != null);
-    assert(installationDetails[_isRebootRequiredKey] != null);
-    assert(installationDetails[_isLaunchableKey] != null);
+    if (installationDetails[_isCompleteKey] != null && !installationDetails[_isCompleteKey]) {
+      return true;
+    }
 
-    return installationDetails[_isCompleteKey] == false ||
-      installationDetails[_isRebootRequiredKey] == true ||
-      installationDetails[_isLaunchableKey] == false;
+    if (installationDetails[_isLaunchableKey] != null && !installationDetails[_isLaunchableKey]) {
+      return true;
+    }
+
+    if (installationDetails[_isRebootRequiredKey] != null && installationDetails[_isRebootRequiredKey]) {
+      return true;
+    }
+
+    return false;
   }
 
   /// Returns the details dictionary for the latest version of Visual Studio
diff --git a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart
index d6da8bf..8ebeb33 100644
--- a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart
+++ b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart
@@ -40,9 +40,20 @@
     'isRebootRequired': false,
     'isComplete': true,
     'isLaunchable': true,
+    'isPrerelease': false,
     'catalog': <String, dynamic>{
       'productDisplayVersion': '15.9.12',
-      'productMilestoneIsPreRelease': true,
+    }
+  };
+
+  // A version of a response that doesn't include certain installation status
+  // information that might be missing in older Visual Studio versions.
+  const Map<String, dynamic> _oldResponse = <String, dynamic>{
+    'installationPath': visualStudioPath,
+    'displayName': 'Visual Studio Community 2017',
+    'installationVersion': '15.9.28307.665',
+    'catalog': <String, dynamic>{
+      'productDisplayVersion': '15.9.12',
     }
   };
 
@@ -173,6 +184,19 @@
       ProcessManager: () => mockProcessManager,
     });
 
+    testUsingContext('isInstalled returns true even with missing status information', () {
+      setMockCompatibleVisualStudioInstallation(null);
+      setMockPrereleaseVisualStudioInstallation(null);
+      setMockAnyVisualStudioInstallation(_oldResponse);
+
+      visualStudio = VisualStudio();
+      expect(visualStudio.isInstalled, true);
+    }, overrides: <Type, Generator>{
+      FileSystem: () => memoryFilesystem,
+      Platform: () => windowsPlatform,
+      ProcessManager: () => mockProcessManager,
+    });
+
     testUsingContext('isInstalled returns true when VS is present but missing components', () {
       setMockCompatibleVisualStudioInstallation(null);
       setMockPrereleaseVisualStudioInstallation(null);
@@ -191,15 +215,9 @@
       setMockAnyVisualStudioInstallation(null);
 
       final Map<String, dynamic> response = Map<String, dynamic>.from(_defaultResponse)
-        ..addAll(<String, dynamic>{
-          'catalog': <String, dynamic>{
-            'productDisplayVersion': '15.9.12',
-            'productMilestoneIsPreRelease': true,
-          }
-        });
+        ..['isPrerelease'] = true;
       setMockPrereleaseVisualStudioInstallation(response);
 
-
       visualStudio = VisualStudio();
       expect(visualStudio.isInstalled, true);
       expect(visualStudio.isPrerelease, true);