Skip to content

Let F# hand Find All References an already classified line - #85281

Open
xperiandri wants to merge 2 commits into
dotnet:mainfrom
xperiandri:fsharp-find-usages-classified-spans
Open

xperiandri wants to merge 2 commits into
dotnet:mainfrom
xperiandri:fsharp-find-usages-classified-spans

Conversation

@xperiandri

@xperiandri xperiandri commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Find All References lists each reference with its line classified. C# and VB classify that line while they search: DefinitionItemFactory and FindLiteralsProgressAdapter call ClassifiedSpansAndHighlightSpanFactory.ClassifyAsync and hand the result to SourceReferenceItem. FSharpSourceReferenceItem has no way to do the same, so it always passes classifiedSpans: null, and AbstractTableDataSourceFindUsagesContext.ExcerptAsync asks the F# classification service for the syntactic and semantic classification of every line again, one reference at a time, after the search.

For a file that is not open, the F# language service answers the semantic part from a whole-file classification it keeps for a few seconds, and computes that classification again once it has expired. The F# search already has the checked file in hand when it reports its references, so it can classify every reference line of a file in one pass.

This adds a constructor to FSharpSourceReferenceItem that takes the classified line and the reference's position in it, the two parts of ClassifiedSpansAndHighlightSpan. The existing constructor is unchanged, so a language service built against the previous version still loads and its references are still classified by the window.

FSharpSourceReferenceItem is a class, so the new constructor is an overload that old binaries never call.

The test project references Microsoft.CodeAnalysis.CSharp.Workspaces, as in #85280, so AdhocWorkspace can create the document a reference points into.

The F# side is dotnet/fsharp#20533. It cannot merge until this has flowed.

Verified with the F# tests of Microsoft.VisualStudio.LanguageServices.ExternalAccess.UnitTests (182, including the two new ones). The ExternalAccess projects build with RunAnalyzersDuringBuild=true without warnings.

🤖 Generated with Claude Code

C# and VB classify the line of each reference while they search and pass it
in SourceReferenceItem. FSharpSourceReferenceItem always passed null, so the
window asked the F# classification service for every line again, one
reference at a time, after the search. A new constructor takes the classified
line and the reference's place in it; the existing one is unchanged.

The EA test project references the C# workspace layer, because AdhocWorkspace
can only create a document for a language whose services are loaded.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 13, 2026 18:05
@xperiandri
xperiandri requested a review from a team as a code owner September 13, 2026 18:05
@dotnet-policy-service dotnet-policy-service Bot added the Community The pull request was submitted by a contributor who is not a Microsoft employee. label Sep 13, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Add the new constructor entries to InternalAPI.Unshipped.txt.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This pull request lets F# Find All References forward precomputed line classification.

Changes:

  • Adds a classification-aware FSharpSourceReferenceItem constructor.
  • Adds tests for classified and legacy paths.
  • Adds the C# Workspaces test dependency.
  • Requires API baseline entries for the new overload.
File summaries
File Summary
src/VisualStudio/ExternalAccess/Test/Microsoft.VisualStudio.LanguageServices.ExternalAccess.UnitTests.csproj Adds the C# Workspaces dependency.
src/VisualStudio/ExternalAccess/Test/FSharp/FSharpSourceReferenceItemTests.cs Tests classification propagation and compatibility.
src/VisualStudio/ExternalAccess/Core/FSharp/FindUsages/FSharpSourceReferenceItem.cs Adds the classification-aware constructor; API baseline entries are still required.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Lite

/// first non-whitespace character to its end, with every character covered.</param>
/// <param name="highlightSpan">The reference within that line, relative to the start of the first classified
/// span.</param>
public FSharpSourceReferenceItem(FSharpDefinitionItem definition, FSharpDocumentSpan sourceSpan, ImmutableArray<ClassifiedSpan> classifiedSpans, TextSpan highlightSpan)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added the new constructor to InternalAPI.Unshipped.txt for both namespaces in 7f2afa3cf3, beside the entry of the existing constructor.

…API baseline

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 13, 2026 18:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No unresolved issues were identified that would block approval.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

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

Labels

Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants