Use `EnumName.name` where possible. (#94496)

diff --git a/examples/api/lib/widgets/focus_manager/focus_node.unfocus.0.dart b/examples/api/lib/widgets/focus_manager/focus_node.unfocus.0.dart
index 6005b48..64930d2 100644
--- a/examples/api/lib/widgets/focus_manager/focus_node.unfocus.0.dart
+++ b/examples/api/lib/widgets/focus_manager/focus_node.unfocus.0.dart
@@ -74,7 +74,7 @@
                         },
                         value: UnfocusDisposition.values[index],
                       ),
-                      Text(describeEnum(UnfocusDisposition.values[index])),
+                      Text(UnfocusDisposition.values[index].name),
                     ],
                   );
                 }),
diff --git a/packages/flutter/lib/src/foundation/diagnostics.dart b/packages/flutter/lib/src/foundation/diagnostics.dart
index c6b1e0c..e9c0468 100644
--- a/packages/flutter/lib/src/foundation/diagnostics.dart
+++ b/packages/flutter/lib/src/foundation/diagnostics.dart
@@ -1568,13 +1568,13 @@
         if (!showSeparator)
           'showSeparator': showSeparator,
         if (level != DiagnosticLevel.info)
-          'level': describeEnum(level),
+          'level': level.name,
         if (showName == false)
           'showName': showName,
         if (emptyBodyDescription != null)
           'emptyBodyDescription': emptyBodyDescription,
         if (style != DiagnosticsTreeStyle.sparse)
-          'style': describeEnum(style!),
+          'style': style!.name,
         if (allowTruncate)
           'allowTruncate': allowTruncate,
         if (hasChildren)
@@ -2303,6 +2303,12 @@
 /// The enum value is displayed with the class name stripped. For example:
 /// [HitTestBehavior.deferToChild] is shown as `deferToChild`.
 ///
+/// This class can be used with classes that appear like enums but are not
+/// "real" enums, so long as their `toString` implementation, in debug mode,
+/// returns a string consisting of the class name followed by the value name. It
+/// can also be used with nullable properties; the null value is represented as
+/// `null`.
+///
 /// See also:
 ///
 ///  * [DiagnosticsProperty] which documents named parameters common to all
@@ -2702,7 +2708,7 @@
     if (exception != null)
       json['exception'] = exception.toString();
     json['propertyType'] = propertyType.toString();
-    json['defaultLevel'] = describeEnum(_defaultLevel);
+    json['defaultLevel'] = _defaultLevel.name;
     if (value is Diagnosticable || value is DiagnosticsNode)
       json['isDiagnosticableValue'] = true;
     if (v is num)
@@ -3016,11 +3022,19 @@
 ///  * [Object.runtimeType], the [Type] of an object.
 String describeIdentity(Object? object) => '${objectRuntimeType(object, '<optimized out>')}#${shortHash(object)}';
 
-// This method exists as a workaround for https://github.com/dart-lang/sdk/issues/30021
 /// Returns a short description of an enum value.
 ///
 /// Strips off the enum class name from the `enumEntry.toString()`.
 ///
+/// For real enums, this is redundant with calling the `name` getter on the enum
+/// value (see [EnumName.name]), a feature that was added to Dart 2.15.
+///
+/// This function can also be used with classes whose `toString` return a value
+/// in the same form as an enum (the class name, a dot, then the value name).
+/// For example, it's used with [SemanticsAction], which is written to appear to
+/// be an enum but is actually a bespoke class so that the index values can be
+/// set as powers of two instead of as sequential integers.
+///
 /// {@tool snippet}
 ///
 /// ```dart
@@ -3031,10 +3045,13 @@
 /// void validateDescribeEnum() {
 ///   assert(Day.monday.toString() == 'Day.monday');
 ///   assert(describeEnum(Day.monday) == 'monday');
