~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/membercache.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// membercache.cs: A container for all member lookups
 
3
//
 
4
// Author: Miguel de Icaza (miguel@gnu.org)
 
5
//         Marek Safar (marek.safar@gmail.com)
 
6
//
 
7
// Dual licensed under the terms of the MIT X11 or GNU GPL
 
8
//
 
9
// Copyright 2001 Ximian, Inc (http://www.ximian.com)
 
10
// Copyright 2004-2010 Novell, Inc
 
11
// Copyright 2011 Xamarin Inc
 
12
//
 
13
//
 
14
 
 
15
using System;
 
16
using System.Collections.Generic;
 
17
 
 
18
namespace Mono.CSharp {
 
19
 
 
20
        [Flags]
 
21
        public enum MemberKind
 
22
        {
 
23
                Constructor = 1,
 
24
                Event = 1 << 1,
 
25
                Field = 1 << 2,
 
26
                Method = 1 << 3,
 
27
                Property = 1 << 4,
 
28
                Indexer = 1 << 5,
 
29
                Operator = 1 << 6,
 
30
                Destructor      = 1 << 7,
 
31
 
 
32
                Class           = 1 << 11,
 
33
                Struct          = 1 << 12,
 
34
                Delegate        = 1 << 13,
 
35
                Enum            = 1 << 14,
 
36
                Interface       = 1 << 15,
 
37
                TypeParameter = 1 << 16,
 
38
 
 
39
                ArrayType = 1 << 19,
 
40
                PointerType = 1 << 20,
 
41
                InternalCompilerType = 1 << 21,
 
42
                MissingType = 1 << 22,
 
43
                Void = 1 << 23,
 
44
                Namespace = 1 << 24,
 
45
 
 
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
 
49
        }
 
50
 
 
51
        [Flags]
 
52
        public enum BindingRestriction
 
53
        {
 
54
                None = 0,
 
55
 
 
56
                // Inspect only queried type members
 
57
                DeclaredOnly = 1 << 1,
 
58
 
 
59
                // Exclude static
 
60
                InstanceOnly = 1 << 2,
 
61
 
 
62
                NoAccessors = 1 << 3,
 
63
 
 
64
                // Member has to be override
 
65
                OverrideOnly = 1 << 4
 
66
        }
 
67
 
 
68
        public struct MemberFilter : IEquatable<MemberSpec>
 
69
        {
 
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
 
75
 
 
76
                public MemberFilter (MethodSpec m)
 
77
                {
 
78
                        Name = m.Name;
 
79
                        Kind = MemberKind.Method;
 
80
                        Parameters = m.Parameters;
 
81
                        MemberType = m.ReturnType;
 
82
                        Arity = m.Arity;
 
83
                }
 
84
 
 
85
                public MemberFilter (string name, int arity, MemberKind kind, AParametersCollection param, TypeSpec type)
 
86
                {
 
87
                        Name = name;
 
88
                        Kind = kind;
 
89
                        Parameters = param;
 
90
                        MemberType = type;
 
91
                        this.Arity = arity;
 
92
                }
 
93
 
 
94
                public static MemberFilter Constructor (AParametersCollection param)
 
95
                {
 
96
                        return new MemberFilter (Mono.CSharp.Constructor.ConstructorName, 0, MemberKind.Constructor, param, null);
 
97
                }
 
98
 
 
99
                public static MemberFilter Property (string name, TypeSpec type)
 
100
                {
 
101
                        return new MemberFilter (name, 0, MemberKind.Property, null, type);
 
102
                }
 
103
 
 
104
                public static MemberFilter Field (string name, TypeSpec type)
 
105
                {
 
106
                        return new MemberFilter (name, 0, MemberKind.Field, null, type);
 
107
                }
 
108
 
 
109
                public static MemberFilter Method (string name, int arity, AParametersCollection param, TypeSpec type)
 
110
                {
 
111
                        return new MemberFilter (name, arity, MemberKind.Method, param, type);
 
112
                }
 
113
 
 
114
                #region IEquatable<MemberSpec> Members
 
115
 
 
116
                public bool Equals (MemberSpec other)
 
117
                {
 
118
                        // Is the member of the correct type ?
 
119
                        // TODO: Isn't this redundant ?
 
120
                        if ((other.Kind & Kind & MemberKind.MaskType) == 0)
 
121
                                return false;
 
122
 
 
123
                        // Check arity when not disabled
 
124
                        if (Arity >= 0 && Arity != other.Arity)
 
125
                                return false;
 
126
 
 
127
                        if (Parameters != null) {
 
128
                                if (other is IParametersMember) {
 
129
                                        var other_param = ((IParametersMember) other).Parameters;
 
130
                                        if (!TypeSpecComparer.Override.IsEqual (Parameters, other_param))
 
131
                                                return false;
 
132
                                } else {
 
133
                                        return false;
 
134
                                }
 
135
                        }
 
136
 
 
137
                        if (MemberType != null) {
 
138
                                if (other is IInterfaceMemberSpec) {
 
139
                                        var other_type = ((IInterfaceMemberSpec) other).MemberType;
 
140
                                        if (!TypeSpecComparer.Override.IsEqual (other_type, MemberType))
 
141
                                                return false;
 
142
                                } else {
 
143
                                        return false;
 
144
                                }
 
145
                        }
 
146
 
 
147
                        return true;
 
148
                }
 
149
 
 
150
                #endregion
 
151
        }
 
152
 
 
153
        //
 
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.
 
158
        //
 
159
        // All of the methods are performance and memory sensitive as the MemberCache
 
160
        // is the underlying engine of all member based operations.
 
161
        //
 
162
        public class MemberCache
 
163
        {
 
164
                [Flags]
 
165
                enum StateFlags
 
166
                {
 
167
                        HasConversionOperator = 1 << 1,
 
168
                        HasUserOperator = 1 << 2
 
169
                }
 
170
 
 
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
 
175
 
 
176
                public static readonly string IndexerNameAlias = "<this>";
 
177
 
 
178
                public static readonly MemberCache Empty = new MemberCache (0);
 
179
 
 
180
                public MemberCache ()
 
181
                        : this (16)
 
182
                {
 
183
                }
 
184
 
 
185
                public MemberCache (int capacity)
 
186
                {
 
187
                        member_hash = new Dictionary<string, IList<MemberSpec>> (capacity);
 
188
                }
 
189
 
 
190
                public MemberCache (MemberCache cache)
 
191
                        : this (cache.member_hash.Count)
 
192
                {
 
193
                        this.state = cache.state;
 
194
                }
 
195
 
 
196
                //
 
197
                // Creates a new MemberCache for the given `container'.
 
198
                //
 
199
                public MemberCache (TypeContainer container)
 
200
                        : this ()                               // TODO: Optimize the size
 
201
                {
 
202
                }
 
203
 
 
204
                //
 
205
                // For cases where we need to union cache members
 
206
                //
 
207
                public void AddBaseType (TypeSpec baseType)
 
208
                {
 
209
                        var cache = baseType.MemberCache;
 
210
 
 
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) {
 
215
                                                list = entry.Value;
 
216
                                        } else {
 
217
                                                list = new List<MemberSpec> (entry.Value);
 
218
                                        }
 
219
 
 
220
                                        member_hash.Add (entry.Key, list);
 
221
                                        continue;
 
222
                                }
 
223
 
 
224
                                foreach (var ce in entry.Value) {
 
225
                                        if (list.Contains (ce))
 
226
                                                continue;
 
227
 
 
228
                                        if (list is MemberSpec[]) {
 
229
                                                list = new List<MemberSpec> () { list [0] };
 
230
                                                member_hash[entry.Key] = list;
 
231
                                        }
 
232
 
 
233
                                        list.Add (ce);
 
234
                                }
 
235
                        }
 
