Repository: dotnet/roslyn
File: src/LanguageServer/Protocol/Handler/ServerLifetime/InitializeHandler.cs (C#)

Code before:
// See the LICENSE file in the project root for more information.

using System;
using System.Diagnostics;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
using Roslyn.LanguageServer.Protocol;

namespace Microsoft.CodeAnalysis.LanguageServer.Handler;

[Method(Methods.InitializeName)]
internal sealed class InitializeHandler() : ILspServiceRequestHandler<InitializeParams, InitializeResult>
{
    public bool MutatesSolutionState => true;
    public bool RequiresLSPSolution => false;

    public async Task<InitializeResult> HandleRequestAsync(InitializeParams request, RequestContext context, CancellationToken cancellationToken)
    {
        var clientCapabilitiesManager = context.GetRequiredLspService<IInitializeManager>();
        var clientCapabilities = request.Capabilities;
        clientCapabilitiesManager.SetInitializeParams(request);

        // If we are running in process with the client, then we don't need to listen for it to exit.
        if (request.ProcessId.HasValue && request.ProcessId.Value != Process.GetCurrentProcess().Id)
        {
            // We were given a client process ID. Monitor that process and exit if it exits.
            _ = WaitForClientProcessExitAsync(request.ProcessId.Value);
        }

        var capabilitiesProvider = context.GetRequiredLspService<ICapabilitiesProvider>();
        var serverCapabilities = capabilitiesProvider.GetCapabilities(clientCapabilities);

        // Record a telemetry event indicating what capabilities are being provided by the server.
        // Useful for figuring out if a particular session is opted into an LSP feature.
        Logger.Log(FunctionId.LSP_Initialize, KeyValueLogMessage.Create(m =>
        {
            m["serverKind"] = context.ServerKind.ToTelemetryString();
            m["capabilities"] = JsonSerializer.Serialize(serverCapabilities, ProtocolConversions.LspJsonSerializerOptions);
        }));

        return new InitializeResult
        {
            Capabilities = serverCapabilities,
        };
    }

    static async Task WaitForClientProcessExitAsync(int clientProcessId)
    {
        try

Review comment (suggestion):
`Process.GetCurrentProcess()` returns an `IDisposable` and this call site doesn’t dispose it. Since this handler runs during initialization (and the process keeps running), this can leave an OS process handle open for the lifetime of the server. Consider capturing the current process ID via a `using var current = Process.GetCurrentProcess();` (or caching it once) and comparing against that value.
```suggestion
        if (request.ProcessId.HasValue && request.ProcessId.Value != Environment.ProcessId)
```

Code after:
// See the LICENSE file in the project root for more information.

using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
using Roslyn.LanguageServer.Protocol;

namespace Microsoft.CodeAnalysis.LanguageServer.Handler;

[Method(Methods.InitializeName)]
internal sealed class InitializeHandler() : ILspServiceRequestHandler<InitializeParams, InitializeResult>
{
    public bool MutatesSolutionState => true;
    public bool RequiresLSPSolution => false;

    public async Task<InitializeResult> HandleRequestAsync(InitializeParams request, RequestContext context, CancellationToken cancellationToken)
    {
        var clientCapabilitiesManager = context.GetRequiredLspService<IInitializeManager>();
        var clientCapabilities = request.Capabilities;
        clientCapabilitiesManager.SetInitializeParams(request);

        if (request.ProcessId is int clientProcessId && RoslynLanguageServer.TryRegisterClientProcessId(clientProcessId))
            context.Logger.LogInformation("Monitoring client process {clientProcessId} for exit", clientProcessId);

        var capabilitiesProvider = context.GetRequiredLspService<ICapabilitiesProvider>();
        var serverCapabilities = capabilitiesProvider.GetCapabilities(clientCapabilities);

        // Record a telemetry event indicating what capabilities are being provided by the server.
        // Useful for figuring out if a particular session is opted into an LSP feature.
        Logger.Log(FunctionId.LSP_Initialize, KeyValueLogMessage.Create(m =>
        {
            m["serverKind"] = context.ServerKind.ToTelemetryString();
            m["capabilities"] = JsonSerializer.Serialize(serverCapabilities, ProtocolConversions.LspJsonSerializerOptions);
        }));

        return new InitializeResult
        {
            Capabilities = serverCapabilities,
        };
    }
}