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,
43 PointerType
= 1 << 20,
44 InternalCompilerType
= 1 << 21,
47 NestedMask
= Class
| Struct
| Delegate
| Enum
| Interface
,
48 GenericMask
= Method
| Class
| Struct
| Delegate
| Interface
,
49 MaskType
= Constructor
| Event
| Field
| Method
| Property
| Indexer
| Operator
| Destructor
| NestedMask
,
54 public enum BindingRestriction
58 // Member has to be accessible
61 // Inspect only queried type members
62 DeclaredOnly
= 1 << 1,
65 InstanceOnly
= 1 << 2,
67 // Ignore member overrides
71 public struct MemberFilter
: IEquatable
<MemberSpec
>
73 public readonly string Name
;
74 public readonly MemberKind Kind
;
75 public readonly AParametersCollection Parameters
;
76 public readonly TypeSpec MemberType
;
78 int arity
; // -1 to ignore the check
79 TypeSpec invocation_type
;
81 private MemberFilter (string name
, MemberKind kind
)
88 invocation_type
= null;
91 public MemberFilter (MethodSpec m
)
94 Kind
= MemberKind
.Method
;
95 Parameters
= m
.Parameters
;
96 MemberType
= m
.ReturnType
;
98 invocation_type
= null;
101 public MemberFilter (string name
, int arity
, MemberKind kind
, AParametersCollection param
, TypeSpec type
)
108 invocation_type
= null;
111 public TypeSpec InvocationType
{
113 return invocation_type
;
116 invocation_type
= value;
120 public static MemberFilter
Constructor (AParametersCollection param
)
122 return new MemberFilter (System
.Reflection
.ConstructorInfo
.ConstructorName
, 0, MemberKind
.Constructor
, param
, null);
125 public static MemberFilter
Property (string name
, TypeSpec type
)
127 return new MemberFilter (name
, 0, MemberKind
.Property
, null, type
);
130 public static MemberFilter
Field (string name
, TypeSpec type
)
132 return new MemberFilter (name
, 0, MemberKind
.Field
, null, type
);
135 public static MemberFilter
Method (string name
, int arity
, AParametersCollection param
, TypeSpec type
)
137 return new MemberFilter (name
, arity
, MemberKind
.Method
, param
, type
);
140 #region IEquatable<MemberSpec> Members
142 public bool Equals (MemberSpec other
)
144 // Is the member of the correct type ?
145 // TODO: Isn't this redundant ?
146 if ((other
.Kind
& Kind
& MemberKind
.MaskType
) == 0)
149 // Check arity when not disabled
150 if (arity
>= 0 && arity
!= other
.Arity
)
153 if (Parameters
!= null) {
154 if (other
is IParametersMember
) {
155 var other_param
= ((IParametersMember
) other
).Parameters
;
156 if (!TypeSpecComparer
.Override
.IsEqual (Parameters
, other_param
))
163 if (MemberType
!= null) {
164 if (other
is IInterfaceMemberSpec
) {
165 var other_type
= ((IInterfaceMemberSpec
) other
).MemberType
;
166 if (!TypeSpecComparer
.Override
.IsEqual (other_type
, MemberType
))
173 if (invocation_type
!= null && !IsAccessible (other
))
179 bool IsAccessible (MemberSpec other
)
182 return Expression
.IsMemberAccessible (invocation_type
, other
, out extra
);
189 /// The MemberCache is used by dynamic and non-dynamic types to speed up
190 /// member lookups. It has a member name based hash table; it maps each member
191 /// name to a list of CacheEntry objects. Each CacheEntry contains a MemberInfo
192 /// and the BindingFlags that were initially used to get it. The cache contains
193 /// all members of the current class and all inherited members. If this cache is
194 /// for an interface types, it also contains all inherited members.
196 /// There are two ways to get a MemberCache:
197 /// * if this is a dynamic type, lookup the corresponding DeclSpace and then
198 /// use the DeclSpace.MemberCache property.
199 /// * if this not a dynamic type, call TypeHandle.GetTypeHandle() to get a
200 /// TypeHandle instance for the type and then use TypeHandle.MemberCache.
202 public class MemberCache
204 readonly Dictionary
<string, IList
<MemberSpec
>> member_hash
;
205 Dictionary
<string, MemberSpec
[]> locase_members
;
206 IList
<MethodSpec
> missing_abstract
;
208 public static readonly string IndexerNameAlias
= "<this>";
210 public static readonly MemberCache Empty
= new MemberCache (0);
212 public MemberCache ()
217 public MemberCache (int capacity
)
219 member_hash
= new Dictionary
<string, IList
<MemberSpec
>> (capacity
);
222 public MemberCache (MemberCache cache
)
223 : this (cache
.member_hash
.Count
)
228 // Creates a new MemberCache for the given `container'.
230 public MemberCache (TypeContainer container
)
231 : this () // TODO: Optimize the size
236 // Member-cache does not contain base members but it does
237 // contain all base interface members, so the Lookup code
238 // can use simple inheritance rules.
240 public void AddInterface (TypeSpec iface
)
242 var cache
= iface
.MemberCache
;
244 IList
<MemberSpec
> list
;
245 foreach (var entry
in cache
.member_hash
) {
246 if (!member_hash
.TryGetValue (entry
.Key
, out list
)) {
247 if (entry
.Value
.Count
== 1) {
250 list
= new List
<MemberSpec
> (entry
.Value
);
253 member_hash
.Add (entry
.Key
, list
);
257 foreach (var ce
in entry
.Value
) {
258 if (ce
.DeclaringType
!= iface
)
261 if (list
.Contains (ce
))
264 if (AddInterfaceMember (ce
, ref list
))
265 member_hash
[entry
.Key
] = list
;
270 public void AddMember (InterfaceMemberBase imb
, string exlicitName
, MemberSpec ms
)
272 // Explicit names cannot be looked-up but can be used for
273 // collision checking (no name mangling needed)
274 if (imb
.IsExplicitImpl
)
275 AddMember (exlicitName
, ms
);
281 // Add non-explicit member to member cache
283 public void AddMember (MemberSpec ms
)
285 AddMember (GetLookupName (ms
), ms
);
288 void AddMember (string name
, MemberSpec member
)
290 IList
<MemberSpec
> list
;
291 if (!member_hash
.TryGetValue (name
, out list
)) {
292 member_hash
.Add (name
, new MemberSpec
[] { member }
);
296 if (member
.DeclaringType
.IsInterface
) {
297 if (AddInterfaceMember (member
, ref list
))
298 member_hash
[name
] = list
;
300 if (list
is MemberSpec
[]) {
301 list
= new List
<MemberSpec
> () { list[0] }
;
302 member_hash
[name
] = list
;
310 // Ignores any base interface member which can be hidden
313 static bool AddInterfaceMember (MemberSpec member
, ref IList
<MemberSpec
> existing
)
315 var member_param
= member
is IParametersMember
? ((IParametersMember
) member
).Parameters
: ParametersCompiled
.EmptyReadOnlyParameters
;
318 // interface IA : IB { int Prop { set; } }
319 // interface IB { bool Prop { get; } }
321 // IB.Prop is never accessible from IA interface
323 for (int i
= 0; i
< existing
.Count
; ++i
) {
324 var entry
= existing
[i
];
326 if (entry
.Arity
!= member
.Arity
)
329 if (entry
is IParametersMember
) {
330 var entry_param
= ((IParametersMember
) entry
).Parameters
;
331 if (!TypeSpecComparer
.Override
.IsEqual (entry_param
, member_param
))
335 if (member
.DeclaringType
.ImplementsInterface (entry
.DeclaringType
)) {
336 if (existing
is MemberSpec
[]) {
337 existing
= new MemberSpec
[] { member }
;
341 existing
.RemoveAt (i
--);
345 if (entry
.DeclaringType
== member
.DeclaringType
|| entry
.DeclaringType
.ImplementsInterface (member
.DeclaringType
))
349 if (existing
is MemberSpec
[]) {
350 existing
= new List
<MemberSpec
> () { existing[0], member }
;
354 existing
.Add (member
);
358 public static IEnumerable
<IndexerSpec
> FindIndexers (TypeSpec container
, BindingRestriction restrictions
)
360 var filter
= new MemberFilter (IndexerNameAlias
, 0, MemberKind
.Indexer
, null, null);
361 var found
= FindMembers (container
, filter
, restrictions
);
362 return found
== null ? null : found
.Cast
<IndexerSpec
> ();
365 public static MemberSpec
FindMember (TypeSpec container
, MemberFilter filter
, BindingRestriction restrictions
)
368 IList
<MemberSpec
> applicable
;
369 if (container
.MemberCache
.member_hash
.TryGetValue (filter
.Name
, out applicable
)) {
370 // Start from the end because interface members are in reverse order
371 for (int i
= applicable
.Count
- 1; i
>= 0; i
--) {
372 var entry
= applicable
[i
];
374 if ((restrictions
& BindingRestriction
.InstanceOnly
) != 0 && entry
.IsStatic
)
377 if (filter
.Equals (entry
))
381 //if ((restrictions & BindingRestriction.AccessibleOnly) != 0)
382 // throw new NotImplementedException ("net");
386 container
= container
.BaseType
;
387 } while (container
!= null && (restrictions
& BindingRestriction
.DeclaredOnly
) == 0);
393 // Returns the first set of members starting from container
395 public static IList
<MemberSpec
> FindMembers (TypeSpec container
, MemberFilter filter
, BindingRestriction restrictions
)
397 IList
<MemberSpec
> applicable
;
398 IList
<MemberSpec
> found
= null;
401 if (container
.MemberCache
.member_hash
.TryGetValue (filter
.Name
, out applicable
)) {
402 for (int i
= 0; i
< applicable
.Count
; ++i
) {
403 var entry
= applicable
[i
];
405 // Is the member of the correct type
406 if ((entry
.Kind
& filter
.Kind
& MemberKind
.MaskType
) == 0)
410 // When using overloadable overrides filter ignore members which
411 // are not base members. Including properties because overrides can
412 // implement get or set only and we are looking for complete base member
414 const MemberKind overloadable
= MemberKind
.Indexer
| MemberKind
.Method
| MemberKind
.Property
;
415 if ((restrictions
& BindingRestriction
.NoOverrides
) != 0 && (entry
.Kind
& overloadable
) != 0) {
416 if ((entry
.Modifiers
& Modifiers
.OVERRIDE
) != 0)
419 if ((entry
.Modifiers
& Modifiers
.OVERRIDE_UNCHECKED
) != 0) {
420 bool is_override
= true;
421 var ms
= entry
as MethodSpec
;
423 is_override
= IsRealMethodOverride (ms
);
425 var ps
= (PropertySpec
) entry
;
427 is_override
= IsRealMethodOverride (ps
.Get
);
428 if (is_override
&& ps
.HasSet
)
429 is_override
= IsRealMethodOverride (ps
.Set
);
433 entry
.Modifiers
= (entry
.Modifiers
& ~Modifiers
.OVERRIDE_UNCHECKED
) | Modifiers
.OVERRIDE
;
439 if ((restrictions
& BindingRestriction
.InstanceOnly
) != 0 && entry
.IsStatic
)
442 // Apply the filter to it.
443 if (!filter
.Equals (entry
))
450 found
= new List
<MemberSpec
> ();
453 } else if (found
== applicable
) {
454 found
= new List
<MemberSpec
> ();
455 found
.Add (applicable
[0]);
463 if (found
== applicable
&& applicable
.Count
!= 1)
464 return new MemberSpec
[] { found[0] }
;
470 container
= container
.BaseType
;
471 } while (container
!= null && (restrictions
& BindingRestriction
.DeclaredOnly
) == 0);
477 // Finds the nested type in container
479 public static TypeSpec
FindNestedType (TypeSpec container
, string name
, int arity
)
481 IList
<MemberSpec
> applicable
;
482 TypeSpec best_match
= null;
484 // TODO: Don't know how to handle this yet
485 // When resolving base type of nested type, parent type must have
486 // base type resolved to scan full hierarchy correctly
487 // Similarly MemberCacheTypes will inflate BaseType and Interfaces
488 // based on type definition
489 var tc
= container
.MemberDefinition
as TypeContainer
;
493 if (container
.MemberCacheTypes
.member_hash
.TryGetValue (name
, out applicable
)) {
494 for (int i
= applicable
.Count
- 1; i
>= 0; i
--) {
495 var entry
= applicable
[i
];
496 if ((entry
.Kind
& MemberKind
.NestedMask
) == 0)
499 var ts
= (TypeSpec
) entry
;
500 if (arity
== ts
.Arity
)
504 if (best_match
== null) {
506 } else if (System
.Math
.Abs (ts
.Arity
+ arity
) < System
.Math
.Abs (ts
.Arity
+ arity
)) {
513 container
= container
.BaseType
;
514 } while (container
!= null);
520 // Looks for extension methods with defined name and extension type
522 public List
<MethodSpec
> FindExtensionMethods (TypeSpec invocationType
, TypeSpec extensionType
, string name
, int arity
)
524 IList
<MemberSpec
> entries
;
525 if (!member_hash
.TryGetValue (name
, out entries
))
528 List
<MethodSpec
> candidates
= null;
529 foreach (var entry
in entries
) {
530 if (entry
.Kind
!= MemberKind
.Method
|| (arity
>= 0 && entry
.Arity
!= arity
))
533 var ms
= (MethodSpec
) entry
;
534 if (!ms
.IsExtensionMethod
)
538 if (!Expression
.IsMemberAccessible (invocationType
, ms
, out extra
))
541 // TODO: CodeGen.Assembly.Builder
542 if ((ms
.DeclaringType
.Modifiers
& Modifiers
.INTERNAL
) != 0 &&
543 !TypeManager
.IsThisOrFriendAssembly (CodeGen
.Assembly
.Builder
, ms
.Assembly
))
546 if (candidates
== null)
547 candidates
= new List
<MethodSpec
> ();
555 // Returns base members of @member member if no exact match is found @bestCandidate returns
558 public static MemberSpec
FindBaseMember (MemberCore member
, out MemberSpec bestCandidate
)
560 bestCandidate
= null;
561 var container
= member
.Parent
.PartialContainer
.Definition
;
562 if (!container
.IsInterface
)
563 container
= container
.BaseType
;
565 string name
= GetLookupName (member
);
566 IList
<MemberSpec
> applicable
;
567 var member_param
= member
is IParametersMember
? ((IParametersMember
) member
).Parameters
: null;
569 var mkind
= GetMemberCoreKind (member
);
572 if (container
.MemberCache
.member_hash
.TryGetValue (name
, out applicable
)) {
573 for (int i
= 0; i
< applicable
.Count
; ++i
) {
574 var entry
= applicable
[i
];
576 if ((entry
.Modifiers
& Modifiers
.PRIVATE
) != 0)
579 if ((entry
.Modifiers
& Modifiers
.AccessibilityMask
) == Modifiers
.INTERNAL
) {
580 if (!TypeManager
.IsThisOrFriendAssembly (member
.Assembly
, entry
.Assembly
))
585 // Is the member of the correct type ?
586 // Destructors are ignored as they cannot be overridden by user
587 if ((entry
.Kind
& ~MemberKind
.Destructor
& mkind
& MemberKind
.MaskType
) == 0) {
588 if ((entry
.Kind
& MemberKind
.Destructor
) == 0 && (member_param
== null || !(entry
is IParametersMember
))) {
589 bestCandidate
= entry
;
596 if (member_param
== null)
600 int arity
= member
.MemberName
.Arity
;
601 if (arity
!= entry
.Arity
)
604 if (entry
is IParametersMember
) {
605 if (entry
.IsAccessor
!= member
is AbstractPropertyEventMethod
)
608 var entry_param
= ((IParametersMember
) entry
).Parameters
;
609 if (TypeSpecComparer
.Override
.IsEqual (entry_param
, member_param
))
615 if (bestCandidate
== null)
616 bestCandidate
= entry
;
619 if (member_param
== null)
623 if (container
.IsInterface
)
626 container
= container
.BaseType
;
627 } while (container
!= null);
633 // Returns inflated version of MemberSpec, it works similarly to
634 // SRE TypeBuilder.GetMethod
636 public static T GetMember
<T
> (TypeSpec container
, T spec
) where T
: MemberSpec
638 IList
<MemberSpec
> applicable
;
639 if (container
.MemberCache
.member_hash
.TryGetValue (GetLookupName (spec
), out applicable
)) {
640 for (int i
= applicable
.Count
- 1; i
>= 0; i
--) {
641 var entry
= applicable
[i
];
642 if (entry
.MemberDefinition
== spec
.MemberDefinition
)
647 throw new InternalErrorException ("Missing member `{0}' on inflated type `{1}'",
648 spec
.GetSignatureForError (), container
.GetSignatureForError ());
651 static MemberKind
GetMemberCoreKind (MemberCore member
)
653 if (member
is FieldBase
)
654 return MemberKind
.Field
;
655 if (member
is Indexer
)
656 return MemberKind
.Indexer
;
658 return MemberKind
.Class
;
659 if (member
is Struct
)
660 return MemberKind
.Struct
;
661 if (member
is Destructor
)
662 return MemberKind
.Destructor
;
663 if (member
is Method
)
664 return MemberKind
.Method
;
665 if (member
is Property
)
666 return MemberKind
.Property
;
667 if (member
is EventField
)
668 return MemberKind
.Event
;
669 if (member
is Interface
)
670 return MemberKind
.Interface
;
671 if (member
is EventProperty
)
672 return MemberKind
.Event
;
674 throw new NotImplementedException (member
.GetType ().ToString ());
677 public static IList
<MemberSpec
> GetCompletitionMembers (TypeSpec container
, string name
)
679 var matches
= new List
<MemberSpec
> ();
680 foreach (var entry
in container
.MemberCache
.member_hash
) {
681 foreach (var name_entry
in entry
.Value
) {
682 if (name_entry
.IsAccessor
)
685 if ((name_entry
.Kind
& (MemberKind
.Constructor
| MemberKind
.FakeMethod
| MemberKind
.Destructor
)) != 0)
689 if (!Expression
.IsMemberAccessible (InternalType
.FakeInternalType
, name_entry
, out extra
))
692 if (name
== null || name_entry
.Name
.StartsWith (name
)) {
693 matches
.Add (name_entry
);
702 // Returns members of @iface only, base members are ignored
704 public static IList
<MethodSpec
> GetInterfaceMembers (TypeSpec iface
)
707 // MemberCache flatten interfaces, therefore in cases like this one
709 // interface IA : IB {}
710 // interface IB { void Foo () }
712 // we would return Foo inside IA which is not expected in this case
714 var methods
= new List
<MethodSpec
> ();
715 foreach (var entry
in iface
.MemberCache
.member_hash
.Values
) {
716 foreach (var name_entry
in entry
) {
717 if (iface
== name_entry
.DeclaringType
) {
718 if (name_entry
.Kind
== MemberKind
.Method
) {
719 methods
.Add ((MethodSpec
) name_entry
);
728 public static IList
<MethodSpec
> GetNotImplementedAbstractMethods (TypeSpec type
)
730 if (type
.MemberCache
.missing_abstract
!= null)
731 return type
.MemberCache
.missing_abstract
;
733 var abstract_methods
= new List
<MethodSpec
> ();
734 List
<TypeSpec
> hierarchy
= null;
737 // Stage 1: top-to-bottom scan for abstract members
739 var abstract_type
= type
;
741 foreach (var entry
in abstract_type
.MemberCache
.member_hash
) {
742 foreach (var name_entry
in entry
.Value
) {
743 if ((name_entry
.Modifiers
& Modifiers
.ABSTRACT
) == 0)
746 if (name_entry
.Kind
!= MemberKind
.Method
)
749 abstract_methods
.Add ((MethodSpec
) name_entry
);
753 var base_type
= abstract_type
.BaseType
;
754 if (!base_type
.IsAbstract
)
757 if (hierarchy
== null)
758 hierarchy
= new List
<TypeSpec
> ();
760 hierarchy
.Add (abstract_type
);
761 abstract_type
= base_type
;
764 int not_implemented_count
= abstract_methods
.Count
;
765 if (not_implemented_count
== 0 || hierarchy
== null) {
766 type
.MemberCache
.missing_abstract
= abstract_methods
;
767 return type
.MemberCache
.missing_abstract
;
771 // Stage 2: Remove already implemented methods
773 foreach (var type_up
in hierarchy
) {
774 var members
= type_up
.MemberCache
.member_hash
;
775 if (members
.Count
== 0)
778 for (int i
= 0; i
< abstract_methods
.Count
; ++i
) {
779 var candidate
= abstract_methods
[i
];
780 if (candidate
== null)
783 IList
<MemberSpec
> applicable
;
784 if (!members
.TryGetValue (candidate
.Name
, out applicable
))
787 var filter
= new MemberFilter (candidate
);
788 foreach (var item
in applicable
) {
789 // TODO: Need to test what should happen for OVERRIDE_UNCHECKED
790 if ((item
.Modifiers
& (Modifiers
.OVERRIDE
| Modifiers
.OVERRIDE_UNCHECKED
| Modifiers
.VIRTUAL
)) == 0)
793 if (filter
.Equals (item
)) {
794 --not_implemented_count
;
795 abstract_methods
[i
] = null;
802 if (not_implemented_count
== abstract_methods
.Count
) {
803 type
.MemberCache
.missing_abstract
= abstract_methods
;
804 return type
.MemberCache
.missing_abstract
;
807 var not_implemented
= new MethodSpec
[not_implemented_count
];
809 foreach (var m
in abstract_methods
) {
813 not_implemented
[counter
++] = m
;
816 type
.MemberCache
.missing_abstract
= not_implemented
;
817 return type
.MemberCache
.missing_abstract
;
820 static string GetLookupName (MemberSpec ms
)
822 if (ms
.Kind
== MemberKind
.Indexer
)
823 return IndexerNameAlias
;
825 if (ms
.Kind
== MemberKind
.Constructor
) {
827 return ConstructorInfo
.TypeConstructorName
;
829 return ConstructorInfo
.ConstructorName
;
835 static string GetLookupName (MemberCore mc
)
838 return IndexerNameAlias
;
840 if (mc
is Constructor
)
841 return ConstructorInfo
.ConstructorName
;
843 return mc
.MemberName
.Name
;
847 // Inflates all member cache nested types
849 public void InflateTypes (MemberCache inflated_cache
, TypeParameterInflator inflator
)
851 foreach (var item
in member_hash
) {
852 IList
<MemberSpec
> inflated_members
= null;
853 for (int i
= 0; i
< item
.Value
.Count
; ++i
) {
854 var member
= item
.Value
[i
];
856 // FIXME: When inflating members refering nested types before they are inflated
860 if ((member
.Kind
& MemberKind
.NestedMask
) != 0 &&
861 (member
.Modifiers
& Modifiers
.COMPILER_GENERATED
) == 0) {
862 if (inflated_members
== null) {
863 inflated_members
= new MemberSpec
[item
.Value
.Count
];
864 inflated_cache
.member_hash
.Add (item
.Key
, inflated_members
);
867 inflated_members
[i
] = member
.InflateMember (inflator
);
874 // Inflates all open type members, requires InflateTypes to be called before
876 public void InflateMembers (MemberCache cacheToInflate
, TypeSpec inflatedType
, TypeParameterInflator inflator
)
878 var inflated_member_hash
= cacheToInflate
.member_hash
;
879 Dictionary
<MethodSpec
, MethodSpec
> accessor_relation
= null;
880 List
<MemberSpec
> accessor_members
= null;
882 foreach (var item
in member_hash
) {
883 var members
= item
.Value
;
884 IList
<MemberSpec
> inflated_members
= null;
885 for (int i
= 0; i
< members
.Count
; ++i
) {
886 var member
= members
[i
];
889 // All nested types have been inflated earlier except for
890 // compiler types which are created later and could miss InflateTypes
892 if ((member
.Kind
& MemberKind
.NestedMask
) != 0 &&
893 (member
.Modifiers
& Modifiers
.COMPILER_GENERATED
) == 0) {
894 if (inflated_members
== null)
895 inflated_members
= inflated_member_hash
[item
.Key
];
901 // Clone the container first
903 if (inflated_members
== null) {
904 inflated_members
= new MemberSpec
[item
.Value
.Count
];
905 inflated_member_hash
.Add (item
.Key
, inflated_members
);
908 var local_inflator
= inflator
;
910 if (member
.DeclaringType
!= inflatedType
) {
912 // Don't inflate non generic interface members
913 // merged into generic interface
915 if (!member
.DeclaringType
.IsGeneric
) {
916 inflated_members
[i
] = member
;
921 // Needed when inflating flatten interfaces. It inflates
922 // container type only, type parameters are already done
924 // Handles cases like:
927 // interface I<U, V> : I<U> {}
929 // class C: I<int, bool> {}
931 var inflated_parent
= inflator
.Inflate (member
.DeclaringType
);
932 if (inflated_parent
!= inflator
.TypeInstance
)
933 local_inflator
= new TypeParameterInflator (inflator
, inflated_parent
);
937 // Inflate every member, its parent is now different
939 var inflated
= member
.InflateMember (local_inflator
);
940 inflated_members
[i
] = inflated
;
942 if (member
is PropertySpec
|| member
is EventSpec
) {
943 if (accessor_members
== null)
944 accessor_members
= new List
<MemberSpec
> ();
946 accessor_members
.Add (inflated
);
950 if (member
.IsAccessor
) {
951 if (accessor_relation
== null)
952 accessor_relation
= new Dictionary
<MethodSpec
, MethodSpec
> ();
953 accessor_relation
.Add ((MethodSpec
) member
, (MethodSpec
) inflated
);
958 if (accessor_members
!= null) {
959 foreach (var member
in accessor_members
) {
960 var prop
= member
as PropertySpec
;
962 if (prop
.Get
!= null)
963 prop
.Get
= accessor_relation
[prop
.Get
];
964 if (prop
.Set
!= null)
965 prop
.Set
= accessor_relation
[prop
.Set
];
970 var ev
= (EventSpec
) member
;
971 ev
.AccessorAdd
= accessor_relation
[ev
.AccessorAdd
];
972 ev
.AccessorRemove
= accessor_relation
[ev
.AccessorRemove
];
978 // For imported class method do additional validation to be sure that metadata
979 // override flag was correct
981 static bool IsRealMethodOverride (MethodSpec ms
)
983 IList
<MemberSpec
> candidates
;
984 var dt
= ms
.DeclaringType
;
985 while (dt
.BaseType
!= null) {
986 var base_cache
= dt
.BaseType
.MemberCache
;
987 if (base_cache
.member_hash
.TryGetValue (ms
.Name
, out candidates
)) {
988 foreach (var candidate
in candidates
) {
989 if (candidate
.Kind
!= ms
.Kind
)
992 if (candidate
.Arity
!= ms
.Arity
)
995 if (!TypeSpecComparer
.Override
.IsEqual (((MethodSpec
) candidate
).Parameters
, ms
.Parameters
))
998 // Everything matches except modifiers, it's not correct soverride
999 if ((candidate
.Modifiers
& Modifiers
.AccessibilityMask
) != (ms
.Modifiers
& Modifiers
.AccessibilityMask
))
1013 // Checks all appropriate container members for CLS compliance
1015 public void VerifyClsCompliance (TypeSpec container
, Report report
)
1017 if (locase_members
!= null)
1020 if (container
.BaseType
== null) {
1021 locase_members
= new Dictionary
<string, MemberSpec
[]> (member_hash
.Count
); // StringComparer.OrdinalIgnoreCase);
1023 container
.BaseType
.MemberCache
.VerifyClsCompliance (container
.BaseType
, report
);
1024 locase_members
= new Dictionary
<string, MemberSpec
[]> (container
.BaseType
.MemberCache
.locase_members
); //, StringComparer.OrdinalIgnoreCase);
1027 var is_imported_type
= container
.MemberDefinition
.IsImported
;
1028 foreach (var entry
in container
.MemberCache
.member_hash
) {
1029 for (int i
= 0; i
< entry
.Value
.Count
; ++i
) {
1030 var name_entry
= entry
.Value
[i
];
1031 if ((name_entry
.Modifiers
& (Modifiers
.PUBLIC
| Modifiers
.PROTECTED
)) == 0)
1034 if ((name_entry
.Modifiers
& (Modifiers
.OVERRIDE
| Modifiers
.COMPILER_GENERATED
)) != 0)
1037 if ((name_entry
.Kind
& MemberKind
.MaskType
) == 0)
1040 if (name_entry
.MemberDefinition
.IsNotCLSCompliant ())
1043 IParametersMember p_a
= name_entry
as IParametersMember
;
1044 if (p_a
!= null && !name_entry
.IsAccessor
) {
1045 if (!is_imported_type
) {
1046 var p_a_pd
= p_a
.Parameters
;
1047 for (int ii
= i
+ 1; ii
< entry
.Value
.Count
; ++ii
) {
1048 var checked_entry
= entry
.Value
[ii
];
1049 IParametersMember p_b
= checked_entry
as IParametersMember
;
1053 if (p_a_pd
.Count
!= p_b
.Parameters
.Count
)
1056 if (checked_entry
.IsAccessor
)
1059 var res
= ParametersCompiled
.IsSameClsSignature (p_a
.Parameters
, p_b
.Parameters
);
1061 var last
= GetLaterDefinedMember (checked_entry
, name_entry
);
1062 if (last
== checked_entry
.MemberDefinition
) {
1063 report
.SymbolRelatedToPreviousError (name_entry
);
1065 report
.SymbolRelatedToPreviousError (checked_entry
);
1068 if ((res
& 1) != 0) {
1069 report
.Warning (3006, 1, last
.Location
,
1070 "Overloaded method `{0}' differing only in ref or out, or in array rank, is not CLS-compliant",
1071 name_entry
.GetSignatureForError ());
1074 if ((res
& 2) != 0) {
1075 report
.Warning (3007, 1, last
.Location
,
1076 "Overloaded method `{0}' differing only by unnamed array types is not CLS-compliant",
1077 name_entry
.GetSignatureForError ());
1084 if (i
> 0 || name_entry
.Kind
== MemberKind
.Constructor
|| name_entry
.Kind
== MemberKind
.Indexer
)
1087 var name_entry_locase
= name_entry
.Name
.ToLowerInvariant ();
1090 if (!locase_members
.TryGetValue (name_entry_locase
, out found
)) {
1091 found
= new MemberSpec
[] { name_entry }
;
1092 locase_members
.Add (name_entry_locase
, found
);
1094 bool same_names_only
= true;
1095 foreach (var f
in found
) {
1096 if (f
.Name
== name_entry
.Name
)
1099 // if (f.IsAccessor && name_entry.IsAccessor)
1102 same_names_only
= false;
1103 if (!is_imported_type
) {
1104 var last
= GetLaterDefinedMember (f
, name_entry
);
1105 if (last
== f
.MemberDefinition
) {
1106 report
.SymbolRelatedToPreviousError (name_entry
);
1108 report
.SymbolRelatedToPreviousError (f
);
1111 report
.Warning (3005, 1, last
.Location
,
1112 "Identifier `{0}' differing only in case is not CLS-compliant", last
.GetSignatureForError ());
1116 if (!same_names_only
) {
1117 Array
.Resize (ref found
, found
.Length
+ 1);
1118 found
[found
.Length
- 1] = name_entry
;
1119 locase_members
[name_entry_locase
] = found
;
1127 // Local report helper to issue correctly ordered members stored in hashtable
1129 static MemberCore
GetLaterDefinedMember (MemberSpec a
, MemberSpec b
)
1131 var mc_a
= a
.MemberDefinition
as MemberCore
;
1132 var mc_b
= b
.MemberDefinition
as MemberCore
;
1139 if (mc_a
.Location
.File
!= mc_a
.Location
.File
)
1142 return mc_b
.Location
.Row
> mc_a
.Location
.Row
? mc_b
: mc_a
;
1145 public bool CheckExistingMembersOverloads (MemberCore member
, AParametersCollection parameters
)
1147 var name
= GetLookupName (member
);
1148 var imb
= member
as InterfaceMemberBase
;
1149 if (imb
!= null && imb
.IsExplicitImpl
) {
1150 name
= imb
.GetFullName (name
);
1153 return CheckExistingMembersOverloads (member
, name
, parameters
);
1156 public bool CheckExistingMembersOverloads (MemberCore member
, string name
, AParametersCollection parameters
)
1158 IList
<MemberSpec
> entries
;
1159 if (!member_hash
.TryGetValue (name
, out entries
))
1162 var Report
= member
.Compiler
.Report
;
1164 int method_param_count
= parameters
.Count
;
1165 for (int i
= entries
.Count
- 1; i
>= 0; --i
) {
1166 var ce
= entries
[i
];
1167 var pm
= ce
as IParametersMember
;
1168 var pd
= pm
== null ? ParametersCompiled
.EmptyReadOnlyParameters
: pm
.Parameters
;
1169 if (pd
.Count
!= method_param_count
)
1172 if (ce
.Arity
!= member
.MemberName
.Arity
)
1175 // Ignore merged interface members
1176 if (member
.Parent
.PartialContainer
!= ce
.DeclaringType
.MemberDefinition
)
1179 var p_types
= pd
.Types
;
1180 if (method_param_count
> 0) {
1181 int ii
= method_param_count
- 1;
1182 TypeSpec type_a
, type_b
;
1184 type_a
= parameters
.Types
[ii
];
1185 type_b
= p_types
[ii
];
1187 if ((pd
.FixedParameters
[ii
].ModFlags
& Parameter
.Modifier
.ISBYREF
) !=
1188 (parameters
.FixedParameters
[ii
].ModFlags
& Parameter
.Modifier
.ISBYREF
))
1191 } while (TypeSpecComparer
.Override
.IsEqual (type_a
, type_b
) && ii
-- != 0);
1197 // Operators can differ in return type only
1199 if (member
is Operator
&& ce
.Kind
== MemberKind
.Operator
&& ((MethodSpec
) ce
).ReturnType
!= ((Operator
) member
).ReturnType
)
1203 // Report difference in parameter modifiers only
1205 if (pd
!= null && member
is MethodCore
) {
1206 ii
= method_param_count
;
1207 while (ii
-- != 0 && parameters
.FixedParameters
[ii
].ModFlags
== pd
.FixedParameters
[ii
].ModFlags
&&
1208 parameters
.ExtensionMethodType
== pd
.ExtensionMethodType
) ;
1211 var mc
= ce
as MethodSpec
;
1212 member
.Compiler
.Report
.SymbolRelatedToPreviousError (ce
);
1213 if ((member
.ModFlags
& Modifiers
.PARTIAL
) != 0 && (mc
.Modifiers
& Modifiers
.PARTIAL
) != 0) {
1214 if (parameters
.HasParams
|| pd
.HasParams
) {
1215 Report
.Error (758, member
.Location
,
1216 "A partial method declaration and partial method implementation cannot differ on use of `params' modifier");
1218 Report
.Error (755, member
.Location
,
1219 "A partial method declaration and partial method implementation must be both an extension method or neither");
1221 } else if (member
is Constructor
) {
1222 Report
.Error (851, member
.Location
,
1223 "Overloaded contructor `{0}' cannot differ on use of parameter modifiers only",
1224 member
.GetSignatureForError ());
1226 Report
.Error (663, member
.Location
,
1227 "Overloaded method `{0}' cannot differ on use of parameter modifiers only",
1228 member
.GetSignatureForError ());
1235 if ((ce
.Kind
& (MemberKind
.Method
| MemberKind
.FakeMethod
)) != 0) {
1236 Method method_a
= member
as Method
;
1237 Method method_b
= ce
.MemberDefinition
as Method
;
1238 if (method_a
!= null && method_b
!= null && (method_a
.ModFlags
& method_b
.ModFlags
& Modifiers
.PARTIAL
) != 0) {
1239 const Modifiers partial_modifiers
= Modifiers
.STATIC
| Modifiers
.UNSAFE
;
1240 if (method_a
.IsPartialDefinition
== method_b
.IsPartialImplementation
) {
1241 if ((method_a
.ModFlags
& partial_modifiers
) == (method_b
.ModFlags
& partial_modifiers
) ||
1242 method_a
.Parent
.IsUnsafe
&& method_b
.Parent
.IsUnsafe
) {
1243 if (method_a
.IsPartialImplementation
) {
1244 method_a
.SetPartialDefinition (method_b
);
1245 if (entries
.Count
== 1)
1246 member_hash
.Remove (name
);
1248 entries
.RemoveAt (i
);
1250 method_b
.SetPartialDefinition (method_a
);
1251 method_a
.caching_flags
|= MemberCore
.Flags
.PartialDefinitionExists
;
1256 if (method_a
.IsStatic
!= method_b
.IsStatic
) {
1257 Report
.SymbolRelatedToPreviousError (ce
);
1258 Report
.Error (763, member
.Location
,
1259 "A partial method declaration and partial method implementation must be both `static' or neither");
1262 Report
.SymbolRelatedToPreviousError (ce
);
1263 Report
.Error (764, member
.Location
,
1264 "A partial method declaration and partial method implementation must be both `unsafe' or neither");
1268 Report
.SymbolRelatedToPreviousError (ce
);
1269 if (method_a
.IsPartialDefinition
) {
1270 Report
.Error (756, member
.Location
, "A partial method `{0}' declaration is already defined",
1271 member
.GetSignatureForError ());
1274 Report
.Error (757, member
.Location
, "A partial method `{0}' implementation is already defined",
1275 member
.GetSignatureForError ());
1279 Report
.SymbolRelatedToPreviousError (ce
);
1281 bool is_reserved_a
= member
is AbstractPropertyEventMethod
|| member
is Operator
;
1282 bool is_reserved_b
= ((MethodSpec
) ce
).IsReservedMethod
;
1284 if (is_reserved_a
|| is_reserved_b
) {
1285 Report
.Error (82, member
.Location
, "A member `{0}' is already reserved",
1287 ce
.GetSignatureForError () :
1288 member
.GetSignatureForError ());
1292 Report
.SymbolRelatedToPreviousError (ce
);
1295 if (member
is Operator
&& ce
.Kind
== MemberKind
.Operator
) {
1296 Report
.Error (557, member
.Location
, "Duplicate user-defined conversion in type `{0}'",
1297 member
.Parent
.GetSignatureForError ());
1301 Report
.Error (111, member
.Location
,
1302 "A member `{0}' is already defined. Rename this member or use different parameter types",
1303 member
.GetSignatureForError ());