236
                }
 
237
 
 
238
                //
 
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.
 
242
                //
 
243
                // Does not work recursively because of generic interfaces
 
244
                //
 
245
                public void AddInterface (TypeSpec iface)
 
246
                {
 
247
                        var cache = iface.MemberCache;
 
248
 
 
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) {
 
253
                                                list = entry.Value;
 
254
                                        } else {
 
255
                                                list = new List<MemberSpec> (entry.Value);
 
256
                                        }
 
257
 
 
258
                                        member_hash.Add (entry.Key, list);
 
259
                                        continue;
 
260
                                }
 
261
 
 
262
                                foreach (var ce in entry.Value) {
 
263
                                        //
 
264
                                        // When two or more different base interfaces implemenent common
 
265
                                        // interface
 
266
                                        //
 
267
                                        // I : IA, IFoo
 
268
                                        // IA : IFoo
 
269
                                        //
 
270
                                        if (list.Contains (ce))
 
271
                                                continue;
 
272
 
 
273
                                        if (AddInterfaceMember (ce, ref list))
 
274
                                                member_hash[entry.Key] = list;
 
275
                                }
 
276
                        }
 
277
                }
 
278
 
 
279
                public void AddMember (InterfaceMemberBase imb, string exlicitName, MemberSpec ms)
 
280
                {
 
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);
 
285
                        else
 
286
                                AddMember (ms);
 
287
                }
 
288
 
 
289
                //
 
290
                // Add non-explicit member to member cache
 
291
                //
 
292
                public void AddMember (MemberSpec ms)
 
293
                {
 
294
                        AddMember (GetLookupName (ms), ms, false);
 
295
                }
 
296
 
 
297
                void AddMember (string name, MemberSpec member, bool removeHiddenMembers)
 
298
                {
 
299
                        if (member.Kind == MemberKind.Operator) {
 
300
                                var dt = member.DeclaringType;
 
301
 
 
302
 
 
303
                                //
 
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
 
307
                                // user conversions
 
308
                                //
 
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:
 
314
                                                break;
 
315
                                        default:
 
316
                                                if (name == Operator.GetMetadataName (Operator.OpType.Implicit) || name == Operator.GetMetadataName (Operator.OpType.Explicit)) {
 
317
                                                        state |= StateFlags.HasConversionOperator;
 
318
                                                } else {
 
319
                                                        state |= StateFlags.HasUserOperator;
 
320
                                                }
 
321
 
 
322
                                                break;
 
323
                                        }
 
324
                                }
 
325
                        }
 
326
 
 
327
                        IList<MemberSpec> list;
 
328
                        if (!member_hash.TryGetValue (name, out list)) {
 
329
                                member_hash.Add (name, new MemberSpec[] { member });
 
330
                                return;
 
331
                        }
 
332
 
 
333
                        if (removeHiddenMembers && member.DeclaringType.IsInterface) {
 
334
                                if (AddInterfaceMember (member, ref list))
 
335
                                        member_hash[name] = list;
 
336
                        } else {
 
337
                                if (list.Count == 1) {
 
338
                                        list = new List<MemberSpec> () { list[0] };
 
339
                                        member_hash[name] = list;
 
340
                                }
 
341
 
 
342
                                list.Add (member);
 
343
                        }
 
344
                }
 
345
 
 
346
                public void AddMemberImported (MemberSpec ms)
 
347
                {
 
348
                        AddMember (GetLookupName (ms), ms, true);
 
349
                }
 
350
 
 
351
                //
 
352
                // Ignores any base interface member which can be hidden
 
353
                // by this interface
 
354
                //
 
355
                static bool AddInterfaceMember (MemberSpec member, ref IList<MemberSpec> existing)
 
356
                {
 
357
                        var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : ParametersCompiled.EmptyReadOnlyParameters;
 
358
 
 
359
                        //
 
360
                        // interface IA : IB { int Prop { set; } }
 
361
                        // interface IB { bool Prop { get; } }
 
362
                        //
 
363
                        // IB.Prop is never accessible from IA interface
 
364
                        //
 
365
                        for (int i = 0; i < existing.Count; ++i) {
 
366
                                var entry = existing[i];
 
367
 
 
368
                                if (entry.Arity != member.Arity)
 
369
                                        continue;
 
370
 
 
371
                                if (entry is IParametersMember) {
 
372
                                        var entry_param = ((IParametersMember) entry).Parameters;
 
373
                                        if (!TypeSpecComparer.Override.IsEqual (entry_param, member_param))
 
374
                                                continue;
 
375
                                }
 
376
 
 
377
                                if (member.DeclaringType.ImplementsInterface (entry.DeclaringType, false)) {
 
378
                                        if (existing.Count == 1) {
 
379
                                                existing = new MemberSpec[] { member };
 
380
                                                return true;
 
381
                                        }
 
382
 
 
383
                                        existing.RemoveAt (i--);
 
384
                                        continue;
 
385
                                }
 
386
 
 
387
                                if ((entry.DeclaringType == member.DeclaringType && entry.IsAccessor == member.IsAccessor) ||
 
388
                                        entry.DeclaringType.ImplementsInterface (member.DeclaringType, false))
 
389
                                        return false;
 
390
                        }
 
391
 
 
392
                        if (existing.Count == 1) {
 
393
                                existing = new List<MemberSpec> () { existing[0], member };
 
394
                                return true;
 
395
                        }
 
396
 
 
397
                        existing.Add (member);
 
398
                        return false;
 
399
                }
 
