Skip to content

Commit 291fb03

Browse files
T-GroCopilot
andcommitted
Fix #3939: Hide compiler-generated auto-property symbols from Symbols API
Fixes #3939 Mark the compiler-generated `v` setter parameter and backing field identifiers in auto-property desugaring with synthetic ranges, so they are excluded from GetAllUsesOfAllSymbolsInFile(). Previously these internal symbols leaked through the API with empty EnclosingEntity and misleading DisplayName/CompiledName values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 01fe483 commit 291fb03

File tree

2 files changed

+16
-11
lines changed

2 files changed

+16
-11
lines changed

src/Compiler/Checking/CheckDeclarations.fs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4418,7 +4418,7 @@ module TcDeclarations =
44184418
// Only the keep the field-targeted attributes
44194419
let attribs = attribs |> List.filter (fun a -> match a.Target with Some t when t.idText = "field" -> true | _ -> false)
44204420
let mLetPortion = synExpr.Range
4421-
let fldId = ident (CompilerGeneratedName id.idText, mLetPortion)
4421+
let fldId = ident (CompilerGeneratedName id.idText, mLetPortion.MakeSynthetic())
44224422
let headPat = SynPat.LongIdent (SynLongIdent([fldId], [], [None]), None, Some noInferredTypars, SynArgPats.Pats [], None, mLetPortion)
44234423
let retInfo = match tyOpt with None -> None | Some ty -> Some (None, SynReturnInfo((ty, SynInfo.unnamedRetVal), ty.Range))
44244424
let isMutable =
@@ -4446,7 +4446,7 @@ module TcDeclarations =
44464446
let mMemberPortion = id.idRange
44474447
// Only the keep the non-field-targeted attributes
44484448
let attribs = attribs |> List.filter (fun a -> match a.Target with Some t when t.idText = "field" -> false | _ -> true)
4449-
let fldId = ident (CompilerGeneratedName id.idText, mMemberPortion)
4449+
let fldId = ident (CompilerGeneratedName id.idText, mMemberPortion.MakeSynthetic())
44504450
let headPatIds = if isStatic then [id] else [ident ("__", mMemberPortion);id]
44514451
let headPat = SynPat.LongIdent (SynLongIdent(headPatIds, [], List.replicate headPatIds.Length None), None, Some noInferredTypars, SynArgPats.Pats [], None, mMemberPortion)
44524452
let memberFlags = { memberFlags with GetterOrSetterIsCompilerGenerated = true }
@@ -4475,7 +4475,7 @@ module TcDeclarations =
44754475
| SynMemberKind.PropertySet
44764476
| SynMemberKind.PropertyGetSet ->
44774477
let setter =
4478-
let vId = ident("v", mMemberPortion)
4478+
let vId = ident("v", mMemberPortion.MakeSynthetic())
44794479
let headPat = SynPat.LongIdent (SynLongIdent(headPatIds, [], List.replicate headPatIds.Length None), None, Some noInferredTypars, SynArgPats.Pats [mkSynPatVar None vId], None, mMemberPortion)
44804480
let rhsExpr = mkSynAssign (SynExpr.Ident fldId) (SynExpr.Ident vId)
44814481
let binding = mkSynBinding (xmlDoc, headPat) (setterAccess, false, false, mMemberPortion, DebugPointAtBinding.NoneAtInvisible, None, rhsExpr, rhsExpr.Range, [], [], Some memberFlagsForSet, SynBindingTrivia.Zero)

tests/FSharp.Compiler.Service.Tests/Symbols.fs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -634,18 +634,23 @@ type Foo =
634634
Assert.True(setMfv.CompiledName.StartsWith("set_"))
635635
| _ -> failwith $"Expected three symbols, got %A{symbols}"
636636

637-
[<Fact(Skip = "Should not resolve the `v` name")>]
638-
let ``AutoProperty with get, set has property symbol 02`` () =
639-
let symbol = Checker.getSymbolUse """
637+
// https://github.com/dotnet/fsharp/issues/3939
638+
[<Fact>]
639+
let ``AutoProperty with get, set does not expose compiler-generated v symbol`` () =
640+
let _, checkResults = getParseAndCheckResults """
640641
namespace Foo
641642
642643
type Foo =
643-
member val AutoPropGetSet{caret} = 0 with get, set
644+
member val AutoPropGetSet = 0 with get, set
644645
"""
645-
// The setter should have a symbol for the generated parameter `v`.
646-
let setVMfv = symbol |> chooseMemberOrFunctionOrValue
647-
if Option.isNone setVMfv then
648-
failwith "No generated v symbol for the setter was found"
646+
let allSymbols = checkResults.GetAllUsesOfAllSymbolsInFile()
647+
let allMfvs = allSymbols |> Seq.choose (fun su -> match su.Symbol with :? FSharpMemberOrFunctionOrValue as mfv -> Some mfv | _ -> None) |> Seq.toList
648+
// The compiler-generated `v` setter parameter should NOT appear in symbol uses
649+
let vSymbols = allMfvs |> List.filter (fun mfv -> mfv.DisplayName = "v")
650+
Assert.True(vSymbols.IsEmpty, $"Compiler-generated 'v' symbol should not be exposed via GetAllUsesOfAllSymbolsInFile, but found {vSymbols.Length} occurrences")
651+
// The compiler-generated backing field should also not appear
652+
let backingFieldSymbols = allMfvs |> List.filter (fun mfv -> mfv.DisplayName.Contains("@"))
653+
Assert.True(backingFieldSymbols.IsEmpty, $"Compiler-generated backing field should not appear, but found: {backingFieldSymbols |> List.map (fun m -> m.DisplayName)}")
649654

650655
[<Fact>]
651656
let ``Property symbol is resolved for property`` () =

0 commit comments

Comments
 (0)