Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: restsharp/RestSharp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 111.4.0
Choose a base ref
...
head repository: restsharp/RestSharp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: dev
Choose a head ref
  • 18 commits
  • 42 files changed
  • 7 contributors

Commits on Jul 30, 2024

  1. Allow setting parameter content type (#2249)

    * Allow setting parameter content type
    * Added a test
    * Add docs
    alexeyzimarev authored Jul 30, 2024
    Copy the full SHA
    fef25a5 View commit details
  2. Copy the full SHA
    aa43b68 View commit details
  3. Bump Polly from 8.3.1 to 8.4.1 (#2234)

    Bumps [Polly](https://github.com/App-vNext/Polly) from 8.3.1 to 8.4.1.
    - [Release notes](https://github.com/App-vNext/Polly/releases)
    - [Changelog](https://github.com/App-vNext/Polly/blob/main/CHANGELOG.md)
    - [Commits](App-vNext/Polly@8.3.1...8.4.1)
    
    ---
    updated-dependencies:
    - dependency-name: Polly
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Jul 30, 2024
    Copy the full SHA
    6c596fe View commit details
  4. Correct typo (#2244)

    minhtaile2712 authored Jul 30, 2024
    Copy the full SHA
    8fee05d View commit details
  5. Correct typo (#2246)

    minhtaile2712 authored Jul 30, 2024
    Copy the full SHA
    8758493 View commit details
  6. Bump JetBrains.Annotations from 2023.3.0 to 2024.2.0 (#2237)

    Bumps JetBrains.Annotations from 2023.3.0 to 2024.2.0.
    
    ---
    updated-dependencies:
    - dependency-name: JetBrains.Annotations
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Jul 30, 2024
    Copy the full SHA
    75ccc00 View commit details
  7. Copy the full SHA
    6391624 View commit details

Commits on Aug 27, 2024

  1. Fixed sentence to be easier to read (#2251)

    Fixed a sentence that accidentally used the word "only" twice.
    MrFrawsty authored Aug 27, 2024
    Copy the full SHA
    777bf19 View commit details

Commits on Aug 29, 2024

  1. Copy the full SHA
    7b7950b View commit details
  2. Copy the full SHA
    0fba5e7 View commit details

Commits on Sep 18, 2024

  1. Copy the full SHA
    3cbd7ad View commit details

Commits on Oct 3, 2024

  1. Copy the full SHA
    bf4008f View commit details

Commits on Dec 16, 2024

  1. Bump dawidd6/action-download-artifact from 6 to 7 (#2274)

    Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 6 to 7.
    - [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
    - [Commits](dawidd6/action-download-artifact@bf251b5...80620a5)
    
    ---
    updated-dependencies:
    - dependency-name: dawidd6/action-download-artifact
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Dec 16, 2024
    Copy the full SHA
    ad6af08 View commit details
  2. Upgrade to support .NET 9 (#2275)

    * Upgrade to support .NET 9
    * Update build targets
    alexeyzimarev authored Dec 16, 2024
    Copy the full SHA
    25922ce View commit details

Commits on Dec 17, 2024

  1. Copy the full SHA
    ba2ebac View commit details
  2. Copy the full SHA
    40b9416 View commit details
  3. Copy the full SHA
    d5739bb View commit details
  4. Use .NET 9

    alexeyzimarev committed Dec 17, 2024
    Copy the full SHA
    58180e8 View commit details
Showing with 672 additions and 497 deletions.
  1. +5 −5 .github/workflows/build-dev.yml
  2. +17 −3 .github/workflows/pull-request.yml
  3. +1 −1 .github/workflows/test-results.yml
  4. +44 −47 Directory.Packages.props
  5. +1 −1 benchmarks/RestSharp.Benchmarks/RestSharp.Benchmarks.csproj
  6. +2 −1 docs/docs/usage/client.md
  7. +19 −0 docs/docs/usage/request.md
  8. +2 −2 docs/versioned_docs/version-v111/intro.md
  9. +3 −3 docs/versioned_docs/version-v111/usage/example.md
  10. +1 −1 gen/SourceGenerator/Extensions.cs
  11. +20 −10 gen/SourceGenerator/ImmutableGenerator.cs
  12. +36 −29 gen/SourceGenerator/InheritedCloneGenerator.cs
  13. +1 −1 src/Directory.Build.props
  14. +0 −6 src/RestSharp/Authenticators/OAuth/OAuthTools.cs
  15. +3 −2 src/RestSharp/Extensions/GenerateImmutableAttribute.cs
  16. +0 −10 src/RestSharp/Options/RestClientOptions.cs
  17. +54 −6 src/RestSharp/Parameters/HeaderParameter.cs
  18. +31 −6 src/RestSharp/Parameters/Parameter.cs
  19. +4 −2 src/RestSharp/Parameters/UrlSegmentParameter.cs
  20. +4 −28 src/RestSharp/Request/RestRequestExtensions.Headers.cs
  21. +1 −1 src/RestSharp/Response/RestResponse.cs
  22. +24 −2 src/RestSharp/Response/RestResponseExtensions.cs
  23. +12 −6 src/RestSharp/RestSharp.csproj
  24. +1 −1 test/Directory.Build.props
  25. +1 −1 test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj
  26. +27 −1 test/RestSharp.Tests.Integrated/MultipartFormDataTests.cs
  27. +23 −0 test/RestSharp.Tests/Headers/DefaultHeaderTests.cs
  28. +2 −2 test/RestSharp.Tests/{AddRangeTests.cs → Headers/HeaderRangeTests.cs}
  29. 0 test/RestSharp.Tests/{ → Headers}/HostHeaderTests.cs
  30. +6 −0 test/RestSharp.Tests/{ → Headers}/RequestHeaderTests.cs
  31. +1 −1 test/RestSharp.Tests/{ → Parameters}/ObjectParameterTests.ArrayData.cs
  32. +1 −1 test/RestSharp.Tests/{ → Parameters}/ObjectParameterTests.CsvData.cs
  33. +1 −1 test/RestSharp.Tests/{ → Parameters}/ObjectParameterTests.FormattedData.cs
  34. +1 −1 test/RestSharp.Tests/{ → Parameters}/ObjectParameterTests.NamedData.cs
  35. +1 −1 test/RestSharp.Tests/{ → Parameters}/ObjectParameterTests.cs
  36. +1 −1 test/RestSharp.Tests/{ → Parameters}/ParameterValidationTests.cs
  37. +26 −19 test/RestSharp.Tests/{ParametersTests.cs → Parameters/UrlSegmentTests.cs}
  38. +0 −32 test/RestSharp.Tests/RestClientTests.cs
  39. +4 −10 test/RestSharp.Tests/RestSharp.Tests.csproj
  40. +197 −0 test/RestSharp.Tests/UrlBuilderTests.Get.cs
  41. +60 −0 test/RestSharp.Tests/UrlBuilderTests.Post.cs
  42. +34 −252 test/RestSharp.Tests/UrlBuilderTests.cs
10 changes: 5 additions & 5 deletions .github/workflows/build-dev.yml
Original file line number Diff line number Diff line change
@@ -23,11 +23,11 @@ jobs:
-
name: Checkout
uses: actions/checkout@v4
# -
# name: Setup .NET
# uses: actions/setup-dotnet@v3
# with:
# dotnet-version: '7.0.102'
-
name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
-
name: Unshallow
run: git fetch --prune --unshallow
20 changes: 17 additions & 3 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
@@ -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 }}
2 changes: 1 addition & 1 deletion .github/workflows/test-results.yml
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ jobs:
steps:
-
name: Download and Extract Artifacts
uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11
uses: dawidd6/action-download-artifact@80620a5d27ce0ae443b965134db88467fc607b43
with:
run_id: ${{ github.event.workflow_run.id }}
path: artifacts
91 changes: 44 additions & 47 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,49 +1,46 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<PropertyGroup Label="Package versions for .NET 6" Condition="$(TargetFramework) == 'net6.0'">
<MicrosoftTestHostVer>[6.0.28,7)</MicrosoftTestHostVer>
</PropertyGroup>
<PropertyGroup Label="Package versions for .NET 7" Condition="$(TargetFramework) == 'net7.0'">
<MicrosoftTestHostVer>7.0.17</MicrosoftTestHostVer>
</PropertyGroup>
<PropertyGroup Label="Package versions for .NET 8" Condition="$(TargetFramework) == 'net8.0'">
<MicrosoftTestHostVer>8.0.3</MicrosoftTestHostVer>
</PropertyGroup>
<ItemGroup Label="Runtime dependencies">
<PackageVersion Include="HttpMultipartParser" Version="8.4.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="CsvHelper" Version="33.0.1" />
<PackageVersion Include="PolySharp" Version="1.14.1" />
<PackageVersion Include="System.Text.Json" Version="8.0.4" />
<PackageVersion Include="WireMock.Net" Version="1.5.60" />
<PackageVersion Include="WireMock.Net.FluentAssertions" Version="1.5.51" />
</ItemGroup>
<ItemGroup Label="Compile dependencies">
<PackageVersion Include="BenchmarkDotNet" Version="0.13.12" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="MinVer" Version="5.0.0" />
<PackageVersion Include="Nullable" Version="1.3.1" />
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies.net472" Version="1.0.3" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="JetBrains.Annotations" Version="2024.2.0" />
</ItemGroup>
<ItemGroup Label="Testing dependencies">
<PackageVersion Include="AutoFixture" Version="4.18.1" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
<PackageVersion Include="HttpTracer" Version="2.1.1" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="$(MicrosoftTestHostVer)" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageVersion Include="Moq" Version="4.20.70" />
<PackageVersion Include="Polly" Version="8.4.1" />
<PackageVersion Include="rest-mock-core" Version="0.7.12" />
<PackageVersion Include="RichardSzalay.MockHttp" Version="7.0.0" />
<PackageVersion Include="System.Net.Http.Json" Version="8.0.0" />
<PackageVersion Include="Xunit.Extensions.Logging" Version="1.1.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" PrivateAssets="All" />
<PackageVersion Include="xunit" Version="2.9.0" />
</ItemGroup>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<PropertyGroup Label="Package versions for .NET 8" Condition="$(TargetFramework) == 'net8.0'">
<MicrosoftTestHostVer>8.0.3</MicrosoftTestHostVer>
</PropertyGroup>
<PropertyGroup Label="Package versions for .NET 9" Condition="$(TargetFramework) == 'net9.0'">
<MicrosoftTestHostVer>9.0.0</MicrosoftTestHostVer>
</PropertyGroup>
<ItemGroup Label="Runtime dependencies">
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3"/>
<PackageVersion Include="CsvHelper" Version="33.0.1"/>
<PackageVersion Include="System.Text.Json" Version="9.0.0"/>
</ItemGroup>
<ItemGroup Label="Compile dependencies">
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0"/>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0"/>
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0"/>
<PackageVersion Include="MinVer" Version="6.0.0"/>
<PackageVersion Include="Nullable" Version="1.3.1"/>
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies.net472" Version="1.0.3"/>
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0"/>
<PackageVersion Include="JetBrains.Annotations" Version="2024.3.0"/>
</ItemGroup>
<ItemGroup Label="Testing dependencies">
<PackageVersion Include="HttpMultipartParser" Version="8.4.0"/>
<PackageVersion Include="PolySharp" Version="1.15.0"/>
<PackageVersion Include="AutoFixture" Version="4.18.1"/>
<PackageVersion Include="coverlet.collector" Version="6.0.2"/>
<PackageVersion Include="FluentAssertions" Version="7.0.0"/>
<PackageVersion Include="HttpTracer" Version="2.1.1"/>
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="$(MicrosoftTestHostVer)"/>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0"/>
<PackageVersion Include="Moq" Version="4.20.72"/>
<PackageVersion Include="Polly" Version="8.5.0"/>
<PackageVersion Include="rest-mock-core" Version="0.7.12"/>
<PackageVersion Include="RichardSzalay.MockHttp" Version="7.0.0"/>
<PackageVersion Include="System.Net.Http.Json" Version="9.0.0"/>
<PackageVersion Include="Xunit.Extensions.Logging" Version="1.1.0"/>
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" PrivateAssets="All"/>
<PackageVersion Include="xunit" Version="2.9.2"/>
<PackageVersion Include="WireMock.Net" Version="1.6.10"/>
<PackageVersion Include="WireMock.Net.FluentAssertions" Version="1.5.51"/>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
3 changes: 2 additions & 1 deletion docs/docs/usage/client.md
Original file line number Diff line number Diff line change
@@ -56,7 +56,8 @@ Constructor parameters to configure the `HttpMessageHandler` and default `HttpCl
You need to set the `useClientFactory` parameter to `true` in the `RestClient` constructor to enable the factory.

```csharp
var client = new RestClient("https://api.twitter.com/2", true);
var options = new RestClientOptions("https://api.twitter.com/2");
var client = new RestClient(options, useClientFactory: true);
```

## Reusing HttpClient
19 changes: 19 additions & 0 deletions docs/docs/usage/request.md
Original file line number Diff line number Diff line change
@@ -71,11 +71,30 @@ request.AddParameter("name", "Væ üé", false); // don't encode the value
If you have files, RestSharp will send a `multipart/form-data` request. Your parameters will be part of this request in the form:

```
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name="parameterName"
ParameterValue
```

Sometimes, you need to override the default content type for the parameter when making a multipart form call. It's possible to do by setting the `ContentType` property of the parameter object. As an example, the code below will create a POST parameter with JSON value, and set the appropriate content type:

```csharp
var parameter = new GetOrPostParameter("someJson", "{\"attributeFormat\":\"pdf\"}") {
ContentType = "application/json"
};
request.AddParameter(parameter);
```

When the request is set to use multipart content, the parameter will be sent as part of the request with the specified content type:

```
Content-Type: application/json; charset=utf-8
Content-Disposition: form-data; name="someJson"
{"attributeFormat":"pdf"}
```

You can also add `GetOrPost` parameter as a default parameter to the client. This will add the parameter to every request made by the client.

```csharp
4 changes: 2 additions & 2 deletions docs/versioned_docs/version-v111/intro.md
Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@ var timeline = await client.GetAsync<HomeTimeline>(request, cancellationToken);
Both snippets above use the `GetAsync` extension, which is a wrapper about `ExecuteGetAsync`, which, in turn, is a wrapper around `ExecuteAsync`.
All `ExecuteAsync` overloads and return the `RestResponse` or `RestResponse<T>`.

The most important difference is that async methods named after HTTP methods (like `GetAsync` or `PostAsync`) return `Task<T>` instead of `Task<RestResponse<T>>`. It means that you won't get an error response if the request fails as those methods throw an exception for unsuccessful HTTP calls. For keeping the API consistent, non-generic functions like `GetAsync` or `PostAsync` also throw an exception if the request fails, although they return the `Task<RestResponse>`.
The most important difference is that async methods named after HTTP methods (like `GetAsync<T>` or `PostAsync<T>`) return `Task<T>` instead of `Task<RestResponse<T>>`. It means that you won't get an error response if the request fails as those methods throw an exception for unsuccessful HTTP calls. For keeping the API consistent, non-generic functions like `GetAsync` or `PostAsync` also throw an exception if the request fails, although they return the `Task<RestResponse>`.

Read [here](advanced/error-handling.md) about how RestSharp handles exceptions.

@@ -84,7 +84,7 @@ There is no need to set the `Content-Type` or add the `DataFormat` parameter to

RestSharp will also handle both XML and JSON responses and perform all necessary deserialization tasks, depending on the server response type. Therefore, you only need to add the `Accept` header if you want to deserialize the response manually.

For example, only you'd only need these lines to make a request with JSON body:
For example, you'd only need these lines to make a request with JSON body:

```csharp
var request = new RestRequest("address/update").AddJsonBody(updatedAddress);
6 changes: 3 additions & 3 deletions docs/versioned_docs/version-v111/usage/example.md
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ For example, let's look at a simple Twitter API v2 client, which uses OAuth2 mac

Before implementing an API client, we need to have a model for it. The model includes an abstraction for the client, which has functions for the API calls we are interested to implement. In addition, the client model would include the necessary request and response models. Usually those are simple classes or records without logic, which are often referred to as DTOs (data transfer objects).

This example starts with a single function that retrieves one Twitter user. Lets being by defining the API client interface:
This example starts with a single function that retrieves one Twitter user. Let's begin by defining the API client interface:

```csharp
public interface ITwitterClient {
@@ -73,7 +73,7 @@ public class TwitterClientOptions(string ApiKey, string ApiSecret);

public TwitterClient(IOptions<TwitterClientOptions> options) {
var opt = new RestClientOptions("https://api.twitter.com/2");
_client = new RestClient(options);
_client = new RestClient(opt);
}
```

@@ -149,4 +149,4 @@ Sample code provided on this page is a production code. For example, the authent

## Final words

This page demonstrates how an API client can be implemented as a typed, configurable client with its own interface. Usage of the client in applications is not covered here as different application types and target frameworks have their own idiomatic ways to use HTTP clients.
This page demonstrates how an API client can be implemented as a typed, configurable client with its own interface. Usage of the client in applications is not covered here as different application types and target frameworks have their own idiomatic ways to use HTTP clients.
2 changes: 1 addition & 1 deletion gen/SourceGenerator/Extensions.cs
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ public static IEnumerable<ClassDeclarationSyntax> FindClasses(this Compilation c
.SelectMany(model => model.SyntaxTree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>())
.Where(predicate);

public static IEnumerable<ClassDeclarationSyntax> FindAnnotatedClass(this Compilation compilation, string attributeName, bool strict) {
public static IEnumerable<ClassDeclarationSyntax> FindAnnotatedClasses(this Compilation compilation, string attributeName, bool strict) {
return compilation.FindClasses(
syntax => syntax.AttributeLists.Any(list => list.Attributes.Any(CheckAttribute))
);
30 changes: 20 additions & 10 deletions gen/SourceGenerator/ImmutableGenerator.cs
Original file line number Diff line number Diff line change
@@ -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));
}
}
}

65 changes: 36 additions & 29 deletions gen/SourceGenerator/InheritedCloneGenerator.cs
Original file line number Diff line number Diff line change
@@ -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));
}
}
}

2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'RestSharp.sln'))\props\Common.props"/>
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net471;net48;net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net471;net48;net8.0;net9.0</TargetFrameworks>
<PackageIcon>restsharp.png</PackageIcon>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://restsharp.dev</PackageProjectUrl>
Loading