diff --git a/src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs b/src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs index a8548a3bd0bfce..4f21419199016b 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs @@ -104,8 +104,9 @@ operation is not (IInvocationOperation or IObjectCreationOperation)) } // Get the parent type declaration so that we can inspect its methods as well as check if we need to add the partial keyword. + // Skip extension blocks, as they can't be partial and can't contain generated regex members. SyntaxNode? typeDeclarationOrCompilationUnit = - nodeToFix.Ancestors().OfType().FirstOrDefault() ?? + nodeToFix.Ancestors().OfType().FirstOrDefault(t => t is not ExtensionBlockDeclarationSyntax) ?? await nodeToFix.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); // Calculate what name should be used for the generated static partial property. @@ -210,7 +211,7 @@ where modifier.Kind() is SyntaxKind.PublicKeyword or SyntaxKind.PrivateKeyword o SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))))); - var typeDeclarationOrCompilationUnit = nodeToFix.Ancestors().OfType().FirstOrDefault() ?? root; + var typeDeclarationOrCompilationUnit = nodeToFix.Ancestors().OfType().FirstOrDefault(t => t is not ExtensionBlockDeclarationSyntax) ?? root; ImmutableArray operationArguments = operation is IObjectCreationOperation objectCreation ? @@ -255,7 +256,7 @@ operation is not (IInvocationOperation or IObjectCreationOperation)) SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))))); - var typeDeclarationOrCompilationUnit = nodeToFix.Ancestors().OfType().FirstOrDefault() ?? root; + var typeDeclarationOrCompilationUnit = nodeToFix.Ancestors().OfType().FirstOrDefault(t => t is not ExtensionBlockDeclarationSyntax) ?? root; ImmutableArray operationArguments = operation is IObjectCreationOperation objectCreation ? @@ -342,7 +343,7 @@ private static Document TryAddNewMember( var trackedRoot = root.TrackNodes(parent is null ? [nodeToFix] : [nodeToFix, parent]); root = trackedRoot.ReplaceNodes( - trackedRoot.GetCurrentNode(nodeToFix)!.Ancestors().OfType(), + trackedRoot.GetCurrentNode(nodeToFix)!.Ancestors().OfType().Where(t => t is not ExtensionBlockDeclarationSyntax), (_, typeDeclaration) => typeDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)) ? typeDeclaration : diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs index 061c34787063ba..24b7308fe93fd4 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs @@ -969,6 +969,66 @@ public void Foo() await VerifyCS.VerifyCodeFixAsync(test, fixedSource); } + [Fact] + public async Task CodeFixSupportsExtensionMembers_StaticInvocation() + { + string test = @"using System.Text.RegularExpressions; + +static class Foo +{ + extension(string value) + { + public bool Test() => [|Regex.IsMatch|](value, @""\d+""); + } +} +"; + string fixedSource = @"using System.Text.RegularExpressions; + +static partial class Foo +{ + extension(string value) + { + public bool Test() => MyRegex.IsMatch(value); + } + + [GeneratedRegex(@""\d+"")] + private static partial Regex MyRegex { get; } +} +"; + + await VerifyCS.VerifyCodeFixAsync(test, fixedSource); + } + + [Fact] + public async Task CodeFixSupportsExtensionMembers_Constructor() + { + string test = @"using System.Text.RegularExpressions; + +static class Foo +{ + extension(string value) + { + public Regex GetRegex() => [|new Regex|](@""\d+""); + } +} +"; + string fixedSource = @"using System.Text.RegularExpressions; + +static partial class Foo +{ + extension(string value) + { + public Regex GetRegex() => MyRegex; + } + + [GeneratedRegex(@""\d+"")] + private static partial Regex MyRegex { get; } +} +"; + + await VerifyCS.VerifyCodeFixAsync(test, fixedSource); + } + [Theory] [MemberData(nameof(InvocationTypes))] public async Task NoDiagnosticForRegexOptionsNonBacktracking(InvocationType invocationType)