diff --git a/src/Zomp.SyncMethodGenerator/AsyncToSyncRewriter.cs b/src/Zomp.SyncMethodGenerator/AsyncToSyncRewriter.cs index 0b1aa26..6c0a2b2 100644 --- a/src/Zomp.SyncMethodGenerator/AsyncToSyncRewriter.cs +++ b/src/Zomp.SyncMethodGenerator/AsyncToSyncRewriter.cs @@ -957,6 +957,14 @@ bool RemoveType(TypeSyntax z, int index) => var originalName = @base.Identifier.Text; var newName = RemoveAsync(originalName); + // A method which returned a task returns nothing once it is synchronized, so whatever + // its documentation said about the task it returned no longer describes anything. The + // documentation of a value which survives is left alone: it is imprecise about the task + // it mentions, but dropping it would say less than saying it imprecisely. + var returnsNothing = GetReturnType(@base.ReturnType, symbol) + is PredefinedTypeSyntax { Keyword.RawKind: (int)SyntaxKind.VoidKeyword } + or IdentifierNameSyntax { Identifier.ValueText: "void" }; + // Documentation var trivia = node.GetLeadingTrivia(); var newTriviaList = trivia; @@ -982,6 +990,12 @@ bool RemoveType(TypeSyntax z, int index) => indicesToRemove.Add(i - 1); // preceding slashes indicesToRemove.Add(i); } + else if (returnsNothing + && xes.StartTag.Name.LocalName.ValueText.Equals("returns", StringComparison.Ordinal)) + { + indicesToRemove.Add(i - 1); // preceding slashes + indicesToRemove.Add(i); + } } ++i; diff --git a/src/Zomp.SyncMethodGenerator/MethodToGenerate.cs b/src/Zomp.SyncMethodGenerator/MethodToGenerate.cs index 90d7b2b..6094d2b 100644 --- a/src/Zomp.SyncMethodGenerator/MethodToGenerate.cs +++ b/src/Zomp.SyncMethodGenerator/MethodToGenerate.cs @@ -5,6 +5,8 @@ /// /// Index of the method in the source file. /// List of namespaces this method is under. +/// Using directives the source file declares outside its namespace. +/// Using directives the source file declares inside its namespace. /// True if namespace is file scoped. /// True if this is C# 14 extension. /// List of classes/structs/records this method belongs to starting from the outer-most class. @@ -17,6 +19,8 @@ internal sealed record MethodToGenerate( int Index, EquatableArray Namespaces, + EquatableArray OuterUsings, + EquatableArray InnerUsings, bool IsNamespaceFileScoped, bool IsCSharp14Extension, EquatableArray Parents, diff --git a/src/Zomp.SyncMethodGenerator/SourceGenerationHelper.cs b/src/Zomp.SyncMethodGenerator/SourceGenerationHelper.cs index e3d2575..bd736fb 100644 --- a/src/Zomp.SyncMethodGenerator/SourceGenerationHelper.cs +++ b/src/Zomp.SyncMethodGenerator/SourceGenerationHelper.cs @@ -100,6 +100,24 @@ internal static string GenerateExtensionClass(MethodToGenerate methodToGenerate) } } + // Directives which were written inside the namespace are emitted inside it, at the + // innermost level. One which names a namespace relatively still resolves from there. + foreach (var @using in methodToGenerate.InnerUsings) + { + _ = sbBegin.Append($$""" +{{new string(' ', 4 * i)}}{{@using}} + +"""); + } + + if (!methodToGenerate.InnerUsings.IsEmpty) + { + _ = sbBegin.Append(""" + + +"""); + } + // Handle classes foreach (var parent in methodToGenerate.Parents) { @@ -136,11 +154,30 @@ internal static string GenerateExtensionClass(MethodToGenerate methodToGenerate) ++i; } + var sbOuterUsings = new StringBuilder(); + foreach (var @using in methodToGenerate.OuterUsings) + { + if (sbOuterUsings.Length == 0) + { + // Separates the directives from the header above them. + _ = sbOuterUsings.Append(""" + + + +"""); + } + + _ = sbOuterUsings.Append($$""" +{{@using}} + +"""); + } + var beforeNamespace = $""" // {(methodToGenerate.DisableNullable ? string.Empty : """ #nullable enable -""")} +""")}{sbOuterUsings} """; return methodToGenerate.IsNamespaceFileScoped ? $$""" diff --git a/src/Zomp.SyncMethodGenerator/SyncMethodSourceGenerator.cs b/src/Zomp.SyncMethodGenerator/SyncMethodSourceGenerator.cs index a3d69fa..3b76bfc 100644 --- a/src/Zomp.SyncMethodGenerator/SyncMethodSourceGenerator.cs +++ b/src/Zomp.SyncMethodGenerator/SyncMethodSourceGenerator.cs @@ -372,6 +372,15 @@ private static string Hash(string value) var isNamespaceFileScoped = false; var namespaces = ImmutableArray.CreateBuilder(); + // Documentation comments are copied across verbatim, and a cref in one is resolved + // against the file it lands in rather than the file it was written in. Without the + // using directives which were in scope where it was written, every cref which relied on + // one goes unresolved, which a project building with warnings as errors reads as a + // build failure. The directives are kept on the side of the namespace they were + // declared on, since one declared inside a namespace may name it only relatively. + var outerUsings = ImmutableArray.CreateBuilder(); + var innerUsings = ImmutableArray.CreateBuilder(); + if (!hasErrors) { while (node is not null and not CompilationUnitSyntax) @@ -380,9 +389,11 @@ private static string Hash(string value) { case NamespaceDeclarationSyntax nds: namespaces.Insert(0, nds.Name.ToString()); + InsertUsings(innerUsings, nds.Usings); break; case FileScopedNamespaceDeclarationSyntax file: namespaces.Add(file.Name.ToString()); + InsertUsings(innerUsings, file.Usings); isNamespaceFileScoped = true; break; default: @@ -391,6 +402,11 @@ private static string Hash(string value) node = node.Parent; } + + if (node is CompilationUnitSyntax compilationUnit) + { + InsertUsings(outerUsings, compilationUnit.Usings); + } } #if ROSLYN_5_0_OR_GREATER @@ -400,11 +416,26 @@ private static string Hash(string value) #endif var signature = BuildSignature(sn, namespaces, classes, methodDeclarationSyntax); - var result = new MethodToGenerate(index, namespaces.ToImmutable(), isNamespaceFileScoped, isCSharp14Extension, classes.ToImmutable(), methodDeclarationSyntax.Identifier.ValueText, content, disableNullable, rewriter.Diagnostics, hasErrors, signature); + var result = new MethodToGenerate(index, namespaces.ToImmutable(), outerUsings.ToImmutable(), innerUsings.ToImmutable(), isNamespaceFileScoped, isCSharp14Extension, classes.ToImmutable(), methodDeclarationSyntax.Identifier.ValueText, content, disableNullable, rewriter.Diagnostics, hasErrors, signature); return result; } + /// + /// Records the directives, innermost first, so that walking outwards from the method builds + /// them up in the order they were written. + /// + /// Collected directives. + /// Directives declared at one level. + private static void InsertUsings(ImmutableArray.Builder destination, SyntaxList usings) + { + var index = 0; + foreach (var @using in usings) + { + destination.Insert(index++, @using.ToString()); + } + } + /// /// Describes the method which is about to be emitted, precisely enough to tell whether two /// of them would declare the same member. The rewritten declaration is used rather than the diff --git a/tests/Generator.Tests/Snapshots/ExtensionMethodTests.CSharp_14_ExtensionCallingAnotherExtension#Callers.StreamCallers.ext.CopyAndDrainAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/ExtensionMethodTests.CSharp_14_ExtensionCallingAnotherExtension#Callers.StreamCallers.ext.CopyAndDrainAsync.g.verified.cs index 50c07d8..e52af22 100644 --- a/tests/Generator.Tests/Snapshots/ExtensionMethodTests.CSharp_14_ExtensionCallingAnotherExtension#Callers.StreamCallers.ext.CopyAndDrainAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/ExtensionMethodTests.CSharp_14_ExtensionCallingAnotherExtension#Callers.StreamCallers.ext.CopyAndDrainAsync.g.verified.cs @@ -3,6 +3,8 @@ #nullable enable namespace Callers { + using Helpers; + public static partial class StreamCallers { extension(global::System.IO.Stream stream) diff --git a/tests/Generator.Tests/Snapshots/ExtensionMethodTests.CSharp_14_ExtensionUnwrapsOntoOneLine#Callers.StreamCallers.ext.DrainTwiceAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/ExtensionMethodTests.CSharp_14_ExtensionUnwrapsOntoOneLine#Callers.StreamCallers.ext.DrainTwiceAsync.g.verified.cs index 6149c8d..1b475ad 100644 --- a/tests/Generator.Tests/Snapshots/ExtensionMethodTests.CSharp_14_ExtensionUnwrapsOntoOneLine#Callers.StreamCallers.ext.DrainTwiceAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/ExtensionMethodTests.CSharp_14_ExtensionUnwrapsOntoOneLine#Callers.StreamCallers.ext.DrainTwiceAsync.g.verified.cs @@ -3,6 +3,8 @@ #nullable enable namespace Callers { + using Helpers; + public static partial class StreamCallers { extension(global::System.IO.Stream stream) diff --git a/tests/Generator.Tests/Snapshots/ExtensionMethodTests.EntityFrameworkQueryableExtensions#Zomp.SyncMethodGenerator.IntegrationTests.EntityFrameworkQuery_0f26cde8.QueryableExtensionAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/ExtensionMethodTests.EntityFrameworkQueryableExtensions#Zomp.SyncMethodGenerator.IntegrationTests.EntityFrameworkQuery_0f26cde8.QueryableExtensionAsync.g.verified.cs index 2377bed..fe5a317 100644 --- a/tests/Generator.Tests/Snapshots/ExtensionMethodTests.EntityFrameworkQueryableExtensions#Zomp.SyncMethodGenerator.IntegrationTests.EntityFrameworkQuery_0f26cde8.QueryableExtensionAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/ExtensionMethodTests.EntityFrameworkQueryableExtensions#Zomp.SyncMethodGenerator.IntegrationTests.EntityFrameworkQuery_0f26cde8.QueryableExtensionAsync.g.verified.cs @@ -1,8 +1,14 @@ //HintName: Zomp.SyncMethodGenerator.IntegrationTests.EntityFrameworkQuery_0f26cde8.QueryableExtensionAsync.g.cs // #nullable enable + +using System.Threading; +using System.Threading.Tasks; + namespace Zomp.SyncMethodGenerator.IntegrationTests { + using Microsoft.EntityFrameworkCore; + public partial class EntityFrameworkQueryableExtensions { public int QueryableExtension(global::Microsoft.EntityFrameworkCore.DbContext dbContext) diff --git a/tests/Generator.Tests/Snapshots/ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGeneric2ExtensionAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGeneric2ExtensionAsync.g.verified.cs index 16675a6..52b17d6 100644 --- a/tests/Generator.Tests/Snapshots/ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGeneric2ExtensionAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGeneric2ExtensionAsync.g.verified.cs @@ -1,13 +1,20 @@ -//HintName: Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGeneric2ExtensionAsync.g.cs -// -#nullable enable -namespace Zomp.SyncMethodGenerator.IntegrationTests -{ - partial class Extensions - { - public static void HasGeneric2Extension(object o) - { - var z = global::Extensi.ons123.MyExtensionClass.TryGetValue(o, out var _, out var _1); - } - } -} +//HintName: Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGeneric2ExtensionAsync.g.cs +// +#nullable enable + +using System.Drawing; +using System.Threading; +using System.Threading.Tasks; + +namespace Zomp.SyncMethodGenerator.IntegrationTests +{ + using Extensi.ons123; + + partial class Extensions + { + public static void HasGeneric2Extension(object o) + { + var z = global::Extensi.ons123.MyExtensionClass.TryGetValue(o, out var _, out var _1); + } + } +} diff --git a/tests/Generator.Tests/Snapshots/ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGenericExtensionAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGenericExtensionAsync.g.verified.cs index 86fde87..1cb1e58 100644 --- a/tests/Generator.Tests/Snapshots/ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGenericExtensionAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/ExtensionMethodTests.UnwrapGenericExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGenericExtensionAsync.g.verified.cs @@ -1,13 +1,20 @@ -//HintName: Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGenericExtensionAsync.g.cs -// -#nullable enable -namespace Zomp.SyncMethodGenerator.IntegrationTests -{ - partial class Extensions - { - public static void HasGenericExtension(object o) - { - var z = global::Extensi.ons123.MyExtensionClass.TryGetValue(o, out var item); - } - } -} +//HintName: Zomp.SyncMethodGenerator.IntegrationTests.Extensions.HasGenericExtensionAsync.g.cs +// +#nullable enable + +using System.Drawing; +using System.Threading; +using System.Threading.Tasks; + +namespace Zomp.SyncMethodGenerator.IntegrationTests +{ + using Extensi.ons123; + + partial class Extensions + { + public static void HasGenericExtension(object o) + { + var z = global::Extensi.ons123.MyExtensionClass.TryGetValue(o, out var item); + } + } +} diff --git a/tests/Generator.Tests/Snapshots/MemoryTests.NonPredefinedTypes#N1.Class.FillAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/MemoryTests.NonPredefinedTypes#N1.Class.FillAsync.g.verified.cs index 450c3c8..6beaa27 100644 --- a/tests/Generator.Tests/Snapshots/MemoryTests.NonPredefinedTypes#N1.Class.FillAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/MemoryTests.NonPredefinedTypes#N1.Class.FillAsync.g.verified.cs @@ -1,14 +1,18 @@ -//HintName: N1.Class.FillAsync.g.cs -// -#nullable enable -namespace N1 -{ - partial class Class - { - void Fill(global::System.Span accelerometers) - { - global::N2.C1.C2.Accelerometer a = new(1, 2, 3); - accelerometers[0] = a; - } - } -} +//HintName: N1.Class.FillAsync.g.cs +// +#nullable enable + +using N2; +using static N2.C1; + +namespace N1 +{ + partial class Class + { + void Fill(global::System.Span accelerometers) + { + global::N2.C1.C2.Accelerometer a = new(1, 2, 3); + accelerometers[0] = a; + } + } +} diff --git a/tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.ConfiguredCancelableAsyncEnumerableExtensionUsingStatic#Test.Extensions.GetConfiguredAsyncEnumerator.g.verified.cs b/tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.ConfiguredCancelableAsyncEnumerableExtensionUsingStatic#Test.Extensions.GetConfiguredAsyncEnumerator.g.verified.cs index 468c0bc..d15b9fb 100644 --- a/tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.ConfiguredCancelableAsyncEnumerableExtensionUsingStatic#Test.Extensions.GetConfiguredAsyncEnumerator.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/SystemAsyncExtensionsTests.ConfiguredCancelableAsyncEnumerableExtensionUsingStatic#Test.Extensions.GetConfiguredAsyncEnumerator.g.verified.cs @@ -1,11 +1,14 @@ -//HintName: Test.Extensions.GetConfiguredAsyncEnumerator.g.cs -// -#nullable enable -namespace Test; -internal static partial class Extensions -{ - public static System.Collections.Generic.IEnumerator GetConfiguredEnumerator(global::System.Collections.Generic.IEnumerable enumerable) - { - return enumerable.GetEnumerator(); - } -} +//HintName: Test.Extensions.GetConfiguredAsyncEnumerator.g.cs +// +#nullable enable + +using static System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable; + +namespace Test; +internal static partial class Extensions +{ + public static System.Collections.Generic.IEnumerator GetConfiguredEnumerator(global::System.Collections.Generic.IEnumerable enumerable) + { + return enumerable.GetEnumerator(); + } +} diff --git a/tests/Generator.Tests/Snapshots/TypeTests.EnumPattern#g.verified.cs b/tests/Generator.Tests/Snapshots/TypeTests.EnumPattern#g.verified.cs index 1d96052..3f3f147 100644 --- a/tests/Generator.Tests/Snapshots/TypeTests.EnumPattern#g.verified.cs +++ b/tests/Generator.Tests/Snapshots/TypeTests.EnumPattern#g.verified.cs @@ -1,2 +1,14 @@ //HintName: Test.Class.MethodAsync.g.cs -_ = global::System.Data.ConnectionState.Closed is global::System.Data.ConnectionState.Closed; +// +#nullable enable + +using static System.Data.ConnectionState; + +namespace Test; +partial class Class +{ + public void Method() + { + _ = global::System.Data.ConnectionState.Closed is global::System.Data.ConnectionState.Closed; + } +} diff --git a/tests/Generator.Tests/Snapshots/UnitTests.DropReturnsDocumentationWhenNothingIsReturned#CountAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/UnitTests.DropReturnsDocumentationWhenNothingIsReturned#CountAsync.g.verified.cs new file mode 100644 index 0000000..d8f04fe --- /dev/null +++ b/tests/Generator.Tests/Snapshots/UnitTests.DropReturnsDocumentationWhenNothingIsReturned#CountAsync.g.verified.cs @@ -0,0 +1,11 @@ +//HintName: Test.Class.CountAsync.g.cs +/// +/// Counts the values. +/// +/// Where to read from. +/// A whose result is the number of values. +public int Count(global::System.IO.Stream input) +{ + input.Flush(); + return 0; +} diff --git a/tests/Generator.Tests/Snapshots/UnitTests.DropReturnsDocumentationWhenNothingIsReturned#ReadAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/UnitTests.DropReturnsDocumentationWhenNothingIsReturned#ReadAsync.g.verified.cs new file mode 100644 index 0000000..118b784 --- /dev/null +++ b/tests/Generator.Tests/Snapshots/UnitTests.DropReturnsDocumentationWhenNothingIsReturned#ReadAsync.g.verified.cs @@ -0,0 +1,7 @@ +//HintName: Test.Class.ReadAsync.g.cs +/// +/// Reads a value. +/// +/// Where to read from. +public void Read(global::System.IO.Stream input) + => input.Flush(); diff --git a/tests/Generator.Tests/Snapshots/UnitTests.GenericTypeInDeclarationPattern#M.B.DoSomethingAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/UnitTests.GenericTypeInDeclarationPattern#M.B.DoSomethingAsync.g.verified.cs index cbd7124..ec8cd27 100644 --- a/tests/Generator.Tests/Snapshots/UnitTests.GenericTypeInDeclarationPattern#M.B.DoSomethingAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/UnitTests.GenericTypeInDeclarationPattern#M.B.DoSomethingAsync.g.verified.cs @@ -3,6 +3,8 @@ #nullable enable namespace M { + using N; + public partial class B { public void DoSomething(object arg) diff --git a/tests/Generator.Tests/Snapshots/UnitTests.GenericTypeInTypeOfExpression#M.B.DoSomethingAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/UnitTests.GenericTypeInTypeOfExpression#M.B.DoSomethingAsync.g.verified.cs index 1c8ff6b..9e3779c 100644 --- a/tests/Generator.Tests/Snapshots/UnitTests.GenericTypeInTypeOfExpression#M.B.DoSomethingAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/UnitTests.GenericTypeInTypeOfExpression#M.B.DoSomethingAsync.g.verified.cs @@ -3,6 +3,8 @@ #nullable enable namespace M { + using N; + public partial class B { public void DoSomething() diff --git a/tests/Generator.Tests/Snapshots/UnitTests.HandleAttribute#ReadSomeBytesAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/UnitTests.HandleAttribute#ReadSomeBytesAsync.g.verified.cs index 7a40f2c..108284f 100644 --- a/tests/Generator.Tests/Snapshots/UnitTests.HandleAttribute#ReadSomeBytesAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/UnitTests.HandleAttribute#ReadSomeBytesAsync.g.verified.cs @@ -1,12 +1,15 @@ -//HintName: Test.Class.ReadSomeBytesAsync.g.cs -// -#nullable enable -namespace Test; -public partial class Class -{ - public int ReadSomeBytes(global::System.IO.Stream stream) - { - var buffer = new byte[100]; - return stream.Read(buffer, 0, 100); - } -} +//HintName: Test.Class.ReadSomeBytesAsync.g.cs +// +#nullable enable + +using System.Diagnostics.CodeAnalysis; + +namespace Test; +public partial class Class +{ + public int ReadSomeBytes(global::System.IO.Stream stream) + { + var buffer = new byte[100]; + return stream.Read(buffer, 0, 100); + } +} diff --git a/tests/Generator.Tests/Snapshots/UnitTests.KeepUsingsSoDocumentationCrefsResolve#SendAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/UnitTests.KeepUsingsSoDocumentationCrefsResolve#SendAsync.g.verified.cs new file mode 100644 index 0000000..d6d7e58 --- /dev/null +++ b/tests/Generator.Tests/Snapshots/UnitTests.KeepUsingsSoDocumentationCrefsResolve#SendAsync.g.verified.cs @@ -0,0 +1,20 @@ +//HintName: Test.Class.SendAsync.g.cs +// +#nullable enable + +using System.Text; + +namespace Test +{ + using System.Net.Sockets; + + public partial class Class + { + /// + /// Sends a over a . + /// + /// Where to read from. + public void Send(global::System.IO.Stream input) + => input.Flush(); + } +} diff --git a/tests/Generator.Tests/Snapshots/UnitTests.Preprocessor#WrappedAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/UnitTests.Preprocessor#WrappedAsync.g.verified.cs index 4cbb8ab..7572de3 100644 --- a/tests/Generator.Tests/Snapshots/UnitTests.Preprocessor#WrappedAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/UnitTests.Preprocessor#WrappedAsync.g.verified.cs @@ -1,11 +1,15 @@ -//HintName: Test.Class.WrappedAsync.g.cs -// -#nullable enable -namespace Test; -public partial class Class -{ - /// - /// A summary - /// - public void Wrapped() { } -} +//HintName: Test.Class.WrappedAsync.g.cs +// +#nullable enable + +using System.Threading; +using System.Threading.Tasks; + +namespace Test; +public partial class Class +{ + /// + /// A summary + /// + public void Wrapped() { } +} diff --git a/tests/Generator.Tests/Snapshots/UnitTests.StaticUsings#N1.C1.MethodAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/UnitTests.StaticUsings#N1.C1.MethodAsync.g.verified.cs index b0e977c..a1f40f5 100644 --- a/tests/Generator.Tests/Snapshots/UnitTests.StaticUsings#N1.C1.MethodAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/UnitTests.StaticUsings#N1.C1.MethodAsync.g.verified.cs @@ -1,13 +1,16 @@ -//HintName: N1.C1.MethodAsync.g.cs -// -#nullable enable -namespace N1 -{ - public partial class C1 - { - public void Method() - { - _ = global::N2.C2.OtherConst; - } - } -} +//HintName: N1.C1.MethodAsync.g.cs +// +#nullable enable + +using static N2.C2; + +namespace N1 +{ + public partial class C1 + { + public void Method() + { + _ = global::N2.C2.OtherConst; + } + } +} diff --git a/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.OneParamsAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.OneParamsAsync.g.verified.cs index 05d3421..87493f6 100644 --- a/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.OneParamsAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.OneParamsAsync.g.verified.cs @@ -1,10 +1,16 @@ -//HintName: Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.OneParamsAsync.g.cs -// -#nullable enable -namespace Zomp.SyncMethodGenerator.IntegrationTests -{ - partial class ExtensionMethods - { - public static void OneParams(object o, string s) => global::Extensi.ons123.MyExtensionClass.SomeMethod(o, s); - } -} +//HintName: Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.OneParamsAsync.g.cs +// +#nullable enable + +using System.Threading; +using System.Threading.Tasks; + +namespace Zomp.SyncMethodGenerator.IntegrationTests +{ + using Extensi.ons123; + + partial class ExtensionMethods + { + public static void OneParams(object o, string s) => global::Extensi.ons123.MyExtensionClass.SomeMethod(o, s); + } +} diff --git a/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.TwoParamsAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.TwoParamsAsync.g.verified.cs index 0d91e8e..7f5f080 100644 --- a/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.TwoParamsAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.TwoParamsAsync.g.verified.cs @@ -1,10 +1,16 @@ -//HintName: Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.TwoParamsAsync.g.cs -// -#nullable enable -namespace Zomp.SyncMethodGenerator.IntegrationTests -{ - partial class ExtensionMethods - { - public static void TwoParams(object o, string s, int i) => global::Extensi.ons123.MyExtensionClass.SomeMethod(o, s, i); - } -} +//HintName: Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.TwoParamsAsync.g.cs +// +#nullable enable + +using System.Threading; +using System.Threading.Tasks; + +namespace Zomp.SyncMethodGenerator.IntegrationTests +{ + using Extensi.ons123; + + partial class ExtensionMethods + { + public static void TwoParams(object o, string s, int i) => global::Extensi.ons123.MyExtensionClass.SomeMethod(o, s, i); + } +} diff --git a/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.ZeroParamsAsync.g.verified.cs b/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.ZeroParamsAsync.g.verified.cs index 01feca1..ab68f68 100644 --- a/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.ZeroParamsAsync.g.verified.cs +++ b/tests/Generator.Tests/Snapshots/UnitTests.UnwrapExtensionMethod#Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.ZeroParamsAsync.g.verified.cs @@ -1,10 +1,16 @@ -//HintName: Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.ZeroParamsAsync.g.cs -// -#nullable enable -namespace Zomp.SyncMethodGenerator.IntegrationTests -{ - partial class ExtensionMethods - { - public static void ZeroParams(object o) => global::Extensi.ons123.MyExtensionClass.SomeMethod(o); - } -} +//HintName: Zomp.SyncMethodGenerator.IntegrationTests.ExtensionMethods.ZeroParamsAsync.g.cs +// +#nullable enable + +using System.Threading; +using System.Threading.Tasks; + +namespace Zomp.SyncMethodGenerator.IntegrationTests +{ + using Extensi.ons123; + + partial class ExtensionMethods + { + public static void ZeroParams(object o) => global::Extensi.ons123.MyExtensionClass.SomeMethod(o); + } +} diff --git a/tests/Generator.Tests/UnitTests.cs b/tests/Generator.Tests/UnitTests.cs index a335e80..326fdb6 100644 --- a/tests/Generator.Tests/UnitTests.cs +++ b/tests/Generator.Tests/UnitTests.cs @@ -853,6 +853,63 @@ public async Task ReadAsync(Stream input, CancellationToken cancellationToken = } """.Verify(sourceType: SourceType.Full, documentationMode: DocumentationMode.None); + /// + /// A cref is resolved against the file it lands in, so the generated file needs the using + /// directives which were in scope where the documentation was written. Without them a + /// project building with warnings as errors fails on CS1574. + /// + /// A task. + [Fact] + public Task KeepUsingsSoDocumentationCrefsResolve() => """ +using System.Text; + +namespace Test +{ + using System.Net.Sockets; + + public partial class Class + { + /// + /// Sends a over a . + /// + /// Where to read from. + /// Cancellation token. + [Zomp.SyncMethodGenerator.CreateSyncVersion] + public async Task SendAsync(Stream input, CancellationToken cancellationToken = default) + => await input.FlushAsync(cancellationToken); + } +} +""".Verify(sourceType: SourceType.Full); + + /// + /// The task a method returned is not returned by its synchronized version, so documentation + /// describing that task describes nothing. Documentation of a value which survives stays. + /// + /// A task. + [Fact] + public Task DropReturnsDocumentationWhenNothingIsReturned() => """ +/// +/// Reads a value. +/// +/// Where to read from. +/// A that represents the asynchronous read. +[Zomp.SyncMethodGenerator.CreateSyncVersion] +public async Task ReadAsync(Stream input) + => await input.FlushAsync(); + +/// +/// Counts the values. +/// +/// Where to read from. +/// A whose result is the number of values. +[Zomp.SyncMethodGenerator.CreateSyncVersion] +public async Task CountAsync(Stream input) +{ + await input.FlushAsync(); + return 0; +} +""".Verify(); + [Fact] public Task VerifyParamHandling() => $$""" static byte[] HelperMethod(params int[] myParams) => null;