-
Notifications
You must be signed in to change notification settings - Fork 4k
/
ITypeSymbol.cs
256 lines (222 loc) · 11.7 KB
/
ITypeSymbol.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
250
251
252
253
254
255
256
// 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// Represents a type.
/// </summary>
/// <remarks>
/// This interface is reserved for implementation by its associated APIs. We reserve the right to
/// change it in the future.
/// </remarks>
public interface ITypeSymbol : INamespaceOrTypeSymbol
{
/// <summary>
/// An enumerated value that identifies whether this type is an array, pointer, enum, and so on.
/// </summary>
TypeKind TypeKind { get; }
/// <summary>
/// The declared base type of this type, or null. The object type, interface types,
/// and pointer types do not have a base type. The base type of a type parameter
/// is its effective base class.
/// </summary>
INamedTypeSymbol? BaseType { get; }
/// <summary>
/// Gets the set of interfaces that this type directly implements. This set does not include
/// interfaces that are base interfaces of directly implemented interfaces. This does
/// include the interfaces declared as constraints on type parameters.
/// </summary>
ImmutableArray<INamedTypeSymbol> Interfaces { get; }
/// <summary>
/// The list of all interfaces of which this type is a declared subtype, excluding this type
/// itself. This includes all declared base interfaces, all declared base interfaces of base
/// types, and all declared base interfaces of those results (recursively). This also is the effective
/// interface set of a type parameter. Each result
/// appears exactly once in the list. This list is topologically sorted by the inheritance
/// relationship: if interface type A extends interface type B, then A precedes B in the
/// list. This is not quite the same as "all interfaces of which this type is a proper
/// subtype" because it does not take into account variance: AllInterfaces for
/// IEnumerable<string> will not include IEnumerable<object>.
/// </summary>
ImmutableArray<INamedTypeSymbol> AllInterfaces { get; }
/// <summary>
/// True if this type is known to be a reference type. It is never the case that
/// <see cref="IsReferenceType"/> and <see cref="IsValueType"/> both return true. However, for an unconstrained type
/// parameter, <see cref="IsReferenceType"/> and <see cref="IsValueType"/> will both return false.
/// </summary>
bool IsReferenceType { get; }
/// <summary>
/// True if this type is known to be a value type. It is never the case that
/// <see cref="IsReferenceType"/> and <see cref="IsValueType"/> both return true. However, for an unconstrained type
/// parameter, <see cref="IsReferenceType"/> and <see cref="IsValueType"/> will both return false.
/// </summary>
bool IsValueType { get; }
/// <summary>
/// Is this a symbol for an anonymous type (including anonymous VB delegate).
/// </summary>
bool IsAnonymousType { get; }
/// <summary>
/// Is this a symbol for a tuple .
/// </summary>
bool IsTupleType { get; }
/// <summary>
/// True if the type represents a native integer. In C#, the types represented
/// by language keywords 'nint' and 'nuint'.
/// </summary>
bool IsNativeIntegerType { get; }
/// <summary>
/// The original definition of this symbol. If this symbol is constructed from another
/// symbol by type substitution then <see cref="OriginalDefinition"/> gets the original symbol as it was defined in
/// source or metadata.
/// </summary>
new ITypeSymbol OriginalDefinition { get; }
/// <summary>
/// An enumerated value that identifies certain 'special' types such as <see cref="System.Object"/>.
/// Returns <see cref="Microsoft.CodeAnalysis.SpecialType.None"/> if the type is not special.
/// </summary>
SpecialType SpecialType { get; }
/// <summary>
/// Returns the corresponding symbol in this type or a base type that implements
/// interfaceMember (either implicitly or explicitly), or null if no such symbol exists
/// (which might be either because this type doesn't implement the container of
/// interfaceMember, or this type doesn't supply a member that successfully implements
/// interfaceMember).
/// </summary>
/// <param name="interfaceMember">
/// Must be a non-null interface property, method, or event.
/// </param>
ISymbol? FindImplementationForInterfaceMember(ISymbol interfaceMember);
/// <summary>
/// True if the type is ref-like, meaning it follows rules similar to CLR by-ref variables. False if the type
/// is not ref-like or if the language has no concept of ref-like types.
/// </summary>
/// <remarks>
/// <see cref="Span{T}" /> is a commonly used ref-like type.
/// </remarks>
bool IsRefLikeType { get; }
/// <summary>
/// True if the type is unmanaged according to language rules. False if managed or if the language
/// has no concept of unmanaged types.
/// </summary>
bool IsUnmanagedType { get; }
/// <summary>
/// True if the type is readonly.
/// </summary>
bool IsReadOnly { get; }
/// <summary>
/// True if the type is a record.
/// </summary>
bool IsRecord { get; }
/// <summary>
/// Converts an <c>ITypeSymbol</c> and a nullable flow state to a string representation.
/// </summary>
/// <param name="topLevelNullability">The top-level nullability to use for formatting.</param>
/// <param name="format">Format or null for the default.</param>
/// <returns>A formatted string representation of the symbol with the given nullability.</returns>
string ToDisplayString(NullableFlowState topLevelNullability, SymbolDisplayFormat? format = null);
/// <summary>
/// Converts a symbol to an array of string parts, each of which has a kind. Useful
/// for colorizing the display string.
/// </summary>
/// <param name="topLevelNullability">The top-level nullability to use for formatting.</param>
/// <param name="format">Format or null for the default.</param>
/// <returns>A read-only array of string parts.</returns>
ImmutableArray<SymbolDisplayPart> ToDisplayParts(NullableFlowState topLevelNullability, SymbolDisplayFormat? format = null);
/// <summary>
/// Converts a symbol to a string that can be displayed to the user. May be tailored to a
/// specific location in the source code.
/// </summary>
/// <param name="semanticModel">Binding information (for determining names appropriate to
/// the context).</param>
/// <param name="topLevelNullability">The top-level nullability to use for formatting.</param>
/// <param name="position">A position in the source code (context).</param>
/// <param name="format">Formatting rules - null implies <see cref="SymbolDisplayFormat.MinimallyQualifiedFormat"/></param>
/// <returns>A formatted string that can be displayed to the user.</returns>
string ToMinimalDisplayString(
SemanticModel semanticModel,
NullableFlowState topLevelNullability,
int position,
SymbolDisplayFormat? format = null);
/// <summary>
/// Convert a symbol to an array of string parts, each of which has a kind. May be tailored
/// to a specific location in the source code. Useful for colorizing the display string.
/// </summary>
/// <param name="semanticModel">Binding information (for determining names appropriate to
/// the context).</param>
/// <param name="topLevelNullability">The top-level nullability to use for formatting.</param>
/// <param name="position">A position in the source code (context).</param>
/// <param name="format">Formatting rules - null implies <see cref="SymbolDisplayFormat.MinimallyQualifiedFormat"/></param>
/// <returns>A read-only array of string parts.</returns>
ImmutableArray<SymbolDisplayPart> ToMinimalDisplayParts(
SemanticModel semanticModel,
NullableFlowState topLevelNullability,
int position,
SymbolDisplayFormat? format = null);
/// <summary>
/// Nullable annotation associated with the type, or <see cref="NullableAnnotation.None"/> if there are none.
/// </summary>
NullableAnnotation NullableAnnotation { get; }
/// <summary>
/// Returns the same type as this type but with the given nullable annotation.
/// </summary>
/// <param name="nullableAnnotation">The nullable annotation to use</param>
ITypeSymbol WithNullableAnnotation(NullableAnnotation nullableAnnotation);
}
// Intentionally not extension methods. We don't want them ever be called for symbol classes
// Once Default Interface Implementations are supported, we can move these methods into the interface.
internal static class ITypeSymbolHelpers
{
internal static bool IsNullableType([NotNullWhen(returnValue: true)] ITypeSymbol? typeOpt)
{
return typeOpt?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T;
}
internal static bool IsNullableOfBoolean([NotNullWhen(returnValue: true)] ITypeSymbol? type)
{
return IsNullableType(type) && IsBooleanType(GetNullableUnderlyingType(type));
}
internal static ITypeSymbol GetNullableUnderlyingType(ITypeSymbol type)
{
Debug.Assert(IsNullableType(type));
return ((INamedTypeSymbol)type).TypeArguments[0];
}
internal static bool IsBooleanType([NotNullWhen(returnValue: true)] ITypeSymbol? type)
{
return type?.SpecialType == SpecialType.System_Boolean;
}
internal static bool IsObjectType([NotNullWhen(returnValue: true)] ITypeSymbol? type)
{
return type?.SpecialType == SpecialType.System_Object;
}
internal static bool IsSignedIntegralType([NotNullWhen(returnValue: true)] ITypeSymbol? type)
{
return type?.SpecialType.IsSignedIntegralType() == true;
}
internal static bool IsUnsignedIntegralType([NotNullWhen(returnValue: true)] ITypeSymbol? type)
{
return type?.SpecialType.IsUnsignedIntegralType() == true;
}
internal static bool IsNumericType([NotNullWhen(returnValue: true)] ITypeSymbol? type)
{
return type?.SpecialType.IsNumericType() == true;
}
internal static ITypeSymbol? GetEnumUnderlyingType(ITypeSymbol? type)
{
return (type as INamedTypeSymbol)?.EnumUnderlyingType;
}
[return: NotNullIfNotNull(parameterName: nameof(type))]
internal static ITypeSymbol? GetEnumUnderlyingTypeOrSelf(ITypeSymbol? type)
{
return GetEnumUnderlyingType(type) ?? type;
}
internal static bool IsDynamicType([NotNullWhen(returnValue: true)] ITypeSymbol? type)
{
return type?.Kind == SymbolKind.DynamicType;
}
}
}