Allows redirect method to return same location (#2773)

* Allows redirect method to return same location

* format and bump version
diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md
index aea6f3a..3c130bc 100644
--- a/packages/go_router/CHANGELOG.md
+++ b/packages/go_router/CHANGELOG.md
@@ -1,7 +1,11 @@
+## 5.1.3
+
+- Allows redirection to return same location.
+
 ## 5.1.2
 
 - Exposes uri and path parameters from GoRouter and fixes its notifications.
-- Updates README
+- Updates README.
 - Removes dynamic calls in examples.
 
 ## 5.1.1
diff --git a/packages/go_router/example/lib/async_redirection.dart b/packages/go_router/example/lib/async_redirection.dart
index 14598a0..b7a1545 100644
--- a/packages/go_router/example/lib/async_redirection.dart
+++ b/packages/go_router/example/lib/async_redirection.dart
@@ -57,7 +57,7 @@
       final bool loggedIn = await StreamAuthScope.of(context).isSignedIn();
       final bool loggingIn = state.subloc == '/login';
       if (!loggedIn) {
-        return loggingIn ? null : '/login';
+        return '/login';
       }
 
       // if the user is logged in but still on the login page, send them to
diff --git a/packages/go_router/example/lib/redirection.dart b/packages/go_router/example/lib/redirection.dart
index 1e23573..4ce8253 100644
--- a/packages/go_router/example/lib/redirection.dart
+++ b/packages/go_router/example/lib/redirection.dart
@@ -77,7 +77,7 @@
       final bool loggedIn = _loginInfo.loggedIn;
       final bool loggingIn = state.subloc == '/login';
       if (!loggedIn) {
-        return loggingIn ? null : '/login';
+        return '/login';
       }
 
       // if the user is logged in but still on the login page, send them to
diff --git a/packages/go_router/lib/src/redirection.dart b/packages/go_router/lib/src/redirection.dart
index 9f68716..996aa34 100644
--- a/packages/go_router/lib/src/redirection.dart
+++ b/packages/go_router/lib/src/redirection.dart
@@ -26,9 +26,10 @@
     {List<RouteMatchList>? redirectHistory,
     Object? extra}) {
   FutureOr<RouteMatchList> processRedirect(RouteMatchList prevMatchList) {
+    final String prevLocation = prevMatchList.location.toString();
     FutureOr<RouteMatchList> processTopLevelRedirect(
         String? topRedirectLocation) {
-      if (topRedirectLocation != null) {
+      if (topRedirectLocation != null && topRedirectLocation != prevLocation) {
         final RouteMatchList newMatch = _getNewMatches(
           topRedirectLocation,
           prevMatchList.location,
@@ -62,7 +63,8 @@
       }
       FutureOr<RouteMatchList> processRouteLevelRedirect(
           String? routeRedirectLocation) {
-        if (routeRedirectLocation != null) {
+        if (routeRedirectLocation != null &&
+            routeRedirectLocation != prevLocation) {
           final RouteMatchList newMatch = _getNewMatches(
             routeRedirectLocation,
             prevMatchList.location,
@@ -102,7 +104,7 @@
       context,
       GoRouterState(
         configuration,
-        location: prevMatchList.location.toString(),
+        location: prevLocation,
         name: null,
         // No name available at the top level trim the query params off the
         // sub-location to match route.redirect
diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml
index c315136..3c63da2 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: 5.1.2
+version: 5.1.3
 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 e10f11a..96df8e7 100644
--- a/packages/go_router/test/go_router_test.dart
+++ b/packages/go_router/test/go_router_test.dart
@@ -1208,6 +1208,37 @@
       expect(redirected, isTrue);
     });
 
+    testWidgets('redirect can redirect to same path',
+        (WidgetTester tester) async {
+      final List<GoRoute> routes = <GoRoute>[
+        GoRoute(
+          path: '/',
+          builder: (BuildContext context, GoRouterState state) =>
+              const HomeScreen(),
+          routes: <GoRoute>[
+            GoRoute(
+                path: 'dummy',
+                // Return same location.
+                redirect: (_, GoRouterState state) => state.location,
+                builder: (BuildContext context, GoRouterState state) =>
+                    const DummyScreen()),
+          ],
+        ),
+      ];
+
+      final GoRouter router = await createRouter(routes, tester,
+          redirect: (BuildContext context, GoRouterState state) {
+        // Return same location.
+        return state.location;
+      });
+
+      expect(router.location, '/');
+      // Directly set the url through platform message.
+      await sendPlatformUrl('/dummy');
+      await tester.pumpAndSettle();
+      expect(router.location, '/dummy');
+    });
+
     testWidgets('top-level redirect w/ named routes',
         (WidgetTester tester) async {
       final List<GoRoute> routes = <GoRoute>[