+///   assert(Day.monday.name == 'monday'); // preferred for real enums
 /// }
 /// ```
 /// {@end-tool}
 String describeEnum(Object enumEntry) {
+  if (enumEntry is Enum)
+    return enumEntry.name;
   final String description = enumEntry.toString();
   final int indexOfDot = description.indexOf('.');
   assert(
diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart
index a1db8bc..f52d533 100644
--- a/packages/flutter/lib/src/painting/image_provider.dart
+++ b/packages/flutter/lib/src/painting/image_provider.dart
@@ -148,7 +148,7 @@
     if (platform != null) {
       if (hasArguments)
         result.write(', ');
-      result.write('platform: ${describeEnum(platform!)}');
+      result.write('platform: ${platform!.name}');
       hasArguments = true;
     }
     result.write(')');
diff --git a/packages/flutter/lib/src/painting/text_style.dart b/packages/flutter/lib/src/painting/text_style.dart
index 3ad318e..5faa8d2 100644
--- a/packages/flutter/lib/src/painting/text_style.dart
+++ b/packages/flutter/lib/src/painting/text_style.dart
@@ -1378,7 +1378,7 @@
     if (decoration != null || decorationColor != null || decorationStyle != null || decorationThickness != null) {
       final List<String> decorationDescription = <String>[];
       if (decorationStyle != null)
-        decorationDescription.add(describeEnum(decorationStyle!));
+        decorationDescription.add(decorationStyle!.name);
 
       // Hide decorationColor from the default text view as it is shown in the
       // terse decoration summary as well.
diff --git a/packages/flutter/lib/src/widgets/media_query.dart b/packages/flutter/lib/src/widgets/media_query.dart
index 9da58dd..c568069 100644
--- a/packages/flutter/lib/src/widgets/media_query.dart
+++ b/packages/flutter/lib/src/widgets/media_query.dart
@@ -605,7 +605,7 @@
       'disableAnimations: $disableAnimations',
       'invertColors: $invertColors',
       'boldText: $boldText',
-      'navigationMode: ${describeEnum(navigationMode)}',
+      'navigationMode: ${navigationMode.name}',
       'gestureSettings: $gestureSettings',
     ];
     return '${objectRuntimeType(this, 'MediaQueryData')}(${properties.join(', ')})';
diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart
index a74039f..c2facf5 100644
--- a/packages/flutter/test/cupertino/text_field_test.dart
+++ b/packages/flutter/test/cupertino/text_field_test.dart
@@ -717,7 +717,7 @@
     await expectLater(
       find.byKey(const ValueKey<int>(1)),
       matchesGoldenFile(
-        'text_field_cursor_test.cupertino_${describeEnum(debugDefaultTargetPlatformOverride!).toLowerCase()}.1.png',
+        'text_field_cursor_test.cupertino_${debugDefaultTargetPlatformOverride!.name.toLowerCase()}.1.png',
       ),
     );
   }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
diff --git a/packages/flutter/test/foundation/diagnostics_test.dart b/packages/flutter/test/foundation/diagnostics_test.dart
index ebc3672..29eedb0 100644
--- a/packages/flutter/test/foundation/diagnostics_test.dart
+++ b/packages/flutter/test/foundation/diagnostics_test.dart
@@ -59,10 +59,10 @@
   expect(json['name'], equals(node.name));
   expect(json['showSeparator'] ?? true, equals(node.showSeparator));
   expect(json['description'], equals(node.toDescription()));
-  expect(json['level'] ?? describeEnum(DiagnosticLevel.info), equals(describeEnum(node.level)));
+  expect(json['level'] ?? DiagnosticLevel.info.name, equals(node.level.name));
   expect(json['showName'] ?? true, equals(node.showName));
   expect(json['emptyBodyDescription'], equals(node.emptyBodyDescription));
-  expect(json['style'] ?? describeEnum(DiagnosticsTreeStyle.sparse), equals(describeEnum(node.style!)));
+  expect(json['style'] ?? DiagnosticsTreeStyle.sparse.name, equals(node.style!.name));
   expect(json['type'], equals(node.runtimeType.toString()));
   expect(json['hasChildren'] ?? false, equals(node.getChildren().isNotEmpty));
 }
diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart
index b1ee467..3f78736 100644
--- a/packages/flutter/test/material/app_bar_test.dart
+++ b/packages/flutter/test/material/app_bar_test.dart
@@ -100,8 +100,8 @@
 
       center = tester.getCenter(title);
       size = tester.getSize(title);
-      expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}');
-      expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${describeEnum(platform)}');
+      expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${platform.name}');
+      expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${platform.name}');
 
       // One action is still centered.
 
@@ -121,8 +121,8 @@
 
       center = tester.getCenter(title);
       size = tester.getSize(title);
-      expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}');
-      expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${describeEnum(platform)}');
+      expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${platform.name}');
+      expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${platform.name}');
 
       // Two actions is left aligned again.
 
@@ -143,7 +143,7 @@
 
       center = tester.getCenter(title);
       size = tester.getSize(title);
-      expect(center.dx, lessThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}');
+      expect(center.dx, lessThan(400 - size.width / 2.0), reason: 'on ${platform.name}');
     }
   });
 
diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart
index 8897d5e..4e2b864 100644
--- a/packages/flutter/test/material/slider_test.dart
+++ b/packages/flutter/test/material/slider_test.dart
@@ -2138,11 +2138,11 @@
       expect(find.byType(Slider), findsOneWidget);
       expect(find.byType(CupertinoSlider), findsOneWidget);
 
-      expect(value, 0.5, reason: 'on ${describeEnum(platform)}');
+      expect(value, 0.5, reason: 'on ${platform.name}');
       final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(CupertinoSlider)));
       // Drag to the right end of the track.
       await gesture.moveBy(const Offset(600.0, 0.0));
-      expect(value, 1.0, reason: 'on ${describeEnum(platform)}');
+      expect(value, 1.0, reason: 'on ${platform.name}');
       await gesture.up();
     }
 
@@ -2153,11 +2153,11 @@
       expect(find.byType(Slider), findsOneWidget);
       expect(find.byType(CupertinoSlider), findsNothing);
 
-      expect(value, 0.5, reason: 'on ${describeEnum(platform)}');
+      expect(value, 0.5, reason: 'on ${platform.name}');
       final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Slider)));
       // Drag to the right end of the track.
       await gesture.moveBy(const Offset(600.0, 0.0));
-      expect(value, 1.0, reason: 'on ${describeEnum(platform)}');
+      expect(value, 1.0, reason: 'on ${platform.name}');
       await gesture.up();
     }
   });
diff --git a/packages/flutter/test/material/switch_list_tile_test.dart b/packages/flutter/test/material/switch_list_tile_test.dart
index 6ce3a4a..47ce364 100644
--- a/packages/flutter/test/material/switch_list_tile_test.dart
+++ b/packages/flutter/test/material/switch_list_tile_test.dart
@@ -198,10 +198,10 @@
       value = false;
       await tester.pumpWidget(buildFrame(platform));
       expect(find.byType(CupertinoSwitch), findsOneWidget);
-      expect(value, isFalse, reason: 'on ${describeEnum(platform)}');
+      expect(value, isFalse, reason: 'on ${platform.name}');
 
       await tester.tap(find.byType(SwitchListTile));
-      expect(value, isTrue, reason: 'on ${describeEnum(platform)}');
+      expect(value, isTrue, reason: 'on ${platform.name}');
     }
 
     for (final TargetPlatform platform in <TargetPlatform>[ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows ]) {
@@ -210,9 +210,9 @@
       await tester.pumpAndSettle(); // Finish the theme change animation.
 
       expect(find.byType(CupertinoSwitch), findsNothing);
-      expect(value, isFalse, reason: 'on ${describeEnum(platform)}');
+      expect(value, isFalse, reason: 'on ${platform.name}');
       await tester.tap(find.byType(SwitchListTile));
-      expect(value, isTrue, reason: 'on ${describeEnum(platform)}');
+      expect(value, isTrue, reason: 'on ${platform.name}');
     }
   });
 
diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart
index c15d1dc..73c205a 100644
--- a/packages/flutter/test/material/switch_test.dart
+++ b/packages/flutter/test/material/switch_test.dart
@@ -752,14 +752,14 @@
     for (final TargetPlatform platform in <TargetPlatform>[ TargetPlatform.iOS, TargetPlatform.macOS ]) {
       value = false;
       await tester.pumpWidget(buildFrame(platform));
-      expect(find.byType(CupertinoSwitch), findsOneWidget, reason: 'on ${describeEnum(platform)}');
+      expect(find.byType(CupertinoSwitch), findsOneWidget, reason: 'on ${platform.name}');
 
       final CupertinoSwitch adaptiveSwitch = tester.widget(find.byType(CupertinoSwitch));
-      expect(adaptiveSwitch.trackColor, inactiveTrackColor, reason: 'on ${describeEnum(platform)}');
+      expect(adaptiveSwitch.trackColor, inactiveTrackColor, reason: 'on ${platform.name}');
 
-      expect(value, isFalse, reason: 'on ${describeEnum(platform)}');
+      expect(value, isFalse, reason: 'on ${platform.name}');
       await tester.tap(find.byType(Switch));
-      expect(value, isTrue, reason: 'on ${describeEnum(platform)}');
+      expect(value, isTrue, reason: 'on ${platform.name}');
     }
 
     for (final TargetPlatform platform in <TargetPlatform>[ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows ]) {
@@ -767,9 +767,9 @@
       await tester.pumpWidget(buildFrame(platform));
       await tester.pumpAndSettle(); // Finish the theme change animation.
       expect(find.byType(CupertinoSwitch), findsNothing);
-      expect(value, isFalse, reason: 'on ${describeEnum(platform)}');
+      expect(value, isFalse, reason: 'on ${platform.name}');
       await tester.tap(find.byType(Switch));
-      expect(value, isTrue, reason: 'on ${describeEnum(platform)}');
+      expect(value, isTrue, reason: 'on ${platform.name}');
     }
   });
 
diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart
index 8874811..f617655 100644
--- a/packages/flutter/test/material/text_field_test.dart
+++ b/packages/flutter/test/material/text_field_test.dart
@@ -641,7 +641,7 @@
     await expectLater(
       find.byKey(const ValueKey<int>(1)),
       matchesGoldenFile(
-        'text_field_cursor_test_${describeEnum(debugDefaultTargetPlatformOverride!).toLowerCase()}.material.1.png',
+        'text_field_cursor_test_${debugDefaultTargetPlatformOverride!.name.toLowerCase()}.material.1.png',
       ),
     );
   }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart
index 03b0855..30f6cb2 100644
--- a/packages/flutter/test/widgets/editable_text_test.dart
+++ b/packages/flutter/test/widgets/editable_text_test.dart
@@ -5054,7 +5054,7 @@
   testWidgets(
     'keyboard shortcuts respect read-only',
     (WidgetTester tester) async {
-      final String platform = describeEnum(defaultTargetPlatform).toLowerCase();
+      final String platform = defaultTargetPlatform.name.toLowerCase();
       final TextEditingController controller = TextEditingController(text: testText);
       controller.selection = const TextSelection(
         baseOffset: 0,
diff --git a/packages/flutter/test/widgets/semantics_tester.dart b/packages/flutter/test/widgets/semantics_tester.dart
index 03cc46d..65a4164 100644
--- a/packages/flutter/test/widgets/semantics_tester.dart
+++ b/packages/flutter/test/widgets/semantics_tester.dart
@@ -823,7 +823,7 @@
       if (label != null) 'label "$label"',
       if (value != null) 'value "$value"',
       if (hint != null) 'hint "$hint"',
-      if (textDirection != null) ' (${describeEnum(textDirection!)})',
+      if (textDirection != null) ' (${textDirection!.name})',
       if (actions != null) 'actions "${actions!.join(', ')}"',
       if (flags != null) 'flags "${flags!.join(', ')}"',
       if (scrollPosition != null) 'scrollPosition "$scrollPosition"',