Skip to content

Add Roslyn LSP entry-point query for file-based programs and refresh discovery#84367

Closed
Copilot wants to merge 4 commits into
mainfrom
copilot/expose-lsp-request-for-fba-heuristic
Closed

Add Roslyn LSP entry-point query for file-based programs and refresh discovery#84367
Copilot wants to merge 4 commits into
mainfrom
copilot/expose-lsp-request-for-fba-heuristic

Conversation

Copilot AI commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Roslyn already had file-based-program entry-point heuristics, but the client was adding its own copy. This change exposes Roslyn’s decision over LSP and fixes the known discovery gaps around top-level statements, workspace-folder updates, and newly created .cs files.

  • New LSP surface

    • Adds workspace/_roslyn_isFileBasedProgramEntryPoint so clients can ask Roslyn whether a file should be treated as an FBA entry point under the current workspace state.
    • Moves the heuristic behind a reusable server-side API instead of duplicating it in the client.
    {
      "method": "workspace/_roslyn_isFileBasedProgramEntryPoint",
      "params": {
        "textDocument": {
          "uri": "file:///workspace/App.cs"
        }
      }
    }
  • Shared entry-point heuristic

    • Factors entry-point detection into shared logic used by both open-file classification and background discovery.
    • Recognizes:
      • #! files as explicit entry points
      • #: + top-level statements as explicit entry points
      • top-level statements without directives as ambiguous entry points
  • Discovery correctness

    • Updates automatic discovery to use the same heuristic as classification, instead of only looking for #! / #: markers.
    • This allows top-level-statement files to participate in discovery when the ambiguous-file path is enabled.
  • Workspace change handling

    • Adds workspace/didChangeWorkspaceFolders handling.
    • Updates InitializeManager and CsprojInConeChecker so workspace-folder state is live rather than captured once at initialization.
    • Re-runs discovery when folders are added or removed.
  • File watching

    • Adds workspace-folder watches for .cs and .csproj.
    • Re-runs discovery when relevant files are created or changed, so new candidate entry points can be loaded without restarting the server.
  • Unit test coverage

    • Adds coverage for:
      • top-level-statements-only discovery
      • rescanning after workspace-folder changes
      • discovering new files from watched-file notifications
      • the new LSP entry-point request
Microsoft Reviewers: Open in CodeFlow

Copilot AI and others added 4 commits July 1, 2026 22:49
Co-authored-by: mwiemer-microsoft <80539004+mwiemer-microsoft@users.noreply.github.com>
Co-authored-by: mwiemer-microsoft <80539004+mwiemer-microsoft@users.noreply.github.com>
Co-authored-by: mwiemer-microsoft <80539004+mwiemer-microsoft@users.noreply.github.com>
Co-authored-by: mwiemer-microsoft <80539004+mwiemer-microsoft@users.noreply.github.com>

private static bool ContainsTopLevelStatements(SourceText sourceText, CancellationToken cancellationToken)
{
var syntaxTree = CSharpSyntaxTree.ParseText(sourceText, options: s_fileBasedProgramParseOptions, cancellationToken: cancellationToken);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We chose to require the leading #! to make a file-based app auto-discoverable, in part because doing this parse on all the C# files in a workspace folder is taxing on memory and cpu.

If we want to move forward with this, we should def be measuring and comparing the perf very carefully.

To be honest I am also a little hesitant about CreateTokenParser based solution for auto-discovery as creating SourceText requires reading the whole file content from disk (checksum is produced eagerly). This extra I/O is hard to notice on an nvme drive when auto-discovery is the only thing running, but, in a real editor startup scenario, there's a lot of contention, and being able to read less (<= ~4KB, say), does help a bit, IIRC.

@mwiemer-microsoft

Copy link
Copy Markdown
Member

This worked on microsoft/vscode-dotnettools#2369 but introduces too many changes at once. We're going to improve this heuristic with a series of PRs for reviewability.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants