Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
</ItemGroup>

<ItemGroup Condition="'$(IsTestProject)' == 'true'">
<Compile Include="$(MSBuildThisFileDirectory)tests\HttpClientTestFactory.cs" Link="Testing\HttpClientTestFactory.cs"/>
<None Include="$(MSBuildThisFileDirectory)testconfig.json">
<Link>$(AssemblyName).testconfig.json</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down Expand Up @@ -109,8 +110,10 @@
</ItemGroup>

<!-- net8.0 has every other shim natively but lacks OverloadResolutionPriority (added in net9.0).
The net4* leg already pulls this in via the Polyfills\*.cs glob above. -->
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
Only Refit.HttpClientFactory uses the attribute; compiling the shim into consumers that already
reference Refit would create a duplicate compiler-recognized type. The net4* leg already pulls
this in via the Polyfills\*.cs glob above. -->
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0' and '$(MSBuildProjectName)' == 'Refit.HttpClientFactory'">
<Compile Include="$(MSBuildThisFileDirectory)Polyfills\OverloadResolutionPriorityAttribute.cs" Link="Polyfills\OverloadResolutionPriorityAttribute.cs"/>
</ItemGroup>

Expand Down
14 changes: 7 additions & 7 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@
</PropertyGroup>

<PropertyGroup Label="Shared Version Variables">
<PrimitivesVersion>6.0.0</PrimitivesVersion>
<PrimitivesVersion>7.0.0</PrimitivesVersion>
<TUnitVersion>1.59.0</TUnitVersion>

<!-- StyleSharp and PerformanceSharp ship from the same repo on a single version line. -->
<SharpAnalyzersVersion>3.26.0</SharpAnalyzersVersion>
<SharpAnalyzersVersion>3.33.0</SharpAnalyzersVersion>
</PropertyGroup>

<PropertyGroup Label="Framework-Aligned Versions">
<AspNetVersion>8.0.28</AspNetVersion>
<AspNetVersion Condition="$(TargetFramework.StartsWith('net9'))">9.0.17</AspNetVersion>
<AspNetVersion Condition="$(TargetFramework.StartsWith('net10'))">10.0.9</AspNetVersion>
<AspNetVersion Condition="$(TargetFramework.StartsWith('net9'))">9.0.18</AspNetVersion>
<AspNetVersion Condition="$(TargetFramework.StartsWith('net10'))">10.0.10</AspNetVersion>

<MicrosoftExtensionsVersion>10.0.9</MicrosoftExtensionsVersion>
<SystemTextJsonVersion>10.0.9</SystemTextJsonVersion>
<MicrosoftExtensionsVersion>10.0.10</MicrosoftExtensionsVersion>
<SystemTextJsonVersion>10.0.10</SystemTextJsonVersion>

<MicrosoftCodeAnalysisAnalyzersVersion>5.6.0</MicrosoftCodeAnalysisAnalyzersVersion>
<MicrosoftCodeAnalysisWorkspacesVersion>4.14.0</MicrosoftCodeAnalysisWorkspacesVersion>

