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
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,13 @@ protected override bool IsValidSnippetLocationCore(SnippetContext context, Cance
protected override AccessorDeclarationSyntax? GenerateSetAccessorDeclaration(CSharpSyntaxContext syntaxContext, SyntaxGenerator generator, CancellationToken cancellationToken)
{
// Having a property with `set` accessor in a readonly struct leads to a compiler error.
// So if user executes snippet inside a readonly struct the right thing to do is to not generate `set` accessor at all
// At the same time having a required property with no setter at all is also illegal.
// Thus out best guess here is to generate an `init` accessor. We can assume they are available
// as a language feature since `required` keyword has a higher minimal language version to use
if (syntaxContext.ContainingTypeDeclaration is StructDeclarationSyntax structDeclaration &&
syntaxContext.SemanticModel.GetDeclaredSymbol(structDeclaration, cancellationToken) is { IsReadOnly: true })
{
return null;
return SyntaxFactory.AccessorDeclaration(SyntaxKind.InitAccessorDeclaration).WithSemicolonToken(SemicolonToken);
}

return base.GenerateSetAccessorDeclaration(syntaxContext, generator, cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Roslyn.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets;
Expand All @@ -14,14 +15,16 @@ public sealed class CSharpProprSnippetProviderTests : AbstractCSharpAutoProperty

protected override string DefaultPropertyBlockText => "{ get; set; }";

[WorkItem("https://github.com/dotnet/roslyn/issues/79954")]
public override Task InsertSnippetInReadonlyStructTest()
=> VerifyPropertyAsync("""
readonly struct MyStruct
{
$$
}
""", "public required {|0:int|} {|1:MyProperty|} { get; }");
""", "public required {|0:int|} {|1:MyProperty|} { get; init; }");

[WorkItem("https://github.com/dotnet/roslyn/issues/79954")]
public override Task InsertSnippetInReadonlyStructTest_ReadonlyModifierInOtherPartialDeclaration()
=> VerifyPropertyAsync("""
partial struct MyStruct
Expand All @@ -32,8 +35,9 @@ partial struct MyStruct
readonly partial struct MyStruct
{
}
""", "public required {|0:int|} {|1:MyProperty|} { get; }");
""", "public required {|0:int|} {|1:MyProperty|} { get; init; }");

[WorkItem("https://github.com/dotnet/roslyn/issues/79954")]
public override Task InsertSnippetInReadonlyStructTest_ReadonlyModifierInOtherPartialDeclaration_MissingPartialModifier()
=> VerifyPropertyAsync("""
struct MyStruct
Expand All @@ -44,7 +48,7 @@ struct MyStruct
readonly partial struct MyStruct
{
}
""", "public required {|0:int|} {|1:MyProperty|} { get; }");
""", "public required {|0:int|} {|1:MyProperty|} { get; init; }");

public override Task VerifySnippetInInterfaceTest()
=> VerifySnippetIsAbsentAsync("""
Expand Down
Loading