400
 
 
401
                public static MemberSpec FindMember (TypeSpec container, MemberFilter filter, BindingRestriction restrictions)
 
402
                {
 
403
                        do {
 
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];
 
409
 
 
410
                                                if ((restrictions & BindingRestriction.InstanceOnly) != 0 && entry.IsStatic)
 
411
                                                        continue;
 
412
 
 
413
                                                if ((restrictions & BindingRestriction.NoAccessors) != 0 && entry.IsAccessor)
 
414
                                                        continue;
 
415
 
 
416
                                                if ((restrictions & BindingRestriction.OverrideOnly) != 0 && (entry.Modifiers & Modifiers.OVERRIDE) == 0)
 
417
                                                        continue;
 
418
 
 
419
                                                if (!filter.Equals (entry))
 
420
                                                        continue;
 
421
 
 
422
                                                if ((restrictions & BindingRestriction.DeclaredOnly) != 0 && container.IsInterface && entry.DeclaringType != container)
 
423
                                                        continue;
 
424
 
 
425
                                                return entry;
 
426
                                        }
 
427
                                }
 
428
 
 
429
                                if ((restrictions & BindingRestriction.DeclaredOnly) != 0)
 
430
                                        break;
 
431
 
 
432
                                container = container.BaseType;
 
433
                        } while (container != null);
 
434
 
 
435
                        return null;
 
436
                }
 
437
 
 
438
                //
 
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
 
441
                //
 
442
                // declaredOnlyClass cannot be used interfaces. Manual filtering is required because names are
 
443
                // compacted
 
444
                //
 
445
                public static IList<MemberSpec> FindMembers (TypeSpec container, string name, bool declaredOnlyClass)
 
446
                {
 
447
                        IList<MemberSpec> applicable;
 
448
 
 
449
                        do {
 
450
                                if (container.MemberCache.member_hash.TryGetValue (name, out applicable) || declaredOnlyClass)
 
451
                                        return applicable;
 
452
 
 
453
                                container = container.BaseType;
 
454
                        } while (container != null);
 
455
 
 
456
                        return null;
 
457
                }
 
458
 
 
459
                //
 
460
                // Finds the nested type in container
 
461
                //
 
462
                public static TypeSpec FindNestedType (TypeSpec container, string name, int arity)
 
463
                {
 
464
                        IList<MemberSpec> applicable;
 
465
                        TypeSpec best_match = null;
 
466
                        do {
 
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;
 
473
                                if (tc != null)
 
474
                                        tc.DefineContainer ();
 
475
 
 
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)
 
480
                                                        continue;
 
481
 
 
482
                                                var ts = (TypeSpec) entry;
 
483
                                                if (arity == ts.Arity)
 
484
                                                        return ts;
 
485
 
 
486
                                                if (arity < 0) {
 
487
                                                        if (best_match == null) {
 
488
                                                                best_match = ts;
 
489
                                                        } else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (ts.Arity + arity)) {
 
490
                                                                best_match = ts;
 
491
                                                        }
 
492
                                                }
 
493
                                        }
 
494
                                }
 
495
 
 
496
                                container = container.BaseType;
 
497
                        } while (container != null);
 
498
 
 
499
                        return best_match;
 
500
                }
 
501
 
 
502
                //
 
503
                // Looks for extension methods with defined name and extension type
 
504
                //
 
505
                public List<MethodSpec> FindExtensionMethods (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity)
 
506
                {
 
507
                        IList<MemberSpec> entries;
 
508
                        if (!member_hash.TryGetValue (name, out entries))
 
509
                                return null;
 
510
 
 
511
                        List<MethodSpec> candidates = null;
 
512
                        foreach (var entry in entries) {
 
513
                                if (entry.Kind != MemberKind.Method || (arity > 0 && entry.Arity != arity))
 
514
                                        continue;
 
515
 
 
516
                                var ms = (MethodSpec) entry;
 
517
                                if (!ms.IsExtensionMethod)
 
518
                                        continue;
 
519
 
 
520
                                if (!ms.IsAccessible (invocationContext))
 
521
                                        continue;
 
522
 
 
523
                                //
 
524
                                // Extension methods cannot be nested hence checking parent is enough
 
525
                                //
 
526
                                if ((ms.DeclaringType.Modifiers & Modifiers.INTERNAL) != 0 && !ms.DeclaringType.MemberDefinition.IsInternalAsPublic (invocationContext.Module.DeclaringAssembly))
 
527
                                        continue;
 
528
 
 
529
                                if (candidates == null)
 
530
                                        candidates = new List<MethodSpec> ();
 
531
                                candidates.Add (ms);
 
532
                        }
 
533
 
 
534
                        return candidates;
 
535
                }
 
536
 
 
537
                //
 
538
                // Returns base members of @member member if no exact match is found @bestCandidate returns
 
539
                // the best match
 
540
                //
 
541
                public static MemberSpec FindBaseMember (MemberCore member, out MemberSpec bestCandidate, ref bool overrides)
 
