forked from dotnet/roslyn
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSourceMethodSymbol.cs
249 lines (217 loc) · 12.3 KB
/
SourceMethodSymbol.cs
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
/// <summary>
/// Base class to represent all source method-like symbols. This includes
/// things like ordinary methods and constructors, and functions
/// like lambdas and local functions.
/// </summary>
internal abstract partial class SourceMethodSymbol : MethodSymbol
{
/// <summary>
/// If there are no constraints, returns an empty immutable array. Otherwise, returns an immutable
/// array of types, indexed by the constrained type parameter in <see cref="MethodSymbol.TypeParameters"/>.
/// </summary>
public abstract ImmutableArray<ImmutableArray<TypeWithAnnotations>> GetTypeParameterConstraintTypes();
/// <summary>
/// If there are no constraints, returns an empty immutable array. Otherwise, returns an immutable
/// array of kinds, indexed by the constrained type parameter in <see cref="MethodSymbol.TypeParameters"/>.
/// </summary>
public abstract ImmutableArray<TypeParameterConstraintKind> GetTypeParameterConstraintKinds();
protected static void ReportBadRefToken(TypeSyntax returnTypeSyntax, BindingDiagnosticBag diagnostics)
{
if (!returnTypeSyntax.HasErrors)
{
var refKeyword = returnTypeSyntax.GetFirstToken();
diagnostics.Add(ErrorCode.ERR_UnexpectedToken, refKeyword.GetLocation(), refKeyword.ToString());
}
}
protected bool AreContainingSymbolLocalsZeroed
{
get
{
if (ContainingSymbol is SourceMethodSymbol method)
{
return method.AreLocalsZeroed;
}
else if (ContainingType is SourceMemberContainerTypeSymbol type)
{
return type.AreLocalsZeroed;
}
else
{
// Sometimes a source method symbol can be contained in a non-source symbol.
// For example in EE. We aren't concerned with respecting SkipLocalsInit in such cases.
return true;
}
}
}
internal void ReportAsyncParameterErrors(BindingDiagnosticBag diagnostics, Location location)
{
var parameters = !this.IsStatic ? this.GetParametersIncludingExtensionParameter() : Parameters;
foreach (var parameter in parameters)
{
bool isExtensionParameter = parameter.IsExtensionParameter();
if (parameter.RefKind != RefKind.None)
{
diagnostics.Add(ErrorCode.ERR_BadAsyncArgType, getLocation(parameter, location, isExtensionParameter));
}
else if (parameter.Type.IsPointerOrFunctionPointer() && !isExtensionParameter)
{
// We already reported an error elsewhere if the receiver parameter of an extension is a pointer type.
diagnostics.Add(ErrorCode.ERR_UnsafeAsyncArgType, getLocation(parameter, location, isExtensionParameter));
}
else if (parameter.Type.IsRestrictedType())
{
diagnostics.Add(ErrorCode.ERR_BadSpecialByRefParameter, getLocation(parameter, location, isExtensionParameter), parameter.Type);
}
}
static Location getLocation(ParameterSymbol parameter, Location location, bool isReceiverParameter)
{
return isReceiverParameter
? location
: parameter.TryGetFirstLocation() ?? location;
}
}
protected override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable();
internal sealed override bool UseUpdatedEscapeRules => ContainingModule.UseUpdatedEscapeRules;
internal override bool HasAsyncMethodBuilderAttribute(out TypeSymbol? builderArgument)
{
return SourceMemberContainerTypeSymbol.HasAsyncMethodBuilderAttribute(this, out builderArgument);
}
internal sealed override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder<CSharpAttributeData> attributes)
{
base.AddSynthesizedAttributes(moduleBuilder, ref attributes);
AddSynthesizedAttributes(this, moduleBuilder, ref attributes);
}
internal static void AddSynthesizedAttributes(MethodSymbol target, PEModuleBuilder moduleBuilder, ref ArrayBuilder<CSharpAttributeData> attributes)
{
Debug.Assert(target is not (LambdaSymbol or LocalFunctionSymbol));
if (target.IsDeclaredReadOnly && !target.ContainingType.IsReadOnly)
{
AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeIsReadOnlyAttribute(target));
}
var compilation = target.DeclaringCompilation;
if (compilation.ShouldEmitNullableAttributes(target) &&
target.ShouldEmitNullableContextValue(out byte nullableContextValue))
{
AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeNullableContextAttribute(target, nullableContextValue));
}
if (target.RequiresExplicitOverride(out _))
{
// On platforms where it is present, add PreserveBaseOverridesAttribute when a methodimpl is used to override a class method.
AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizePreserveBaseOverridesAttribute());
}
bool isAsync = target.IsAsync;
bool isIterator = target.IsIterator;
if ((isAsync || isIterator) && !target.GetIsNewExtensionMember())
{
// The async state machine type is not synthesized until the async method body is rewritten. If we are
// only emitting metadata the method body will not have been rewritten, and the async state machine
// type will not have been created. In this case, omit the attribute.
if (moduleBuilder.CompilationState.TryGetStateMachineType(target, out NamedTypeSymbol? stateMachineType))
{
var arg = new TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type),
TypedConstantKind.Type, stateMachineType.GetUnboundGenericTypeOrSelf());
if (isAsync && isIterator)
{
AddSynthesizedAttribute(ref attributes,
compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorStateMachineAttribute__ctor,
ImmutableArray.Create(arg)));
}
else if (isAsync)
{
AddSynthesizedAttribute(ref attributes,
compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor,
ImmutableArray.Create(arg)));
}
else if (isIterator)
{
AddSynthesizedAttribute(ref attributes,
compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor,
ImmutableArray.Create(arg)));
}
}
if (isAsync && !isIterator)
{
// Regular async (not async-iterator) kick-off method calls MoveNext, which contains user code.
// This means we need to emit DebuggerStepThroughAttribute in order
// to have correct stepping behavior during debugging.
AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDebuggerStepThroughAttribute());
}
}
// Do not generate CompilerGeneratedAttribute for members of compiler-generated types:
if (((target.IsImplicitlyDeclared && target is not SourceFieldLikeEventSymbol.SourceEventDefinitionAccessorSymbol { PartialImplementationPart.IsImplicitlyDeclared: false }) ||
target is SourcePropertyAccessorSymbol { IsAutoPropertyAccessor: true }) &&
!target.ContainingType.IsImplicitlyDeclared &&
target is SynthesizedMethodBaseSymbol or
SourcePropertyAccessorSymbol or
SynthesizedSourceOrdinaryMethodSymbol or
SynthesizedRecordEqualityOperatorBase or
SynthesizedEventAccessorSymbol or
SourceFieldLikeEventSymbol.SourceEventDefinitionAccessorSymbol)
{
Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor));
AddSynthesizedAttribute(ref attributes,
compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor));
}
if (target is SourceConstructorSymbolBase)
{
AddRequiredMembersMarkerAttributes(ref attributes, target);
}
if (target.IsExtensionMethod)
{
// No need to check if [Extension] attribute was explicitly set since
// we'll issue CS1112 error in those cases and won't generate IL.
AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(
WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor));
}
if (target is SourcePropertyAccessorSymbol { AssociatedSymbol: SourcePropertySymbolBase property })
{
if (!target.NotNullMembers.IsEmpty)
{
foreach (var attributeData in property.MemberNotNullAttributeIfExists)
{
AddSynthesizedAttribute(ref attributes, SynthesizedAttributeData.Create(attributeData));
}
}
if (!target.NotNullWhenTrueMembers.IsEmpty || !target.NotNullWhenFalseMembers.IsEmpty)
{
foreach (var attributeData in property.MemberNotNullWhenAttributeIfExists)
{
AddSynthesizedAttribute(ref attributes, SynthesizedAttributeData.Create(attributeData));
}
}
}
if (target is MethodToClassRewriter.BaseMethodWrapperSymbol)
{
AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_DebuggerHiddenAttribute__ctor));
}
if (IsInstanceIncrementDecrementOrCompoundAssignmentOperator(target))
{
AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor,
ImmutableArray.Create(new TypedConstant(compilation.GetSpecialType(SpecialType.System_String), TypedConstantKind.Primitive, nameof(CompilerFeatureRequiredFeatures.UserDefinedCompoundAssignmentOperators)))
));
}
}
internal static bool IsInstanceIncrementDecrementOrCompoundAssignmentOperator(MethodSymbol target)
{
if (target.MethodKind == MethodKind.UserDefinedOperator && !target.IsStatic)
{
SyntaxKind syntaxKind = SyntaxFacts.GetOperatorKind(target.Name);
return syntaxKind is (SyntaxKind.PlusPlusToken or SyntaxKind.MinusMinusToken) ||
SyntaxFacts.IsOverloadableCompoundAssignmentOperator(syntaxKind);
}
return false;
}
}
}