-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Expand file tree
/
Copy pathProxyMethodDescription.cs
More file actions
172 lines (152 loc) · 9.43 KB
/
Copy pathProxyMethodDescription.cs
File metadata and controls
172 lines (152 loc) · 9.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Orleans.CodeGenerator.SyntaxGeneration;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace Orleans.CodeGenerator;
/// <summary>
/// Describes an invokable method on a proxy interface.
/// </summary>
[DebuggerDisplay("{Method} (from {ProxyInterface})")]
internal class ProxyMethodDescription : IEquatable<ProxyMethodDescription>
{
private readonly GeneratedInvokableDescription _originalInvokable;
public static ProxyMethodDescription Create(
ProxyInterfaceDescription proxyInterface,
GeneratedInvokableDescription generatedInvokable,
IMethodSymbol method)
=> new(proxyInterface, generatedInvokable, method);
private ProxyMethodDescription(ProxyInterfaceDescription proxyInterface, GeneratedInvokableDescription generatedInvokable, IMethodSymbol method)
{
_originalInvokable = generatedInvokable;
Method = method;
ProxyInterface = proxyInterface;
TypeParameters = new List<(string Name, ITypeParameterSymbol Parameter)>();
MethodTypeParameters = new List<(string Name, ITypeParameterSymbol Parameter)>();
TypeParametersWithArguments = [.. Method.ContainingType.GetAllTypeParameters().Zip(method.ContainingType.GetAllTypeArguments(), (a, b) => (a, b))];
var names = new HashSet<string>(StringComparer.Ordinal);
foreach (var (typeParameter, typeArgument) in TypeParametersWithArguments)
{
var tpName = GetTypeParameterName(names, typeParameter);
TypeParameters.Add((tpName, typeParameter));
}
foreach (var typeParameter in Method.TypeParameters)
{
var tpName = GetTypeParameterName(names, typeParameter);
TypeParameters.Add((tpName, typeParameter));
MethodTypeParameters.Add((tpName, typeParameter));
}
TypeParameterSubstitutions = new(SymbolEqualityComparer.Default);
foreach (var (name, parameter) in TypeParameters)
{
TypeParameterSubstitutions[parameter] = name;
}
foreach (var (parameter, arg) in TypeParametersWithArguments)
{
TypeParameterSubstitutions[parameter] = arg.ToDisplayName();
}
GeneratedInvokable = new ConstructedGeneratedInvokableDescription(generatedInvokable, this);
static string GetTypeParameterName(HashSet<string> names, ITypeParameterSymbol typeParameter)
{
var count = 0;
var result = typeParameter.Name;
while (names.Contains(result))
{
result = $"{typeParameter.Name}_{++count}";
}
names.Add(result);
return result.EscapeIdentifier();
}
}
public ProxyGenerationContext GenerationContext => InvokableMethod.GenerationContext;
public InvokableMethodDescription InvokableMethod => _originalInvokable.MethodDescription;
public ConstructedGeneratedInvokableDescription GeneratedInvokable { get; }
public ProxyInterfaceDescription ProxyInterface { get; }
public IMethodSymbol Method { get; }
public InvokableMethodId InvokableId { get; }
public List<(string Name, ITypeParameterSymbol Parameter)> TypeParameters { get; }
public List<(string Name, ITypeParameterSymbol Parameter)> MethodTypeParameters { get; }
public ImmutableArray<(ITypeParameterSymbol Parameter, ITypeSymbol Argument)> TypeParametersWithArguments { get; }
public Dictionary<ITypeParameterSymbol, string> TypeParameterSubstitutions { get; }
/// <summary>
/// Mapping of method return types to invokable base type. The code generator will create a derived type with the method arguments as fields.
/// </summary>
public IReadOnlyDictionary<INamedTypeSymbol, INamedTypeSymbol> InvokableBaseTypes => InvokableMethod.InvokableBaseTypes;
public InvokableMethodId InvokableKey => InvokableMethod.Key;
public List<(string, TypedConstant)> CustomInitializerMethods => InvokableMethod.CustomInitializerMethods;
public string GeneratedMethodId => InvokableMethod.GeneratedMethodId;
public string MethodId => InvokableMethod.MethodId;
public bool HasAlias => InvokableMethod.HasAlias;
public long? ResponseTimeoutTicks => InvokableMethod.ResponseTimeoutTicks;
public override int GetHashCode() => ProxyInterface.GetHashCode() * 17 ^ InvokableMethod.GetHashCode();
public bool Equals(ProxyMethodDescription other) => other is not null && InvokableMethod.Key.Equals(other.InvokableKey) && ProxyInterface.Equals(other.ProxyInterface);
public override bool Equals(object other) => other is ProxyMethodDescription imd && Equals(imd);
internal sealed class ConstructedGeneratedInvokableDescription : ISerializableTypeDescription
{
private readonly GeneratedInvokableDescription _invokableDescription;
private readonly ProxyMethodDescription _proxyMethod;
public ConstructedGeneratedInvokableDescription(GeneratedInvokableDescription invokableDescription, ProxyMethodDescription proxyMethod)
{
_invokableDescription = invokableDescription;
_proxyMethod = proxyMethod;
Members = new List<IMemberDescription>(invokableDescription.Members.Count);
var proxyMethodParameters = proxyMethod.Method.Parameters;
foreach (var member in invokableDescription.Members.OfType<InvokableGenerator.MethodParameterFieldDescription>())
{
Members.Add(new InvokableGenerator.MethodParameterFieldDescription(
member.LibraryTypes,
proxyMethodParameters[member.ParameterOrdinal],
member.FieldName,
member.FieldId,
proxyMethod.TypeParameterSubstitutions,
member.IsSerializable));
}
}
public Accessibility Accessibility => _invokableDescription.Accessibility;
public TypeSyntax TypeSyntax => field ??= CreateTypeSyntax();
public TypeSyntax OpenTypeSyntax => _invokableDescription.OpenTypeSyntax;
public bool HasComplexBaseType => BaseType is { SpecialType: not SpecialType.System_Object };
public bool IncludePrimaryConstructorParameters => false;
public INamedTypeSymbol BaseType => _invokableDescription.BaseType;
public TypeSyntax BaseTypeSyntax => field ??= BaseType.ToTypeSyntax(_proxyMethod.TypeParameterSubstitutions);
public string Namespace => GeneratedNamespace;
public string GeneratedNamespace => _invokableDescription.GeneratedNamespace;
public string Name => _invokableDescription.Name;
public bool IsValueType => _invokableDescription.IsValueType;
public bool IsSealedType => _invokableDescription.IsSealedType;
public bool IsAbstractType => _invokableDescription.IsAbstractType;
public bool IsEnumType => _invokableDescription.IsEnumType;
public bool IsGenericType => TypeParameters.Count > 0;
public List<IMemberDescription> Members { get; }
public Compilation Compilation => MethodDescription.GenerationContext.Compilation;
public bool IsEmptyConstructable => ActivatorConstructorParameters is not { Count: > 0 };
public bool UseActivator => ActivatorConstructorParameters is { Count: > 0 };
public bool TrackReferences => _invokableDescription.TrackReferences;
public bool OmitDefaultMemberValues => _invokableDescription.OmitDefaultMemberValues;
public List<(string Name, ITypeParameterSymbol Parameter)> TypeParameters => _proxyMethod.TypeParameters;
public List<INamedTypeSymbol> SerializationHooks => _invokableDescription.SerializationHooks;
public bool IsShallowCopyable => _invokableDescription.IsShallowCopyable;
public bool IsUnsealedImmutable => _invokableDescription.IsUnsealedImmutable;
public bool IsImmutable => _invokableDescription.IsImmutable;
public bool IsExceptionType => _invokableDescription.IsExceptionType;
public List<TypeSyntax> ActivatorConstructorParameters => _invokableDescription.ActivatorConstructorParameters;
public bool UsesInvokablePool => _invokableDescription.UsesInvokablePool;
public bool HasActivatorConstructor => UseActivator;
public string? ReturnValueInitializerMethod => _invokableDescription.ReturnValueInitializerMethod;
public InvokableMethodDescription MethodDescription => _invokableDescription.MethodDescription;
public ExpressionSyntax GetObjectCreationExpression() => ObjectCreationExpression(TypeSyntax, ArgumentList(), null);
private TypeSyntax CreateTypeSyntax()
{
var simpleName = InvokableGenerator.GetSimpleClassName(MethodDescription);
var subs = _proxyMethod.TypeParameterSubstitutions;
return (TypeParameters, Namespace) switch
{
({ Count: > 0 }, { Length: > 0 }) => QualifiedName(ParseName(Namespace), GenericName(Identifier(simpleName), TypeArgumentList(SeparatedList<TypeSyntax>(TypeParameters.Select(p => IdentifierName(subs[p.Parameter])))))),
({ Count: > 0 }, _) => GenericName(Identifier(simpleName), TypeArgumentList(SeparatedList<TypeSyntax>(TypeParameters.Select(p => IdentifierName(subs[p.Parameter]))))),
(_, { Length: > 0 }) => QualifiedName(ParseName(Namespace), IdentifierName(simpleName)),
_ => IdentifierName(simpleName),
};
}
}
}