542
                {
 
543
                        bestCandidate = null;
 
544
                        var container = member.Parent.PartialContainer.Definition;
 
545
                        if (!container.IsInterface) {
 
546
                                container = container.BaseType;
 
547
 
 
548
                                // It can happen for a user definition of System.Object
 
549
                                if (container == null)
 
550
                                        return null;
 
551
                        }
 
552
 
 
553
                        string name = GetLookupName (member);
 
554
                        var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : null;
 
555
 
 
556
                        var mkind = GetMemberCoreKind (member);
 
557
                        bool member_with_accessors = mkind == MemberKind.Indexer || mkind == MemberKind.Property;
 
558
 
 
559
                        IList<MemberSpec> applicable;
 
560
                        MemberSpec ambig_candidate = null;
 
561
 
 
562
                        do {
 
563
                                if (container.MemberCache.member_hash.TryGetValue (name, out applicable)) {
 
564
                                        for (int i = 0; i < applicable.Count; ++i) {
 
565
                                                var entry = applicable [i];
 
566
 
 
567
                                                if ((entry.Modifiers & Modifiers.PRIVATE) != 0)
 
568
                                                        continue;
 
569
 
 
570
                                                if ((entry.Modifiers & Modifiers.AccessibilityMask) == Modifiers.INTERNAL &&
 
571
                                                        !entry.DeclaringType.MemberDefinition.IsInternalAsPublic (member.Module.DeclaringAssembly))
 
572
                                                        continue;
 
573
 
 
574
                                                //
 
575
                                                // Isn't the member of same kind ?
 
576
                                                //
 
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)
 
580
                                                                continue;
 
581
 
 
582
                                                        // A method with different arity does not hide base member
 
583
                                                        if (mkind != MemberKind.Method && member.MemberName.Arity != entry.Arity)
 
584
                                                                continue;
 
585
 
 
586
                                                        bestCandidate = entry;
 
587
                                                        return null;
 
588
                                                }
 
589
 
 
590
                                                //
 
591
                                                // Same kind of different arity is valid
 
592
                                                //
 
593
                                                if (member.MemberName.Arity != entry.Arity) {
 
594
                                                        continue;
 
595
                                                }
 
596
 
 
597
                                                if ((entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) {
 
598
                                                        if (entry.IsAccessor != member is AbstractPropertyEventMethod)
 
599
                                                                continue;
 
600
 
 
601
                                                        var pm = entry as IParametersMember;
 
602
                                                        if (!TypeSpecComparer.Override.IsEqual (pm.Parameters, member_param))
 
603
                                                                continue;
 
604
                                                }
 
605
 
 
606
                                                //
 
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
 
609
                                                //
 
610
                                                if (member_with_accessors && ((entry.Modifiers & (Modifiers.OVERRIDE | Modifiers.SEALED)) == Modifiers.OVERRIDE)) {
 
611
                                                        //
 
612
                                                        // Set candidate to override implementation to flag we found an implementation
 
613
                                                        //
 
614
                                                        overrides = true;
 
615
                                                        continue;
 
616
                                                }
 
617
 
 
618
                                                //
 
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
 
621
                                                //
 
622
                                                if (ambig_candidate == null && (entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) {
 
623
                                                        bestCandidate = null;
 
624
                                                        ambig_candidate = entry;
 
625
                                                        continue;
 
626
                                                }
 
627
 
 
628
                                                bestCandidate = ambig_candidate;
 
629
                                                return entry;
 
630
                                        }
 
631
                                }
 
632
 
 
633
                                if (container.IsInterface || ambig_candidate != null)
 
634
                                        break;
 
635
 
 
636
                                container = container.BaseType;
 
637
                        } while (container != null);
 
638
 
 
639
                        return ambig_candidate;
 
640
                }
 
641
 
 
642
                //
 
643
                // Returns inflated version of MemberSpec, it works similarly to
 
644
                // SRE TypeBuilder.GetMethod
 
645
                //
 
646
                public static T GetMember<T> (TypeSpec container, T spec) where T : MemberSpec
 
647
                {
 
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)
 
653
                                                return (T) entry;
 
654
                                }
 
655
                        }
 
656
 
 
657
                        throw new InternalErrorException ("Missing member `{0}' on inflated type `{1}'",
 
658
                                spec.GetSignatureForError (), container.GetSignatureForError ());
 
659
                }
 
660
 
 
661
                static MemberKind GetMemberCoreKind (MemberCore member)
 
662
                {
 
663
                        if (member is FieldBase)
 
664
                                return MemberKind.Field;
 
665
                        if (member is Indexer)
 
666
                                return MemberKind.Indexer;
 
667
                        if (member is Class)
 
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;
 
685
                        if (member is Enum)
 
686
                                return MemberKind.Enum;
 
687
 
 
688
                        throw new NotImplementedException (member.GetType ().ToString ());
 
689
                }
 
690
 
 
691
                public static List<FieldSpec> GetAllFieldsForDefiniteAssignment (TypeSpec container)
 
692
                {
 
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)
 
697
                                                continue;
 
698
 
 
699
                                        if ((name_entry.Modifiers & Modifiers.STATIC) != 0)
 
700
                                                continue;
 
701
 
 
702
                                        //
 
703
                                        // Fixed size buffers are not subject to definite assignment checking
 
704
                                        //
 
705
                                        if (name_entry is FixedFieldSpec || name_entry is ConstSpec)
 
706
                                                continue;
 
707
 
 
708
                                        var fs = (FieldSpec) name_entry;
 
709
 
 
710
                                        //
 
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
 
714
                                        //
 
715
                                        if (!fs.IsPublic && container.MemberDefinition.IsImported && (!fs.MemberType.IsArray && TypeSpec.IsReferenceType (fs.MemberType)))
 
716
                                                continue;
 
717
 
 
718
                                        if (fields == null)
 
719
                                                fields = new List<FieldSpec> ();
 
720
 
 
721
                                        fields.Add (fs);
 
722
                                        break;
 
723
                                }
 
724
                        }
 
725
 
 
726
                        return fields ?? new List<FieldSpec> (0);
 
727
                }
 
728
 
 
729
                public static IList<MemberSpec> GetCompletitionMembers (IMemberContext ctx, TypeSpec container, string name)
 
730
                {
 
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)
 
735
                                                continue;
 
736
 
 
737
                                        if ((name_entry.Kind & (MemberKind.Constructor | MemberKind.Destructor | MemberKind.Operator)) != 0)
 
738
                                                continue;
 
739
 
 
740
                                        if (!name_entry.IsAccessible (ctx))
 
741
                                                continue;
 
742
 
 
743
                                        if (name == null || name_entry.Name.StartsWith (name)) {
 
744
                                                matches.Add (name_entry);
 
745
                                        }
 
746
                                }
 
747
                        }
 
748
 
 
749
                        return matches;
 
750
                }
 
751
 
 
752
                //
 
753
                // Returns members of @iface only, base members are ignored
 
754
                //
 
755
                public static List<MethodSpec> GetInterfaceMethods (TypeSpec iface)
 
756
                {
 
757
                        //
 
758
                        // MemberCache flatten interfaces, therefore in cases like this one
 
759
                        // 
 
760
                        // interface IA : IB {}
 
761
                        // interface IB { void Foo () }
 
762
                        //
 
763
                        // we would return Foo inside IA which is not expected in this case
 
764
                        //
 
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);
 
771
                                                }
 
772
                                        }
 
773
                                }
 
774
                        }
 
775
 
 
776
                        return methods;
 
777
                }
 
778
 
 
779
                //
 
780
                // Returns all not implememted abstract members inside abstract type
 
781
                // NOTE: Returned list is shared and must not be modified
 
782
                //
 
783
                public static IList<MethodSpec> GetNotImplementedAbstractMethods (TypeSpec type)
 
