Free cookie consent management tool by TermsFeed Policy Generator

source: tags/3.3.11/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory-5.5.0/TypeSystem/TypeSystemExtensions.cs @ 13398

Last change on this file since 13398 was 11700, checked in by jkarder, 9 years ago

#2077: created branch and added first version

File size: 29.1 KB
Line 
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
19using System;
20using System.Collections.Generic;
21using System.Linq;
22using ICSharpCode.NRefactory.Semantics;
23using ICSharpCode.NRefactory.TypeSystem.Implementation;
24using ICSharpCode.NRefactory.Utils;
25
26namespace 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&lt;T&gt; {
152    ///   List&lt;T&gt; open;
153    ///   X&lt;X&lt;T[]&gt;&gt; open;
154    ///   X&lt;string&gt; 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&lt;Dictionary&lt;,&gt;&gt;)</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&lt;string, &gt;</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}
Note: See TracBrowser for help on using the repository browser.