Skip to content

Commit 136467c

Browse files
committed
Move Builder.GetParameterDisplayString into the RoslynExtensions class; refactor
This centralises the rendering logic plus simplifies the implementation to use `ITypeSymbol.WithNullableAnnotation` and hands the rendering off to the default `ToDisplayString` implementation
1 parent cf67fd7 commit 136467c

3 files changed

Lines changed: 43 additions & 29 deletions

File tree

AutomaticInterface/AutomaticInterface/RoslynExtensions.cs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using System.Text;
45
using System.Text.RegularExpressions;
@@ -85,8 +86,36 @@ List<string> generatedInterfaceNames
8586
public static string ToDisplayString(
8687
this IParameterSymbol symbol,
8788
SymbolDisplayFormat displayFormat,
89+
bool nullableContextEnabled,
8890
List<string> generatedInterfaceNames
89-
) => ToDisplayString((ISymbol)symbol, displayFormat, generatedInterfaceNames);
91+
)
92+
{
93+
string? RenderTypeSymbolWithNullableAnnotation(SymbolDisplayPart part) =>
94+
part.Symbol is ITypeSymbol typeSymbol
95+
? typeSymbol
96+
.WithNullableAnnotation(NullableAnnotation.Annotated)
97+
.ToDisplayString(displayFormat)
98+
: null;
99+
100+
// Special case for reference parameters with default value null (e.g. string x = null) - the nullable
101+
// context isn't applied automatically, so it must be forced explicitly
102+
var forceNullableAnnotation =
103+
nullableContextEnabled
104+
&& symbol
105+
is {
106+
Type.IsReferenceType: true,
107+
HasExplicitDefaultValue: true,
108+
ExplicitDefaultValue: null
109+
}
110+
&& symbol.NullableAnnotation != NullableAnnotation.Annotated;
111+
112+
return ToDisplayString(
113+
symbol,
114+
displayFormat,
115+
generatedInterfaceNames,
116+
forceNullableAnnotation ? RenderTypeSymbolWithNullableAnnotation : null
117+
);
118+
}
90119

91120
public static string ToDisplayString(
92121
this ITypeSymbol symbol,
@@ -100,7 +129,8 @@ List<string> generatedInterfaceNames
100129
private static string ToDisplayString(
101130
this ISymbol symbol,
102131
SymbolDisplayFormat displayFormat,
103-
List<string> generatedInterfaceNames
132+
List<string> generatedInterfaceNames,
133+
Func<SymbolDisplayPart, string?>? customRenderDisplayPart = null
104134
)
105135
{
106136
var displayStringBuilder = new StringBuilder();
@@ -122,7 +152,8 @@ List<string> generatedInterfaceNames
122152
}
123153
else
124154
{
125-
displayStringBuilder.Append(part);
155+
var customRender = customRenderDisplayPart?.Invoke(part);
156+
displayStringBuilder.Append(customRender ?? part.ToString());
126157
}
127158
}
128159

AutomaticInterface/DotnetAutomaticInterface/Builder.cs

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4-
using System.Text;
54
using Microsoft.CodeAnalysis;
65
using Microsoft.CodeAnalysis.CSharp;
76
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -163,7 +162,13 @@ List<string> generatedInterfaceNames
163162

164163
var paramResult = new HashSet<string>();
165164
method
166-
.Parameters.Select(p => GetParameterDisplayString(p, codeGenerator.HasNullable))
165+
.Parameters.Select(p =>
166+
p.ToDisplayString(
167+
FullyQualifiedDisplayFormat,
168+
codeGenerator.HasNullable,
169+
generatedInterfaceNames
170+
)
171+
)
167172
.ToList()
168173
.ForEach(x => paramResult.Add(x));
169174

@@ -234,28 +239,6 @@ private static bool IsNullable(ITypeSymbol typeSymbol)
234239
return false;
235240
}
236241

237-
private static string GetParameterDisplayString(
238-
IParameterSymbol param,
239-
bool nullableContextEnabled
240-
)
241-
{
242-
// If this parameter has default value null and we're enabling the nullable context, we need to force the nullable annotation if there isn't one already
243-
if (
244-
param.HasExplicitDefaultValue
245-
&& param.ExplicitDefaultValue is null
246-
&& param.NullableAnnotation != NullableAnnotation.Annotated
247-
&& param.Type.IsReferenceType
248-
&& nullableContextEnabled
249-
)
250-
{
251-
var addNullable = new AddNullableAnnotationSyntaxRewriter();
252-
return addNullable
253-
.Visit(param.DeclaringSyntaxReferences.First().GetSyntax())
254-
.ToFullString();
255-
}
256-
return param.ToDisplayString(FullyQualifiedDisplayFormat);
257-
}
258-
259242
private static void AddEventsToInterface(
260243
List<ISymbol> members,
261244
InterfaceBuilder codeGenerator,

AutomaticInterface/Tests/Methods/Methods.WorksWithMixedOptionalNullParameters.verified.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace AutomaticInterfaceExample
1313
public partial interface IDemoClass
1414
{
1515
/// <inheritdoc cref="AutomaticInterfaceExample.DemoClass.TryStartTransaction(int?, int, string, Func{int, int})" />
16-
bool TryStartTransaction(int? param, int param2 = 0, string? data = null, Func<int, int>? func = null);
16+
bool TryStartTransaction(int? param, int param2 = 0, string? data = null, Func<int, int> func = null);
1717

1818
}
1919
}

0 commit comments

Comments
 (0)