2 // membercache.cs: A container for all member lookups
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Marek Safar (marek.safar@gmail.com)
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2004-2010 Novell, Inc
16 using System
.Collections
.Generic
;
17 using System
.Globalization
;
18 using System
.Reflection
.Emit
;
19 using System
.Reflection
;
22 namespace Mono
.CSharp
{
25 public enum MemberKind
41 TypeParameter
= 1 << 16,
44 PointerType
= 1 << 20,
45 InternalCompilerType
= 1 << 21,
48 NestedMask
= Class
| Struct
| Delegate
| Enum
| Interface
,
49 GenericMask
= Method
| Class
| Struct
| Delegate
| Interface
,
50 MaskType
= Constructor
| Event
| Field
| Method
| Property
| Indexer
| Operator
| Destructor
| NestedMask
,
55 public enum BindingRestriction
59 // Member has to be accessible
62 // Inspect only queried type members
63 DeclaredOnly
= 1 << 1,
66 InstanceOnly
= 1 << 2,
68 // Ignore member overrides
72 public struct MemberFilter
: IEquatable
<MemberSpec
>
74 public readonly string Name
;
75 public readonly MemberKind Kind
;
76 public readonly AParametersCollection Parameters
;
77 public readonly TypeSpec MemberType
;
79 int arity
; // -1 to ignore the check
80 TypeSpec invocation_type
;
82 private MemberFilter (string name
, MemberKind kind
)
89 invocation_type
= null;
92 public MemberFilter (MethodSpec m
)
95 Kind
= MemberKind
.Method
;
96 Parameters
= m
.Parameters
;
97 MemberType
= m
.ReturnType
;
99 invocation_type
= null;
102 public MemberFilter (string name
, int arity
, MemberKind kind
, AParametersCollection param
, TypeSpec type
)
109 invocation_type
= null;
112 public TypeSpec InvocationType
{
114 return invocation_type
;
117 invocation_type
= value;
121 public static MemberFilter
Constructor (AParametersCollection param
)
123 return new MemberFilter (System
.Reflection
.ConstructorInfo
.ConstructorName
, 0, MemberKind
.Constructor
, param
, null);
126 public static MemberFilter
Property (string name
, TypeSpec type
)
128 return new MemberFilter (name
, 0, MemberKind
.Property
, null, type
);
131 public static MemberFilter
Field (string name
, TypeSpec type
)
133 return new MemberFilter (name
, 0, MemberKind
.Field
, null, type
);
136 public static MemberFilter
Method (string name
, int arity
, AParametersCollection param
, TypeSpec type
)
138 return new MemberFilter (name
, arity
, MemberKind
.Method
, param
, type
);
141 #region IEquatable<MemberSpec> Members
143 public bool Equals (MemberSpec other
)
145 // Is the member of the correct type ?
146 // TODO: Isn't this redundant ?
147 if ((other
.Kind
& Kind
& MemberKind
.MaskType
) == 0)
150 // Check arity when not disabled
151 if (arity
>= 0 && arity
!= other
.Arity
)
154 if (Parameters
!= null) {
155 if (other
is IParametersMember
) {
156 var other_param
= ((IParametersMember
) other
).Parameters
;
157 if (!TypeSpecComparer
.Override
.IsEqual (Parameters
, other_param
))
164 if (MemberType
!= null) {
165 if (other
is IInterfaceMemberSpec
) {
166 var other_type
= ((IInterfaceMemberSpec
) other
).MemberType
;
167 if (!TypeSpecComparer
.Override
.IsEqual (other_type
, MemberType
))
174 if (invocation_type
!= null && !IsAccessible (other
))
180 bool IsAccessible (MemberSpec other
)
183 return Expression
.IsMemberAccessible (invocation_type
, other
, out extra
);
190 /// The MemberCache is used by dynamic and non-dynamic types to speed up
191 /// member lookups. It has a member name based hash table; it maps each member
192 /// name to a list of CacheEntry objects. Each CacheEntry contains a MemberInfo
193 /// and the BindingFlags that were initially used to get it. The cache contains
194 /// all members of the current class and all inherited members. If this cache is
195 /// for an interface types, it also contains all inherited members.
197 /// There are two ways to get a MemberCache:
198 /// * if this is a dynamic type, lookup the corresponding DeclSpace and then
199 /// use the DeclSpace.MemberCache property.
200 /// * if this not a dynamic type, call TypeHandle.GetTypeHandle() to get a
201 /// TypeHandle instance for the type and then use TypeHandle.MemberCache.
203 public class MemberCache
207 HasNoImplicitOperator
= 1,
208 HasNoExplicitOperator
= 1 << 1
211 readonly Dictionary
<string, IList
<MemberSpec
>> member_hash
;
212 Dictionary
<string, MemberSpec
[]> locase_members
;
213 IList
<MethodSpec
> missing_abstract
;
216 public static readonly string IndexerNameAlias
= "<this>";
218 public static readonly MemberCache Empty
= new MemberCache (0);
220 public MemberCache ()
225 public MemberCache (int capacity
)
227 member_hash
= new Dictionary
<string, IList
<MemberSpec
>> (capacity
);
230 public MemberCache (MemberCache cache
)
231 : this (cache
.member_hash
.Count
)
236 // Creates a new MemberCache for the given `container'.
238 public MemberCache (TypeContainer container
)
239 : this () // TODO: Optimize the size
244 // Member-cache does not contain base members but it does
245 // contain all base interface members, so the Lookup code
246 // can use simple inheritance rules.
248 public void AddInterface (TypeSpec iface
)
250 var cache
= iface
.MemberCache
;
252 IList
<MemberSpec
> list
;
253 foreach (var entry
in cache
.member_hash
) {
254 if (!member_hash
.TryGetValue (entry
.Key
, out list
)) {
255 if (entry
.Value
.Count
== 1) {
258 list
= new List
<MemberSpec
> (entry
.Value
);
261 member_hash
.Add (entry
.Key
, list
);
265 foreach (var ce
in entry
.Value
) {
266 if (ce
.DeclaringType
!= iface
)
269 if (list
.Contains (ce
))
272 if (AddInterfaceMember (ce
, ref list
))
273 member_hash
[entry
.Key
] = list
;
278 public void AddMember (InterfaceMemberBase imb
, string exlicitName
, MemberSpec ms
)
280 // Explicit names cannot be looked-up but can be used for
281 // collision checking (no name mangling needed)
282 if (imb
.IsExplicitImpl
)
283 AddMember (exlicitName
, ms
);
289 // Add non-explicit member to member cache
291 public void AddMember (MemberSpec ms
)
293 AddMember (GetLookupName (ms
), ms
);
296 void AddMember (string name
, MemberSpec member
)
298 IList
<MemberSpec
> list
;
299 if (!member_hash
.TryGetValue (name
, out list
)) {
300 member_hash
.Add (name
, new MemberSpec
[] { member }
);
304 if (member
.DeclaringType
.IsInterface
) {
305 if (AddInterfaceMember (member
, ref list
))
306 member_hash
[name
] = list
;
308 if (list
is MemberSpec
[]) {
309 list
= new List
<MemberSpec
> () { list[0] }
;
310 member_hash
[name
] = list
;
318 // Ignores any base interface member which can be hidden
321 static bool AddInterfaceMember (MemberSpec member
, ref IList
<MemberSpec
> existing
)
323 var member_param
= member
is IParametersMember
? ((IParametersMember
) member
).Parameters
: ParametersCompiled
.EmptyReadOnlyParameters
;
326 // interface IA : IB { int Prop { set; } }
327 // interface IB { bool Prop { get; } }
329 // IB.Prop is never accessible from IA interface
331 for (int i
= 0; i
< existing
.Count
; ++i
) {
332 var entry
= existing
[i
];
334 if (entry
.Arity
!= member
.Arity
)
337 if (entry
is IParametersMember
) {
338 var entry_param
= ((IParametersMember
) entry
).Parameters
;
339 if (!TypeSpecComparer
.Override
.IsEqual (entry_param
, member_param
))
343 if (member
.DeclaringType
.ImplementsInterface (entry
.DeclaringType
)) {
344 if (existing
is MemberSpec
[]) {
345 existing
= new MemberSpec
[] { member }
;
349 existing
.RemoveAt (i
--);
353 if (entry
.DeclaringType
== member
.DeclaringType
|| entry
.DeclaringType
.ImplementsInterface (member
.DeclaringType
))
357 if (existing
is MemberSpec
[]) {
358 existing
= new List
<MemberSpec
> () { existing[0], member }
;
362 existing
.Add (member
);
366 public static IEnumerable
<IndexerSpec
> FindIndexers (TypeSpec container
, BindingRestriction restrictions
)
368 var filter
= new MemberFilter (IndexerNameAlias
, 0, MemberKind
.Indexer
, null, null);
369 var found
= FindMembers (container
, filter
, restrictions
);
370 return found
== null ? null : found
.Cast
<IndexerSpec
> ();
373 public static MemberSpec
FindMember (TypeSpec container
, MemberFilter filter
, BindingRestriction restrictions
)
376 IList
<MemberSpec
> applicable
;
377 if (container
.MemberCache
.member_hash
.TryGetValue (filter
.Name
, out applicable
)) {
378 // Start from the end because interface members are in reverse order
379 for (int i
= applicable
.Count
- 1; i
>= 0; i
--) {
380 var entry
= applicable
[i
];
382 if ((restrictions
& BindingRestriction
.InstanceOnly
) != 0 && entry
.IsStatic
)
385 if (filter
.Equals (entry
))
389 //if ((restrictions & BindingRestriction.AccessibleOnly) != 0)
390 // throw new NotImplementedException ("net");
394 container
= container
.BaseType
;
395 } while (container
!= null && (restrictions
& BindingRestriction
.DeclaredOnly
) == 0);
401 // Returns the first set of members starting from container
403 public static IList
<MemberSpec
> FindMembers (TypeSpec container
, MemberFilter filter
, BindingRestriction restrictions
)
405 IList
<MemberSpec
> applicable
;
406 IList
<MemberSpec
> found
= null;
409 if (container
.MemberCache
.member_hash
.TryGetValue (filter
.Name
, out applicable
)) {
410 for (int i
= 0; i
< applicable
.Count
; ++i
) {
411 var entry
= applicable
[i
];
413 // Is the member of the correct type
414 if ((entry
.Kind
& filter
.Kind
& MemberKind
.MaskType
) == 0)
418 // When using overloadable overrides filter ignore members which
419 // are not base members. Including properties because overrides can
420 // implement get or set only and we are looking for complete base member
422 const MemberKind overloadable
= MemberKind
.Indexer
| MemberKind
.Method
| MemberKind
.Property
;
423 if ((restrictions
& BindingRestriction
.NoOverrides
) != 0 && (entry
.Kind
& overloadable
) != 0) {
424 if ((entry
.Modifiers
& Modifiers
.OVERRIDE
) != 0)
427 if ((entry
.Modifiers
& Modifiers
.OVERRIDE_UNCHECKED
) != 0) {
428 bool is_override
= true;
429 var ms
= entry
as MethodSpec
;
431 is_override
= IsRealMethodOverride (ms
);
433 var ps
= (PropertySpec
) entry
;
435 is_override
= IsRealMethodOverride (ps
.Get
);
436 if (is_override
&& ps
.HasSet
)
437 is_override
= IsRealMethodOverride (ps
.Set
);
441 entry
.Modifiers
= (entry
.Modifiers
& ~Modifiers
.OVERRIDE_UNCHECKED
) | Modifiers
.OVERRIDE
;
447 if ((restrictions
& BindingRestriction
.InstanceOnly
) != 0 && entry
.IsStatic
)
450 // Apply the filter to it.
451 if (!filter
.Equals (entry
))
458 found
= new List
<MemberSpec
> ();
461 } else if (found
== applicable
) {
462 found
= new List
<MemberSpec
> ();
463 found
.Add (applicable
[0]);
471 if (found
== applicable
&& applicable
.Count
!= 1)
472 return new MemberSpec
[] { found[0] }
;
478 container
= container
.BaseType
;
479 } while (container
!= null && (restrictions
& BindingRestriction
.DeclaredOnly
) == 0);
485 // Finds the nested type in container
487 public static TypeSpec
FindNestedType (TypeSpec container
, string name
, int arity
)
489 IList
<MemberSpec
> applicable
;
490 TypeSpec best_match
= null;
492 // TODO: Don't know how to handle this yet
493 // When resolving base type of nested type, parent type must have
494 // base type resolved to scan full hierarchy correctly
495 // Similarly MemberCacheTypes will inflate BaseType and Interfaces
496 // based on type definition
497 var tc
= container
.MemberDefinition
as TypeContainer
;
501 if (container
.MemberCacheTypes
.member_hash
.TryGetValue (name
, out applicable
)) {
502 for (int i
= applicable
.Count
- 1; i
>= 0; i
--) {
503 var entry
= applicable
[i
];
504 if ((entry
.Kind
& MemberKind
.NestedMask
) == 0)
507 var ts
= (TypeSpec
) entry
;
508 if (arity
== ts
.Arity
)
512 if (best_match
== null) {
514 } else if (System
.Math
.Abs (ts
.Arity
+ arity
) < System
.Math
.Abs (ts
.Arity
+ arity
)) {
521 container
= container
.BaseType
;
522 } while (container
!= null);
528 // Looks for extension methods with defined name and extension type
530 public List
<MethodSpec
> FindExtensionMethods (TypeSpec invocationType
, TypeSpec extensionType
, string name
, int arity
)
532 IList
<MemberSpec
> entries
;
533 if (!member_hash
.TryGetValue (name
, out entries
))
536 List
<MethodSpec
> candidates
= null;
537 foreach (var entry
in entries
) {
538 if (entry
.Kind
!= MemberKind
.Method
|| (arity
>= 0 && entry
.Arity
!= arity
))
541 var ms
= (MethodSpec
) entry
;
542 if (!ms
.IsExtensionMethod
)
546 if (!Expression
.IsMemberAccessible (invocationType
, ms
, out extra
))
549 // TODO: CodeGen.Assembly.Builder
550 if ((ms
.DeclaringType
.Modifiers
& Modifiers
.INTERNAL
) != 0 &&
551 !TypeManager
.IsThisOrFriendAssembly (CodeGen
.Assembly
.Builder
, ms
.Assembly
))
554 if (candidates
== null)
555 candidates
= new List
<MethodSpec
> ();
563 // Returns base members of @member member if no exact match is found @bestCandidate returns
566 public static MemberSpec
FindBaseMember (MemberCore member
, out MemberSpec bestCandidate
)
568 bestCandidate
= null;
569 var container
= member
.Parent
.PartialContainer
.Definition
;
570 if (!container
.IsInterface
)
571 container
= container
.BaseType
;
573 string name
= GetLookupName (member
);
574 IList
<MemberSpec
> applicable
;
575 var member_param
= member
is IParametersMember
? ((IParametersMember
) member
).Parameters
: null;
577 var mkind
= GetMemberCoreKind (member
);
580 if (container
.MemberCache
.member_hash
.TryGetValue (name
, out applicable
)) {
581 for (int i
= 0; i
< applicable
.Count
; ++i
) {
582 var entry
= applicable
[i
];
584 if ((entry
.Modifiers
& Modifiers
.PRIVATE
) != 0)
587 if ((entry
.Modifiers
& Modifiers
.AccessibilityMask
) == Modifiers
.INTERNAL
) {
588 if (!TypeManager
.IsThisOrFriendAssembly (member
.Assembly
, entry
.Assembly
))
593 // Is the member of the correct type ?
594 // Destructors are ignored as they cannot be overridden by user
595 if ((entry
.Kind
& ~MemberKind
.Destructor
& mkind
& MemberKind
.MaskType
) == 0) {
596 if ((entry
.Kind
& MemberKind
.Destructor
) == 0 && (member_param
== null || !(entry
is IParametersMember
))) {
597 bestCandidate
= entry
;
604 if (member_param
== null)
608 int arity
= member
.MemberName
.Arity
;
609 if (arity
!= entry
.Arity
)
612 if (entry
is IParametersMember
) {
613 if (entry
.IsAccessor
!= member
is AbstractPropertyEventMethod
)
616 var entry_param
= ((IParametersMember
) entry
).Parameters
;
617 if (TypeSpecComparer
.Override
.IsEqual (entry_param
, member_param
))
623 if (bestCandidate
== null)
624 bestCandidate
= entry
;
627 if (member_param
== null)
631 if (container
.IsInterface
)
634 container
= container
.BaseType
;
635 } while (container
!= null);
641 // Returns inflated version of MemberSpec, it works similarly to
642 // SRE TypeBuilder.GetMethod
644 public static T GetMember
<T
> (TypeSpec container
, T spec
) where T
: MemberSpec
646 IList
<MemberSpec
> applicable
;
647 if (container
.MemberCache
.member_hash
.TryGetValue (GetLookupName (spec
), out applicable
)) {
648 for (int i
= applicable
.Count
- 1; i
>= 0; i
--) {
649 var entry
= applicable
[i
];
650 if (entry
.MemberDefinition
== spec
.MemberDefinition
)
655 throw new InternalErrorException ("Missing member `{0}' on inflated type `{1}'",
656 spec
.GetSignatureForError (), container
.GetSignatureForError ());
659 static MemberKind
GetMemberCoreKind (MemberCore member
)
661 if (member
is FieldBase
)
662 return MemberKind
.Field
;
663 if (member
is Indexer
)
664 return MemberKind
.Indexer
;
666 return MemberKind
.Class
;
667 if (member
is Struct
)
668 return MemberKind
.Struct
;
669 if (member
is Destructor
)
670 return MemberKind
.Destructor
;
671 if (member
is Method
)
672 return MemberKind
.Method
;
673 if (member
is Property
)
674 return MemberKind
.Property
;
675 if (member
is EventField
)
676 return MemberKind
.Event
;
677 if (member
is Interface
)
678 return MemberKind
.Interface
;
679 if (member
is EventProperty
)
680 return MemberKind
.Event
;
682 throw new NotImplementedException (member
.GetType ().ToString ());
685 public static IList
<MemberSpec
> GetCompletitionMembers (TypeSpec container
, string name
)
687 var matches
= new List
<MemberSpec
> ();
688 foreach (var entry
in container
.MemberCache
.member_hash
) {
689 foreach (var name_entry
in entry
.Value
) {
690 if (name_entry
.IsAccessor
)
693 if ((name_entry
.Kind
& (MemberKind
.Constructor
| MemberKind
.FakeMethod
| MemberKind
.Destructor
)) != 0)
697 if (!Expression
.IsMemberAccessible (InternalType
.FakeInternalType
, name_entry
, out extra
))
700 if (name
== null || name_entry
.Name
.StartsWith (name
)) {
701 matches
.Add (name_entry
);
710 // Returns members of @iface only, base members are ignored
712 public static IList
<MethodSpec
> GetInterfaceMembers (TypeSpec iface
)
715 // MemberCache flatten interfaces, therefore in cases like this one
717 // interface IA : IB {}
718 // interface IB { void Foo () }
720 // we would return Foo inside IA which is not expected in this case
722 var methods
= new List
<MethodSpec
> ();
723 foreach (var entry
in iface
.MemberCache
.member_hash
.Values
) {
724 foreach (var name_entry
in entry
) {
725 if (iface
== name_entry
.DeclaringType
) {
726 if (name_entry
.Kind
== MemberKind
.Method
) {
727 methods
.Add ((MethodSpec
) name_entry
);
736 public static IList
<MethodSpec
> GetNotImplementedAbstractMethods (TypeSpec type
)
738 if (type
.MemberCache
.missing_abstract
!= null)
739 return type
.MemberCache
.missing_abstract
;
741 var abstract_methods
= new List
<MethodSpec
> ();
742 List
<TypeSpec
> hierarchy
= null;
745 // Stage 1: top-to-bottom scan for abstract members
747 var abstract_type
= type
;
749 foreach (var entry
in abstract_type
.MemberCache
.member_hash
) {
750 foreach (var name_entry
in entry
.Value
) {
751 if ((name_entry
.Modifiers
& Modifiers
.ABSTRACT
) == 0)
754 if (name_entry
.Kind
!= MemberKind
.Method
)
757 abstract_methods
.Add ((MethodSpec
) name_entry
);
761 var base_type
= abstract_type
.BaseType
;
762 if (!base_type
.IsAbstract
)
765 if (hierarchy
== null)
766 hierarchy
= new List
<TypeSpec
> ();
768 hierarchy
.Add (abstract_type
);
769 abstract_type
= base_type
;
772 int not_implemented_count
= abstract_methods
.Count
;
773 if (not_implemented_count
== 0 || hierarchy
== null) {
774 type
.MemberCache
.missing_abstract
= abstract_methods
;
775 return type
.MemberCache
.missing_abstract
;
779 // Stage 2: Remove already implemented methods
781 foreach (var type_up
in hierarchy
) {
782 var members
= type_up
.MemberCache
.member_hash
;
783 if (members
.Count
== 0)
786 for (int i
= 0; i
< abstract_methods
.Count
; ++i
) {
787 var candidate
= abstract_methods
[i
];
788 if (candidate
== null)
791 IList
<MemberSpec
> applicable
;
792 if (!members
.TryGetValue (candidate
.Name
, out applicable
))
795 var filter
= new MemberFilter (candidate
);
796 foreach (var item
in applicable
) {
797 // TODO: Need to test what should happen for OVERRIDE_UNCHECKED
798 if ((item
.Modifiers
& (Modifiers
.OVERRIDE
| Modifiers
.OVERRIDE_UNCHECKED
| Modifiers
.VIRTUAL
)) == 0)
801 if (filter
.Equals (item
)) {
802 --not_implemented_count
;
803 abstract_methods
[i
] = null;
810 if (not_implemented_count
== abstract_methods
.Count
) {
811 type
.MemberCache
.missing_abstract
= abstract_methods
;
812 return type
.MemberCache
.missing_abstract
;
815 var not_implemented
= new MethodSpec
[not_implemented_count
];
817 foreach (var m
in abstract_methods
) {
821 not_implemented
[counter
++] = m
;
824 type
.MemberCache
.missing_abstract
= not_implemented
;
825 return type
.MemberCache
.missing_abstract
;
828 static string GetLookupName (MemberSpec ms
)
830 if (ms
.Kind
== MemberKind
.Indexer
)
831 return IndexerNameAlias
;
833 if (ms
.Kind
== MemberKind
.Constructor
) {
835 return ConstructorInfo
.TypeConstructorName
;
837 return ConstructorInfo
.ConstructorName
;
843 static string GetLookupName (MemberCore mc
)
846 return IndexerNameAlias
;
848 if (mc
is Constructor
)
849 return ConstructorInfo
.ConstructorName
;
851 return mc
.MemberName
.Name
;
855 // Returns all operators declared on container and its base types
857 public static MethodSpec
[] GetUserOperator (TypeSpec container
, Operator
.OpType op
, bool declaredOnly
)
859 MethodSpec
[] found
= null;
861 IList
<MemberSpec
> applicable
;
863 var mc
= container
.MemberCache
;
864 if (op
== Operator
.OpType
.Implicit
&& (mc
.state
& StateFlags
.HasNoImplicitOperator
) == 0 ||
865 op
== Operator
.OpType
.Explicit
&& (mc
.state
& StateFlags
.HasNoExplicitOperator
) == 0) {
867 if (mc
.member_hash
.TryGetValue (Operator
.GetMetadataName (op
), out applicable
)) {
871 found
= new MethodSpec
[applicable
.Count
];
873 start_index
= found
.Length
- 1;
874 Array
.Resize (ref found
, found
.Length
+ applicable
.Count
);
877 for (int i
= 0; i
< applicable
.Count
; ++i
) {
878 if (applicable
[i
].Kind
== MemberKind
.Operator
)
879 found
[i
+ start_index
] = (MethodSpec
) applicable
[i
];
881 } else if (op
== Operator
.OpType
.Implicit
) {
882 mc
.state
|= StateFlags
.HasNoImplicitOperator
;
883 } else if (op
== Operator
.OpType
.Explicit
) {
884 mc
.state
|= StateFlags
.HasNoExplicitOperator
;
888 // BaseType call can be expensive
892 container
= container
.BaseType
;
893 } while (container
!= null && container
.BaseType
!= null);
899 // Inflates all member cache nested types
901 public void InflateTypes (MemberCache inflated_cache
, TypeParameterInflator inflator
)
903 foreach (var item
in member_hash
) {
904 IList
<MemberSpec
> inflated_members
= null;
905 for (int i
= 0; i
< item
.Value
.Count
; ++i
) {
906 var member
= item
.Value
[i
];
908 // FIXME: When inflating members refering nested types before they are inflated
912 if ((member
.Kind
& MemberKind
.NestedMask
) != 0 &&
913 (member
.Modifiers
& Modifiers
.COMPILER_GENERATED
) == 0) {
914 if (inflated_members
== null) {
915 inflated_members
= new MemberSpec
[item
.Value
.Count
];
916 inflated_cache
.member_hash
.Add (item
.Key
, inflated_members
);
919 inflated_members
[i
] = member
.InflateMember (inflator
);
926 // Inflates all open type members, requires InflateTypes to be called before
928 public void InflateMembers (MemberCache cacheToInflate
, TypeSpec inflatedType
, TypeParameterInflator inflator
)
930 var inflated_member_hash
= cacheToInflate
.member_hash
;
931 Dictionary
<MethodSpec
, MethodSpec
> accessor_relation
= null;
932 List
<MemberSpec
> accessor_members
= null;
934 foreach (var item
in member_hash
) {
935 var members
= item
.Value
;
936 IList
<MemberSpec
> inflated_members
= null;
937 for (int i
= 0; i
< members
.Count
; ++i
) {
938 var member
= members
[i
];
941 // All nested types have been inflated earlier except for
942 // compiler types which are created later and could miss InflateTypes
944 if ((member
.Kind
& MemberKind
.NestedMask
) != 0 &&
945 (member
.Modifiers
& Modifiers
.COMPILER_GENERATED
) == 0) {
946 if (inflated_members
== null)
947 inflated_members
= inflated_member_hash
[item
.Key
];
953 // Clone the container first
955 if (inflated_members
== null) {
956 inflated_members
= new MemberSpec
[item
.Value
.Count
];
957 inflated_member_hash
.Add (item
.Key
, inflated_members
);
960 var local_inflator
= inflator
;
962 if (member
.DeclaringType
!= inflatedType
) {
964 // Don't inflate non generic interface members
965 // merged into generic interface
967 if (!member
.DeclaringType
.IsGeneric
) {
968 inflated_members
[i
] = member
;
973 // Needed when inflating flatten interfaces. It inflates
974 // container type only, type parameters are already done
976 // Handles cases like:
979 // interface I<U, V> : I<U> {}
981 // class C: I<int, bool> {}
983 var inflated_parent
= inflator
.Inflate (member
.DeclaringType
);
984 if (inflated_parent
!= inflator
.TypeInstance
)
985 local_inflator
= new TypeParameterInflator (inflator
, inflated_parent
);
989 // Inflate every member, its parent is now different
991 var inflated
= member
.InflateMember (local_inflator
);
992 inflated_members
[i
] = inflated
;
994 if (member
is PropertySpec
|| member
is EventSpec
) {
995 if (accessor_members
== null)
996 accessor_members
= new List
<MemberSpec
> ();
998 accessor_members
.Add (inflated
);
1002 if (member
.IsAccessor
) {
1003 if (accessor_relation
== null)
1004 accessor_relation
= new Dictionary
<MethodSpec
, MethodSpec
> ();
1005 accessor_relation
.Add ((MethodSpec
) member
, (MethodSpec
) inflated
);
1010 if (accessor_members
!= null) {
1011 foreach (var member
in accessor_members
) {
1012 var prop
= member
as PropertySpec
;
1014 if (prop
.Get
!= null)
1015 prop
.Get
= accessor_relation
[prop
.Get
];
1016 if (prop
.Set
!= null)
1017 prop
.Set
= accessor_relation
[prop
.Set
];
1022 var ev
= (EventSpec
) member
;
1023 ev
.AccessorAdd
= accessor_relation
[ev
.AccessorAdd
];
1024 ev
.AccessorRemove
= accessor_relation
[ev
.AccessorRemove
];
1030 // For imported class method do additional validation to be sure that metadata
1031 // override flag was correct
1033 static bool IsRealMethodOverride (MethodSpec ms
)
1035 IList
<MemberSpec
> candidates
;
1036 var dt
= ms
.DeclaringType
;
1037 while (dt
.BaseType
!= null) {
1038 var base_cache
= dt
.BaseType
.MemberCache
;
1039 if (base_cache
.member_hash
.TryGetValue (ms
.Name
, out candidates
)) {
1040 foreach (var candidate
in candidates
) {
1041 if (candidate
.Kind
!= ms
.Kind
)
1044 if (candidate
.Arity
!= ms
.Arity
)
1047 if (!TypeSpecComparer
.Override
.IsEqual (((MethodSpec
) candidate
).Parameters
, ms
.Parameters
))
1050 // Everything matches except modifiers, it's not correct soverride
1051 if ((candidate
.Modifiers
& Modifiers
.AccessibilityMask
) != (ms
.Modifiers
& Modifiers
.AccessibilityMask
))
1065 // Checks all appropriate container members for CLS compliance
1067 public void VerifyClsCompliance (TypeSpec container
, Report report
)
1069 if (locase_members
!= null)
1072 if (container
.BaseType
== null) {
1073 locase_members
= new Dictionary
<string, MemberSpec
[]> (member_hash
.Count
); // StringComparer.OrdinalIgnoreCase);
1075 container
.BaseType
.MemberCache
.VerifyClsCompliance (container
.BaseType
, report
);
1076 locase_members
= new Dictionary
<string, MemberSpec
[]> (container
.BaseType
.MemberCache
.locase_members
); //, StringComparer.OrdinalIgnoreCase);
1079 var is_imported_type
= container
.MemberDefinition
.IsImported
;
1080 foreach (var entry
in container
.MemberCache
.member_hash
) {
1081 for (int i
= 0; i
< entry
.Value
.Count
; ++i
) {
1082 var name_entry
= entry
.Value
[i
];
1083 if ((name_entry
.Modifiers
& (Modifiers
.PUBLIC
| Modifiers
.PROTECTED
)) == 0)
1086 if ((name_entry
.Modifiers
& (Modifiers
.OVERRIDE
| Modifiers
.COMPILER_GENERATED
)) != 0)
1089 if ((name_entry
.Kind
& MemberKind
.MaskType
) == 0)
1092 if (name_entry
.MemberDefinition
.IsNotCLSCompliant ())
1095 IParametersMember p_a
= name_entry
as IParametersMember
;
1096 if (p_a
!= null && !name_entry
.IsAccessor
) {
1097 if (!is_imported_type
) {
1098 var p_a_pd
= p_a
.Parameters
;
1099 for (int ii
= i
+ 1; ii
< entry
.Value
.Count
; ++ii
) {
1100 var checked_entry
= entry
.Value
[ii
];
1101 IParametersMember p_b
= checked_entry
as IParametersMember
;
1105 if (p_a_pd
.Count
!= p_b
.Parameters
.Count
)
1108 if (checked_entry
.IsAccessor
)
1111 var res
= ParametersCompiled
.IsSameClsSignature (p_a
.Parameters
, p_b
.Parameters
);
1113 var last
= GetLaterDefinedMember (checked_entry
, name_entry
);
1114 if (last
== checked_entry
.MemberDefinition
) {
1115 report
.SymbolRelatedToPreviousError (name_entry
);
1117 report
.SymbolRelatedToPreviousError (checked_entry
);
1120 if ((res
& 1) != 0) {
1121 report
.Warning (3006, 1, last
.Location
,
1122 "Overloaded method `{0}' differing only in ref or out, or in array rank, is not CLS-compliant",
1123 name_entry
.GetSignatureForError ());
1126 if ((res
& 2) != 0) {
1127 report
.Warning (3007, 1, last
.Location
,
1128 "Overloaded method `{0}' differing only by unnamed array types is not CLS-compliant",
1129 name_entry
.GetSignatureForError ());
1136 if (i
> 0 || name_entry
.Kind
== MemberKind
.Constructor
|| name_entry
.Kind
== MemberKind
.Indexer
)
1139 var name_entry_locase
= name_entry
.Name
.ToLowerInvariant ();
1142 if (!locase_members
.TryGetValue (name_entry_locase
, out found
)) {
1143 found
= new MemberSpec
[] { name_entry }
;
1144 locase_members
.Add (name_entry_locase
, found
);
1146 bool same_names_only
= true;
1147 foreach (var f
in found
) {
1148 if (f
.Name
== name_entry
.Name
)
1151 // if (f.IsAccessor && name_entry.IsAccessor)
1154 same_names_only
= false;
1155 if (!is_imported_type
) {
1156 var last
= GetLaterDefinedMember (f
, name_entry
);
1157 if (last
== f
.MemberDefinition
) {
1158 report
.SymbolRelatedToPreviousError (name_entry
);
1160 report
.SymbolRelatedToPreviousError (f
);
1163 report
.Warning (3005, 1, last
.Location
,
1164 "Identifier `{0}' differing only in case is not CLS-compliant", last
.GetSignatureForError ());
1168 if (!same_names_only
) {
1169 Array
.Resize (ref found
, found
.Length
+ 1);
1170 found
[found
.Length
- 1] = name_entry
;
1171 locase_members
[name_entry_locase
] = found
;
1179 // Local report helper to issue correctly ordered members stored in hashtable
1181 static MemberCore
GetLaterDefinedMember (MemberSpec a
, MemberSpec b
)
1183 var mc_a
= a
.MemberDefinition
as MemberCore
;
1184 var mc_b
= b
.MemberDefinition
as MemberCore
;
1191 if (mc_a
.Location
.File
!= mc_a
.Location
.File
)
1194 return mc_b
.Location
.Row
> mc_a
.Location
.Row
? mc_b
: mc_a
;
1197 public bool CheckExistingMembersOverloads (MemberCore member
, AParametersCollection parameters
)
1199 var name
= GetLookupName (member
);
1200 var imb
= member
as InterfaceMemberBase
;
1201 if (imb
!= null && imb
.IsExplicitImpl
) {
1202 name
= imb
.GetFullName (name
);
1205 return CheckExistingMembersOverloads (member
, name
, parameters
);
1208 public bool CheckExistingMembersOverloads (MemberCore member
, string name
, AParametersCollection parameters
)
1210 IList
<MemberSpec
> entries
;
1211 if (!member_hash
.TryGetValue (name
, out entries
))
1214 var Report
= member
.Compiler
.Report
;
1216 int method_param_count
= parameters
.Count
;
1217 for (int i
= entries
.Count
- 1; i
>= 0; --i
) {
1218 var ce
= entries
[i
];
1219 var pm
= ce
as IParametersMember
;
1220 var pd
= pm
== null ? ParametersCompiled
.EmptyReadOnlyParameters
: pm
.Parameters
;
1221 if (pd
.Count
!= method_param_count
)
1224 if (ce
.Arity
!= member
.MemberName
.Arity
)
1227 // Ignore merged interface members
1228 if (member
.Parent
.PartialContainer
!= ce
.DeclaringType
.MemberDefinition
)
1231 var p_types
= pd
.Types
;
1232 if (method_param_count
> 0) {
1233 int ii
= method_param_count
- 1;
1234 TypeSpec type_a
, type_b
;
1236 type_a
= parameters
.Types
[ii
];
1237 type_b
= p_types
[ii
];
1239 if ((pd
.FixedParameters
[ii
].ModFlags
& Parameter
.Modifier
.ISBYREF
) !=
1240 (parameters
.FixedParameters
[ii
].ModFlags
& Parameter
.Modifier
.ISBYREF
))
1243 } while (TypeSpecComparer
.Override
.IsEqual (type_a
, type_b
) && ii
-- != 0);
1249 // Operators can differ in return type only
1251 if (member
is Operator
&& ce
.Kind
== MemberKind
.Operator
&& ((MethodSpec
) ce
).ReturnType
!= ((Operator
) member
).ReturnType
)
1255 // Report difference in parameter modifiers only
1257 if (pd
!= null && member
is MethodCore
) {
1258 ii
= method_param_count
;
1259 while (ii
-- != 0 && parameters
.FixedParameters
[ii
].ModFlags
== pd
.FixedParameters
[ii
].ModFlags
&&
1260 parameters
.ExtensionMethodType
== pd
.ExtensionMethodType
) ;
1263 var mc
= ce
as MethodSpec
;
1264 member
.Compiler
.Report
.SymbolRelatedToPreviousError (ce
);
1265 if ((member
.ModFlags
& Modifiers
.PARTIAL
) != 0 && (mc
.Modifiers
& Modifiers
.PARTIAL
) != 0) {
1266 if (parameters
.HasParams
|| pd
.HasParams
) {
1267 Report
.Error (758, member
.Location
,
1268 "A partial method declaration and partial method implementation cannot differ on use of `params' modifier");
1270 Report
.Error (755, member
.Location
,
1271 "A partial method declaration and partial method implementation must be both an extension method or neither");
1273 } else if (member
is Constructor
) {
1274 Report
.Error (851, member
.Location
,
1275 "Overloaded contructor `{0}' cannot differ on use of parameter modifiers only",
1276 member
.GetSignatureForError ());
1278 Report
.Error (663, member
.Location
,
1279 "Overloaded method `{0}' cannot differ on use of parameter modifiers only",
1280 member
.GetSignatureForError ());
1287 if ((ce
.Kind
& (MemberKind
.Method
| MemberKind
.FakeMethod
)) != 0) {
1288 Method method_a
= member
as Method
;
1289 Method method_b
= ce
.MemberDefinition
as Method
;
1290 if (method_a
!= null && method_b
!= null && (method_a
.ModFlags
& method_b
.ModFlags
& Modifiers
.PARTIAL
) != 0) {
1291 const Modifiers partial_modifiers
= Modifiers
.STATIC
| Modifiers
.UNSAFE
;
1292 if (method_a
.IsPartialDefinition
== method_b
.IsPartialImplementation
) {
1293 if ((method_a
.ModFlags
& partial_modifiers
) == (method_b
.ModFlags
& partial_modifiers
) ||
1294 method_a
.Parent
.IsUnsafe
&& method_b
.Parent
.IsUnsafe
) {
1295 if (method_a
.IsPartialImplementation
) {
1296 method_a
.SetPartialDefinition (method_b
);
1297 if (entries
.Count
== 1)
1298 member_hash
.Remove (name
);
1300 entries
.RemoveAt (i
);
1302 method_b
.SetPartialDefinition (method_a
);
1303 method_a
.caching_flags
|= MemberCore
.Flags
.PartialDefinitionExists
;
1308 if (method_a
.IsStatic
!= method_b
.IsStatic
) {
1309 Report
.SymbolRelatedToPreviousError (ce
);
1310 Report
.Error (763, member
.Location
,
1311 "A partial method declaration and partial method implementation must be both `static' or neither");
1314 Report
.SymbolRelatedToPreviousError (ce
);
1315 Report
.Error (764, member
.Location
,
1316 "A partial method declaration and partial method implementation must be both `unsafe' or neither");
1320 Report
.SymbolRelatedToPreviousError (ce
);
1321 if (method_a
.IsPartialDefinition
) {
1322 Report
.Error (756, member
.Location
, "A partial method `{0}' declaration is already defined",
1323 member
.GetSignatureForError ());
1326 Report
.Error (757, member
.Location
, "A partial method `{0}' implementation is already defined",
1327 member
.GetSignatureForError ());
1331 Report
.SymbolRelatedToPreviousError (ce
);
1333 bool is_reserved_a
= member
is AbstractPropertyEventMethod
|| member
is Operator
;
1334 bool is_reserved_b
= ((MethodSpec
) ce
).IsReservedMethod
;
1336 if (is_reserved_a
|| is_reserved_b
) {
1337 Report
.Error (82, member
.Location
, "A member `{0}' is already reserved",
1339 ce
.GetSignatureForError () :
1340 member
.GetSignatureForError ());
1344 Report
.SymbolRelatedToPreviousError (ce
);
1347 if (member
is Operator
&& ce
.Kind
== MemberKind
.Operator
) {
1348 Report
.Error (557, member
.Location
, "Duplicate user-defined conversion in type `{0}'",
1349 member
.Parent
.GetSignatureForError ());
1353 Report
.Error (111, member
.Location
,
1354 "A member `{0}' is already defined. Rename this member or use different parameter types",
1355 member
.GetSignatureForError ());