diff --git a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceField.cs b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceField.cs index 88b0388872777..3a051264177cf 100644 --- a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceField.cs +++ b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService_IntroduceField.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -28,7 +29,13 @@ protected override Task IntroduceFieldAsync( bool isConstant, CancellationToken cancellationToken) { - var oldTypeDeclaration = expression.GetAncestorOrThis(); + // Get the ancestor TypeDeclarationSyntax that is NOT an ExtensionBlockDeclarationSyntax. + // Extension blocks can't contain fields, so we need to find the containing class/struct. + // + // Note, this can be revised in the future as we do expect to allow constants/static in + // extension blocks in a future version of the language. + var oldTypeDeclaration = expression.GetAncestorsOrThis() + .FirstOrDefault(t => t is not ExtensionBlockDeclarationSyntax); var oldType = oldTypeDeclaration != null ? document.SemanticModel.GetDeclaredSymbol(oldTypeDeclaration, cancellationToken) diff --git a/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs b/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs index 6fa85ff50ad71..26347dfbed8bd 100644 --- a/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs +++ b/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs @@ -8559,4 +8559,64 @@ public Customer* D } } """); + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/81337")] + public Task TestExtensionBlockIntroduceConstant() + => TestInRegularAndScriptAsync( + """ + public static class CEx + { + extension(C c) + { + public string P => c[[|"P"|]]; + } + } + + public class C { public string this[string k] => ""; } + """, + """ + public static class CEx + { + private const string {|Rename:V|} = "P"; + + extension(C c) + { + public string P => c[V]; + } + } + + public class C { public string this[string k] => ""; } + """, + new(parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp14))); + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/81337")] + public Task TestExtensionBlockIntroduceConstant_AllOccurrences() + => TestInRegularAndScriptAsync( + """ + public static class CEx + { + extension(C c) + { + public string P => c[[|"P"|]]; + public string P2 => c["P"]; + } + } + + public class C { public string this[string k] => ""; } + """, + """ + public static class CEx + { + private const string {|Rename:V|} = "P"; + + extension(C c) + { + public string P => c[V]; + public string P2 => c[V]; + } + } + + public class C { public string this[string k] => ""; } + """, + new(parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp14), index: 1)); }