diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index fa1806ee4..8c1faff17 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -23,15 +23,22 @@ jobs: runs-on: windows-latest strategy: matrix: - dotnet: ['net48', 'net6.0', 'net7.0', 'net8.0'] + dotnet: ['net48', 'net8.0', 'net9.0'] steps: - name: Checkout uses: actions/checkout@v4 + - + name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 8.0.x + 9.0.x - name: Run tests - run: dotnet test -f ${{ matrix.dotnet }} + run: dotnet test -c Debug -f ${{ matrix.dotnet }} - name: Upload Test Results if: always() @@ -47,12 +54,19 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - dotnet: ['net6.0', 'net7.0', 'net8.0'] + dotnet: ['net8.0', 'net9.0'] steps: - name: Checkout uses: actions/checkout@v4 + - + name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 8.0.x + 9.0.x - name: Run tests run: dotnet test -f ${{ matrix.dotnet }} diff --git a/Directory.Packages.props b/Directory.Packages.props index 61c85f4c3..ed1fd4b2e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,49 +1,46 @@ - - true - - - [6.0.28,7) - - - 7.0.17 - - - 8.0.3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + true + + + 8.0.3 + + + 9.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/benchmarks/RestSharp.Benchmarks/RestSharp.Benchmarks.csproj b/benchmarks/RestSharp.Benchmarks/RestSharp.Benchmarks.csproj index f60295a8f..3d939e0fb 100644 --- a/benchmarks/RestSharp.Benchmarks/RestSharp.Benchmarks.csproj +++ b/benchmarks/RestSharp.Benchmarks/RestSharp.Benchmarks.csproj @@ -1,7 +1,7 @@ Exe - net7.0 + net9.0 false preview enable diff --git a/gen/SourceGenerator/Extensions.cs b/gen/SourceGenerator/Extensions.cs index 12daff3e6..f529412a1 100644 --- a/gen/SourceGenerator/Extensions.cs +++ b/gen/SourceGenerator/Extensions.cs @@ -21,7 +21,7 @@ public static IEnumerable FindClasses(this Compilation c .SelectMany(model => model.SyntaxTree.GetRoot().DescendantNodes().OfType()) .Where(predicate); - public static IEnumerable FindAnnotatedClass(this Compilation compilation, string attributeName, bool strict) { + public static IEnumerable FindAnnotatedClasses(this Compilation compilation, string attributeName, bool strict) { return compilation.FindClasses( syntax => syntax.AttributeLists.Any(list => list.Attributes.Any(CheckAttribute)) ); diff --git a/gen/SourceGenerator/ImmutableGenerator.cs b/gen/SourceGenerator/ImmutableGenerator.cs index 7576359bd..e0860bd67 100644 --- a/gen/SourceGenerator/ImmutableGenerator.cs +++ b/gen/SourceGenerator/ImmutableGenerator.cs @@ -15,18 +15,28 @@ namespace SourceGenerator; -[Generator] -public class ImmutableGenerator : ISourceGenerator { - public void Initialize(GeneratorInitializationContext context) { } - - public void Execute(GeneratorExecutionContext context) { - var compilation = context.Compilation; +[Generator(LanguageNames.CSharp)] +public class ImmutableGenerator : IIncrementalGenerator { + public void Initialize(IncrementalGeneratorInitializationContext context) { + var c = context.CompilationProvider.SelectMany((x, _) => GetImmutableClasses(x)); + + context.RegisterSourceOutput( + c.Collect(), + static (ctx, sources) => { + foreach (var source in sources) { + ctx.AddSource(source.Item1, source.Item2); + } + } + ); + return; - var mutableClasses = compilation.FindAnnotatedClass("GenerateImmutable", strict: true); + IEnumerable<(string, SourceText)> GetImmutableClasses(Compilation compilation) { + var mutableClasses = compilation.FindAnnotatedClasses("GenerateImmutable", strict: true); - foreach (var mutableClass in mutableClasses) { - var immutableClass = GenerateImmutableClass(mutableClass, compilation); - context.AddSource($"ReadOnly{mutableClass.Identifier.Text}.cs", SourceText.From(immutableClass, Encoding.UTF8)); + foreach (var mutableClass in mutableClasses) { + var immutableClass = GenerateImmutableClass(mutableClass, compilation); + yield return ($"ReadOnly{mutableClass.Identifier.Text}.cs", SourceText.From(immutableClass, Encoding.UTF8)); + } } } diff --git a/gen/SourceGenerator/InheritedCloneGenerator.cs b/gen/SourceGenerator/InheritedCloneGenerator.cs index 2bc635443..76b81911e 100644 --- a/gen/SourceGenerator/InheritedCloneGenerator.cs +++ b/gen/SourceGenerator/InheritedCloneGenerator.cs @@ -14,37 +14,44 @@ namespace SourceGenerator; -[Generator] -public class InheritedCloneGenerator : ISourceGenerator { +[Generator(LanguageNames.CSharp)] +public class InheritedCloneGenerator : IIncrementalGenerator { const string AttributeName = "GenerateClone"; - public void Initialize(GeneratorInitializationContext context) { } - - public void Execute(GeneratorExecutionContext context) { - var compilation = context.Compilation; - - var candidates = compilation.FindAnnotatedClass(AttributeName, false); - - foreach (var candidate in candidates) { - var semanticModel = compilation.GetSemanticModel(candidate.SyntaxTree); - var genericClassSymbol = semanticModel.GetDeclaredSymbol(candidate); - if (genericClassSymbol == null) continue; - - // Get the method name from the attribute Name argument - var attributeData = genericClassSymbol.GetAttributes().FirstOrDefault(a => a.AttributeClass?.Name == $"{AttributeName}Attribute"); - var methodName = (string)attributeData.NamedArguments.FirstOrDefault(arg => arg.Key == "Name").Value.Value; - - // Get the generic argument type where properties need to be copied from - var attributeSyntax = candidate.AttributeLists - .SelectMany(l => l.Attributes) - .FirstOrDefault(a => a.Name.ToString().StartsWith(AttributeName)); - if (attributeSyntax == null) continue; // This should never happen - - var typeArgumentSyntax = ((GenericNameSyntax)attributeSyntax.Name).TypeArgumentList.Arguments[0]; - var typeSymbol = (INamedTypeSymbol)semanticModel.GetSymbolInfo(typeArgumentSyntax).Symbol; - - var code = GenerateMethod(candidate, genericClassSymbol, typeSymbol, methodName); - context.AddSource($"{genericClassSymbol.Name}.Clone.g.cs", SourceText.From(code, Encoding.UTF8)); + public void Initialize(IncrementalGeneratorInitializationContext context) { + var c = context.CompilationProvider.SelectMany((x, _) => GetClones(x)); + + context.RegisterSourceOutput( + c.Collect(), + static (ctx, sources) => { + foreach (var source in sources) { + ctx.AddSource(source.Item1, source.Item2); + } + } + ); + return; + + IEnumerable<(string, SourceText)> GetClones(Compilation compilation) { + var candidates = compilation.FindAnnotatedClasses(AttributeName, false); + + foreach (var candidate in candidates) { + var semanticModel = compilation.GetSemanticModel(candidate.SyntaxTree); + var genericClassSymbol = semanticModel.GetDeclaredSymbol(candidate); + if (genericClassSymbol == null) continue; + + var attributeData = genericClassSymbol.GetAttributes().FirstOrDefault(a => a.AttributeClass?.Name == $"{AttributeName}Attribute"); + var methodName = (string)attributeData.NamedArguments.FirstOrDefault(arg => arg.Key == "Name").Value.Value; + var baseType = attributeData.NamedArguments.FirstOrDefault(arg => arg.Key == "BaseType").Value.Value; + + // Get the generic argument type where properties need to be copied from + var attributeSyntax = candidate.AttributeLists + .SelectMany(l => l.Attributes) + .FirstOrDefault(a => a.Name.ToString().StartsWith(AttributeName)); + if (attributeSyntax == null) continue; // This should never happen + + var code = GenerateMethod(candidate, genericClassSymbol, (INamedTypeSymbol)baseType, methodName); + yield return ($"{genericClassSymbol.Name}.Clone.g.cs", SourceText.From(code, Encoding.UTF8)); + } } } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 70ef2495c..85288d985 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,7 +1,7 @@ - netstandard2.0;net471;net48;net6.0;net7.0;net8.0 + netstandard2.0;net471;net48;net8.0;net9.0 restsharp.png Apache-2.0 https://restsharp.dev diff --git a/src/RestSharp/Authenticators/OAuth/OAuthTools.cs b/src/RestSharp/Authenticators/OAuth/OAuthTools.cs index e8cf4102a..4c70eab8e 100644 --- a/src/RestSharp/Authenticators/OAuth/OAuthTools.cs +++ b/src/RestSharp/Authenticators/OAuth/OAuthTools.cs @@ -83,12 +83,6 @@ public static string GetNonce() { /// /// The value to escape. /// The escaped value. - /// - /// The method is supposed to take on - /// RFC 3986 behavior if certain elements are present in a .config file. Even if this - /// actually worked (which in my experiments it doesn't), we can't rely on every - /// host actually having this configuration element present. - /// [return: NotNullIfNotNull(nameof(value))] public static string? UrlEncodeRelaxed(string? value) { if (value == null) return null; diff --git a/src/RestSharp/Extensions/GenerateImmutableAttribute.cs b/src/RestSharp/Extensions/GenerateImmutableAttribute.cs index 172d7c24e..1cafdb049 100644 --- a/src/RestSharp/Extensions/GenerateImmutableAttribute.cs +++ b/src/RestSharp/Extensions/GenerateImmutableAttribute.cs @@ -19,8 +19,9 @@ namespace RestSharp.Extensions; class GenerateImmutableAttribute : Attribute; [AttributeUsage(AttributeTargets.Class)] -class GenerateCloneAttribute : Attribute where T : class { - public string? Name { get; set; } +class GenerateCloneAttribute : Attribute { + public Type? BaseType { get; set; } + public string? Name { get; set; } }; [AttributeUsage(AttributeTargets.Property)] diff --git a/src/RestSharp/Options/RestClientOptions.cs b/src/RestSharp/Options/RestClientOptions.cs index 74fde4ef0..96ebf9df1 100644 --- a/src/RestSharp/Options/RestClientOptions.cs +++ b/src/RestSharp/Options/RestClientOptions.cs @@ -181,16 +181,6 @@ public RestClientOptions(string baseUrl) : this(new Uri(Ensure.NotEmptyString(ba /// public CookieContainer? CookieContainer { get; set; } - /// - /// Maximum request duration in milliseconds. When the request timeout is specified using , - /// the lowest value between the client timeout and request timeout will be used. - /// - [Obsolete("Use Timeout instead.")] - public int MaxTimeout { - get => (int) (Timeout?.TotalMilliseconds ?? 0); - set => Timeout = TimeSpan.FromMilliseconds(value); - } - /// /// Request duration. Used when the request timeout is not specified using , /// diff --git a/src/RestSharp/Response/RestResponse.cs b/src/RestSharp/Response/RestResponse.cs index dc48f2ddc..62b5d569a 100644 --- a/src/RestSharp/Response/RestResponse.cs +++ b/src/RestSharp/Response/RestResponse.cs @@ -24,7 +24,7 @@ namespace RestSharp; /// Container for data sent back from API including deserialized data /// /// Type of data to deserialize to -[GenerateClone(Name = "FromResponse")] +[GenerateClone(BaseType = typeof(RestResponse), Name = "FromResponse")] [DebuggerDisplay($"{{{nameof(DebuggerDisplay)}()}}")] public partial class RestResponse(RestRequest request) : RestResponse(request) { /// diff --git a/src/RestSharp/RestSharp.csproj b/src/RestSharp/RestSharp.csproj index d01835924..5643d4c02 100644 --- a/src/RestSharp/RestSharp.csproj +++ b/src/RestSharp/RestSharp.csproj @@ -12,9 +12,6 @@ - - - RestClient.Extensions.cs @@ -63,12 +60,21 @@ - + - + - + + + + + + + + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 9ad7f24e7..b3c32f6d1 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -3,7 +3,7 @@ true false - net48;net6.0;net7.0;net8.0 + net48;net8.0;net9.0 disable xUnit1033 trx%3bLogFileName=$(MSBuildProjectName).trx diff --git a/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj b/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj index 36f53edc9..75c24e34a 100644 --- a/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj +++ b/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj @@ -2,7 +2,7 @@ Exe false - net6.0 + net9.0