Skip to content

Commit

Permalink
Add CompiledName to signature file.
Browse files Browse the repository at this point in the history
  • Loading branch information
nojaf committed Jul 6, 2023
1 parent 15e783b commit 6e37c3d
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ let cliEventAttrTypeName = clrTypeName "Microsoft.FSharp.Core.CLIEventAttribute"
[<CompiledName("StructAttribute")>]
let structAttrTypeName = clrTypeName "Microsoft.FSharp.Core.StructAttribute"

[<CompiledName("CompiledNameAttribute")>]
let compiledNameAttrTypeName = clrTypeName "Microsoft.FSharp.Core.CompiledNameAttribute"

[<CompiledName("FSharpListTypeName")>]
let fsListTypeName = clrTypeName "Microsoft.FSharp.Collections.FSharpList`1"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,17 +124,49 @@ let updateSignatureFieldDecls (implementationRecordRepr: IRecordRepresentation)
[ implementationRecordRepr.FieldDeclarations.Count .. (signatureFieldCount - 1) ]
|> List.iter (fun idx -> signatureRecordRepr.FieldDeclarations.Item idx |> deleteChild)

/// <returns>ImplementationBinding * SignatureBinding</returns>
/// <param name="pat">Implementation top reference pattern.</param>
let tryFindBindingPairFromTopReferencePat (pat: ITopReferencePat) =
match pat.Binding, pat.DeclaredElement.As<IFSharpMember>() with
type BindingPair =
| BindingPair of
implBinding: IBindingLikeDeclaration *
implMember: IFSharpMember *
sigBinding: IBindingLikeDeclaration *
sigMember: IFSharpMember

let tryFindBindingPairFromTopReferencePat (implTopRefPat: ITopReferencePat) =
match implTopRefPat.Binding, implTopRefPat.DeclaredElement.As<IFSharpMember>() with
| null, _ | _, null -> None
| implBinding, fsMember ->
| implBinding, implMember ->

fsMember.GetDeclarations()
|> Seq.tryPick (function
| :? IReferencePat as pat when pat.IsFSharpSigFile() ->
Option.ofObj pat.Binding
|> Option.map (fun sigBinding -> implBinding, sigBinding)
let tryPickFromDeclaration (condition: IReferencePat -> bool) (declaration: IDeclaration) =
match declaration with
| :? IReferencePat as pat when pat.IsFSharpSigFile() && condition pat ->
Option.both (Option.ofObj pat.Binding) (Option.ofObj (pat.DeclaredElement.As<IFSharpMember>()))
|> Option.map (fun (sigBinding, sigMember) -> BindingPair(implBinding, implMember, sigBinding, sigMember))
| _ -> None
)

implMember.GetDeclarations()
|> Seq.tryPick (tryPickFromDeclaration (fun _ -> true))
|> Option.orElseWith (fun () ->
let parentDeclarations = implMember.ContainingType.GetDeclarations()

// Find the parent signature counter part
let parentSignatureDeclaration =
parentDeclarations
|> Seq.tryPick (fun d ->
match d with
| :? INamedModuleDeclaration as signatureModule when signatureModule.IsFSharpSigFile() ->
Some signatureModule
| _ -> None)

parentSignatureDeclaration
|> Option.bind (fun signatureModule ->
signatureModule.MemberDeclarations
|> Seq.tryPick (
tryPickFromDeclaration (fun (sigRefPat: IReferencePat) ->
match implBinding.HeadPattern with
| :? IReferencePat as implPat ->
implPat.DeclaredName = sigRefPat.DeclaredName
|| implPat.Identifier.Name = sigRefPat.Identifier.Name
| _ -> false)
)
)
)
Original file line number Diff line number Diff line change
@@ -1,12 +1,56 @@
namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Daemon.QuickFixes

open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree
open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Daemon.Highlightings
open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Util
open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree
open JetBrains.ReSharper.Plugins.FSharp.Util
open JetBrains.ReSharper.Psi.ExtensionsAPI
open JetBrains.ReSharper.Resources.Shell
open type JetBrains.ReSharper.Plugins.FSharp.Psi.FSharpTreeNodeExtensions
open JetBrains.ReSharper.Plugins.FSharp.Psi.PsiUtil.PsiModificationUtil
open JetBrains.ReSharper.Plugins.FSharp.Psi.Intentions.QuickFixes.SignatureFixUtil
open JetBrains.ReSharper.Plugins.FSharp.Psi
open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree

type UpdateCompiledNameInSignatureFix(error: ValueNotContainedMutabilityCompiledNamesDifferError) =
inherit FSharpQuickFixBase()