784
                {
 
785
                        if (type.MemberCache.missing_abstract != null)
 
786
                                return type.MemberCache.missing_abstract;
 
787
                                
 
788
                        var abstract_methods = new List<MethodSpec> ();
 
789
                        List<TypeSpec> hierarchy = null;
 
790
 
 
791
                        //
 
792
                        // Stage 1: top-to-bottom scan for abstract members
 
793
                        //
 
794
                        var abstract_type = type;
 
795
                        while (true) {
 
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)
 
799
                                                        continue;
 
800
 
 
801
                                                if (name_entry.Kind != MemberKind.Method)
 
802
                                                        continue;
 
803
 
 
804
                                                abstract_methods.Add ((MethodSpec) name_entry);
 
805
                                        }
 
806
                                }
 
807
 
 
808
                                var base_type = abstract_type.BaseType;
 
809
                                if (!base_type.IsAbstract)
 
810
                                        break;
 
811
 
 
812
                                if (hierarchy == null)
 
813
                                        hierarchy = new List<TypeSpec> ();
 
814
 
 
815
                                hierarchy.Add (abstract_type);
 
816
                                abstract_type = base_type;
 
817
                        }
 
818
 
 
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;
 
823
                        }
 
824
 
 
825
                        //
 
826
                        // Stage 2: Remove already implemented methods
 
827
                        //
 
828
                        foreach (var type_up in hierarchy) {
 
829
                                var members = type_up.MemberCache.member_hash;
 
830
                                if (members.Count == 0)
 
831
                                        continue;
 
832
 
 
833
                                for (int i = 0; i < abstract_methods.Count; ++i) {
 
834
                                        var candidate = abstract_methods [i];
 
835
                                        if (candidate == null)
 
836
                                                continue;
 
837
 
 
838
                                        IList<MemberSpec> applicable;
 
839
                                        if (!members.TryGetValue (candidate.Name, out applicable))
 
840
                                                continue;
 
841
 
 
842
                                        var filter = new MemberFilter (candidate);
 
843
                                        foreach (var item in applicable) {
 
844
                                                if ((item.Modifiers & (Modifiers.OVERRIDE | Modifiers.VIRTUAL)) == 0)
 
845
                                                        continue;
 
846
 
 
847
                                                //
 
848
                                                // Abstract override does not override anything
 
849
                                                //
 
850
                                                if ((item.Modifiers & Modifiers.ABSTRACT) != 0)
 
851
                                                        continue;
 
852
 
 
853
                                                if (filter.Equals (item)) {
 
854
                                                        --not_implemented_count;
 
855
                                                        abstract_methods [i] = null;
 
856
                                                        break;
 
857
                                                }
 
858
                                        }
 
859
                                }
 
860
                        }
 
861
 
 
862
                        if (not_implemented_count == abstract_methods.Count) {
 
863
                                type.MemberCache.missing_abstract = abstract_methods;
 
864
                                return type.MemberCache.missing_abstract;
 
865
                        }
 
866
 
 
867
                        var not_implemented = new MethodSpec[not_implemented_count];
 
868
                        int counter = 0;
 
869
                        foreach (var m in abstract_methods) {
 
870
                                if (m == null)
 
871
                                        continue;
 
872
 
 
873
                                not_implemented[counter++] = m;
 
874
                        }
 
875
 
 
876
                        type.MemberCache.missing_abstract = not_implemented;
 
877
                        return type.MemberCache.missing_abstract;
 
878
                }
 
879
 
 
880
                static string GetLookupName (MemberSpec ms)
 
881
                {
 
882
                        if (ms.Kind == MemberKind.Indexer)
 
883
                                return IndexerNameAlias;
 
884
 
 
885
                        if (ms.Kind == MemberKind.Constructor) {
 
886
                                if (ms.IsStatic)
 
887
                                        return Constructor.TypeConstructorName;
 
888
 
 
889
                                return Constructor.ConstructorName;
 
890
                        }
 
891
 
 
892
                        return ms.Name;
 
893
                }
 
894
 
 
895
                static string GetLookupName (MemberCore mc)
 
896
                {
 
897
                        if (mc is Indexer)
 
898
                                return IndexerNameAlias;
 
899
 
 
900
                        if (mc is Constructor)
 
901
                                return mc.IsStatic ? Constructor.TypeConstructorName : Constructor.ConstructorName;
 
902
 
 
903
                        return mc.MemberName.Name;
 
904
                }
 
905
 
 
906
                //
 
907
                // Returns all operators declared on container and its base types (until declaredOnly is used)
 
908
                //
 
909
                public static IList<MemberSpec> GetUserOperator (TypeSpec container, Operator.OpType op, bool declaredOnly)
 
910
                {
 
911
                        IList<MemberSpec> found = null;
 
912
                        bool shared_list = true;
 
913
                        IList<MemberSpec> applicable;
 
914
                        do {
 
915
                                var mc = container.MemberCache;
 
916
 
 
917
                                if (((op == Operator.OpType.Implicit || op == Operator.OpType.Explicit) && (mc.state & StateFlags.HasConversionOperator) != 0) ||
 
918
                                         (mc.state & StateFlags.HasUserOperator) != 0) {
 
919
 
 
920
                                        if (mc.member_hash.TryGetValue (Operator.GetMetadataName (op), out applicable)) {
 
921
                                                int i;
 
922
                                                for (i = 0; i < applicable.Count; ++i) {
 
923
                                                        if (applicable[i].Kind != MemberKind.Operator) {
 
924
                                                                break;
 
925
                                                        }
 
926
                                                }
 
927
 
 
928
                                                //
 
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
 
931
                                                //
 
932
                                                if (i != applicable.Count) {
 
933
                                                        for (i = 0; i < applicable.Count; ++i) {
 
934
                                                                if (applicable[i].Kind != MemberKind.Operator) {
 
935
                                                                        continue;
 
936
                                                                }
 
937
 
 
938
                                                                if (found == null) {
 
939
                                                                        found = new List<MemberSpec> ();
 
940
                                                                        found.Add (applicable[i]);
 
941
                                                                } else {
 
942
                                                                        List<MemberSpec> prev;
 
943
                                                                        if (shared_list) {
 
944
                                                                                shared_list = false;
 
945
                                                                                prev = new List<MemberSpec> (found.Count + 1);
 
946
                                                                                prev.AddRange (found);
 
947
                                                                        } else {
 
948
                                                                                prev = (List<MemberSpec>) found;
 
949
                                                                        }
 
950
 
 
951
                                                                        prev.Add (applicable[i]);
 
952
                                                                }
 
953
                                                        }
 
954
                                                } else {
 
955
                                                        if (found == null) {
 
956
                                                                found = applicable;
 
957
                                                                shared_list = true;
 
958
                                                        } else {
 
959
                                                                List<MemberSpec> merged;
 
960
                                                                if (shared_list) {
 
961
                                                                        shared_list = false;
 
962
                                                                        merged = new List<MemberSpec> (found.Count + applicable.Count);
 
963
                                                                        merged.AddRange (found);
 
964
                                                                        found = merged;
 
965
                                                                } else {
 
966
                                                                        merged = (List<MemberSpec>) found;
 
967
                                                                }
 
968
 
 
969
                                                                merged.AddRange (applicable);
 
970
                                                        }
 
971
                                                }
 
972
                                        }
 
973
                                }
 
974
 
 
975
                                // BaseType call can be expensive
 
976
                                if (declaredOnly)
 
977
                                        break;
 
978
 
 
979
                                container = container.BaseType;
 
980
                        } while (container != null);
 
981
 
 
982
                        return found;
 
983
                }
 
