[go_router] Fixes bug that GoRouterState in top level redirect doesn'… (#4173)

…t contain complete data

fixes https://github.com/flutter/flutter/issues/106461
diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md
index bb8d8d7..b0df45c 100644
--- a/packages/go_router/CHANGELOG.md
+++ b/packages/go_router/CHANGELOG.md
@@ -1,8 +1,11 @@
+## 8.0.5
+
+- Fixes a bug that GoRouterState in top level redirect doesn't contain complete data.
+
 ## 8.0.4
 
 - Updates documentations around `GoRouter.of`, `GoRouter.maybeOf`, and `BuildContext` extension. 
 
-
 ## 8.0.3
 
 - Makes namedLocation and route name related APIs case sensitive.
diff --git a/packages/go_router/lib/src/builder.dart b/packages/go_router/lib/src/builder.dart
index d68958c..c98f2f8 100644
--- a/packages/go_router/lib/src/builder.dart
+++ b/packages/go_router/lib/src/builder.dart
@@ -145,8 +145,7 @@
     if (matchList.isError) {
       keyToPage = <GlobalKey<NavigatorState>, List<Page<Object?>>>{
         navigatorKey: <Page<Object?>>[
-          _buildErrorPage(
-              context, _buildErrorState(matchList.error!, matchList.uri)),
+          _buildErrorPage(context, _buildErrorState(matchList)),
         ]
       };
     } else {
@@ -325,8 +324,7 @@
     if (match is ImperativeRouteMatch) {
       effectiveMatchList = match.matches;
       if (effectiveMatchList.isError) {
-        return _buildErrorState(
-            effectiveMatchList.error!, effectiveMatchList.uri);
+        return _buildErrorState(effectiveMatchList);
       }
     } else {
       effectiveMatchList = matchList;
@@ -491,19 +489,18 @@
         child: child,
       );
 
-  GoRouterState _buildErrorState(
-    Exception error,
-    Uri uri,
-  ) {
-    final String location = uri.toString();
+  GoRouterState _buildErrorState(RouteMatchList matchList) {
+    final String location = matchList.uri.toString();
+    assert(matchList.isError);
     return GoRouterState(
       configuration,
       location: location,
-      matchedLocation: uri.path,
-      name: null,
-      queryParameters: uri.queryParameters,
-      queryParametersAll: uri.queryParametersAll,
-      error: error,
+      matchedLocation: matchList.uri.path,
+      fullPath: matchList.fullPath,
+      pathParameters: matchList.pathParameters,
+      queryParameters: matchList.uri.queryParameters,
+      queryParametersAll: matchList.uri.queryParametersAll,
+      error: matchList.error,
       pageKey: ValueKey<String>('$location(error)'),
     );
   }
diff --git a/packages/go_router/lib/src/configuration.dart b/packages/go_router/lib/src/configuration.dart
index 89fb540..865007d 100644
--- a/packages/go_router/lib/src/configuration.dart
+++ b/packages/go_router/lib/src/configuration.dart
@@ -414,9 +414,10 @@
         GoRouterState(
           this,
           location: prevLocation,
-          name: null,
           // No name available at the top level trim the query params off the
           // sub-location to match route.redirect
+          fullPath: prevMatchList.fullPath,
+          pathParameters: prevMatchList.pathParameters,
           matchedLocation: prevMatchList.uri.path,
           queryParameters: prevMatchList.uri.queryParameters,
           queryParametersAll: prevMatchList.uri.queryParametersAll,
diff --git a/packages/go_router/lib/src/state.dart b/packages/go_router/lib/src/state.dart
index 9c634ed..13ee9ad 100644
--- a/packages/go_router/lib/src/state.dart
+++ b/packages/go_router/lib/src/state.dart
@@ -17,12 +17,12 @@
     this._configuration, {
     required this.location,
     required this.matchedLocation,
-    required this.name,
+    this.name,
     this.path,
-    this.fullPath,
-    this.pathParameters = const <String, String>{},
-    this.queryParameters = const <String, String>{},
-    this.queryParametersAll = const <String, List<String>>{},
+    required this.fullPath,
+    required this.pathParameters,
+    required this.queryParameters,
+    required this.queryParametersAll,
     this.extra,
     this.error,
     required this.pageKey,
@@ -42,16 +42,24 @@
   /// matchedLocation = /family/f2
   final String matchedLocation;
 
-  /// The optional name of the route.
+  /// The optional name of the route associated with this app.
+  ///
+  /// This can be null for GoRouterState pass into top level redirect.
   final String? name;
 
-  /// The path to this sub-route, e.g. family/:fid
+  /// The path of the route associated with this app. e.g. family/:fid
+  ///
+  /// This can be null for GoRouterState pass into top level redirect.
   final String? path;
 
   /// The full path to this sub-route, e.g. /family/:fid
+  ///
+  /// For top level redirect, this is the entire path that matches the location.
+  /// It can be empty if go router can't find a match. In that case, the [error]
+  /// contains more information.
   final String? fullPath;
 
-  /// The parameters for this sub-route, e.g. {'fid': 'f2'}
+  /// The parameters for this match, e.g. {'fid': 'f2'}
   final Map<String, String> pathParameters;
 
   /// The query parameters for the location, e.g. {'from': '/family/f2'}
@@ -64,7 +72,7 @@
   /// An extra object to pass along with the navigation.
   final Object? extra;
 
-  /// The error associated with this sub-route.
+  /// The error associated with this match.
   final Exception? error;
 
   /// A unique string key for this sub-route.
@@ -129,8 +137,6 @@
 
   /// Get a location from route name and parameters.
   /// This is useful for redirecting to a named location.
-  // TODO(chunhtai): remove this method when go_router can provide a way to
-  // look up named location during redirect.
   String namedLocation(
     String name, {
     Map<String, String> pathParameters = const <String, String>{},
diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml
index 390811d..db489ed 100644
--- a/packages/go_router/pubspec.yaml
+++ b/packages/go_router/pubspec.yaml
@@ -1,7 +1,7 @@
 name: go_router
 description: A declarative router for Flutter based on Navigation 2 supporting
   deep linking, data-driven routes and more
-version: 8.0.4
+version: 8.0.5
 repository: https://github.com/flutter/packages/tree/main/packages/go_router
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22
 
diff --git a/packages/go_router/test/go_router_test.dart b/packages/go_router/test/go_router_test.dart
index ed258aa..2ebb4af 100644
--- a/packages/go_router/test/go_router_test.dart
+++ b/packages/go_router/test/go_router_test.dart
@@ -2022,7 +2022,7 @@
           expect(Uri.parse(state.location).queryParameters, isNotEmpty);
           expect(Uri.parse(state.matchedLocation).queryParameters, isEmpty);
           expect(state.path, isNull);
-          expect(state.fullPath, isNull);
+          expect(state.fullPath, '/login');
           expect(state.pathParameters.length, 0);
           expect(state.queryParameters.length, 1);
           expect(state.queryParameters['from'], '/');
@@ -2036,6 +2036,40 @@
       expect(find.byType(LoginScreen), findsOneWidget);
     });
 
+    testWidgets('top-level redirect state contains path parameters',
+        (WidgetTester tester) async {
+      final List<GoRoute> routes = <GoRoute>[
+        GoRoute(
+            path: '/',
+            builder: (BuildContext context, GoRouterState state) =>
+                const DummyScreen(),
+            routes: <RouteBase>[
+              GoRoute(
+                path: ':id',
+                builder: (BuildContext context, GoRouterState state) =>
+                    const DummyScreen(),
+              ),
+            ]),
+      ];
+
+      final GoRouter router = await createRouter(
+        routes,
+        tester,
+        initialLocation: '/123',
+        redirect: (BuildContext context, GoRouterState state) {
+          expect(state.path, isNull);
+          expect(state.fullPath, '/:id');
+          expect(state.pathParameters.length, 1);
+          expect(state.pathParameters['id'], '123');
+          return null;
+        },
+      );
+
+      final List<RouteMatch> matches =
+          router.routerDelegate.currentConfiguration.matches;
+      expect(matches, hasLength(2));
+    });
+
     testWidgets('route-level redirect state', (WidgetTester tester) async {
       const String loc = '/book/0';
       final List<GoRoute> routes = <GoRoute>[