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.Semantics; |
---|
23 | using ICSharpCode.NRefactory.TypeSystem.Implementation; |
---|
24 | using ICSharpCode.NRefactory.Utils; |
---|
25 | |
---|
26 | namespace ICSharpCode.NRefactory.TypeSystem |
---|
27 | { |
---|
28 | /// <summary> |
---|
29 | /// Contains extension methods for the type system. |
---|
30 | /// </summary> |
---|
31 | public static class TypeSystemExtensions |
---|
32 | { |
---|
33 | #region GetAllBaseTypes |
---|
34 | /// <summary> |
---|
35 | /// Gets all base types. |
---|
36 | /// </summary> |
---|
37 | /// <remarks>This is the reflexive and transitive closure of <see cref="IType.DirectBaseTypes"/>. |
---|
38 | /// Note that this method does not return all supertypes - doing so is impossible due to contravariance |
---|
39 | /// (and undesirable for covariance as the list could become very large). |
---|
40 | /// |
---|
41 | /// The output is ordered so that base types occur before derived types. |
---|
42 | /// </remarks> |
---|
43 | public static IEnumerable<IType> GetAllBaseTypes(this IType type) |
---|
44 | { |
---|
45 | if (type == null) |
---|
46 | throw new ArgumentNullException("type"); |
---|
47 | BaseTypeCollector collector = new BaseTypeCollector(); |
---|
48 | collector.CollectBaseTypes(type); |
---|
49 | return collector; |
---|
50 | } |
---|
51 | |
---|
52 | /// <summary> |
---|
53 | /// Gets all non-interface base types. |
---|
54 | /// </summary> |
---|
55 | /// <remarks> |
---|
56 | /// When <paramref name="type"/> is an interface, this method will also return base interfaces (return same output as GetAllBaseTypes()). |
---|
57 | /// |
---|
58 | /// The output is ordered so that base types occur before derived types. |
---|
59 | /// </remarks> |
---|
60 | public static IEnumerable<IType> GetNonInterfaceBaseTypes(this IType type) |
---|
61 | { |
---|
62 | if (type == null) |
---|
63 | throw new ArgumentNullException("type"); |
---|
64 | BaseTypeCollector collector = new BaseTypeCollector(); |
---|
65 | collector.SkipImplementedInterfaces = true; |
---|
66 | collector.CollectBaseTypes(type); |
---|
67 | return collector; |
---|
68 | } |
---|
69 | #endregion |
---|
70 | |
---|
71 | #region GetAllBaseTypeDefinitions |
---|
72 | /// <summary> |
---|
73 | /// Gets all base type definitions. |
---|
74 | /// The output is ordered so that base types occur before derived types. |
---|
75 | /// </summary> |
---|
76 | /// <remarks> |
---|
77 | /// This is equivalent to type.GetAllBaseTypes().Select(t => t.GetDefinition()).Where(d => d != null).Distinct(). |
---|
78 | /// </remarks> |
---|
79 | public static IEnumerable<ITypeDefinition> GetAllBaseTypeDefinitions(this IType type) |
---|
80 | { |
---|
81 | if (type == null) |
---|
82 | throw new ArgumentNullException("type"); |
---|
83 | |
---|
84 | return type.GetAllBaseTypes().Select(t => t.GetDefinition()).Where(d => d != null).Distinct(); |
---|
85 | } |
---|
86 | |
---|
87 | /// <summary> |
---|
88 | /// Gets whether this type definition is derived from the base type definition. |
---|
89 | /// </summary> |
---|
90 | public static bool IsDerivedFrom(this ITypeDefinition type, ITypeDefinition baseType) |
---|
91 | { |
---|
92 | if (type == null) |
---|
93 | throw new ArgumentNullException("type"); |
---|
94 | if (baseType == null) |
---|
95 | return false; |
---|
96 | if (type.Compilation != baseType.Compilation) { |
---|
97 | throw new InvalidOperationException("Both arguments to IsDerivedFrom() must be from the same compilation."); |
---|
98 | } |
---|
99 | return type.GetAllBaseTypeDefinitions().Contains(baseType); |
---|
100 | } |
---|
101 | |
---|
102 | /// <summary> |
---|
103 | /// Gets whether this type definition is derived from a given known type. |
---|
104 | /// </summary> |
---|
105 | public static bool IsDerivedFrom(this ITypeDefinition type, KnownTypeCode baseType) |
---|
106 | { |
---|
107 | if (type == null) |
---|
108 | throw new ArgumentNullException("type"); |
---|
109 | if (baseType == KnownTypeCode.None) |
---|
110 | return false; |
---|
111 | return IsDerivedFrom(type, type.Compilation.FindType(baseType).GetDefinition()); |
---|
112 | } |
---|
113 | #endregion |
---|
114 | |
---|
115 | #region IsOpen / IsUnbound / IsKnownType |
---|
116 | sealed class TypeClassificationVisitor : TypeVisitor |
---|
117 | { |
---|
118 | internal bool isOpen; |
---|
119 | internal IEntity typeParameterOwner; |
---|
120 | int typeParameterOwnerNestingLevel; |
---|
121 | |
---|
122 | public override IType VisitTypeParameter(ITypeParameter type) |
---|
123 | { |
---|
124 | isOpen = true; |
---|
125 | // If both classes and methods, or different classes (nested types) |
---|
126 | // are involved, find the most specific one |
---|
127 | int newNestingLevel = GetNestingLevel(type.Owner); |
---|
128 | if (newNestingLevel > typeParameterOwnerNestingLevel) { |
---|
129 | typeParameterOwner = type.Owner; |
---|
130 | typeParameterOwnerNestingLevel = newNestingLevel; |
---|
131 | } |
---|
132 | return base.VisitTypeParameter(type); |
---|
133 | } |
---|
134 | |
---|
135 | static int GetNestingLevel(IEntity entity) |
---|
136 | { |
---|
137 | int level = 0; |
---|
138 | while (entity != null) { |
---|
139 | level++; |
---|
140 | entity = entity.DeclaringTypeDefinition; |
---|
141 | } |
---|
142 | return level; |
---|
143 | } |
---|
144 | } |
---|
145 | |
---|
146 | /// <summary> |
---|
147 | /// Gets whether the type is an open type (contains type parameters). |
---|
148 | /// </summary> |
---|
149 | /// <example> |
---|
150 | /// <code> |
---|
151 | /// class X<T> { |
---|
152 | /// List<T> open; |
---|
153 | /// X<X<T[]>> open; |
---|
154 | /// X<string> closed; |
---|
155 | /// int closed; |
---|
156 | /// } |
---|
157 | /// </code> |
---|
158 | /// </example> |
---|
159 | public static bool IsOpen(this IType type) |
---|
160 | { |
---|
161 | if (type == null) |
---|
162 | throw new ArgumentNullException("type"); |
---|
163 | TypeClassificationVisitor v = new TypeClassificationVisitor(); |
---|
164 | type.AcceptVisitor(v); |
---|
165 | return v.isOpen; |
---|
166 | } |
---|
167 | |
---|
168 | /// <summary> |
---|
169 | /// Gets the entity that owns the type parameters occurring in the specified type. |
---|
170 | /// If both class and method type parameters are present, the method is returned. |
---|
171 | /// Returns null if the specified type is closed. |
---|
172 | /// </summary> |
---|
173 | /// <seealso cref="IsOpen"/> |
---|
174 | static IEntity GetTypeParameterOwner(IType type) |
---|
175 | { |
---|
176 | if (type == null) |
---|
177 | throw new ArgumentNullException("type"); |
---|
178 | TypeClassificationVisitor v = new TypeClassificationVisitor(); |
---|
179 | type.AcceptVisitor(v); |
---|
180 | return v.typeParameterOwner; |
---|
181 | } |
---|
182 | |
---|
183 | /// <summary> |
---|
184 | /// Gets whether the type is unbound (is a generic type, but no type arguments were provided). |
---|
185 | /// </summary> |
---|
186 | /// <remarks> |
---|
187 | /// In "<c>typeof(List<Dictionary<,>>)</c>", only the Dictionary is unbound, the List is considered |
---|
188 | /// bound despite containing an unbound type. |
---|
189 | /// This method returns false for partially parameterized types (<c>Dictionary<string, ></c>). |
---|
190 | /// </remarks> |
---|
191 | public static bool IsUnbound(this IType type) |
---|
192 | { |
---|
193 | if (type == null) |
---|
194 | throw new ArgumentNullException("type"); |
---|
195 | return type is ITypeDefinition && type.TypeParameterCount > 0; |
---|
196 | } |
---|
197 | |
---|
198 | /// <summary> |
---|
199 | /// Gets whether the type is the specified known type. |
---|
200 | /// For generic known types, this returns true any parameterization of the type (and also for the definition itself). |
---|
201 | /// </summary> |
---|
202 | public static bool IsKnownType(this IType type, KnownTypeCode knownType) |
---|
203 | { |
---|
204 | var def = type.GetDefinition(); |
---|
205 | return def != null && def.KnownTypeCode == knownType; |
---|
206 | } |
---|
207 | #endregion |
---|
208 | |
---|
209 | #region Import |
---|
210 | /// <summary> |
---|
211 | /// Imports a symbol from another compilation. |
---|
212 | /// </summary> |
---|
213 | public static ISymbol Import(this ICompilation compilation, ISymbol symbol) |
---|
214 | { |
---|
215 | if (compilation == null) |
---|
216 | throw new ArgumentNullException("compilation"); |
---|
217 | if (symbol == null) |
---|
218 | return null; |
---|
219 | switch (symbol.SymbolKind) { |
---|
220 | case SymbolKind.TypeParameter: |
---|
221 | return (ITypeParameter)Import(compilation, (IType)symbol); |
---|
222 | case SymbolKind.Variable: |
---|
223 | IVariable v = (IVariable)symbol; |
---|
224 | return new DefaultVariable( |
---|
225 | Import(compilation, v.Type), |
---|
226 | v.Name, v.Region, v.IsConst, v.ConstantValue |
---|
227 | ); |
---|
228 | case SymbolKind.Parameter: |
---|
229 | IParameter p = (IParameter)symbol; |
---|
230 | if (p.Owner != null) { |
---|
231 | int index = p.Owner.Parameters.IndexOf(p); |
---|
232 | var owner = (IParameterizedMember)Import(compilation, p.Owner); |
---|
233 | if (owner == null || index < 0 || index >= owner.Parameters.Count) |
---|
234 | return null; |
---|
235 | return owner.Parameters[index]; |
---|
236 | } else { |
---|
237 | return new DefaultParameter( |
---|
238 | Import(compilation, p.Type), |
---|
239 | p.Name, null, p.Region, |
---|
240 | null, p.IsRef, p.IsOut, p.IsParams |
---|
241 | ); |
---|
242 | } |
---|
243 | case SymbolKind.Namespace: |
---|
244 | return Import(compilation, (INamespace)symbol); |
---|
245 | default: |
---|
246 | if (symbol is IEntity) |
---|
247 | return Import(compilation, (IEntity)symbol); |
---|
248 | throw new NotSupportedException("Unsupported symbol kind: " + symbol.SymbolKind); |
---|
249 | } |
---|
250 | } |
---|
251 | |
---|
252 | /// <summary> |
---|
253 | /// Imports a type from another compilation. |
---|
254 | /// </summary> |
---|
255 | public static IType Import(this ICompilation compilation, IType type) |
---|
256 | { |
---|
257 | if (compilation == null) |
---|
258 | throw new ArgumentNullException("compilation"); |
---|
259 | if (type == null) |
---|
260 | return null; |
---|
261 | var compilationProvider = type as ICompilationProvider; |
---|
262 | if (compilationProvider != null && compilationProvider.Compilation == compilation) |
---|
263 | return type; |
---|
264 | IEntity typeParameterOwner = GetTypeParameterOwner(type); |
---|
265 | IEntity importedTypeParameterOwner = compilation.Import(typeParameterOwner); |
---|
266 | if (importedTypeParameterOwner != null) { |
---|
267 | return type.ToTypeReference().Resolve(new SimpleTypeResolveContext(importedTypeParameterOwner)); |
---|
268 | } else { |
---|
269 | return type.ToTypeReference().Resolve(compilation.TypeResolveContext); |
---|
270 | } |
---|
271 | } |
---|
272 | |
---|
273 | /// <summary> |
---|
274 | /// Imports a type from another compilation. |
---|
275 | /// </summary> |
---|
276 | public static ITypeDefinition Import(this ICompilation compilation, ITypeDefinition typeDefinition) |
---|
277 | { |
---|
278 | if (compilation == null) |
---|
279 | throw new ArgumentNullException("compilation"); |
---|
280 | if (typeDefinition == null) |
---|
281 | return null; |
---|
282 | if (typeDefinition.Compilation == compilation) |
---|
283 | return typeDefinition; |
---|
284 | return typeDefinition.ToTypeReference().Resolve(compilation.TypeResolveContext).GetDefinition(); |
---|
285 | } |
---|
286 | |
---|
287 | /// <summary> |
---|
288 | /// Imports an entity from another compilation. |
---|
289 | /// </summary> |
---|
290 | public static IEntity Import(this ICompilation compilation, IEntity entity) |
---|
291 | { |
---|
292 | if (compilation == null) |
---|
293 | throw new ArgumentNullException("compilation"); |
---|
294 | if (entity == null) |
---|
295 | return null; |
---|
296 | if (entity.Compilation == compilation) |
---|
297 | return entity; |
---|
298 | if (entity is IMember) |
---|
299 | return ((IMember)entity).ToReference().Resolve(compilation.TypeResolveContext); |
---|
300 | else if (entity is ITypeDefinition) |
---|
301 | return ((ITypeDefinition)entity).ToTypeReference().Resolve(compilation.TypeResolveContext).GetDefinition(); |
---|
302 | else |
---|
303 | throw new NotSupportedException("Unknown entity type"); |
---|
304 | } |
---|
305 | |
---|
306 | /// <summary> |
---|
307 | /// Imports a member from another compilation. |
---|
308 | /// </summary> |
---|
309 | public static IMember Import(this ICompilation compilation, IMember member) |
---|
310 | { |
---|
311 | if (compilation == null) |
---|
312 | throw new ArgumentNullException("compilation"); |
---|
313 | if (member == null) |
---|
314 | return null; |
---|
315 | if (member.Compilation == compilation) |
---|
316 | return member; |
---|
317 | return member.ToReference().Resolve(compilation.TypeResolveContext); |
---|
318 | } |
---|
319 | |
---|
320 | /// <summary> |
---|
321 | /// Imports a member from another compilation. |
---|
322 | /// </summary> |
---|
323 | public static IMethod Import(this ICompilation compilation, IMethod method) |
---|
324 | { |
---|
325 | return (IMethod)compilation.Import((IMember)method); |
---|
326 | } |
---|
327 | |
---|
328 | /// <summary> |
---|
329 | /// Imports a member from another compilation. |
---|
330 | /// </summary> |
---|
331 | public static IField Import(this ICompilation compilation, IField field) |
---|
332 | { |
---|
333 | return (IField)compilation.Import((IMember)field); |
---|
334 | } |
---|
335 | |
---|
336 | /// <summary> |
---|
337 | /// Imports a member from another compilation. |
---|
338 | /// </summary> |
---|
339 | public static IEvent Import(this ICompilation compilation, IEvent ev) |
---|
340 | { |
---|
341 | return (IEvent)compilation.Import((IMember)ev); |
---|
342 | } |
---|
343 | |
---|
344 | /// <summary> |
---|
345 | /// Imports a member from another compilation. |
---|
346 | /// </summary> |
---|
347 | public static IProperty Import(this ICompilation compilation, IProperty property) |
---|
348 | { |
---|
349 | return (IProperty)compilation.Import((IMember)property); |
---|
350 | } |
---|
351 | |
---|
352 | /// <summary> |
---|
353 | /// Imports a namespace from another compilation. |
---|
354 | /// </summary> |
---|
355 | /// <remarks> |
---|
356 | /// This method may return null if the namespace does not exist in the target compilation. |
---|
357 | /// </remarks> |
---|
358 | public static INamespace Import(this ICompilation compilation, INamespace ns) |
---|
359 | { |
---|
360 | if (compilation == null) |
---|
361 | throw new ArgumentNullException("compilation"); |
---|
362 | if (ns == null) |
---|
363 | return null; |
---|
364 | if (ns.ParentNamespace == null) { |
---|
365 | // root namespace |
---|
366 | return compilation.GetNamespaceForExternAlias(ns.ExternAlias); |
---|
367 | } else { |
---|
368 | INamespace parent = Import(compilation, ns.ParentNamespace); |
---|
369 | if (parent != null) |
---|
370 | return parent.GetChildNamespace(ns.Name); |
---|
371 | else |
---|
372 | return null; |
---|
373 | } |
---|
374 | } |
---|
375 | #endregion |
---|
376 | |
---|
377 | #region GetDelegateInvokeMethod |
---|
378 | /// <summary> |
---|
379 | /// Gets the invoke method for a delegate type. |
---|
380 | /// </summary> |
---|
381 | /// <remarks> |
---|
382 | /// Returns null if the type is not a delegate type; or if the invoke method could not be found. |
---|
383 | /// </remarks> |
---|
384 | public static IMethod GetDelegateInvokeMethod(this IType type) |
---|
385 | { |
---|
386 | if (type == null) |
---|
387 | throw new ArgumentNullException("type"); |
---|
388 | if (type.Kind == TypeKind.Delegate) |
---|
389 | return type.GetMethods(m => m.Name == "Invoke", GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); |
---|
390 | else |
---|
391 | return null; |
---|
392 | } |
---|
393 | #endregion |
---|
394 | |
---|
395 | #region GetType/Member |
---|
396 | /// <summary> |
---|
397 | /// Gets all unresolved type definitions from the file. |
---|
398 | /// For partial classes, each part is returned. |
---|
399 | /// </summary> |
---|
400 | public static IEnumerable<IUnresolvedTypeDefinition> GetAllTypeDefinitions (this IUnresolvedFile file) |
---|
401 | { |
---|
402 | return TreeTraversal.PreOrder(file.TopLevelTypeDefinitions, t => t.NestedTypes); |
---|
403 | } |
---|
404 | |
---|
405 | /// <summary> |
---|
406 | /// Gets all unresolved type definitions from the assembly. |
---|
407 | /// For partial classes, each part is returned. |
---|
408 | /// </summary> |
---|
409 | public static IEnumerable<IUnresolvedTypeDefinition> GetAllTypeDefinitions (this IUnresolvedAssembly assembly) |
---|
410 | { |
---|
411 | return TreeTraversal.PreOrder(assembly.TopLevelTypeDefinitions, t => t.NestedTypes); |
---|
412 | } |
---|
413 | |
---|
414 | public static IEnumerable<ITypeDefinition> GetAllTypeDefinitions (this IAssembly assembly) |
---|
415 | { |
---|
416 | return TreeTraversal.PreOrder(assembly.TopLevelTypeDefinitions, t => t.NestedTypes); |
---|
417 | } |
---|
418 | |
---|
419 | /// <summary> |
---|
420 | /// Gets all type definitions in the compilation. |
---|
421 | /// This may include types from referenced assemblies that are not accessible in the main assembly. |
---|
422 | /// </summary> |
---|
423 | public static IEnumerable<ITypeDefinition> GetAllTypeDefinitions (this ICompilation compilation) |
---|
424 | { |
---|
425 | return compilation.Assemblies.SelectMany(a => a.GetAllTypeDefinitions()); |
---|
426 | } |
---|
427 | |
---|
428 | /// <summary> |
---|
429 | /// Gets all top level type definitions in the compilation. |
---|
430 | /// This may include types from referenced assemblies that are not accessible in the main assembly. |
---|
431 | /// </summary> |
---|
432 | public static IEnumerable<ITypeDefinition> GetTopLevelTypeDefinitons (this ICompilation compilation) |
---|
433 | { |
---|
434 | return compilation.Assemblies.SelectMany(a => a.TopLevelTypeDefinitions); |
---|
435 | } |
---|
436 | |
---|
437 | /// <summary> |
---|
438 | /// Gets the type (potentially a nested type) defined at the specified location. |
---|
439 | /// Returns null if no type is defined at that location. |
---|
440 | /// </summary> |
---|
441 | public static IUnresolvedTypeDefinition GetInnermostTypeDefinition (this IUnresolvedFile file, int line, int column) |
---|
442 | { |
---|
443 | return file.GetInnermostTypeDefinition (new TextLocation (line, column)); |
---|
444 | } |
---|
445 | |
---|
446 | /// <summary> |
---|
447 | /// Gets the member defined at the specified location. |
---|
448 | /// Returns null if no member is defined at that location. |
---|
449 | /// </summary> |
---|
450 | public static IUnresolvedMember GetMember (this IUnresolvedFile file, int line, int column) |
---|
451 | { |
---|
452 | return file.GetMember (new TextLocation (line, column)); |
---|
453 | } |
---|
454 | #endregion |
---|
455 | |
---|
456 | #region Resolve on collections |
---|
457 | public static IList<IAttribute> CreateResolvedAttributes(this IList<IUnresolvedAttribute> attributes, ITypeResolveContext context) |
---|
458 | { |
---|
459 | if (attributes == null) |
---|
460 | throw new ArgumentNullException("attributes"); |
---|
461 | if (attributes.Count == 0) |
---|
462 | return EmptyList<IAttribute>.Instance; |
---|
463 | else |
---|
464 | return new ProjectedList<ITypeResolveContext, IUnresolvedAttribute, IAttribute>(context, attributes, (c, a) => a.CreateResolvedAttribute(c)); |
---|
465 | } |
---|
466 | |
---|
467 | public static IList<ITypeParameter> CreateResolvedTypeParameters(this IList<IUnresolvedTypeParameter> typeParameters, ITypeResolveContext context) |
---|
468 | { |
---|
469 | if (typeParameters == null) |
---|
470 | throw new ArgumentNullException("typeParameters"); |
---|
471 | if (typeParameters.Count == 0) |
---|
472 | return EmptyList<ITypeParameter>.Instance; |
---|
473 | else |
---|
474 | return new ProjectedList<ITypeResolveContext, IUnresolvedTypeParameter, ITypeParameter>(context, typeParameters, (c, a) => a.CreateResolvedTypeParameter(c)); |
---|
475 | } |
---|
476 | |
---|
477 | public static IList<IParameter> CreateResolvedParameters(this IList<IUnresolvedParameter> parameters, ITypeResolveContext context) |
---|
478 | { |
---|
479 | if (parameters == null) |
---|
480 | throw new ArgumentNullException("parameters"); |
---|
481 | if (parameters.Count == 0) |
---|
482 | return EmptyList<IParameter>.Instance; |
---|
483 | else |
---|
484 | return new ProjectedList<ITypeResolveContext, IUnresolvedParameter, IParameter>(context, parameters, (c, a) => a.CreateResolvedParameter(c)); |
---|
485 | } |
---|
486 | |
---|
487 | public static IList<IType> Resolve(this IList<ITypeReference> typeReferences, ITypeResolveContext context) |
---|
488 | { |
---|
489 | if (typeReferences == null) |
---|
490 | throw new ArgumentNullException("typeReferences"); |
---|
491 | if (typeReferences.Count == 0) |
---|
492 | return EmptyList<IType>.Instance; |
---|
493 | else |
---|
494 | return new ProjectedList<ITypeResolveContext, ITypeReference, IType>(context, typeReferences, (c, t) => t.Resolve(c)); |
---|
495 | } |
---|
496 | |
---|
497 | // There is intentionally no Resolve() overload for IList<IMemberReference>: the resulting IList<Member> would |
---|
498 | // contains nulls when there are resolve errors. |
---|
499 | |
---|
500 | public static IList<ResolveResult> Resolve(this IList<IConstantValue> constantValues, ITypeResolveContext context) |
---|
501 | { |
---|
502 | if (constantValues == null) |
---|
503 | throw new ArgumentNullException("constantValues"); |
---|
504 | if (constantValues.Count == 0) |
---|
505 | return EmptyList<ResolveResult>.Instance; |
---|
506 | else |
---|
507 | return new ProjectedList<ITypeResolveContext, IConstantValue, ResolveResult>(context, constantValues, (c, t) => t.Resolve(c)); |
---|
508 | } |
---|
509 | #endregion |
---|
510 | |
---|
511 | #region GetSubTypeDefinitions |
---|
512 | public static IEnumerable<ITypeDefinition> GetSubTypeDefinitions (this IType baseType) |
---|
513 | { |
---|
514 | if (baseType == null) |
---|
515 | throw new ArgumentNullException ("baseType"); |
---|
516 | var def = baseType.GetDefinition (); |
---|
517 | if (def == null) |
---|
518 | return Enumerable.Empty<ITypeDefinition> (); |
---|
519 | return def.GetSubTypeDefinitions (); |
---|
520 | } |
---|
521 | |
---|
522 | /// <summary> |
---|
523 | /// Gets all sub type definitions defined in a context. |
---|
524 | /// </summary> |
---|
525 | public static IEnumerable<ITypeDefinition> GetSubTypeDefinitions (this ITypeDefinition baseType) |
---|
526 | { |
---|
527 | if (baseType == null) |
---|
528 | throw new ArgumentNullException ("baseType"); |
---|
529 | foreach (var contextType in baseType.Compilation.GetAllTypeDefinitions ()) { |
---|
530 | if (contextType.IsDerivedFrom (baseType)) |
---|
531 | yield return contextType; |
---|
532 | } |
---|
533 | } |
---|
534 | #endregion |
---|
535 | |
---|
536 | #region IAssembly.GetTypeDefinition() |
---|
537 | /// <summary> |
---|
538 | /// Retrieves the specified type in this compilation. |
---|
539 | /// Returns an <see cref="UnknownType"/> if the type cannot be found in this compilation. |
---|
540 | /// </summary> |
---|
541 | /// <remarks> |
---|
542 | /// There can be multiple types with the same full name in a compilation, as a |
---|
543 | /// full type name is only unique per assembly. |
---|
544 | /// If there are multiple possible matches, this method will return just one of them. |
---|
545 | /// When possible, use <see cref="IAssembly.GetTypeDefinition"/> instead to |
---|
546 | /// retrieve a type from a specific assembly. |
---|
547 | /// </remarks> |
---|
548 | public static IType FindType(this ICompilation compilation, FullTypeName fullTypeName) |
---|
549 | { |
---|
550 | if (compilation == null) |
---|
551 | throw new ArgumentNullException("compilation"); |
---|
552 | foreach (IAssembly asm in compilation.Assemblies) { |
---|
553 | ITypeDefinition def = asm.GetTypeDefinition(fullTypeName); |
---|
554 | if (def != null) |
---|
555 | return def; |
---|
556 | } |
---|
557 | return new UnknownType(fullTypeName); |
---|
558 | } |
---|
559 | |
---|
560 | /// <summary> |
---|
561 | /// Gets the type definition for the specified unresolved type. |
---|
562 | /// Returns null if the unresolved type does not belong to this assembly. |
---|
563 | /// </summary> |
---|
564 | public static ITypeDefinition GetTypeDefinition(this IAssembly assembly, FullTypeName fullTypeName) |
---|
565 | { |
---|
566 | if (assembly == null) |
---|
567 | throw new ArgumentNullException("assembly"); |
---|
568 | TopLevelTypeName topLevelTypeName = fullTypeName.TopLevelTypeName; |
---|
569 | ITypeDefinition typeDef = assembly.GetTypeDefinition(topLevelTypeName); |
---|
570 | if (typeDef == null) |
---|
571 | return null; |
---|
572 | int typeParameterCount = topLevelTypeName.TypeParameterCount; |
---|
573 | for (int i = 0; i < fullTypeName.NestingLevel; i++) { |
---|
574 | string name = fullTypeName.GetNestedTypeName(i); |
---|
575 | typeParameterCount += fullTypeName.GetNestedTypeAdditionalTypeParameterCount(i); |
---|
576 | typeDef = FindNestedType(typeDef, name, typeParameterCount); |
---|
577 | if (typeDef == null) |
---|
578 | break; |
---|
579 | } |
---|
580 | return typeDef; |
---|
581 | } |
---|
582 | |
---|
583 | static ITypeDefinition FindNestedType(ITypeDefinition typeDef, string name, int typeParameterCount) |
---|
584 | { |
---|
585 | foreach (var nestedType in typeDef.NestedTypes) { |
---|
586 | if (nestedType.Name == name && nestedType.TypeParameterCount == typeParameterCount) |
---|
587 | return nestedType; |
---|
588 | } |
---|
589 | return null; |
---|
590 | } |
---|
591 | #endregion |
---|
592 | |
---|
593 | #region ITypeReference.Resolve(ICompilation) |
---|
594 | |
---|
595 | /// <summary> |
---|
596 | /// Resolves a type reference in the compilation's main type resolve context. |
---|
597 | /// Some type references require a more specific type resolve context and will not resolve using this method. |
---|
598 | /// </summary> |
---|
599 | /// <returns> |
---|
600 | /// Returns the resolved type. |
---|
601 | /// In case of an error, returns <see cref="SpecialType.UnknownType"/>. |
---|
602 | /// Never returns null. |
---|
603 | /// </returns> |
---|
604 | public static IType Resolve (this ITypeReference reference, ICompilation compilation) |
---|
605 | { |
---|
606 | if (reference == null) |
---|
607 | throw new ArgumentNullException ("reference"); |
---|
608 | if (compilation == null) |
---|
609 | throw new ArgumentNullException ("compilation"); |
---|
610 | return reference.Resolve (compilation.TypeResolveContext); |
---|
611 | } |
---|
612 | #endregion |
---|
613 | |
---|
614 | #region ITypeDefinition.GetAttribute |
---|
615 | /// <summary> |
---|
616 | /// Gets the attribute of the specified attribute type (or derived attribute types). |
---|
617 | /// </summary> |
---|
618 | /// <param name="entity">The entity on which the attributes are declared.</param> |
---|
619 | /// <param name="attributeType">The attribute type to look for.</param> |
---|
620 | /// <param name="inherit"> |
---|
621 | /// Specifies whether attributes inherited from base classes and base members (if the given <paramref name="entity"/> in an <c>override</c>) |
---|
622 | /// should be returned. The default is <c>true</c>. |
---|
623 | /// </param> |
---|
624 | /// <returns> |
---|
625 | /// Returns the attribute that was found; or <c>null</c> if none was found. |
---|
626 | /// If inherit is true, an from the entity itself will be returned if possible; |
---|
627 | /// and the base entity will only be searched if none exists. |
---|
628 | /// </returns> |
---|
629 | public static IAttribute GetAttribute(this IEntity entity, IType attributeType, bool inherit = true) |
---|
630 | { |
---|
631 | return GetAttributes(entity, attributeType, inherit).FirstOrDefault(); |
---|
632 | } |
---|
633 | |
---|
634 | /// <summary> |
---|
635 | /// Gets the attributes of the specified attribute type (or derived attribute types). |
---|
636 | /// </summary> |
---|
637 | /// <param name="entity">The entity on which the attributes are declared.</param> |
---|
638 | /// <param name="attributeType">The attribute type to look for.</param> |
---|
639 | /// <param name="inherit"> |
---|
640 | /// Specifies whether attributes inherited from base classes and base members (if the given <paramref name="entity"/> in an <c>override</c>) |
---|
641 | /// should be returned. The default is <c>true</c>. |
---|
642 | /// </param> |
---|
643 | /// <returns> |
---|
644 | /// Returns the list of attributes that were found. |
---|
645 | /// If inherit is true, attributes from the entity itself are returned first; followed by attributes inherited from the base entity. |
---|
646 | /// </returns> |
---|
647 | public static IEnumerable<IAttribute> GetAttributes(this IEntity entity, IType attributeType, bool inherit = true) |
---|
648 | { |
---|
649 | if (entity == null) |
---|
650 | throw new ArgumentNullException("entity"); |
---|
651 | if (attributeType == null) |
---|
652 | throw new ArgumentNullException("attributeType"); |
---|
653 | return GetAttributes(entity, attributeType.Equals, inherit); |
---|
654 | } |
---|
655 | |
---|
656 | /// <summary> |
---|
657 | /// Gets the attribute of the specified attribute type (or derived attribute types). |
---|
658 | /// </summary> |
---|
659 | /// <param name="entity">The entity on which the attributes are declared.</param> |
---|
660 | /// <param name="attributeType">The attribute type to look for.</param> |
---|
661 | /// <param name="inherit"> |
---|
662 | /// Specifies whether attributes inherited from base classes and base members (if the given <paramref name="entity"/> in an <c>override</c>) |
---|
663 | /// should be returned. The default is <c>true</c>. |
---|
664 | /// </param> |
---|
665 | /// <returns> |
---|
666 | /// Returns the attribute that was found; or <c>null</c> if none was found. |
---|
667 | /// If inherit is true, an from the entity itself will be returned if possible; |
---|
668 | /// and the base entity will only be searched if none exists. |
---|
669 | /// </returns> |
---|
670 | public static IAttribute GetAttribute(this IEntity entity, FullTypeName attributeType, bool inherit = true) |
---|
671 | { |
---|
672 | return GetAttributes(entity, attributeType, inherit).FirstOrDefault(); |
---|
673 | } |
---|
674 | |
---|
675 | /// <summary> |
---|
676 | /// Gets the attributes of the specified attribute type (or derived attribute types). |
---|
677 | /// </summary> |
---|
678 | /// <param name="entity">The entity on which the attributes are declared.</param> |
---|
679 | /// <param name="attributeType">The attribute type to look for.</param> |
---|
680 | /// <param name="inherit"> |
---|
681 | /// Specifies whether attributes inherited from base classes and base members (if the given <paramref name="entity"/> in an <c>override</c>) |
---|
682 | /// should be returned. The default is <c>true</c>. |
---|
683 | /// </param> |
---|
684 | /// <returns> |
---|
685 | /// Returns the list of attributes that were found. |
---|
686 | /// If inherit is true, attributes from the entity itself are returned first; followed by attributes inherited from the base entity. |
---|
687 | /// </returns> |
---|
688 | public static IEnumerable<IAttribute> GetAttributes(this IEntity entity, FullTypeName attributeType, bool inherit = true) |
---|
689 | { |
---|
690 | if (entity == null) |
---|
691 | throw new ArgumentNullException("entity"); |
---|
692 | return GetAttributes(entity, attrType => { |
---|
693 | ITypeDefinition typeDef = attrType.GetDefinition(); |
---|
694 | return typeDef != null && typeDef.FullTypeName == attributeType; |
---|
695 | }, inherit); |
---|
696 | } |
---|
697 | |
---|
698 | /// <summary> |
---|
699 | /// Gets the attribute of the specified attribute type (or derived attribute types). |
---|
700 | /// </summary> |
---|
701 | /// <param name="entity">The entity on which the attributes are declared.</param> |
---|
702 | /// <param name="inherit"> |
---|
703 | /// Specifies whether attributes inherited from base classes and base members (if the given <paramref name="entity"/> in an <c>override</c>) |
---|
704 | /// should be returned. The default is <c>true</c>. |
---|
705 | /// </param> |
---|
706 | /// <returns> |
---|
707 | /// Returns the attribute that was found; or <c>null</c> if none was found. |
---|
708 | /// If inherit is true, an from the entity itself will be returned if possible; |
---|
709 | /// and the base entity will only be searched if none exists. |
---|
710 | /// </returns> |
---|
711 | public static IEnumerable<IAttribute> GetAttributes(this IEntity entity, bool inherit = true) |
---|
712 | { |
---|
713 | if (entity == null) |
---|
714 | throw new ArgumentNullException ("entity"); |
---|
715 | return GetAttributes(entity, a => true, inherit); |
---|
716 | } |
---|
717 | |
---|
718 | static IEnumerable<IAttribute> GetAttributes(IEntity entity, Predicate<IType> attributeTypePredicate, bool inherit) |
---|
719 | { |
---|
720 | if (!inherit) { |
---|
721 | foreach (var attr in entity.Attributes) { |
---|
722 | if (attributeTypePredicate(attr.AttributeType)) |
---|
723 | yield return attr; |
---|
724 | } |
---|
725 | yield break; |
---|
726 | } |
---|
727 | ITypeDefinition typeDef = entity as ITypeDefinition; |
---|
728 | if (typeDef != null) { |
---|
729 | foreach (var baseType in typeDef.GetNonInterfaceBaseTypes().Reverse()) { |
---|
730 | ITypeDefinition baseTypeDef = baseType.GetDefinition(); |
---|
731 | if (baseTypeDef == null) |
---|
732 | continue; |
---|
733 | foreach (var attr in baseTypeDef.Attributes) { |
---|
734 | if (attributeTypePredicate(attr.AttributeType)) |
---|
735 | yield return attr; |
---|
736 | } |
---|
737 | } |
---|
738 | yield break; |
---|
739 | } |
---|
740 | IMember member = entity as IMember; |
---|
741 | if (member != null) { |
---|
742 | HashSet<IMember> visitedMembers = new HashSet<IMember>(); |
---|
743 | do { |
---|
744 | member = member.MemberDefinition; // it's sufficient to look at the definitions |
---|
745 | if (!visitedMembers.Add(member)) { |
---|
746 | // abort if we seem to be in an infinite loop (cyclic inheritance) |
---|
747 | break; |
---|
748 | } |
---|
749 | foreach (var attr in member.Attributes) { |
---|
750 | if (attributeTypePredicate(attr.AttributeType)) |
---|
751 | yield return attr; |
---|
752 | } |
---|
753 | } while (member.IsOverride && (member = InheritanceHelper.GetBaseMember(member)) != null); |
---|
754 | yield break; |
---|
755 | } |
---|
756 | throw new NotSupportedException("Unknown entity type"); |
---|
757 | } |
---|
758 | #endregion |
---|
759 | |
---|
760 | #region IAssembly.GetTypeDefinition(string,string,int) |
---|
761 | /// <summary> |
---|
762 | /// Gets the type definition for a top-level type. |
---|
763 | /// </summary> |
---|
764 | /// <remarks>This method uses ordinal name comparison, not the compilation's name comparer.</remarks> |
---|
765 | public static ITypeDefinition GetTypeDefinition(this IAssembly assembly, string namespaceName, string name, int typeParameterCount = 0) |
---|
766 | { |
---|
767 | if (assembly == null) |
---|
768 | throw new ArgumentNullException ("assembly"); |
---|
769 | return assembly.GetTypeDefinition (new TopLevelTypeName (namespaceName, name, typeParameterCount)); |
---|
770 | } |
---|
771 | #endregion |
---|
772 | |
---|
773 | #region ResolveResult |
---|
774 | public static ISymbol GetSymbol(this ResolveResult rr) |
---|
775 | { |
---|
776 | if (rr is LocalResolveResult) { |
---|
777 | return ((LocalResolveResult)rr).Variable; |
---|
778 | } else if (rr is MemberResolveResult) { |
---|
779 | return ((MemberResolveResult)rr).Member; |
---|
780 | } else if (rr is TypeResolveResult) { |
---|
781 | return ((TypeResolveResult)rr).Type.GetDefinition(); |
---|
782 | } |
---|
783 | |
---|
784 | return null; |
---|
785 | } |
---|
786 | #endregion |
---|
787 | } |
---|
788 | } |
---|