override this.IsAvailable(cache) = failwith "todo"
override this.Text = failwith "todo"
let mutable bindingImplementation = null
let mutable bindingSignature = null

let tryFindCompiledNameAttribute (binding: IBindingLikeDeclaration) =
binding.Attributes
|> Seq.tryFind (FSharpAttributesUtil.resolvesToType FSharpPredefinedType.compiledNameAttrTypeName)

override this.Text = $"Update CompiledName for {error.Pat.Identifier.Name} in signature"

override x.IsAvailable _ =
match tryFindBindingPairFromTopReferencePat error.Pat with
| None -> false
| Some (BindingPair(implementation, implMember, signature, sigMember)) ->
bindingImplementation <- implementation
bindingSignature <- signature
implMember.Mfv.CompiledName <> sigMember.Mfv.CompiledName

override x.ExecutePsiTransaction _ =
use writeCookie = WriteLockCookie.Create(error.Pat.IsPhysical())
use disableFormatter = new DisableCodeFormatter()

let signatureCompiledNameAttribute = tryFindCompiledNameAttribute bindingSignature
let implementationCompiledNamedAttribute = tryFindCompiledNameAttribute bindingImplementation
match implementationCompiledNamedAttribute, signatureCompiledNameAttribute with
| None, None -> failwith "both don't have the attribute, add the attribute to the signature" // weird situation though
| Some value, None ->
if bindingSignature.Attributes.IsEmpty then
// We create an elementFactory with the implementation file because the CreateEmptyAttributeList is tied to implementation files only.
let elementFactory = bindingImplementation.CreateElementFactory()
let attributeList = elementFactory.CreateEmptyAttributeList()
FSharpAttributesUtil.addAttribute attributeList value |> ignore
addNodesBefore bindingSignature [
attributeList
NewLine(bindingSignature.GetLineEnding())
] |> ignore
else
FSharpAttributesUtil.addAttributeAfter (Seq.last bindingSignature.Attributes) value
| None, Some value -> failwith "add the attribute to the signature"
| Some value, Some value1 -> failwith "update the value of the signature"
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Daemon.QuickFixes

open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Daemon.Highlightings
open JetBrains.ReSharper.Resources.Shell
open JetBrains.ReSharper.Plugins.FSharp.Psi.Intentions.QuickFixes
open JetBrains.ReSharper.Plugins.FSharp.Psi.Intentions.QuickFixes.SignatureFixUtil

type UpdateMutabilityInSignatureFix(error: ValueNotContainedMutabilityAttributesDifferError) =
inherit FSharpQuickFixBase()
Expand All @@ -12,9 +12,9 @@ type UpdateMutabilityInSignatureFix(error: ValueNotContainedMutabilityAttributes
override x.Text = $"Update mutability for {error.Pat.Identifier.Name} in signature"

override x.IsAvailable _ =
match SignatureFixUtil.tryFindBindingPairFromTopReferencePat error.Pat with
match tryFindBindingPairFromTopReferencePat error.Pat with
| None -> false
| Some (topLevelBinding, signature) ->
| Some (BindingPair(implBinding = topLevelBinding; sigBinding = signature)) ->
bindingSignature <- signature
topLevelBinding.IsMutable <> signature.IsMutable

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module A

[<CompiledName("X")>]
let x{caret} (a:int) (b:int) = a + 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module A

[<CompiledName("X")>]
let x{caret} (a:int) (b:int) = a + 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module A

val x: a:int -> b:int -> int
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module A

[<CompiledName("X")>]
val x: a:int -> b:int -> int
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
<Compile Include="src\QuickFixes\RemovePatternArgumentFixTest.fs" />
<Compile Include="src\QuickFixes\AddSetterFixTest.fs" />
<Compile Include="src\QuickFixes\UpdateMutabilityInSignatureFixTest.fs" />
<Compile Include="src\QuickFixes\UpdateCompiledNameInSignatureFixTest.fs" />
<Compile Include="src\QuickDoc\QuickDocTest.fs" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace JetBrains.ReSharper.Plugins.FSharp.Tests.Intentions.QuickFixes

open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Daemon.QuickFixes
open NUnit.Framework

type UpdateCompiledNameInSignatureFixTest() =
inherit FSharpQuickFixTestBase<UpdateCompiledNameInSignatureFix>()

override x.RelativeTestDataPath = "features/quickFixes/updateCompiledNameInSignatureFix"

[<Test>] member x.``Attribute in implementation - 01`` () = x.DoNamedTestWithSignature()

0 comments on commit 6e37c3d

Please sign in to comment.