1 | // Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team |
---|
2 | // |
---|
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this |
---|
4 | // software and associated documentation files (the "Software"), to deal in the Software |
---|
5 | // without restriction, including without limitation the rights to use, copy, modify, merge, |
---|
6 | // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
---|
7 | // to whom the Software is furnished to do so, subject to the following conditions: |
---|
8 | // |
---|
9 | // The above copyright notice and this permission notice shall be included in all copies or |
---|
10 | // substantial portions of the Software. |
---|
11 | // |
---|
12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
---|
13 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
---|
14 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
---|
15 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
---|
16 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
---|
17 | // DEALINGS IN THE SOFTWARE. |
---|
18 | |
---|
19 | using System; |
---|
20 | using System.Collections.Generic; |
---|
21 | using System.Linq; |
---|
22 | using ICSharpCode.NRefactory.Documentation; |
---|
23 | using ICSharpCode.NRefactory.Utils; |
---|
24 | |
---|
25 | namespace ICSharpCode.NRefactory.TypeSystem.Implementation |
---|
26 | { |
---|
27 | /// <summary> |
---|
28 | /// Default implementation of <see cref="ITypeDefinition"/>. |
---|
29 | /// </summary> |
---|
30 | public class DefaultResolvedTypeDefinition : ITypeDefinition |
---|
31 | { |
---|
32 | readonly ITypeResolveContext parentContext; |
---|
33 | readonly IUnresolvedTypeDefinition[] parts; |
---|
34 | Accessibility accessibility = Accessibility.Internal; |
---|
35 | bool isAbstract, isSealed, isShadowing; |
---|
36 | bool isSynthetic = true; // true if all parts are synthetic |
---|
37 | |
---|
38 | public DefaultResolvedTypeDefinition(ITypeResolveContext parentContext, params IUnresolvedTypeDefinition[] parts) |
---|
39 | { |
---|
40 | if (parentContext == null || parentContext.CurrentAssembly == null) |
---|
41 | throw new ArgumentException("Parent context does not specify any assembly", "parentContext"); |
---|
42 | if (parts == null || parts.Length == 0) |
---|
43 | throw new ArgumentException("No parts were specified", "parts"); |
---|
44 | this.parentContext = parentContext; |
---|
45 | this.parts = parts; |
---|
46 | |
---|
47 | foreach (IUnresolvedTypeDefinition part in parts) { |
---|
48 | isAbstract |= part.IsAbstract; |
---|
49 | isSealed |= part.IsSealed; |
---|
50 | isShadowing |= part.IsShadowing; |
---|
51 | isSynthetic &= part.IsSynthetic; // true if all parts are synthetic |
---|
52 | |
---|
53 | // internal is the default, so use another part's accessibility until we find a non-internal accessibility |
---|
54 | if (accessibility == Accessibility.Internal) |
---|
55 | accessibility = part.Accessibility; |
---|
56 | } |
---|
57 | } |
---|
58 | |
---|
59 | IList<ITypeParameter> typeParameters; |
---|
60 | |
---|
61 | public IList<ITypeParameter> TypeParameters { |
---|
62 | get { |
---|
63 | var result = LazyInit.VolatileRead(ref this.typeParameters); |
---|
64 | if (result != null) { |
---|
65 | return result; |
---|
66 | } |
---|
67 | ITypeResolveContext contextForTypeParameters = parts[0].CreateResolveContext(parentContext); |
---|
68 | contextForTypeParameters = contextForTypeParameters.WithCurrentTypeDefinition(this); |
---|
69 | if (parentContext.CurrentTypeDefinition == null || parentContext.CurrentTypeDefinition.TypeParameterCount == 0) { |
---|
70 | result = parts[0].TypeParameters.CreateResolvedTypeParameters(contextForTypeParameters); |
---|
71 | } else { |
---|
72 | // This is a nested class inside a generic class; copy type parameters from outer class if we can: |
---|
73 | var outerClass = parentContext.CurrentTypeDefinition; |
---|
74 | ITypeParameter[] typeParameters = new ITypeParameter[parts[0].TypeParameters.Count]; |
---|
75 | for (int i = 0; i < typeParameters.Length; i++) { |
---|
76 | var unresolvedTP = parts[0].TypeParameters[i]; |
---|
77 | if (i < outerClass.TypeParameterCount && outerClass.TypeParameters[i].Name == unresolvedTP.Name) |
---|
78 | typeParameters[i] = outerClass.TypeParameters[i]; |
---|
79 | else |
---|
80 | typeParameters[i] = unresolvedTP.CreateResolvedTypeParameter(contextForTypeParameters); |
---|
81 | } |
---|
82 | result = Array.AsReadOnly(typeParameters); |
---|
83 | } |
---|
84 | return LazyInit.GetOrSet(ref this.typeParameters, result); |
---|
85 | } |
---|
86 | } |
---|
87 | |
---|
88 | IList<IAttribute> attributes; |
---|
89 | |
---|
90 | public IList<IAttribute> Attributes { |
---|
91 | get { |
---|
92 | var result = LazyInit.VolatileRead(ref this.attributes); |
---|
93 | if (result != null) { |
---|
94 | return result; |
---|
95 | } |
---|
96 | result = new List<IAttribute>(); |
---|
97 | var context = parentContext.WithCurrentTypeDefinition(this); |
---|
98 | foreach (IUnresolvedTypeDefinition part in parts) { |
---|
99 | ITypeResolveContext parentContextForPart = part.CreateResolveContext(context); |
---|
100 | foreach (var attr in part.Attributes) { |
---|
101 | result.Add(attr.CreateResolvedAttribute(parentContextForPart)); |
---|
102 | } |
---|
103 | } |
---|
104 | if (result.Count == 0) |
---|
105 | result = EmptyList<IAttribute>.Instance; |
---|
106 | return LazyInit.GetOrSet(ref this.attributes, result); |
---|
107 | } |
---|
108 | } |
---|
109 | |
---|
110 | public IList<IUnresolvedTypeDefinition> Parts { |
---|
111 | get { return parts; } |
---|
112 | } |
---|
113 | |
---|
114 | public SymbolKind SymbolKind { |
---|
115 | get { return parts[0].SymbolKind; } |
---|
116 | } |
---|
117 | |
---|
118 | [Obsolete("Use the SymbolKind property instead.")] |
---|
119 | public EntityType EntityType { |
---|
120 | get { return (EntityType)parts[0].SymbolKind; } |
---|
121 | } |
---|
122 | |
---|
123 | public virtual TypeKind Kind { |
---|
124 | get { return parts[0].Kind; } |
---|
125 | } |
---|
126 | |
---|
127 | #region NestedTypes |
---|
128 | IList<ITypeDefinition> nestedTypes; |
---|
129 | |
---|
130 | public IList<ITypeDefinition> NestedTypes { |
---|
131 | get { |
---|
132 | IList<ITypeDefinition> result = LazyInit.VolatileRead(ref this.nestedTypes); |
---|
133 | if (result != null) { |
---|
134 | return result; |
---|
135 | } else { |
---|
136 | result = ( |
---|
137 | from part in parts |
---|
138 | from nestedTypeRef in part.NestedTypes |
---|
139 | group nestedTypeRef by new { nestedTypeRef.Name, nestedTypeRef.TypeParameters.Count } into g |
---|
140 | select new DefaultResolvedTypeDefinition(new SimpleTypeResolveContext(this), g.ToArray()) |
---|
141 | ).ToList<ITypeDefinition>().AsReadOnly(); |
---|
142 | return LazyInit.GetOrSet(ref this.nestedTypes, result); |
---|
143 | } |
---|
144 | } |
---|
145 | } |
---|
146 | #endregion |
---|
147 | |
---|
148 | #region Members |
---|
149 | sealed class MemberList : IList<IMember> |
---|
150 | { |
---|
151 | internal readonly ITypeResolveContext[] contextPerMember; |
---|
152 | internal readonly IUnresolvedMember[] unresolvedMembers; |
---|
153 | internal readonly IMember[] resolvedMembers; |
---|
154 | internal readonly int NonPartialMemberCount; |
---|
155 | |
---|
156 | public MemberList(List<ITypeResolveContext> contextPerMember, List<IUnresolvedMember> unresolvedNonPartialMembers, List<PartialMethodInfo> partialMethodInfos) |
---|
157 | { |
---|
158 | this.NonPartialMemberCount = unresolvedNonPartialMembers.Count; |
---|
159 | this.contextPerMember = contextPerMember.ToArray(); |
---|
160 | this.unresolvedMembers = unresolvedNonPartialMembers.ToArray(); |
---|
161 | if (partialMethodInfos == null) { |
---|
162 | this.resolvedMembers = new IMember[unresolvedNonPartialMembers.Count]; |
---|
163 | } else { |
---|
164 | this.resolvedMembers = new IMember[unresolvedNonPartialMembers.Count + partialMethodInfos.Count]; |
---|
165 | for (int i = 0; i < partialMethodInfos.Count; i++) { |
---|
166 | var info = partialMethodInfos[i]; |
---|
167 | int memberIndex = NonPartialMemberCount + i; |
---|
168 | resolvedMembers[memberIndex] = DefaultResolvedMethod.CreateFromMultipleParts( |
---|
169 | info.Parts.ToArray(), info.Contexts.ToArray (), false); |
---|
170 | } |
---|
171 | } |
---|
172 | } |
---|
173 | |
---|
174 | public IMember this[int index] { |
---|
175 | get { |
---|
176 | IMember output = LazyInit.VolatileRead(ref resolvedMembers[index]); |
---|
177 | if (output != null) { |
---|
178 | return output; |
---|
179 | } |
---|
180 | return LazyInit.GetOrSet(ref resolvedMembers[index], unresolvedMembers[index].CreateResolved(contextPerMember[index])); |
---|
181 | } |
---|
182 | set { throw new NotSupportedException(); } |
---|
183 | } |
---|
184 | |
---|
185 | public int Count { |
---|
186 | get { return resolvedMembers.Length; } |
---|
187 | } |
---|
188 | |
---|
189 | bool ICollection<IMember>.IsReadOnly { |
---|
190 | get { return true; } |
---|
191 | } |
---|
192 | |
---|
193 | public int IndexOf(IMember item) |
---|
194 | { |
---|
195 | for (int i = 0; i < this.Count; i++) { |
---|
196 | if (this[i].Equals(item)) |
---|
197 | return i; |
---|
198 | } |
---|
199 | return -1; |
---|
200 | } |
---|
201 | |
---|
202 | void IList<IMember>.Insert(int index, IMember item) |
---|
203 | { |
---|
204 | throw new NotSupportedException(); |
---|
205 | } |
---|
206 | |
---|
207 | void IList<IMember>.RemoveAt(int index) |
---|
208 | { |
---|
209 | throw new NotSupportedException(); |
---|
210 | } |
---|
211 | |
---|
212 | void ICollection<IMember>.Add(IMember item) |
---|
213 | { |
---|
214 | throw new NotSupportedException(); |
---|
215 | } |
---|
216 | |
---|
217 | void ICollection<IMember>.Clear() |
---|
218 | { |
---|
219 | throw new NotSupportedException(); |
---|
220 | } |
---|
221 | |
---|
222 | bool ICollection<IMember>.Contains(IMember item) |
---|
223 | { |
---|
224 | return IndexOf(item) >= 0; |
---|
225 | } |
---|
226 | |
---|
227 | void ICollection<IMember>.CopyTo(IMember[] array, int arrayIndex) |
---|
228 | { |
---|
229 | for (int i = 0; i < this.Count; i++) { |
---|
230 | array[arrayIndex + i] = this[i]; |
---|
231 | } |
---|
232 | } |
---|
233 | |
---|
234 | bool ICollection<IMember>.Remove(IMember item) |
---|
235 | { |
---|
236 | throw new NotSupportedException(); |
---|
237 | } |
---|
238 | |
---|
239 | public IEnumerator<IMember> GetEnumerator() |
---|
240 | { |
---|
241 | for (int i = 0; i < this.Count; i++) { |
---|
242 | yield return this[i]; |
---|
243 | } |
---|
244 | } |
---|
245 | |
---|
246 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
---|
247 | { |
---|
248 | return GetEnumerator(); |
---|
249 | } |
---|
250 | } |
---|
251 | |
---|
252 | sealed class PartialMethodInfo |
---|
253 | { |
---|
254 | public readonly string Name; |
---|
255 | public readonly int TypeParameterCount; |
---|
256 | public readonly IList<IParameter> Parameters; |
---|
257 | public readonly List<IUnresolvedMethod> Parts = new List<IUnresolvedMethod>(); |
---|
258 | public readonly List<ITypeResolveContext> Contexts = new List<ITypeResolveContext>(); |
---|
259 | |
---|
260 | public PartialMethodInfo(IUnresolvedMethod method, ITypeResolveContext context) |
---|
261 | { |
---|
262 | this.Name = method.Name; |
---|
263 | this.TypeParameterCount = method.TypeParameters.Count; |
---|
264 | this.Parameters = method.Parameters.CreateResolvedParameters(context); |
---|
265 | this.Parts.Add(method); |
---|
266 | this.Contexts.Add (context); |
---|
267 | } |
---|
268 | |
---|
269 | public void AddPart(IUnresolvedMethod method, ITypeResolveContext context) |
---|
270 | { |
---|
271 | if (method.HasBody) { |
---|
272 | // make the implementation the primary part |
---|
273 | this.Parts.Insert(0, method); |
---|
274 | this.Contexts.Insert (0, context); |
---|
275 | } else { |
---|
276 | this.Parts.Add(method); |
---|
277 | this.Contexts.Add (context); |
---|
278 | } |
---|
279 | } |
---|
280 | |
---|
281 | public bool IsSameSignature(PartialMethodInfo other, StringComparer nameComparer) |
---|
282 | { |
---|
283 | return nameComparer.Equals(this.Name, other.Name) |
---|
284 | && this.TypeParameterCount == other.TypeParameterCount |
---|
285 | && ParameterListComparer.Instance.Equals(this.Parameters, other.Parameters); |
---|
286 | } |
---|
287 | } |
---|
288 | |
---|
289 | MemberList memberList; |
---|
290 | |
---|
291 | MemberList GetMemberList() |
---|
292 | { |
---|
293 | var result = LazyInit.VolatileRead(ref this.memberList); |
---|
294 | if (result != null) { |
---|
295 | return result; |
---|
296 | } |
---|
297 | List<IUnresolvedMember> unresolvedMembers = new List<IUnresolvedMember>(); |
---|
298 | List<ITypeResolveContext> contextPerMember = new List<ITypeResolveContext>(); |
---|
299 | List<PartialMethodInfo> partialMethodInfos = null; |
---|
300 | bool addDefaultConstructorIfRequired = false; |
---|
301 | foreach (IUnresolvedTypeDefinition part in parts) { |
---|
302 | ITypeResolveContext parentContextForPart = part.CreateResolveContext(parentContext); |
---|
303 | ITypeResolveContext contextForPart = parentContextForPart.WithCurrentTypeDefinition(this); |
---|
304 | foreach (var member in part.Members) { |
---|
305 | IUnresolvedMethod method = member as IUnresolvedMethod; |
---|
306 | if (method != null && method.IsPartial) { |
---|
307 | // Merge partial method declaration and implementation |
---|
308 | if (partialMethodInfos == null) |
---|
309 | partialMethodInfos = new List<PartialMethodInfo>(); |
---|
310 | PartialMethodInfo newInfo = new PartialMethodInfo(method, contextForPart); |
---|
311 | PartialMethodInfo existingInfo = null; |
---|
312 | foreach (var info in partialMethodInfos) { |
---|
313 | if (newInfo.IsSameSignature(info, Compilation.NameComparer)) { |
---|
314 | existingInfo = info; |
---|
315 | break; |
---|
316 | } |
---|
317 | } |
---|
318 | if (existingInfo != null) { |
---|
319 | // Add the unresolved method to the PartialMethodInfo: |
---|
320 | existingInfo.AddPart(method, contextForPart); |
---|
321 | } else { |
---|
322 | partialMethodInfos.Add(newInfo); |
---|
323 | } |
---|
324 | } else { |
---|
325 | unresolvedMembers.Add(member); |
---|
326 | contextPerMember.Add(contextForPart); |
---|
327 | } |
---|
328 | } |
---|
329 | |
---|
330 | addDefaultConstructorIfRequired |= part.AddDefaultConstructorIfRequired; |
---|
331 | } |
---|
332 | if (addDefaultConstructorIfRequired) { |
---|
333 | TypeKind kind = this.Kind; |
---|
334 | if (kind == TypeKind.Class && !this.IsStatic && !unresolvedMembers.Any(m => m.SymbolKind == SymbolKind.Constructor && !m.IsStatic) |
---|
335 | || kind == TypeKind.Enum || kind == TypeKind.Struct) |
---|
336 | { |
---|
337 | contextPerMember.Add(parts[0].CreateResolveContext(parentContext).WithCurrentTypeDefinition(this)); |
---|
338 | unresolvedMembers.Add(DefaultUnresolvedMethod.CreateDefaultConstructor(parts[0])); |
---|
339 | } |
---|
340 | } |
---|
341 | result = new MemberList(contextPerMember, unresolvedMembers, partialMethodInfos); |
---|
342 | return LazyInit.GetOrSet(ref this.memberList, result); |
---|
343 | } |
---|
344 | |
---|
345 | public IList<IMember> Members { |
---|
346 | get { return GetMemberList(); } |
---|
347 | } |
---|
348 | |
---|
349 | public IEnumerable<IField> Fields { |
---|
350 | get { |
---|
351 | var members = GetMemberList(); |
---|
352 | for (int i = 0; i < members.unresolvedMembers.Length; i++) { |
---|
353 | if (members.unresolvedMembers[i].SymbolKind == SymbolKind.Field) |
---|
354 | yield return (IField)members[i]; |
---|
355 | } |
---|
356 | } |
---|
357 | } |
---|
358 | |
---|
359 | public IEnumerable<IMethod> Methods { |
---|
360 | get { |
---|
361 | var members = GetMemberList(); |
---|
362 | for (int i = 0; i < members.unresolvedMembers.Length; i++) { |
---|
363 | if (members.unresolvedMembers[i] is IUnresolvedMethod) |
---|
364 | yield return (IMethod)members[i]; |
---|
365 | } |
---|
366 | for (int i = members.unresolvedMembers.Length; i < members.Count; i++) { |
---|
367 | yield return (IMethod)members[i]; |
---|
368 | } |
---|
369 | } |
---|
370 | } |
---|
371 | |
---|
372 | public IEnumerable<IProperty> Properties { |
---|
373 | get { |
---|
374 | var members = GetMemberList(); |
---|
375 | for (int i = 0; i < members.unresolvedMembers.Length; i++) { |
---|
376 | switch (members.unresolvedMembers[i].SymbolKind) { |
---|
377 | case SymbolKind.Property: |
---|
378 | case SymbolKind.Indexer: |
---|
379 | yield return (IProperty)members[i]; |
---|
380 | break; |
---|
381 | } |
---|
382 | } |
---|
383 | } |
---|
384 | } |
---|
385 | |
---|
386 | public IEnumerable<IEvent> Events { |
---|
387 | get { |
---|
388 | var members = GetMemberList(); |
---|
389 | for (int i = 0; i < members.unresolvedMembers.Length; i++) { |
---|
390 | if (members.unresolvedMembers[i].SymbolKind == SymbolKind.Event) |
---|
391 | yield return (IEvent)members[i]; |
---|
392 | } |
---|
393 | } |
---|
394 | } |
---|
395 | #endregion |
---|
396 | |
---|
397 | volatile KnownTypeCode knownTypeCode = (KnownTypeCode)(-1); |
---|
398 | |
---|
399 | public KnownTypeCode KnownTypeCode { |
---|
400 | get { |
---|
401 | KnownTypeCode result = this.knownTypeCode; |
---|
402 | if (result == (KnownTypeCode)(-1)) { |
---|
403 | result = KnownTypeCode.None; |
---|
404 | ICompilation compilation = this.Compilation; |
---|
405 | for (int i = 0; i < KnownTypeReference.KnownTypeCodeCount; i++) { |
---|
406 | if (compilation.FindType((KnownTypeCode)i) == this) { |
---|
407 | result = (KnownTypeCode)i; |
---|
408 | break; |
---|
409 | } |
---|
410 | } |
---|
411 | this.knownTypeCode = result; |
---|
412 | } |
---|
413 | return result; |
---|
414 | } |
---|
415 | } |
---|
416 | |
---|
417 | volatile IType enumUnderlyingType; |
---|
418 | |
---|
419 | public IType EnumUnderlyingType { |
---|
420 | get { |
---|
421 | IType result = this.enumUnderlyingType; |
---|
422 | if (result == null) { |
---|
423 | if (this.Kind == TypeKind.Enum) { |
---|
424 | result = CalculateEnumUnderlyingType(); |
---|
425 | } else { |
---|
426 | result = SpecialType.UnknownType; |
---|
427 | } |
---|
428 | this.enumUnderlyingType = result; |
---|
429 | } |
---|
430 | return result; |
---|
431 | } |
---|
432 | } |
---|
433 | |
---|
434 | IType CalculateEnumUnderlyingType() |
---|
435 | { |
---|
436 | foreach (var part in parts) { |
---|
437 | var context = part.CreateResolveContext(parentContext).WithCurrentTypeDefinition(this); |
---|
438 | foreach (var baseTypeRef in part.BaseTypes) { |
---|
439 | IType type = baseTypeRef.Resolve(context); |
---|
440 | if (type.Kind != TypeKind.Unknown) |
---|
441 | return type; |
---|
442 | } |
---|
443 | } |
---|
444 | return this.Compilation.FindType(KnownTypeCode.Int32); |
---|
445 | } |
---|
446 | |
---|
447 | volatile byte hasExtensionMethods; // 0 = unknown, 1 = true, 2 = false |
---|
448 | |
---|
449 | public bool HasExtensionMethods { |
---|
450 | get { |
---|
451 | byte val = this.hasExtensionMethods; |
---|
452 | if (val == 0) { |
---|
453 | if (CalculateHasExtensionMethods()) |
---|
454 | val = 1; |
---|
455 | else |
---|
456 | val = 2; |
---|
457 | this.hasExtensionMethods = val; |
---|
458 | } |
---|
459 | return val == 1; |
---|
460 | } |
---|
461 | } |
---|
462 | |
---|
463 | bool CalculateHasExtensionMethods() |
---|
464 | { |
---|
465 | bool noExtensionMethods = true; |
---|
466 | foreach (var part in parts) { |
---|
467 | // Return true if any part has extension methods |
---|
468 | if (part.HasExtensionMethods == true) |
---|
469 | return true; |
---|
470 | if (part.HasExtensionMethods == null) |
---|
471 | noExtensionMethods = false; |
---|
472 | } |
---|
473 | // Return false if all parts are known to have no extension methods |
---|
474 | if (noExtensionMethods) |
---|
475 | return false; |
---|
476 | // If unsure, look at the resolved methods. |
---|
477 | return Methods.Any(m => m.IsExtensionMethod); |
---|
478 | } |
---|
479 | |
---|
480 | public bool IsPartial { |
---|
481 | get { return parts.Length > 1 || parts[0].IsPartial; } |
---|
482 | } |
---|
483 | |
---|
484 | public bool? IsReferenceType { |
---|
485 | get { |
---|
486 | switch (this.Kind) { |
---|
487 | case TypeKind.Class: |
---|
488 | case TypeKind.Interface: |
---|
489 | case TypeKind.Module: |
---|
490 | case TypeKind.Delegate: |
---|
491 | return true; |
---|
492 | case TypeKind.Struct: |
---|
493 | case TypeKind.Enum: |
---|
494 | case TypeKind.Void: |
---|
495 | return false; |
---|
496 | default: |
---|
497 | throw new InvalidOperationException("Invalid value for TypeKind"); |
---|
498 | } |
---|
499 | } |
---|
500 | } |
---|
501 | |
---|
502 | public int TypeParameterCount { |
---|
503 | get { return parts[0].TypeParameters.Count; } |
---|
504 | } |
---|
505 | |
---|
506 | public IList<IType> TypeArguments { |
---|
507 | get { |
---|
508 | // ToList() call is necessary because IList<> isn't covariant |
---|
509 | return TypeParameters.ToList<IType>(); |
---|
510 | } |
---|
511 | } |
---|
512 | |
---|
513 | public bool IsParameterized { |
---|
514 | get { return false; } |
---|
515 | } |
---|
516 | |
---|
517 | #region DirectBaseTypes |
---|
518 | IList<IType> directBaseTypes; |
---|
519 | |
---|
520 | public IEnumerable<IType> DirectBaseTypes { |
---|
521 | get { |
---|
522 | IList<IType> result = LazyInit.VolatileRead(ref this.directBaseTypes); |
---|
523 | if (result != null) { |
---|
524 | return result; |
---|
525 | } |
---|
526 | using (var busyLock = BusyManager.Enter(this)) { |
---|
527 | if (busyLock.Success) { |
---|
528 | result = CalculateDirectBaseTypes(); |
---|
529 | return LazyInit.GetOrSet(ref this.directBaseTypes, result); |
---|
530 | } else { |
---|
531 | // This can happen for "class Test : $Test.Base$ { public class Base {} }" |
---|
532 | // and also for the valid code |
---|
533 | // "class Test : Base<Test.Inner> { public class Inner {} }" |
---|
534 | |
---|
535 | // Don't cache the error! |
---|
536 | return EmptyList<IType>.Instance; |
---|
537 | } |
---|
538 | } |
---|
539 | } |
---|
540 | } |
---|
541 | |
---|
542 | IList<IType> CalculateDirectBaseTypes() |
---|
543 | { |
---|
544 | List<IType> result = new List<IType>(); |
---|
545 | bool hasNonInterface = false; |
---|
546 | if (this.Kind != TypeKind.Enum) { |
---|
547 | foreach (var part in parts) { |
---|
548 | var context = part.CreateResolveContext(parentContext).WithCurrentTypeDefinition(this); |
---|
549 | foreach (var baseTypeRef in part.BaseTypes) { |
---|
550 | IType baseType = baseTypeRef.Resolve(context); |
---|
551 | if (!(baseType.Kind == TypeKind.Unknown || result.Contains(baseType))) { |
---|
552 | result.Add(baseType); |
---|
553 | if (baseType.Kind != TypeKind.Interface) |
---|
554 | hasNonInterface = true; |
---|
555 | } |
---|
556 | } |
---|
557 | } |
---|
558 | } |
---|
559 | if (!hasNonInterface && !(this.Name == "Object" && this.Namespace == "System" && this.TypeParameterCount == 0)) { |
---|
560 | KnownTypeCode primitiveBaseType; |
---|
561 | switch (this.Kind) { |
---|
562 | case TypeKind.Enum: |
---|
563 | primitiveBaseType = KnownTypeCode.Enum; |
---|
564 | break; |
---|
565 | case TypeKind.Struct: |
---|
566 | case TypeKind.Void: |
---|
567 | primitiveBaseType = KnownTypeCode.ValueType; |
---|
568 | break; |
---|
569 | case TypeKind.Delegate: |
---|
570 | primitiveBaseType = KnownTypeCode.Delegate; |
---|
571 | break; |
---|
572 | default: |
---|
573 | primitiveBaseType = KnownTypeCode.Object; |
---|
574 | break; |
---|
575 | } |
---|
576 | IType t = parentContext.Compilation.FindType(primitiveBaseType); |
---|
577 | if (t.Kind != TypeKind.Unknown) |
---|
578 | result.Add(t); |
---|
579 | } |
---|
580 | return result; |
---|
581 | } |
---|
582 | #endregion |
---|
583 | |
---|
584 | public string FullName { |
---|
585 | get { return parts[0].FullName; } |
---|
586 | } |
---|
587 | |
---|
588 | public string Name { |
---|
589 | get { return parts[0].Name; } |
---|
590 | } |
---|
591 | |
---|
592 | public string ReflectionName { |
---|
593 | get { return parts[0].ReflectionName; } |
---|
594 | } |
---|
595 | |
---|
596 | public string Namespace { |
---|
597 | get { return parts[0].Namespace; } |
---|
598 | } |
---|
599 | |
---|
600 | public FullTypeName FullTypeName { |
---|
601 | get { return parts[0].FullTypeName; } |
---|
602 | } |
---|
603 | |
---|
604 | public DomRegion Region { |
---|
605 | get { return parts[0].Region; } |
---|
606 | } |
---|
607 | |
---|
608 | public DomRegion BodyRegion { |
---|
609 | get { return parts[0].BodyRegion; } |
---|
610 | } |
---|
611 | |
---|
612 | public ITypeDefinition DeclaringTypeDefinition { |
---|
613 | get { return parentContext.CurrentTypeDefinition; } |
---|
614 | } |
---|
615 | |
---|
616 | public IType DeclaringType { |
---|
617 | get { return parentContext.CurrentTypeDefinition; } |
---|
618 | } |
---|
619 | |
---|
620 | public IAssembly ParentAssembly { |
---|
621 | get { return parentContext.CurrentAssembly; } |
---|
622 | } |
---|
623 | |
---|
624 | public virtual DocumentationComment Documentation { |
---|
625 | get { |
---|
626 | foreach (var part in parts) { |
---|
627 | var unresolvedProvider = part.UnresolvedFile as IUnresolvedDocumentationProvider; |
---|
628 | if (unresolvedProvider != null) { |
---|
629 | var doc = unresolvedProvider.GetDocumentation(part, this); |
---|
630 | if (doc != null) |
---|
631 | return doc; |
---|
632 | } |
---|
633 | } |
---|
634 | IDocumentationProvider provider = AbstractResolvedEntity.FindDocumentation(parentContext); |
---|
635 | if (provider != null) |
---|
636 | return provider.GetDocumentation(this); |
---|
637 | else |
---|
638 | return null; |
---|
639 | } |
---|
640 | } |
---|
641 | |
---|
642 | public ICompilation Compilation { |
---|
643 | get { return parentContext.Compilation; } |
---|
644 | } |
---|
645 | |
---|
646 | #region Modifiers |
---|
647 | public bool IsStatic { get { return isAbstract && isSealed; } } |
---|
648 | public bool IsAbstract { get { return isAbstract; } } |
---|
649 | public bool IsSealed { get { return isSealed; } } |
---|
650 | public bool IsShadowing { get { return isShadowing; } } |
---|
651 | public bool IsSynthetic { get { return isSynthetic; } } |
---|
652 | |
---|
653 | public Accessibility Accessibility { |
---|
654 | get { return accessibility; } |
---|
655 | } |
---|
656 | |
---|
657 | bool IHasAccessibility.IsPrivate { |
---|
658 | get { return accessibility == Accessibility.Private; } |
---|
659 | } |
---|
660 | |
---|
661 | bool IHasAccessibility.IsPublic { |
---|
662 | get { return accessibility == Accessibility.Public; } |
---|
663 | } |
---|
664 | |
---|
665 | bool IHasAccessibility.IsProtected { |
---|
666 | get { return accessibility == Accessibility.Protected; } |
---|
667 | } |
---|
668 | |
---|
669 | bool IHasAccessibility.IsInternal { |
---|
670 | get { return accessibility == Accessibility.Internal; } |
---|
671 | } |
---|
672 | |
---|
673 | bool IHasAccessibility.IsProtectedOrInternal { |
---|
674 | get { return accessibility == Accessibility.ProtectedOrInternal; } |
---|
675 | } |
---|
676 | |
---|
677 | bool IHasAccessibility.IsProtectedAndInternal { |
---|
678 | get { return accessibility == Accessibility.ProtectedAndInternal; } |
---|
679 | } |
---|
680 | #endregion |
---|
681 | |
---|
682 | ITypeDefinition IType.GetDefinition() |
---|
683 | { |
---|
684 | return this; |
---|
685 | } |
---|
686 | |
---|
687 | IType IType.AcceptVisitor(TypeVisitor visitor) |
---|
688 | { |
---|
689 | return visitor.VisitTypeDefinition(this); |
---|
690 | } |
---|
691 | |
---|
692 | IType IType.VisitChildren(TypeVisitor visitor) |
---|
693 | { |
---|
694 | return this; |
---|
695 | } |
---|
696 | |
---|
697 | public ITypeReference ToTypeReference() |
---|
698 | { |
---|
699 | ITypeDefinition declTypeDef = this.DeclaringTypeDefinition; |
---|
700 | if (declTypeDef != null) { |
---|
701 | return new NestedTypeReference(declTypeDef.ToTypeReference(), this.Name, this.TypeParameterCount - declTypeDef.TypeParameterCount); |
---|
702 | } else { |
---|
703 | IAssembly asm = this.ParentAssembly; |
---|
704 | IAssemblyReference asmRef; |
---|
705 | if (asm != null) |
---|
706 | asmRef = new DefaultAssemblyReference(asm.AssemblyName); |
---|
707 | else |
---|
708 | asmRef = null; |
---|
709 | return new GetClassTypeReference(asmRef, this.Namespace, this.Name, this.TypeParameterCount); |
---|
710 | } |
---|
711 | } |
---|
712 | |
---|
713 | ISymbolReference ISymbol.ToReference() |
---|
714 | { |
---|
715 | return (ISymbolReference)ToTypeReference(); |
---|
716 | } |
---|
717 | |
---|
718 | public IEnumerable<IType> GetNestedTypes(Predicate<ITypeDefinition> filter = null, GetMemberOptions options = GetMemberOptions.None) |
---|
719 | { |
---|
720 | const GetMemberOptions opt = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions; |
---|
721 | if ((options & opt) == opt) { |
---|
722 | if (filter == null) |
---|
723 | return this.NestedTypes; |
---|
724 | else |
---|
725 | return GetNestedTypesImpl(filter); |
---|
726 | } else { |
---|
727 | return GetMembersHelper.GetNestedTypes(this, filter, options); |
---|
728 | } |
---|
729 | } |
---|
730 | |
---|
731 | IEnumerable<IType> GetNestedTypesImpl(Predicate<ITypeDefinition> filter) |
---|
732 | { |
---|
733 | foreach (var nestedType in this.NestedTypes) { |
---|
734 | if (filter(nestedType)) |
---|
735 | yield return nestedType; |
---|
736 | } |
---|
737 | } |
---|
738 | |
---|
739 | public IEnumerable<IType> GetNestedTypes(IList<IType> typeArguments, Predicate<ITypeDefinition> filter = null, GetMemberOptions options = GetMemberOptions.None) |
---|
740 | { |
---|
741 | return GetMembersHelper.GetNestedTypes(this, typeArguments, filter, options); |
---|
742 | } |
---|
743 | |
---|
744 | #region GetMembers() |
---|
745 | IEnumerable<IMember> GetFilteredMembers(Predicate<IUnresolvedMember> filter) |
---|
746 | { |
---|
747 | var members = GetMemberList(); |
---|
748 | for (int i = 0; i < members.unresolvedMembers.Length; i++) { |
---|
749 | if (filter == null || filter(members.unresolvedMembers[i])) { |
---|
750 | yield return members[i]; |
---|
751 | } |
---|
752 | } |
---|
753 | for (int i = members.unresolvedMembers.Length; i < members.Count; i++) { |
---|
754 | var method = (IMethod)members[i]; |
---|
755 | bool ok = false; |
---|
756 | foreach (var part in method.Parts) { |
---|
757 | if (filter == null || filter(part)) { |
---|
758 | ok = true; |
---|
759 | break; |
---|
760 | } |
---|
761 | } |
---|
762 | if (ok) |
---|
763 | yield return method; |
---|
764 | } |
---|
765 | } |
---|
766 | |
---|
767 | IEnumerable<IMethod> GetFilteredMethods(Predicate<IUnresolvedMethod> filter) |
---|
768 | { |
---|
769 | var members = GetMemberList(); |
---|
770 | for (int i = 0; i < members.unresolvedMembers.Length; i++) { |
---|
771 | IUnresolvedMethod unresolved = members.unresolvedMembers[i] as IUnresolvedMethod; |
---|
772 | if (unresolved != null && (filter == null || filter(unresolved))) { |
---|
773 | yield return (IMethod)members[i]; |
---|
774 | } |
---|
775 | } |
---|
776 | for (int i = members.unresolvedMembers.Length; i < members.Count; i++) { |
---|
777 | var method = (IMethod)members[i]; |
---|
778 | bool ok = false; |
---|
779 | foreach (var part in method.Parts) { |
---|
780 | if (filter == null || filter(part)) { |
---|
781 | ok = true; |
---|
782 | break; |
---|
783 | } |
---|
784 | } |
---|
785 | if (ok) |
---|
786 | yield return method; |
---|
787 | } |
---|
788 | } |
---|
789 | |
---|
790 | IEnumerable<TResolved> GetFilteredNonMethods<TUnresolved, TResolved>(Predicate<TUnresolved> filter) where TUnresolved : class, IUnresolvedMember where TResolved : class, IMember |
---|
791 | { |
---|
792 | var members = GetMemberList(); |
---|
793 | for (int i = 0; i < members.unresolvedMembers.Length; i++) { |
---|
794 | TUnresolved unresolved = members.unresolvedMembers[i] as TUnresolved; |
---|
795 | if (unresolved != null && (filter == null || filter(unresolved))) { |
---|
796 | yield return (TResolved)members[i]; |
---|
797 | } |
---|
798 | } |
---|
799 | } |
---|
800 | |
---|
801 | public virtual IEnumerable<IMethod> GetMethods(Predicate<IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.None) |
---|
802 | { |
---|
803 | if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { |
---|
804 | return GetFilteredMethods(Utils.ExtensionMethods.And(m => !m.IsConstructor, filter)); |
---|
805 | } else { |
---|
806 | return GetMembersHelper.GetMethods(this, filter, options); |
---|
807 | } |
---|
808 | } |
---|
809 | |
---|
810 | public virtual IEnumerable<IMethod> GetMethods(IList<IType> typeArguments, Predicate<IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.None) |
---|
811 | { |
---|
812 | return GetMembersHelper.GetMethods(this, typeArguments, filter, options); |
---|
813 | } |
---|
814 | |
---|
815 | public virtual IEnumerable<IMethod> GetConstructors(Predicate<IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) |
---|
816 | { |
---|
817 | if (ComHelper.IsComImport(this)) { |
---|
818 | IType coClass = ComHelper.GetCoClass(this); |
---|
819 | using (var busyLock = BusyManager.Enter(this)) { |
---|
820 | if (busyLock.Success) { |
---|
821 | return coClass.GetConstructors(filter, options) |
---|
822 | .Select(m => new SpecializedMethod(m, m.Substitution) { DeclaringType = this }); |
---|
823 | } |
---|
824 | } |
---|
825 | return EmptyList<IMethod>.Instance; |
---|
826 | } |
---|
827 | if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { |
---|
828 | return GetFilteredMethods(Utils.ExtensionMethods.And(m => m.IsConstructor && !m.IsStatic, filter)); |
---|
829 | } else { |
---|
830 | return GetMembersHelper.GetConstructors(this, filter, options); |
---|
831 | } |
---|
832 | } |
---|
833 | |
---|
834 | public virtual IEnumerable<IProperty> GetProperties(Predicate<IUnresolvedProperty> filter = null, GetMemberOptions options = GetMemberOptions.None) |
---|
835 | { |
---|
836 | if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { |
---|
837 | return GetFilteredNonMethods<IUnresolvedProperty, IProperty>(filter); |
---|
838 | } else { |
---|
839 | return GetMembersHelper.GetProperties(this, filter, options); |
---|
840 | } |
---|
841 | } |
---|
842 | |
---|
843 | public virtual IEnumerable<IField> GetFields(Predicate<IUnresolvedField> filter = null, GetMemberOptions options = GetMemberOptions.None) |
---|
844 | { |
---|
845 | if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { |
---|
846 | return GetFilteredNonMethods<IUnresolvedField, IField>(filter); |
---|
847 | } else { |
---|
848 | return GetMembersHelper.GetFields(this, filter, options); |
---|
849 | } |
---|
850 | } |
---|
851 | |
---|
852 | public virtual IEnumerable<IEvent> GetEvents(Predicate<IUnresolvedEvent> filter = null, GetMemberOptions options = GetMemberOptions.None) |
---|
853 | { |
---|
854 | if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { |
---|
855 | return GetFilteredNonMethods<IUnresolvedEvent, IEvent>(filter); |
---|
856 | } else { |
---|
857 | return GetMembersHelper.GetEvents(this, filter, options); |
---|
858 | } |
---|
859 | } |
---|
860 | |
---|
861 | public virtual IEnumerable<IMember> GetMembers(Predicate<IUnresolvedMember> filter = null, GetMemberOptions options = GetMemberOptions.None) |
---|
862 | { |
---|
863 | if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { |
---|
864 | return GetFilteredMembers(filter); |
---|
865 | } else { |
---|
866 | return GetMembersHelper.GetMembers(this, filter, options); |
---|
867 | } |
---|
868 | } |
---|
869 | |
---|
870 | public virtual IEnumerable<IMethod> GetAccessors(Predicate<IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.None) |
---|
871 | { |
---|
872 | if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { |
---|
873 | return GetFilteredAccessors(filter); |
---|
874 | } else { |
---|
875 | return GetMembersHelper.GetAccessors(this, filter, options); |
---|
876 | } |
---|
877 | } |
---|
878 | |
---|
879 | IEnumerable<IMethod> GetFilteredAccessors(Predicate<IUnresolvedMethod> filter) |
---|
880 | { |
---|
881 | var members = GetMemberList(); |
---|
882 | for (int i = 0; i < members.unresolvedMembers.Length; i++) { |
---|
883 | IUnresolvedMember unresolved = members.unresolvedMembers[i]; |
---|
884 | var unresolvedProperty = unresolved as IUnresolvedProperty; |
---|
885 | var unresolvedEvent = unresolved as IUnresolvedEvent; |
---|
886 | if (unresolvedProperty != null) { |
---|
887 | if (unresolvedProperty.CanGet && (filter == null || filter(unresolvedProperty.Getter))) |
---|
888 | yield return ((IProperty)members[i]).Getter; |
---|
889 | if (unresolvedProperty.CanSet && (filter == null || filter(unresolvedProperty.Setter))) |
---|
890 | yield return ((IProperty)members[i]).Setter; |
---|
891 | } else if (unresolvedEvent != null) { |
---|
892 | if (unresolvedEvent.CanAdd && (filter == null || filter(unresolvedEvent.AddAccessor))) |
---|
893 | yield return ((IEvent)members[i]).AddAccessor; |
---|
894 | if (unresolvedEvent.CanRemove && (filter == null || filter(unresolvedEvent.RemoveAccessor))) |
---|
895 | yield return ((IEvent)members[i]).RemoveAccessor; |
---|
896 | if (unresolvedEvent.CanInvoke && (filter == null || filter(unresolvedEvent.InvokeAccessor))) |
---|
897 | yield return ((IEvent)members[i]).InvokeAccessor; |
---|
898 | } |
---|
899 | } |
---|
900 | } |
---|
901 | #endregion |
---|
902 | |
---|
903 | #region GetInterfaceImplementation |
---|
904 | public IMember GetInterfaceImplementation(IMember interfaceMember) |
---|
905 | { |
---|
906 | return GetInterfaceImplementation(new[] { interfaceMember })[0]; |
---|
907 | } |
---|
908 | |
---|
909 | public IList<IMember> GetInterfaceImplementation(IList<IMember> interfaceMembers) |
---|
910 | { |
---|
911 | // TODO: review the subtle rules for interface reimplementation, |
---|
912 | // write tests and fix this method. |
---|
913 | // Also virtual/override is going to be tricky - |
---|
914 | // I think we'll need to consider the 'virtual' method first for |
---|
915 | // reimplemenatation purposes, but then actually return the 'override' |
---|
916 | // (as that's the method that ends up getting called) |
---|
917 | |
---|
918 | interfaceMembers = interfaceMembers.ToList(); // avoid evaluating more than once |
---|
919 | |
---|
920 | var result = new IMember[interfaceMembers.Count]; |
---|
921 | var signatureToIndexDict = new MultiDictionary<IMember, int>(SignatureComparer.Ordinal); |
---|
922 | for (int i = 0; i < interfaceMembers.Count; i++) { |
---|
923 | signatureToIndexDict.Add(interfaceMembers[i], i); |
---|
924 | } |
---|
925 | foreach (var member in GetMembers(m => !m.IsExplicitInterfaceImplementation)) { |
---|
926 | foreach (int interfaceMemberIndex in signatureToIndexDict[member]) { |
---|
927 | result[interfaceMemberIndex] = member; |
---|
928 | } |
---|
929 | } |
---|
930 | foreach (var explicitImpl in GetMembers(m => m.IsExplicitInterfaceImplementation)) { |
---|
931 | foreach (var interfaceMember in explicitImpl.ImplementedInterfaceMembers) { |
---|
932 | foreach (int potentialMatchingIndex in signatureToIndexDict[interfaceMember]) { |
---|
933 | if (interfaceMember.Equals(interfaceMembers[potentialMatchingIndex])) { |
---|
934 | result[potentialMatchingIndex] = explicitImpl; |
---|
935 | } |
---|
936 | } |
---|
937 | } |
---|
938 | } |
---|
939 | return result; |
---|
940 | } |
---|
941 | #endregion |
---|
942 | |
---|
943 | public TypeParameterSubstitution GetSubstitution() |
---|
944 | { |
---|
945 | return TypeParameterSubstitution.Identity; |
---|
946 | } |
---|
947 | |
---|
948 | public TypeParameterSubstitution GetSubstitution(IList<IType> methodTypeArguments) |
---|
949 | { |
---|
950 | return TypeParameterSubstitution.Identity; |
---|
951 | } |
---|
952 | |
---|
953 | public bool Equals(IType other) |
---|
954 | { |
---|
955 | return this == other; |
---|
956 | } |
---|
957 | |
---|
958 | public override string ToString() |
---|
959 | { |
---|
960 | return this.ReflectionName; |
---|
961 | } |
---|
962 | } |
---|
963 | } |
---|