984
 
 
985
                //
 
986
                // Inflates all member cache nested types
 
987
                //
 
988
                public void InflateTypes (MemberCache inflated_cache, TypeParameterInflator inflator)
 
989
                {
 
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];
 
994
 
 
995
                                        // FIXME: When inflating members refering nested types before they are inflated
 
996
                                        if (member == null)
 
997
                                                continue;
 
998
 
 
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);
 
1004
                                                }
 
1005
 
 
1006
                                                inflated_members [i] = member.InflateMember (inflator);
 
1007
                                        }
 
1008
                                }
 
1009
                        }
 
1010
                }
 
1011
 
 
1012
                //
 
1013
                // Inflates all open type members, requires InflateTypes to be called before
 
1014
                //
 
1015
                public void InflateMembers (MemberCache cacheToInflate, TypeSpec inflatedType, TypeParameterInflator inflator)
 
1016
                {
 
1017
                        var inflated_member_hash = cacheToInflate.member_hash;
 
1018
                        Dictionary<MemberSpec, MethodSpec> accessor_relation = null;
 
1019
                        List<MemberSpec> accessor_members = null;
 
1020
 
 
1021
                        // Copy member specific flags when all members were added
 
1022
                        cacheToInflate.state = state;
 
1023
 
 
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];
 
1029
 
 
1030
                                        //
 
1031
                                        // All nested types have been inflated earlier except for
 
1032
                                        // compiler types which are created later and could miss InflateTypes
 
1033
                                        //
 
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];
 
1038
 
 
1039
                                                continue;
 
1040
                                        }
 
1041
 
 
1042
                                        //
 
1043
                                        // Clone the container first
 
1044
                                        //
 
1045
                                        if (inflated_members == null) {
 
1046
                                                inflated_members = new MemberSpec [item.Value.Count];
 
1047
                                                inflated_member_hash.Add (item.Key, inflated_members);
 
1048
                                        }
 
1049
 
 
1050
                                        var local_inflator = inflator;
 
1051
 
 
1052
                                        if (member.DeclaringType != inflatedType) {
 
1053
                                                //
 
1054
                                                // Don't inflate top-level non-generic interface members
 
1055
                                                // merged into generic interface
 
1056
                                                //
 
1057
                                                if (!member.DeclaringType.IsGeneric && !member.DeclaringType.IsNested) {
 
1058
                                                        inflated_members [i] = member;
 
1059
                                                        continue;
 
1060
                                                }
 
1061
 
 
1062
                                                //
 
1063
                                                // Needed when inflating flatten interfaces. It inflates
 
1064
                                                // container type only, type parameters are already done
 
1065
                                                //
 
1066
                                                // Handles cases like:
 
1067
                                                //
 
1068
                                                // interface I<T> {}
 
1069
                                                // interface I<U, V> : I<U> {}
 
1070
                                                // 
 
1071
                                                // class C: I<int, bool> {}
 
1072
                                                //
 
1073
                                                var inflated_parent = inflator.Inflate (member.DeclaringType);
 
1074
                                                if (inflated_parent != inflator.TypeInstance)
 
1075
                                                        local_inflator = new TypeParameterInflator (inflator, inflated_parent);
 
1076
                                        }
 
1077
 
 
1078
                                        //
 
1079
                                        // Inflate every member, its parent is now different
 
1080
                                        //
 
1081
                                        var inflated = member.InflateMember (local_inflator);
 
1082
                                        inflated_members [i] = inflated;
 
1083
 
 
1084
                                        if (member is PropertySpec || member is EventSpec) {
 
1085
                                                if (accessor_members == null)
 
1086
                                                        accessor_members = new List<MemberSpec> ();
 
1087
 
 
1088
                                                accessor_members.Add (inflated);
 
1089
                                                continue;
 
1090
                                        }
 
1091
 
 
1092
                                        if (member.IsAccessor) {
 
1093
                                                if (accessor_relation == null)
 
1094
                                                        accessor_relation = new Dictionary<MemberSpec, MethodSpec> ();
 
1095
                                                accessor_relation.Add (member, (MethodSpec) inflated);
 
1096
                                        }
 
1097
                                }
 
1098
                        }
 
1099
 
 
1100
                        if (accessor_members != null) {
 
1101
                                foreach (var member in accessor_members) {
 
1102
                                        var prop = member as PropertySpec;
 
1103
                                        if (prop != null) {
 
1104
                                                if (prop.Get != null)
 
1105
                                                        prop.Get = accessor_relation[prop.Get];
 
1106
                                                if (prop.Set != null)
 
1107
                                                        prop.Set = accessor_relation[prop.Set];
 
1108
 
 
1109
                                                continue;
 
1110
                                        }
 
1111
 
 
1112
                                        var ev = (EventSpec) member;
 
1113
                                        ev.AccessorAdd = accessor_relation[ev.AccessorAdd];
 
1114
                                        ev.AccessorRemove = accessor_relation[ev.AccessorRemove];
 
1115
                                }
 
1116
                        }
 
1117
                }
 
1118
 
 
1119
                //
 
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
 
1126
                //
 
1127
                public void RemoveHiddenMembers (TypeSpec container)
 
