From 84d20890331a86ce5659b261ab13546916ae1bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20te=20Winkel?= Date: Tue, 18 Jul 2023 21:16:47 +0200 Subject: [PATCH 1/2] Fix #1261 --- .../InterfaceStubGenerator.cs | 35 ++++++++------- Refit.Tests/NamespaceCollisionApi.cs | 12 +++++ Refit.Tests/RestService.cs | 45 ++++++++++++++++++- 3 files changed, 73 insertions(+), 19 deletions(-) diff --git a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs index e59526513..88bfdc962 100644 --- a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs +++ b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs @@ -95,7 +95,7 @@ public void GenerateInterfaceStubs( var methodSymbols = new List(); foreach (var group in candidateMethods.GroupBy(m => m.SyntaxTree)) { - var model = compilation.GetSemanticModel(group.Key); + var model = compilation.GetSemanticModel(group.Key); foreach (var method in group) { // Get the symbol being declared by the method @@ -148,7 +148,7 @@ public void GenerateInterfaceStubs( // Bail out if there aren't any interfaces to generate code for. This may be the case with transitives if(!interfaces.Any()) return; - + var supportsNullable = options.LanguageVersion >= LanguageVersion.CSharp8; @@ -222,16 +222,17 @@ internal static partial class Generated httpMethodBaseAttributeSymbol, supportsNullable, interfaceToNullableEnabledMap[group.Key]); - + var keyName = group.Key.Name; - if(keyCount.TryGetValue(keyName, out var value)) + int value; + while(keyCount.TryGetValue(keyName, out value)) { keyName = $"{keyName}{++value}"; } keyCount[keyName] = value; addSource(context, $"{keyName}.g.cs", SourceText.From(classSource, Encoding.UTF8)); - } + } } @@ -315,7 +316,7 @@ partial class {ns}{classDeclaration} Client = client; this.requestBuilder = requestBuilder; }} - + "); // Get any other methods on the refit interfaces. We'll need to generate something for them and warn var nonRefitMethods = interfaceSymbol.GetMembers().OfType().Except(refitMethods, SymbolEqualityComparer.Default).Cast().ToList(); @@ -335,7 +336,7 @@ partial class {ns}{classDeclaration} var derivedRefitMethods = derivedMethods.Where(m => IsRefitMethod(m, httpMethodBaseAttributeSymbol)).ToList(); var derivedNonRefitMethods = derivedMethods.Except(derivedMethods, SymbolEqualityComparer.Default).Cast().ToList(); - // Handle Refit Methods + // Handle Refit Methods foreach(var method in refitMethods) { ProcessRefitMethod(source, method, true); @@ -363,7 +364,7 @@ partial class {ns}{classDeclaration} if(disposeMethod != null) { ProcessDisposableMethod(source, disposeMethod); - } + } source.Append(@" } @@ -392,21 +393,21 @@ void ProcessRefitMethod(StringBuilder source, IMethodSymbol methodSymbol, bool i argList.Add($"@{param.MetadataName}"); } - // List of types. + // List of types. var typeList = new List(); foreach(var param in methodSymbol.Parameters) { - typeList.Add($"typeof({param.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)})"); + typeList.Add($"typeof({param.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)})"); } // List of generic arguments - var genericList = new List(); + var genericList = new List(); foreach(var typeParam in methodSymbol.TypeParameters) { genericList.Add($"typeof({typeParam.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)})"); } - var genericString = genericList.Count > 0 ? $", new global::System.Type[] {{ {string.Join(", ", genericList)} }}" : string.Empty; + var genericString = genericList.Count > 0 ? $", new global::System.Type[] {{ {string.Join(", ", genericList)} }}" : string.Empty; source.Append(@$" var ______arguments = new object[] {{ {string.Join(", ", argList)} }}; @@ -468,7 +469,7 @@ void WriteConstraitsForTypeParameter(StringBuilder source, ITypeParameterSymbol parameters.Add(typeConstraint.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); } } - + // new constraint has to be last if (typeParameter.HasConstructorConstraint && !isOverrideOrExplicitImplementation) { @@ -497,7 +498,7 @@ void ProcessNonRefitMethod(TContext context, Action 0) { @@ -527,7 +528,7 @@ void WriteMethodOpening(StringBuilder source, IMethodSymbol methodSymbol, bool i source.Append(string.Join(", ", list)); } - + source.Append(@$") {GenerateConstraints(methodSymbol.TypeParameters, isExplicitInterface)} {{"); } @@ -595,7 +596,7 @@ class SyntaxReceiver : ISyntaxReceiver public void OnVisitSyntaxNode(SyntaxNode syntaxNode) { - // We're looking for methods with an attribute that are in an interfaces + // We're looking for methods with an attribute that are in an interfaces if(syntaxNode is MethodDeclarationSyntax methodDeclarationSyntax && methodDeclarationSyntax.Parent is InterfaceDeclarationSyntax && methodDeclarationSyntax.AttributeLists.Count > 0) diff --git a/Refit.Tests/NamespaceCollisionApi.cs b/Refit.Tests/NamespaceCollisionApi.cs index 4649bf547..9930a2ad7 100644 --- a/Refit.Tests/NamespaceCollisionApi.cs +++ b/Refit.Tests/NamespaceCollisionApi.cs @@ -23,9 +23,21 @@ public static INamespaceCollisionApi Create() namespace CollisionA { public class SomeType { } + + public interface INamespaceCollisionApi + { + [Get("/")] + Task SomeRequest(); + } } namespace CollisionB { public class SomeType { } + + public interface INamespaceCollisionApi + { + [Get("/")] + Task SomeRequest(); + } } diff --git a/Refit.Tests/RestService.cs b/Refit.Tests/RestService.cs index bcf391f89..5225cd306 100644 --- a/Refit.Tests/RestService.cs +++ b/Refit.Tests/RestService.cs @@ -2120,11 +2120,14 @@ public async Task TypeCollisionTest() mockHttp.Expect(HttpMethod.Get, Url) .Respond("application/json", "{ }"); - var fixtureA = RestService.For(Url); + var fixtureA = RestService.For(Url, settings); var respA = await fixtureA.SomeARequest(); - var fixtureB = RestService.For(Url); + mockHttp.Expect(HttpMethod.Get, Url) + .Respond("application/json", "{ }"); + + var fixtureB = RestService.For(Url, settings); var respB = await fixtureB.SomeBRequest(); @@ -2132,6 +2135,44 @@ public async Task TypeCollisionTest() Assert.IsType(respB); } + [Fact] + public async Task SameTypeNameInMultipleNamespacesTest() + { + var mockHttp = new MockHttpMessageHandler(); + + var settings = new RefitSettings + { + HttpMessageHandlerFactory = () => mockHttp, + }; + + const string Url = "https://httpbin.org/get"; + + mockHttp.Expect(HttpMethod.Get, Url + "/") + .Respond("application/json", "{ }"); + + var fixtureA = RestService.For(Url, settings); + + var respA = await fixtureA.SomeRequest(); + + mockHttp.Expect(HttpMethod.Get, Url + "/") + .Respond("application/json", "{ }"); + + var fixtureB = RestService.For(Url, settings); + + var respB = await fixtureB.SomeRequest(); + + mockHttp.Expect(HttpMethod.Get, Url + "/") + .Respond("application/json", "{ }"); + + var fixtureC = RestService.For(Url, settings); + + var respC = await fixtureC.SomeRequest(); + + Assert.IsType(respA); + Assert.IsType(respB); + Assert.IsType(respC); + } + From 6994eefde590bc7ddc164e6f555c2ef130d89528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20te=20Winkel?= Date: Mon, 2 Oct 2023 19:57:58 +0200 Subject: [PATCH 2/2] Revert accidental change. Fix unit tests on difference in extra spaces in output. --- InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs | 2 +- Refit.Tests/InterfaceStubGenerator.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs index 91257250b..a23a763bd 100644 --- a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs +++ b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs @@ -545,7 +545,7 @@ void WriteMethodOpening(StringBuilder source, IMethodSymbol methodSymbol, bool i source.Append(string.Join(", ", list)); } - source.Append(@$") {GenerateConstraints(methodSymbol.TypeParameters, isExplicitInterface)} + source.Append(@$"){GenerateConstraints(methodSymbol.TypeParameters, isExplicitInterface)} {{"); } diff --git a/Refit.Tests/InterfaceStubGenerator.cs b/Refit.Tests/InterfaceStubGenerator.cs index 3b92f9015..715553cc3 100644 --- a/Refit.Tests/InterfaceStubGenerator.cs +++ b/Refit.Tests/InterfaceStubGenerator.cs @@ -200,7 +200,7 @@ public RefitTestsIGitHubApi(global::System.Net.Http.HttpClient client, global::R Client = client; this.requestBuilder = requestBuilder; } - + /// @@ -626,7 +626,7 @@ public RefitTestsIGitHubApiDisposable(global::System.Net.Http.HttpClient client, Client = client; this.requestBuilder = requestBuilder; } - + /// @@ -698,7 +698,7 @@ public RefitTestsTestNestedINestedGitHubApi(global::System.Net.Http.HttpClient c Client = client; this.requestBuilder = requestBuilder; } - + /// @@ -1054,7 +1054,7 @@ public IServiceWithoutNamespace(global::System.Net.Http.HttpClient client, globa Client = client; this.requestBuilder = requestBuilder; } - + ///