Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move more stuff to cancellable tasks in VS.Editor #15670

Merged
merged 28 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c1cf261
wip
vzarytovskii Jul 19, 2023
9bc12be
Merge remote-tracking branch 'upstream/main' into more-cancellable-ta…
vzarytovskii Jul 24, 2023
9013fb2
remove unused code
vzarytovskii Jul 24, 2023
472ead0
some additions
vzarytovskii Jul 24, 2023
605acaf
Address feedback + some fixes to issues found along the way
vzarytovskii Jul 24, 2023
2452adc
Fantoms
vzarytovskii Jul 24, 2023
8205117
More stuff
vzarytovskii Jul 24, 2023
a0c2094
Forgotten fantomas, obviously
vzarytovskii Jul 24, 2023
9e13950
Merge branch 'main' into more-cancellable-tasks2
T-Gro Jul 25, 2023
ffc6319
Merge main
vzarytovskii Aug 1, 2023
8d3657d
More fixes
vzarytovskii Aug 1, 2023
5ef4575
Cache syntactic classifications
vzarytovskii Aug 2, 2023
1240a40
Merge main
vzarytovskii Aug 2, 2023
bcef6db
Merge fix
vzarytovskii Aug 2, 2023
08e662a
Fantomas
vzarytovskii Aug 2, 2023
480fc7e
Custom sliding expiration for syntactic classifications
vzarytovskii Aug 2, 2023
95ac070
More voptions
vzarytovskii Aug 2, 2023
95bd02d
Fantomas + test fixes + pr fixes
vzarytovskii Aug 2, 2023
4964847
Various fixes
vzarytovskii Aug 2, 2023
be2337e
Automated command ran: fantomas
github-actions[bot] Aug 2, 2023
7f3c212
Merge branch 'main' into more-cancellable-tasks2
vzarytovskii Aug 2, 2023
4a1e094
Various fixes
vzarytovskii Aug 3, 2023
769fb15
Merge branch 'more-cancellable-tasks2' of https://github.com/vzarytov…
vzarytovskii Aug 3, 2023
5581a1e
Revert "Various fixes"
vzarytovskii Aug 3, 2023
08db52a
Revert "Revert "Various fixes""
vzarytovskii Aug 4, 2023
a179400
Rever accidental tokenizer changes
vzarytovskii Aug 4, 2023
3a45d4f
Automated command ran: fantomas
github-actions[bot] Aug 4, 2023
392543c
Merge branch 'main' into more-cancellable-tasks2
vzarytovskii Aug 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -188,15 +188,15 @@ module internal ClassificationDefinitions =
do VSColorTheme.add_ThemeChanged handler

member _.GetColor(ctype) =
match customColorData |> List.tryFind (fun item -> item.ClassificationName = ctype) with
| Some item ->
match customColorData |> List.tryFindV (fun item -> item.ClassificationName = ctype) with
| ValueSome item ->
let light, dark = item.LightThemeColor, item.DarkThemeColor

match getCurrentThemeId () with
| LightTheme -> Nullable light
| DarkTheme -> Nullable dark
| UnknownTheme -> Nullable()
| None -> Nullable()
| ValueNone -> Nullable()

interface ISetThemeColors with
member _.SetColors() = setColors ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
ct = ct
)

result.ToImmutable()
result.MoveToImmutable()

static let addSemanticClassification
sourceText
Expand Down Expand Up @@ -118,11 +118,17 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =

d.ForEach(f)

Collections.ObjectModel.ReadOnlyDictionary lookup :> IReadOnlyDictionary<_, _>
lookup :> IReadOnlyDictionary<_, _>

let semanticClassificationCache =
new DocumentCache<SemanticClassificationLookup>("fsharp-semantic-classification-cache")

// We don't really care here about concurrency in neither DocumentCahce, nor underlying hashmap.
let syntacticClassificationCache =
new DocumentCache<Dictionary<TextSpan, ImmutableArray<ClassifiedSpan>>>(
"fsharp-syntactic-classification-cache",
CacheItemPolicy(SlidingExpiration = (TimeSpan.FromMinutes 5)))

interface IFSharpClassificationService with
// Do not perform classification if we don't have project options (#defines matter)
member _.AddLexicalClassifications(_: SourceText, _: TextSpan, _: List<ClassifiedSpan>, _: CancellationToken) = ()
Expand All @@ -137,7 +143,7 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
cancellableTask {
use _logBlock = Logger.LogBlock(LogEditorFunctionId.Classification_Syntactic)

let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
let! cancellationToken = CancellableTask.getCancellationToken ()

let defines, langVersion, strictIndentation = document.GetFsharpParsingOptions()

Expand All @@ -160,10 +166,30 @@ type internal FSharpClassificationService [<ImportingConstructor>] () =
TelemetryReporter.ReportSingleEventWithDuration(TelemetryEvents.AddSyntacticCalssifications, eventProps)

if not isOpenDocument then
let classifiedSpans =
getLexicalClassifications (document.FilePath, defines, sourceText, textSpan, cancellationToken)
// If called concurrently, it'll likely race here (in both getting and setting/adding to underlying dictionary)
// But we don't really care for such small caches, will change the implementation if it shows that it's a problem.
match! syntacticClassificationCache.TryGetValueAsync document with
| ValueSome classifiedSpansDict ->
match classifiedSpansDict.TryGetValue(textSpan) with
| true, classifiedSpans -> result.AddRange(classifiedSpans)
| _ ->
let classifiedSpans =
getLexicalClassifications (document.FilePath, defines, sourceText, textSpan, cancellationToken)

classifiedSpansDict.Add(textSpan, classifiedSpans)
result.AddRange(classifiedSpans)
| ValueNone ->

let classifiedSpans =
getLexicalClassifications (document.FilePath, defines, sourceText, textSpan, cancellationToken)

let classifiedSpansDict = Dictionary<TextSpan, ImmutableArray<ClassifiedSpan>>()

do! syntacticClassificationCache.SetAsync(document, classifiedSpansDict)

do classifiedSpansDict[textSpan] <- classifiedSpans

result.AddRange(classifiedSpans)
result.AddRange(classifiedSpans)
else
result.AddRange(
Tokenizer.getClassifiedSpans (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type internal AddMissingFunKeywordCodeFixProvider [<ImportingConstructor>] () =
if textOfError <> "->" then
return ValueNone
else
let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
let! cancellationToken = CancellableTask.getCancellationToken ()
let document = context.Document

let! defines, langVersion, strictIndentation =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type internal AddMissingRecToMutuallyRecFunctionsCodeFixProvider [<ImportingCons
interface IFSharpCodeFixProvider with
member _.GetCodeFixIfAppliesAsync context =
cancellableTask {
let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
let! cancellationToken = CancellableTask.getCancellationToken ()

let! defines, langVersion, strictIndentation =
context.Document.GetFsharpParsingOptionsAsync(nameof (AddMissingRecToMutuallyRecFunctionsCodeFixProvider))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ namespace Microsoft.VisualStudio.FSharp.Editor

open System.Composition
open System.Threading.Tasks
open System.Threading
open System.Collections.Immutable

open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes

open FSharp.Compiler.EditorServices
open FSharp.Compiler.Text
open CancellableTasks

[<ExportCodeFixProvider(FSharpConstants.FSharpLanguageName, Name = CodeFix.AddOpen); Shared>]
type internal AddOpenCodeFixProvider [<ImportingConstructor>] (assemblyContentProvider: AssemblyContentProvider) =
Expand Down Expand Up @@ -68,7 +70,7 @@ type internal AddOpenCodeFixProvider [<ImportingConstructor>] (assemblyContentPr

let! parseResults, checkResults =
document.GetFSharpParseAndCheckResultsAsync(nameof (AddOpenCodeFixProvider))
|> liftAsync
|> CancellableTask.start context.CancellationToken

let line = sourceText.Lines.GetLineFromPosition(context.Span.End)
let linePos = sourceText.Lines.GetLinePosition(context.Span.End)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Microsoft.VisualStudio.FSharp.Editor
open System
open System.Composition
open System.Threading.Tasks
open System.Threading
open System.Collections.Immutable

open Microsoft.CodeAnalysis.Text
Expand All @@ -13,6 +14,7 @@ open Microsoft.CodeAnalysis.CodeFixes
open FSharp.Compiler.EditorServices
open FSharp.Compiler.Text
open FSharp.Compiler.Symbols
open CancellableTasks

[<ExportCodeFixProvider(FSharpConstants.FSharpLanguageName, Name = CodeFix.AddTypeAnnotationToObjectOfIndeterminateType); Shared>]
type internal AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider [<ImportingConstructor>] () =
Expand Down Expand Up @@ -44,7 +46,7 @@ type internal AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider [<Importin

let! _, checkFileResults =
document.GetFSharpParseAndCheckResultsAsync(nameof (AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider))
|> liftAsync
|> CancellableTask.start context.CancellationToken

let decl =
checkFileResults.GetDeclarationLocation(
Expand Down
12 changes: 6 additions & 6 deletions vsintegration/src/FSharp.Editor/CodeFixes/CodeFixHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ module internal CodeFixExtensions =

member ctx.GetSourceTextAsync() =
cancellableTask {
let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
let! cancellationToken = CancellableTask.getCancellationToken ()
return! ctx.Document.GetTextAsync cancellationToken
}

Expand Down Expand Up @@ -157,7 +157,7 @@ module IFSharpCodeFixProviderExtensions =
cancellableTask {
let sw = Stopwatch.StartNew()

let! token = CancellableTask.getCurrentCancellationToken ()
let! token = CancellableTask.getCancellationToken ()
let! sourceText = doc.GetTextAsync token

let! codeFixOpts =
Expand All @@ -167,10 +167,10 @@ module IFSharpCodeFixProviderExtensions =
// TODO: this crops the diags on a very high level,
// a proper fix is needed.
|> Seq.distinctBy (fun d -> d.Id, d.Location)
|> Seq.map (fun diag -> CodeFixContext(doc, diag, IFSharpCodeFixProvider.Action, token))
|> Seq.map (fun context -> provider.GetCodeFixIfAppliesAsync context)
|> Seq.map (fun task -> task token)
|> Task.WhenAll
|> Seq.map (fun diag ->
let context = CodeFixContext(doc, diag, IFSharpCodeFixProvider.Action, token)
provider.GetCodeFixIfAppliesAsync context)
|> CancellableTask.whenAll

let codeFixes = codeFixOpts |> Seq.map ValueOption.toOption |> Seq.choose id
let changes = codeFixes |> Seq.collect (fun codeFix -> codeFix.Changes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type internal ConvertCSharpLambdaToFSharpLambdaCodeFixProvider [<ImportingConstr
interface IFSharpCodeFixProvider with
member _.GetCodeFixIfAppliesAsync context =
cancellableTask {
let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
let! cancellationToken = CancellableTask.getCancellationToken ()

let! parseResults = context.Document.GetFSharpParseResultsAsync(nameof ConvertCSharpLambdaToFSharpLambdaCodeFixProvider)
let! sourceText = context.Document.GetTextAsync(cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ open FSharp.Compiler.Symbols
open FSharp.Compiler.Syntax
open FSharp.Compiler.Text
open FSharp.Compiler.Tokenization
open CancellableTasks

[<NoEquality; NoComparison>]
type internal InterfaceState =
Expand Down Expand Up @@ -189,17 +190,19 @@ type internal ImplementInterfaceCodeFixProvider [<ImportingConstructor>] () =

override _.RegisterCodeFixesAsync context : Task =
asyncMaybe {
let! ct = Async.CancellationToken |> liftAsync

let! parseResults, checkFileResults =
context.Document.GetFSharpParseAndCheckResultsAsync(nameof (ImplementInterfaceCodeFixProvider))
|> liftAsync
|> CancellableTask.start ct

let cancellationToken = context.CancellationToken
let! sourceText = context.Document.GetTextAsync(cancellationToken)
let textLine = sourceText.Lines.GetLineFromPosition context.Span.Start

let! _, _, parsingOptions, _ =
context.Document.GetFSharpCompilationOptionsAsync(nameof (ImplementInterfaceCodeFixProvider))
|> liftAsync
|> CancellableTask.start ct

let defines = CompilerEnvironment.GetConditionalDefinesForEditing parsingOptions
let langVersionOpt = Some parsingOptions.LangVersionText
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ namespace Microsoft.VisualStudio.FSharp.Editor

open System.Composition
open System.Threading.Tasks
open System.Threading
open System.Collections.Immutable

open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes

open FSharp.Compiler.EditorServices
open FSharp.Compiler.Text
open CancellableTasks

[<ExportCodeFixProvider(FSharpConstants.FSharpLanguageName, Name = CodeFix.MakeDeclarationMutable); Shared>]
type internal MakeDeclarationMutableFixProvider [<ImportingConstructor>] () =
Expand Down Expand Up @@ -43,7 +45,7 @@ type internal MakeDeclarationMutableFixProvider [<ImportingConstructor>] () =

let! parseFileResults, checkFileResults =
document.GetFSharpParseAndCheckResultsAsync(nameof (MakeDeclarationMutableFixProvider))
|> liftAsync
|> CancellableTask.start context.CancellationToken

let decl =
checkFileResults.GetDeclarationLocation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ type internal MissingReferenceCodeFixProvider() =

let exactProjectMatches =
solution.Projects
|> Seq.tryFind (fun project ->
|> Seq.tryFindV (fun project ->
String.Compare(project.AssemblyName, assemblyName, StringComparison.OrdinalIgnoreCase) = 0)

match exactProjectMatches with
| Some refProject ->
| ValueSome refProject ->
let codefix =
createCodeFix (
String.Format(SR.AddProjectReference(), refProject.Name),
Expand All @@ -76,21 +76,21 @@ type internal MissingReferenceCodeFixProvider() =
)

context.RegisterCodeFix(codefix, ImmutableArray.Create diagnostic)
| None ->
| ValueNone ->
let metadataReferences =
solution.Projects
|> Seq.collect (fun project -> project.MetadataReferences)
|> Seq.tryFind (fun ref ->
|> Seq.tryFindV (fun ref ->
let referenceAssemblyName = Path.GetFileNameWithoutExtension(ref.Display)
String.Compare(referenceAssemblyName, assemblyName, StringComparison.OrdinalIgnoreCase) = 0)

match metadataReferences with
| Some metadataRef ->
| ValueSome metadataRef ->
let codefix =
createCodeFix (String.Format(SR.AddAssemblyReference(), assemblyName), context, AddMetadataRef metadataRef)

context.RegisterCodeFix(codefix, ImmutableArray.Create diagnostic)
| None -> ()
| ValueNone -> ()
| _ -> ())
}
|> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken)
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ type internal RemoveSuperfluousCaptureForUnionCaseWithNoDataCodeFixProvider [<Im

return
classifications
|> Array.tryFind (fun c -> c.Type = SemanticClassificationType.UnionCase)
|> ValueOption.ofOption
|> Array.tryFindV (fun c -> c.Type = SemanticClassificationType.UnionCase)
|> ValueOption.map (fun unionCaseItem ->
// The error/warning captures entire pattern match, like "Ns.Type.DuName bindingName". We want to keep type info when suggesting a replacement, and only remove "bindingName".
let typeInfoLength = unionCaseItem.Range.EndColumn - m.StartColumn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type internal RemoveUnusedBindingCodeFixProvider [<ImportingConstructor>] () =
interface IFSharpCodeFixProvider with
member _.GetCodeFixIfAppliesAsync context =
cancellableTask {
let! token = CancellableTask.getCurrentCancellationToken ()
let! token = CancellableTask.getCancellationToken ()

let! sourceText = context.Document.GetTextAsync token
let! parseResults = context.Document.GetFSharpParseResultsAsync(nameof RemoveUnusedBindingCodeFixProvider)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ open FSharp.Compiler.Diagnostics
open FSharp.Compiler.EditorServices
open FSharp.Compiler.Syntax
open FSharp.Compiler.Text
open CancellableTasks

[<ExportCodeFixProvider(FSharpConstants.FSharpLanguageName, Name = CodeFix.ReplaceWithSuggestion); Shared>]
type internal ReplaceWithSuggestionCodeFixProvider [<ImportingConstructor>] (settings: EditorOptions) =
Expand All @@ -28,7 +29,7 @@ type internal ReplaceWithSuggestionCodeFixProvider [<ImportingConstructor>] (set

let! parseFileResults, checkFileResults =
document.GetFSharpParseAndCheckResultsAsync(nameof (ReplaceWithSuggestionCodeFixProvider))
|> liftAsync
|> CancellableTask.start context.CancellationToken

// This is all needed to get a declaration list
let! sourceText = document.GetTextAsync(context.CancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ open Microsoft.CodeAnalysis.CodeFixes

open FSharp.Compiler.Symbols
open FSharp.Compiler.Text
open CancellableTasks

[<ExportCodeFixProvider(FSharpConstants.FSharpLanguageName, Name = CodeFix.UseMutationWhenValueIsMutable); Shared>]
type internal UseMutationWhenValueIsMutableCodeFixProvider [<ImportingConstructor>] () =
Expand Down Expand Up @@ -51,7 +52,7 @@ type internal UseMutationWhenValueIsMutableCodeFixProvider [<ImportingConstructo

let! _, checkFileResults =
document.GetFSharpParseAndCheckResultsAsync(nameof (UseMutationWhenValueIsMutableCodeFixProvider))
|> liftAsync
|> CancellableTask.start context.CancellationToken

let! symbolUse =
checkFileResults.GetSymbolUseAtLocation(
Expand Down
Loading