Skip to content

Commit

Permalink
Add initial regex source generator (#59186)
Browse files Browse the repository at this point in the history
* Add RegexGeneratorAttribute

Adds the new RegexGenerator attribute that's a signal to the regex
generator to generate code for the specified regex.

* Implement RegexGenerator

Add a source generator for generating C# code for Regex.  This is
primarily a port of RegexCompiler.cs, generating C# code instead of
MSIL.

* Add generator test project

Adds tests dedicated to the mechanics of the source generator, e.g. that
appropriate diagnostics are issued for improper use of RegexGenerator.

* Integrate source generator into many regex tests

Start integrating the source generator into the regex test suite, so
that many existing tests also validate the generated code.

* Address PR feedback

* Improve cachability of source generator

Changing the generator to not collect all regexes together means we don't need to reprocess/regenerate all regexes every time any one of them is changed.

* Use closest matching ctor from GetRegexAsync

To better test the appropriate ctor usage.

* Improve a few of the polyfills

* Address PR feedback

* Fully qualify types and remove unnecessary $s

Also fixed one place where the IL we were generating wasn't as good as the reflection emit code.

* Suppress a couple more warnings

* Fix stray !

* Fix TODO about unrolling multi comparisons

Also clean up generated code in a few places to make it more readable / concise.

* Update resources per PR feedback

* Add more tests, clean up parser code, and allow instance/interface methods

* Fix test suppression on mobile
  • Loading branch information
stephentoub committed Sep 22, 2021
1 parent 072cbae commit 00aa651
Show file tree
Hide file tree
Showing 55 changed files with 10,017 additions and 975 deletions.
10 changes: 10 additions & 0 deletions docs/project/list-of-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,13 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL
| __`SYSLIB1037`__ | *_`SYSLIB1032`-`SYSLIB1039` reserved for System.Text.Json.SourceGeneration._* |
| __`SYSLIB1038`__ | *_`SYSLIB1032`-`SYSLIB1039` reserved for System.Text.Json.SourceGeneration._* |
| __`SYSLIB1039`__ | *_`SYSLIB1032`-`SYSLIB1039` reserved for System.Text.Json.SourceGeneration._* |
| __`SYSLIB1040`__ | Invalid RegexGenerator attribute |
| __`SYSLIB1041`__ | Multiple RegexGenerator attribute |
| __`SYSLIB1042`__ | Invalid RegexGenerator arguments |
| __`SYSLIB1043`__ | RegexGenerator method must have a valid signature |
| __`SYSLIB1044`__ | RegexGenerator only supports C# 10 and newer |
| __`SYSLIB1045`__ | *_`SYSLIB1045`-`SYSLIB1049` reserved for System.Text.RegularExpressions.Generator._* |
| __`SYSLIB1046`__ | *_`SYSLIB1045`-`SYSLIB1049` reserved for System.Text.RegularExpressions.Generator._* |
| __`SYSLIB1047`__ | *_`SYSLIB1045`-`SYSLIB1049` reserved for System.Text.RegularExpressions.Generator._* |
| __`SYSLIB1048`__ | *_`SYSLIB1045`-`SYSLIB1049` reserved for System.Text.RegularExpressions.Generator._* |
| __`SYSLIB1049`__ | *_`SYSLIB1045`-`SYSLIB1049` reserved for System.Text.RegularExpressions.Generator._* |
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31709.452
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{63551298-BFD4-43FC-8465-AC454228B83C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.CompilerServices.Unsafe", "..\System.Runtime.CompilerServices.Unsafe\ref\System.Runtime.CompilerServices.Unsafe.csproj", "{84AABEC1-5CDA-4AB8-819E-9CA508DB6F39}"
Expand All @@ -17,6 +21,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{15319A22-BC9
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D8FD137E-6961-4629-A71A-53394897FE6B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{7A5AF59C-5114-4788-B5AA-80C977766060}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.RegularExpressions.Generator", "gen\System.Text.RegularExpressions.Generator.csproj", "{3699C8E2-C354-4AED-81DC-ECBAC3EFEB4B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.RegularExpressions.Generators.Tests", "tests\System.Text.RegularExpressions.Generators.Tests\System.Text.RegularExpressions.Generators.Tests.csproj", "{32ABFCDA-10FD-4A98-A429-145C28021EBE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -47,17 +57,27 @@ Global
{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC}.Release|Any CPU.Build.0 = Release|Any CPU
{3699C8E2-C354-4AED-81DC-ECBAC3EFEB4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3699C8E2-C354-4AED-81DC-ECBAC3EFEB4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3699C8E2-C354-4AED-81DC-ECBAC3EFEB4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3699C8E2-C354-4AED-81DC-ECBAC3EFEB4B}.Release|Any CPU.Build.0 = Release|Any CPU
{32ABFCDA-10FD-4A98-A429-145C28021EBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32ABFCDA-10FD-4A98-A429-145C28021EBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32ABFCDA-10FD-4A98-A429-145C28021EBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32ABFCDA-10FD-4A98-A429-145C28021EBE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{63551298-BFD4-43FC-8465-AC454228B83C} = {2ACCCAAB-F0CE-4839-82BD-F174861DEA78}
{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC} = {2ACCCAAB-F0CE-4839-82BD-F174861DEA78}
{84AABEC1-5CDA-4AB8-819E-9CA508DB6F39} = {15319A22-BC91-407B-A795-334DD05C82A0}
{C043B00D-8662-43E4-9E87-8BB317059111} = {15319A22-BC91-407B-A795-334DD05C82A0}
{B7E3B087-583F-49B0-8820-787CD98E54C7} = {D8FD137E-6961-4629-A71A-53394897FE6B}
{C043B00D-8662-43E4-9E87-8BB317059111} = {15319A22-BC91-407B-A795-334DD05C82A0}
{0409C086-D7CC-43F8-9762-C94FB1E47F5B} = {D8FD137E-6961-4629-A71A-53394897FE6B}
{8EE1A7C4-3630-4900-8976-9B3ADAFF10DC} = {2ACCCAAB-F0CE-4839-82BD-F174861DEA78}
{3699C8E2-C354-4AED-81DC-ECBAC3EFEB4B} = {7A5AF59C-5114-4788-B5AA-80C977766060}
{32ABFCDA-10FD-4A98-A429-145C28021EBE} = {2ACCCAAB-F0CE-4839-82BD-F174861DEA78}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1ED4AB32-B7AA-478F-A96B-F725ACD0AABB}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using Microsoft.CodeAnalysis;

namespace System.Text.RegularExpressions.Generator
{
internal static class DiagnosticDescriptors
{
public static DiagnosticDescriptor InvalidRegexGeneratorAttribute { get; } = new DiagnosticDescriptor(
id: "SYSLIB1040",
title: new LocalizableResourceString(nameof(SR.InvalidRegexGeneratorAttributeTitle), SR.ResourceManager, typeof(FxResources.System.Text.RegularExpressions.Generator.SR)),
messageFormat: new LocalizableResourceString(nameof(SR.InvalidRegexGeneratorAttributeMessage), SR.ResourceManager, typeof(FxResources.System.Text.RegularExpressions.Generator.SR)),
category: "RegexGenerator",
DiagnosticSeverity.Error,
isEnabledByDefault: true,
customTags: WellKnownDiagnosticTags.NotConfigurable);

public static DiagnosticDescriptor MultipleRegexGeneratorAttributes { get; } = new DiagnosticDescriptor(
id: "SYSLIB1041",
title: new LocalizableResourceString(nameof(SR.InvalidRegexGeneratorAttributeTitle), SR.ResourceManager, typeof(FxResources.System.Text.RegularExpressions.Generator.SR)),
messageFormat: new LocalizableResourceString(nameof(SR.MultipleRegexGeneratorAttributesMessage), SR.ResourceManager, typeof(FxResources.System.Text.RegularExpressions.Generator.SR)),
category: "RegexGenerator",
DiagnosticSeverity.Error,
isEnabledByDefault: true,
customTags: WellKnownDiagnosticTags.NotConfigurable);

public static DiagnosticDescriptor InvalidRegexArguments { get; } = new DiagnosticDescriptor(
id: "SYSLIB1042",
title: new LocalizableResourceString(nameof(SR.InvalidRegexGeneratorAttributeTitle), SR.ResourceManager, typeof(FxResources.System.Text.RegularExpressions.Generator.SR)),
messageFormat: new LocalizableResourceString(nameof(SR.InvalidRegexArgumentsMessage), SR.ResourceManager, typeof(FxResources.System.Text.RegularExpressions.Generator.SR)),
category: "RegexGenerator",
DiagnosticSeverity.Error,
isEnabledByDefault: true,
customTags: WellKnownDiagnosticTags.NotConfigurable);

public static DiagnosticDescriptor RegexMethodMustHaveValidSignature { get; } = new DiagnosticDescriptor(
id: "SYSLIB1043",
title: new LocalizableResourceString(nameof(SR.InvalidRegexGeneratorAttributeTitle), SR.ResourceManager, typeof(FxResources.System.Text.RegularExpressions.Generator.SR)),
messageFormat: new LocalizableResourceString(nameof(SR.RegexMethodMustHaveValidSignatureMessage), SR.ResourceManager, typeof(FxResources.System.Text.RegularExpressions.Generator.SR)),
category: "RegexGenerator",
DiagnosticSeverity.Error,
isEnabledByDefault: true,
customTags: WellKnownDiagnosticTags.NotConfigurable);

public static DiagnosticDescriptor InvalidLangVersion { get; } = new DiagnosticDescriptor(
id: "SYSLIB1044",
title: new LocalizableResourceString(nameof(SR.InvalidRegexGeneratorAttributeTitle), SR.ResourceManager, typeof(FxResources.System.Text.RegularExpressions.Generator.SR)),
messageFormat: new LocalizableResourceString(nameof(SR.InvalidLangVersionMessage), SR.ResourceManager, typeof(FxResources.System.Text.RegularExpressions.Generator.SR)),
category: "RegexGenerator",
DiagnosticSeverity.Error,
isEnabledByDefault: true,
customTags: WellKnownDiagnosticTags.NotConfigurable);
}
}
Loading

0 comments on commit 00aa651

Please sign in to comment.