diff --git a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.Shared.projitems b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.Shared.projitems
index 5589f69c2..3c02c35ff 100644
--- a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.Shared.projitems
+++ b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.Shared.projitems
@@ -6,10 +6,12 @@
b591423d-f92d-4e00-b0eb-615c9853506c
- InterfaceStubGenerator.Shared
+ Refit.Generator
+
+
\ No newline at end of file
diff --git a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs
index c479e7972..c8a02b1b1 100644
--- a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs
+++ b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs
@@ -119,6 +119,8 @@ ImmutableArray candidateInterfaces
return;
}
+ var refitMetadata = new RefitMetadata(disposableInterfaceSymbol, httpMethodBaseAttributeSymbol);
+
// Check the candidates and keep the ones we're actually interested in
#pragma warning disable RS1024 // Compare symbols correctly
@@ -134,7 +136,7 @@ ImmutableArray candidateInterfaces
{
// Get the symbol being declared by the method
var methodSymbol = model.GetDeclaredSymbol(method);
- if (IsRefitMethod(methodSymbol, httpMethodBaseAttributeSymbol))
+ if (refitMetadata.IsRefitMethod(methodSymbol))
{
var isAnnotated =
compilation.Options.NullableContextOptions
@@ -170,9 +172,9 @@ ImmutableArray candidateInterfaces
continue;
// The interface has no refit methods, but its base interfaces might
- var hasDerivedRefit = ifaceSymbol
- .AllInterfaces.SelectMany(i => i.GetMembers().OfType())
- .Any(m => IsRefitMethod(m, httpMethodBaseAttributeSymbol));
+ var hasDerivedRefit = ifaceSymbol.AllInterfaces
+ .SelectMany(i => i.GetMembers().OfType())
+ .Any(refitMetadata.IsRefitMethod);
if (hasDerivedRefit)
{
@@ -276,20 +278,15 @@ public static void Initialize()
// each group is keyed by the Interface INamedTypeSymbol and contains the members
// with a refit attribute on them. Types may contain other members, without the attribute, which we'll
// need to check for and error out on
-
- var classSource = ProcessInterface(
- context,
- reportDiagnostic,
- group.Key,
- group.Value,
- preserveAttributeSymbol,
- disposableInterfaceSymbol,
- httpMethodBaseAttributeSymbol,
- supportsNullable,
- interfaceToNullableEnabledMap[group.Key]
- );
-
- var keyName = group.Key.Name;
+ var model = new RefitClientModel(group.Key, group.Value, refitMetadata);
+ var classSource = ProcessInterface(context,
+ reportDiagnostic,
+ model,
+ preserveAttributeSymbol,
+ supportsNullable,
+ interfaceToNullableEnabledMap[model.RefitInterface]);
+
+ var keyName = model.FileName;
int value;
while (keyCount.TryGetValue(keyName, out value))
{
@@ -304,39 +301,14 @@ public static void Initialize()
static string ProcessInterface(
TContext context,
Action reportDiagnostic,
- INamedTypeSymbol interfaceSymbol,
- List refitMethods,
+ RefitClientModel interfaceModel,
ISymbol preserveAttributeSymbol,
- ISymbol disposableInterfaceSymbol,
- INamedTypeSymbol httpMethodBaseAttributeSymbol,
bool supportsNullable,
bool nullableEnabled
)
{
- // Get the class name with the type parameters, then remove the namespace
- var className = interfaceSymbol.ToDisplayString();
- var lastDot = className.LastIndexOf('.');
- if (lastDot > 0)
- {
- className = className.Substring(lastDot + 1);
- }
- var classDeclaration = $"{interfaceSymbol.ContainingType?.Name}{className}";
-
- // Get the class name itself
- var classSuffix = $"{interfaceSymbol.ContainingType?.Name}{interfaceSymbol.Name}";
- var ns = interfaceSymbol.ContainingNamespace?.ToDisplayString();
-
- // if it's the global namespace, our lookup rules say it should be the same as the class name
- if (
- interfaceSymbol.ContainingNamespace != null
- && interfaceSymbol.ContainingNamespace.IsGlobalNamespace
- )
- {
- ns = string.Empty;
- }
-
- // Remove dots
- ns = ns!.Replace(".", "");
+ INamedTypeSymbol interfaceSymbol = interfaceModel.RefitInterface;
+ List refitMethods = interfaceModel.RefitMethods;
// See what the nullable context is
@@ -371,8 +343,8 @@ partial class Generated
[{preserveAttributeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}]
[global::System.Reflection.Obfuscation(Exclude=true)]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
- partial class {ns}{classDeclaration}
- : {interfaceSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}{GenerateConstraints(interfaceSymbol.TypeParameters, false)}
+ partial class {interfaceModel.NamespacePrefix}{interfaceModel.ClassDeclaration}
+ : {interfaceModel.BaseInterfaceDeclaration}{GenerateConstraints(interfaceSymbol.TypeParameters, false)}
{{
///
@@ -380,49 +352,13 @@ partial class {ns}{classDeclaration}
readonly global::Refit.IRequestBuilder requestBuilder;
///
- public {ns}{classSuffix}(global::System.Net.Http.HttpClient client, global::Refit.IRequestBuilder requestBuilder)
+ public {interfaceModel.NamespacePrefix}{interfaceModel.ClassSuffix}(global::System.Net.Http.HttpClient client, global::Refit.IRequestBuilder requestBuilder)
{{
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();
-
- // get methods for all inherited
- var derivedMethods = interfaceSymbol
- .AllInterfaces.SelectMany(i => i.GetMembers().OfType())
- .ToList();
-
- // Look for disposable
- var disposeMethod = derivedMethods.Find(
- m =>
- m.ContainingType?.Equals(
- disposableInterfaceSymbol,
- SymbolEqualityComparer.Default
- ) == true
- );
- if (disposeMethod != null)
- {
- //remove it from the derived methods list so we don't process it with the rest
- derivedMethods.Remove(disposeMethod);
- }
-
- // Pull out the refit methods from the derived types
- var derivedRefitMethods = derivedMethods
- .Where(m => IsRefitMethod(m, httpMethodBaseAttributeSymbol))
- .ToList();
- var derivedNonRefitMethods = derivedMethods
- .Except(derivedMethods, SymbolEqualityComparer.Default)
- .Cast()
- .ToList();
+");
var memberNames = new HashSet(interfaceSymbol.GetMembers().Select(x => x.Name));
@@ -432,30 +368,22 @@ partial class {ns}{classDeclaration}
ProcessRefitMethod(source, method, true, memberNames);
}
- foreach (var method in refitMethods.Concat(derivedRefitMethods))
+ foreach (var method in interfaceModel.AllRefitMethods)
{
ProcessRefitMethod(source, method, false, memberNames);
}
// Handle non-refit Methods that aren't static or properties or have a method body
- foreach (var method in nonRefitMethods.Concat(derivedNonRefitMethods))
+ foreach (var method in interfaceModel.NonRefitMethods)
{
- if (
- method.IsStatic
- || method.MethodKind == MethodKind.PropertyGet
- || method.MethodKind == MethodKind.PropertySet
- || !method.IsAbstract
- ) // If an interface method has a body, it won't be abstract
- continue;
-
ProcessNonRefitMethod(context, reportDiagnostic, source, method);
}
// Handle Dispose
- if (disposeMethod != null)
+ if (interfaceModel.DisposeMethod != null)
{
- ProcessDisposableMethod(source, disposeMethod);
- }
+ ProcessDisposableMethod(source, interfaceModel.DisposeMethod);
+ }
source.Append(
@"
@@ -779,14 +707,6 @@ static string UniqueName(string name, HashSet methodNames)
return candidateName;
}
- static bool IsRefitMethod(IMethodSymbol? methodSymbol, INamedTypeSymbol httpMethodAttibute)
- {
- return methodSymbol
- ?.GetAttributes()
- .Any(ad => ad.AttributeClass?.InheritsFromOrEquals(httpMethodAttibute) == true)
- == true;
- }
-
#if ROSLYN_4
///
diff --git a/InterfaceStubGenerator.Shared/RefitClientModel.cs b/InterfaceStubGenerator.Shared/RefitClientModel.cs
new file mode 100644
index 000000000..d6ad313d7
--- /dev/null
+++ b/InterfaceStubGenerator.Shared/RefitClientModel.cs
@@ -0,0 +1,113 @@
+using System.Collections.Generic;
+using System.Linq;
+
+using Microsoft.CodeAnalysis;
+
+namespace Refit.Generator;
+
+internal class RefitClientModel
+{
+ readonly RefitMetadata refitMetadata;
+
+ public RefitClientModel(INamedTypeSymbol refitInterface, List refitMethods, RefitMetadata refitMetadata)
+ {
+ RefitInterface = refitInterface;
+ RefitMethods = refitMethods;
+ this.refitMetadata = refitMetadata;
+
+ // Get any other methods on the refit interfaces. We'll need to generate something for them and warn
+ var nonRefitMethods = refitInterface
+ .GetMembers()
+ .OfType()
+ .Except(refitMethods, SymbolEqualityComparer.Default)
+ .Cast()
+ .ToList();
+
+ // get methods for all inherited
+ var derivedMethods = refitInterface
+ .AllInterfaces.SelectMany(i => i.GetMembers().OfType())
+ .ToList();
+
+ // Look for disposable
+ DisposeMethod = derivedMethods.Find(
+ m =>
+ m.ContainingType?.Equals(
+ refitMetadata.DisposableInterfaceSymbol,
+ SymbolEqualityComparer.Default
+ ) == true
+ );
+ if (DisposeMethod != null)
+ {
+ //remove it from the derived methods list so we don't process it with the rest
+ derivedMethods.Remove(DisposeMethod);
+ }
+
+ // Pull out the refit methods from the derived types
+ var derivedRefitMethods = derivedMethods.Where(refitMetadata.IsRefitMethod).ToList();
+ var derivedNonRefitMethods = derivedMethods.Except(derivedMethods, SymbolEqualityComparer.Default).Cast().ToList();
+
+ AllRefitMethods = refitMethods.Concat(derivedRefitMethods);
+ NonRefitMethods = nonRefitMethods.Concat(derivedNonRefitMethods)
+ .Where(static method =>
+ {
+ return !(method.IsStatic ||
+ method.MethodKind == MethodKind.PropertyGet ||
+ method.MethodKind == MethodKind.PropertySet ||
+ !method.IsAbstract);
+ });
+ }
+
+ public INamedTypeSymbol RefitInterface { get; }
+ public List RefitMethods { get; }
+ public IEnumerable AllRefitMethods { get; }
+ public IEnumerable NonRefitMethods { get; }
+
+ public string FileName => RefitInterface.Name;
+
+ public string ClassDeclaration
+ {
+ get
+ {
+ // Get the class name with the type parameters, then remove the namespace
+ var className = RefitInterface.ToDisplayString();
+ var lastDot = className.LastIndexOf('.');
+ if (lastDot > 0)
+ {
+ className = className.Substring(lastDot + 1);
+ }
+ var classDeclaration = $"{RefitInterface.ContainingType?.Name}{className}";
+ return classDeclaration;
+ }
+ }
+
+ public string ClassSuffix
+ {
+ get
+ {
+ // Get the class name itself
+ var classSuffix = $"{RefitInterface.ContainingType?.Name}{RefitInterface.Name}";
+ return classSuffix;
+ }
+ }
+
+ public string NamespacePrefix
+ {
+ get
+ {
+ var ns = RefitInterface.ContainingNamespace?.ToDisplayString();
+
+ // if it's the global namespace, our lookup rules say it should be the same as the class name
+ if (RefitInterface.ContainingNamespace != null && RefitInterface.ContainingNamespace.IsGlobalNamespace)
+ {
+ return string.Empty;
+ }
+
+ // Remove dots
+ ns = ns!.Replace(".", "");
+ return ns;
+ }
+ }
+ public string BaseInterfaceDeclaration => $"{RefitInterface.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}";
+
+ public IMethodSymbol DisposeMethod { get; }
+}
diff --git a/InterfaceStubGenerator.Shared/RefitMetadata.cs b/InterfaceStubGenerator.Shared/RefitMetadata.cs
new file mode 100644
index 000000000..b6fa0bbd0
--- /dev/null
+++ b/InterfaceStubGenerator.Shared/RefitMetadata.cs
@@ -0,0 +1,22 @@
+using System.Linq;
+
+using Microsoft.CodeAnalysis;
+
+namespace Refit.Generator;
+
+internal class RefitMetadata
+{
+ public RefitMetadata(INamedTypeSymbol? disposableInterfaceSymbol, INamedTypeSymbol httpMethodBaseAttributeSymbol)
+ {
+ DisposableInterfaceSymbol = disposableInterfaceSymbol;
+ HttpMethodBaseAttributeSymbol = httpMethodBaseAttributeSymbol;
+ }
+
+ public INamedTypeSymbol? DisposableInterfaceSymbol { get; }
+ public INamedTypeSymbol HttpMethodBaseAttributeSymbol { get; }
+
+ public bool IsRefitMethod(IMethodSymbol? methodSymbol)
+ {
+ return methodSymbol?.GetAttributes().Any(ad => ad.AttributeClass?.InheritsFromOrEquals(HttpMethodBaseAttributeSymbol) == true) == true;
+ }
+}