Skip to content

Commit fd5372b

Browse files
Fix crash when converting primary constructor to normal constructor (#78234)
2 parents 81de82f + d6a4f0f commit fd5372b

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

src/Features/CSharp/Portable/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorCodeRefactoringProvider.cs

+9
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ void AddConstructorDeclaration()
349349

350350
async Task RewritePrimaryConstructorParameterReferencesAsync()
351351
{
352+
using var _ = PooledHashSet<EqualsValueClauseSyntax>.GetInstance(out var removedInitializers);
353+
removedInitializers.AddRange(initializedFieldsAndProperties.Select(t => t.initializer));
354+
352355
foreach (var (parameter, references) in parameterReferences)
353356
{
354357
// Only have to update references if we're synthesizing a field for this parameter.
@@ -364,6 +367,12 @@ async Task RewritePrimaryConstructorParameterReferencesAsync()
364367

365368
foreach (var identifierName in grouping)
366369
{
370+
// Don't both updating an identifier that was in a node we already decided to explicitly remove. For
371+
// example, if we have `int Prop { get; } = p;` and we already deleted `= p`, then no need to update
372+
// the `p` reference here.
373+
if (identifierName.GetAncestors<EqualsValueClauseSyntax>().Any(removedInitializers.Contains))
374+
continue;
375+
367376
var xmlElement = identifierName.AncestorsAndSelf().OfType<XmlEmptyElementSyntax>().FirstOrDefault();
368377
if (xmlElement is { Name.LocalName.ValueText: "paramref" })
369378
{

src/Features/CSharpTest/ConvertPrimaryToRegularConstructor/ConvertPrimaryToRegularConstructorTests.cs

+45
Original file line numberDiff line numberDiff line change
@@ -2757,4 +2757,49 @@ public void Goo() { }
27572757
LanguageVersion = LanguageVersionExtensions.CSharpNext,
27582758
}.RunAsync();
27592759
}
2760+
2761+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76981")]
2762+
public async Task TestConvertWithReferencesToParameter1()
2763+
{
2764+
await new VerifyCS.Test
2765+
{
2766+
TestCode = """
2767+
namespace N
2768+
{
2769+
internal class [|Goo(int bar)|]
2770+
{
2771+
public int Bar { get; private set; } = bar;
2772+
2773+
public void Baz()
2774+
{
2775+
Bar = bar;
2776+
}
2777+
}
2778+
}
2779+
""",
2780+
FixedCode = """
2781+
namespace N
2782+
{
2783+
internal class Goo
2784+
{
2785+
private readonly int bar;
2786+
2787+
public Goo(int bar)
2788+
{
2789+
this.bar = bar;
2790+
Bar = bar;
2791+
}
2792+
2793+
public int Bar { get; private set; }
2794+
2795+
public void Baz()
2796+
{
2797+
Bar = bar;
2798+
}
2799+
}
2800+
}
2801+
""",
2802+
LanguageVersion = LanguageVersionExtensions.CSharpNext,
2803+
}.RunAsync();
2804+
}
27602805
}

0 commit comments

Comments
 (0)