├── .config └── dotnet-tools.json ├── .devcontainer └── devcontainer.json ├── .editorconfig ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .husky ├── .gitattributes └── pre-commit ├── .vscode ├── extensions.json └── spellright.dict ├── Directory.Build.props ├── Directory.Packages.props ├── LICENSE ├── README.md ├── Zomp.SyncMethodGenerator.sln ├── codecov.yml ├── cspell.json ├── package.json ├── src ├── Directory.Build.props ├── Zomp.SyncMethodGenerator │ ├── AnalyzerReleases.Shipped.md │ ├── AnalyzerReleases.Unshipped.md │ ├── AsyncToSyncRewriter.cs │ ├── DiagnosticMessages.cs │ ├── Extensions.cs │ ├── Helpers │ │ └── EquatableArray.cs │ ├── MethodParent.cs │ ├── MethodParentDeclaration.cs │ ├── MethodToGenerate.cs │ ├── Models │ │ └── ReportedDiagnostic.cs │ ├── Operation.cs │ ├── SourceGenerationHelper.cs │ ├── SyncMethodSourceGenerator.cs │ ├── Zomp.SyncMethodGenerator.csproj │ └── tools │ │ ├── install.ps1 │ │ └── uninstall.ps1 └── images │ └── icon.png ├── stylecop.json ├── tests ├── GenerationSandbox.Tests │ ├── AsyncExtensions.GenericMath.cs │ ├── AsyncExtensions.cs │ ├── AsyncWithIProgress.cs │ ├── GenerationSandbox.Tests.csproj │ └── SyncTests.cs ├── Generator.Tests │ ├── ArgumentTests.cs │ ├── ConditionalExtensionTests.cs │ ├── DelegateTests.cs │ ├── ExtensionMethodTests.cs │ ├── ExternalLibraryTests.cs │ ├── FileNameTests.cs │ ├── Generator.Tests.csproj │ ├── GenericMathTests.cs │ ├── IncrementalGeneratorTests.cs │ ├── IntegrationTesting.cs │ ├── InterpolatedStringTests.cs │ ├── IsCancellationRequestedTests.cs │ ├── MemoryTests.cs │ ├── ModuleInitializer.cs │ ├── NullabilityTests.cs │ ├── ParentTests.cs │ ├── PreprocessorTests.cs │ ├── Snapshots │ │ ├── ArgumentTests.DropNamedArgument#CallProgressMethodAsync.g.verified.cs │ │ ├── ArgumentTests.DropNullArgument#CallProgressMethodAsync.g.verified.cs │ │ ├── ConditionalExtensionTests.CheckArrayNullability#g.verified.cs │ │ ├── ConditionalExtensionTests.ConditionalToExtension#g.verified.cs │ │ ├── ConditionalExtensionTests.HandleCastForArray#g.verified.cs │ │ ├── ConditionalExtensionTests.HandleCastForNull#g.verified.cs │ │ ├── ConditionalExtensionTests.KeepTypeParameters#g.verified.cs │ │ ├── ConditionalExtensionTests.LongChained#g.verified.cs │ │ ├── ConditionalExtensionTests.NullConditionalExtension#g.verified.cs │ │ ├── ConditionalExtensionTests.NullConditionalExtensionChained#g.verified.cs │ │ ├── ConditionalExtensionTests.NullConditionalWithoutExtension#g.verified.cs │ │ ├── ConditionalExtensionTests.StartWithExpression#g.verified.cs │ │ ├── DelegateTests.AsyncDelegate#g.verified.cs │ │ ├── DelegateTests.AsyncDelegateExplicit#g.verified.cs │ │ ├── DelegateTests.AsyncDelegateWithCancellationToken#g.verified.cs │ │ ├── DelegateTests.AsyncDelegateWithIProgress#g.verified.cs │ │ ├── DelegateTests.AsyncDelegateWithNullableIProgress#g.verified.cs │ │ ├── DelegateTests.AsyncDelegateWithParameter#g.verified.cs │ │ ├── DelegateTests.AsyncVarDelegateWithParameter#g.verified.cs │ │ ├── DelegateTests.AsyncVarDelegateWithParameterAndReturnType#g.verified.cs │ │ ├── DelegateTests.DropCompletedTaskFromLambda#g.verified.cs │ │ ├── DelegateTests.FuncToActionInParameter#g.verified.cs │ │ ├── DelegateTests.FuncToActionInParameterExplicitInvoke#g.verified.cs │ │ ├── DelegateTests.FuncToActionInParameterTwice#g.verified.cs │ │ ├── DelegateTests.FuncToActionInParameterTwiceExplicitInvoke#g.verified.cs │ │ ├── DelegateTests.FuncToActionInParameterTwiceWithArgument#g.verified.cs │ │ ├── ExtensionMethodTests.LeftOfTheDotTest#Tests.Class.MethodAsync.g.verified.cs │ │ ├── ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGeneric2ExtensionAsync.g.verified.cs │ │ ├── ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGenericExtensionAsync.g.verified.cs │ │ ├── ExternalLibraryTests.ToListAsync#g.verified.cs │ │ ├── FileNameTests.DoNotCollideClassNames#Test.Class{T,T2}.MethodAsync.g.verified.cs │ │ ├── FileNameTests.DoNotCollideClassNames#Test.Class{T}.MethodAsync.g.verified.cs │ │ ├── FileNameTests.DoNotCollideClassNames#g.verified.cs │ │ ├── GenericMathTests.GeneratesWithIProgressCorrectly.DotNet8_0#Test.EnumerableExtensions.IndexOfMaxSoFarAsync.g.verified.cs │ │ ├── IntegrationTesting.ChecksumRead#ChecksumReadAsync.g.verified.cs │ │ ├── IntegrationTesting.ChecksumRead#HalfCheckSumAsync.g.verified.cs │ │ ├── IntegrationTesting.CombineTwoLists#CombineAsync.g.verified.cs │ │ ├── IntegrationTesting.EagerPreconditionInIteratorBlock#ReadLineByLineAsync.g.verified.cs │ │ ├── IntegrationTesting.EagerPreconditionsInAsyncMethod#GetAllTextAsync.g.verified.cs │ │ ├── IntegrationTesting.GeneratesSyncMethodCorrectly#Test.EnumerableExtensions.GetAveragesAsync.g.verified.cs │ │ ├── IntegrationTesting.WithIAsyncEnumerator#EnumeratorTestAsync.g.verified.cs │ │ ├── InterpolatedStringTests.EnsureParentheses#g.verified.cs │ │ ├── InterpolatedStringTests.HandleFormatString#g.verified.cs │ │ ├── IsCancellationRequestedTests.IfCancelled#g.verified.cs │ │ ├── IsCancellationRequestedTests.IfNotCancelled#g.verified.cs │ │ ├── IsCancellationRequestedTests.WhileNotCancelled#g.verified.cs │ │ ├── MemoryTests.ConvertMemoryToSpan#g.verified.cs │ │ ├── MemoryTests.ConvertMemoryToSpanAfterPropertyAccess#g.verified.cs │ │ ├── MemoryTests.DropSpanAfterAsMemory#MakeArrayAsync.g.verified.cs │ │ ├── MemoryTests.DropSpanAfterAsMemoryWithWhitespace#MakeArrayAsync.g.verified.cs │ │ ├── MemoryTests.MemorySpanProperty_explicitType=False#MakeArray.g.verified.cs │ │ ├── MemoryTests.MemorySpanProperty_explicitType=True#MakeArray.g.verified.cs │ │ ├── MemoryTests.MemoryToSpan#ReadAsMemoryAsync.g.verified.cs │ │ ├── MemoryTests.NonPredefinedTypes#N1.Class.FillAsync.g.verified.cs │ │ ├── MemoryTests.PreserveUnrelatedSpan#HasMemoryAsync.g.verified.cs │ │ ├── MemoryTests.ReadOnlyMemoryToReadOnlySpan#WriteAsync.g.verified.cs │ │ ├── NullabilityTests.ConditionalNullable#Test.MyClass.MethodAsync.g.verified.cs │ │ ├── NullabilityTests.ConditionalNullableStructTwice#Test.MyClass.MethodAsync.g.verified.cs │ │ ├── NullabilityTests.ConditionalNullableTwice#Test.MyClass.MethodAsync.g.verified.cs │ │ ├── NullabilityTests.NoNullableSupport#Test.WithNullableDisabled.MethodAsync.g.verified.cs │ │ ├── NullabilityTests.NullableDisable#Test.WithNullableDisabled.DoNothingAsync.g.verified.cs │ │ ├── NullabilityTests.NullableOmitExplicit#Test.MyClass.MethodAsync.g.verified.cs │ │ ├── ParentTests.Record#Test.Record.MethodAsync.g.verified.cs │ │ ├── ParentTests.RecordClass#Test.Record.MethodAsync.g.verified.cs │ │ ├── ParentTests.RecordStruct#Test.RecordStruct.MethodAsync.g.verified.cs │ │ ├── ParentTests.Struct#Test.Struct.MethodAsync.g.verified.cs │ │ ├── PreprocessorTests.MacrosAroundBraces#g.verified.cs │ │ ├── SpecialMethodsTests.DropMethodsWithSpecialNamesInUserClass#g.verified.cs │ │ ├── SpecialMethodsTests.FromTaskResultCheck#g.verified.cs │ │ ├── SpecialMethodsTests.FromValueTaskResultCheck#g.verified.cs │ │ ├── SpecialMethodsTests.TaskDelayToThreadSleepWithInt#g.verified.cs │ │ ├── SpecialMethodsTests.TaskDelayToThreadSleepWithSpan#g.verified.cs │ │ ├── SyncOnlyTests.DoNotMixSymbols.verified.txt │ │ ├── SyncOnlyTests.DoNotRemove#g.verified.cs │ │ ├── SyncOnlyTests.DoNotRemoveInsideSyncOnly#g.verified.cs │ │ ├── SyncOnlyTests.InsideEmptyIf#g.verified.cs │ │ ├── SyncOnlyTests.InsideParameter#IsNullAsync.g.verified.cs │ │ ├── SyncOnlyTests.LastParameter#IsNullAsync.g.verified.cs │ │ ├── SyncOnlyTests.MultipleBlocksArentInterfering#g.verified.cs │ │ ├── SyncOnlyTests.NestedSyncOnly#g.verified.cs │ │ ├── SyncOnlyTests.NotSyncOnly#g.verified.cs │ │ ├── SyncOnlyTests.NotSyncOnlyFollowedBySyncOnly#g.verified.cs │ │ ├── SyncOnlyTests.NotSyncOnlyInsideSyncOnly.verified.txt │ │ ├── SyncOnlyTests.ProhibitElif.verified.txt │ │ ├── SyncOnlyTests.SimpleMacro#ExecAsync.g.verified.cs │ │ ├── SyncOnlyTests.StatementAtTheEnd#g.verified.cs │ │ ├── SyncOnlyTests.SwitchStatementProcessesDirectives#g.verified.cs │ │ ├── SyncOnlyTests.SyncOnlyBeforeMethodBody#MethodWithObsoleteSyncAsync.g.verified.cs │ │ ├── SystemAsyncExtensionsTests.AsyncForEachDeconstruct#SumAsync.g.verified.cs │ │ ├── SystemAsyncExtensionsTests.AsyncForEachQualified#SumAsync.g.verified.cs │ │ ├── SystemAsyncExtensionsTests.ConfiguredCancelableAsyncEnumerable#g.verified.cs │ │ ├── SystemAsyncExtensionsTests.ConfiguredCancelableAsyncEnumerableExtension#GetConfiguredEnumeratorAsync.g.verified.cs │ │ ├── SystemAsyncExtensionsTests.ConfiguredCancelableAsyncEnumerableExtensionUsingStatic#Test.Extensions.GetConfiguredAsyncEnumerator.g.verified.cs │ │ ├── SystemAsyncExtensionsTests.DropConfigureAwaitExtensions#InvokeAsync.g.verified.cs │ │ ├── SystemAsyncExtensionsTests.DropConfiguredCancelableAsyncEnumerable#Iterate.g.verified.cs │ │ ├── SystemAsyncExtensionsTests.DropConfiguredCancelableAsyncEnumerableExtensionInvocation#Test.Extensions.MethodAsync.g.verified.cs │ │ ├── SystemAsyncExtensionsTests.DropWithCancellation#Iterate.g.verified.cs │ │ ├── TypeTests.ArrayParameter#g.verified.cs │ │ ├── TypeTests.BinaryPattern#g.verified.cs │ │ ├── TypeTests.CastFullyQualifiedType#GetCustomObjectAsync.g.verified.cs │ │ ├── TypeTests.CastFullyQualifiedTypeTwice#GetCustomObjectAsync.g.verified.cs │ │ ├── TypeTests.ConvertExceptionType#g.verified.cs │ │ ├── TypeTests.ConvertForeachType#g.verified.cs │ │ ├── TypeTests.CreateNullableType#g.verified.cs │ │ ├── TypeTests.DeclarationExpression#g.verified.cs │ │ ├── TypeTests.EnumPattern#g.verified.cs │ │ ├── TypeTests.EnumPatternName#.Class.ReturnTrueAsync.g.verified.cs │ │ ├── TypeTests.EventHandlerType#g.verified.cs │ │ ├── TypeTests.FullyQualifiedArray#g.verified.cs │ │ ├── TypeTests.GenericClassWithGenericInnerClass#Test.Class{T}.FooAsync.g.verified.cs │ │ ├── TypeTests.HandleAsCast#g.verified.cs │ │ ├── TypeTests.HandleDiscardSymbol#g.verified.cs │ │ ├── TypeTests.HandleNameOf#g.verified.cs │ │ ├── TypeTests.HandleNameOfGenericTuple#g.verified.cs │ │ ├── TypeTests.HandleNullableTuple#g.verified.cs │ │ ├── TypeTests.HandleTuple#g.verified.cs │ │ ├── TypeTests.HandleTypeOf#g.verified.cs │ │ ├── TypeTests.NestedGenerics#g.verified.cs │ │ ├── TypeTests.NotPattern#g.verified.cs │ │ ├── TypeTests.NullableDeclarationExpression#g.verified.cs │ │ ├── TypeTests.NullableForeach#g.verified.cs │ │ ├── TypeTests.PatternIsEnumMember#g.verified.cs │ │ ├── TypeTests.PatternIsNotLiteral#g.verified.cs │ │ ├── TypeTests.PatternMatchingWithConstant#g.verified.cs │ │ ├── TypeTests.QualifiedGenericName#g.verified.cs │ │ ├── TypeTests.QualifiedNonGenericName#System.Class.MethodAsync.g.verified.cs │ │ ├── TypeTests.SwitchType#SwitchAsync.g.verified.cs │ │ ├── TypeTests.TestTypes#g.verified.cs │ │ ├── TypeTests.UseFullyQualifiedTypeInIsExpression#HasIsExpressionAsync.g.verified.cs │ │ ├── TypeTests.VariableDeclaration#g.verified.cs │ │ ├── TypeTests.VariableDeclarationRedundant#g.verified.cs │ │ ├── UnitTests.BasicEvent#g.verified.cs │ │ ├── UnitTests.BasicInterface#Test.IMyInterface.MethodAsync.g.verified.cs │ │ ├── UnitTests.BrokenIfStatement#g.verified.cs │ │ ├── UnitTests.CallPropertiesReturningTasksWithAsync#MyMethodAsync.g.verified.cs │ │ ├── UnitTests.CallWithTypeParameters#MyFuncAsync.g.verified.cs │ │ ├── UnitTests.ConvertAsyncDelegateToDelegate#g.verified.cs │ │ ├── UnitTests.ConvertAsyncDelegateToSync#g.verified.cs │ │ ├── UnitTests.DefaultParameter#GetColorAsync.g.verified.cs │ │ ├── UnitTests.DeleteIfBetweenPreprocessorDirectives#g.verified.cs │ │ ├── UnitTests.DoNotCallPropertiesReturningGenericTasks#MyMethodAsync.g.verified.cs │ │ ├── UnitTests.DoNotCallPropertiesReturningGenericTasksExpression#MyMethodAsync.g.verified.cs │ │ ├── UnitTests.DoNotCallPropertiesReturningTasks#MyMethodAsync.g.verified.cs │ │ ├── UnitTests.DoNotDropInvocationChainThatHasAsyncAnywhere#WriteAllTextAsync.g.verified.cs │ │ ├── UnitTests.DropBrackets#GetIntAsync.g.verified.cs │ │ ├── UnitTests.DropCompletedTask#ExecAsync.g.verified.cs │ │ ├── UnitTests.DropIProgressExpressionArgument#CallWithIProgressAsync.g.verified.cs │ │ ├── UnitTests.DropIProgressStatement#CallWithIProgressAsync.g.verified.cs │ │ ├── UnitTests.DropUnawaitedCompletedTask#DoSomethingAsync.g.verified.cs │ │ ├── UnitTests.DropUnawaitedCompletedValueTask#DoSomethingAsync.g.verified.cs │ │ ├── UnitTests.FindsASpan#GetMemoryOrSpanAsync.g.verified.cs │ │ ├── UnitTests.FullyQualifiedAndNullable#g.verified.cs │ │ ├── UnitTests.GenericAsyncCall#Test.GenericClass{T}.FooAsync.g.verified.cs │ │ ├── UnitTests.GenericClass#Test.GenericClass{T1,T2}.EmptyAsync.g.verified.cs │ │ ├── UnitTests.GenericClassMemberAccess#Test.GenericClass{T}.MethodAsync.g.verified.cs │ │ ├── UnitTests.HandleAsTask#g.verified.cs │ │ ├── UnitTests.HandleAsTaskOnParameter#g.verified.cs │ │ ├── UnitTests.HandleAttribute#ReadSomeBytesAsync.g.verified.cs │ │ ├── UnitTests.HandleAttributeOnLocalFunction#g.verified.cs │ │ ├── UnitTests.KeepDefaultValueTaskWithResult#ReturnDefault.g.verified.cs │ │ ├── UnitTests.LocalFunction#InternalExampleAsync.g.verified.cs │ │ ├── UnitTests.LocalFunctionDelegateWithEndingAsync#DoItAsync.g.verified.cs │ │ ├── UnitTests.LocalFunctionNonGeneric#InternalExampleAsync.g.verified.cs │ │ ├── UnitTests.MemoryToSpanWithBody#ReadAsMemoryAsync.g.verified.cs │ │ ├── UnitTests.MultipleClasses#NsOne.C1.C2.C3.C4.EmptyAsync.g.verified.cs │ │ ├── UnitTests.MultipleInitializers#g.verified.cs │ │ ├── UnitTests.MultipleNamespaces#NsOne.NsTwo.NsThree.NsFour.MultipleNamespaces.EmptyAsync.g.verified.cs │ │ ├── UnitTests.Overloads#ReadAsMemoryAsync.g.verified.cs │ │ ├── UnitTests.Overloads#ReadAsMemoryAsync_2.g.verified.cs │ │ ├── UnitTests.PassIAsyncDisposable#g.verified.cs │ │ ├── UnitTests.Preprocessor#WrappedAsync.g.verified.cs │ │ ├── UnitTests.ReturnDefaultValueTask#ReturnAsync.g.verified.cs │ │ ├── UnitTests.ReturnTask#ReturnAsync.g.verified.cs │ │ ├── UnitTests.ReturnTaskNoBody#ReturnAsync.g.verified.cs │ │ ├── UnitTests.ReturnValueTask#ReturnAsync.g.verified.cs │ │ ├── UnitTests.ReturnValueTaskConditional#ReturnAsync.g.verified.cs │ │ ├── UnitTests.ReturnValueTaskConditionalFalse#ReturnFalseAsync.g.verified.cs │ │ ├── UnitTests.ReturnValueTaskConditionalTrue#ReturnTrueAsync.g.verified.cs │ │ ├── UnitTests.ReturnValueTaskInstance#ReturnAsync.g.verified.cs │ │ ├── UnitTests.ReturnValueTaskNoBody#ReturnAsync.g.verified.cs │ │ ├── UnitTests.StaticUsings#N1.C1.MethodAsync.g.verified.cs │ │ ├── UnitTests.TaskOfArrayOfGeneric#GetArrayOfTAsync.g.verified.cs │ │ ├── UnitTests.TaskOfT#GetPointAsync.g.verified.cs │ │ ├── UnitTests.TaskOfT2IList#GetArrayOfTAsync.g.verified.cs │ │ ├── UnitTests.TaskOfTArray#GetPointAsync.g.verified.cs │ │ ├── UnitTests.TaskOfTIList#GetPointAsync.g.verified.cs │ │ ├── UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.OneParamsAsync.g.verified.cs │ │ ├── UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.TwoParamsAsync.g.verified.cs │ │ ├── UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.ZeroParamsAsync.g.verified.cs │ │ ├── UnitTests.VerifyAsyncParamHandling#g.verified.cs │ │ ├── UnitTests.VerifyParamHandling#g.verified.cs │ │ ├── UnitTests.WhenDroppingStatementLeaveTrivia#g.verified.cs │ │ ├── UnitTests.WithAction#WithAction.g.verified.cs │ │ └── UnitTests.WithPreprocessor#WithPreprocessorAsync.g.verified.cs │ ├── SourceType.cs │ ├── SpecialMethodsTests.cs │ ├── SyncOnlyTests.cs │ ├── SystemAsyncExtensionsTests.cs │ ├── TestHelper.cs │ ├── TypeTests.cs │ └── UnitTests.cs └── coverlet.runsettings ├── version.json └── yarn.lock /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "dotnet-reportgenerator-globaltool": { 6 | "version": "5.4.4", 7 | "commands": [ 8 | "reportgenerator" 9 | ] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/dotnet 3 | { 4 | "name": "Zomp Sync Method Generator", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/dotnet:8.0-jammy", 7 | // Features to add to the dev container. More info: https://containers.dev/features. 8 | // "features": {}, 9 | // Configure tool-specific properties. 10 | "customizations": { 11 | // Configure properties specific to VS Code. 12 | "vscode": { 13 | "settings": {}, 14 | "extensions": [] 15 | } 16 | }, 17 | "features": { 18 | "ghcr.io/devcontainers/features/dotnet:2": { 19 | "version": "6.0", 20 | "additionalVersions": "8.0, 9.0" 21 | }, 22 | "ghcr.io/devcontainers/features/sshd:1": { 23 | "version": "latest" 24 | } 25 | }, 26 | "mounts": [ 27 | "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" 28 | ], 29 | "postCreateCommand": "dotnet tool restore && dotnet restore" 30 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 31 | // "remoteUser": "root" 32 | } 33 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = crlf 3 | indent_style = space 4 | indent_size = 2 5 | insert_final_newline = true 6 | spelling_exclusion_path = .\.vscode\spellright.dict 7 | 8 | # Xml project files 9 | [*.{csproj,props}] 10 | indent_size = 2 11 | 12 | # C# files 13 | [*.cs] 14 | csharp_style_namespace_declarations = file_scoped 15 | dotnet_diagnostic.SA1101.severity = none 16 | dotnet_diagnostic.SA1633.severity = none 17 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3540 18 | dotnet_diagnostic.SA1118.severity = none 19 | indent_size = 4 20 | csharp_style_expression_bodied_methods = true:silent 21 | csharp_style_namespace_declarations = file_scoped 22 | csharp_style_expression_bodied_operators = true 23 | csharp_style_expression_bodied_local_functions = true 24 | 25 | # SA1005: Single line comments should begin with single space 26 | dotnet_diagnostic.SA1005.severity = none 27 | 28 | csharp_style_var_for_built_in_types = true:error 29 | csharp_style_var_when_type_is_apparent = true:error 30 | csharp_style_var_elsewhere = true:error 31 | 32 | [tests/**.cs] 33 | # CS1591: Missing XML comment for publicly visible type or member 34 | dotnet_diagnostic.CS1591.severity = none 35 | dotnet_diagnostic.CA1819.severity = none 36 | dotnet_diagnostic.CA2255.severity = none 37 | 38 | # SA1005: Single line comments should begin with single space 39 | dotnet_diagnostic.SA1005.severity = none 40 | 41 | # SA1512: Single-line comments should not be followed by blank line 42 | dotnet_diagnostic.SA1512.severity = none 43 | 44 | dotnet_diagnostic.IDE0305.severity = error 45 | dotnet_diagnostic.IDE0340.severity = error 46 | 47 | [*.sh] 48 | end_of_line = lf 49 | -------------------------------------------------------------------------------- /.husky/.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | formatLevel=minimal 2 | if [ -n "$1" ]; then 3 | formatLevel=$1 4 | fi 5 | 6 | EXIT_STATUS=0 7 | dotnet format --verify-no-changes Zomp.SyncMethodGenerator.sln --exclude tests/Generator.Tests/Snapshots/*g.verified.cs -v $formatLevel whitespace || EXIT_STATUS=$? 8 | exit $EXIT_STATUS 9 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ban.spellright", 4 | "DavidAnson.vscode-markdownlint", 5 | "streetsidesoftware.code-spell-checker", 6 | "foxundermoon.shell-format", 7 | "GitHub.vscode-github-actions", 8 | "ms-dotnettools.csharp" 9 | ], 10 | "unwantedRecommendations": ["ban.spellright"] 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/spellright.dict: -------------------------------------------------------------------------------- 1 | awaitable 2 | codecov 3 | equatable 4 | extensi 5 | impl 6 | func 7 | Nuget 8 | numerics 9 | retval 10 | zomp 11 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | © Zomp Inc. All rights reserved. 4 | Zomp 5 | Victor Irzak 6 | false 7 | $(MSBuildThisFileDirectory)artifacts 8 | preview 9 | enable 10 | enable 11 | true 12 | true 13 | true 14 | true 15 | True 16 | true 17 | latest 18 | true 19 | AllEnabledByDefault 20 | 21 | 22 | 23 | 24 | /tmp/$(USER)/project/obj/ 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | $(NoWarn);CA1810 35 | 36 | 37 | $(NoWarn);CA1848 38 | 39 | 40 | $(NoWarn);CA1711;CA1707 41 | 42 | 43 | $(NoWarn);CA2007 44 | 45 | 46 | $(NoWarn);SA1502 47 | 48 | 49 | $(NoWarn);SA1600 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Victor Irzak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Zomp.SyncMethodGenerator.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.32916.344 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Zomp.SyncMethodGenerator", "src\Zomp.SyncMethodGenerator\Zomp.SyncMethodGenerator.csproj", "{9C4836A5-FD48-4563-AFAF-EC32AD1859BD}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{120EB42D-886C-4640-9C40-89104F84BABE}" 9 | ProjectSection(SolutionItems) = preProject 10 | src\Directory.Build.props = src\Directory.Build.props 11 | EndProjectSection 12 | EndProject 13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{AE4C95B5-1D26-4B3F-9459-4D0F70099FD5}" 14 | ProjectSection(SolutionItems) = preProject 15 | tests\coverlet.runsettings = tests\coverlet.runsettings 16 | EndProjectSection 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0504B10E-4B5F-45E9-8661-05057A232157}" 19 | ProjectSection(SolutionItems) = preProject 20 | .editorconfig = .editorconfig 21 | .gitignore = .gitignore 22 | Directory.Build.props = Directory.Build.props 23 | Directory.Packages.props = Directory.Packages.props 24 | NuGet.Config = NuGet.Config 25 | package.json = package.json 26 | version.json = version.json 27 | EndProjectSection 28 | EndProject 29 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generator.Tests", "tests\Generator.Tests\Generator.Tests.csproj", "{DEB7DF97-43ED-49D6-8C05-6B2681208610}" 30 | EndProject 31 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenerationSandbox.Tests", "tests\GenerationSandbox.Tests\GenerationSandbox.Tests.csproj", "{BDEA21AD-6081-44AC-AD85-63803FDBED89}" 32 | EndProject 33 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{12C22879-AE16-4BD4-ADE5-1F97DDEF9E11}" 34 | EndProject 35 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{1C91E12D-2680-4E7D-9A8F-8E4548F49C62}" 36 | ProjectSection(SolutionItems) = preProject 37 | .github\workflows\build.yml = .github\workflows\build.yml 38 | EndProjectSection 39 | EndProject 40 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".husky", ".husky", "{D10EEA31-447A-4D33-A305-E5274E1B4240}" 41 | ProjectSection(SolutionItems) = preProject 42 | .husky\pre-commit = .husky\pre-commit 43 | EndProjectSection 44 | EndProject 45 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".config", ".config", "{F40847A8-EF57-4E9F-8AF6-CAB2CC20B45E}" 46 | ProjectSection(SolutionItems) = preProject 47 | .config\dotnet-tools.json = .config\dotnet-tools.json 48 | EndProjectSection 49 | EndProject 50 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".vscode", ".vscode", "{356FB7F3-77F6-4DF7-95CC-25EA735F4755}" 51 | ProjectSection(SolutionItems) = preProject 52 | .vscode\spellright.dict = .vscode\spellright.dict 53 | EndProjectSection 54 | EndProject 55 | Global 56 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 57 | Debug|Any CPU = Debug|Any CPU 58 | Release|Any CPU = Release|Any CPU 59 | EndGlobalSection 60 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 61 | {9C4836A5-FD48-4563-AFAF-EC32AD1859BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 62 | {9C4836A5-FD48-4563-AFAF-EC32AD1859BD}.Debug|Any CPU.Build.0 = Debug|Any CPU 63 | {9C4836A5-FD48-4563-AFAF-EC32AD1859BD}.Release|Any CPU.ActiveCfg = Release|Any CPU 64 | {9C4836A5-FD48-4563-AFAF-EC32AD1859BD}.Release|Any CPU.Build.0 = Release|Any CPU 65 | {DEB7DF97-43ED-49D6-8C05-6B2681208610}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 66 | {DEB7DF97-43ED-49D6-8C05-6B2681208610}.Debug|Any CPU.Build.0 = Debug|Any CPU 67 | {DEB7DF97-43ED-49D6-8C05-6B2681208610}.Release|Any CPU.ActiveCfg = Release|Any CPU 68 | {DEB7DF97-43ED-49D6-8C05-6B2681208610}.Release|Any CPU.Build.0 = Release|Any CPU 69 | {BDEA21AD-6081-44AC-AD85-63803FDBED89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 70 | {BDEA21AD-6081-44AC-AD85-63803FDBED89}.Debug|Any CPU.Build.0 = Debug|Any CPU 71 | {BDEA21AD-6081-44AC-AD85-63803FDBED89}.Release|Any CPU.ActiveCfg = Release|Any CPU 72 | {BDEA21AD-6081-44AC-AD85-63803FDBED89}.Release|Any CPU.Build.0 = Release|Any CPU 73 | EndGlobalSection 74 | GlobalSection(SolutionProperties) = preSolution 75 | HideSolutionNode = FALSE 76 | EndGlobalSection 77 | GlobalSection(NestedProjects) = preSolution 78 | {9C4836A5-FD48-4563-AFAF-EC32AD1859BD} = {120EB42D-886C-4640-9C40-89104F84BABE} 79 | {DEB7DF97-43ED-49D6-8C05-6B2681208610} = {AE4C95B5-1D26-4B3F-9459-4D0F70099FD5} 80 | {BDEA21AD-6081-44AC-AD85-63803FDBED89} = {AE4C95B5-1D26-4B3F-9459-4D0F70099FD5} 81 | {12C22879-AE16-4BD4-ADE5-1F97DDEF9E11} = {0504B10E-4B5F-45E9-8661-05057A232157} 82 | {1C91E12D-2680-4E7D-9A8F-8E4548F49C62} = {12C22879-AE16-4BD4-ADE5-1F97DDEF9E11} 83 | {D10EEA31-447A-4D33-A305-E5274E1B4240} = {0504B10E-4B5F-45E9-8661-05057A232157} 84 | {F40847A8-EF57-4E9F-8AF6-CAB2CC20B45E} = {0504B10E-4B5F-45E9-8661-05057A232157} 85 | {356FB7F3-77F6-4DF7-95CC-25EA735F4755} = {0504B10E-4B5F-45E9-8661-05057A232157} 86 | EndGlobalSection 87 | GlobalSection(ExtensibilityGlobals) = postSolution 88 | SolutionGuid = {0CDD8FAE-3E18-41AF-8A3B-3E12A09E0E41} 89 | EndGlobalSection 90 | EndGlobal 91 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | threshold: 10% 6 | patch: 7 | default: 8 | threshold: 10% 9 | -------------------------------------------------------------------------------- /cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", 3 | "version": "0.2", 4 | // Enable your dictionary by adding it to the list of `dictionaries` 5 | "dictionaries": ["csharp", "custom-words"], 6 | "language": "en,en-CA,softwareTerms", 7 | "languageSettings": [ 8 | { 9 | "languageId": "markdown", 10 | "ignoreRegExpList": ["/`[\\s\\S]*?`/g"] 11 | } 12 | ], 13 | 14 | // Tell CSpell about your dictionary 15 | "dictionaryDefinitions": [ 16 | { 17 | // The name of the dictionary is used to look it up. 18 | "name": "custom-words", 19 | // Path to the custom word file. Relative to this `cspell.json` file. 20 | "path": "./.vscode/spellright.dict", 21 | // Some editor extensions will use `addWords` for adding words to your 22 | // personal dictionary. 23 | "addWords": true 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "husky": "^9.1.7" 4 | }, 5 | "license": "SEE LICENSE IN LICENSE", 6 | "scripts": { 7 | "prepare": "husky install" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Sync Method Generator 6 | git 7 | https://github.com/zompinc/sync-method-generator.git 8 | https://github.com/zompinc/sync-method-generator 9 | false 10 | snupkg 11 | true 12 | nullablePublicOnly 13 | true 14 | icon.png 15 | true 16 | true 17 | README.md 18 | MIT 19 | 20 | 21 | 22 | true 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/AnalyzerReleases.Shipped.md: -------------------------------------------------------------------------------- 1 | ; Shipped analyzer releases 2 | ; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md 3 | 4 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/AnalyzerReleases.Unshipped.md: -------------------------------------------------------------------------------- 1 | ; Unshipped analyzer release 2 | ; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md 3 | 4 | ### New Rules 5 | 6 | Rule ID | Category | Severity | Notes 7 | --------|----------|----------|------- 8 | ZSMGEN001 | Preprocessor | Error | DiagnosticMessages 9 | ZSMGEN002 | Preprocessor | Error | DiagnosticMessages 10 | ZSMGEN003 | Preprocessor | Error | DiagnosticMessages 11 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/DiagnosticMessages.cs: -------------------------------------------------------------------------------- 1 | namespace Zomp.SyncMethodGenerator; 2 | 3 | internal static class DiagnosticMessages 4 | { 5 | internal static readonly DiagnosticDescriptor InvalidNesting = new( 6 | id: "ZSMGEN001", 7 | title: $"{AsyncToSyncRewriter.SyncOnly} and !{AsyncToSyncRewriter.SyncOnly} cannot be nested inside each other", 8 | messageFormat: $"Couldn't process directive '{{0}}'. {AsyncToSyncRewriter.SyncOnly} and !{AsyncToSyncRewriter.SyncOnly} cannot be nested inside each other.", 9 | category: Preprocessor, 10 | DiagnosticSeverity.Error, 11 | isEnabledByDefault: true); 12 | 13 | internal static readonly DiagnosticDescriptor InvalidCondition = new( 14 | id: "ZSMGEN002", 15 | title: $"{AsyncToSyncRewriter.SyncOnly} and other symbols must not be in the same condition", 16 | messageFormat: $"Couldn't process condition '{{0}}'. {AsyncToSyncRewriter.SyncOnly} and other symbols must not be in the same condition.", 17 | category: Preprocessor, 18 | DiagnosticSeverity.Error, 19 | isEnabledByDefault: true); 20 | 21 | internal static readonly DiagnosticDescriptor InvalidElif = new( 22 | id: "ZSMGEN003", 23 | title: $"{AsyncToSyncRewriter.SyncOnly} cannot be used with #elif", 24 | messageFormat: $"Couldn't process directive '{{0}}'. {AsyncToSyncRewriter.SyncOnly} cannot be used with #elif.", 25 | category: Preprocessor, 26 | DiagnosticSeverity.Error, 27 | isEnabledByDefault: true); 28 | 29 | private const string Preprocessor = "Preprocessor"; 30 | } 31 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/Extensions.cs: -------------------------------------------------------------------------------- 1 | using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; 2 | 3 | namespace Zomp.SyncMethodGenerator; 4 | 5 | internal static class Extensions 6 | { 7 | /// 8 | /// Gets array of indices that match a predicate. 9 | /// 10 | /// The type. 11 | /// Original elements. 12 | /// The predicate. 13 | /// Array of indices that match a predicate. 14 | internal static int[] GetIndices(this IEnumerable elements, Func predicate) 15 | => elements.Select((ps, i) => (ps, i)) 16 | .Where((elem, i) => predicate(elem.ps, i)) 17 | .Select(t => t.i) 18 | .ToArray(); 19 | 20 | internal static int[] GetIndices(this IEnumerable elements, Func predicate) 21 | => elements.GetIndices((e, _) => predicate(e)); 22 | 23 | internal static bool EndsWithAsync(this string str) 24 | => str.EndsWith("Async", StringComparison.Ordinal); 25 | 26 | internal static SyntaxToken PrependSpace(this SyntaxToken token) 27 | => token.WithLeadingTrivia(Space); 28 | 29 | internal static SyntaxToken AppendSpace(this SyntaxToken token) 30 | => token.WithTrailingTrivia(Space); 31 | 32 | internal static T PrependSpace(this T syntax) 33 | where T : ExpressionSyntax 34 | => syntax.WithLeadingTrivia(Space); 35 | 36 | internal static T AppendSpace(this T syntax) 37 | where T : ExpressionSyntax 38 | => syntax.WithTrailingTrivia(Space); 39 | 40 | internal static SimpleNameSyntax ChangeIdentifier(this MemberAccessExpressionSyntax mae, string id) 41 | { 42 | return mae is { Name: GenericNameSyntax gns } 43 | ? GenericName(Identifier(id), gns.TypeArgumentList) 44 | : IdentifierName(Identifier(id)); 45 | } 46 | 47 | internal static SimpleNameSyntax ChangeIdentifier(this MemberBindingExpressionSyntax mae, string id) 48 | { 49 | return mae is { Name: GenericNameSyntax gns } 50 | ? GenericName(Identifier(id), gns.TypeArgumentList) 51 | : IdentifierName(Identifier(id)); 52 | } 53 | 54 | internal static BlockSyntax CreateBlock(this ICollection statements, int indentationLevel = 0) 55 | { 56 | var list = new List(); 57 | 58 | var i = 0; 59 | foreach (var statement in statements) 60 | { 61 | var leading = new List(); 62 | var trailing = new List() { CarriageReturnLineFeed }; 63 | 64 | if (i == 0) 65 | { 66 | leading.Add(CarriageReturnLineFeed); 67 | } 68 | 69 | if (statement is IfStatementSyntax && i < statements.Count - 1) 70 | { 71 | trailing.Add(CarriageReturnLineFeed); 72 | } 73 | 74 | if (i == statements.Count - 1) 75 | { 76 | trailing.Add(Whitespace(new string(' ', 4 * indentationLevel))); 77 | } 78 | 79 | if (indentationLevel > 0) 80 | { 81 | leading.Add(Whitespace(new string(' ', 4 * (indentationLevel + 1)))); 82 | } 83 | 84 | list.Add(statement.WithTrailingTrivia(trailing) 85 | .WithLeadingTrivia(leading)); 86 | ++i; 87 | } 88 | 89 | return Block(List(list)) 90 | .WithLeadingTrivia(CarriageReturnLineFeed, Whitespace(new string(' ', 4 * indentationLevel))); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/Helpers/EquatableArray.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | 4 | using System.Collections; 5 | using System.Diagnostics.CodeAnalysis; 6 | 7 | namespace Zomp.SyncMethodGenerator.Helpers; 8 | 9 | /// 10 | /// An immutable, equatable array. This is equivalent to but with value equality support. 11 | /// 12 | /// The type of values in the array. 13 | /// 14 | /// Modified from: https://github.com/dotnet/runtime/issues/77183#issuecomment-1284577055. 15 | /// Remove this struct when the issue above is resolved. 16 | /// 17 | /// 18 | /// Initializes a new instance of the struct. 19 | /// 20 | /// The input to wrap. 21 | [ExcludeFromCodeCoverage] 22 | internal readonly struct EquatableArray(ImmutableArray array) : IEquatable>, IEnumerable 23 | where T : IEquatable 24 | { 25 | /// 26 | /// The underlying array. 27 | /// 28 | private readonly T[]? array = Unsafe.As, T[]?>(ref array); 29 | 30 | /// 31 | /// Gets a value indicating whether the current array is empty. 32 | /// 33 | public bool IsEmpty 34 | { 35 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 36 | get => AsImmutableArray().IsEmpty; 37 | } 38 | 39 | /// 40 | /// Gets a reference to an item at a specified position within the array. 41 | /// 42 | /// The index of the item to retrieve a reference to. 43 | /// A reference to an item at a specified position within the array. 44 | public ref readonly T this[int index] 45 | { 46 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 47 | get => ref AsImmutableArray().ItemRef(index); 48 | } 49 | 50 | /// 51 | /// Implicitly converts an to . 52 | /// 53 | /// An instance from a given . 54 | public static implicit operator EquatableArray(ImmutableArray array) => FromImmutableArray(array); 55 | 56 | /// 57 | /// Implicitly converts an to . 58 | /// 59 | /// An instance from a given . 60 | public static implicit operator ImmutableArray(EquatableArray array) => array.AsImmutableArray(); 61 | 62 | /// 63 | /// Checks whether two values are the same. 64 | /// 65 | /// The first value. 66 | /// The second value. 67 | /// Whether and are equal. 68 | public static bool operator ==(EquatableArray left, EquatableArray right) => left.Equals(right); 69 | 70 | /// 71 | /// Checks whether two values are not the same. 72 | /// 73 | /// The first value. 74 | /// The second value. 75 | /// Whether and are not equal. 76 | public static bool operator !=(EquatableArray left, EquatableArray right) => !left.Equals(right); 77 | 78 | /// 79 | /// Creates an instance from a given . 80 | /// 81 | /// The input instance. 82 | /// An instance from a given . 83 | public static EquatableArray FromImmutableArray(ImmutableArray array) 84 | { 85 | return new(array); 86 | } 87 | 88 | /// 89 | public bool Equals(EquatableArray array) 90 | { 91 | return AsSpan().SequenceEqual(array.AsSpan()); 92 | } 93 | 94 | /// 95 | public override bool Equals([NotNullWhen(true)] object? obj) 96 | { 97 | return obj is EquatableArray array && Equals(this, array); 98 | } 99 | 100 | /// 101 | public override int GetHashCode() 102 | { 103 | if (this.array is not T[] array) 104 | { 105 | return 0; 106 | } 107 | 108 | HashCode hashCode = default; 109 | 110 | foreach (var item in array) 111 | { 112 | hashCode.Add(item); 113 | } 114 | 115 | return hashCode.ToHashCode(); 116 | } 117 | 118 | /// 119 | /// Gets an instance from the current . 120 | /// 121 | /// The from the current . 122 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 123 | public ImmutableArray AsImmutableArray() 124 | { 125 | return Unsafe.As>(ref Unsafe.AsRef(in array)); 126 | } 127 | 128 | /// 129 | /// Returns a wrapping the current items. 130 | /// 131 | /// A wrapping the current items. 132 | public ReadOnlySpan AsSpan() 133 | { 134 | return AsImmutableArray().AsSpan(); 135 | } 136 | 137 | /// 138 | /// Copies the contents of this instance to a mutable array. 139 | /// 140 | /// The newly instantiated array. 141 | public T[] ToArray() 142 | { 143 | return [.. AsImmutableArray()]; 144 | } 145 | 146 | /// 147 | /// Gets an value to traverse items in the current array. 148 | /// 149 | /// An value to traverse items in the current array. 150 | public ImmutableArray.Enumerator GetEnumerator() 151 | { 152 | return AsImmutableArray().GetEnumerator(); 153 | } 154 | 155 | /// 156 | IEnumerator IEnumerable.GetEnumerator() 157 | { 158 | return ((IEnumerable)AsImmutableArray()).GetEnumerator(); 159 | } 160 | 161 | /// 162 | IEnumerator IEnumerable.GetEnumerator() 163 | { 164 | return ((IEnumerable)AsImmutableArray()).GetEnumerator(); 165 | } 166 | } 167 | 168 | /// 169 | /// Extensions for . 170 | /// 171 | [ExcludeFromCodeCoverage] 172 | internal static class EquatableArray 173 | { 174 | /// 175 | /// Creates an instance from a given . 176 | /// 177 | /// The type of items in the input array. 178 | /// The input instance. 179 | /// An instance from a given . 180 | public static EquatableArray AsEquatableArray(this ImmutableArray array) 181 | where T : IEquatable 182 | { 183 | return new(array); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/MethodParent.cs: -------------------------------------------------------------------------------- 1 | namespace Zomp.SyncMethodGenerator; 2 | 3 | internal enum MethodParent 4 | { 5 | Class, 6 | Struct, 7 | Record, 8 | Interface, 9 | } 10 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/MethodParentDeclaration.cs: -------------------------------------------------------------------------------- 1 | namespace Zomp.SyncMethodGenerator; 2 | 3 | /// 4 | /// Represents a class a belongs to. 5 | /// 6 | /// Type of container. 7 | /// Class name. 8 | /// A list of modifiers. 9 | /// A list of type parameters. 10 | /// Indicates whether struct or class are explicitly specified for a record. 11 | internal sealed record MethodParentDeclaration(MethodParent MethodParent, string ParentName, EquatableArray Modifiers, EquatableArray TypeParameterListSyntax, SyntaxToken ClassOrStructKeyword) 12 | { 13 | public MethodParentDeclaration(MethodParent methodParent, SyntaxToken parentName, SyntaxTokenList modifiers, TypeParameterListSyntax? typeParameterList, SyntaxToken classOrStructKeyword = default) 14 | : this( 15 | methodParent, 16 | parentName.ValueText, 17 | modifiers.Select(z => (ushort)z.RawKind).Where(z => z != (ushort)SyntaxKind.PartialKeyword).ToImmutableArray(), 18 | (typeParameterList is null ? [] : typeParameterList.Parameters.Select(z => z.Identifier.ValueText)).ToImmutableArray(), 19 | classOrStructKeyword) 20 | { 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/MethodToGenerate.cs: -------------------------------------------------------------------------------- 1 | namespace Zomp.SyncMethodGenerator; 2 | 3 | /// 4 | /// Represents a sync method to generate from its async version. 5 | /// 6 | /// Index of the method in the source file. 7 | /// List of namespaces this method is under. 8 | /// True if namespace is file scoped. 9 | /// List of classes/structs/records this method belongs to starting from the outer-most class. 10 | /// Name of the method. 11 | /// Implementation. 12 | /// Disables nullable for the method. 13 | /// Diagnostics. 14 | /// True if there are errors in . 15 | internal sealed record MethodToGenerate( 16 | int Index, 17 | EquatableArray Namespaces, 18 | bool IsNamespaceFileScoped, 19 | EquatableArray Parents, 20 | string MethodName, 21 | string Implementation, 22 | bool DisableNullable, 23 | EquatableArray Diagnostics, 24 | bool HasErrors); 25 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/Models/ReportedDiagnostic.cs: -------------------------------------------------------------------------------- 1 | namespace Zomp.SyncMethodGenerator.Models; 2 | 3 | /// 4 | /// Basic diagnostic description for reporting diagnostic inside the incremental pipeline. 5 | /// 6 | /// Diagnostic descriptor. 7 | /// File path. 8 | /// Text span. 9 | /// Line span. 10 | /// Trivia. 11 | /// 12 | internal sealed record ReportedDiagnostic(DiagnosticDescriptor Descriptor, string FilePath, TextSpan TextSpan, LinePositionSpan LineSpan, string Trivia) 13 | { 14 | /// 15 | /// Implicitly converts to . 16 | /// 17 | /// Diagnostic to convert. 18 | public static implicit operator Diagnostic(ReportedDiagnostic diagnostic) 19 | => Diagnostic.Create( 20 | descriptor: diagnostic.Descriptor, 21 | location: Location.Create(diagnostic.FilePath, diagnostic.TextSpan, diagnostic.LineSpan), 22 | messageArgs: [diagnostic.Trivia]); 23 | 24 | /// 25 | /// Creates a new from and . 26 | /// 27 | /// Descriptor. 28 | /// Location. 29 | /// Trivia. 30 | /// A new . 31 | public static ReportedDiagnostic Create(DiagnosticDescriptor descriptor, Location location, string trivia) 32 | { 33 | return new(descriptor, location.SourceTree?.FilePath ?? string.Empty, location.SourceSpan, location.GetLineSpan().Span, trivia); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/Operation.cs: -------------------------------------------------------------------------------- 1 | namespace Zomp.SyncMethodGenerator; 2 | 3 | [N.SourceGenerators.UnionTypes.UnionType(typeof(List), "NewStatements")] 4 | [N.SourceGenerators.UnionTypes.UnionType(typeof(bool), "RemoveLeadingEndIf")] 5 | internal sealed partial class Operation 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/SourceGenerationHelper.cs: -------------------------------------------------------------------------------- 1 | namespace Zomp.SyncMethodGenerator; 2 | 3 | /// 4 | /// Contains routines to construct a generated source file with a synchronized method. 5 | /// 6 | public static class SourceGenerationHelper 7 | { 8 | internal const string CreateSyncVersionAttributeSource = $$""" 9 | // 10 | namespace Zomp.SyncMethodGenerator 11 | { 12 | #if !SYNC_METHOD_GENERATOR_DISABLE_ATTRIBUTE_GENERATION 13 | /// 14 | /// An attribute that can be used to automatically generate a synchronous version of an async method. Must be used in a partial class. 15 | /// 16 | [System.AttributeUsage(System.AttributeTargets.Method)] 17 | internal class {{SyncMethodSourceGenerator.CreateSyncVersionAttribute}} : System.Attribute 18 | { 19 | /// 20 | /// Gets or sets a value indicating whether "#nullable enable" directive will be omitted from generated code. False by default. 21 | /// 22 | public bool {{SyncMethodSourceGenerator.OmitNullableDirective}} { get; set; } 23 | } 24 | #endif 25 | } 26 | """; 27 | 28 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0072:Add missing cases", Justification = "Only deal with selected SyntaxKinds")] 29 | internal static string GenerateExtensionClass(MethodToGenerate methodToGenerate) 30 | { 31 | static string GetKeyword(SyntaxKind sk) => sk switch 32 | { 33 | SyntaxKind.PublicKeyword => "public", 34 | SyntaxKind.InternalKeyword => "internal", 35 | SyntaxKind.PrivateKeyword => "private", 36 | SyntaxKind.SealedKeyword => "sealed", 37 | SyntaxKind.ProtectedKeyword => "protected", 38 | SyntaxKind.StaticKeyword => "static", 39 | SyntaxKind.AbstractKeyword => "abstract", 40 | _ => throw new InvalidOperationException($"{sk} is not supported"), 41 | }; 42 | 43 | // Handle namespaces 44 | var sbBegin = new StringBuilder(); 45 | var sbEnd = new StringBuilder(); 46 | var i = 0; 47 | 48 | if (!methodToGenerate.IsNamespaceFileScoped) 49 | { 50 | foreach (var @namespace in methodToGenerate.Namespaces) 51 | { 52 | var indent = new string(' ', 4 * i); 53 | _ = sbBegin.Append($$""" 54 | {{indent}}namespace {{@namespace}} 55 | {{indent}}{ 56 | 57 | """); 58 | _ = sbEnd.Insert(0, $$""" 59 | {{indent}}} 60 | 61 | """); 62 | ++i; 63 | } 64 | } 65 | 66 | // Handle classes 67 | foreach (var parent in methodToGenerate.Parents) 68 | { 69 | var indent = new string(' ', 4 * i); 70 | 71 | var modifiers = string.Join(string.Empty, parent.Modifiers.Select(z => GetKeyword((SyntaxKind)z) + " ")); 72 | var parentType = parent.MethodParent switch 73 | { 74 | MethodParent.Class => "class", 75 | MethodParent.Interface => "interface", 76 | MethodParent.Struct => "struct", 77 | MethodParent.Record => "record" 78 | + parent.ClassOrStructKeyword.Kind() switch 79 | { 80 | SyntaxKind.StructKeyword => " struct", 81 | SyntaxKind.ClassKeyword => " class", 82 | _ => string.Empty, 83 | }, 84 | _ => throw new NotImplementedException("Cannot handle the parent of the method"), 85 | }; 86 | 87 | var classDeclarationLine = $"{modifiers}partial {parentType} {parent.ParentName}{(parent.TypeParameterListSyntax.IsEmpty ? string.Empty 88 | : "<" + string.Join(", ", parent.TypeParameterListSyntax) + ">")}"; 89 | 90 | _ = sbBegin.Append($$""" 91 | {{indent}}{{classDeclarationLine}} 92 | {{indent}}{ 93 | 94 | """); 95 | _ = sbEnd.Insert(0, $$""" 96 | {{indent}}} 97 | 98 | """); 99 | ++i; 100 | } 101 | 102 | var beforeNamespace = $""" 103 | // {(methodToGenerate.DisableNullable ? string.Empty : """ 104 | 105 | #nullable enable 106 | """)} 107 | """; 108 | 109 | return methodToGenerate.IsNamespaceFileScoped ? $$""" 110 | {{beforeNamespace}} 111 | namespace {{methodToGenerate.Namespaces.First()}}; 112 | {{sbBegin}}{{new string(' ', 4 * i)}}{{methodToGenerate.Implementation.Trim()}} 113 | {{sbEnd}} 114 | """ 115 | : $$""" 116 | {{beforeNamespace}} 117 | {{sbBegin}}{{new string(' ', 4 * i)}}{{methodToGenerate.Implementation.Trim()}} 118 | {{sbEnd}} 119 | """; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/Zomp.SyncMethodGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | git 5 | netstandard2.0 6 | false 7 | preview 8 | Generates synchronized method from async method 9 | enable 10 | true 11 | enable 12 | © Zomp Inc. All rights reserved. 13 | Zomp 14 | Victor Irzak 15 | true 16 | true 17 | $(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage 18 | async sync csharp source generator 19 | true 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | <_ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))" /> 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $analyzersDir = Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers" 4 | if (-Not (Test-Path $analyzersDir)) 5 | { 6 | return 7 | } 8 | 9 | $analyzersPaths = Join-Path ( $analyzersDir ) * -Resolve 10 | 11 | foreach($analyzersPath in $analyzersPaths) 12 | { 13 | # Install the language agnostic analyzers. 14 | if (Test-Path $analyzersPath) 15 | { 16 | foreach ($analyzerFilePath in Get-ChildItem $analyzersPath -Filter *.dll) 17 | { 18 | if($project.Object.AnalyzerReferences) 19 | { 20 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 21 | } 22 | } 23 | } 24 | } 25 | 26 | # $project.Type gives the language name like (C# or VB.NET) 27 | $languageFolder = "" 28 | if($project.Type -eq "C#") 29 | { 30 | $languageFolder = "cs" 31 | } 32 | if($project.Type -eq "VB.NET") 33 | { 34 | $languageFolder = "vb" 35 | } 36 | if($languageFolder -eq "") 37 | { 38 | return 39 | } 40 | 41 | foreach($analyzersPath in $analyzersPaths) 42 | { 43 | # Install language specific analyzers. 44 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 45 | if (Test-Path $languageAnalyzersPath) 46 | { 47 | foreach ($analyzerFilePath in Get-ChildItem $languageAnalyzersPath -Filter *.dll) 48 | { 49 | if($project.Object.AnalyzerReferences) 50 | { 51 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Zomp.SyncMethodGenerator/tools/uninstall.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $analyzersDir = Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers" 4 | if (-Not (Test-Path $analyzersDir)) 5 | { 6 | return 7 | } 8 | 9 | $analyzersPaths = Join-Path ( $analyzersDir ) * -Resolve 10 | 11 | foreach($analyzersPath in $analyzersPaths) 12 | { 13 | # Uninstall the language agnostic analyzers. 14 | if (Test-Path $analyzersPath) 15 | { 16 | foreach ($analyzerFilePath in Get-ChildItem $analyzersPath -Filter *.dll) 17 | { 18 | if($project.Object.AnalyzerReferences) 19 | { 20 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 21 | } 22 | } 23 | } 24 | } 25 | 26 | # $project.Type gives the language name like (C# or VB.NET) 27 | $languageFolder = "" 28 | if($project.Type -eq "C#") 29 | { 30 | $languageFolder = "cs" 31 | } 32 | if($project.Type -eq "VB.NET") 33 | { 34 | $languageFolder = "vb" 35 | } 36 | if($languageFolder -eq "") 37 | { 38 | return 39 | } 40 | 41 | foreach($analyzersPath in $analyzersPaths) 42 | { 43 | # Uninstall language specific analyzers. 44 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 45 | if (Test-Path $languageAnalyzersPath) 46 | { 47 | foreach ($analyzerFilePath in Get-ChildItem $languageAnalyzersPath -Filter *.dll) 48 | { 49 | if($project.Object.AnalyzerReferences) 50 | { 51 | try 52 | { 53 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 54 | } 55 | catch 56 | { 57 | 58 | } 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zompinc/sync-method-generator/c4f2f3a4b173be94fc88a8977caa40c37e72b674/src/images/icon.png -------------------------------------------------------------------------------- /stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 3 | "settings": { 4 | "documentationRules": { 5 | "companyName": "Zomp", 6 | "documentInternalElements": false 7 | }, 8 | "orderingRules": { 9 | "usingDirectivesPlacement": "outsideNamespace", 10 | "systemUsingDirectivesFirst": false 11 | }, 12 | "readabilityRules": { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/GenerationSandbox.Tests/AsyncExtensions.GenericMath.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | 5 | namespace GenerationSandbox.Tests; 6 | 7 | /// 8 | /// Test class. 9 | /// 10 | public static partial class AsyncExtensions 11 | { 12 | /// 13 | /// Finds maximum value so far and returns its 0 based index. 14 | /// 15 | /// Numeric type. 16 | /// Items to scan. 17 | /// The progress. 18 | /// Cancellation token. 19 | /// Max indices. 20 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 21 | public static async IAsyncEnumerable IndexOfMaxSoFarAsync(this IAsyncEnumerable items, IProgress? progress = null, [EnumeratorCancellation] CancellationToken ct = default) 22 | where T : IComparisonOperators 23 | { 24 | ArgumentNullException.ThrowIfNull(items); 25 | 26 | var i = 0; 27 | 28 | T? largestSoFar = default; 29 | await foreach (var item in items) 30 | { 31 | ct.ThrowIfCancellationRequested(); 32 | 33 | if ((i & 0x3ff) == 0) 34 | { 35 | progress?.Report(i); 36 | } 37 | 38 | if (largestSoFar is null || largestSoFar < item) 39 | { 40 | largestSoFar = item; 41 | yield return i; 42 | } 43 | 44 | ++i; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/GenerationSandbox.Tests/AsyncExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | 6 | namespace GenerationSandbox.Tests; 7 | 8 | /// 9 | /// Test class. 10 | /// 11 | public static partial class AsyncExtensions 12 | { 13 | /// 14 | /// Calculates rolling average. 15 | /// 16 | /// Items to average. 17 | /// Size of averaging window. 18 | /// Reports progress. 19 | /// Cancellation token. 20 | /// Moving averages. 21 | /// 22 | /// Credit: modified from https://www.codeguru.co.in/2021/06/moving-average-in-c-using-linq.html. 23 | /// 24 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 25 | public static async IAsyncEnumerable MovingAverageAsync(this IAsyncEnumerable source, int windowSize, IProgress? progress = null, [EnumeratorCancellation] CancellationToken ct = default) 26 | { 27 | #if NETFRAMEWORK 28 | if (source is null) 29 | { 30 | throw new ArgumentNullException(nameof(source)); 31 | } 32 | #else 33 | ArgumentNullException.ThrowIfNull(source); 34 | #endif 35 | 36 | var queue = new Queue(windowSize); 37 | 38 | var i = 0; 39 | await foreach (var d in source) 40 | { 41 | ct.ThrowIfCancellationRequested(); 42 | 43 | // report progress every 4 iterations 44 | if ((i & 0x3) == 0) 45 | { 46 | progress?.Report(i); 47 | } 48 | 49 | if (queue.Count == windowSize) 50 | { 51 | queue.Dequeue(); 52 | } 53 | 54 | queue.Enqueue(d); 55 | yield return queue.Average(); 56 | ++i; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/GenerationSandbox.Tests/AsyncWithIProgress.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace GenerationSandbox.Tests; 5 | 6 | internal sealed partial class AsyncWithIProgress 7 | { 8 | public static async Task WithIProgressAsync(IProgress? progress = null) 9 | { 10 | await Task.CompletedTask; 11 | } 12 | 13 | public static void WithIProgress() 14 | { 15 | } 16 | 17 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 18 | public static async Task CallWithIProgressAsync() 19 | { 20 | CustomProgress progress = new(); 21 | 22 | if (true) 23 | { 24 | progress++; 25 | } 26 | 27 | await WithIProgressAsync(progress); 28 | } 29 | 30 | private sealed class CustomProgress : IProgress 31 | { 32 | public static CustomProgress operator ++(CustomProgress a) => a; 33 | 34 | public void Report(float value) => throw new NotImplementedException(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/GenerationSandbox.Tests/GenerationSandbox.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | $(NoWarn);CA1062;CA1303;CA1508;CA1515;CA1812;CA1815;CA1822;CA1829;CA1852;CA2000;CA5394 6 | $(NoWarn);CS0219;CS0162;CS1998;CS8603;CS8619 7 | $(NoWarn);IDE0004;IDE0005;IDE0007;IDE0011;IDE0035;IDE0040;IDE0041;IDE0058;IDE0060;IDE0065 8 | $(NoWarn);RS1035 9 | $(NoWarn);SA1200;SA1201;SA1202;SA1204;SA1400;SA1402;SA1403;SA1404;SA1601 10 | false 11 | net8.0 12 | $(TargetFrameworks);net472 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /tests/GenerationSandbox.Tests/SyncTests.cs: -------------------------------------------------------------------------------- 1 | #if NET8_0_OR_GREATER 2 | using System.Linq; 3 | #endif 4 | using Xunit; 5 | 6 | namespace GenerationSandbox.Tests; 7 | 8 | public class SyncTests 9 | { 10 | [Fact] 11 | public void TestGeneratedAverageRoutine() 12 | { 13 | var expected = new double[] { 9, 9.5, 8, 7.333333333333333, 5, 4, 2 }; 14 | var myNumbers = new double[] { 9, 10, 5, 7, 3, 2, 1 }; 15 | var result = myNumbers.MovingAverage(3); 16 | Assert.Equal(expected, result); 17 | } 18 | 19 | [Fact] 20 | public void TestStaticAsyncWithIProgress() 21 | => AsyncWithIProgress.CallWithIProgress(); 22 | 23 | #if NET8_0_OR_GREATER 24 | [Fact] 25 | public void TestIndexOfMaxSoFar() 26 | { 27 | var expected = new int[] { 0, 1, 4 }; 28 | var myNumbers = new int[] { 9, 10, 5, 7, 11, 2, 1 }; 29 | var result = myNumbers.IndexOfMaxSoFar().ToArray(); 30 | Assert.Equal(expected, result); 31 | } 32 | #endif 33 | } 34 | -------------------------------------------------------------------------------- /tests/Generator.Tests/ArgumentTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class ArgumentTests 4 | { 5 | [Fact] 6 | public Task DropNullArgument() => """ 7 | public void ProgressMethodAsync() { } 8 | 9 | public async Task ProgressMethodAsync(IProgress? a) => await Task.CompletedTask; 10 | 11 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 12 | public async Task CallProgressMethodAsync() 13 | { 14 | await ProgressMethodAsync(null); 15 | } 16 | """.Verify(); 17 | 18 | [Fact] 19 | public Task DropNamedArgument() => """ 20 | public void ProgressMethod(int p1 = 0, int p2 = 0) { } 21 | 22 | public async Task ProgressMethodAsync(int p1 = 0, int p2 = 0, IProgress? progress = null) => await Task.CompletedTask; 23 | 24 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 25 | public async Task CallProgressMethodAsync() 26 | { 27 | await ProgressMethodAsync(progress: null); 28 | } 29 | """.Verify(); 30 | } 31 | -------------------------------------------------------------------------------- /tests/Generator.Tests/ConditionalExtensionTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class ConditionalExtensionTests 4 | { 5 | [Fact] 6 | public Task NullConditionalWithoutExtension() => """ 7 | Assembly? a = null; 8 | _ = a?.ToString(); 9 | """.Verify(sourceType: SourceType.MethodBody); 10 | 11 | [Fact] 12 | public Task NullConditionalExtension() => """ 13 | Assembly? a = null; 14 | _ = a?.GetCustomAttributes(); 15 | """.Verify(sourceType: SourceType.MethodBody); 16 | 17 | [Fact] 18 | public Task StartWithExpression() => """ 19 | _ = GetType().Assembly?.GetCustomAttributes(); 20 | """.Verify(sourceType: SourceType.MethodBody); 21 | 22 | [Fact] 23 | public Task NullConditionalExtensionChained() => """ 24 | Assembly? a = null; 25 | _ = a?.GetCustomAttributes()?.ToList(); 26 | """.Verify(sourceType: SourceType.MethodBody); 27 | 28 | [Fact] 29 | public Task LongChained() => """ 30 | Assembly? a = null; 31 | _ = a?.GetCustomAttributes() 32 | ?.ToList() 33 | ?.Where(z => 1 == 0) 34 | ?.Where(z => 2 == 0) 35 | ?.Where(z => 3 == 0); 36 | """.Verify(sourceType: SourceType.MethodBody); 37 | 38 | [Fact] 39 | public Task CheckArrayNullability() => """ 40 | int[]? array = null; 41 | var z = array?.Single(); 42 | """.Verify(sourceType: SourceType.MethodBody); 43 | 44 | [Fact] 45 | public Task KeepTypeParameters() => """ 46 | string[]? arr = []; 47 | _ = arr?.Select(z => null); 48 | """.Verify(sourceType: SourceType.MethodBody); 49 | 50 | [Fact] 51 | public Task HandleCastForNull() 52 | => "_ = ((string[]?)null)?.Select(z => null);" 53 | .Verify(sourceType: SourceType.MethodBody); 54 | 55 | [Fact] 56 | public Task HandleCastForArray() 57 | => "_ = ((string[]?)[])?.Select(z => null);" 58 | .Verify(sourceType: SourceType.MethodBody); 59 | 60 | #if NET8_0_OR_GREATER 61 | [Fact] 62 | public Task ConditionalToExtension() => """ 63 | [CreateSyncVersion] 64 | public static async Task MethodAsync(IEnumerable? integers) 65 | { 66 | var res = integers?.Chunk(2).First(); 67 | } 68 | """.Verify(); 69 | #endif 70 | } 71 | -------------------------------------------------------------------------------- /tests/Generator.Tests/DelegateTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class DelegateTests 4 | { 5 | [Theory] 6 | [InlineData("await Task.CompletedTask;")] 7 | [InlineData("{ await Task.CompletedTask; };")] 8 | public Task DropCompletedTaskFromLambda(string statements) 9 | => $"var delAsync = async () => {statements}" 10 | .Verify(disableUnique: true, sourceType: SourceType.MethodBody); 11 | 12 | [Fact] 13 | public Task AsyncDelegate() => """ 14 | var delAsync = async () => await Task.CompletedTask; 15 | await delAsync(); 16 | """.Verify(sourceType: SourceType.MethodBody); 17 | 18 | [Fact] 19 | public Task FuncToActionInParameter() => """ 20 | [CreateSyncVersion] 21 | async Task MethodAsync(Func bar) 22 | { 23 | await bar(5); 24 | } 25 | """.Verify(); 26 | 27 | [Fact] 28 | public Task FuncToActionInParameterExplicitInvoke() => """ 29 | [CreateSyncVersion] 30 | async Task MethodAsync(Func bar) 31 | { 32 | await bar.Invoke(); 33 | } 34 | """.Verify(); 35 | 36 | [Fact] 37 | public Task FuncToActionInParameterTwice() => """ 38 | [CreateSyncVersion] 39 | async Task MethodAsync(Func> bar) 40 | { 41 | await bar()(); 42 | } 43 | """.Verify(); 44 | 45 | [Fact] 46 | public Task FuncToActionInParameterTwiceExplicitInvoke() => """ 47 | [CreateSyncVersion] 48 | async Task MethodAsync(Func> bar) 49 | { 50 | await bar().Invoke(); 51 | } 52 | """.Verify(); 53 | 54 | [Fact] 55 | public Task FuncToActionInParameterTwiceWithArgument() => """ 56 | [CreateSyncVersion] 57 | async Task MethodAsync(Func> bar) 58 | { 59 | await bar(9)(); 60 | } 61 | """.Verify(); 62 | 63 | [Theory] 64 | [InlineData(true)] 65 | [InlineData(false)] 66 | public Task AsyncDelegateWithCancellationToken(bool explicitParameter) 67 | { 68 | var @explicit = explicitParameter ? "CancellationToken " : string.Empty; 69 | return $""" 70 | Func> delAsync = async ({@explicit}ct) => await Task.FromResult(2); 71 | var result = await delAsync(CancellationToken.None); 72 | """.Verify(disableUnique: true, sourceType: SourceType.MethodBody); 73 | } 74 | 75 | [Fact] 76 | public Task AsyncDelegateWithParameter() 77 | => "Func delAsync = async (p, s) => await Task.CompletedTask;" 78 | .Verify(sourceType: SourceType.MethodBody); 79 | 80 | [Fact] 81 | public Task AsyncVarDelegateWithParameter() 82 | => "var delAsync = async (Point p, Size s) => await Task.CompletedTask;" 83 | .Verify(sourceType: SourceType.MethodBody); 84 | 85 | [Fact] 86 | public Task AsyncVarDelegateWithParameterAndReturnType() 87 | => "var delAsync = async (Point p, Size s) => await Task.FromResult(p);" 88 | .Verify(sourceType: SourceType.MethodBody); 89 | 90 | [Theory] 91 | [InlineData("null!")] 92 | [InlineData("new Progress()")] 93 | public Task AsyncDelegateWithIProgress(string iProgressArg) => $""" 94 | Func, CancellationToken, Task> delAsync = async (p, ct) => await Task.FromResult(2); 95 | var result = await delAsync({iProgressArg}, CancellationToken.None); 96 | """.Verify(disableUnique: true, sourceType: SourceType.MethodBody); 97 | 98 | [Theory] 99 | 100 | [InlineData("null")] 101 | [InlineData("new Progress()")] 102 | public Task AsyncDelegateWithNullableIProgress(string iProgressArg) => $""" 103 | Func?, CancellationToken, Task> delAsync = async (p, ct) => await Task.FromResult(2); 104 | var result = await delAsync({iProgressArg}, CancellationToken.None); 105 | """.Verify(disableUnique: true, sourceType: SourceType.MethodBody); 106 | 107 | [Fact] 108 | public Task AsyncDelegateExplicit() => """ 109 | Func delAsync = async () => await Task.CompletedTask; 110 | await delAsync(); 111 | """.Verify(sourceType: SourceType.MethodBody); 112 | } 113 | -------------------------------------------------------------------------------- /tests/Generator.Tests/ExtensionMethodTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class ExtensionMethodTests 4 | { 5 | [Fact] 6 | public Task UnwrapGenericExtensionMethod() => """ 7 | using System.Drawing; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace Zomp.SyncMethodGenerator.IntegrationTests 12 | { 13 | using Extensi.ons123; 14 | partial class Extensions 15 | { 16 | [CreateSyncVersion] 17 | public static async Task HasGenericExtensionAsync(object o, CancellationToken ct) 18 | { 19 | var z = o.TryGetValue(out var item); 20 | } 21 | 22 | [CreateSyncVersion] 23 | public static async Task HasGeneric2ExtensionAsync(object o, CancellationToken ct) 24 | { 25 | var z = o.TryGetValue(out var _, out var _1); 26 | } 27 | } 28 | } 29 | 30 | namespace Extensi.ons123 31 | { 32 | internal static class MyExtensionClass 33 | { 34 | public static bool TryGetValue(this object _, out T? item) 35 | { 36 | item = default; 37 | return false; 38 | } 39 | 40 | public static bool TryGetValue(this object _, out T1? item1, out T2? item2) 41 | { 42 | item1 = default; 43 | item2 = default; 44 | return false; 45 | } 46 | } 47 | } 48 | """.Verify(sourceType: SourceType.Full); 49 | 50 | [Fact] 51 | public Task LeftOfTheDotTest() => """ 52 | namespace Tests; 53 | 54 | internal class Bar 55 | { 56 | public static Bar Create() => new Bar(); 57 | } 58 | 59 | partial class Class 60 | { 61 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 62 | public async Task MethodAsync() 63 | { 64 | _ = Bar.Create()?.DoSomething(); 65 | } 66 | } 67 | 68 | internal static class BarExtension 69 | { 70 | public static Bar DoSomething(this Bar bar) => bar; 71 | } 72 | """.Verify(sourceType: SourceType.Full); 73 | } 74 | -------------------------------------------------------------------------------- /tests/Generator.Tests/ExternalLibraryTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class ExternalLibraryTests 4 | { 5 | #if NETCOREAPP1_0_OR_GREATER 6 | [Fact] 7 | public Task ToListAsync() => """ 8 | [CreateSyncVersion] 9 | public async Task MethodAsync(IAsyncEnumerable @enum) 10 | { 11 | _ = await @enum.ToListAsync(); 12 | } 13 | """.Verify(); 14 | #endif 15 | } 16 | -------------------------------------------------------------------------------- /tests/Generator.Tests/FileNameTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class FileNameTests 4 | { 5 | [Fact] 6 | public Task DoNotCollideClassNames() => """ 7 | namespace Test; 8 | 9 | public partial class Class 10 | { 11 | [CreateSyncVersion] 12 | public async Task MethodAsync() 13 | { 14 | } 15 | } 16 | 17 | public partial class Class 18 | { 19 | [CreateSyncVersion] 20 | public async Task MethodAsync() 21 | { 22 | } 23 | } 24 | 25 | public partial class Class 26 | { 27 | [CreateSyncVersion] 28 | public async Task MethodAsync() 29 | { 30 | } 31 | } 32 | """.Verify(sourceType: SourceType.Full); 33 | } 34 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Generator.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | $(TargetFrameworks);net472 6 | false 7 | preview 8 | $(NoWarn);CA1515;RS1035 9 | 10 | 11 | true 12 | true 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | all 22 | runtime; build; native; contentfiles; analyzers; buildtransitive 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /tests/Generator.Tests/GenericMathTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class GenericMathTests 4 | { 5 | [Fact] 6 | public Task GeneratesWithIProgressCorrectly() => $$""" 7 | namespace Test 8 | { 9 | public static partial class EnumerableExtensions 10 | { 11 | /// 12 | /// Finds maximum value so far and returns its 0 based index 13 | /// 14 | /// Numeric type 15 | /// Items to scan. 16 | /// The progress 17 | /// Cancellation token 18 | /// Max indices 19 | [CreateSyncVersion] 20 | public static async IAsyncEnumerable IndexOfMaxSoFarAsync(this IAsyncEnumerable items, IProgress? progress = null, [EnumeratorCancellation] CancellationToken ct = default) 21 | #if NET8_0_OR_GREATER 22 | where T : IComparisonOperators 23 | #else 24 | where T : IComparisonOperators 25 | #endif 26 | { 27 | var i = 0; 28 | 29 | T? largestSoFar = default; 30 | await foreach (var item in items) 31 | { 32 | ct.ThrowIfCancellationRequested(); 33 | 34 | if ((i & 0x3ff) == 0) 35 | { 36 | progress?.Report(i); 37 | } 38 | 39 | if (largestSoFar is null || largestSoFar < item) 40 | { 41 | largestSoFar = item; 42 | yield return i; 43 | } 44 | 45 | ++i; 46 | } 47 | } 48 | } 49 | } 50 | """.Verify(true, sourceType: SourceType.Full); 51 | } 52 | -------------------------------------------------------------------------------- /tests/Generator.Tests/IncrementalGeneratorTests.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Zomp.SyncMethodGenerator; 3 | 4 | namespace Generator.Tests; 5 | 6 | public class IncrementalGeneratorTests 7 | { 8 | [Theory] 9 | [InlineData( 10 | IncrementalStepRunReason.Cached, 11 | IncrementalStepRunReason.Unchanged, 12 | IncrementalStepRunReason.Cached, 13 | """ 14 | using System; 15 | using System.Threading.Tasks; 16 | 17 | class Test 18 | { 19 | public void ProgressMethod() { } 20 | public Task ProgressMethodAsync() => Task.CompletedTask; 21 | 22 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 23 | public async Task CallProgressMethodAsync() 24 | { 25 | await ProgressMethodAsync(); 26 | } 27 | } 28 | """, 29 | """ 30 | using System; 31 | using System.Threading.Tasks; 32 | 33 | class Test 34 | { 35 | public void ProgressMethod() { } 36 | public Task ProgressMethodAsync() => Task.Yield(); 37 | 38 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 39 | public async Task CallProgressMethodAsync() 40 | { 41 | await ProgressMethodAsync(); 42 | } 43 | } 44 | """)] 45 | [InlineData( 46 | IncrementalStepRunReason.Modified, 47 | IncrementalStepRunReason.Modified, 48 | IncrementalStepRunReason.Modified, 49 | """ 50 | using System; 51 | using System.Threading.Tasks; 52 | 53 | class Test 54 | { 55 | public void ProgressMethod() { } 56 | public Task ProgressMethodAsync() => Task.CompletedTask; 57 | 58 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 59 | public async Task CallProgressMethodAsync() 60 | { 61 | } 62 | } 63 | """, 64 | """ 65 | using System; 66 | using System.Threading.Tasks; 67 | 68 | class Test 69 | { 70 | public void ProgressMethod() { } 71 | public Task ProgressMethodAsync() => Task.CompletedTask; 72 | 73 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 74 | public async Task CallProgressMethodAsync() 75 | { 76 | await ProgressMethodAsync(); 77 | } 78 | } 79 | """)] 80 | public void CheckGeneratorIsIncremental( 81 | IncrementalStepRunReason sourceStepReason, 82 | IncrementalStepRunReason executeStepReason, 83 | IncrementalStepRunReason combineStepReason, 84 | string source, 85 | string sourceUpdated) 86 | { 87 | var baseSyntaxTree = CSharpSyntaxTree.ParseText(source); 88 | 89 | Compilation compilation = CSharpCompilation.Create( 90 | "compilation", 91 | [baseSyntaxTree], 92 | [MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location)], 93 | new CSharpCompilationOptions(OutputKind.ConsoleApplication)); 94 | 95 | var sourceGenerator = new SyncMethodSourceGenerator().AsSourceGenerator(); 96 | 97 | GeneratorDriver driver = CSharpGeneratorDriver.Create( 98 | generators: [sourceGenerator], 99 | driverOptions: new GeneratorDriverOptions(default, trackIncrementalGeneratorSteps: true)); 100 | 101 | // Run the generator 102 | driver = driver.RunGenerators(compilation); 103 | 104 | // Update the compilation and rerun the generator 105 | compilation = compilation.ReplaceSyntaxTree(baseSyntaxTree, CSharpSyntaxTree.ParseText(sourceUpdated)); 106 | driver = driver.RunGenerators(compilation); 107 | 108 | var result = driver.GetRunResult().Results.Single(); 109 | var sourceOutputs = 110 | result.TrackedOutputSteps.SelectMany(outputStep => outputStep.Value).SelectMany(output => output.Outputs); 111 | var (value, reason) = Assert.Single(sourceOutputs); 112 | Assert.Equal(sourceStepReason, reason); 113 | Assert.Equal(executeStepReason, result.TrackedSteps["GetMethodToGenerate"].Single().Outputs[0].Reason); 114 | Assert.Equal(combineStepReason, result.TrackedSteps["GenerateSource"].Single().Outputs[0].Reason); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /tests/Generator.Tests/IntegrationTesting.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class IntegrationTesting 4 | { 5 | #if NETCOREAPP1_0_OR_GREATER 6 | [Fact] 7 | public Task GeneratesSyncMethodCorrectly() => """ 8 | namespace Test 9 | { 10 | public static partial class EnumerableExtensions 11 | { 12 | [CreateSyncVersion] 13 | public static async IAsyncEnumerable GetAveragesAsync(this IAsyncEnumerable list, int adjacentCount, [EnumeratorCancellation] CancellationToken ct = default) 14 | where T : IConvertible 15 | { 16 | double total = 0; 17 | 18 | int avgCount = adjacentCount * 2 + 1; 19 | 20 | var meanQueue = new Queue(); 21 | await foreach (var o in list.WithCancellation(ct).ConfigureAwait(false)) 22 | { 23 | var item = o.ToDouble(null); 24 | if (meanQueue.Count == avgCount) 25 | { 26 | total -= meanQueue.Dequeue(); 27 | } 28 | meanQueue.Enqueue(item); 29 | total += item; 30 | 31 | if (meanQueue.Count == avgCount) 32 | { 33 | yield return total / avgCount; 34 | } 35 | } 36 | } 37 | } 38 | } 39 | """.Verify(sourceType: SourceType.Full); 40 | #endif 41 | 42 | [Fact] 43 | public Task WithIAsyncEnumerator() => """ 44 | [CreateSyncVersion] 45 | async Task EnumeratorTestAsync(IAsyncEnumerable range, CancellationToken ct) 46 | { 47 | IAsyncEnumerator e = range.GetAsyncEnumerator(ct); 48 | try 49 | { 50 | while (await e.MoveNextAsync().ConfigureAwait(false)) Console.Write(e.Current + " "); 51 | } 52 | finally { if (e != null) await e.DisposeAsync(); } 53 | } 54 | """.Verify(); 55 | 56 | [Fact] 57 | public Task CombineTwoLists() => """ 58 | [CreateSyncVersion] 59 | public static async IAsyncEnumerable<(TLeft Left, TRight Right)> CombineAsync(this IAsyncEnumerable list1, IAsyncEnumerable list2, [EnumeratorCancellation] CancellationToken ct = default) 60 | { 61 | await using var enumerator2 = list2.GetAsyncEnumerator(ct); 62 | await foreach (var item in list1.WithCancellation(ct).ConfigureAwait(false)) 63 | { 64 | if (!(await enumerator2.MoveNextAsync().ConfigureAwait(false))) 65 | { 66 | throw new InvalidOperationException("Must have the same size"); 67 | } 68 | yield return (item, enumerator2.Current); 69 | } 70 | } 71 | """.Verify(); 72 | 73 | #if NETCOREAPP1_0_OR_GREATER 74 | [Fact] 75 | public Task ChecksumRead() => """ 76 | [CreateSyncVersion] 77 | static async Task HalfCheckSumAsync(Memory buffer, Stream stream, CancellationToken ct) 78 | => (await ChecksumReadAsync(buffer, stream, ct).ConfigureAwait(false)) / 2; 79 | 80 | [CreateSyncVersion] 81 | static async Task ChecksumReadAsync(Memory buffer, Stream stream, CancellationToken ct) 82 | { 83 | int bytesRead = await stream.ReadAsync(buffer, ct).ConfigureAwait(true); 84 | return Checksum(buffer.Span.Slice(0, bytesRead)); 85 | } 86 | static int Checksum(Span buffer) => 0; 87 | """.Verify(); 88 | 89 | // From: https://devblogs.microsoft.com/premier-developer/dissecting-the-local-functions-in-c-7/#use-case-2-eager-preconditions-in-async-methods 90 | [Fact] 91 | public Task EagerPreconditionsInAsyncMethod() => """ 92 | [CreateSyncVersion] 93 | public static Task GetAllTextAsync(string fileName) 94 | { 95 | // Eager argument validation 96 | if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException(nameof(fileName)); 97 | return GetAllTextAsync(); 98 | 99 | async Task GetAllTextAsync() 100 | { 101 | var result = await File.ReadAllTextAsync(fileName); 102 | return result; 103 | } 104 | } 105 | """.Verify(); 106 | #endif 107 | 108 | // Modified from: https://devblogs.microsoft.com/premier-developer/dissecting-the-local-functions-in-c-7/#use-case-1-eager-preconditions-in-iterator-blocks 109 | [Fact] 110 | public Task EagerPreconditionInIteratorBlock() => """ 111 | [CreateSyncVersion] 112 | public static IAsyncEnumerable ReadLineByLineAsync(string fileName) 113 | { 114 | if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException(nameof(fileName)); 115 | 116 | return ReadLineByLineImpl(); 117 | 118 | async IAsyncEnumerable ReadLineByLineImpl() 119 | { 120 | await foreach (var line in CreateAsyncEnumerable()) 121 | { 122 | yield return line; 123 | } 124 | } 125 | 126 | async IAsyncEnumerable CreateAsyncEnumerable() 127 | { 128 | foreach (var i in new[] { "a", "b" }) 129 | { 130 | yield return await Task.FromResult(i); 131 | } 132 | } 133 | } 134 | """.Verify(); 135 | } 136 | -------------------------------------------------------------------------------- /tests/Generator.Tests/InterpolatedStringTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class InterpolatedStringTests 4 | { 5 | [Theory] 6 | [InlineData("await File.ReadAllTextAsync(\"123\")")] 7 | [InlineData("(await File.ReadAllTextAsync(\"123\"))")] 8 | public Task EnsureParentheses(string call) => $$""" 9 | var z = $"123{{{call}}}456"; 10 | """.Verify(false, true, sourceType: SourceType.MethodBody); 11 | 12 | [Theory] 13 | [InlineData("await File.ReadAllTextAsync(\"123\")")] 14 | [InlineData("(await File.ReadAllTextAsync(\"123\"))")] 15 | public Task HandleFormatString(string call) => $$""" 16 | var z = $"123{{{call}}:hh}456"; 17 | """.Verify(false, true, sourceType: SourceType.MethodBody); 18 | } 19 | -------------------------------------------------------------------------------- /tests/Generator.Tests/IsCancellationRequestedTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class IsCancellationRequestedTests 4 | { 5 | [Fact] 6 | public Task WhileNotCancelled() => $$""" 7 | while (((!((ct.IsCancellationRequested))))) 8 | { 9 | await Task.Delay(120000, ct); 10 | } 11 | """.Verify(sourceType: SourceType.MethodBody); 12 | 13 | [Fact] 14 | public Task IfCancelled() => $$""" 15 | if (((((ct.IsCancellationRequested))))) 16 | { 17 | await Task.Delay(120000, ct); 18 | } 19 | """.Verify(sourceType: SourceType.MethodBody); 20 | 21 | [Fact] 22 | public Task IfNotCancelled() => $$""" 23 | if (((!((ct.IsCancellationRequested))))) 24 | { 25 | await Task.Delay(120000, ct); 26 | } 27 | """.Verify(sourceType: SourceType.MethodBody); 28 | } 29 | -------------------------------------------------------------------------------- /tests/Generator.Tests/MemoryTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class MemoryTests 4 | { 5 | #if NETCOREAPP1_0_OR_GREATER 6 | [Fact] 7 | public Task MemoryToSpan() => """ 8 | [CreateSyncVersion] 9 | private async Task ReadAsMemoryAsync(Stream stream, byte[] sampleBytes, CancellationToken ct = default) 10 | => await stream.ReadAsync(sampleBytes.AsMemory(0, 123), ct).ConfigureAwait(false); 11 | """.Verify(); 12 | 13 | [InlineData(false)] 14 | [InlineData(true)] 15 | [Theory] 16 | public Task MemorySpanProperty(bool explicitType) 17 | { 18 | var typeName = explicitType ? "Memory" : "var"; 19 | 20 | return $$""" 21 | [CreateSyncVersion] 22 | private async Task MakeArray(byte[] sampleBytes, CancellationToken ct = default) 23 | { 24 | {{typeName}} mem = sampleBytes.AsMemory(0, 123); 25 | var arr = mem.Span.ToArray(); 26 | } 27 | """.Verify(false, false, parameters: explicitType); 28 | } 29 | 30 | [Fact] 31 | public Task ReadOnlyMemoryToReadOnlySpan() => """ 32 | [CreateSyncVersion] 33 | static async Task WriteAsync(ReadOnlyMemory buffer, Stream stream, CancellationToken ct) 34 | => await stream.WriteAsync(buffer, ct).ConfigureAwait(true); 35 | """.Verify(); 36 | #endif 37 | 38 | [Fact] 39 | public Task DropSpanAfterAsMemory() => """ 40 | [CreateSyncVersion] 41 | public async Task MakeArrayAsync(byte[] sampleBytes, CancellationToken ct = default) 42 | { 43 | var arr = sampleBytes.AsMemory(0, 123).Span.ToArray(); 44 | } 45 | """.Verify(); 46 | 47 | [Fact] 48 | public Task DropSpanAfterAsMemoryWithWhitespace() => """ 49 | [CreateSyncVersion] 50 | public async Task MakeArrayAsync(byte[] sampleBytes, CancellationToken ct = default) 51 | { 52 | var arr = 53 | sampleBytes.AsMemory(0, 123).Span.ToArray(); 54 | } 55 | """.Verify(); 56 | 57 | [Fact] 58 | public Task PreserveUnrelatedSpan() => """ 59 | [CreateSyncVersion] 60 | public async Task HasMemoryAsync(Memory mem) 61 | { 62 | void Inner() 63 | { 64 | Unrelated mem = new(); 65 | int shouldBeInt = mem.Span; 66 | } 67 | } 68 | 69 | class Unrelated 70 | { 71 | public int Span { get; set; } 72 | } 73 | """.Verify(); 74 | 75 | [Fact] 76 | public Task NonPredefinedTypes() => """ 77 | using N2; 78 | using static N2.C1; 79 | 80 | namespace N1 81 | { 82 | partial class Class 83 | { 84 | [CreateSyncVersion] 85 | async Task FillAsync(Memory accelerometers) 86 | { 87 | C2.Accelerometer a = new(1, 2, 3); 88 | accelerometers.Span[0] = a; 89 | } 90 | } 91 | } 92 | 93 | namespace N2 94 | { 95 | internal class C1 96 | { 97 | public class C2 98 | { 99 | public record struct Accelerometer(short X, short Y, short Z); 100 | } 101 | } 102 | } 103 | """.Verify(sourceType: SourceType.Full); 104 | 105 | [Fact] 106 | public Task ConvertMemoryToSpan() => """ 107 | Memory GetMemory() => MemoryPool.Shared.Rent().Memory; 108 | 109 | [CreateSyncVersion] 110 | async Task MethodAsync() 111 | { 112 | var m = GetMemory(); 113 | } 114 | """.Verify(); 115 | 116 | [Fact] 117 | public Task ConvertMemoryToSpanAfterPropertyAccess() => """ 118 | var m = MemoryPool.Shared.Rent().Memory; 119 | """.Verify(sourceType: SourceType.MethodBody); 120 | } 121 | -------------------------------------------------------------------------------- /tests/Generator.Tests/ModuleInitializer.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace Generator.Tests; 4 | 5 | /// 6 | /// Module initializer. 7 | /// 8 | public static partial class ModuleInitializer 9 | { 10 | private const string MethodTestCasePattern = "void Method\\(\\)\\s*{\\r\\n(.*)}"; 11 | private const string SimpleTestCasePattern = "// \\s*#nullable enable\\s*namespace Test;\\s*partial class Class\\s*{\\r\\n(.*)}"; 12 | private const string DefaultTestPathPattern = "Test\\.Class\\.(MethodAsync\\.)?"; 13 | 14 | [System.Runtime.CompilerServices.ModuleInitializer] 15 | public static void Initialize() 16 | { 17 | VerifySourceGenerators.Initialize(); 18 | VerifierSettings.RegisterFileConverter(Convert); 19 | } 20 | 21 | // From https://github.com/VerifyTests/Verify.SourceGenerators/issues/67#issuecomment-1536710180 22 | private static ConversionResult Convert(RunResultWithIgnoreList target, IReadOnlyDictionary context) 23 | { 24 | var exceptions = new List(); 25 | var targets = new List(); 26 | foreach (var result in target.Result.Results) 27 | { 28 | if (result.Exception != null) 29 | { 30 | exceptions.Add(result.Exception); 31 | } 32 | 33 | var collection = result.GeneratedSources 34 | .Where(x => !target.IgnoredFiles.Contains(x.HintName)) 35 | .OrderBy(x => x.HintName) 36 | .Select(SourceToTarget); 37 | targets.AddRange(collection); 38 | } 39 | 40 | if (exceptions.Count == 1) 41 | { 42 | throw exceptions.First(); 43 | } 44 | 45 | if (exceptions.Count > 1) 46 | { 47 | throw new AggregateException(exceptions); 48 | } 49 | 50 | if (target.Result.Diagnostics.Any()) 51 | { 52 | var info = new 53 | { 54 | target.Result.Diagnostics, 55 | }; 56 | return new(info, targets); 57 | } 58 | 59 | return new(null, targets); 60 | } 61 | 62 | private static Target SourceToTarget(GeneratedSourceResult source) 63 | { 64 | #if NET8_0_OR_GREATER 65 | var r = DefaultTestRegex(); 66 | #else 67 | var r = new Regex(SimpleTestCasePattern, RegexOptions.Singleline | RegexOptions.Compiled); 68 | #endif 69 | var sourceText = source.SourceText.ToString(); 70 | var match = r.Match(source.SourceText.ToString()); 71 | 72 | var sourceToStore = sourceText; 73 | if (match.Success) 74 | { 75 | sourceToStore = TestHelper.ChangeIndentation(match.Groups[1].Value, TestHelper.RemoveIndentation); 76 | 77 | #if NET8_0_OR_GREATER 78 | var methodMatch = DefaultMethodTestRegex(); 79 | #else 80 | var methodMatch = new Regex(MethodTestCasePattern, RegexOptions.Singleline | RegexOptions.Compiled); 81 | #endif 82 | match = methodMatch.Match(sourceToStore); 83 | 84 | if (match.Success) 85 | { 86 | sourceToStore = TestHelper.ChangeIndentation(match.Groups[1].Value, TestHelper.RemoveIndentation); 87 | } 88 | } 89 | 90 | var data = $""" 91 | //HintName: {source.HintName} 92 | {sourceToStore} 93 | """; 94 | 95 | var path = Path.GetFileNameWithoutExtension(source.HintName); 96 | #if NET8_0_OR_GREATER 97 | var r2 = DefaultTestPathRegex(); 98 | #else 99 | var r2 = new Regex(DefaultTestPathPattern, RegexOptions.Singleline | RegexOptions.Compiled); 100 | #endif 101 | path = r2.Replace(path, string.Empty); 102 | return new("cs", data, path); 103 | } 104 | 105 | #if NET8_0_OR_GREATER 106 | [GeneratedRegex(SimpleTestCasePattern, RegexOptions.Singleline | RegexOptions.Compiled)] 107 | private static partial Regex DefaultTestRegex(); 108 | 109 | [GeneratedRegex(MethodTestCasePattern, RegexOptions.Singleline | RegexOptions.Compiled)] 110 | private static partial Regex DefaultMethodTestRegex(); 111 | 112 | [GeneratedRegex(DefaultTestPathPattern)] 113 | private static partial Regex DefaultTestPathRegex(); 114 | #endif 115 | 116 | internal sealed class RunResultWithIgnoreList 117 | { 118 | public required GeneratorDriverRunResult Result { get; init; } 119 | 120 | public List IgnoredFiles { get; init; } = []; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /tests/Generator.Tests/NullabilityTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class NullabilityTests 4 | { 5 | [Fact(Skip = "Execute when resolved: https://github.com/dotnet/roslyn/issues/49555")] 6 | public Task NullableDisable() => """ 7 | #nullable disable 8 | 9 | namespace Test; 10 | 11 | internal partial class WithNullableDisabled 12 | { 13 | [CreateSyncVersion] 14 | public async Task DoNothingAsync(string l) 15 | { 16 | l = null; 17 | await Task.CompletedTask; 18 | } 19 | } 20 | """.Verify(sourceType: SourceType.Full); 21 | 22 | [Fact] 23 | public Task NullableOmitExplicit() => """ 24 | #nullable disable 25 | 26 | namespace Test; 27 | 28 | partial class MyClass 29 | { 30 | [Obsolete] 31 | [CreateSyncVersion(OmitNullableDirective = true)] 32 | public async Task MethodAsync() 33 | { 34 | string f = null; 35 | } 36 | } 37 | """.Verify(sourceType: SourceType.Full); 38 | 39 | [Fact] 40 | public Task ConditionalNullable() => """ 41 | #nullable disable 42 | 43 | namespace Test; 44 | 45 | partial class MyClass 46 | { 47 | [CreateSyncVersion(OmitNullableDirective = true)] 48 | public async Task MethodAsync(Stream stream) 49 | { 50 | _ = stream?.DoSomething(); 51 | } 52 | } 53 | 54 | internal static class Extension 55 | { 56 | public static Stream DoSomething(this Stream stream) => stream; 57 | } 58 | """.Verify(sourceType: SourceType.Full); 59 | 60 | [Fact] 61 | public Task ConditionalNullableTwice() => """ 62 | #nullable disable 63 | 64 | namespace Test; 65 | 66 | partial class MyClass 67 | { 68 | [CreateSyncVersion(OmitNullableDirective = true)] 69 | public async Task MethodAsync(Stream stream) 70 | { 71 | _ = stream?.DoSomething()?.DoSomething(); 72 | } 73 | } 74 | 75 | internal static class Extension 76 | { 77 | public static Stream DoSomething(this Stream stream) => stream; 78 | } 79 | """.Verify(sourceType: SourceType.Full); 80 | 81 | [Fact] 82 | public Task ConditionalNullableStructTwice() => """ 83 | #nullable disable 84 | 85 | namespace Test; 86 | 87 | partial class MyClass 88 | { 89 | [CreateSyncVersion(OmitNullableDirective = true)] 90 | public async Task MethodAsync(int? myInt) 91 | { 92 | _ = myInt?.DoSomething().DoSomething2(); 93 | } 94 | } 95 | 96 | internal static class Extension 97 | { 98 | public static int DoSomething(this int myInt) => myInt; 99 | public static int DoSomething2(this int myInt) => myInt; 100 | } 101 | """.Verify(sourceType: SourceType.Full); 102 | 103 | [Fact] 104 | public Task NoNullableSupport() => """ 105 | namespace Test; 106 | 107 | partial class WithNullableDisabled 108 | { 109 | [CreateSyncVersion] 110 | public async Task MethodAsync(string l) => await Task.CompletedTask; 111 | } 112 | """.Verify(sourceType: SourceType.Full, languageVersion: LanguageVersion.CSharp7_3); 113 | } 114 | -------------------------------------------------------------------------------- /tests/Generator.Tests/ParentTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class ParentTests 4 | { 5 | [Fact] 6 | public Task Struct() => """ 7 | namespace Test; 8 | public partial struct Struct 9 | { 10 | [CreateSyncVersion] 11 | public readonly async Task MethodAsync() => await Task.Delay(1000); 12 | } 13 | """.Verify(sourceType: SourceType.Full); 14 | 15 | [Fact] 16 | public Task Record() => """ 17 | namespace Test; 18 | public partial record Record 19 | { 20 | [CreateSyncVersion] 21 | public async Task MethodAsync() => await Task.Delay(1000); 22 | } 23 | """.Verify(sourceType: SourceType.Full); 24 | 25 | [Fact] 26 | public Task RecordStruct() => """ 27 | namespace Test; 28 | public partial record struct RecordStruct 29 | { 30 | [CreateSyncVersion] 31 | public readonly async Task MethodAsync() => await Task.Delay(1000); 32 | } 33 | """.Verify(sourceType: SourceType.Full); 34 | 35 | [Fact] 36 | public Task RecordClass() => """ 37 | namespace Test; 38 | public partial record class Record 39 | { 40 | [CreateSyncVersion] 41 | public async Task MethodAsync() => await Task.Delay(1000); 42 | } 43 | """.Verify(sourceType: SourceType.Full); 44 | } 45 | -------------------------------------------------------------------------------- /tests/Generator.Tests/PreprocessorTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class PreprocessorTests 4 | { 5 | [Fact] 6 | public Task MacrosAroundBraces() => $$""" 7 | #if !BLA 8 | { 9 | #endif 10 | 11 | #if !BLA 12 | } 13 | #endif 14 | """.Verify(sourceType: SourceType.MethodBody); 15 | } 16 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ArgumentTests.DropNamedArgument#CallProgressMethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.CallProgressMethodAsync.g.cs 2 | public void CallProgressMethod() 3 | { 4 | ProgressMethod(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ArgumentTests.DropNullArgument#CallProgressMethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.CallProgressMethodAsync.g.cs 2 | public void CallProgressMethod() 3 | { 4 | ProgressMethod(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ConditionalExtensionTests.CheckArrayNullability#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | int[]? array = null; 3 | var z = ((object?)array == null ? (int?)null : global::System.Linq.Enumerable.Single(array)); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ConditionalExtensionTests.ConditionalToExtension#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | public static void Method(global::System.Collections.Generic.IEnumerable? integers) 3 | { 4 | var res = ((object?)integers == null ? (int[]?)null : global::System.Linq.Enumerable.First(global::System.Linq.Enumerable.Chunk(integers, 2))); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ConditionalExtensionTests.HandleCastForArray#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = ((global::System.Func?>)((param)=>(object?)param == null ? (global::System.Collections.Generic.IEnumerable?)null : global::System.Linq.Enumerable.Select(param, z => null)))(((string[]?)[])); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ConditionalExtensionTests.HandleCastForNull#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = ((global::System.Func?>)((param)=>(object?)param == null ? (global::System.Collections.Generic.IEnumerable?)null : global::System.Linq.Enumerable.Select(param, z => null)))(((string[]?)null)); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ConditionalExtensionTests.KeepTypeParameters#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | string[]? arr = []; 3 | _ = ((object?)arr == null ? (global::System.Collections.Generic.IEnumerable?)null : global::System.Linq.Enumerable.Select(arr, z => null)); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ConditionalExtensionTests.LongChained#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Reflection.Assembly? a = null; 3 | _ = ((global::System.Func?>)((param)=> 4 | { 5 | if ((object?)param == null) 6 | { 7 | return null; 8 | } 9 | 10 | global::System.Collections.Generic.IEnumerable check0 = global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes(param); 11 | if ((object?)check0 == null) 12 | { 13 | return null; 14 | } 15 | 16 | global::System.Collections.Generic.List check1 = global::System.Linq.Enumerable.ToList(check0); 17 | if ((object?)check1 == null) 18 | { 19 | return null; 20 | } 21 | 22 | global::System.Collections.Generic.IEnumerable check2 = global::System.Linq.Enumerable.Where(check1, z => 1 == 0); 23 | if ((object?)check2 == null) 24 | { 25 | return null; 26 | } 27 | 28 | global::System.Collections.Generic.IEnumerable check3 = global::System.Linq.Enumerable.Where(check2, z => 2 == 0); 29 | return (object?)check3 == null ? (global::System.Collections.Generic.IEnumerable?)null : global::System.Linq.Enumerable.Where(check3, z => 3 == 0); 30 | }))(a); 31 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ConditionalExtensionTests.NullConditionalExtension#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Reflection.Assembly? a = null; 3 | _ = ((object?)a == null ? (global::System.Collections.Generic.IEnumerable?)null : global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes(a)); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ConditionalExtensionTests.NullConditionalExtensionChained#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Reflection.Assembly? a = null; 3 | _ = ((global::System.Func?>)((param)=> 4 | { 5 | if ((object?)param == null) 6 | { 7 | return null; 8 | } 9 | 10 | global::System.Collections.Generic.IEnumerable check0 = global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes(param); 11 | return (object?)check0 == null ? (global::System.Collections.Generic.List?)null : global::System.Linq.Enumerable.ToList(check0); 12 | }))(a); 13 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ConditionalExtensionTests.NullConditionalWithoutExtension#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Reflection.Assembly? a = null; 3 | _ = a?.ToString(); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ConditionalExtensionTests.StartWithExpression#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = ((global::System.Func?>)((param)=>(object?)param == null ? (global::System.Collections.Generic.IEnumerable?)null : global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes(param)))(GetType().Assembly); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.AsyncDelegate#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | var del = () => { }; 3 | del(); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.AsyncDelegateExplicit#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Action del = () => { }; 3 | del(); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.AsyncDelegateWithCancellationToken#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Func del = () => 2; 3 | var result = del(); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.AsyncDelegateWithIProgress#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Func del = () => 2; 3 | var result = del(); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.AsyncDelegateWithNullableIProgress#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Func del = () => 2; 3 | var result = del(); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.AsyncDelegateWithParameter#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Action del = (p, s) => { }; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.AsyncVarDelegateWithParameter#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | var del = (global::System.Drawing.Point p, global::System.Drawing.Size s) => { }; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.AsyncVarDelegateWithParameterAndReturnType#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | var del = (global::System.Drawing.Point p, global::System.Drawing.Size s) => p; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.DropCompletedTaskFromLambda#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | var del = () => { }; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.FuncToActionInParameter#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | void Method(global::System.Action bar) 3 | { 4 | bar(5); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.FuncToActionInParameterExplicitInvoke#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | void Method(global::System.Action bar) 3 | { 4 | bar.Invoke(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.FuncToActionInParameterTwice#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | void Method(global::System.Func bar) 3 | { 4 | bar()(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.FuncToActionInParameterTwiceExplicitInvoke#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | void Method(global::System.Func bar) 3 | { 4 | bar().Invoke(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/DelegateTests.FuncToActionInParameterTwiceWithArgument#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | void Method(global::System.Func bar) 3 | { 4 | bar(9)(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ExtensionMethodTests.LeftOfTheDotTest#Tests.Class.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Tests.Class.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Tests; 5 | partial class Class 6 | { 7 | public void Method() 8 | { 9 | _ = ((global::System.Func)((param)=>(object?)param == null ? (global::Tests.Bar?)null : global::Tests.BarExtension.DoSomething(param)))(global::Tests.Bar.Create()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGeneric2ExtensionAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGeneric2ExtensionAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Zomp.SyncMethodGenerator.IntegrationTests 5 | { 6 | partial class Extensions 7 | { 8 | public static void HasGeneric2Extension(object o) 9 | { 10 | var z = global::Extensi.ons123.MyExtensionClass.TryGetValue(o, out var _, out var _1); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGenericExtensionAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGenericExtensionAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Zomp.SyncMethodGenerator.IntegrationTests 5 | { 6 | partial class Extensions 7 | { 8 | public static void HasGenericExtension(object o) 9 | { 10 | var z = global::Extensi.ons123.MyExtensionClass.TryGetValue(o, out var item); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ExternalLibraryTests.ToListAsync#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | public void Method(global::System.Collections.Generic.IEnumerable @enum) 3 | { 4 | _ = global::System.Linq.Enumerable.ToList(@enum); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/FileNameTests.DoNotCollideClassNames#Test.Class{T,T2}.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class{T,T2}.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | public partial class Class 6 | { 7 | public void Method() 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/FileNameTests.DoNotCollideClassNames#Test.Class{T}.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class{T}.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | public partial class Class 6 | { 7 | public void Method() 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/FileNameTests.DoNotCollideClassNames#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | public partial class Class 6 | { 7 | public void Method() 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/GenericMathTests.GeneratesWithIProgressCorrectly.DotNet8_0#Test.EnumerableExtensions.IndexOfMaxSoFarAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.EnumerableExtensions.IndexOfMaxSoFarAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test 5 | { 6 | public static partial class EnumerableExtensions 7 | { 8 | /// 9 | /// Finds maximum value so far and returns its 0 based index 10 | /// 11 | /// Numeric type 12 | /// Items to scan. 13 | /// Max indices 14 | public static global::System.Collections.Generic.IEnumerable IndexOfMaxSoFar(this global::System.Collections.Generic.IEnumerable items) 15 | #if NET8_0_OR_GREATER 16 | where T : global::System.Numerics.IComparisonOperators 17 | #else 18 | where T : IComparisonOperators 19 | #endif 20 | { 21 | var i = 0; 22 | 23 | T? largestSoFar = default; 24 | foreach (var item in items) 25 | { 26 | 27 | if (largestSoFar is null || largestSoFar < item) 28 | { 29 | largestSoFar = item; 30 | yield return i; 31 | } 32 | 33 | ++i; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/IntegrationTesting.ChecksumRead#ChecksumReadAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ChecksumReadAsync.g.cs 2 | static int ChecksumRead(global::System.Span buffer, global::System.IO.Stream stream) 3 | { 4 | int bytesRead = stream.Read(buffer); 5 | return Checksum(buffer.Slice(0, bytesRead)); 6 | } 7 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/IntegrationTesting.ChecksumRead#HalfCheckSumAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.HalfCheckSumAsync.g.cs 2 | static int HalfCheckSum(global::System.Span buffer, global::System.IO.Stream stream) 3 | => ChecksumRead(buffer, stream) / 2; 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/IntegrationTesting.CombineTwoLists#CombineAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.CombineAsync.g.cs 2 | public static global::System.Collections.Generic.IEnumerable<(TLeft Left, TRight Right)> Combine(this global::System.Collections.Generic.IEnumerable list1, global::System.Collections.Generic.IEnumerable list2) 3 | { 4 | using var enumerator2 = list2.GetEnumerator(); 5 | foreach (var item in list1) 6 | { 7 | if (!enumerator2.MoveNext()) 8 | { 9 | throw new global::System.InvalidOperationException("Must have the same size"); 10 | } 11 | yield return (item, enumerator2.Current); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/IntegrationTesting.EagerPreconditionInIteratorBlock#ReadLineByLineAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReadLineByLineAsync.g.cs 2 | public static global::System.Collections.Generic.IEnumerable ReadLineByLine(string fileName) 3 | { 4 | if (string.IsNullOrEmpty(fileName)) throw new global::System.ArgumentNullException(nameof(fileName)); 5 | 6 | return ReadLineByLineImpl(); 7 | 8 | global::System.Collections.Generic.IEnumerable ReadLineByLineImpl() 9 | { 10 | foreach (var line in CreateAsyncEnumerable()) 11 | { 12 | yield return line; 13 | } 14 | } 15 | 16 | global::System.Collections.Generic.IEnumerable CreateAsyncEnumerable() 17 | { 18 | foreach (var i in new[] { "a", "b" }) 19 | { 20 | yield return i; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/IntegrationTesting.EagerPreconditionsInAsyncMethod#GetAllTextAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetAllTextAsync.g.cs 2 | public static string GetAllText(string fileName) 3 | { 4 | // Eager argument validation 5 | if (string.IsNullOrEmpty(fileName)) throw new global::System.ArgumentNullException(nameof(fileName)); 6 | return GetAllText(); 7 | 8 | string GetAllText() 9 | { 10 | var result = global::System.IO.File.ReadAllText(fileName); 11 | return result; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/IntegrationTesting.GeneratesSyncMethodCorrectly#Test.EnumerableExtensions.GetAveragesAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.EnumerableExtensions.GetAveragesAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test 5 | { 6 | public static partial class EnumerableExtensions 7 | { 8 | public static global::System.Collections.Generic.IEnumerable GetAverages(this global::System.Collections.Generic.IEnumerable list, int adjacentCount) 9 | where T : global::System.IConvertible 10 | { 11 | double total = 0; 12 | 13 | int avgCount = adjacentCount * 2 + 1; 14 | 15 | var meanQueue = new global::System.Collections.Generic.Queue(); 16 | foreach (var o in list) 17 | { 18 | var item = o.ToDouble(null); 19 | if (meanQueue.Count == avgCount) 20 | { 21 | total -= meanQueue.Dequeue(); 22 | } 23 | meanQueue.Enqueue(item); 24 | total += item; 25 | 26 | if (meanQueue.Count == avgCount) 27 | { 28 | yield return total / avgCount; 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/IntegrationTesting.WithIAsyncEnumerator#EnumeratorTestAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.EnumeratorTestAsync.g.cs 2 | void EnumeratorTest(global::System.Collections.Generic.IEnumerable range) 3 | { 4 | global::System.Collections.Generic.IEnumerator e = range.GetEnumerator(); 5 | try 6 | { 7 | while (e.MoveNext()) global::System.Console.Write(e.Current + " "); 8 | } 9 | finally { if (e != null) e.Dispose(); } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/InterpolatedStringTests.EnsureParentheses#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | var z = $"123{(global::System.IO.File.ReadAllText("123"))}456"; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/InterpolatedStringTests.HandleFormatString#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | var z = $"123{(global::System.IO.File.ReadAllText("123")):hh}456"; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/IsCancellationRequestedTests.IfCancelled#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/IsCancellationRequestedTests.IfNotCancelled#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | if (true) 3 | { 4 | global::System.Threading.Thread.Sleep(120000); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/IsCancellationRequestedTests.WhileNotCancelled#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | while (true) 3 | { 4 | global::System.Threading.Thread.Sleep(120000); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/MemoryTests.ConvertMemoryToSpan#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | var m = GetMemory().Span; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/MemoryTests.ConvertMemoryToSpanAfterPropertyAccess#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | var m = global::System.Buffers.MemoryPool.Shared.Rent().Memory.Span; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/MemoryTests.DropSpanAfterAsMemory#MakeArrayAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MakeArrayAsync.g.cs 2 | public void MakeArray(byte[] sampleBytes) 3 | { 4 | var arr = global::System.MemoryExtensions.AsSpan(sampleBytes, 0, 123).ToArray(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/MemoryTests.DropSpanAfterAsMemoryWithWhitespace#MakeArrayAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MakeArrayAsync.g.cs 2 | public void MakeArray(byte[] sampleBytes) 3 | { 4 | var arr = 5 | global::System.MemoryExtensions.AsSpan(sampleBytes, 0, 123).ToArray(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/MemoryTests.MemorySpanProperty_explicitType=False#MakeArray.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MakeArray.g.cs 2 | private void MakeArray(byte[] sampleBytes) 3 | { 4 | var mem = global::System.MemoryExtensions.AsSpan(sampleBytes, 0, 123); 5 | var arr = mem.ToArray(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/MemoryTests.MemorySpanProperty_explicitType=True#MakeArray.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MakeArray.g.cs 2 | private void MakeArray(byte[] sampleBytes) 3 | { 4 | global::System.Span mem = global::System.MemoryExtensions.AsSpan(sampleBytes, 0, 123); 5 | var arr = mem.ToArray(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/MemoryTests.MemoryToSpan#ReadAsMemoryAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReadAsMemoryAsync.g.cs 2 | private void ReadAsMemory(global::System.IO.Stream stream, byte[] sampleBytes) 3 | => stream.Read(global::System.MemoryExtensions.AsSpan(sampleBytes, 0, 123)); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/MemoryTests.NonPredefinedTypes#N1.Class.FillAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: N1.Class.FillAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace N1 5 | { 6 | partial class Class 7 | { 8 | void Fill(global::System.Span accelerometers) 9 | { 10 | global::N2.C1.C2.Accelerometer a = new(1, 2, 3); 11 | accelerometers[0] = a; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/MemoryTests.PreserveUnrelatedSpan#HasMemoryAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.HasMemoryAsync.g.cs 2 | public void HasMemory(global::System.Span mem) 3 | { 4 | void Inner() 5 | { 6 | global::Test.Class.Unrelated mem = new(); 7 | int shouldBeInt = mem.Span; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/MemoryTests.ReadOnlyMemoryToReadOnlySpan#WriteAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.WriteAsync.g.cs 2 | static void Write(global::System.ReadOnlySpan buffer, global::System.IO.Stream stream) 3 | => stream.Write(buffer); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/NullabilityTests.ConditionalNullable#Test.MyClass.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.MyClass.MethodAsync.g.cs 2 | // 3 | namespace Test; 4 | partial class MyClass 5 | { 6 | public void Method(global::System.IO.Stream stream) 7 | { 8 | _ = ((object)stream == null ? (global::System.IO.Stream)null : global::Test.Extension.DoSomething(stream)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/NullabilityTests.ConditionalNullableStructTwice#Test.MyClass.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.MyClass.MethodAsync.g.cs 2 | // 3 | namespace Test; 4 | partial class MyClass 5 | { 6 | public void Method(int? myInt) 7 | { 8 | _ = (!myInt.HasValue ? (int?)null : global::Test.Extension.DoSomething2(global::Test.Extension.DoSomething(myInt.Value))); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/NullabilityTests.ConditionalNullableTwice#Test.MyClass.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.MyClass.MethodAsync.g.cs 2 | // 3 | namespace Test; 4 | partial class MyClass 5 | { 6 | public void Method(global::System.IO.Stream stream) 7 | { 8 | _ = ((global::System.Func)((param)=> 9 | { 10 | if ((object)param == null) 11 | { 12 | return null; 13 | } 14 | 15 | global::System.IO.Stream check0 = global::Test.Extension.DoSomething(param); 16 | return (object)check0 == null ? (global::System.IO.Stream)null : global::Test.Extension.DoSomething(check0); 17 | }))(stream); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/NullabilityTests.NoNullableSupport#Test.WithNullableDisabled.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.WithNullableDisabled.MethodAsync.g.cs 2 | // 3 | namespace Test; 4 | partial class WithNullableDisabled 5 | { 6 | public void Method(string l) { } 7 | } 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/NullabilityTests.NullableDisable#Test.WithNullableDisabled.DoNothingAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.WithNullableDisabled.DoNothingAsync.g.cs 2 | // 3 | #nullable disabled 4 | namespace Test; 5 | internal partial class WithNullableDisabled 6 | { 7 | public void DoNothing(string l) 8 | { 9 | l = null; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/NullabilityTests.NullableOmitExplicit#Test.MyClass.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.MyClass.MethodAsync.g.cs 2 | // 3 | namespace Test; 4 | partial class MyClass 5 | { 6 | [global::System.ObsoleteAttribute] 7 | public void Method() 8 | { 9 | string f = null; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ParentTests.Record#Test.Record.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Record.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | public partial record Record 6 | { 7 | public void Method() => global::System.Threading.Thread.Sleep(1000); 8 | } 9 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ParentTests.RecordClass#Test.Record.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Record.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | public partial record class Record 6 | { 7 | public void Method() => global::System.Threading.Thread.Sleep(1000); 8 | } 9 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ParentTests.RecordStruct#Test.RecordStruct.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.RecordStruct.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | public partial record struct RecordStruct 6 | { 7 | public readonly void Method() => global::System.Threading.Thread.Sleep(1000); 8 | } 9 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/ParentTests.Struct#Test.Struct.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Struct.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | public partial struct Struct 6 | { 7 | public readonly void Method() => global::System.Threading.Thread.Sleep(1000); 8 | } 9 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/PreprocessorTests.MacrosAroundBraces#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | #if !BLA 3 | { 4 | #endif 5 | 6 | #if !BLA 7 | } 8 | #endif 9 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SpecialMethodsTests.DropMethodsWithSpecialNamesInUserClass#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | public static int Method() 3 | { 4 | } 5 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SpecialMethodsTests.FromTaskResultCheck#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = 1; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SpecialMethodsTests.FromValueTaskResultCheck#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = 1; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SpecialMethodsTests.TaskDelayToThreadSleepWithInt#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Threading.Thread.Sleep(1); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SpecialMethodsTests.TaskDelayToThreadSleepWithSpan#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Threading.Thread.Sleep(new global::System.TimeSpan(2, 3, 4)); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.DoNotMixSymbols.verified.txt: -------------------------------------------------------------------------------- 1 | { 2 | Diagnostics: [ 3 | { 4 | Location: : (6,0)-(6,38), 5 | Message: Couldn't process condition '#if SYMBOL1 && !(SYNC_ONLY || SYMBOL2)'. SYNC_ONLY and other symbols must not be in the same condition., 6 | Severity: Error, 7 | Descriptor: { 8 | Id: ZSMGEN002, 9 | Title: SYNC_ONLY and other symbols must not be in the same condition, 10 | MessageFormat: Couldn't process condition '{0}'. SYNC_ONLY and other symbols must not be in the same condition., 11 | Category: Preprocessor, 12 | DefaultSeverity: Error, 13 | IsEnabledByDefault: true 14 | } 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.DoNotRemove#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | #if SYMBOL1 3 | ArgumentNullException.ThrowIfNull(source); 4 | #elif SYMBOL2 5 | ArgumentNullException.ThrowIfNull(source); 6 | #else 7 | global::System.ArgumentNullException.ThrowIfNull(source); 8 | #endif 9 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.DoNotRemoveInsideSyncOnly#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | #if SYMBOL 3 | throw new global::System.InvalidOperationException("Some exception"); 4 | #endif 5 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.InsideEmptyIf#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | if (true) 3 | { 4 | throw new InvalidOperationException("Some exception"); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.InsideParameter#IsNullAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.IsNullAsync.g.cs 2 | public bool IsNull( 3 | global::System.Data.IDataReader reader, 4 | int i) 5 | { 6 | return reader.IsDBNull(i); 7 | } 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.LastParameter#IsNullAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.IsNullAsync.g.cs 2 | public bool IsNull( 3 | global::System.Data.IDataReader reader 4 | ) 5 | { 6 | return reader.IsDBNull(i); 7 | } 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.MultipleBlocksArentInterfering#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | string a = ""; 3 | int b = 0; 4 | 5 | if (a != null) 6 | { 7 | b = 50; 8 | } 9 | 10 | _ = a + b; 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.NestedSyncOnly#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | System.Console.Write("Sync"); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.NotSyncOnly#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.NotSyncOnlyFollowedBySyncOnly#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | System.Console.Write("Sync"); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.NotSyncOnlyInsideSyncOnly.verified.txt: -------------------------------------------------------------------------------- 1 | { 2 | Diagnostics: [ 3 | { 4 | Location: : (8,0)-(8,14), 5 | Message: Couldn't process directive '#if !SYNC_ONLY'. SYNC_ONLY and !SYNC_ONLY cannot be nested inside each other., 6 | Severity: Error, 7 | Descriptor: { 8 | Id: ZSMGEN001, 9 | Title: SYNC_ONLY and !SYNC_ONLY cannot be nested inside each other, 10 | MessageFormat: Couldn't process directive '{0}'. SYNC_ONLY and !SYNC_ONLY cannot be nested inside each other., 11 | Category: Preprocessor, 12 | DefaultSeverity: Error, 13 | IsEnabledByDefault: true 14 | } 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.ProhibitElif.verified.txt: -------------------------------------------------------------------------------- 1 | { 2 | Diagnostics: [ 3 | { 4 | Location: : (8,0)-(8,12), 5 | Message: Couldn't process directive '#elif Symbol'. SYNC_ONLY cannot be used with #elif., 6 | Severity: Error, 7 | Descriptor: { 8 | Id: ZSMGEN003, 9 | Title: SYNC_ONLY cannot be used with #elif, 10 | MessageFormat: Couldn't process directive '{0}'. SYNC_ONLY cannot be used with #elif., 11 | Category: Preprocessor, 12 | DefaultSeverity: Error, 13 | IsEnabledByDefault: true 14 | } 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.SimpleMacro#ExecAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ExecAsync.g.cs 2 | public void Exec() 3 | { 4 | throw new InvalidOperationException("Some exception"); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.StatementAtTheEnd#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | 3 | global::System.Console.Write("Done"); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.SwitchStatementProcessesDirectives#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | var i = 0; 3 | switch (i) 4 | { 5 | case 0: 6 | break; 7 | case 2: 8 | System.Console.Write("Sync"); 9 | break; 10 | case 3: 11 | #if SYMBOL 12 | System.Console.Write("Symbol"); 13 | #endif 14 | break; 15 | } 16 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SyncOnlyTests.SyncOnlyBeforeMethodBody#MethodWithObsoleteSyncAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodWithObsoleteSyncAsync.g.cs 2 | [global::System.Obsolete] 3 | [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] 4 | public void MethodWithObsoleteSync() 5 | { 6 | global::System.Threading.Thread.Sleep(1000); 7 | } 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.AsyncForEachDeconstruct#SumAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.SumAsync.g.cs 2 | int Sum(global::System.Collections.Generic.IEnumerable<(int a, int b)> enumerable) 3 | { 4 | int sum = 0; 5 | 6 | foreach (var (a, b) in enumerable) 7 | { 8 | sum += a + b; 9 | } 10 | 11 | return sum; 12 | } 13 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.AsyncForEachQualified#SumAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.SumAsync.g.cs 2 | int Sum(global::System.Collections.Generic.IEnumerable enumerable) 3 | { 4 | int sum = 0; 5 | 6 | foreach (int? i in enumerable) 7 | { 8 | if (i.HasValue) 9 | { 10 | sum += i.Value; 11 | } 12 | } 13 | 14 | return sum; 15 | } 16 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.ConfiguredCancelableAsyncEnumerable#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | internal int Method(global::System.Collections.Generic.IEnumerable<(global::System.IO.Stream A, int B)> enumerable) 3 | { 4 | var enumerator = enumerable.GetEnumerator(); 5 | 6 | int sum = 0; 7 | while (enumerator.MoveNext()) 8 | { 9 | sum += (int)enumerator.Current.A.Length + enumerator.Current.B; 10 | } 11 | 12 | return sum; 13 | } 14 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.ConfiguredCancelableAsyncEnumerableExtension#GetConfiguredEnumeratorAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetConfiguredEnumeratorAsync.g.cs 2 | // From https://github.com/dotnet/reactive/blob/5f831de0bc70bc660d21c3b9e04e581269691a2a/Ix.NET/Source/System.Linq.Async/System/Threading/Tasks/AsyncEnumerableExt.cs#L15 3 | 4 | public static System.Collections.Generic.IEnumerator GetConfiguredEnumerator(global::System.Collections.Generic.IEnumerable enumerable) 5 | { 6 | return enumerable.GetEnumerator(); 7 | } 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.ConfiguredCancelableAsyncEnumerableExtensionUsingStatic#Test.Extensions.GetConfiguredAsyncEnumerator.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Extensions.GetConfiguredAsyncEnumerator.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | internal static partial class Extensions 6 | { 7 | public static System.Collections.Generic.IEnumerator GetConfiguredEnumerator(global::System.Collections.Generic.IEnumerable enumerable) 8 | { 9 | return enumerable.GetEnumerator(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.DropConfigureAwaitExtensions#InvokeAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.InvokeAsync.g.cs 2 | public void Invoke() 3 | => _ = GetItem(4); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.DropConfiguredCancelableAsyncEnumerable#Iterate.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.Iterate.g.cs 2 | public static void Iterate(this global::System.Collections.Generic.IEnumerable list1) 3 | { 4 | foreach (var item in list1) 5 | { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.DropConfiguredCancelableAsyncEnumerableExtensionInvocation#Test.Extensions.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Extensions.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | internal static partial class Extensions 6 | { 7 | internal static void Method(global::System.Collections.Generic.IEnumerable enumerable) 8 | { 9 | using System.Collections.Generic.IEnumerator enumerator = enumerable.GetEnumerator(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.DropWithCancellation#Iterate.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.Iterate.g.cs 2 | public static void Iterate(this global::System.Collections.Generic.IEnumerable list1) 3 | { 4 | foreach (var item in list1) 5 | { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.ArrayParameter#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | public void Method(int[] o) 3 | { 4 | } 5 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.BinaryPattern#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = new object() is global::System.DBNull or global::System.IO.Stream; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.CastFullyQualifiedType#GetCustomObjectAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetCustomObjectAsync.g.cs 2 | public object GetCustomObject(object o) 3 | { 4 | return (global::Test.Class.CustomClass)o; 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.CastFullyQualifiedTypeTwice#GetCustomObjectAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetCustomObjectAsync.g.cs 2 | public object GetCustomObject(object o) 3 | { 4 | return (global::Test.Class.CustomClass)(object)(global::Test.Class.CustomClass)o; 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.ConvertExceptionType#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | try 3 | { 4 | } 5 | catch (global::System.OperationCanceledException) 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.ConvertForeachType#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | foreach (int i in new int[] { 1 }) 3 | { 4 | } 5 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.CreateNullableType#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | new global::System.Collections.Generic.Dictionary().TryGetValue(0, out (int I, global::System.IO.Stream? S)? a); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.DeclarationExpression#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | new global::System.Collections.Generic.Dictionary().TryGetValue(0, out global::System.IO.Stream a); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.EnumPattern#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = global::System.Data.ConnectionState.Closed is global::System.Data.ConnectionState.Closed; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.EnumPatternName#.Class.ReturnTrueAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: .Class.ReturnTrueAsync.g.cs 2 | // 3 | #nullable enable 4 | partial class Class 5 | { 6 | public bool ReturnTrue() 7 | { 8 | return global::Test.Test is global::Test.Test; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.EventHandlerType#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = new global::System.Diagnostics.DataReceivedEventHandler((s, e) => { }); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.FullyQualifiedArray#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Text.RegularExpressions.Regex[] variable = null!; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.GenericClassWithGenericInnerClass#Test.Class{T}.FooAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class{T}.FooAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | internal partial class Class 6 | { 7 | public void Foo(global::Test.Class.Int i) { } 8 | } 9 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.HandleAsCast#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = new object() as global::System.IO.Stream; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.HandleDiscardSymbol#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = int.TryParse("2", out _); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.HandleNameOf#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = nameof(global::System.IO.Stream); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.HandleNameOfGenericTuple#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = nameof(global::System.Collections.Generic.IEnumerable<(global::System.IO.Stream? S, int I)>); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.HandleNullableTuple#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | public void Method((global::System.IO.Stream? S, int I) z) { } 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.HandleTuple#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | public void Method((global::System.IO.Stream S, int I) z) { } 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.HandleTypeOf#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = typeof(global::System.IO.Stream); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.NestedGenerics#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | var dict = new global::System.Collections.Generic.Dictionary>(); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.NotPattern#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = new object() is not global::System.DBNull; 3 | 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.NullableDeclarationExpression#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | new global::System.Collections.Generic.Dictionary().TryGetValue(0, out global::System.IO.Stream? a); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.NullableForeach#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | foreach (global::System.IO.Stream? i in global::System.Array.Empty()) 3 | { 4 | } 5 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.PatternIsEnumMember#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = global::System.StringComparison.CurrentCulture is global::System.StringComparison.CurrentCulture; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.PatternIsNotLiteral#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = global::System.StringComparison.CurrentCulture is not global::System.StringComparison.CurrentCulture; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.PatternMatchingWithConstant#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | _ = 1 is 2; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.QualifiedGenericName#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Collections.Generic.HashSet z = null!; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.QualifiedNonGenericName#System.Class.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: System.Class.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace System; 5 | public partial class Class 6 | { 7 | public void Method() 8 | { 9 | global::System.Security.Cryptography.CryptographicException z = null!; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.SwitchType#SwitchAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.SwitchAsync.g.cs 2 | public void Switch(global::System.IO.Stream stream) 3 | { 4 | var s = stream switch 5 | { 6 | global::System.IO.FileStream fs => fs, 7 | _ => throw new global::System.InvalidOperationException("No"), 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.TestTypes#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | string myStr; 3 | string myStrPredefined; 4 | global::System.Exception ex; 5 | short myShort; 6 | short[] myShorts; 7 | long myLong; 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.UseFullyQualifiedTypeInIsExpression#HasIsExpressionAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.HasIsExpressionAsync.g.cs 2 | public void HasIsExpression(global::System.IO.Stream stream) => _ = stream is global::System.IO.FileStream; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.VariableDeclaration#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.IO.MemoryStream ms = new(); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/TypeTests.VariableDeclarationRedundant#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.IO.MemoryStream ms = new global::System.IO.MemoryStream(); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.BasicEvent#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | MyEvent?.Invoke(this, global::System.EventArgs.Empty); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.BasicInterface#Test.IMyInterface.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.IMyInterface.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | public partial interface IMyInterface 6 | { 7 | void Method() 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.BrokenIfStatement#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.CallPropertiesReturningTasksWithAsync#MyMethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MyMethodAsync.g.cs 2 | public void MyMethod() 3 | { 4 | w.Action(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.CallWithTypeParameters#MyFuncAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MyFuncAsync.g.cs 2 | public void MyFunc() 3 | { 4 | MyFunc(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.ConvertAsyncDelegateToDelegate#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | global::System.Action a = delegate () { global::System.Threading.Thread.Sleep(100); }; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.ConvertAsyncDelegateToSync#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | public int Method(global::System.Func task) 3 | { 4 | var r = task(); 5 | return r; 6 | } 7 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DefaultParameter#GetColorAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetColorAsync.g.cs 2 | public void GetColor(global::System.IO.FileAccess access = global::System.IO.FileAccess.Read) { } 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DeleteIfBetweenPreprocessorDirectives#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | #if MY_SPECIAL_SYMBOL 3 | if (true) 4 | { 5 | } 6 | #else 7 | #endif 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DoNotCallPropertiesReturningGenericTasks#MyMethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MyMethodAsync.g.cs 2 | public void MyMethod() 3 | { 4 | } 5 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DoNotCallPropertiesReturningGenericTasksExpression#MyMethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MyMethodAsync.g.cs 2 | public void MyMethod() 3 | { } 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DoNotCallPropertiesReturningTasks#MyMethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MyMethodAsync.g.cs 2 | public void MyMethod() 3 | { 4 | } 5 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DoNotDropInvocationChainThatHasAsyncAnywhere#WriteAllTextAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.WriteAllTextAsync.g.cs 2 | public static void WriteAllText(string file, string contents) 3 | { 4 | global::System.IO.File.WriteAllText(file, contents); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DropBrackets#GetIntAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetIntAsync.g.cs 2 | public static int GetInt() 3 | { 4 | return new[] { 1, 2 }[0]; 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DropCompletedTask#ExecAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ExecAsync.g.cs 2 | public void Exec() 3 | { 4 | } 5 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DropIProgressExpressionArgument#CallWithIProgressAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.CallWithIProgressAsync.g.cs 2 | public static void CallWithIProgress() 3 | { 4 | WithIProgress(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DropIProgressStatement#CallWithIProgressAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.CallWithIProgressAsync.g.cs 2 | public static void CallWithIProgress() 3 | { 4 | 5 | WithIProgress(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DropUnawaitedCompletedTask#DoSomethingAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.DoSomethingAsync.g.cs 2 | public static void DoSomething() { } 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.DropUnawaitedCompletedValueTask#DoSomethingAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.DoSomethingAsync.g.cs 2 | public static void DoSomething() { } 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.FindsASpan#GetMemoryOrSpanAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetMemoryOrSpanAsync.g.cs 2 | private void GetMemoryOrSpan() 3 | { 4 | var instance = new global::Test.Class.ClassThatReturnsMemoryAndSpan(); 5 | global::System.Span mem = instance.GetSpan(); 6 | var arr = mem.ToArray(); 7 | } 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.FullyQualifiedAndNullable#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | string Method(global::System.Net.HttpStatusCode? bar) 3 | { 4 | return string.Empty; 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.GenericAsyncCall#Test.GenericClass{T}.FooAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.GenericClass{T}.FooAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | partial class GenericClass 6 | { 7 | public T Foo() 8 | => this.InnerFoo(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.GenericClass#Test.GenericClass{T1,T2}.EmptyAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.GenericClass{T1,T2}.EmptyAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | partial class GenericClass 6 | { 7 | void Empty() 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.GenericClassMemberAccess#Test.GenericClass{T}.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.GenericClass{T}.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | partial class GenericClass 6 | { 7 | public void Method() 8 | { 9 | _ = global::Test.GenericClass.Bar; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.HandleAsTask#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | public void Method() => OtherMethod(); 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.HandleAsTaskOnParameter#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | public int Method(int vt) 3 | { 4 | var r = vt; 5 | return r; 6 | } 7 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.HandleAttribute#ReadSomeBytesAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReadSomeBytesAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | public partial class Class 6 | { 7 | public int ReadSomeBytes(global::System.IO.Stream stream) 8 | { 9 | var buffer = new byte[100]; 10 | return stream.Read(buffer, 0, 100); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.HandleAttributeOnLocalFunction#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | void Local() 3 | { 4 | } 5 | 6 | Local(); 7 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.KeepDefaultValueTaskWithResult#ReturnDefault.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReturnDefault.g.cs 2 | public static int ReturnDefault() => default; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.LocalFunction#InternalExampleAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.InternalExampleAsync.g.cs 2 | public static int InternalExample(global::System.IO.Stream stream) 3 | { 4 | static int Internal(global::System.IO.Stream stream) 5 | { 6 | var buf = new byte[1]; 7 | return stream.Read(buf, 0, 1); 8 | } 9 | return Internal(stream); 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.LocalFunctionDelegateWithEndingAsync#DoItAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.DoItAsync.g.cs 2 | public static void DoIt() 3 | { 4 | static int Local() 5 | { 6 | return 0; 7 | } 8 | 9 | _ = SomeMethod(Local); 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.LocalFunctionNonGeneric#InternalExampleAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.InternalExampleAsync.g.cs 2 | public static int InternalExample(global::System.IO.Stream stream) 3 | { 4 | static void LocalFunc() 5 | { 6 | } 7 | 8 | LocalFunc(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.MemoryToSpanWithBody#ReadAsMemoryAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReadAsMemoryAsync.g.cs 2 | private void ReadAsMemory(global::System.IO.Stream stream, byte[] sampleBytes) 3 | { 4 | stream.Read(global::System.MemoryExtensions.AsSpan(sampleBytes, 0, 123)); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.MultipleClasses#NsOne.C1.C2.C3.C4.EmptyAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: NsOne.C1.C2.C3.C4.EmptyAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace NsOne 5 | { 6 | public partial class C1 7 | { 8 | partial class C2 9 | { 10 | private protected partial class C3 11 | { 12 | private partial class C4 13 | { 14 | void Empty() 15 | { 16 | } 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.MultipleInitializers#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | int b = 2; 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.MultipleNamespaces#NsOne.NsTwo.NsThree.NsFour.MultipleNamespaces.EmptyAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: NsOne.NsTwo.NsThree.NsFour.MultipleNamespaces.EmptyAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace NsOne 5 | { 6 | namespace NsTwo.NsThree 7 | { 8 | namespace NsFour 9 | { 10 | public partial class MultipleNamespaces 11 | { 12 | void Empty() 13 | { 14 | } 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.Overloads#ReadAsMemoryAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReadAsMemoryAsync.g.cs 2 | void ReadAsMemory(global::System.IO.Stream stream, byte[] sampleBytes) 3 | => stream.Read(global::System.MemoryExtensions.AsSpan(sampleBytes, 0, 123)); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.Overloads#ReadAsMemoryAsync_2.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReadAsMemoryAsync_2.g.cs 2 | void ReadAsMemory(global::System.IO.Stream stream, byte[] sampleBytes) 3 | => stream.Read(global::System.MemoryExtensions.AsSpan(sampleBytes, 0, 123)); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.PassIAsyncDisposable#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | void Method(global::Test.Class.ImplementsBothDisposables a) 3 | { 4 | using (a) 5 | { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.Preprocessor#WrappedAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.WrappedAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Test; 5 | public partial class Class 6 | { 7 | /// 8 | /// A summary 9 | /// 10 | public void Wrapped() { } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.ReturnDefaultValueTask#ReturnAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReturnAsync.g.cs 2 | private void Return(bool input) 3 | { 4 | if (input) 5 | { 6 | return; 7 | } 8 | global::System.Console.WriteLine("123"); 9 | } 10 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.ReturnTask#ReturnAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReturnAsync.g.cs 2 | private void Return(bool input) 3 | { 4 | if (input) 5 | { 6 | Return(); return; 7 | } 8 | Return(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.ReturnTaskNoBody#ReturnAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReturnAsync.g.cs 2 | private void Return(bool input) 3 | { 4 | if (input) { Return(); return; } 5 | Return(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.ReturnValueTask#ReturnAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReturnAsync.g.cs 2 | private void Return(bool input) 3 | { 4 | if (input) 5 | { 6 | Return(); return; 7 | } 8 | Return(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.ReturnValueTaskConditional#ReturnAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReturnAsync.g.cs 2 | private void Return(bool input) 3 | { 4 | if (input) Return(); else Return(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.ReturnValueTaskConditionalFalse#ReturnFalseAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReturnFalseAsync.g.cs 2 | private void ReturnFalse(bool input) 3 | { 4 | if (!input) Return(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.ReturnValueTaskConditionalTrue#ReturnTrueAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReturnTrueAsync.g.cs 2 | private void ReturnTrue(bool input) 3 | { 4 | if (input) Return(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.ReturnValueTaskInstance#ReturnAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReturnAsync.g.cs 2 | public static int Return() { return 1; } 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.ReturnValueTaskNoBody#ReturnAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.ReturnAsync.g.cs 2 | private void Return(bool input) 3 | { 4 | if (input) { Return(); return; } 5 | Return(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.StaticUsings#N1.C1.MethodAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: N1.C1.MethodAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace N1 5 | { 6 | public partial class C1 7 | { 8 | public void Method() 9 | { 10 | _ = global::N2.C2.OtherConst; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.TaskOfArrayOfGeneric#GetArrayOfTAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetArrayOfTAsync.g.cs 2 | public static global::System.Collections.Generic.LinkedListNode[] GetArrayOfT() where T : new() 3 | { 4 | return new global::System.Collections.Generic.LinkedListNode[] { }; 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.TaskOfT#GetPointAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetPointAsync.g.cs 2 | public static global::System.Drawing.Point GetPoint() 3 | { 4 | return new global::System.Drawing.Point(1, 2); 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.TaskOfT2IList#GetArrayOfTAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetArrayOfTAsync.g.cs 2 | public static global::System.Collections.Generic.IList GetArrayOfT() where T: new() 3 | { 4 | return new T[] { new T() }; 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.TaskOfTArray#GetPointAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetPointAsync.g.cs 2 | public static global::System.Drawing.Point[] GetPoint() 3 | { 4 | return new[] { new global::System.Drawing.Point(1, 2) }; 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.TaskOfTIList#GetPointAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.GetPointAsync.g.cs 2 | public static global::System.Collections.Generic.IList GetPoint() 3 | { 4 | return new[] { new global::System.Drawing.Point(1, 2) }; 5 | } 6 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.OneParamsAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.OneParamsAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Zomp.SyncMethodGenerator.IntegrationTests 5 | { 6 | partial class ExtensionMethods 7 | { 8 | public static void OneParams(object o, string s) => global::Extensi.ons123.MyExtensionClass.SomeMethod(o, s); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.TwoParamsAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.TwoParamsAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Zomp.SyncMethodGenerator.IntegrationTests 5 | { 6 | partial class ExtensionMethods 7 | { 8 | public static void TwoParams(object o, string s, int i) => global::Extensi.ons123.MyExtensionClass.SomeMethod(o, s, i); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.ZeroParamsAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.ZeroParamsAsync.g.cs 2 | // 3 | #nullable enable 4 | namespace Zomp.SyncMethodGenerator.IntegrationTests 5 | { 6 | partial class ExtensionMethods 7 | { 8 | public static void ZeroParams(object o) => global::Extensi.ons123.MyExtensionClass.SomeMethod(o); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.VerifyAsyncParamHandling#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | static byte[] HelperMethod(params int[] myParams) => null; 3 | _ = HelperMethod(1, 2); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.VerifyParamHandling#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | static byte[] HelperMethod(params int[] myParams) => null; 3 | _ = HelperMethod(1, 2); 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.WhenDroppingStatementLeaveTrivia#g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.MethodAsync.g.cs 2 | #if !MY_SPECIAL_SYMBOL 3 | #endif 4 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.WithAction#WithAction.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.WithAction.g.cs 2 | public static void WithAction(global::System.Action>? action) { } 3 | -------------------------------------------------------------------------------- /tests/Generator.Tests/Snapshots/UnitTests.WithPreprocessor#WithPreprocessorAsync.g.verified.cs: -------------------------------------------------------------------------------- 1 | //HintName: Test.Class.WithPreprocessorAsync.g.cs 2 | // 3 | namespace Test; 4 | public partial class Class 5 | { 6 | #if NET8_0_OR_GREATER 7 | private void WithPreprocessor() { } 8 | } 9 | -------------------------------------------------------------------------------- /tests/Generator.Tests/SourceType.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public enum SourceType 4 | { 5 | /// 6 | /// Listing of a body of a block method. A single parameter is passed: CancellationToken ct. 7 | /// 8 | MethodBody, 9 | 10 | /// 11 | /// Listing of a body of a class. 12 | /// 13 | ClassBody, 14 | 15 | /// 16 | /// Listing for the file in full. 17 | /// 18 | Full, 19 | } 20 | -------------------------------------------------------------------------------- /tests/Generator.Tests/SpecialMethodsTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class SpecialMethodsTests 4 | { 5 | [Theory] 6 | [InlineData(false)] 7 | [InlineData(true)] 8 | public Task TaskDelayToThreadSleepWithInt(bool caf) => 9 | $"await Task.Delay(1){Caf(caf)};" 10 | .Verify(disableUnique: true, sourceType: SourceType.MethodBody); 11 | 12 | [Fact] 13 | public Task TaskDelayToThreadSleepWithSpan() => 14 | "await Task.Delay(new TimeSpan(2, 3, 4));" 15 | .Verify(sourceType: SourceType.MethodBody); 16 | 17 | [Theory] 18 | [InlineData(false)] 19 | [InlineData(true)] 20 | public Task FromTaskResultCheck(bool caf) => 21 | $"_ = await Task.FromResult(1){Caf(caf)};" 22 | .Verify(disableUnique: true, sourceType: SourceType.MethodBody); 23 | 24 | #if NETCOREAPP1_0_OR_GREATER 25 | [Theory] 26 | [InlineData(false)] 27 | [InlineData(true)] 28 | public Task FromValueTaskResultCheck(bool caf) => 29 | $"_ = await ValueTask.FromResult(1){Caf(caf)};" 30 | .Verify(disableUnique: true, sourceType: SourceType.MethodBody); 31 | #endif 32 | 33 | [Theory] 34 | [InlineData("await PrivateClass.Delay(2, 5);")] 35 | [InlineData("var z = await PrivateClass.FromResult(2, 6);")] 36 | public Task DropMethodsWithSpecialNamesInUserClass(string invocation) => $$""" 37 | [CreateSyncVersion] 38 | public static async Task MethodAsync(CancellationToken ct) 39 | { 40 | {{invocation}} 41 | } 42 | 43 | private class PrivateClass 44 | { 45 | public static Task Delay(int delay, int unrelated) => Task.CompletedTask; 46 | 47 | public static Task FromResult(TResult delay, int unrelated) => Task.FromResult(delay); 48 | } 49 | """.Verify(disableUnique: true); 50 | 51 | private static string Caf(bool apply) => apply ? ".ConfigureAwait(false)" : string.Empty; 52 | } 53 | -------------------------------------------------------------------------------- /tests/Generator.Tests/SyncOnlyTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class SyncOnlyTests 4 | { 5 | [Theory] 6 | [InlineData(true, "")] 7 | [InlineData(true, "if (!await component.AsyncDump(ct)) { }\n")] 8 | [InlineData(false, "\nif (!await component.AsyncDump(ct)) { }")] 9 | [InlineData(false, "\nif (!await component.AsyncDump(ct)) throw new InvalidOperationException(\"async exception\");")] 10 | public Task SimpleMacro(bool before, string additionalIgnorableCommands) => $$""" 11 | Component component = new(); 12 | 13 | [CreateSyncVersion] 14 | public async Task ExecAsync(CancellationToken ct) 15 | { 16 | {{(before ? additionalIgnorableCommands : string.Empty)}}#if SYNC_ONLY 17 | throw new InvalidOperationException("Some exception"); 18 | #endif{{(before ? string.Empty : additionalIgnorableCommands)}} 19 | } 20 | 21 | class Component 22 | { 23 | internal async Task AsyncDump(CancellationToken token) { 24 | return await Task.FromResult(false); 25 | } 26 | } 27 | """.Verify(false, true); 28 | 29 | [Fact] 30 | public Task InsideEmptyIf() => $$""" 31 | if (true) 32 | { 33 | #if SYNC_ONLY 34 | throw new InvalidOperationException("Some exception"); 35 | #endif 36 | } 37 | """.Verify(false, true, sourceType: SourceType.MethodBody); 38 | 39 | [Fact] 40 | public Task StatementAtTheEnd() => $$""" 41 | 42 | #if SYNC_ONLY 43 | #endif 44 | Console.Write("Done"); 45 | """.Verify(false, true, sourceType: SourceType.MethodBody); 46 | 47 | [Fact] 48 | public Task DoNotRemove() => """ 49 | #if SYMBOL1 50 | ArgumentNullException.ThrowIfNull(source); 51 | #elif SYMBOL2 52 | ArgumentNullException.ThrowIfNull(source); 53 | #else 54 | ArgumentNullException.ThrowIfNull(source); 55 | #endif 56 | """.Verify(sourceType: SourceType.MethodBody); 57 | 58 | [Fact] 59 | public Task DoNotRemoveInsideSyncOnly() => """ 60 | #if SYNC_ONLY 61 | #if SYMBOL 62 | throw new global::System.InvalidOperationException("Some exception"); 63 | #endif 64 | #endif 65 | await Task.CompletedTask; 66 | """.Verify(sourceType: SourceType.MethodBody); 67 | 68 | [Fact] 69 | public Task NotSyncOnly() => """ 70 | #if !SYNC_ONLY 71 | Console.Write("Async"); 72 | #endif 73 | await Task.CompletedTask; 74 | """.Verify(sourceType: SourceType.MethodBody); 75 | 76 | [Theory] 77 | [InlineData(false)] 78 | [InlineData(true)] 79 | public Task NotSyncOnlyInsideSyncOnly(bool atLastToken) 80 | { 81 | var lastStatement = string.Empty; 82 | if (!atLastToken) 83 | { 84 | lastStatement = "await Task.CompletedTask;"; 85 | } 86 | 87 | return $$""" 88 | if (true) { } 89 | #if SYNC_ONLY 90 | #if !SYNC_ONLY 91 | Console.Write("Async"); 92 | #endif 93 | #endif 94 | {{lastStatement}} 95 | """.Verify(disableUnique: true, sourceType: SourceType.MethodBody); 96 | } 97 | 98 | [Fact] 99 | public Task NestedSyncOnly() => """ 100 | #if SYNC_ONLY 101 | #if SYNC_ONLY 102 | System.Console.Write("Sync"); 103 | #endif 104 | #endif 105 | await Task.CompletedTask; 106 | """.Verify(sourceType: SourceType.MethodBody); 107 | 108 | [Theory] 109 | [InlineData(false)] 110 | [InlineData(true)] 111 | public Task SyncOnlyBeforeMethodBody(bool beforeDeclaration) => $$""" 112 | {{(beforeDeclaration ? "[CreateSyncVersion]\n" : string.Empty)}}#if SYNC_ONLY 113 | [global::System.Obsolete] 114 | [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] 115 | #endif{{(beforeDeclaration ? string.Empty : "\n[CreateSyncVersion]")}} 116 | public async Task MethodWithObsoleteSyncAsync() 117 | { 118 | await Task.Delay(1000); 119 | } 120 | """.Verify(disableUnique: true); 121 | 122 | [Fact] 123 | public Task InsideParameter() => $$""" 124 | [CreateSyncVersion] 125 | public async Task IsNullAsync( 126 | #if SYNC_ONLY 127 | global::System.Data.IDataReader reader, 128 | #else 129 | DbDataReader reader, 130 | #endif 131 | int i) 132 | { 133 | return await reader.IsDBNullAsync(i); 134 | } 135 | """.Verify(disableUnique: true); 136 | 137 | [Fact] 138 | public Task LastParameter() => $$""" 139 | [CreateSyncVersion] 140 | public async Task IsNullAsync( 141 | #if SYNC_ONLY 142 | global::System.Data.IDataReader reader 143 | #else 144 | DbDataReader reader 145 | #endif 146 | ) 147 | { 148 | return await reader.IsDBNullAsync(i); 149 | } 150 | """.Verify(disableUnique: true); 151 | 152 | [Theory] 153 | [InlineData(false, false)] 154 | [InlineData(false, true)] 155 | [InlineData(true, false)] 156 | [InlineData(true, true)] 157 | public Task NotSyncOnlyFollowedBySyncOnly(bool syncFirst, bool useElse) 158 | { 159 | var conditions = syncFirst switch 160 | { 161 | true when useElse => """ 162 | #if SYNC_ONLY 163 | System.Console.Write("Sync"); 164 | #else 165 | Console.Write("Async"); 166 | #endif 167 | """, 168 | true when !useElse => """ 169 | #if SYNC_ONLY 170 | System.Console.Write("Sync"); 171 | #endif 172 | #if !SYNC_ONLY 173 | Console.Write("Async"); 174 | #endif 175 | """, 176 | false when useElse => """ 177 | #if !SYNC_ONLY 178 | Console.Write("Async"); 179 | #else 180 | System.Console.Write("Sync"); 181 | #endif 182 | """, 183 | _ => """ 184 | #if SYNC_ONLY 185 | System.Console.Write("Sync"); 186 | #endif 187 | #if !SYNC_ONLY 188 | Console.Write("Async"); 189 | #endif 190 | """, 191 | }; 192 | 193 | return $$""" 194 | {{conditions}} 195 | await Task.CompletedTask; 196 | """.Verify(disableUnique: true, sourceType: SourceType.MethodBody); 197 | } 198 | 199 | [Fact] 200 | public Task ProhibitElif() => """ 201 | #if SYNC_ONLY 202 | Console.Write("Async"); 203 | #elif Symbol 204 | Console.Write("Whatevs"); 205 | #endif 206 | await Task.CompletedTask; 207 | """.Verify(sourceType: SourceType.MethodBody); 208 | 209 | [Fact] 210 | public Task DoNotMixSymbols() => """ 211 | #if SYMBOL1 && !(SYNC_ONLY || SYMBOL2) 212 | System.Console.Write("Sync"); 213 | #endif 214 | """.Verify(sourceType: SourceType.MethodBody); 215 | 216 | [Fact] 217 | public Task SwitchStatementProcessesDirectives() => """ 218 | var i = 0; 219 | switch (i) 220 | { 221 | case 0: 222 | #if !SYNC_ONLY 223 | Console.Write("Async"); 224 | #endif 225 | break; 226 | case 2: 227 | #if SYNC_ONLY 228 | System.Console.Write("Sync"); 229 | #endif 230 | break; 231 | case 3: 232 | #if SYMBOL 233 | System.Console.Write("Symbol"); 234 | #endif 235 | break; 236 | } 237 | 238 | await Task.CompletedTask; 239 | """.Verify(sourceType: SourceType.MethodBody); 240 | 241 | [Fact] 242 | public Task MultipleBlocksArentInterfering() => """ 243 | string a = await Task.FromResult(""); 244 | int b = 0; 245 | 246 | if (a != null) 247 | { 248 | b = 50; 249 | } 250 | 251 | #if SYNC_ONLY 252 | _ = a + b; 253 | #else 254 | _ = a + b + await Task.FromResult(30); 255 | #endif 256 | """.Verify(sourceType: SourceType.MethodBody); 257 | } 258 | -------------------------------------------------------------------------------- /tests/Generator.Tests/SystemAsyncExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class SystemAsyncExtensionsTests 4 | { 5 | [Fact] 6 | public Task DropConfiguredCancelableAsyncEnumerable() => """ 7 | [CreateSyncVersion] 8 | public static async Task Iterate(this IAsyncEnumerable list1, [EnumeratorCancellation] CancellationToken ct = default) 9 | { 10 | await foreach (var item in list1.ConfigureAwait(false)) 11 | { 12 | } 13 | } 14 | """.Verify(); 15 | 16 | [Fact] 17 | public Task DropWithCancellation() => """ 18 | [CreateSyncVersion] 19 | public static async Task Iterate(this IAsyncEnumerable list1, [EnumeratorCancellation] CancellationToken ct = default) 20 | { 21 | await foreach (var item in list1.WithCancellation(ct)) 22 | { 23 | } 24 | } 25 | """.Verify(); 26 | 27 | [Theory] 28 | [InlineData(true, true)] 29 | [InlineData(true, false)] 30 | [InlineData(false, true)] 31 | [InlineData(false, false)] 32 | public Task DropConfigureAwaitExtensions(bool isGeneric, bool isValueTask) 33 | { 34 | var taskPart = isValueTask ? "ValueTask" : "Task"; 35 | var genericPart = isGeneric ? "" : string.Empty; 36 | var genericTaskPart = taskPart + genericPart; 37 | var variablePart = isGeneric ? "T" : "int"; 38 | return $$""" 39 | namespace Test; 40 | 41 | public static class AwaitHelper 42 | { 43 | public static Configured{{taskPart}}Awaitable{{genericPart}} Caf{{genericPart}}(this {{genericTaskPart}} task) 44 | { 45 | return task.ConfigureAwait(false); 46 | } 47 | } 48 | 49 | partial class Class 50 | { 51 | {{variablePart}} GetItem{{genericPart}}({{variablePart}} z) => default; 52 | 53 | async {{genericTaskPart}} GetItemAsync{{genericPart}}({{variablePart}} z) => default; 54 | 55 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 56 | public async Task InvokeAsync() 57 | => _ = await GetItemAsync(4).Caf(); 58 | } 59 | """.Verify(disableUnique: true, sourceType: SourceType.Full); 60 | } 61 | 62 | [Fact] 63 | public Task AsyncForEachQualified() => """ 64 | [CreateSyncVersion] 65 | async Task SumAsync(IAsyncEnumerable enumerable) 66 | { 67 | int sum = 0; 68 | 69 | await foreach (int? i in enumerable) 70 | { 71 | if (i.HasValue) 72 | { 73 | sum += i.Value; 74 | } 75 | } 76 | 77 | return sum; 78 | } 79 | """.Verify(); 80 | 81 | [Fact] 82 | public Task AsyncForEachDeconstruct() => """ 83 | [CreateSyncVersion] 84 | async Task SumAsync(IAsyncEnumerable<(int a, int b)> enumerable) 85 | { 86 | int sum = 0; 87 | 88 | await foreach (var (a, b) in enumerable) 89 | { 90 | sum += a + b; 91 | } 92 | 93 | return sum; 94 | } 95 | """.Verify(); 96 | 97 | [Fact] 98 | public Task ConfiguredCancelableAsyncEnumerable() => """ 99 | [CreateSyncVersion] 100 | internal async Task MethodAsync(IAsyncEnumerable<(Stream A, int B)> enumerable, CancellationToken ct) 101 | { 102 | var enumerator = enumerable.WithCancellation(ct).ConfigureAwait(false).GetAsyncEnumerator(); 103 | 104 | int sum = 0; 105 | while (await enumerator.MoveNextAsync()) 106 | { 107 | sum += (int)enumerator.Current.A.Length + enumerator.Current.B; 108 | } 109 | 110 | return sum; 111 | } 112 | """.Verify(); 113 | 114 | [Fact] 115 | public Task ConfiguredCancelableAsyncEnumerableExtension() => """ 116 | // From https://github.com/dotnet/reactive/blob/5f831de0bc70bc660d21c3b9e04e581269691a2a/Ix.NET/Source/System.Linq.Async/System/Threading/Tasks/AsyncEnumerableExt.cs#L15 117 | 118 | [CreateSyncVersion] 119 | public static ConfiguredCancelableAsyncEnumerable.Enumerator GetConfiguredEnumeratorAsync(IAsyncEnumerable enumerable, CancellationToken ct) 120 | { 121 | return enumerable.ConfigureAwait(false).WithCancellation(ct).GetAsyncEnumerator(); 122 | } 123 | """.Verify(); 124 | 125 | [Fact] 126 | public Task ConfiguredCancelableAsyncEnumerableExtensionUsingStatic() => """ 127 | using static System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable; 128 | namespace Test; 129 | 130 | internal static partial class Extensions 131 | { 132 | [CreateSyncVersion] 133 | public static Enumerator GetConfiguredAsyncEnumerator(IAsyncEnumerable enumerable, CancellationToken ct) 134 | { 135 | return enumerable.ConfigureAwait(false).WithCancellation(ct).GetAsyncEnumerator(); 136 | } 137 | } 138 | """.Verify(sourceType: SourceType.Full); 139 | 140 | [Fact] 141 | public Task DropConfiguredCancelableAsyncEnumerableExtensionInvocation() => """ 142 | namespace Test; 143 | 144 | internal static partial class Extensions 145 | { 146 | // From https://github.com/dotnet/reactive/blob/5f831de0bc70bc660d21c3b9e04e581269691a2a/Ix.NET/Source/System.Linq.Async/System/Threading/Tasks/AsyncEnumerableExt.cs#L15 147 | internal static ConfiguredCancelableAsyncEnumerable.Enumerator GetConfiguredAsyncEnumerator(this IAsyncEnumerable enumerable, CancellationToken ct) 148 | { 149 | return enumerable.ConfigureAwait(false).WithCancellation(ct).GetAsyncEnumerator(); 150 | } 151 | 152 | [CreateSyncVersion] 153 | internal static async Task MethodAsync(IAsyncEnumerable enumerable, CancellationToken ct) 154 | { 155 | await using ConfiguredCancelableAsyncEnumerable.Enumerator enumerator = enumerable.GetConfiguredAsyncEnumerator(ct); 156 | } 157 | } 158 | """.Verify(sourceType: SourceType.Full); 159 | } 160 | -------------------------------------------------------------------------------- /tests/Generator.Tests/TestHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | using System.Diagnostics; 3 | using System.Text.RegularExpressions; 4 | using Zomp.SyncMethodGenerator; 5 | using static Generator.Tests.ModuleInitializer; 6 | 7 | namespace Generator.Tests; 8 | 9 | /// 10 | /// Helps set up the test cases. 11 | /// 12 | internal static partial class TestHelper 13 | { 14 | private const string GlobalUsingsSource = """ 15 | global using global::System; 16 | global using global::System.Buffers; 17 | global using global::System.Collections.Generic; 18 | global using global::System.Data; 19 | global using global::System.Data.Common; 20 | global using global::System.Diagnostics; 21 | global using global::System.Drawing; 22 | global using global::System.IO; 23 | global using global::System.Linq; 24 | #if NET8_0_OR_GREATER 25 | global using global::System.Numerics; 26 | #endif 27 | global using global::System.Reflection; 28 | global using global::System.Runtime.CompilerServices; 29 | global using global::System.Threading; 30 | global using global::System.Threading.Tasks; 31 | global using global::Zomp.SyncMethodGenerator; 32 | """; 33 | 34 | private static readonly string[] PreprocessorSymbols 35 | #if NETFRAMEWORK 36 | = []; 37 | #else 38 | = 39 | [ 40 | #if NET8_0 41 | "NET8_0", 42 | #endif 43 | #if NET8_0_OR_GREATER 44 | "NET8_0_OR_GREATER", 45 | #endif 46 | ]; 47 | #endif 48 | 49 | internal static Task Verify( 50 | this string source, 51 | bool uniqueForFramework = false, 52 | bool disableUnique = false, 53 | SourceType sourceType = SourceType.ClassBody, 54 | LanguageVersion languageVersion = LanguageVersion.Preview, 55 | params object?[] parameters) 56 | { 57 | var parseOptions = CSharpParseOptions.Default 58 | .WithLanguageVersion(languageVersion) 59 | .WithPreprocessorSymbols(PreprocessorSymbols); 60 | 61 | if (sourceType != SourceType.Full) 62 | { 63 | if (sourceType == SourceType.MethodBody) 64 | { 65 | source = $$""" 66 | [CreateSyncVersion] 67 | async Task MethodAsync(CancellationToken ct) 68 | { 69 | {{ChangeIndentation(source, InsertIndentation)}} 70 | } 71 | """; 72 | } 73 | 74 | source = ChangeIndentation(source, InsertIndentation); 75 | source = $$""" 76 | namespace Test; 77 | partial class Class 78 | { 79 | {{source}} 80 | } 81 | """; 82 | } 83 | 84 | var syntaxTree = CSharpSyntaxTree.ParseText(source, parseOptions); 85 | var globalUsings = CSharpSyntaxTree.ParseText(GlobalUsingsSource, parseOptions); 86 | 87 | // SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source); 88 | var linqAssembly = typeof(Enumerable).Assembly.Location; 89 | var locations = new List 90 | { 91 | typeof(IAsyncEnumerable<>).Assembly.Location, 92 | typeof(DataReceivedEventHandler).Assembly.Location, 93 | typeof(DbDataReader).Assembly.Location, 94 | typeof(ValueTask<>).Assembly.Location, 95 | typeof(System.Drawing.Point).Assembly.Location, 96 | typeof(object).Assembly.Location, 97 | typeof(Console).Assembly.Location, 98 | typeof(Memory<>).Assembly.Location, 99 | typeof(System.Buffers.MemoryPool<>).Assembly.Location, 100 | typeof(Queue<>).Assembly.Location, 101 | typeof(LinkedListNode<>).Assembly.Location, 102 | #if NET8_0_OR_GREATER 103 | typeof(AsyncEnumerable).Assembly.Location, 104 | #endif 105 | linqAssembly, 106 | }; 107 | 108 | var directory = Path.GetDirectoryName(linqAssembly); 109 | var runtimeLocation = directory is null ? null : Path.Combine(directory, "System.Runtime.dll"); 110 | if (runtimeLocation is not null && File.Exists(runtimeLocation)) 111 | { 112 | locations.Add(runtimeLocation); 113 | } 114 | 115 | var distinct = locations.Distinct().ToArray(); 116 | 117 | var references = distinct 118 | .Select(l => MetadataReference.CreateFromFile(l)); 119 | 120 | var compilation = CSharpCompilation.Create( 121 | assemblyName: "Tests", 122 | options: new(OutputKind.DynamicallyLinkedLibrary), 123 | syntaxTrees: [syntaxTree, globalUsings], 124 | references: references); 125 | 126 | var generator = new SyncMethodSourceGenerator(); 127 | 128 | var driver = CSharpGeneratorDriver.Create(generator).WithUpdatedParseOptions(parseOptions); 129 | 130 | driver = driver.RunGenerators(compilation); 131 | 132 | // Ensure that at least two sources are generated 133 | var results = driver.GetRunResult(); 134 | if (results.Diagnostics.Length == 0 && results.GeneratedTrees.Length < 2) 135 | { 136 | throw new InvalidOperationException("Nothing generated"); 137 | } 138 | 139 | var target = new RunResultWithIgnoreList 140 | { 141 | Result = driver.GetRunResult(), 142 | IgnoredFiles = { $"{SyncMethodSourceGenerator.CreateSyncVersionAttribute}.g.cs" }, 143 | }; 144 | 145 | var verifier = Verifier 146 | .Verify(target) 147 | .UseDirectory("Snapshots"); 148 | 149 | if (uniqueForFramework) 150 | { 151 | verifier = verifier.UniqueForTargetFrameworkAndVersion(); 152 | } 153 | 154 | if (disableUnique) 155 | { 156 | verifier = verifier.DisableRequireUniquePrefix(); 157 | } 158 | 159 | if (parameters is { Length: > 0 }) 160 | { 161 | verifier = verifier.UseParameters(parameters); 162 | } 163 | 164 | return verifier; 165 | } 166 | 167 | internal static string InsertIndentation(string s) => s.Length == 0 || s[0] == '#' ? s : $" {s}"; 168 | 169 | internal static string RemoveIndentation(string s) => s.StartsWith(" ", StringComparison.Ordinal) ? s[4..] : s; 170 | 171 | internal static string ChangeIndentation(string source, Func func) 172 | { 173 | #if NET8_0_OR_GREATER 174 | var lines = NewLineRegex().Split(source); 175 | #else 176 | var lines = Regex.Split(source, "\r\n"); 177 | #endif 178 | var linesWithIndentation = string.Join("\r\n", lines.Select(func)); 179 | return linesWithIndentation; 180 | } 181 | 182 | #if NET8_0_OR_GREATER 183 | [GeneratedRegex("\r\n")] 184 | private static partial Regex NewLineRegex(); 185 | #endif 186 | } 187 | -------------------------------------------------------------------------------- /tests/Generator.Tests/TypeTests.cs: -------------------------------------------------------------------------------- 1 | namespace Generator.Tests; 2 | 3 | public class TypeTests 4 | { 5 | [Fact] 6 | public Task ConvertExceptionType() => $$""" 7 | try 8 | { 9 | await Task.CompletedTask; 10 | } 11 | catch (OperationCanceledException) 12 | { 13 | } 14 | """.Verify(false, true, sourceType: SourceType.MethodBody); 15 | 16 | [Fact] 17 | public Task NotPattern() => 18 | "_ = new object() is not DBNull;" 19 | .Verify(false, true, sourceType: SourceType.MethodBody); 20 | 21 | [Fact] 22 | public Task PatternMatchingWithConstant() => 23 | "_ = 1 is 2;" 24 | .Verify(sourceType: SourceType.MethodBody); 25 | 26 | [Fact] 27 | public Task PatternIsNotLiteral() => 28 | "_ = StringComparison.CurrentCulture is not StringComparison.CurrentCulture;" 29 | .Verify(sourceType: SourceType.MethodBody); 30 | 31 | [Fact] 32 | public Task PatternIsEnumMember() => 33 | "_ = StringComparison.CurrentCulture is StringComparison.CurrentCulture;" 34 | .Verify(sourceType: SourceType.MethodBody); 35 | 36 | [Fact] 37 | public Task VariableDeclarationRedundant() => 38 | "MemoryStream ms = new MemoryStream();" 39 | .Verify(false, true, sourceType: SourceType.MethodBody); 40 | 41 | [Fact] 42 | public Task VariableDeclaration() => 43 | "MemoryStream ms = new();" 44 | .Verify(false, true, sourceType: SourceType.MethodBody); 45 | 46 | [Fact] 47 | public Task BinaryPattern() => 48 | "_ = new object() is DBNull or Stream;" 49 | .Verify(false, true, sourceType: SourceType.MethodBody); 50 | 51 | [Theory] 52 | [InlineData(true)] 53 | [InlineData(false)] 54 | public Task EnumPattern(bool isQualified) => 55 | $$""" 56 | using static System.Data.ConnectionState; 57 | namespace Test; 58 | 59 | partial class Class 60 | { 61 | [CreateSyncVersion] 62 | public Task MethodAsync() 63 | { 64 | _ = {{(isQualified ? "System.Data.ConnectionState." : string.Empty)}}Closed is System.Data.ConnectionState.Closed; 65 | } 66 | } 67 | """ 68 | .Verify(false, true, sourceType: SourceType.Full); 69 | 70 | [Fact] 71 | public Task EnumPatternName() => 72 | """ 73 | enum Test { Test } 74 | 75 | partial class Class 76 | { 77 | [Zomp.SyncMethodGenerator.CreateSyncVersion] 78 | public Task ReturnTrueAsync() 79 | { 80 | return Task.FromResult(Test.Test is Test.Test); 81 | } 82 | } 83 | """ 84 | .Verify(false, true, sourceType: SourceType.Full); 85 | 86 | [Fact] 87 | public Task DeclarationExpression() => 88 | "new Dictionary().TryGetValue(0, out Stream a);" 89 | .Verify(false, true, sourceType: SourceType.MethodBody); 90 | 91 | [Fact] 92 | public Task NullableDeclarationExpression() => 93 | "new Dictionary().TryGetValue(0, out Stream? a);" 94 | .Verify(false, true, sourceType: SourceType.MethodBody); 95 | 96 | [Fact] 97 | public Task ConvertForeachType() => $$""" 98 | foreach (Int32 i in new Int32[] { 1 }) 99 | { 100 | } 101 | 102 | await Task.CompletedTask; 103 | """.Verify(false, true, sourceType: SourceType.MethodBody); 104 | 105 | [Fact] 106 | public Task NullableForeach() 107 | => """ 108 | foreach (Stream? i in Array.Empty()) 109 | { 110 | } 111 | """ 112 | .Verify(sourceType: SourceType.MethodBody); 113 | 114 | [Fact] 115 | public Task NestedGenerics() 116 | => "var dict = new Dictionary>();" 117 | .Verify(sourceType: SourceType.MethodBody); 118 | 119 | [Fact] 120 | public Task TestTypes() => $$""" 121 | String myStr; 122 | string myStrPredefined; 123 | Exception ex; 124 | Int16 myShort; 125 | Int16[] myShorts; 126 | long myLong; 127 | 128 | await Task.CompletedTask; 129 | """.Verify(false, true, sourceType: SourceType.MethodBody); 130 | 131 | [Fact] 132 | public Task ArrayParameter() => """ 133 | [CreateSyncVersion] 134 | public async Task MethodAsync(Int32[] o) 135 | { 136 | } 137 | """.Verify(); 138 | 139 | [Fact] 140 | public Task CastFullyQualifiedType() => """ 141 | class CustomClass { } 142 | 143 | [CreateSyncVersion] 144 | public async Task GetCustomObjectAsync(object o) 145 | { 146 | return (CustomClass)o; 147 | } 148 | """.Verify(); 149 | 150 | [Fact] 151 | public Task FullyQualifiedArray() 152 | => "System.Text.RegularExpressions.Regex[] variable = null!;" 153 | .Verify(sourceType: SourceType.MethodBody); 154 | 155 | [Fact] 156 | public Task CastFullyQualifiedTypeTwice() => """ 157 | class CustomClass { } 158 | 159 | [CreateSyncVersion] 160 | public async Task GetCustomObjectAsync(object o) 161 | { 162 | return (CustomClass)(object)(CustomClass)o; 163 | } 164 | """.Verify(); 165 | 166 | [Fact] 167 | public Task UseFullyQualifiedTypeInIsExpression() => """ 168 | [CreateSyncVersion] 169 | public async Task HasIsExpressionAsync(Stream stream) => _ = stream is FileStream; 170 | """.Verify(); 171 | 172 | [Fact] 173 | public Task HandleDiscardSymbol() 174 | => "_ = int.TryParse(\"2\", out _);" 175 | .Verify(sourceType: SourceType.MethodBody); 176 | 177 | [Fact] 178 | public Task HandleTypeOf() 179 | => "_ = typeof(Stream);" 180 | .Verify(sourceType: SourceType.MethodBody); 181 | 182 | [Fact] 183 | public Task HandleTuple() 184 | => "[CreateSyncVersion]public async Task MethodAsync((Stream S, int I) z) { }" 185 | .Verify(); 186 | 187 | [Fact] 188 | public Task HandleNullableTuple() 189 | => "[CreateSyncVersion]public async Task MethodAsync((Stream? S, int I) z) { }" 190 | .Verify(); 191 | 192 | [Fact] 193 | public Task HandleNameOf() 194 | => "_ = nameof(Stream);" 195 | .Verify(sourceType: SourceType.MethodBody); 196 | 197 | [Fact] 198 | public Task QualifiedGenericName() 199 | => "System.Collections.Generic.HashSet z = null!;" 200 | .Verify(sourceType: SourceType.MethodBody); 201 | 202 | [Theory] 203 | [InlineData("")] 204 | [InlineData("System.")] 205 | [InlineData("global::System.")] 206 | public Task QualifiedNonGenericName(string prefix) 207 | => $$""" 208 | namespace System; 209 | 210 | public partial class Class 211 | { 212 | [CreateSyncVersion] 213 | public async Task MethodAsync() 214 | { 215 | {{prefix}}Security.Cryptography.CryptographicException z = null!; 216 | } 217 | } 218 | """.Verify(disableUnique: true, sourceType: SourceType.Full); 219 | 220 | [Fact] 221 | public Task HandleAsCast() 222 | => "_ = new object() as Stream;" 223 | .Verify(sourceType: SourceType.MethodBody); 224 | 225 | [Fact] 226 | public Task HandleNameOfGenericTuple() 227 | => "_ = nameof(IEnumerable<(Stream? S, int I)>);" 228 | .Verify(sourceType: SourceType.MethodBody); 229 | 230 | [Fact] 231 | public Task SwitchType() => """ 232 | [CreateSyncVersion] 233 | public async Task SwitchAsync(Stream stream) 234 | { 235 | var s = stream switch 236 | { 237 | FileStream fs => fs, 238 | _ => throw new InvalidOperationException("No"), 239 | }; 240 | } 241 | """.Verify(); 242 | 243 | [Fact] 244 | public Task GenericClassWithGenericInnerClass() => """ 245 | namespace Test; 246 | 247 | internal partial class Class 248 | { 249 | [CreateSyncVersion] 250 | public async Task FooAsync(Int i) { } 251 | 252 | internal class Int { } 253 | } 254 | """.Verify(sourceType: SourceType.Full); 255 | 256 | [Fact] 257 | public Task EventHandlerType() 258 | => "_ = new DataReceivedEventHandler((s, e) => { });" 259 | .Verify(sourceType: SourceType.MethodBody); 260 | 261 | [Fact] 262 | public Task CreateNullableType() 263 | => "new Dictionary().TryGetValue(0, out (int I, Stream? S)? a);" 264 | .Verify(sourceType: SourceType.MethodBody); 265 | } 266 | -------------------------------------------------------------------------------- /tests/coverlet.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cobertura 8 | [*Tests]* 9 | **/*.g.cs 10 | Obsolete,GeneratedCodeAttribute,CompilerGeneratedAttribute,LoggerMessageAttribute 11 | false 12 | false 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "1.4", 4 | "assemblyVersion": { 5 | "precision": "revision" 6 | }, 7 | "publicReleaseRefSpec": [ 8 | "^refs/heads/master$", 9 | "^refs/heads/v\\d+\\.\\d+$" 10 | ], 11 | "cloudBuild": { 12 | "buildNumber": { 13 | "enabled": true 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | husky@^9.1.7: 6 | version "9.1.7" 7 | resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.7.tgz#d46a38035d101b46a70456a850ff4201344c0b2d" 8 | integrity sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA== 9 | --------------------------------------------------------------------------------