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
11
// Copyright 2011 Xamarin Inc
16
using System.Collections.Generic;
18
namespace Mono.CSharp {
21
public enum MemberKind
37
TypeParameter = 1 << 16,
40
PointerType = 1 << 20,
41
InternalCompilerType = 1 << 21,
42
MissingType = 1 << 22,
46
NestedMask = Class | Struct | Delegate | Enum | Interface,
47
GenericMask = Method | Class | Struct | Delegate | Interface,
48
MaskType = Constructor | Event | Field | Method | Property | Indexer | Operator | Destructor | NestedMask
52
public enum BindingRestriction
56
// Inspect only queried type members
57
DeclaredOnly = 1 << 1,
60
InstanceOnly = 1 << 2,
64
// Member has to be override
68
public struct MemberFilter : IEquatable<MemberSpec>
70
public readonly string Name;
71
public readonly MemberKind Kind;
72
public readonly AParametersCollection Parameters;
73
public readonly TypeSpec MemberType;
74
public readonly int Arity; // -1 to ignore the check
76
public MemberFilter (MethodSpec m)
79
Kind = MemberKind.Method;
80
Parameters = m.Parameters;
81
MemberType = m.ReturnType;
85
public MemberFilter (string name, int arity, MemberKind kind, AParametersCollection param, TypeSpec type)
94
public static MemberFilter Constructor (AParametersCollection param)
96
return new MemberFilter (Mono.CSharp.Constructor.ConstructorName, 0, MemberKind.Constructor, param, null);
99
public static MemberFilter Property (string name, TypeSpec type)
101
return new MemberFilter (name, 0, MemberKind.Property, null, type);
104
public static MemberFilter Field (string name, TypeSpec type)
106
return new MemberFilter (name, 0, MemberKind.Field, null, type);
109
public static MemberFilter Method (string name, int arity, AParametersCollection param, TypeSpec type)
111
return new MemberFilter (name, arity, MemberKind.Method, param, type);
114
#region IEquatable<MemberSpec> Members
116
public bool Equals (MemberSpec other)
118
// Is the member of the correct type ?
119
// TODO: Isn't this redundant ?
120
if ((other.Kind & Kind & MemberKind.MaskType) == 0)
123
// Check arity when not disabled
124
if (Arity >= 0 && Arity != other.Arity)
127
if (Parameters != null) {
128
if (other is IParametersMember) {
129
var other_param = ((IParametersMember) other).Parameters;
130
if (!TypeSpecComparer.Override.IsEqual (Parameters, other_param))
137
if (MemberType != null) {
138
if (other is IInterfaceMemberSpec) {
139
var other_type = ((IInterfaceMemberSpec) other).MemberType;
140
if (!TypeSpecComparer.Override.IsEqual (other_type, MemberType))
154
// The MemberCache is the main members container used by compiler. It contains
155
// all members imported or defined during compilation using on demand filling
156
// process. Inflated containers are also using MemberCache to make inflated
157
// members look like normal definition.
159
// All of the methods are performance and memory sensitive as the MemberCache
160
// is the underlying engine of all member based operations.
162
public class MemberCache
167
HasConversionOperator = 1 << 1,
168
HasUserOperator = 1 << 2
171
readonly Dictionary<string, IList<MemberSpec>> member_hash;
172
Dictionary<string, MemberSpec[]> locase_members;
173
IList<MethodSpec> missing_abstract;
174
StateFlags state; // TODO: Move to TypeSpec or ITypeDefinition
176
public static readonly string IndexerNameAlias = "<this>";
178
public static readonly MemberCache Empty = new MemberCache (0);
180
public MemberCache ()
185
public MemberCache (int capacity)
187
member_hash = new Dictionary<string, IList<MemberSpec>> (capacity);
190
public MemberCache (MemberCache cache)
191
: this (cache.member_hash.Count)
193
this.state = cache.state;
197
// Creates a new MemberCache for the given `container'.
199
public MemberCache (TypeContainer container)
200
: this () // TODO: Optimize the size
205
// For cases where we need to union cache members
207
public void AddBaseType (TypeSpec baseType)
209
var cache = baseType.MemberCache;
211
IList<MemberSpec> list;
212
foreach (var entry in cache.member_hash) {
213
if (!member_hash.TryGetValue (entry.Key, out list)) {
214
if (entry.Value.Count == 1) {
217
list = new List<MemberSpec> (entry.Value);
220
member_hash.Add (entry.Key, list);
224
foreach (var ce in entry.Value) {
225
if (list.Contains (ce))
228
if (list is MemberSpec[]) {
229
list = new List<MemberSpec> () { list [0] };
230
member_hash[entry.Key] = list;
239
// Member-cache does not contain base members but it does
240
// contain all base interface members, so the Lookup code
241
// can use simple inheritance rules.
243
// Does not work recursively because of generic interfaces
245
public void AddInterface (TypeSpec iface)
247
var cache = iface.MemberCache;
249
IList<MemberSpec> list;
250
foreach (var entry in cache.member_hash) {
251
if (!member_hash.TryGetValue (entry.Key, out list)) {
252
if (entry.Value.Count == 1) {
255
list = new List<MemberSpec> (entry.Value);
258
member_hash.Add (entry.Key, list);
262
foreach (var ce in entry.Value) {
264
// When two or more different base interfaces implemenent common
270
if (list.Contains (ce))
273
if (AddInterfaceMember (ce, ref list))
274
member_hash[entry.Key] = list;
279
public void AddMember (InterfaceMemberBase imb, string exlicitName, MemberSpec ms)
281
// Explicit names cannot be looked-up but can be used for
282
// collision checking (no name mangling needed)
283
if (imb.IsExplicitImpl)
284
AddMember (exlicitName, ms, false);
290
// Add non-explicit member to member cache
292
public void AddMember (MemberSpec ms)
294
AddMember (GetLookupName (ms), ms, false);
297
void AddMember (string name, MemberSpec member, bool removeHiddenMembers)
299
if (member.Kind == MemberKind.Operator) {
300
var dt = member.DeclaringType;
304
// Some core types have user operators but they cannot be used like normal
305
// user operators as they are predefined and therefore having different
306
// rules (e.g. binary operators) by not setting the flag we hide them for
309
if (!BuiltinTypeSpec.IsPrimitiveType (dt) || dt.BuiltinType == BuiltinTypeSpec.Type.Char) {
310
switch (dt.BuiltinType) {
311
case BuiltinTypeSpec.Type.String:
312
case BuiltinTypeSpec.Type.Delegate:
313
case BuiltinTypeSpec.Type.MulticastDelegate:
316
if (name == Operator.GetMetadataName (Operator.OpType.Implicit) || name == Operator.GetMetadataName (Operator.OpType.Explicit)) {
317
state |= StateFlags.HasConversionOperator;
319
state |= StateFlags.HasUserOperator;
327
IList<MemberSpec> list;
328
if (!member_hash.TryGetValue (name, out list)) {
329
member_hash.Add (name, new MemberSpec[] { member });
333
if (removeHiddenMembers && member.DeclaringType.IsInterface) {
334
if (AddInterfaceMember (member, ref list))
335
member_hash[name] = list;
337
if (list.Count == 1) {
338
list = new List<MemberSpec> () { list[0] };
339
member_hash[name] = list;
346
public void AddMemberImported (MemberSpec ms)
348
AddMember (GetLookupName (ms), ms, true);
352
// Ignores any base interface member which can be hidden
355
static bool AddInterfaceMember (MemberSpec member, ref IList<MemberSpec> existing)
357
var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : ParametersCompiled.EmptyReadOnlyParameters;
360
// interface IA : IB { int Prop { set; } }
361
// interface IB { bool Prop { get; } }
363
// IB.Prop is never accessible from IA interface
365
for (int i = 0; i < existing.Count; ++i) {
366
var entry = existing[i];
368
if (entry.Arity != member.Arity)
371
if (entry is IParametersMember) {
372
var entry_param = ((IParametersMember) entry).Parameters;
373
if (!TypeSpecComparer.Override.IsEqual (entry_param, member_param))
377
if (member.DeclaringType.ImplementsInterface (entry.DeclaringType, false)) {
378
if (existing.Count == 1) {
379
existing = new MemberSpec[] { member };
383
existing.RemoveAt (i--);
387
if ((entry.DeclaringType == member.DeclaringType && entry.IsAccessor == member.IsAccessor) ||
388
entry.DeclaringType.ImplementsInterface (member.DeclaringType, false))
392
if (existing.Count == 1) {
393
existing = new List<MemberSpec> () { existing[0], member };
397
existing.Add (member);
401
public static MemberSpec FindMember (TypeSpec container, MemberFilter filter, BindingRestriction restrictions)
404
IList<MemberSpec> applicable;
405
if (container.MemberCache.member_hash.TryGetValue (filter.Name, out applicable)) {
406
// Start from the end because interface members are in reverse order
407
for (int i = applicable.Count - 1; i >= 0; i--) {
408
var entry = applicable [i];
410
if ((restrictions & BindingRestriction.InstanceOnly) != 0 && entry.IsStatic)
413
if ((restrictions & BindingRestriction.NoAccessors) != 0 && entry.IsAccessor)
416
if ((restrictions & BindingRestriction.OverrideOnly) != 0 && (entry.Modifiers & Modifiers.OVERRIDE) == 0)
419
if (!filter.Equals (entry))
422
if ((restrictions & BindingRestriction.DeclaredOnly) != 0 && container.IsInterface && entry.DeclaringType != container)
429
if ((restrictions & BindingRestriction.DeclaredOnly) != 0)
432
container = container.BaseType;
433
} while (container != null);
439
// A special method to work with member lookup only. It returns a list of all members named @name
440
// starting from @container. It's very performance sensitive
442
// declaredOnlyClass cannot be used interfaces. Manual filtering is required because names are
445
public static IList<MemberSpec> FindMembers (TypeSpec container, string name, bool declaredOnlyClass)
447
IList<MemberSpec> applicable;
450
if (container.MemberCache.member_hash.TryGetValue (name, out applicable) || declaredOnlyClass)
453
container = container.BaseType;
454
} while (container != null);
460
// Finds the nested type in container
462
public static TypeSpec FindNestedType (TypeSpec container, string name, int arity)
464
IList<MemberSpec> applicable;
465
TypeSpec best_match = null;
467
// TODO: Don't know how to handle this yet
468
// When resolving base type of nested type, parent type must have
469
// base type resolved to scan full hierarchy correctly
470
// Similarly MemberCacheTypes will inflate BaseType and Interfaces
471
// based on type definition
472
var tc = container.MemberDefinition as TypeContainer;
474
tc.DefineContainer ();
476
if (container.MemberCacheTypes.member_hash.TryGetValue (name, out applicable)) {
477
for (int i = applicable.Count - 1; i >= 0; i--) {
478
var entry = applicable[i];
479
if ((entry.Kind & MemberKind.NestedMask) == 0)
482
var ts = (TypeSpec) entry;
483
if (arity == ts.Arity)
487
if (best_match == null) {
489
} else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (ts.Arity + arity)) {
496
container = container.BaseType;
497
} while (container != null);
503
// Looks for extension methods with defined name and extension type
505
public List<MethodSpec> FindExtensionMethods (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity)
507
IList<MemberSpec> entries;
508
if (!member_hash.TryGetValue (name, out entries))
511
List<MethodSpec> candidates = null;
512
foreach (var entry in entries) {
513
if (entry.Kind != MemberKind.Method || (arity > 0 && entry.Arity != arity))
516
var ms = (MethodSpec) entry;
517
if (!ms.IsExtensionMethod)
520
if (!ms.IsAccessible (invocationContext))
524
// Extension methods cannot be nested hence checking parent is enough
526
if ((ms.DeclaringType.Modifiers & Modifiers.INTERNAL) != 0 && !ms.DeclaringType.MemberDefinition.IsInternalAsPublic (invocationContext.Module.DeclaringAssembly))
529
if (candidates == null)
530
candidates = new List<MethodSpec> ();
538
// Returns base members of @member member if no exact match is found @bestCandidate returns
541
public static MemberSpec FindBaseMember (MemberCore member, out MemberSpec bestCandidate, ref bool overrides)
543
bestCandidate = null;
544
var container = member.Parent.PartialContainer.Definition;
545
if (!container.IsInterface) {
546
container = container.BaseType;
548
// It can happen for a user definition of System.Object
549
if (container == null)
553
string name = GetLookupName (member);
554
var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : null;
556
var mkind = GetMemberCoreKind (member);
557
bool member_with_accessors = mkind == MemberKind.Indexer || mkind == MemberKind.Property;
559
IList<MemberSpec> applicable;
560
MemberSpec ambig_candidate = null;
563
if (container.MemberCache.member_hash.TryGetValue (name, out applicable)) {
564
for (int i = 0; i < applicable.Count; ++i) {
565
var entry = applicable [i];
567
if ((entry.Modifiers & Modifiers.PRIVATE) != 0)
570
if ((entry.Modifiers & Modifiers.AccessibilityMask) == Modifiers.INTERNAL &&
571
!entry.DeclaringType.MemberDefinition.IsInternalAsPublic (member.Module.DeclaringAssembly))
575
// Isn't the member of same kind ?
577
if ((entry.Kind & ~MemberKind.Destructor & mkind & MemberKind.MaskType) == 0) {
578
// Destructors are ignored as they cannot be overridden by user
579
if ((entry.Kind & MemberKind.Destructor) != 0)
582
// A method with different arity does not hide base member
583
if (mkind != MemberKind.Method && member.MemberName.Arity != entry.Arity)
586
bestCandidate = entry;
591
// Same kind of different arity is valid
593
if (member.MemberName.Arity != entry.Arity) {
597
if ((entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) {
598
if (entry.IsAccessor != member is AbstractPropertyEventMethod)
601
var pm = entry as IParametersMember;
602
if (!TypeSpecComparer.Override.IsEqual (pm.Parameters, member_param))
607
// Skip override for member with accessors. It may not fully implement the base member
608
// but keep flag we found an implementation in case the base member is abstract
610
if (member_with_accessors && ((entry.Modifiers & (Modifiers.OVERRIDE | Modifiers.SEALED)) == Modifiers.OVERRIDE)) {
612
// Set candidate to override implementation to flag we found an implementation
619
// For members with parameters we can encounter an ambiguous candidates (they match exactly)
620
// because generic type parameters could be inflated into same types
622
if (ambig_candidate == null && (entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) {
623
bestCandidate = null;
624
ambig_candidate = entry;
628
bestCandidate = ambig_candidate;
633
if (container.IsInterface || ambig_candidate != null)
636
container = container.BaseType;
637
} while (container != null);
639
return ambig_candidate;
643
// Returns inflated version of MemberSpec, it works similarly to
644
// SRE TypeBuilder.GetMethod
646
public static T GetMember<T> (TypeSpec container, T spec) where T : MemberSpec
648
IList<MemberSpec> applicable;
649
if (container.MemberCache.member_hash.TryGetValue (GetLookupName (spec), out applicable)) {
650
for (int i = applicable.Count - 1; i >= 0; i--) {
651
var entry = applicable[i];
652
if (entry.MemberDefinition == spec.MemberDefinition)
657
throw new InternalErrorException ("Missing member `{0}' on inflated type `{1}'",
658
spec.GetSignatureForError (), container.GetSignatureForError ());
661
static MemberKind GetMemberCoreKind (MemberCore member)
663
if (member is FieldBase)
664
return MemberKind.Field;
665
if (member is Indexer)
666
return MemberKind.Indexer;
668
return MemberKind.Class;
669
if (member is Struct)
670
return MemberKind.Struct;
671
if (member is Destructor)
672
return MemberKind.Destructor;
673
if (member is Method)
674
return MemberKind.Method;
675
if (member is Property)
676
return MemberKind.Property;
677
if (member is EventField)
678
return MemberKind.Event;
679
if (member is Interface)
680
return MemberKind.Interface;
681
if (member is EventProperty)
682
return MemberKind.Event;
683
if (member is Delegate)
684
return MemberKind.Delegate;
686
return MemberKind.Enum;
688
throw new NotImplementedException (member.GetType ().ToString ());
691
public static List<FieldSpec> GetAllFieldsForDefiniteAssignment (TypeSpec container)
693
List<FieldSpec> fields = null;
694
foreach (var entry in container.MemberCache.member_hash) {
695
foreach (var name_entry in entry.Value) {
696
if (name_entry.Kind != MemberKind.Field)
699
if ((name_entry.Modifiers & Modifiers.STATIC) != 0)
703
// Fixed size buffers are not subject to definite assignment checking
705
if (name_entry is FixedFieldSpec || name_entry is ConstSpec)
708
var fs = (FieldSpec) name_entry;
711
// LAMESPEC: Very bizzare hack, definitive assignment is not done
712
// for imported non-public reference fields except array. No idea what the
713
// actual csc rule is
715
if (!fs.IsPublic && container.MemberDefinition.IsImported && (!fs.MemberType.IsArray && TypeSpec.IsReferenceType (fs.MemberType)))
719
fields = new List<FieldSpec> ();
726
return fields ?? new List<FieldSpec> (0);
729
public static IList<MemberSpec> GetCompletitionMembers (IMemberContext ctx, TypeSpec container, string name)
731
var matches = new List<MemberSpec> ();
732
foreach (var entry in container.MemberCache.member_hash) {
733
foreach (var name_entry in entry.Value) {
734
if (name_entry.IsAccessor)
737
if ((name_entry.Kind & (MemberKind.Constructor | MemberKind.Destructor | MemberKind.Operator)) != 0)
740
if (!name_entry.IsAccessible (ctx))
743
if (name == null || name_entry.Name.StartsWith (name)) {
744
matches.Add (name_entry);
753
// Returns members of @iface only, base members are ignored
755
public static List<MethodSpec> GetInterfaceMethods (TypeSpec iface)
758
// MemberCache flatten interfaces, therefore in cases like this one
760
// interface IA : IB {}
761
// interface IB { void Foo () }
763
// we would return Foo inside IA which is not expected in this case
765
var methods = new List<MethodSpec> ();
766
foreach (var entry in iface.MemberCache.member_hash.Values) {
767
foreach (var name_entry in entry) {
768
if (iface == name_entry.DeclaringType) {
769
if (name_entry.Kind == MemberKind.Method) {
770
methods.Add ((MethodSpec) name_entry);
780
// Returns all not implememted abstract members inside abstract type
781
// NOTE: Returned list is shared and must not be modified
783
public static IList<MethodSpec> GetNotImplementedAbstractMethods (TypeSpec type)
785
if (type.MemberCache.missing_abstract != null)
786
return type.MemberCache.missing_abstract;
788
var abstract_methods = new List<MethodSpec> ();
789
List<TypeSpec> hierarchy = null;
792
// Stage 1: top-to-bottom scan for abstract members
794
var abstract_type = type;
796
foreach (var entry in abstract_type.MemberCache.member_hash) {
797
foreach (var name_entry in entry.Value) {
798
if ((name_entry.Modifiers & (Modifiers.ABSTRACT | Modifiers.OVERRIDE)) != Modifiers.ABSTRACT)
801
if (name_entry.Kind != MemberKind.Method)
804
abstract_methods.Add ((MethodSpec) name_entry);
808
var base_type = abstract_type.BaseType;
809
if (!base_type.IsAbstract)
812
if (hierarchy == null)
813
hierarchy = new List<TypeSpec> ();
815
hierarchy.Add (abstract_type);
816
abstract_type = base_type;
819
int not_implemented_count = abstract_methods.Count;
820
if (not_implemented_count == 0 || hierarchy == null) {
821
type.MemberCache.missing_abstract = abstract_methods;
822
return type.MemberCache.missing_abstract;
826
// Stage 2: Remove already implemented methods
828
foreach (var type_up in hierarchy) {
829
var members = type_up.MemberCache.member_hash;
830
if (members.Count == 0)
833
for (int i = 0; i < abstract_methods.Count; ++i) {
834
var candidate = abstract_methods [i];
835
if (candidate == null)
838
IList<MemberSpec> applicable;
839
if (!members.TryGetValue (candidate.Name, out applicable))
842
var filter = new MemberFilter (candidate);
843
foreach (var item in applicable) {
844
if ((item.Modifiers & (Modifiers.OVERRIDE | Modifiers.VIRTUAL)) == 0)
848
// Abstract override does not override anything
850
if ((item.Modifiers & Modifiers.ABSTRACT) != 0)
853
if (filter.Equals (item)) {
854
--not_implemented_count;
855
abstract_methods [i] = null;
862
if (not_implemented_count == abstract_methods.Count) {
863
type.MemberCache.missing_abstract = abstract_methods;
864
return type.MemberCache.missing_abstract;
867
var not_implemented = new MethodSpec[not_implemented_count];
869
foreach (var m in abstract_methods) {
873
not_implemented[counter++] = m;
876
type.MemberCache.missing_abstract = not_implemented;
877
return type.MemberCache.missing_abstract;
880
static string GetLookupName (MemberSpec ms)
882
if (ms.Kind == MemberKind.Indexer)
883
return IndexerNameAlias;
885
if (ms.Kind == MemberKind.Constructor) {
887
return Constructor.TypeConstructorName;
889
return Constructor.ConstructorName;
895
static string GetLookupName (MemberCore mc)
898
return IndexerNameAlias;
900
if (mc is Constructor)
901
return mc.IsStatic ? Constructor.TypeConstructorName : Constructor.ConstructorName;
903
return mc.MemberName.Name;
907
// Returns all operators declared on container and its base types (until declaredOnly is used)
909
public static IList<MemberSpec> GetUserOperator (TypeSpec container, Operator.OpType op, bool declaredOnly)
911
IList<MemberSpec> found = null;
912
bool shared_list = true;
913
IList<MemberSpec> applicable;
915
var mc = container.MemberCache;
917
if (((op == Operator.OpType.Implicit || op == Operator.OpType.Explicit) && (mc.state & StateFlags.HasConversionOperator) != 0) ||
918
(mc.state & StateFlags.HasUserOperator) != 0) {
920
if (mc.member_hash.TryGetValue (Operator.GetMetadataName (op), out applicable)) {
922
for (i = 0; i < applicable.Count; ++i) {
923
if (applicable[i].Kind != MemberKind.Operator) {
929
// Handles very rare case where a method with same name as operator (op_xxxx) exists
930
// and we have to resize the applicable list
932
if (i != applicable.Count) {
933
for (i = 0; i < applicable.Count; ++i) {
934
if (applicable[i].Kind != MemberKind.Operator) {
939
found = new List<MemberSpec> ();
940
found.Add (applicable[i]);
942
List<MemberSpec> prev;
945
prev = new List<MemberSpec> (found.Count + 1);
946
prev.AddRange (found);
948
prev = (List<MemberSpec>) found;
951
prev.Add (applicable[i]);
959
List<MemberSpec> merged;
962
merged = new List<MemberSpec> (found.Count + applicable.Count);
963
merged.AddRange (found);
966
merged = (List<MemberSpec>) found;
969
merged.AddRange (applicable);
975
// BaseType call can be expensive
979
container = container.BaseType;
980
} while (container != null);
986
// Inflates all member cache nested types
988
public void InflateTypes (MemberCache inflated_cache, TypeParameterInflator inflator)
990
foreach (var item in member_hash) {
991
IList<MemberSpec> inflated_members = null;
992
for (int i = 0; i < item.Value.Count; ++i ) {
993
var member = item.Value[i];
995
// FIXME: When inflating members refering nested types before they are inflated
999
if ((member.Kind & MemberKind.NestedMask) != 0 &&
1000
(member.Modifiers & Modifiers.COMPILER_GENERATED) == 0) {
1001
if (inflated_members == null) {
1002
inflated_members = new MemberSpec[item.Value.Count];
1003
inflated_cache.member_hash.Add (item.Key, inflated_members);
1006
inflated_members [i] = member.InflateMember (inflator);
1013
// Inflates all open type members, requires InflateTypes to be called before
1015
public void InflateMembers (MemberCache cacheToInflate, TypeSpec inflatedType, TypeParameterInflator inflator)
1017
var inflated_member_hash = cacheToInflate.member_hash;
1018
Dictionary<MemberSpec, MethodSpec> accessor_relation = null;
1019
List<MemberSpec> accessor_members = null;
1021
// Copy member specific flags when all members were added
1022
cacheToInflate.state = state;
1024
foreach (var item in member_hash) {
1025
var members = item.Value;
1026
IList<MemberSpec> inflated_members = null;
1027
for (int i = 0; i < members.Count; ++i ) {
1028
var member = members[i];
1031
// All nested types have been inflated earlier except for
1032
// compiler types which are created later and could miss InflateTypes
1034
if ((member.Kind & MemberKind.NestedMask) != 0 &&
1035
(member.Modifiers & Modifiers.COMPILER_GENERATED) == 0) {
1036
if (inflated_members == null)
1037
inflated_members = inflated_member_hash[item.Key];
1043
// Clone the container first
1045
if (inflated_members == null) {
1046
inflated_members = new MemberSpec [item.Value.Count];
1047
inflated_member_hash.Add (item.Key, inflated_members);
1050
var local_inflator = inflator;
1052
if (member.DeclaringType != inflatedType) {
1054
// Don't inflate top-level non-generic interface members
1055
// merged into generic interface
1057
if (!member.DeclaringType.IsGeneric && !member.DeclaringType.IsNested) {
1058
inflated_members [i] = member;
1063
// Needed when inflating flatten interfaces. It inflates
1064
// container type only, type parameters are already done
1066
// Handles cases like:
1068
// interface I<T> {}
1069
// interface I<U, V> : I<U> {}
1071
// class C: I<int, bool> {}
1073
var inflated_parent = inflator.Inflate (member.DeclaringType);
1074
if (inflated_parent != inflator.TypeInstance)
1075
local_inflator = new TypeParameterInflator (inflator, inflated_parent);
1079
// Inflate every member, its parent is now different
1081
var inflated = member.InflateMember (local_inflator);
1082
inflated_members [i] = inflated;
1084
if (member is PropertySpec || member is EventSpec) {
1085
if (accessor_members == null)
1086
accessor_members = new List<MemberSpec> ();
1088
accessor_members.Add (inflated);
1092
if (member.IsAccessor) {
1093
if (accessor_relation == null)
1094
accessor_relation = new Dictionary<MemberSpec, MethodSpec> ();
1095
accessor_relation.Add (member, (MethodSpec) inflated);
1100
if (accessor_members != null) {
1101
foreach (var member in accessor_members) {
1102
var prop = member as PropertySpec;
1104
if (prop.Get != null)
1105
prop.Get = accessor_relation[prop.Get];
1106
if (prop.Set != null)
1107
prop.Set = accessor_relation[prop.Set];
1112
var ev = (EventSpec) member;
1113
ev.AccessorAdd = accessor_relation[ev.AccessorAdd];
1114
ev.AccessorRemove = accessor_relation[ev.AccessorRemove];
1120
// Removes hidden base members of an interface. For compiled interfaces we cannot
1121
// do name filtering during Add (as we do for import) because we need all base
1122
// names to be valid during type definition.
1123
// Add replaces hidden base member with current one which means any name collision
1124
// (CS0108) of non-first name would be unnoticed because the name was replaced
1125
// with the one from compiled type
1127
public void RemoveHiddenMembers (TypeSpec container)
1129
foreach (var entry in member_hash) {
1130
var values = entry.Value;
1132
int container_members_start_at = 0;
1133
while (values[container_members_start_at].DeclaringType != container && ++container_members_start_at < entry.Value.Count);
1135
if (container_members_start_at == 0 || container_members_start_at == values.Count)
1138
for (int i = 0; i < container_members_start_at; ++i) {
1139
var member = values[i];
1141
if (!container.ImplementsInterface (member.DeclaringType, false))
1144
var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : ParametersCompiled.EmptyReadOnlyParameters;
1146
for (int ii = container_members_start_at; ii < values.Count; ++ii) {
1147
var container_entry = values[ii];
1149
if (container_entry.Arity != member.Arity)
1152
if (container_entry is IParametersMember) {
1153
if (!TypeSpecComparer.Override.IsEqual (((IParametersMember) container_entry).Parameters, member_param))
1157
values.RemoveAt (i);
1158
--container_members_start_at;
1167
// Checks all appropriate container members for CLS compliance
1169
public void VerifyClsCompliance (TypeSpec container, Report report)
1171
if (locase_members != null)
1174
if (container.BaseType == null) {
1175
locase_members = new Dictionary<string, MemberSpec[]> (member_hash.Count); // StringComparer.OrdinalIgnoreCase);
1177
var btype = container.BaseType.GetDefinition ();
1178
btype.MemberCache.VerifyClsCompliance (btype, report);
1179
locase_members = new Dictionary<string, MemberSpec[]> (btype.MemberCache.locase_members); //, StringComparer.OrdinalIgnoreCase);
1182
var is_imported_type = container.MemberDefinition.IsImported;
1183
foreach (var entry in container.MemberCache.member_hash) {
1184
for (int i = 0; i < entry.Value.Count; ++i ) {
1185
var name_entry = entry.Value[i];
1186
if ((name_entry.Modifiers & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
1189
if ((name_entry.Modifiers & (Modifiers.OVERRIDE | Modifiers.COMPILER_GENERATED)) != 0)
1192
if ((name_entry.Kind & MemberKind.MaskType) == 0)
1195
if (name_entry.MemberDefinition.CLSAttributeValue == false)
1198
IParametersMember p_a = null;
1199
if (!is_imported_type) {
1200
p_a = name_entry as IParametersMember;
1201
if (p_a != null && !name_entry.IsAccessor) {
1202
var p_a_pd = p_a.Parameters;
1204
// Check differing overloads in @container
1206
for (int ii = i + 1; ii < entry.Value.Count; ++ii) {
1207
var checked_entry = entry.Value[ii];
1208
IParametersMember p_b = checked_entry as IParametersMember;
1212
if (p_a_pd.Count != p_b.Parameters.Count)
1215
if (checked_entry.IsAccessor)
1218
var res = ParametersCompiled.IsSameClsSignature (p_a.Parameters, p_b.Parameters);
1220
ReportOverloadedMethodClsDifference (name_entry, checked_entry, res, report);
1226
if (i > 0 || name_entry.Kind == MemberKind.Constructor || name_entry.Kind == MemberKind.Indexer)
1229
var name_entry_locase = name_entry.Name.ToLowerInvariant ();
1232
if (!locase_members.TryGetValue (name_entry_locase, out found)) {
1233
found = new MemberSpec[] { name_entry };
1234
locase_members.Add (name_entry_locase, found);
1236
bool same_names_only = true;
1237
foreach (var f in found) {
1238
if (f.Name == name_entry.Name) {
1240
IParametersMember p_b = f as IParametersMember;
1244
if (p_a.Parameters.Count != p_b.Parameters.Count)
1250
var res = ParametersCompiled.IsSameClsSignature (p_a.Parameters, p_b.Parameters);
1252
ReportOverloadedMethodClsDifference (f, name_entry, res, report);
1259
same_names_only = false;
1260
if (!is_imported_type) {
1261
var last = GetLaterDefinedMember (f, name_entry);
1262
if (last == f.MemberDefinition) {
1263
report.SymbolRelatedToPreviousError (name_entry);
1265
report.SymbolRelatedToPreviousError (f);
1268
report.Warning (3005, 1, last.Location,
1269
"Identifier `{0}' differing only in case is not CLS-compliant", last.GetSignatureForError ());
1273
if (!same_names_only) {
1274
Array.Resize (ref found, found.Length + 1);
1275
found[found.Length - 1] = name_entry;
1276
locase_members[name_entry_locase] = found;
1284
// Local report helper to issue correctly ordered members stored in hashtable
1286
static MemberCore GetLaterDefinedMember (MemberSpec a, MemberSpec b)
1288
var mc_a = a.MemberDefinition as MemberCore;
1289
var mc_b = b.MemberDefinition as MemberCore;
1296
if (a.DeclaringType.MemberDefinition != b.DeclaringType.MemberDefinition)
1299
if (mc_a.Location.File != mc_a.Location.File)
1302
return mc_b.Location.Row > mc_a.Location.Row ? mc_b : mc_a;
1305
static void ReportOverloadedMethodClsDifference (MemberSpec a, MemberSpec b, int res, Report report)
1307
var last = GetLaterDefinedMember (a, b);
1308
if (last == a.MemberDefinition) {
1309
report.SymbolRelatedToPreviousError (b);
1311
report.SymbolRelatedToPreviousError (a);
1314
if ((res & 1) != 0) {
1315
report.Warning (3006, 1, last.Location,
1316
"Overloaded method `{0}' differing only in ref or out, or in array rank, is not CLS-compliant",
1317
last.GetSignatureForError ());
1320
if ((res & 2) != 0) {
1321
report.Warning (3007, 1, last.Location,
1322
"Overloaded method `{0}' differing only by unnamed array types is not CLS-compliant",
1323
last.GetSignatureForError ());
1327
public bool CheckExistingMembersOverloads (MemberCore member, AParametersCollection parameters)
1329
var name = GetLookupName (member);
1330
var imb = member as InterfaceMemberBase;
1331
if (imb != null && imb.IsExplicitImpl) {
1332
name = imb.GetFullName (name);
1335
return CheckExistingMembersOverloads (member, name, parameters);
1338
public bool CheckExistingMembersOverloads (MemberCore member, string name, AParametersCollection parameters)
1340
IList<MemberSpec> entries;
1341
if (!member_hash.TryGetValue (name, out entries))
1344
var Report = member.Compiler.Report;
1346
int method_param_count = parameters.Count;
1347
for (int i = entries.Count - 1; i >= 0; --i) {
1348
var ce = entries[i];
1349
var pm = ce as IParametersMember;
1350
var pd = pm == null ? ParametersCompiled.EmptyReadOnlyParameters : pm.Parameters;
1351
if (pd.Count != method_param_count)
1354
if (ce.Arity != member.MemberName.Arity)
1357
// Ignore merged interface members
1358
if (member.Parent.PartialContainer != ce.DeclaringType.MemberDefinition)
1361
var p_types = pd.Types;
1362
if (method_param_count > 0) {
1363
int ii = method_param_count - 1;
1364
TypeSpec type_a, type_b;
1366
type_a = parameters.Types [ii];
1367
type_b = p_types [ii];
1369
var a_byref = (pd.FixedParameters[ii].ModFlags & Parameter.Modifier.RefOutMask) != 0;
1370
var b_byref = (parameters.FixedParameters[ii].ModFlags & Parameter.Modifier.RefOutMask) != 0;
1372
if (a_byref != b_byref)
1375
} while (TypeSpecComparer.Override.IsEqual (type_a, type_b) && ii-- != 0);
1381
// Operators can differ in return type only
1383
if (member is Operator && ce.Kind == MemberKind.Operator && ((MethodSpec) ce).ReturnType != ((Operator) member).ReturnType)
1387
// Report difference in parameter modifiers only
1389
if (pd != null && member is MethodCore) {
1390
ii = method_param_count;
1392
(parameters.FixedParameters[ii].ModFlags & Parameter.Modifier.ModifierMask) ==
1393
(pd.FixedParameters[ii].ModFlags & Parameter.Modifier.ModifierMask) &&
1394
parameters.ExtensionMethodType == pd.ExtensionMethodType) ;
1397
var mc = ce as MethodSpec;
1398
member.Compiler.Report.SymbolRelatedToPreviousError (ce);
1399
if ((member.ModFlags & Modifiers.PARTIAL) != 0 && (mc.Modifiers & Modifiers.PARTIAL) != 0) {
1400
if (parameters.HasParams || pd.HasParams) {
1401
Report.Error (758, member.Location,
1402
"A partial method declaration and partial method implementation cannot differ on use of `params' modifier");
1404
Report.Error (755, member.Location,
1405
"A partial method declaration and partial method implementation must be both an extension method or neither");
1407
} else if (member is Constructor) {
1408
Report.Error (851, member.Location,
1409
"Overloaded contructor `{0}' cannot differ on use of parameter modifiers only",
1410
member.GetSignatureForError ());
1412
Report.Error (663, member.Location,
1413
"Overloaded method `{0}' cannot differ on use of parameter modifiers only",
1414
member.GetSignatureForError ());
1421
if ((ce.Kind & MemberKind.Method) != 0) {
1422
Method method_a = member as Method;
1423
Method method_b = ce.MemberDefinition as Method;
1424
if (method_a != null && method_b != null && (method_a.ModFlags & method_b.ModFlags & Modifiers.PARTIAL) != 0) {
1425
const Modifiers partial_modifiers = Modifiers.STATIC | Modifiers.UNSAFE;
1426
if (method_a.IsPartialDefinition == method_b.IsPartialImplementation) {
1427
if ((method_a.ModFlags & partial_modifiers) == (method_b.ModFlags & partial_modifiers) ||
1428
method_a.Parent.IsUnsafe && method_b.Parent.IsUnsafe) {
1429
if (method_a.IsPartialImplementation) {
1430
method_a.SetPartialDefinition (method_b);
1431
if (entries.Count == 1)
1432
member_hash.Remove (name);
1434
entries.RemoveAt (i);
1436
method_b.SetPartialDefinition (method_a);
1437
method_a.caching_flags |= MemberCore.Flags.PartialDefinitionExists;
1442
if (method_a.IsStatic != method_b.IsStatic) {
1443
Report.SymbolRelatedToPreviousError (ce);
1444
Report.Error (763, member.Location,
1445
"A partial method declaration and partial method implementation must be both `static' or neither");
1448
Report.SymbolRelatedToPreviousError (ce);
1449
Report.Error (764, member.Location,
1450
"A partial method declaration and partial method implementation must be both `unsafe' or neither");
1454
Report.SymbolRelatedToPreviousError (ce);
1455
if (method_a.IsPartialDefinition) {
1456
Report.Error (756, member.Location, "A partial method `{0}' declaration is already defined",
1457
member.GetSignatureForError ());
1460
Report.Error (757, member.Location, "A partial method `{0}' implementation is already defined",
1461
member.GetSignatureForError ());
1465
Report.SymbolRelatedToPreviousError (ce);
1467
bool is_reserved_a = member is AbstractPropertyEventMethod || member is Operator;
1468
bool is_reserved_b = ((MethodSpec) ce).IsReservedMethod;
1470
if (is_reserved_a || is_reserved_b) {
1471
Report.Error (82, member.Location, "A member `{0}' is already reserved",
1473
ce.GetSignatureForError () :
1474
member.GetSignatureForError ());
1478
Report.SymbolRelatedToPreviousError (ce);
1481
if (member is Operator && ce.Kind == MemberKind.Operator) {
1482
Report.Error (557, member.Location, "Duplicate user-defined conversion in type `{0}'",
1483
member.Parent.GetSignatureForError ());
1487
Report.Error (111, member.Location,
1488
"A member `{0}' is already defined. Rename this member or use different parameter types",
1489
member.GetSignatureForError ());