Repository: dotnet/roslyn
File: src/Features/CSharp/Portable/Completion/KeywordRecommenders/WhereKeywordRecommender.cs (C#)

Code before:
            var decl = token.GetAncestor<DelegateDeclarationSyntax>();
            if (decl != null && decl.TypeParameterList != null)
            {
                return true;
            }
        }

        // void Goo<T>() |

        if (token.Kind() == SyntaxKind.CloseParenToken &&
            token.Parent.IsKind(SyntaxKind.ParameterList))
        {
            var tokenParent = token.Parent;
            if (tokenParent.IsParentKind<MethodDeclarationSyntax>(SyntaxKind.MethodDeclaration, out var methodDeclaration))
            {
                if (methodDeclaration.Arity > 0)
                {
                    return true;
                }
            }
            else if (tokenParent.Parent is LocalFunctionStatementSyntax { TypeParameterList.Parameters.Count: > 0 })
            {
                return true;
            }
            // extension<T>(...) |
            else if (tokenParent.Parent is ExtensionBlockDeclarationSyntax extensionDecl)
            {
                if (extensionDecl.TypeParameterList?.Parameters.Count > 0)
                {
                    return true;
                }
            }
        }

        // class C<T> : IGoo |
        var baseList = token.GetAncestor<BaseListSyntax>();
        if (baseList?.Parent is TypeDeclarationSyntax typeDecl)
        {
            if (typeDecl.TypeParameterList != null &&
                baseList.Types.Any(t => token == t.GetLastToken(includeSkipped: true)))
            {
                // token is IdentifierName "where"
                // only suggest "where" if token's previous token is also "where"
                if (token.Parent is IdentifierNameSyntax && token.HasMatchingText(SyntaxKind.WhereKeyword))
                {
                    // Check for zero-width tokens in case there is a missing comma in the base list.
                    // For example: class C<T> : Goo where where |
                    return token
                        .GetPreviousToken(includeZeroWidth: true)
                        .IsKindOrHasMatchingText(SyntaxKind.WhereKeyword);
                }

Review comment (suggestion):
@copilot fixup the topmost if block to be if (tokenParent.Parent is MethodDeclarationSyntax { Arity: > 0 }) and remove the inner if.

for this 'if' block, you can change it to is ExtensionBlockDeclarationSyntax { TypeParameterList.Parameters.Count: > 0 } like how it is done in the above LocalFunctionStatementSyntax check.

Code after:
                                or ExtensionBlockDeclarationSyntax { TypeParameterList: not null }
                                or DelegateDeclarationSyntax { TypeParameterList: not null })
        {
            return true;
        }

        // class C<T> : IGoo |
        var baseList = token.GetAncestor<BaseListSyntax>();
        if (baseList?.Parent is TypeDeclarationSyntax typeDecl)
        {
            if (typeDecl.TypeParameterList != null &&
                baseList.Types.Any(t => token == t.GetLastToken(includeSkipped: true)))
            {
                // token is IdentifierName "where"
                // only suggest "where" if token's previous token is also "where"
                if (token.Parent is IdentifierNameSyntax && token.HasMatchingText(SyntaxKind.WhereKeyword))
                {
                    // Check for zero-width tokens in case there is a missing comma in the base list.
                    // For example: class C<T> : Goo where where |
                    return token
                        .GetPreviousToken(includeZeroWidth: true)
                        .IsKindOrHasMatchingText(SyntaxKind.WhereKeyword);
                }

                // System.|
                // Not done typing the qualified name
                if (token.IsKind(SyntaxKind.DotToken))
                {
                    return false;
                }

                return true;
            }
        }

        // class C<T> where T : IGoo |
        // delegate void D<T> where T : IGoo |
        if (token.IsLastTokenOfNode<TypeParameterConstraintSyntax>())
        {
            return true;
        }

        return false;
    }

    private static bool IsQueryContext(CSharpSyntaxContext context)
    {
        var token = context.TargetToken;

        // var q = from x in y
        //         |