Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions FSharp.Editor.sln
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.VS.FSI", "vsintegrat
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSharp.Editor.IntegrationTests", "vsintegration\tests\FSharp.Editor.IntegrationTests\FSharp.Editor.IntegrationTests.csproj", "{42BE0F2F-BC45-437B-851D-E88A83201339}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Test.Utilities", "tests\FSharp.Test.Utilities\FSharp.Test.Utilities.fsproj", "{B7148170-93C5-4F2F-B31D-85316D3248CF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -73,6 +75,12 @@ Global
{42BE0F2F-BC45-437B-851D-E88A83201339}.Proto|Any CPU.Build.0 = Debug|Any CPU
{42BE0F2F-BC45-437B-851D-E88A83201339}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42BE0F2F-BC45-437B-851D-E88A83201339}.Release|Any CPU.Build.0 = Release|Any CPU
{B7148170-93C5-4F2F-B31D-85316D3248CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7148170-93C5-4F2F-B31D-85316D3248CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7148170-93C5-4F2F-B31D-85316D3248CF}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
{B7148170-93C5-4F2F-B31D-85316D3248CF}.Proto|Any CPU.Build.0 = Debug|Any CPU
{B7148170-93C5-4F2F-B31D-85316D3248CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7148170-93C5-4F2F-B31D-85316D3248CF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
9 changes: 6 additions & 3 deletions tests/FSharp.Test.Utilities/ProjectGeneration.fs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,9 @@ type SyntheticProject =
OtherOptions: string list
AutoAddModules: bool
NugetReferences: Reference list
FrameworkReferences: Reference list }
FrameworkReferences: Reference list
/// If set to true this project won't cause an exception if there are errors in the initial check
SkipInitialCheck: bool }

static member Create(?name: string) =
let name = defaultArg name $"TestProject_{Guid.NewGuid().ToString()[..7]}"
Expand All @@ -245,7 +247,8 @@ type SyntheticProject =
OtherOptions = []
AutoAddModules = true
NugetReferences = []
FrameworkReferences = [] }
FrameworkReferences = []
SkipInitialCheck = false }

static member Create([<ParamArray>] sourceFiles: SyntheticSourceFile[]) =
{ SyntheticProject.Create() with SourceFiles = sourceFiles |> List.ofArray }
Expand Down Expand Up @@ -754,7 +757,7 @@ let SaveAndCheckProject project checker =

let! results = checker.ParseAndCheckProject(options)

if not (Array.isEmpty results.Diagnostics) then
if not (Array.isEmpty results.Diagnostics || project.SkipInitialCheck) then
failwith $"Project {project.Name} failed initial check: \n%A{results.Diagnostics}"

let! signatures =
Expand Down
19 changes: 0 additions & 19 deletions vsintegration/src/FSharp.Editor/CodeFixes/CodeFixHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor

open System
open System.Threading
open System.Threading.Tasks
open System.Collections.Immutable
open System.Diagnostics

Expand Down Expand Up @@ -73,24 +72,6 @@ module internal CodeFixHelpers =

TelemetryReporter.ReportSingleEvent(TelemetryEvents.CodefixActivated, props)

let createFixAllProvider name getChanges =
FixAllProvider.Create(fun fixAllCtx doc allDiagnostics ->
backgroundTask {
let sw = Stopwatch.StartNew()
let! (changes: seq<TextChange>) = getChanges (doc, allDiagnostics, fixAllCtx.CancellationToken)
let! text = doc.GetTextAsync(fixAllCtx.CancellationToken)
let doc = doc.WithText(text.WithChanges(changes))

do
reportCodeFixTelemetry
allDiagnostics
doc
name
[| "scope", fixAllCtx.Scope.ToString(); "elapsedMs", sw.ElapsedMilliseconds |]

return doc
})

