diff --git a/Funcky.Async/Funcky.Async.csproj b/Funcky.Async/Funcky.Async.csproj
index 242e2e5e..361db122 100644
--- a/Funcky.Async/Funcky.Async.csproj
+++ b/Funcky.Async/Funcky.Async.csproj
@@ -12,6 +12,7 @@
true
All
+ true
$(NoWarn);RS0026
diff --git a/Funcky.SourceGenerator.Test/OrNoneGeneratorSnapshotTests.CopiesStringSyntaxAttributeFromOriginalDefinition.00.verified.cs b/Funcky.SourceGenerator.Test/OrNoneGeneratorSnapshotTests.CopiesStringSyntaxAttributeFromOriginalDefinition.00.verified.cs
new file mode 100644
index 00000000..57e7b2e4
--- /dev/null
+++ b/Funcky.SourceGenerator.Test/OrNoneGeneratorSnapshotTests.CopiesStringSyntaxAttributeFromOriginalDefinition.00.verified.cs
@@ -0,0 +1,12 @@
+//HintName: .g.cs
+//
+#nullable enable
+
+namespace Funcky.Extensions
+{
+ public static partial class ParseExtensions
+ {
+ [global::System.Diagnostics.Contracts.Pure]
+ public static Funcky.Monads.Option ParseTargetOrNone(this string candidate, [global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("foo")] string format) => global::Funcky.Extensions.Target.TryParse(candidate, format, out var result) ? result : default(Funcky.Monads.Option);
+ }
+}
\ No newline at end of file
diff --git a/Funcky.SourceGenerator.Test/OrNoneGeneratorSnapshotTests.CopiesStringSyntaxAttributeFromOriginalDefinition.01.verified.cs b/Funcky.SourceGenerator.Test/OrNoneGeneratorSnapshotTests.CopiesStringSyntaxAttributeFromOriginalDefinition.01.verified.cs
new file mode 100644
index 00000000..524f7293
--- /dev/null
+++ b/Funcky.SourceGenerator.Test/OrNoneGeneratorSnapshotTests.CopiesStringSyntaxAttributeFromOriginalDefinition.01.verified.cs
@@ -0,0 +1,15 @@
+//HintName: OrNoneFromTryPatternAttribute.g.cs
+namespace Funcky.Internal
+{
+ [global::System.Diagnostics.Conditional("COMPILE_TIME_ONLY")]
+ [global::System.AttributeUsage(global::System.AttributeTargets.Class, AllowMultiple = true)]
+ internal class OrNoneFromTryPatternAttribute : global::System.Attribute
+ {
+ public OrNoneFromTryPatternAttribute(global::System.Type type, string method)
+ => (Type, Method) = (type, method);
+
+ public global::System.Type Type { get; }
+
+ public string Method { get; }
+ }
+}
\ No newline at end of file
diff --git a/Funcky.SourceGenerator.Test/OrNoneGeneratorSnapshotTests.cs b/Funcky.SourceGenerator.Test/OrNoneGeneratorSnapshotTests.cs
index 5900f1f2..364e2e6e 100644
--- a/Funcky.SourceGenerator.Test/OrNoneGeneratorSnapshotTests.cs
+++ b/Funcky.SourceGenerator.Test/OrNoneGeneratorSnapshotTests.cs
@@ -183,4 +183,35 @@ public static bool TryParseExact(string candidate, out Target result)
return TestHelper.Verify(source + Environment.NewLine + OptionSource);
}
+
+ [Fact]
+ public Task CopiesStringSyntaxAttributeFromOriginalDefinition()
+ {
+ const string source = """
+ #nullable enable
+
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+ using Funcky.Internal;
+
+ namespace Funcky.Extensions
+ {
+ [OrNoneFromTryPattern(typeof(Target), nameof(Target.TryParse))]
+ public static partial class ParseExtensions
+ {
+ }
+
+ public sealed class Target
+ {
+ public static bool TryParse(string candidate, [StringSyntaxAttribute("foo")] string format, out Target result)
+ {
+ result = default!;
+ return false;
+ }
+ }
+ }
+ """;
+
+ return TestHelper.Verify(source + Environment.NewLine + OptionSource);
+ }
}
diff --git a/Funcky.SourceGenerator/OrNoneFromTryPatternGenerator.cs b/Funcky.SourceGenerator/OrNoneFromTryPatternGenerator.cs
index c8545624..f48f3427 100644
--- a/Funcky.SourceGenerator/OrNoneFromTryPatternGenerator.cs
+++ b/Funcky.SourceGenerator/OrNoneFromTryPatternGenerator.cs
@@ -11,6 +11,7 @@ namespace Funcky.SourceGenerator;
public sealed class OrNoneFromTryPatternGenerator : IIncrementalGenerator
{
private const string AttributeFullName = "Funcky.Internal.OrNoneFromTryPatternAttribute";
+ private const string StringSyntaxAttributeFullName = "System.Diagnostics.CodeAnalysis.StringSyntaxAttribute";
private static readonly IEnumerable GeneratedFileHeadersSource = ImmutableList.Create("// ", "#nullable enable", string.Empty);
public void Initialize(IncrementalGeneratorInitializationContext context)
@@ -127,7 +128,27 @@ private static ParameterSyntax GenerateParameter(IParameterSymbol parameter, int
=> Parameter(Identifier(GetParameterName(parameter, index)))
.WithModifiers(index == 0 ? TokenList(Token(SyntaxKind.ThisKeyword)) : TokenList())
.WithType(GenerateTypeSyntax(parameter.Type))
- .WithDefault(GetParameterDefaultValue(parameter));
+ .WithDefault(GetParameterDefaultValue(parameter))
+ .WithAttributeLists(GenerateParameterAttributeLists(parameter));
+
+ private static SyntaxList GenerateParameterAttributeLists(IParameterSymbol parameter)
+ => GenerateParameterAttributes(parameter).ToImmutableArray() is { Length: >0 } attributes
+ ? SingletonList(AttributeList(SeparatedList(attributes)))
+ : List();
+
+ private static IEnumerable GenerateParameterAttributes(IParameterSymbol parameter)
+ => parameter.GetAttributes().Where(ShouldCopyParameterAttribute).Select(GenerateParameterAttribute);
+
+ private static AttributeSyntax GenerateParameterAttribute(AttributeData originalAttribute)
+ => Attribute(
+ ParseName(GenerateTypeSyntax(originalAttribute.AttributeClass!).ToString()),
+ AttributeArgumentList(SeparatedList(originalAttribute.ConstructorArguments.Select(GenerateAttributeArgument))));
+
+ private static AttributeArgumentSyntax GenerateAttributeArgument(TypedConstant argumentValue)
+ => AttributeArgument(ParseExpression(argumentValue.ToCSharpString()));
+
+ private static bool ShouldCopyParameterAttribute(AttributeData originalAttribute)
+ => originalAttribute.AttributeClass?.ToDisplayString() == StringSyntaxAttributeFullName;
private static TypeSyntax GenerateTypeSyntax(ITypeSymbol type)
{
diff --git a/Funcky.Xunit/Funcky.Xunit.csproj b/Funcky.Xunit/Funcky.Xunit.csproj
index 62af097c..a8fd65ef 100644
--- a/Funcky.Xunit/Funcky.Xunit.csproj
+++ b/Funcky.Xunit/Funcky.Xunit.csproj
@@ -11,6 +11,7 @@
Funcky
+ true
$(NoWarn);NU5104
diff --git a/Funcky/Funcky.csproj b/Funcky/Funcky.csproj
index 3a33b07e..237a31a1 100644
--- a/Funcky/Funcky.csproj
+++ b/Funcky/Funcky.csproj
@@ -1,6 +1,6 @@
- net6.0;net5.0;netcoreapp3.1;netstandard2.0;netstandard2.1
+ net7.0;net6.0;net5.0;netcoreapp3.1;netstandard2.0;netstandard2.1
preview
enable
Funcky
@@ -14,12 +14,13 @@
true
All
+ true
$(DefineConstants);CONTRACTS_FULL
-
+
diff --git a/Funcky/PublicAPI.Unshipped.txt b/Funcky/PublicAPI.Unshipped.txt
index 2dbb3e98..55580012 100644
--- a/Funcky/PublicAPI.Unshipped.txt
+++ b/Funcky/PublicAPI.Unshipped.txt
@@ -4,6 +4,40 @@ Funcky.RequireClass.RequireClass() -> void
Funcky.RequireStruct
Funcky.RequireStruct.RequireStruct() -> void
static Funcky.Extensions.EnumerableExtensions.ElementAtOrNone(this System.Collections.Generic.IEnumerable! source, System.Index index) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseBigIntegerOrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseBigIntegerOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseByteOrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseByteOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseDateOnlyOrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseDateOnlyOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseDateTimeOffsetOrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseDateTimeOffsetOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseDateTimeOrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseDateTimeOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseDecimalOrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseDecimalOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseDoubleOrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseDoubleOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseGuidOrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseGuidOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseInt16OrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseInt16OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseInt32OrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseInt32OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseInt64OrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseInt64OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseSByteOrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseSByteOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseSingleOrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseSingleOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseTimeOnlyOrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseTimeOnlyOrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseUInt16OrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseUInt16OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseUInt32OrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseUInt32OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseUInt64OrNone(this string? candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
+static Funcky.Extensions.ParseExtensions.ParseUInt64OrNone(this System.ReadOnlySpan candidate, System.IFormatProvider? provider) -> Funcky.Monads.Option
static Funcky.Extensions.QueryableExtensions.ElementAtOrNone(this System.Linq.IQueryable! source, int index) -> Funcky.Monads.Option
static Funcky.Extensions.QueryableExtensions.ElementAtOrNone(this System.Linq.IQueryable! source, System.Index index) -> Funcky.Monads.Option
static Funcky.Extensions.StreamExtensions.ReadByteOrNone(this System.IO.Stream! stream) -> Funcky.Monads.Option