1128
                {
 
1129
                        foreach (var entry in member_hash) {
 
1130
                                var values = entry.Value;
 
1131
 
 
1132
                                int container_members_start_at = 0;
 
1133
                                while (values[container_members_start_at].DeclaringType != container && ++container_members_start_at < entry.Value.Count);
 
1134
 
 
1135
                                if (container_members_start_at == 0 || container_members_start_at == values.Count)
 
1136
                                        continue;
 
1137
 
 
1138
                                for (int i = 0; i < container_members_start_at; ++i) {
 
1139
                                        var member = values[i];
 
1140
 
 
1141
                                        if (!container.ImplementsInterface (member.DeclaringType, false))
 
1142
                                                continue;
 
1143
 
 
1144
                                        var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : ParametersCompiled.EmptyReadOnlyParameters;
 
1145
 
 
1146
                                        for (int ii = container_members_start_at; ii < values.Count; ++ii) {
 
1147
                                                var container_entry = values[ii];
 
1148
 
 
1149
                                                if (container_entry.Arity != member.Arity)
 
1150
                                                        continue;
 
1151
 
 
1152
                                                if (container_entry is IParametersMember) {
 
1153
                                                        if (!TypeSpecComparer.Override.IsEqual (((IParametersMember) container_entry).Parameters, member_param))
 
1154
                                                                continue;
 
1155
                                                }
 
1156
 
 
1157
                                                values.RemoveAt (i);
 
1158
                                                --container_members_start_at;
 
1159
                                                --ii;
 
1160
                                                --i;
 
1161
                                        }
 
1162
                                }
 
1163
                        }
 
1164
                }
 
1165
 
 
1166
                //
 
1167
                // Checks all appropriate container members for CLS compliance
 
1168
                //
 
1169
                public void VerifyClsCompliance (TypeSpec container, Report report)
 
1170
                {
 
1171
                        if (locase_members != null)
 
1172
                                return;
 
1173
 
 
1174
                        if (container.BaseType == null) {
 
1175
                                locase_members = new Dictionary<string, MemberSpec[]> (member_hash.Count); // StringComparer.OrdinalIgnoreCase);
 
1176
                        } else {
 
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);
 
1180
                        }
 
1181
 
 
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)
 
1187
                                                continue;
 
1188
 
 
1189
                                        if ((name_entry.Modifiers & (Modifiers.OVERRIDE | Modifiers.COMPILER_GENERATED)) != 0)
 
1190
                                                continue;
 
1191
 
 
1192
                                        if ((name_entry.Kind & MemberKind.MaskType) == 0)
 
1193
                                                continue;
 
1194
 
 
1195
                                        if (name_entry.MemberDefinition.CLSAttributeValue == false)
 
1196
                                            continue;
 
1197
 
 
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;
 
1203
                                                        //
 
1204
                                                        // Check differing overloads in @container
 
1205
                                                        //
 
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;
 
1209
                                                                if (p_b == null)
 
1210
                                                                        continue;
 
1211
 
 
1212
                                                                if (p_a_pd.Count != p_b.Parameters.Count)
 
1213
                                                                        continue;
 
1214
 
 
1215
                                                                if (checked_entry.IsAccessor)
 
1216
                                                                        continue;
 
1217
 
 
1218
                                                                var res = ParametersCompiled.IsSameClsSignature (p_a.Parameters, p_b.Parameters);
 
1219
                                                                if (res != 0) {
 
1220
                                                                        ReportOverloadedMethodClsDifference (name_entry, checked_entry, res, report);
 
1221
                                                                }
 
1222
                                                        }
 
1223
                                                }
 
1224
                                        }
 
1225
 
 
1226
                                        if (i > 0 || name_entry.Kind == MemberKind.Constructor || name_entry.Kind == MemberKind.Indexer)
 
1227
                                                continue;
 
1228
 
 
1229
                                        var name_entry_locase = name_entry.Name.ToLowerInvariant ();
 
1230
 
 
1231
                                        MemberSpec[] found;
 
1232
                                        if (!locase_members.TryGetValue (name_entry_locase, out found)) {
 
1233
                                                found = new MemberSpec[] { name_entry };
 
1234
                                                locase_members.Add (name_entry_locase, found);
 
1235
                                        } else {
 
1236
                                                bool same_names_only = true;
 
1237
                                                foreach (var f in found) {
 
1238
                                                        if (f.Name == name_entry.Name) {
 
1239
                                                                if (p_a != null) {
 
1240
                                                                        IParametersMember p_b = f as IParametersMember;
 
1241
                                                                        if (p_b == null)
 
1242
                                                                                continue;
 
1243
 
 
1244
                                                                        if (p_a.Parameters.Count != p_b.Parameters.Count)
 
1245
                                                                                continue;
 
1246
 
 
1247
                                                                        if (f.IsAccessor)
 
1248
                                                                                continue;
 
1249
 
 
1250
                                                                        var res = ParametersCompiled.IsSameClsSignature (p_a.Parameters, p_b.Parameters);
 
1251
                                                                        if (res != 0) {
 
1252
                                                                                ReportOverloadedMethodClsDifference (f, name_entry, res, report);
 
1253
                                                                        }
 
1254
                                                                }
 
1255
 
 
1256
                                                                continue;
 
1257
                                                        }
 
1258
 
 
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);
 
1264
                                                                } else {
 
1265
                                                                        report.SymbolRelatedToPreviousError (f);
 
1266
                                                                }
 
1267
 
 
1268
                                                                report.Warning (3005, 1, last.Location,
 
1269
                                                                        "Identifier `{0}' differing only in case is not CLS-compliant", last.GetSignatureForError ());
 
1270
                                                        }
 
1271
                                                }
 
1272
 
 
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;
 
1277
                                                }
 
1278
                                        }
 
1279
                                }
 
1280
                        }
 
1281
                }
 
1282
 
 
1283
                //
 
1284
                // Local report helper to issue correctly ordered members stored in hashtable
 
1285
                //
 
1286
                static MemberCore GetLaterDefinedMember (MemberSpec a, MemberSpec b)
 
1287
                {
 
1288
                        var mc_a = a.MemberDefinition as MemberCore;
 
1289
                        var mc_b = b.MemberDefinition as MemberCore;
 
1290
                        if (mc_a == null)
 
1291
                                return mc_b;
 
1292
 
 
1293
                        if (mc_b == null)
 
1294
                                return mc_a;
 
1295
 
 
1296
                        if (a.DeclaringType.MemberDefinition != b.DeclaringType.MemberDefinition)
 
1297
                                return mc_b;
 
1298
 
 
1299
                        if (mc_a.Location.File != mc_a.Location.File)
 
1300
                                return mc_b;
 
1301
 
 
1302
                        return mc_b.Location.Row > mc_a.Location.Row ? mc_b : mc_a;
 
1303
                }
 