let createTextChangeCodeFix (name: string, title: string, context: CodeFixContext, changes: TextChange seq) =
CodeAction.Create(
title,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
namespace Microsoft.VisualStudio.FSharp.Editor

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

Expand All @@ -13,11 +11,13 @@ open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
open Microsoft.VisualStudio.FSharp.Editor.SymbolHelpers

open FSharp.Compiler.Diagnostics
open FSharp.Compiler.Tokenization.FSharpKeywords

open CancellableTasks

[<ExportCodeFixProvider(FSharpConstants.FSharpLanguageName, Name = CodeFix.FSharpRenameParamToMatchSignature); Shared>]
type internal RenameParamToMatchSignatureCodeFixProvider [<ImportingConstructor>] () =

inherit CodeFixProvider()

let getSuggestion (d: Diagnostic) =
Expand All @@ -28,53 +28,41 @@ type internal RenameParamToMatchSignatureCodeFixProvider [<ImportingConstructor>
else
ValueNone

override _.FixableDiagnosticIds = ImmutableArray.Create("FS3218")
override _.FixableDiagnosticIds = ImmutableArray.Create "FS3218"

override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix this

member this.GetChanges(document: Document, diagnostics: ImmutableArray<Diagnostic>, ct: CancellationToken) =
backgroundTask {
let! sourceText = document.GetTextAsync(ct)
override this.GetFixAllProvider() = this.RegisterFsharpFixAll()

let! changes =
seq {
for d in diagnostics do
let suggestionOpt = getSuggestion d
interface IFSharpCodeFixProvider with
member _.GetCodeFixIfAppliesAsync context =
cancellableTask {
let! sourceText = context.GetSourceTextAsync()

match suggestionOpt with
| ValueSome suggestion ->
let replacement = NormalizeIdentifierBackticks suggestion
let suggestionOpt = getSuggestion context.Diagnostics[0]

async {
let! symbolUses = getSymbolUsesOfSymbolAtLocationInDocument (document, d.Location.SourceSpan.Start)
let symbolUses = symbolUses |> Option.defaultValue [||]
match suggestionOpt with
| ValueSome suggestion ->
let replacement = NormalizeIdentifierBackticks suggestion

return
[|
for symbolUse in symbolUses do
match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.Range) with
| None -> ()
| Some span ->
let textSpan = Tokenizer.fixupSpan (sourceText, span)
yield TextChange(textSpan, replacement)
|]
let! symbolUses = getSymbolUsesOfSymbolAtLocationInDocument (context.Document, context.Span.Start)
let symbolUses = symbolUses |> Option.defaultValue [||]

let changes =
[
for symbolUse in symbolUses do
let span = RoslynHelpers.FSharpRangeToTextSpan(sourceText, symbolUse.Range)
let textSpan = Tokenizer.fixupSpan (sourceText, span)
yield TextChange(textSpan, replacement)
]

return
ValueSome
{
Name = CodeFix.FSharpRenameParamToMatchSignature
Message = CompilerDiagnostics.GetErrorMessage(FSharpDiagnosticKind.ReplaceWithSuggestion suggestion)
Changes = changes
}
| ValueNone -> ()
}
|> Async.Parallel

return (changes |> Seq.concat)
}

override this.RegisterCodeFixesAsync ctx : Task =
backgroundTask {
let title = ctx.Diagnostics |> Seq.head |> getSuggestion

match title with
| ValueSome title ->
let! changes = this.GetChanges(ctx.Document, ctx.Diagnostics, ctx.CancellationToken)
ctx.RegisterFsharpFix(CodeFix.FSharpRenameParamToMatchSignature, title, changes)
| ValueNone -> ()
}

override this.GetFixAllProvider() =
CodeFixHelpers.createFixAllProvider CodeFix.FSharpRenameParamToMatchSignature this.GetChanges

| ValueNone -> return ValueNone
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type TestCodeFix = { Message: string; FixedCode: string }
type Mode =
| Auto
| WithOption of CustomProjectOption: string
| WithSignature of FsiCode: string
| Manual of Squiggly: string * Diagnostic: string

let inline toOption o =
Expand All @@ -41,6 +42,7 @@ let getDocument code mode =
match mode with
| Auto -> RoslynTestHelpers.GetFsDocument code
| WithOption option -> RoslynTestHelpers.GetFsDocument(code, option)
| WithSignature fsiCode -> RoslynTestHelpers.GetFsiAndFsDocuments fsiCode code |> Seq.last
| Manual _ -> RoslynTestHelpers.GetFsDocument code

let getRelevantDiagnostics (document: Document) =
Expand All @@ -64,6 +66,7 @@ let createTestCodeFixContext (code: string) document (mode: Mode) diagnosticIds
getRelevantDiagnostics document
|> Array.filter (fun d -> diagnosticIds |> Seq.contains d.ErrorNumberText)
| WithOption _ -> getRelevantDiagnostics document
| WithSignature _ -> getRelevantDiagnostics document
| Manual (squiggly, diagnostic) ->
let spanStart = code.IndexOf squiggly
let span = TextSpan(spanStart, squiggly.Length)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

module FSharp.Editor.Tests.CodeFixes.RenameParamToMatchSignatureTests

open Microsoft.VisualStudio.FSharp.Editor
open Xunit

open CodeFixTestFramework

let private codeFix = RenameParamToMatchSignatureCodeFixProvider()

[<Fact>]
let ``Fixes FS3218`` () =
let fsCode =
"""
module Library

let id y = y
"""

let fsiCode =
"""
module Library

val id: x: 'a -> 'a
"""

let expected =
Some
{
Message = "Replace with 'x'"
FixedCode =
"""
module Library

let id x = x
"""
}

let actual = codeFix |> tryFix fsCode (WithSignature fsiCode)

Assert.Equal(expected, actual)
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<Compile Include="CodeFixes\ChangeEqualsInFieldTypeToColonTests.fs" />
<Compile Include="CodeFixes\RemoveUnusedOpensTests.fs" />
<Compile Include="CodeFixes\SimplifyNameTests.fs" />
<Compile Include="CodeFixes\RenameParamToMatchSignatureTests.fs" />
<Compile Include="Hints\HintTestFramework.fs" />
<Compile Include="Hints\OptionParserTests.fs" />
<Compile Include="Hints\InlineParameterNameHintTests.fs" />
Expand Down
28 changes: 18 additions & 10 deletions vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -358,17 +358,25 @@ type RoslynTestHelpers private () =
|> RoslynTestHelpers.GetSingleDocument

static member GetFsiAndFsDocuments (fsiCode: string) (fsCode: string) =
let projectId = ProjectId.CreateNewId()
let projFilePath = "C:\\test.fsproj"

let fsiDocInfo =
RoslynTestHelpers.CreateDocumentInfo projectId "C:\\test.fsi" fsiCode

let fsDocInfo = RoslynTestHelpers.CreateDocumentInfo projectId "C:\\test.fs" fsCode

let projInfo =
RoslynTestHelpers.CreateProjectInfo projectId projFilePath [ fsiDocInfo; fsDocInfo ]
{ SyntheticProject.Create(
{ sourceFile "test" [] with
SignatureFile = Custom fsiCode
Source = fsCode
}
) with

AutoAddModules = false
SkipInitialCheck = true
OtherOptions =
[
"--targetprofile:netcore" // without this lib some symbols are not loaded
"--nowarn:3384" // The .NET SDK for this script could not be determined
]
}

let solution = RoslynTestHelpers.CreateSolution [ projInfo ]
let solution, _ = RoslynTestHelpers.CreateSolution projInfo
let project = solution.Projects |> Seq.exactlyOne

project.Documents
|> Seq.sortWith (fun d1 _ -> if d1.IsFSharpSignatureFile then -1 else 1)