private static bool HasWrongName(PathSegment segment, UrlAttribute urlAttribute, SyntaxNodeAnalysisContext context, out Replacement <Location> nameReplacement, out Replacement <Span> spanReplacement)
        {
            if (context.ContainingSymbol is IMethodSymbol method &&
                segment.Parameter is { } templateParameter)
            {
                if (!TryFindParameter(templateParameter, method, out _))
                {
                    if (method.Parameters.TrySingle(x => IsOrphan(x), out var symbol) &&
                        symbol.TrySingleDeclaration(context.CancellationToken, out var parameterSyntax))
                    {
                        nameReplacement = new Replacement <Location>(parameterSyntax.Identifier.GetLocation(), templateParameter.Name.ToString());
                        spanReplacement = new Replacement <Span>(templateParameter.Name, symbol.Name);
                        return(true);
                    }

                    // Using TryFirst instead of Count() here as a silly optimization
                    // As it is called after TrySingle it means Count() > 1
                    if (method.Parameters.TryFirst(x => IsOrphan(x), out _) &&
                        method.TrySingleDeclaration(context.CancellationToken, out MethodDeclarationSyntax? methodDeclaration))
                    {
                        nameReplacement = new Replacement <Location>(methodDeclaration.ParameterList.GetLocation(), null);
                        spanReplacement = new Replacement <Span>(templateParameter.Name, null);
                        return(true);
                    }
                }
            }

            nameReplacement = default;
            spanReplacement = default;
            return(false);

            bool IsOrphan(IParameterSymbol p)
            {
                if (IsFromRoute(p) &&
                    urlAttribute.UrlTemplate is { } template)
                {
                    foreach (var candidateSegment in template.Path)
                    {
                        if (candidateSegment.Parameter is { } candidateParameter&&
                            candidateParameter.Name.Equals(p.Name, StringComparison.Ordinal))
                        {
                            return(false);
                        }
                    }

                    return(true);
                }

                return(false);
            }
        }
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (!context.IsExcludedFromAnalysis() &&
                context.Node is AttributeSyntax attribute &&
                UrlAttribute.TryCreate(attribute, context, out var urlAttribute) &&
                urlAttribute.UrlTemplate is { } template)
            {
                foreach (var segment in template.Path)
                {
                    if (HasWrongName(segment, urlAttribute, context, out var nameReplacement, out var spanReplacement))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP001ParameterSymbolName,
                                nameReplacement.Node,
                                nameReplacement.Property(nameof(NameSyntax))));

                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP002RouteParameterName,
                                spanReplacement.Node.GetLocation(),
                                spanReplacement.Property(nameof(UrlTemplate))));
                    }

                    if (HasWrongType(segment, context, out var typeReplacement, out spanReplacement))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP003ParameterSymbolType,
                                typeReplacement.Node.GetLocation(),
                                typeReplacement.Property(nameof(TypeSyntax))));

                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP004RouteParameterType,
                                spanReplacement.Node.GetLocation(),
                                spanReplacement.Property(nameof(UrlTemplate))));
                    }

                    if (HasWrongSyntax(segment, out spanReplacement))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP005ParameterSyntax,
                                spanReplacement.Node.GetLocation(),
                                spanReplacement.Property(nameof(UrlTemplate))));
                    }

                    if (HasWrongRegexSyntax(segment, out spanReplacement))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP006ParameterRegex,
                                spanReplacement.Node.GetLocation(),
                                spanReplacement.Property(nameof(UrlTemplate))));
                    }

                    if (HasMissingMethodParameter(segment, context, out var location, out var name))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP007MissingParameter,
                                location,
                                name));
                    }

                    if (HasInvalidName(segment, out spanReplacement))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP008ValidRouteParameterName,
                                spanReplacement.Node.GetLocation(),
                                spanReplacement.Property(nameof(UrlTemplate))));
                    }

                    if (ShouldKebabCase(segment, out var kebabCase))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP009KebabCaseUrl,
                                segment.Span.GetLocation(),
                                ImmutableDictionary <string, string> .Empty.Add(nameof(UrlTemplate), kebabCase)));
                    }

                    if (HasSyntaxError(segment, out location))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP010UrlSyntax,
                                location,
                                segment.Span.ToString(location)));
                    }

                    if (IsMultipleOccurringParameter(segment, urlAttribute, context, out location))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP011RouteParameterNameMustBeUnique,
                                location));
                    }

                    if (ShouldUseExplicitRoute(segment, context, out spanReplacement))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP012UseExplicitRoute,
                                spanReplacement.Node.GetLocation(),
                                spanReplacement.Property(nameof(UrlTemplate))));
                    }

                    if (ShouldRenameController(segment, urlAttribute, context, out nameReplacement))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptors.ASP013ControllerNameShouldMatchRoute,
                                nameReplacement.Node,
                                nameReplacement.Property(nameof(NameSyntax)),
                                nameReplacement.NewText));
                    }
                }
            }
        }