1304
 
 
1305
                static void ReportOverloadedMethodClsDifference (MemberSpec a, MemberSpec b, int res, Report report)
 
1306
                {
 
1307
                        var last = GetLaterDefinedMember (a, b);
 
1308
                        if (last == a.MemberDefinition) {
 
1309
                                report.SymbolRelatedToPreviousError (b);
 
1310
                        } else {
 
1311
                                report.SymbolRelatedToPreviousError (a);
 
1312
                        }
 
1313
 
 
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 ());
 
1318
                        }
 
1319
 
 
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 ());
 
1324
                        }
 
1325
                }
 
1326
 
 
1327
                public bool CheckExistingMembersOverloads (MemberCore member, AParametersCollection parameters)
 
1328
                {
 
1329
                        var name = GetLookupName (member);
 
1330
                        var imb = member as InterfaceMemberBase;
 
1331
                        if (imb != null && imb.IsExplicitImpl) {
 
1332
                                name = imb.GetFullName (name);
 
1333
                        }
 
1334
 
 
1335
                        return CheckExistingMembersOverloads (member, name, parameters);
 
1336
                }
 
1337
 
 
1338
                public bool CheckExistingMembersOverloads (MemberCore member, string name, AParametersCollection parameters)
 
1339
                {
 
1340
                        IList<MemberSpec> entries;
 
1341
                        if (!member_hash.TryGetValue (name, out entries))
 
1342
                                return false;
 
1343
 
 
1344
                        var Report = member.Compiler.Report;
 
1345
 
 
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)
 
1352
                                        continue;
 
1353
 
 
1354
                                if (ce.Arity != member.MemberName.Arity)
 
1355
                                        continue;
 
1356
 
 
1357
                                // Ignore merged interface members
 
1358
                                if (member.Parent.PartialContainer != ce.DeclaringType.MemberDefinition)
 
1359
                                        continue;
 
1360
 
 
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;
 
1365
                                        do {
 
1366
                                                type_a = parameters.Types [ii];
 
1367
                                                type_b = p_types [ii];
 
1368
 
 
1369
                                                var a_byref = (pd.FixedParameters[ii].ModFlags & Parameter.Modifier.RefOutMask) != 0;
 
1370
                                                var b_byref = (parameters.FixedParameters[ii].ModFlags & Parameter.Modifier.RefOutMask) != 0;
 
1371
 
 
1372
                                                if (a_byref != b_byref)
 
1373
                                                        break;
 
1374
 
 
1375
                                        } while (TypeSpecComparer.Override.IsEqual (type_a, type_b) && ii-- != 0);
 
1376
 
 
1377
                                        if (ii >= 0)
 
1378
                                                continue;
 
1379
 
 
1380
                                        //
 
1381
                                        // Operators can differ in return type only
 
1382
                                        //
 
1383
                                        if (member is Operator && ce.Kind == MemberKind.Operator && ((MethodSpec) ce).ReturnType != ((Operator) member).ReturnType)
 
1384
                                                continue;
 
1385
 
 
1386
                                        //
 
1387
                                        // Report difference in parameter modifiers only
 
1388
                                        //
 
1389
                                        if (pd != null && member is MethodCore) {
 
1390
                                                ii = method_param_count;
 
1391
                                                while (ii-- != 0 &&
 
1392
                                                        (parameters.FixedParameters[ii].ModFlags & Parameter.Modifier.ModifierMask) ==
 
1393
                                                        (pd.FixedParameters[ii].ModFlags & Parameter.Modifier.ModifierMask) &&
 
1394
                                                        parameters.ExtensionMethodType == pd.ExtensionMethodType) ;
 
1395
 
 
1396
                                                if (ii >= 0) {
 
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");
 
1403
                                                                } else {
 
1404
                                                                        Report.Error (755, member.Location,
 
1405
                                                                                "A partial method declaration and partial method implementation must be both an extension method or neither");
 
1406
                                                                }
 
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 ());
 
1411
                                                        } else {
 
1412
                                                                Report.Error (663, member.Location,
 
1413
                                                                        "Overloaded method `{0}' cannot differ on use of parameter modifiers only",
 
1414
                                                                        member.GetSignatureForError ());
 
1415
                                                        }
 
1416
                                                        return false;
 
1417
                                                }
 
1418
                                        }
 
1419
                                }
 
1420
 
 
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);
 
1433
                                                                        else
 
1434
                                                                                entries.RemoveAt (i);
 
1435
                                                                } else {
 
1436
                                                                        method_b.SetPartialDefinition (method_a);
 
1437
                                                                        method_a.caching_flags |= MemberCore.Flags.PartialDefinitionExists;
 
1438
                                                                }
 
1439
                                                                continue;
 
1440
                                                        }
 
1441
 
 
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");
 
1446
                                                        }
 
1447
 
 
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");
 
1451
                                                        return false;
 
1452
                                                }
 
1453
 
 
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 ());
 
1458
                                                }
 
1459
 
 
1460
                                                Report.Error (757, member.Location, "A partial method `{0}' implementation is already defined",
 
1461
                                                        member.GetSignatureForError ());
 
1462
                                                return false;
 
1463
                                        }
 
1464
 
 
1465
                                        Report.SymbolRelatedToPreviousError (ce);
 
1466
 
 
1467
                                        bool is_reserved_a = member is AbstractPropertyEventMethod || member is Operator;
 
1468
                                        bool is_reserved_b = ((MethodSpec) ce).IsReservedMethod;
 
1469
 
 
1470
                                        if (is_reserved_a || is_reserved_b) {
 
1471
                                                Report.Error (82, member.Location, "A member `{0}' is already reserved",
 
1472
                                                        is_reserved_a ?
 
1473
                                                        ce.GetSignatureForError () :
 
1474
                                                        member.GetSignatureForError ());
 
1475
                                                return false;
 
1476
                                        }
 
1477
                                } else {
 
1478
                                        Report.SymbolRelatedToPreviousError (ce);
 
1479
                                }
 
1480
 
 
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 ());
 
1484
                                        return false;
 
1485
                                }
 
1486
 
 
1487
                                Report.Error (111, member.Location,
 
1488
                                        "A member `{0}' is already defined. Rename this member or use different parameter types",
 
1489
                                        member.GetSignatureForError ());
 
1490
                                return false;
 
1491
                        }
 
1492
 
 
1493
                        return true;
 
1494
                }
 
1495
        }
 
1496
}