<SourceLinkVersion>10.0.300</SourceLinkVersion>
<SourceLinkVersion>10.0.301</SourceLinkVersion>
<ThreadingAnalyzersVersion>18.7.23</ThreadingAnalyzersVersion>
<NetFrameworkReferenceAssembliesVersion>1.0.3</NetFrameworkReferenceAssembliesVersion>
</PropertyGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/InterfaceStubGenerator.Shared/DiagnosticDescriptors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ internal static class DiagnosticDescriptors
{
/// <summary>Diagnostic reported when the Refit assembly is not referenced.</summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "RS2008", Justification = "Diagnostic IDs are stable and intentionally not tracked in an analyzer release-tracking file.")]
public static readonly DiagnosticDescriptor RefitNotReferenced =
internal static readonly DiagnosticDescriptor RefitNotReferenced =
new(
"RF002",
"Refit must be referenced",
Expand All @@ -21,7 +21,7 @@ internal static class DiagnosticDescriptors

/// <summary>Diagnostic reported when a source-generation-only attribute is used on a method that cannot generate inline.</summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "RS2008", Justification = "Diagnostic IDs are stable and intentionally not tracked in an analyzer release-tracking file.")]
public static readonly DiagnosticDescriptor SourceGenOnlyAttributeRequiresInlineRequest =
internal static readonly DiagnosticDescriptor SourceGenOnlyAttributeRequiresInlineRequest =
new(
"RF007",
"Attribute requires generated request building",
Expand Down
7 changes: 1 addition & 6 deletions src/InterfaceStubGenerator.Shared/Emitter.Constraints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,7 @@ internal static string BuildConstraintsForTypeParameter(
int indentationLevel) =>
!HasConstraintKeywords(typeParameter, isOverrideOrExplicitImplementation)
? string.Empty
: Indent(indentationLevel)
+ "where "
+ typeParameter.TypeName
+ " : "
+ BuildConstraintList(typeParameter, isOverrideOrExplicitImplementation)
+ "\n";
: $"{Indent(indentationLevel)}where {typeParameter.TypeName} : {BuildConstraintList(typeParameter, isOverrideOrExplicitImplementation)}\n";

/// <summary>Determines whether a type parameter has constraints that should be emitted.</summary>
/// <param name="typeParameter">The type parameter constraint to inspect.</param>
Expand Down
12 changes: 6 additions & 6 deletions src/InterfaceStubGenerator.Shared/Emitter.Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ internal static (bool IsAsync, string ReturnPrefix, string ConfigureAwaitSuffix)
{
ReturnTypeInfo.AsyncVoid => (true, "await (", ").ConfigureAwait(false)"),
ReturnTypeInfo.AsyncResult => (true, "return await (", ").ConfigureAwait(false)"),
ReturnTypeInfo.AsyncEnumerable => (false, ReturnStatementPrefix, string.Empty),
ReturnTypeInfo.Observable => (false, ReturnStatementPrefix, string.Empty),
ReturnTypeInfo.RequestMessage => (false, ReturnStatementPrefix, string.Empty),
ReturnTypeInfo.Return => (false, ReturnStatementPrefix, string.Empty),
ReturnTypeInfo.AsyncEnumerable
or ReturnTypeInfo.Observable
or ReturnTypeInfo.RequestMessage
or ReturnTypeInfo.Return => (false, ReturnStatementPrefix, string.Empty),
ReturnTypeInfo.SyncVoid => (false, string.Empty, string.Empty),
_ => throw new ArgumentOutOfRangeException(
nameof(returnTypeInfo),
Expand Down Expand Up @@ -324,8 +324,8 @@ internal static string BuildExplicitInterfacePrefix(in MethodModel methodModel,

var containingType = methodModel.ContainingType;
return containingType.StartsWith(GlobalPrefix, StringComparison.Ordinal)
? containingType + "."
: GlobalPrefix + containingType + ".";
? $"{containingType}."
: $"{GlobalPrefix}{containingType}.";
}

/// <summary>Builds the generated method parameter list.</summary>
Expand Down
20 changes: 10 additions & 10 deletions src/InterfaceStubGenerator.Shared/Emitter.Inline.Content.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,17 @@ internal static string BuildInlineFormUnroll(
{
var settingsLocal = emission.SettingsLocal;
var bodyIndent = Indent(MethodBodyIndentation);
var inner = bodyIndent + " ";
var inner = $"{bodyIndent} ";
var fields = bodyParameter.FormFields!.Value.AsArray();
var bodyExpr = "@" + bodyParameter.Name;
var bodyExpr = $"@{bodyParameter.Name}";
var entriesLocal = locals.New("______formEntries");

// Nullable reference annotations are a C# 8 feature; older consumers get the unannotated types, which also match
// the .NET Framework/netstandard FormUrlEncodedContent constructor signature. The generated code stays
// compilable down to the C# 7.3 floor (explicit KeyValuePair construction, != null guards - no C# 9 syntax).
var nullable = supportsNullable ? "?" : string.Empty;
var kvpType = "global::System.Collections.Generic.KeyValuePair<string" + nullable + ", string" + nullable + ">";
var site = new FormUnrollSite(bodyExpr, entriesLocal, inner, "new " + kvpType, locals);
var kvpType = $"global::System.Collections.Generic.KeyValuePair<string{nullable}, string{nullable}>";
var site = new FormUnrollSite(bodyExpr, entriesLocal, inner, $"new {kvpType}", locals);

var adds = new PooledStringBuilder();
foreach (var field in fields)
Expand Down Expand Up @@ -137,11 +137,11 @@ internal static void AppendFormFieldUnroll(
{
var indent = site.Indentation;
var valueLocal = site.Locals.New("______formValue");
var keyExpr = "global::Refit.GeneratedRequestRunner.BuildQueryKey("
+ emission.SettingsLocal + ", "
+ ToCSharpStringLiteral(field.PropertyName) + ", "
+ ToNullableCSharpStringLiteral(field.ExplicitName) + ", "
+ ToNullableCSharpStringLiteral(field.PrefixSegment) + ")";
var propertyNameLiteral = ToCSharpStringLiteral(field.PropertyName);
var explicitNameLiteral = ToNullableCSharpStringLiteral(field.ExplicitName);
var prefixSegmentLiteral = ToNullableCSharpStringLiteral(field.PrefixSegment);
var keyExpr =
$"global::Refit.GeneratedRequestRunner.BuildQueryKey({emission.SettingsLocal}, {propertyNameLiteral}, {explicitNameLiteral}, {prefixSegmentLiteral})";

_ = sb.Append(indent).Append("var ").Append(valueLocal).Append(" = ").Append(site.BodyExpr).Append(".@").Append(field.PropertyName).AppendLine(";");

Expand All @@ -155,7 +155,7 @@ internal static void AppendFormFieldUnroll(
}

// "!= null" (not the C# 9 "is not null" pattern) keeps the emitted null guard compilable down to C# 7.3.
var childIndent = indent + " ";
var childIndent = $"{indent} ";
_ = sb.Append(indent).Append("if (").Append(valueLocal).AppendLine(" != null)")
.Append(indent).AppendLine("{");
AppendFormEntryAdd(sb, in site, childIndent, keyExpr, valueExpr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ internal static (string Source, string? FieldName) BuildFormFieldsField(

// The getter lambda degrades to the consumer's language version: 'static' is C# 9 and the 'object?' cast
// annotation is C# 8, so both are omitted below those versions to keep generation compilable at the C# 7.3 floor.
var getterOpen = ">(" + (supportsStaticLambdas ? "static " : string.Empty)
+ "body => (" + (supportsNullable ? "object?" : "object") + ")body.@";
var getterOpen = $">({(supportsStaticLambdas ? "static " : string.Empty)}body => ({(supportsNullable ? "object?" : "object")})body.@";

var elements = BuildFormFieldElements(fields, bodyType, elementIndent, getterOpen);

Expand Down
6 changes: 3 additions & 3 deletions src/InterfaceStubGenerator.Shared/Emitter.Inline.Multipart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ internal static void AppendMultipartPart(
UniqueNameBuilder locals)
{
var bodyIndent = Indent(MethodBodyIndentation);
var valueExpression = "@" + parameter.Name;
var valueExpression = $"@{parameter.Name}";

// A reference-typed enumerable adds one part per element; a null collection contributes no parts, matching the
// reflection builder's skip of a null parameter value.
Expand All @@ -89,7 +89,7 @@ internal static void AppendMultipartPart(
.Append(bodyIndent).AppendLine("{")
.Append(bodyIndent).Append(" foreach (var ").Append(elementLocal).Append(" in ").Append(valueExpression).AppendLine(")")
.Append(bodyIndent).AppendLine(" {");
AppendMultipartAdd(sb, part, settingsLocal, contentLocal, elementLocal, bodyIndent + " ");
AppendMultipartAdd(sb, part, settingsLocal, contentLocal, elementLocal, $"{bodyIndent} ");
_ = sb.Append(bodyIndent).AppendLine(" }")
.Append(bodyIndent).AppendLine("}");
return;
Expand All @@ -100,7 +100,7 @@ internal static void AppendMultipartPart(
{
_ = sb.Append(bodyIndent).Append("if (").Append(valueExpression).AppendLine(" != null)")
.Append(bodyIndent).AppendLine("{");
AppendMultipartAdd(sb, part, settingsLocal, contentLocal, valueExpression, bodyIndent + " ");
AppendMultipartAdd(sb, part, settingsLocal, contentLocal, valueExpression, $"{bodyIndent} ");
_ = sb.Append(bodyIndent).AppendLine("}");
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ internal static List<PathReplacement> CollectPathReplacements(
foreach (var binding in bindings)
{
var bindingValue = BuildPathValueExpressionCore(
"@" + parameter.Name + "." + binding.PropertyClrName,
$"@{parameter.Name}.{binding.PropertyClrName}",
binding.PropertyType,
binding.ValueFormat,
binding.PropertyCanBeNull,
Expand Down
4 changes: 2 additions & 2 deletions src/InterfaceStubGenerator.Shared/Emitter.Inline.Path.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal static partial class Emitter
/// <c>ReadOnlySpan</c> overload accepts via the array-to-span conversion. The array element type is inferred from the
/// tuple values rather than stated, so no nullable reference annotation is emitted into a pre-C# 8 consumer.</remarks>
internal static string WrapPathReplacements(string tuples, bool supportsCollectionExpressions) =>
supportsCollectionExpressions ? ", [" + tuples + "]" : ", new[] { " + tuples + " }";
supportsCollectionExpressions ? $", [{tuples}]" : $", new[] {{ {tuples} }}";

/// <summary>Determines whether any path parameter passes its value through pre-encoded.</summary>
/// <param name="request">The parsed request model.</param>
Expand Down Expand Up @@ -124,7 +124,7 @@ internal static string BuildInlinePathExpression(
var template = ToCSharpStringLiteral(request.Path);
var settingsLocal = emission.SettingsLocal;
var allowUnmatched = $"{settingsLocal}.AllowUnmatchedRouteParameters";
var valueExpression = "@" + pathParameter.Value.Name;
var valueExpression = $"@{pathParameter.Value.Name}";
_ = parameterInfoNames.TryGetValue(pathParameter.Value.Name, out var providerField);
const string runner = "global::Refit.GeneratedRequestRunner.BuildRequestPath";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ internal static void AppendDictionaryQueryStatements(
var dictionary = query.Dictionary!;
var bodyIndent = Indent(MethodBodyIndentation);
var guarded = parameter.CanBeNull;
var indent = guarded ? bodyIndent + " " : bodyIndent;
var entryLocal = emission.QueryValueLocal + "_entry";
var keyLocal = emission.QueryValueLocal + "_key";
var indent = guarded ? $"{bodyIndent} " : bodyIndent;
var entryLocal = $"{emission.QueryValueLocal}_entry";
var keyLocal = $"{emission.QueryValueLocal}_key";
var valueLocal = emission.QueryValueLocal + ValueLocalSuffix;

if (guarded)
Expand All @@ -44,7 +44,7 @@ internal static void AppendDictionaryQueryStatements(
_ = sb.Append(indent).Append(ForeachVarKeyword).Append(entryLocal).Append(" in @").Append(parameter.Name).AppendLine(")")
.Append(indent).AppendLine("{");

var entryIndent = indent + " ";
var entryIndent = $"{indent} ";
_ = sb.Append(entryIndent).Append("var ").Append(valueLocal).Append(" = ").Append(entryLocal).AppendLine(".Value;");

var valueIndent = entryIndent;
Expand All @@ -53,7 +53,7 @@ internal static void AppendDictionaryQueryStatements(
// The reflection builder skips an entry whose value is null before it ever formats the key.
_ = sb.Append(entryIndent).Append("if (").Append(valueLocal).AppendLine(NotNullCheckSuffix)
.Append(entryIndent).AppendLine("{");
valueIndent = entryIndent + " ";
valueIndent = $"{entryIndent} ";
}

var entry = new DictionaryEntrySite(entryLocal, keyLocal, valueLocal, valueIndent);
Expand Down Expand Up @@ -93,7 +93,7 @@ internal static void AppendDictionaryEntryStatements(
var (entryLocal, keyLocal, valueLocal, indent) = entry;
var keyTypeOf = $"typeof({dictionary.KeyTypeName})";
var customKey = EmitFormatUrlParameter($"{entryLocal}.Key", keyTypeOf, keyTypeOf, emission);
var fastKey = BuildFastFormatExpression(entryLocal + ".Key", dictionary.KeyFormat, emission);
var fastKey = BuildFastFormatExpression($"{entryLocal}.Key", dictionary.KeyFormat, emission);
var keyExpression = fastKey is null
? customKey
: $"{emission.UseDefaultFormattingLocal} ? ({fastKey}) : {customKey}";
Expand All @@ -102,7 +102,7 @@ internal static void AppendDictionaryEntryStatements(
.Append(indent).Append("if (!string.IsNullOrWhiteSpace(").Append(keyLocal).AppendLine("))")
.Append(indent).AppendLine("{");

var innerIndent = indent + " ";
var innerIndent = $"{indent} ";
if (dictionary.ValueProperties is { } valueProperties)
{
AppendDictionaryValueFlatten(sb, parameter, query, providerField, emission, entry, valueProperties);
Expand Down Expand Up @@ -146,12 +146,12 @@ internal static void AppendDictionaryValueFlatten(
{
var dictionary = query.Dictionary!;
var (_, keyLocal, valueLocal, entryIndent) = entry;
var indent = entryIndent + " ";
var indent = $"{entryIndent} ";

var parentKeyExpression = keyLocal;
if (dictionary.PrefixSegment is { } prefix)
{
var parentKeyLocal = keyLocal + "_prefixed";
var parentKeyLocal = $"{keyLocal}_prefixed";
_ = sb.Append(indent).Append("var ").Append(parentKeyLocal).Append(" = ")
.Append(ToCSharpStringLiteral(prefix)).Append(" + ").Append(keyLocal).AppendLine(";");
parentKeyExpression = parentKeyLocal;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ internal static void AppendEnumFormatterSource(
{
var memberIndent = Indent(MethodMemberIndentation);
var bodyIndent = Indent(MethodBodyIndentation);
var caseIndent = bodyIndent + " ";
var caseIndent = $"{bodyIndent} ";
var format = valueFormat.Format;

_ = memberSb.AppendLine()
Expand Down
Loading
Loading