~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/mcs/membercache.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+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
//
 
12
//
 
13
 
 
14
using System;
 
15
using System.Collections.Generic;
 
16
 
 
17
namespace Mono.CSharp {
 
18
 
 
19
        [Flags]
 
20
        public enum MemberKind
 
21
        {
 
22
                Constructor = 1,
 
23
                Event = 1 << 1,
 
24
                Field = 1 << 2,
 
25
                Method = 1 << 3,
 
26
                Property = 1 << 4,
 
27
                Indexer = 1 << 5,
 
28
                Operator = 1 << 6,
 
29
                Destructor      = 1 << 7,
 
30
 
 
31
                Class           = 1 << 11,
 
32
                Struct          = 1 << 12,
 
33
                Delegate        = 1 << 13,
 
34
                Enum            = 1 << 14,
 
35
                Interface       = 1 << 15,
 
36
                TypeParameter = 1 << 16,
 
37
 
 
38
                ArrayType = 1 << 19,
 
39
                PointerType = 1 << 20,
 
40
                InternalCompilerType = 1 << 21,
 
41
                MissingType = 1 << 22,
 
42
                Void = 1 << 23,
 
43
 
 
44
                NestedMask = Class | Struct | Delegate | Enum | Interface,
 
45
                GenericMask = Method | Class | Struct | Delegate | Interface,
 
46
                MaskType = Constructor | Event | Field | Method | Property | Indexer | Operator | Destructor | NestedMask
 
47
        }
 
48
 
 
49
        [Flags]
 
50
        public enum BindingRestriction
 
51
        {
 
52
                None = 0,
 
53
 
 
54
                // Inspect only queried type members
 
55
                DeclaredOnly = 1 << 1,
 
56
 
 
57
                // Exclude static
 
58
                InstanceOnly = 1 << 2,
 
59
 
 
60
                NoAccessors = 1 << 3,
 
61
 
 
62
                // Member has to be override
 
63
                OverrideOnly = 1 << 4
 
64
        }
 
65
 
 
66
        public struct MemberFilter : IEquatable<MemberSpec>
 
67
        {
 
68
                public readonly string Name;
 
69
                public readonly MemberKind Kind;
 
70
                public readonly AParametersCollection Parameters;
 
71
                public readonly TypeSpec MemberType;
 
72
                public readonly int Arity; // -1 to ignore the check
 
73
 
 
74
                private MemberFilter (string name, MemberKind kind)
 
75
                {
 
76
                        Name = name;
 
77
                        Kind = kind;
 
78
                        Parameters = null;
 
79
                        MemberType = null;
 
80
                        Arity = -1;
 
81
                }
 
82
 
 
83
                public MemberFilter (MethodSpec m)
 
84
                {
 
85
                        Name = m.Name;
 
86
                        Kind = MemberKind.Method;
 
87
                        Parameters = m.Parameters;
 
88
                        MemberType = m.ReturnType;
 
89
                        Arity = m.Arity;
 
90
                }
 
91
 
 
92
                public MemberFilter (string name, int arity, MemberKind kind, AParametersCollection param, TypeSpec type)
 
93
                {
 
94
                        Name = name;
 
95
                        Kind = kind;
 
96
                        Parameters = param;
 
97
                        MemberType = type;
 
98
                        this.Arity = arity;
 
99
                }
 
100
 
 
101
                public static MemberFilter Constructor (AParametersCollection param)
 
102
                {
 
103
                        return new MemberFilter (Mono.CSharp.Constructor.ConstructorName, 0, MemberKind.Constructor, param, null);
 
104
                }
 
105
 
 
106
                public static MemberFilter Property (string name, TypeSpec type)
 
107
                {
 
108
                        return new MemberFilter (name, 0, MemberKind.Property, null, type);
 
109
                }
 
110
 
 
111
                public static MemberFilter Field (string name, TypeSpec type)
 
112
                {
 
113
                        return new MemberFilter (name, 0, MemberKind.Field, null, type);
 
114
                }
 
115
 
 
116
                public static MemberFilter Method (string name, int arity, AParametersCollection param, TypeSpec type)
 
117
                {
 
118
                        return new MemberFilter (name, arity, MemberKind.Method, param, type);
 
119
                }
 
120
 
 
121
                #region IEquatable<MemberSpec> Members
 
122
 
 
123
                public bool Equals (MemberSpec other)
 
124
                {
 
125
                        // Is the member of the correct type ?
 
126
                        // TODO: Isn't this redundant ?
 
127
                        if ((other.Kind & Kind & MemberKind.MaskType) == 0)
 
128
                                return false;
 
129
 
 
130
                        // Check arity when not disabled
 
131
                        if (Arity >= 0 && Arity != other.Arity)
 
132
                                return false;
 
133
 
 
134
                        if (Parameters != null) {
 
135
                                if (other is IParametersMember) {
 
136
                                        var other_param = ((IParametersMember) other).Parameters;
 
137
                                        if (!TypeSpecComparer.Override.IsEqual (Parameters, other_param))
 
138
                                                return false;
 
139
                                } else {
 
140
                                        return false;
 
141
                                }
 
142
                        }
 
143
 
 
144
                        if (MemberType != null) {
 
145
                                if (other is IInterfaceMemberSpec) {
 
146
                                        var other_type = ((IInterfaceMemberSpec) other).MemberType;
 
147
                                        if (!TypeSpecComparer.Override.IsEqual (other_type, MemberType))
 
148
                                                return false;
 
149
                                } else {
 
150
                                        return false;
 
151
                                }
 
152
                        }
 
153
 
 
154
                        return true;
 
155
                }
 
156
 
 
157
                #endregion
 
158
        }
 
159
 
 
160
        //
 
161
        // The MemberCache is the main members container used by compiler. It contains
 
162
        // all members imported or defined during compilation using on demand filling
 
163
        // process. Inflated containers are also using MemberCache to make inflated
 
164
        // members look like normal definition.
 
165
        //
 
166
        // All of the methods are performance and memory sensitive as the MemberCache
 
167
        // is the underlying engine of all member based operations.
 
168
        //
 
169
        public class MemberCache
 
170
        {
 
171
                [Flags]
 
172
                enum StateFlags
 
173
                {
 
174
                        HasConversionOperator = 1 << 1,
 
175
                        HasUserOperator = 1 << 2
 
176
                }
 
177
 
 
178
                readonly Dictionary<string, IList<MemberSpec>> member_hash;
 
179
                Dictionary<string, MemberSpec[]> locase_members;
 
180
                IList<MethodSpec> missing_abstract;
 
181
                StateFlags state;       // TODO: Move to TypeSpec or ITypeDefinition
 
182
 
 
183
                public static readonly string IndexerNameAlias = "<this>";
 
184
 
 
185
                public static readonly MemberCache Empty = new MemberCache (0);
 
186
 
 
187
                public MemberCache ()
 
188
                        : this (16)
 
189
                {
 
190
                }
 
191
 
 
192
                public MemberCache (int capacity)
 
193
                {
 
194
                        member_hash = new Dictionary<string, IList<MemberSpec>> (capacity);
 
195
                }
 
196
 
 
197
                public MemberCache (MemberCache cache)
 
198
                        : this (cache.member_hash.Count)
 
199
                {
 
200
                        this.state = cache.state;
 
201
                }
 
202
 
 
203
                //
 
204
                // Creates a new MemberCache for the given `container'.
 
205
                //
 
206
                public MemberCache (TypeContainer container)
 
207
                        : this ()                               // TODO: Optimize the size
 
208
                {
 
209
                }
 
210
 
 
211
                //
 
212
                // For cases where we need to union cache members
 
213
                //
 
214
                public void AddBaseType (TypeSpec baseType)
 
215
                {
 
216
                        var cache = baseType.MemberCache;
 
217
 
 
218
                        IList<MemberSpec> list;
 
219
                        foreach (var entry in cache.member_hash) {
 
220
                                if (!member_hash.TryGetValue (entry.Key, out list)) {
 
221
                                        if (entry.Value.Count == 1) {
 
222
                                                list = entry.Value;
 
223
                                        } else {
 
224
                                                list = new List<MemberSpec> (entry.Value);
 
225
                                        }
 
226
 
 
227
                                        member_hash.Add (entry.Key, list);
 
228
                                        continue;
 
229
                                }
 
230
 
 
231
                                foreach (var ce in entry.Value) {
 
232
                                        if (list.Contains (ce))
 
233
                                                continue;
 
234
 
 
235
                                        if (list is MemberSpec[]) {
 
236
                                                list = new List<MemberSpec> () { list [0] };
 
237
                                                member_hash[entry.Key] = list;
 
238
                                        }
 
239
 
 
240
                                        list.Add (ce);
 
241
                                }
 
242
                        }
 
243
                }
 
244
 
 
245
                //
 
246
                // Member-cache does not contain base members but it does
 
247
                // contain all base interface members, so the Lookup code
 
248
                // can use simple inheritance rules.
 
249
                //
 
250
                public void AddInterface (TypeSpec iface)
 
251
                {
 
252
                        var cache = iface.MemberCache;
 
253
 
 
254
                        IList<MemberSpec> list;
 
255
                        foreach (var entry in cache.member_hash) {
 
256
                                if (!member_hash.TryGetValue (entry.Key, out list)) {
 
257
                                        if (entry.Value.Count == 1) {
 
258
                                                list = entry.Value;
 
259
                                        } else {
 
260
                                                list = new List<MemberSpec> (entry.Value);
 
261
                                        }
 
262
 
 
263
                                        member_hash.Add (entry.Key, list);
 
264
                                        continue;
 
265
                                }
 
266
 
 
267
                                foreach (var ce in entry.Value) {
 
268
                                        if (list.Contains (ce))
 
269
                                                continue;
 
270
 
 
271
                                        if (AddInterfaceMember (ce, ref list))
 
272
                                                member_hash[entry.Key] = list;
 
273
                                }
 
274
                        }
 
275
 
 
276
                        // Add also all base interfaces
 
277
                        if (iface.Interfaces != null) {
 
278
                                foreach (var base_iface in iface.Interfaces)
 
279
                                        AddInterface (base_iface);
 
280
                        }
 
281
                }
 
282
 
 
283
                public void AddMember (InterfaceMemberBase imb, string exlicitName, MemberSpec ms)
 
284
                {
 
285
                        // Explicit names cannot be looked-up but can be used for
 
286
                        // collision checking (no name mangling needed)
 
287
                        if (imb.IsExplicitImpl)
 
288
                                AddMember (exlicitName, ms, false);
 
289
                        else
 
290
                                AddMember (ms);
 
291
                }
 
292
 
 
293
                //
 
294
                // Add non-explicit member to member cache
 
295
                //
 
296
                public void AddMember (MemberSpec ms)
 
297
                {
 
298
                        AddMember (GetLookupName (ms), ms, false);
 
299
                }
 
300
 
 
301
                void AddMember (string name, MemberSpec member, bool removeHiddenMembers)
 
302
                {
 
303
                        if (member.Kind == MemberKind.Operator) {
 
304
                                var dt = member.DeclaringType;
 
305
                                switch (dt.BuiltinType) {
 
306
                                case BuiltinTypeSpec.Type.String:
 
307
                                case BuiltinTypeSpec.Type.Delegate:
 
308
                                case BuiltinTypeSpec.Type.MulticastDelegate:
 
309
                                        // Some core types have user operators but they cannot be used as normal
 
310
                                        // user operators as they are predefined and therefore having different
 
311
                                        // rules (e.g. binary operators) by not setting the flag we hide them for
 
312
                                        // user conversions
 
313
                                        // TODO: Should I do this for all core types ?
 
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
                        IList<MemberSpec> list;
 
327
                        if (!member_hash.TryGetValue (name, out list)) {
 
328
                                member_hash.Add (name, new MemberSpec[] { member });
 
329
                                return;
 
330
                        }
 
331
 
 
332
                        if (removeHiddenMembers && member.DeclaringType.IsInterface) {
 
333
                                if (AddInterfaceMember (member, ref list))
 
334
                                        member_hash[name] = list;
 
335
                        } else {
 
336
                                if (list.Count == 1) {
 
337
                                        list = new List<MemberSpec> () { list[0] };
 
338
                                        member_hash[name] = list;
 
339
                                }
 
340
 
 
341
                                list.Add (member);
 
342
                        }
 
343
                }
 
344
 
 
345
                public void AddMemberImported (MemberSpec ms)
 
346
                {
 
347
                        AddMember (GetLookupName (ms), ms, true);
 
348
                }
 
349
 
 
350
                //
 
351
                // Ignores any base interface member which can be hidden
 
352
                // by this interface
 
353
                //
 
354
                static bool AddInterfaceMember (MemberSpec member, ref IList<MemberSpec> existing)
 
355
                {
 
356
                        var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : ParametersCompiled.EmptyReadOnlyParameters;
 
357
 
 
358
                        //
 
359
                        // interface IA : IB { int Prop { set; } }
 
360
                        // interface IB { bool Prop { get; } }
 
361
                        //
 
362
                        // IB.Prop is never accessible from IA interface
 
363
                        //
 
364
                        for (int i = 0; i < existing.Count; ++i) {
 
365
                                var entry = existing[i];
 
366
 
 
367
                                if (entry.Arity != member.Arity)
 
368
                                        continue;
 
369
 
 
370
                                if (entry is IParametersMember) {
 
371
                                        var entry_param = ((IParametersMember) entry).Parameters;
 
372
                                        if (!TypeSpecComparer.Override.IsEqual (entry_param, member_param))
 
373
                                                continue;
 
374
                                }
 
375
 
 
376
                                if (member.DeclaringType.ImplementsInterface (entry.DeclaringType, false)) {
 
377
                                        if (existing.Count == 1) {
 
378
                                                existing = new MemberSpec[] { member };
 
379
                                                return true;
 
380
                                        }
 
381
 
 
382
                                        existing.RemoveAt (i--);
 
383
                                        continue;
 
384
                                }
 
385
 
 
386
                                if ((entry.DeclaringType == member.DeclaringType && entry.IsAccessor == member.IsAccessor) ||
 
387
                                        entry.DeclaringType.ImplementsInterface (member.DeclaringType, false))
 
388
                                        return false;
 
389
                        }
 
390
 
 
391
                        if (existing.Count == 1) {
 
392
                                existing = new List<MemberSpec> () { existing[0], member };
 
393
                                return true;
 
394
                        }
 
395
 
 
396
                        existing.Add (member);
 
397
                        return false;
 
398
                }
 
399
 
 
400
                public static MemberSpec FindMember (TypeSpec container, MemberFilter filter, BindingRestriction restrictions)
 
401
                {
 
402
                        do {
 
403
                                IList<MemberSpec> applicable;
 
404
                                if (container.MemberCache.member_hash.TryGetValue (filter.Name, out applicable)) {
 
405
                                        // Start from the end because interface members are in reverse order
 
406
                                        for (int i = applicable.Count - 1; i >= 0; i--) {
 
407
                                                var entry = applicable [i];
 
408
 
 
409
                                                if ((restrictions & BindingRestriction.InstanceOnly) != 0 && entry.IsStatic)
 
410
                                                        continue;
 
411
 
 
412
                                                if ((restrictions & BindingRestriction.NoAccessors) != 0 && entry.IsAccessor)
 
413
                                                        continue;
 
414
 
 
415
                                                if ((restrictions & BindingRestriction.OverrideOnly) != 0 && (entry.Modifiers & Modifiers.OVERRIDE) == 0)
 
416
                                                        continue;
 
417
 
 
418
                                                if (!filter.Equals (entry))
 
419
                                                        continue;
 
420
 
 
421
                                                if ((restrictions & BindingRestriction.DeclaredOnly) != 0 && container.IsInterface && entry.DeclaringType != container)
 
422
                                                        continue;
 
423
 
 
424
                                                return entry;
 
425
                                        }
 
426
                                }
 
427
 
 
428
                                if ((restrictions & BindingRestriction.DeclaredOnly) != 0)
 
429
                                        break;
 
430
 
 
431
                                container = container.BaseType;
 
432
                        } while (container != null);
 
433
 
 
434
                        return null;
 
435
                }
 
436
 
 
437
                //
 
438
                // A special method to work with member lookup only. It returns a list of all members named @name
 
439
                // starting from @container. It's very performance sensitive
 
440
                //
 
441
                public static IList<MemberSpec> FindMembers (TypeSpec container, string name, bool declaredOnly)
 
442
                {
 
443
                        IList<MemberSpec> applicable;
 
444
 
 
445
                        do {
 
446
                                if (container.MemberCache.member_hash.TryGetValue (name, out applicable) || declaredOnly)
 
447
                                        return applicable;
 
448
 
 
449
                                container = container.BaseType;
 
450
                        } while (container != null);
 
451
 
 
452
                        return null;
 
453
                }
 
454
 
 
455
                //
 
456
                // Finds the nested type in container
 
457
                //
 
458
                public static TypeSpec FindNestedType (TypeSpec container, string name, int arity)
 
459
                {
 
460
                        IList<MemberSpec> applicable;
 
461
                        TypeSpec best_match = null;
 
462
                        do {
 
463
                                // TODO: Don't know how to handle this yet
 
464
                                // When resolving base type of nested type, parent type must have
 
465
                                // base type resolved to scan full hierarchy correctly
 
466
                                // Similarly MemberCacheTypes will inflate BaseType and Interfaces
 
467
                                // based on type definition
 
468
                                var tc = container.MemberDefinition as TypeContainer;
 
469
                                if (tc != null)
 
470
                                        tc.DefineType ();
 
471
 
 
472
                                if (container.MemberCacheTypes.member_hash.TryGetValue (name, out applicable)) {
 
473
                                        for (int i = applicable.Count - 1; i >= 0; i--) {
 
474
                                                var entry = applicable[i];
 
475
                                                if ((entry.Kind & MemberKind.NestedMask) == 0)
 
476
                                                        continue;
 
477
 
 
478
                                                var ts = (TypeSpec) entry;
 
479
                                                if (arity == ts.Arity)
 
480
                                                        return ts;
 
481
 
 
482
                                                if (arity < 0) {
 
483
                                                        if (best_match == null) {
 
484
                                                                best_match = ts;
 
485
                                                        } else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (ts.Arity + arity)) {
 
486
                                                                best_match = ts;
 
487
                                                        }
 
488
                                                }
 
489
                                        }
 
490
                                }
 
491
 
 
492
                                container = container.BaseType;
 
493
                        } while (container != null);
 
494
 
 
495
                        return best_match;
 
496
                }
 
497
 
 
498
                //
 
499
                // Looks for extension methods with defined name and extension type
 
500
                //
 
501
                public List<MethodSpec> FindExtensionMethods (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity)
 
502
                {
 
503
                        IList<MemberSpec> entries;
 
504
                        if (!member_hash.TryGetValue (name, out entries))
 
505
                                return null;
 
506
 
 
507
                        List<MethodSpec> candidates = null;
 
508
                        foreach (var entry in entries) {
 
509
                                if (entry.Kind != MemberKind.Method || (arity > 0 && entry.Arity != arity))
 
510
                                        continue;
 
511
 
 
512
                                var ms = (MethodSpec) entry;
 
513
                                if (!ms.IsExtensionMethod)
 
514
                                        continue;
 
515
 
 
516
                                if (!ms.IsAccessible (invocationContext))
 
517
                                        continue;
 
518
 
 
519
                                //
 
520
                                // Extension methods cannot be nested hence checking parent is enough
 
521
                                //
 
522
                                if ((ms.DeclaringType.Modifiers & Modifiers.INTERNAL) != 0 && !ms.DeclaringType.MemberDefinition.IsInternalAsPublic (invocationContext.Module.DeclaringAssembly))
 
523
                                        continue;
 
524
 
 
525
                                if (candidates == null)
 
526
                                        candidates = new List<MethodSpec> ();
 
527
                                candidates.Add (ms);
 
528
                        }
 
529
 
 
530
                        return candidates;
 
531
                }
 
532
 
 
533
                //
 
534
                // Returns base members of @member member if no exact match is found @bestCandidate returns
 
535
                // the best match
 
536
                //
 
537
                public static MemberSpec FindBaseMember (MemberCore member, out MemberSpec bestCandidate, ref bool overrides)
 
538
                {
 
539
                        bestCandidate = null;
 
540
                        var container = member.Parent.PartialContainer.Definition;
 
541
                        if (!container.IsInterface) {
 
542
                                container = container.BaseType;
 
543
 
 
544
                                // It can happen for a user definition of System.Object
 
545
                                if (container == null)
 
546
                                        return null;
 
547
                        }
 
548
 
 
549
                        string name = GetLookupName (member);
 
550
                        var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : null;
 
551
 
 
552
                        var mkind = GetMemberCoreKind (member);
 
553
                        bool member_with_accessors = mkind == MemberKind.Indexer || mkind == MemberKind.Property;
 
554
 
 
555
                        IList<MemberSpec> applicable;
 
556
                        MemberSpec ambig_candidate = null;
 
557
 
 
558
                        do {
 
559
                                if (container.MemberCache.member_hash.TryGetValue (name, out applicable)) {
 
560
                                        for (int i = 0; i < applicable.Count; ++i) {
 
561
                                                var entry = applicable [i];
 
562
 
 
563
                                                if ((entry.Modifiers & Modifiers.PRIVATE) != 0)
 
564
                                                        continue;
 
565
 
 
566
                                                if ((entry.Modifiers & Modifiers.AccessibilityMask) == Modifiers.INTERNAL &&
 
567
                                                        !entry.DeclaringType.MemberDefinition.IsInternalAsPublic (member.Module.DeclaringAssembly))
 
568
                                                        continue;
 
569
 
 
570
                                                //
 
571
                                                // Isn't the member of same kind ?
 
572
                                                //
 
573
                                                if ((entry.Kind & ~MemberKind.Destructor & mkind & MemberKind.MaskType) == 0) {
 
574
                                                        // Destructors are ignored as they cannot be overridden by user
 
575
                                                        if ((entry.Kind & MemberKind.Destructor) != 0)
 
576
                                                                continue;
 
577
 
 
578
                                                        // A method with different arity does not hide base member
 
579
                                                        if (mkind != MemberKind.Method && member.MemberName.Arity != entry.Arity)
 
580
                                                                continue;
 
581
 
 
582
                                                        bestCandidate = entry;
 
583
                                                        return null;
 
584
                                                }
 
585
 
 
586
                                                //
 
587
                                                // Same kind of different arity is valid
 
588
                                                //
 
589
                                                if (member.MemberName.Arity != entry.Arity) {
 
590
                                                        continue;
 
591
                                                }
 
592
 
 
593
                                                if ((entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) {
 
594
                                                        if (entry.IsAccessor != member is AbstractPropertyEventMethod)
 
595
                                                                continue;
 
596
 
 
597
                                                        var pm = entry as IParametersMember;
 
598
                                                        if (!TypeSpecComparer.Override.IsEqual (pm.Parameters, member_param))
 
599
                                                                continue;
 
600
                                                }
 
601
 
 
602
                                                //
 
603
                                                // Skip override for member with accessors. It may not fully implement the base member
 
604
                                                // but keep flag we found an implementation in case the base member is abstract
 
605
                                                //
 
606
                                                if (member_with_accessors && ((entry.Modifiers & (Modifiers.OVERRIDE | Modifiers.SEALED)) == Modifiers.OVERRIDE)) {
 
607
                                                        //
 
608
                                                        // Set candidate to override implementation to flag we found an implementation
 
609
                                                        //
 
610
                                                        overrides = true;
 
611
                                                        continue;
 
612
                                                }
 
613
 
 
614
                                                //
 
615
                                                // For members with parameters we can encounter an ambiguous candidates (they match exactly)
 
616
                                                // because generic type parameters could be inflated into same types
 
617
                                                //
 
618
                                                if (ambig_candidate == null && (entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) {
 
619
                                                        bestCandidate = null;
 
620
                                                        ambig_candidate = entry;
 
621
                                                        continue;
 
622
                                                }
 
623
 
 
624
                                                bestCandidate = ambig_candidate;
 
625
                                                return entry;
 
626
                                        }
 
627
                                }
 
628
 
 
629
                                if (container.IsInterface || ambig_candidate != null)
 
630
                                        break;
 
631
 
 
632
                                container = container.BaseType;
 
633
                        } while (container != null);
 
634
 
 
635
                        return ambig_candidate;
 
636
                }
 
637
 
 
638
                //
 
639
                // Returns inflated version of MemberSpec, it works similarly to
 
640
                // SRE TypeBuilder.GetMethod
 
641
                //
 
642
                public static T GetMember<T> (TypeSpec container, T spec) where T : MemberSpec
 
643
                {
 
644
                        IList<MemberSpec> applicable;
 
645
                        if (container.MemberCache.member_hash.TryGetValue (GetLookupName (spec), out applicable)) {
 
646
                                for (int i = applicable.Count - 1; i >= 0; i--) {
 
647
                                        var entry = applicable[i];
 
648
                                        if (entry.MemberDefinition == spec.MemberDefinition)
 
649
                                                return (T) entry;
 
650
                                }
 
651
                        }
 
652
 
 
653
                        throw new InternalErrorException ("Missing member `{0}' on inflated type `{1}'",
 
654
                                spec.GetSignatureForError (), container.GetSignatureForError ());
 
655
                }
 
656
 
 
657
                static MemberKind GetMemberCoreKind (MemberCore member)
 
658
                {
 
659
                        if (member is FieldBase)
 
660
                                return MemberKind.Field;
 
661
                        if (member is Indexer)
 
662
                                return MemberKind.Indexer;
 
663
                        if (member is Class)
 
664
                                return MemberKind.Class;
 
665
                        if (member is Struct)
 
666
                                return MemberKind.Struct;
 
667
                        if (member is Destructor)
 
668
                                return MemberKind.Destructor;
 
669
                        if (member is Method)
 
670
                                return MemberKind.Method;
 
671
                        if (member is Property)
 
672
                                return MemberKind.Property;
 
673
                        if (member is EventField)
 
674
                                return MemberKind.Event;
 
675
                        if (member is Interface)
 
676
                                return MemberKind.Interface;
 
677
                        if (member is EventProperty)
 
678
                                return MemberKind.Event;
 
679
                        if (member is Delegate)
 
680
                                return MemberKind.Delegate;
 
681
                        if (member is Enum)
 
682
                                return MemberKind.Enum;
 
683
 
 
684
                        throw new NotImplementedException (member.GetType ().ToString ());
 
685
                }
 
686
 
 
687
                public static IList<MemberSpec> GetCompletitionMembers (IMemberContext ctx, TypeSpec container, string name)
 
688
                {
 
689
                        var matches = new List<MemberSpec> ();
 
690
                        foreach (var entry in container.MemberCache.member_hash) {
 
691
                                foreach (var name_entry in entry.Value) {
 
692
                                        if (name_entry.IsAccessor)
 
693
                                                continue;
 
694
 
 
695
                                        if ((name_entry.Kind & (MemberKind.Constructor | MemberKind.Destructor | MemberKind.Operator)) != 0)
 
696
                                                continue;
 
697
 
 
698
                                        if (!name_entry.IsAccessible (ctx))
 
699
                                                continue;
 
700
 
 
701
                                        if (name == null || name_entry.Name.StartsWith (name)) {
 
702
                                                matches.Add (name_entry);
 
703
                                        }
 
704
                                }
 
705
                        }
 
706
 
 
707
                        return matches;
 
708
                }
 
709
 
 
710
                //
 
711
                // Returns members of @iface only, base members are ignored
 
712
                //
 
713
                public static List<MethodSpec> GetInterfaceMethods (TypeSpec iface)
 
714
                {
 
715
                        //
 
716
                        // MemberCache flatten interfaces, therefore in cases like this one
 
717
                        // 
 
718
                        // interface IA : IB {}
 
719
                        // interface IB { void Foo () }
 
720
                        //
 
721
                        // we would return Foo inside IA which is not expected in this case
 
722
                        //
 
723
                        var methods = new List<MethodSpec> ();
 
724
                        foreach (var entry in iface.MemberCache.member_hash.Values) {
 
725
                                foreach (var name_entry in entry) {
 
726
                                        if (iface == name_entry.DeclaringType) {
 
727
                                                if (name_entry.Kind == MemberKind.Method) {
 
728
                                                        methods.Add ((MethodSpec) name_entry);
 
729
                                                }
 
730
                                        }
 
731
                                }
 
732
                        }
 
733
 
 
734
                        return methods;
 
735
                }
 
736
 
 
737
                //
 
738
                // Returns all not implememted abstract members inside abstract type
 
739
                // NOTE: Returned list is shared and must not be modified
 
740
                //
 
741
                public static IList<MethodSpec> GetNotImplementedAbstractMethods (TypeSpec type)
 
742
                {
 
743
                        if (type.MemberCache.missing_abstract != null)
 
744
                                return type.MemberCache.missing_abstract;
 
745
                                
 
746
                        var abstract_methods = new List<MethodSpec> ();
 
747
                        List<TypeSpec> hierarchy = null;
 
748
 
 
749
                        //
 
750
                        // Stage 1: top-to-bottom scan for abstract members
 
751
                        //
 
752
                        var abstract_type = type;
 
753
                        while (true) {
 
754
                                foreach (var entry in abstract_type.MemberCache.member_hash) {
 
755
                                        foreach (var name_entry in entry.Value) {
 
756
                                                if ((name_entry.Modifiers & Modifiers.ABSTRACT) == 0)
 
757
                                                        continue;
 
758
 
 
759
                                                if (name_entry.Kind != MemberKind.Method)
 
760
                                                        continue;
 
761
 
 
762
                                                abstract_methods.Add ((MethodSpec) name_entry);
 
763
                                        }
 
764
                                }
 
765
 
 
766
                                var base_type = abstract_type.BaseType;
 
767
                                if (!base_type.IsAbstract)
 
768
                                        break;
 
769
 
 
770
                                if (hierarchy == null)
 
771
                                        hierarchy = new List<TypeSpec> ();
 
772
 
 
773
                                hierarchy.Add (abstract_type);
 
774
                                abstract_type = base_type;
 
775
                        }
 
776
 
 
777
                        int not_implemented_count = abstract_methods.Count;
 
778
                        if (not_implemented_count == 0 || hierarchy == null) {
 
779
                                type.MemberCache.missing_abstract = abstract_methods;
 
780
                                return type.MemberCache.missing_abstract;
 
781
                        }
 
782
 
 
783
                        //
 
784
                        // Stage 2: Remove already implemented methods
 
785
                        //
 
786
                        foreach (var type_up in hierarchy) {
 
787
                                var members = type_up.MemberCache.member_hash;
 
788
                                if (members.Count == 0)
 
789
                                        continue;
 
790
 
 
791
                                for (int i = 0; i < abstract_methods.Count; ++i) {
 
792
                                        var candidate = abstract_methods [i];
 
793
                                        if (candidate == null)
 
794
                                                continue;
 
795
 
 
796
                                        IList<MemberSpec> applicable;
 
797
                                        if (!members.TryGetValue (candidate.Name, out applicable))
 
798
                                                continue;
 
799
 
 
800
                                        var filter = new MemberFilter (candidate);
 
801
                                        foreach (var item in applicable) {
 
802
                                                if ((item.Modifiers & (Modifiers.OVERRIDE | Modifiers.VIRTUAL)) == 0)
 
803
                                                        continue;
 
804
 
 
805
                                                if (filter.Equals (item)) {
 
806
                                                        --not_implemented_count;
 
807
                                                        abstract_methods [i] = null;
 
808
                                                        break;
 
809
                                                }
 
810
                                        }
 
811
                                }
 
812
                        }
 
813
 
 
814
                        if (not_implemented_count == abstract_methods.Count) {
 
815
                                type.MemberCache.missing_abstract = abstract_methods;
 
816
                                return type.MemberCache.missing_abstract;
 
817
                        }
 
818
 
 
819
                        var not_implemented = new MethodSpec[not_implemented_count];
 
820
                        int counter = 0;
 
821
                        foreach (var m in abstract_methods) {
 
822
                                if (m == null)
 
823
                                        continue;
 
824
 
 
825
                                not_implemented[counter++] = m;
 
826
                        }
 
827
 
 
828
                        type.MemberCache.missing_abstract = not_implemented;
 
829
                        return type.MemberCache.missing_abstract;
 
830
                }
 
831
 
 
832
                static string GetLookupName (MemberSpec ms)
 
833
                {
 
834
                        if (ms.Kind == MemberKind.Indexer)
 
835
                                return IndexerNameAlias;
 
836
 
 
837
                        if (ms.Kind == MemberKind.Constructor) {
 
838
                                if (ms.IsStatic)
 
839
                                        return Constructor.TypeConstructorName;
 
840
 
 
841
                                return Constructor.ConstructorName;
 
842
                        }
 
843
 
 
844
                        return ms.Name;
 
845
                }
 
846
 
 
847
                static string GetLookupName (MemberCore mc)
 
848
                {
 
849
                        if (mc is Indexer)
 
850
                                return IndexerNameAlias;
 
851
 
 
852
                        if (mc is Constructor)
 
853
                                return Constructor.ConstructorName;
 
854
 
 
855
                        return mc.MemberName.Name;
 
856
                }
 
857
 
 
858
                //
 
859
                // Returns all operators declared on container and its base types (until declaredOnly is used)
 
860
                //
 
861
                public static IList<MemberSpec> GetUserOperator (TypeSpec container, Operator.OpType op, bool declaredOnly)
 
862
                {
 
863
                        IList<MemberSpec> found = null;
 
864
 
 
865
                        IList<MemberSpec> applicable;
 
866
                        do {
 
867
                                var mc = container.MemberCache;
 
868
 
 
869
                                if (((op == Operator.OpType.Implicit || op == Operator.OpType.Explicit) && (mc.state & StateFlags.HasConversionOperator) != 0) ||
 
870
                                         (mc.state & StateFlags.HasUserOperator) != 0) {
 
871
 
 
872
                                        if (mc.member_hash.TryGetValue (Operator.GetMetadataName (op), out applicable)) {
 
873
                                                int i;
 
874
                                                for (i = 0; i < applicable.Count; ++i) {
 
875
                                                        if (applicable[i].Kind != MemberKind.Operator) {
 
876
                                                                break;
 
877
                                                        }
 
878
                                                }
 
879
 
 
880
                                                //
 
881
                                                // Handles very rare case where a method with same name as operator (op_xxxx) exists
 
882
                                                // and we have to resize the applicable list
 
883
                                                //
 
884
                                                if (i != applicable.Count) {
 
885
                                                        for (i = 0; i < applicable.Count; ++i) {
 
886
                                                                if (applicable[i].Kind != MemberKind.Operator) {
 
887
                                                                        continue;
 
888
                                                                }
 
889
 
 
890
                                                                if (found == null) {
 
891
                                                                        found = new List<MemberSpec> ();
 
892
                                                                        found.Add (applicable[i]);
 
893
                                                                } else {
 
894
                                                                        var prev = found as List<MemberSpec>;
 
895
                                                                        if (prev == null) {
 
896
                                                                                prev = new List<MemberSpec> (found.Count + 1);
 
897
                                                                                prev.AddRange (found);
 
898
                                                                        }
 
899
 
 
900
                                                                        prev.Add (applicable[i]);
 
901
                                                                }
 
902
                                                        }
 
903
                                                } else {
 
904
                                                        if (found == null) {
 
905
                                                                found = applicable;
 
906
                                                        } else {
 
907
                                                                var merged = found as List<MemberSpec>;
 
908
                                                                if (merged == null) {
 
909
                                                                        merged = new List<MemberSpec> (found.Count + applicable.Count);
 
910
                                                                        merged.AddRange (found);
 
911
                                                                        found = merged;
 
912
                                                                }
 
913
 
 
914
                                                                merged.AddRange (applicable);
 
915
                                                        }
 
916
                                                }
 
917
                                        }
 
918
                                }
 
919
 
 
920
                                // BaseType call can be expensive
 
921
                                if (declaredOnly)
 
922
                                        break;
 
923
 
 
924
                                container = container.BaseType;
 
925
                        } while (container != null);
 
926
 
 
927
                        return found;
 
928
                }
 
929
 
 
930
                //
 
931
                // Inflates all member cache nested types
 
932
                //
 
933
                public void InflateTypes (MemberCache inflated_cache, TypeParameterInflator inflator)
 
934
                {
 
935
                        foreach (var item in member_hash) {
 
936
                                IList<MemberSpec> inflated_members = null;
 
937
                                for (int i = 0; i < item.Value.Count; ++i ) {
 
938
                                        var member = item.Value[i];
 
939
 
 
940
                                        // FIXME: When inflating members refering nested types before they are inflated
 
941
                                        if (member == null)
 
942
                                                continue;
 
943
 
 
944
                                        if ((member.Kind & MemberKind.NestedMask) != 0 &&
 
945
                                                (member.Modifiers & Modifiers.COMPILER_GENERATED) == 0) {
 
946
                                                if (inflated_members == null) {
 
947
                                                        inflated_members = new MemberSpec[item.Value.Count];
 
948
                                                        inflated_cache.member_hash.Add (item.Key, inflated_members);
 
949
                                                }
 
950
 
 
951
                                                inflated_members [i] = member.InflateMember (inflator);
 
952
                                        }
 
953
                                }
 
954
                        }
 
955
                }
 
956
 
 
957
                //
 
958
                // Inflates all open type members, requires InflateTypes to be called before
 
959
                //
 
960
                public void InflateMembers (MemberCache cacheToInflate, TypeSpec inflatedType, TypeParameterInflator inflator)
 
961
                {
 
962
                        var inflated_member_hash = cacheToInflate.member_hash;
 
963
                        Dictionary<MemberSpec, MethodSpec> accessor_relation = null;
 
964
                        List<MemberSpec> accessor_members = null;
 
965
 
 
966
                        // Copy member specific flags when all members were added
 
967
                        cacheToInflate.state = state;
 
968
 
 
969
                        foreach (var item in member_hash) {
 
970
                                var members = item.Value;
 
971
                                IList<MemberSpec> inflated_members = null;
 
972
                                for (int i = 0; i < members.Count; ++i ) {
 
973
                                        var member = members[i];
 
974
 
 
975
                                        //
 
976
                                        // All nested types have been inflated earlier except for
 
977
                                        // compiler types which are created later and could miss InflateTypes
 
978
                                        //
 
979
                                        if ((member.Kind & MemberKind.NestedMask) != 0 &&
 
980
                                                (member.Modifiers & Modifiers.COMPILER_GENERATED) == 0) {
 
981
                                                if (inflated_members == null)
 
982
                                                        inflated_members = inflated_member_hash[item.Key];
 
983
 
 
984
                                                continue;
 
985
                                        }
 
986
 
 
987
                                        //
 
988
                                        // Clone the container first
 
989
                                        //
 
990
                                        if (inflated_members == null) {
 
991
                                                inflated_members = new MemberSpec [item.Value.Count];
 
992
                                                inflated_member_hash.Add (item.Key, inflated_members);
 
993
                                        }
 
994
 
 
995
                                        var local_inflator = inflator;
 
996
 
 
997
                                        if (member.DeclaringType != inflatedType) {
 
998
                                                //
 
999
                                                // Don't inflate top-level non-generic interface members
 
1000
                                                // merged into generic interface
 
1001
                                                //
 
1002
                                                if (!member.DeclaringType.IsGeneric && !member.DeclaringType.IsNested) {
 
1003
                                                        inflated_members [i] = member;
 
1004
                                                        continue;
 
1005
                                                }
 
1006
 
 
1007
                                                //
 
1008
                                                // Needed when inflating flatten interfaces. It inflates
 
1009
                                                // container type only, type parameters are already done
 
1010
                                                //
 
1011
                                                // Handles cases like:
 
1012
                                                //
 
1013
                                                // interface I<T> {}
 
1014
                                                // interface I<U, V> : I<U> {}
 
1015
                                                // 
 
1016
                                                // class C: I<int, bool> {}
 
1017
                                                //
 
1018
                                                var inflated_parent = inflator.Inflate (member.DeclaringType);
 
1019
                                                if (inflated_parent != inflator.TypeInstance)
 
1020
                                                        local_inflator = new TypeParameterInflator (inflator, inflated_parent);
 
1021
                                        }
 
1022
 
 
1023
                                        //
 
1024
                                        // Inflate every member, its parent is now different
 
1025
                                        //
 
1026
                                        var inflated = member.InflateMember (local_inflator);
 
1027
                                        inflated_members [i] = inflated;
 
1028
 
 
1029
                                        if (member is PropertySpec || member is EventSpec) {
 
1030
                                                if (accessor_members == null)
 
1031
                                                        accessor_members = new List<MemberSpec> ();
 
1032
 
 
1033
                                                accessor_members.Add (inflated);
 
1034
                                                continue;
 
1035
                                        }
 
1036
 
 
1037
                                        if (member.IsAccessor) {
 
1038
                                                if (accessor_relation == null)
 
1039
                                                        accessor_relation = new Dictionary<MemberSpec, MethodSpec> ();
 
1040
                                                accessor_relation.Add (member, (MethodSpec) inflated);
 
1041
                                        }
 
1042
                                }
 
1043
                        }
 
1044
 
 
1045
                        if (accessor_members != null) {
 
1046
                                foreach (var member in accessor_members) {
 
1047
                                        var prop = member as PropertySpec;
 
1048
                                        if (prop != null) {
 
1049
                                                if (prop.Get != null)
 
1050
                                                        prop.Get = accessor_relation[prop.Get];
 
1051
                                                if (prop.Set != null)
 
1052
                                                        prop.Set = accessor_relation[prop.Set];
 
1053
 
 
1054
                                                continue;
 
1055
                                        }
 
1056
 
 
1057
                                        var ev = (EventSpec) member;
 
1058
                                        ev.AccessorAdd = accessor_relation[ev.AccessorAdd];
 
1059
                                        ev.AccessorRemove = accessor_relation[ev.AccessorRemove];
 
1060
                                }
 
1061
                        }
 
1062
                }
 
1063
 
 
1064
                //
 
1065
                // Removes hidden base members of an interface. For compiled interfaces we cannot
 
1066
                // do name filtering during Add (as we do for import) because we need all base
 
1067
                // names to be valid during type definition.
 
1068
                // Add replaces hidden base member with current one which means any name collision
 
1069
                // (CS0108) of non-first name would be unnoticed because the name was replaced
 
1070
                // with the one from compiled type
 
1071
                //
 
1072
                public void RemoveHiddenMembers (TypeSpec container)
 
1073
                {
 
1074
                        foreach (var entry in member_hash) {
 
1075
                                var values = entry.Value;
 
1076
 
 
1077
                                int container_members_start_at = 0;
 
1078
                                while (values[container_members_start_at].DeclaringType != container && ++container_members_start_at < entry.Value.Count);
 
1079
 
 
1080
                                if (container_members_start_at == 0 || container_members_start_at == values.Count)
 
1081
                                        continue;
 
1082
 
 
1083
                                for (int i = 0; i < container_members_start_at; ++i) {
 
1084
                                        var member = values[i];
 
1085
 
 
1086
                                        if (!container.ImplementsInterface (member.DeclaringType, false))
 
1087
                                                continue;
 
1088
 
 
1089
                                        var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : ParametersCompiled.EmptyReadOnlyParameters;
 
1090
 
 
1091
                                        for (int ii = container_members_start_at; ii < values.Count; ++ii) {
 
1092
                                                var container_entry = values[ii];
 
1093
 
 
1094
                                                if (container_entry.Arity != member.Arity)
 
1095
                                                        continue;
 
1096
 
 
1097
                                                if (container_entry is IParametersMember) {
 
1098
                                                        if (!TypeSpecComparer.Override.IsEqual (((IParametersMember) container_entry).Parameters, member_param))
 
1099
                                                                continue;
 
1100
                                                }
 
1101
 
 
1102
                                                values.RemoveAt (i);
 
1103
                                                --container_members_start_at;
 
1104
                                                --ii;
 
1105
                                                --i;
 
1106
                                        }
 
1107
                                }
 
1108
                        }
 
1109
                }
 
1110
 
 
1111
                //
 
1112
                // Checks all appropriate container members for CLS compliance
 
1113
                //
 
1114
                public void VerifyClsCompliance (TypeSpec container, Report report)
 
1115
                {
 
1116
                        if (locase_members != null)
 
1117
                                return;
 
1118
 
 
1119
                        if (container.BaseType == null) {
 
1120
                                locase_members = new Dictionary<string, MemberSpec[]> (member_hash.Count); // StringComparer.OrdinalIgnoreCase);
 
1121
                        } else {
 
1122
                                container.BaseType.MemberCache.VerifyClsCompliance (container.BaseType, report);
 
1123
                                locase_members = new Dictionary<string, MemberSpec[]> (container.BaseType.MemberCache.locase_members); //, StringComparer.OrdinalIgnoreCase);
 
1124
                        }
 
1125
 
 
1126
                        var is_imported_type = container.MemberDefinition.IsImported;
 
1127
                        foreach (var entry in container.MemberCache.member_hash) {
 
1128
                                for (int i = 0; i < entry.Value.Count; ++i ) {
 
1129
                                        var name_entry = entry.Value[i];
 
1130
                                        if ((name_entry.Modifiers & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
 
1131
                                                continue;
 
1132
 
 
1133
                                        if ((name_entry.Modifiers & (Modifiers.OVERRIDE | Modifiers.COMPILER_GENERATED)) != 0)
 
1134
                                                continue;
 
1135
 
 
1136
                                        if ((name_entry.Kind & MemberKind.MaskType) == 0)
 
1137
                                                continue;
 
1138
 
 
1139
                                        if (name_entry.MemberDefinition.CLSAttributeValue == false)
 
1140
                                            continue;
 
1141
 
 
1142
                                        IParametersMember p_a = name_entry as IParametersMember;
 
1143
                                        if (p_a != null && !name_entry.IsAccessor) {
 
1144
                                                if (!is_imported_type) {
 
1145
                                                        var p_a_pd = p_a.Parameters;
 
1146
                                                        for (int ii = i + 1; ii < entry.Value.Count; ++ii) {
 
1147
                                                                var checked_entry = entry.Value[ii];
 
1148
                                                                IParametersMember p_b = checked_entry as IParametersMember;
 
1149
                                                                if (p_b == null)
 
1150
                                                                        continue;
 
1151
 
 
1152
                                                                if (p_a_pd.Count != p_b.Parameters.Count)
 
1153
                                                                        continue;
 
1154
 
 
1155
                                                                if (checked_entry.IsAccessor)
 
1156
                                                                        continue;
 
1157
 
 
1158
                                                                var res = ParametersCompiled.IsSameClsSignature (p_a.Parameters, p_b.Parameters);
 
1159
                                                                if (res != 0) {
 
1160
                                                                        var last = GetLaterDefinedMember (checked_entry, name_entry);
 
1161
                                                                        if (last == checked_entry.MemberDefinition) {
 
1162
                                                                                report.SymbolRelatedToPreviousError (name_entry);
 
1163
                                                                        } else {
 
1164
                                                                                report.SymbolRelatedToPreviousError (checked_entry);
 
1165
                                                                        }
 
1166
 
 
1167
                                                                        if ((res & 1) != 0) {
 
1168
                                                                                report.Warning (3006, 1, last.Location,
 
1169
                                                                                                "Overloaded method `{0}' differing only in ref or out, or in array rank, is not CLS-compliant",
 
1170
                                                                                                name_entry.GetSignatureForError ());
 
1171
                                                                        }
 
1172
 
 
1173
                                                                        if ((res & 2) != 0) {
 
1174
                                                                                report.Warning (3007, 1, last.Location,
 
1175
                                                                                        "Overloaded method `{0}' differing only by unnamed array types is not CLS-compliant",
 
1176
                                                                                        name_entry.GetSignatureForError ());
 
1177
                                                                        }
 
1178
                                                                }
 
1179
                                                        }
 
1180
                                                }
 
1181
                                        }
 
1182
 
 
1183
                                        if (i > 0 || name_entry.Kind == MemberKind.Constructor || name_entry.Kind == MemberKind.Indexer)
 
1184
                                                continue;
 
1185
 
 
1186
                                        var name_entry_locase = name_entry.Name.ToLowerInvariant ();
 
1187
 
 
1188
                                        MemberSpec[] found;
 
1189
                                        if (!locase_members.TryGetValue (name_entry_locase, out found)) {
 
1190
                                                found = new MemberSpec[] { name_entry };
 
1191
                                                locase_members.Add (name_entry_locase, found);
 
1192
                                        } else {
 
1193
                                                bool same_names_only = true;
 
1194
                                                foreach (var f in found) {
 
1195
                                                        if (f.Name == name_entry.Name)
 
1196
                                                                continue;
 
1197
 
 
1198
//                                                      if (f.IsAccessor && name_entry.IsAccessor)
 
1199
//                                                              continue;
 
1200
 
 
1201
                                                        same_names_only = false;
 
1202
                                                        if (!is_imported_type) {
 
1203
                                                                var last = GetLaterDefinedMember (f, name_entry);
 
1204
                                                                if (last == f.MemberDefinition) {
 
1205
                                                                        report.SymbolRelatedToPreviousError (name_entry);
 
1206
                                                                } else {
 
1207
                                                                        report.SymbolRelatedToPreviousError (f);
 
1208
                                                                }
 
1209
 
 
1210
                                                                report.Warning (3005, 1, last.Location,
 
1211
                                                                        "Identifier `{0}' differing only in case is not CLS-compliant", last.GetSignatureForError ());
 
1212
                                                        }
 
1213
                                                }
 
1214
 
 
1215
                                                if (!same_names_only) {
 
1216
                                                        Array.Resize (ref found, found.Length + 1);
 
1217
                                                        found[found.Length - 1] = name_entry;
 
1218
                                                        locase_members[name_entry_locase] = found;
 
1219
                                                }
 
1220
                                        }
 
1221
                                }
 
1222
                        }
 
1223
                }
 
1224
 
 
1225
                //
 
1226
                // Local report helper to issue correctly ordered members stored in hashtable
 
1227
                //
 
1228
                static MemberCore GetLaterDefinedMember (MemberSpec a, MemberSpec b)
 
1229
                {
 
1230
                        var mc_a = a.MemberDefinition as MemberCore;
 
1231
                        var mc_b = b.MemberDefinition as MemberCore;
 
1232
                        if (mc_a == null)
 
1233
                                return mc_b;
 
1234
 
 
1235
                        if (mc_b == null)
 
1236
                                return mc_a;
 
1237
 
 
1238
                        if (mc_a.Location.File != mc_a.Location.File)
 
1239
                                return mc_b;
 
1240
 
 
1241
                        return mc_b.Location.Row > mc_a.Location.Row ? mc_b : mc_a;
 
1242
                }
 
1243
 
 
1244
                public bool CheckExistingMembersOverloads (MemberCore member, AParametersCollection parameters)
 
1245
                {
 
1246
                        var name = GetLookupName (member);
 
1247
                        var imb = member as InterfaceMemberBase;
 
1248
                        if (imb != null && imb.IsExplicitImpl) {
 
1249
                                name = imb.GetFullName (name);
 
1250
                        }
 
1251
 
 
1252
                        return CheckExistingMembersOverloads (member, name, parameters);
 
1253
                }
 
1254
 
 
1255
                public bool CheckExistingMembersOverloads (MemberCore member, string name, AParametersCollection parameters)
 
1256
                {
 
1257
                        IList<MemberSpec> entries;
 
1258
                        if (!member_hash.TryGetValue (name, out entries))
 
1259
                                return false;
 
1260
 
 
1261
                        var Report = member.Compiler.Report;
 
1262
 
 
1263
                        int method_param_count = parameters.Count;
 
1264
                        for (int i = entries.Count - 1; i >= 0; --i) {
 
1265
                                var ce = entries[i];
 
1266
                                var pm = ce as IParametersMember;
 
1267
                                var pd = pm == null ? ParametersCompiled.EmptyReadOnlyParameters : pm.Parameters;
 
1268
                                if (pd.Count != method_param_count)
 
1269
                                        continue;
 
1270
 
 
1271
                                if (ce.Arity != member.MemberName.Arity)
 
1272
                                        continue;
 
1273
 
 
1274
                                // Ignore merged interface members
 
1275
                                if (member.Parent.PartialContainer != ce.DeclaringType.MemberDefinition)
 
1276
                                        continue;
 
1277
 
 
1278
                                var p_types = pd.Types;
 
1279
                                if (method_param_count > 0) {
 
1280
                                        int ii = method_param_count - 1;
 
1281
                                        TypeSpec type_a, type_b;
 
1282
                                        do {
 
1283
                                                type_a = parameters.Types [ii];
 
1284
                                                type_b = p_types [ii];
 
1285
 
 
1286
                                                if ((pd.FixedParameters [ii].ModFlags & Parameter.Modifier.ISBYREF) !=
 
1287
                                                        (parameters.FixedParameters [ii].ModFlags & Parameter.Modifier.ISBYREF))
 
1288
                                                        break;
 
1289
 
 
1290
                                        } while (TypeSpecComparer.Override.IsEqual (type_a, type_b) && ii-- != 0);
 
1291
 
 
1292
                                        if (ii >= 0)
 
1293
                                                continue;
 
1294
 
 
1295
                                        //
 
1296
                                        // Operators can differ in return type only
 
1297
                                        //
 
1298
                                        if (member is Operator && ce.Kind == MemberKind.Operator && ((MethodSpec) ce).ReturnType != ((Operator) member).ReturnType)
 
1299
                                                continue;
 
1300
 
 
1301
                                        //
 
1302
                                        // Report difference in parameter modifiers only
 
1303
                                        //
 
1304
                                        if (pd != null && member is MethodCore) {
 
1305
                                                ii = method_param_count;
 
1306
                                                while (ii-- != 0 && parameters.FixedParameters[ii].ModFlags == pd.FixedParameters[ii].ModFlags &&
 
1307
                                                        parameters.ExtensionMethodType == pd.ExtensionMethodType) ;
 
1308
 
 
1309
                                                if (ii >= 0) {
 
1310
                                                        var mc = ce as MethodSpec;
 
1311
                                                        member.Compiler.Report.SymbolRelatedToPreviousError (ce);
 
1312
                                                        if ((member.ModFlags & Modifiers.PARTIAL) != 0 && (mc.Modifiers & Modifiers.PARTIAL) != 0) {
 
1313
                                                                if (parameters.HasParams || pd.HasParams) {
 
1314
                                                                        Report.Error (758, member.Location,
 
1315
                                                                                "A partial method declaration and partial method implementation cannot differ on use of `params' modifier");
 
1316
                                                                } else {
 
1317
                                                                        Report.Error (755, member.Location,
 
1318
                                                                                "A partial method declaration and partial method implementation must be both an extension method or neither");
 
1319
                                                                }
 
1320
                                                        } else if (member is Constructor) {
 
1321
                                                                Report.Error (851, member.Location,
 
1322
                                                                        "Overloaded contructor `{0}' cannot differ on use of parameter modifiers only",
 
1323
                                                                        member.GetSignatureForError ());
 
1324
                                                        } else {
 
1325
                                                                Report.Error (663, member.Location,
 
1326
                                                                        "Overloaded method `{0}' cannot differ on use of parameter modifiers only",
 
1327
                                                                        member.GetSignatureForError ());
 
1328
                                                        }
 
1329
                                                        return false;
 
1330
                                                }
 
1331
                                        }
 
1332
                                }
 
1333
 
 
1334
                                if ((ce.Kind & MemberKind.Method) != 0) {
 
1335
                                        Method method_a = member as Method;
 
1336
                                        Method method_b = ce.MemberDefinition as Method;
 
1337
                                        if (method_a != null && method_b != null && (method_a.ModFlags & method_b.ModFlags & Modifiers.PARTIAL) != 0) {
 
1338
                                                const Modifiers partial_modifiers = Modifiers.STATIC | Modifiers.UNSAFE;
 
1339
                                                if (method_a.IsPartialDefinition == method_b.IsPartialImplementation) {
 
1340
                                                        if ((method_a.ModFlags & partial_modifiers) == (method_b.ModFlags & partial_modifiers) ||
 
1341
                                                                method_a.Parent.IsUnsafe && method_b.Parent.IsUnsafe) {
 
1342
                                                                if (method_a.IsPartialImplementation) {
 
1343
                                                                        method_a.SetPartialDefinition (method_b);
 
1344
                                                                        if (entries.Count == 1)
 
1345
                                                                                member_hash.Remove (name);
 
1346
                                                                        else
 
1347
                                                                                entries.RemoveAt (i);
 
1348
                                                                } else {
 
1349
                                                                        method_b.SetPartialDefinition (method_a);
 
1350
                                                                        method_a.caching_flags |= MemberCore.Flags.PartialDefinitionExists;
 
1351
                                                                }
 
1352
                                                                continue;
 
1353
                                                        }
 
1354
 
 
1355
                                                        if (method_a.IsStatic != method_b.IsStatic) {
 
1356
                                                                Report.SymbolRelatedToPreviousError (ce);
 
1357
                                                                Report.Error (763, member.Location,
 
1358
                                                                        "A partial method declaration and partial method implementation must be both `static' or neither");
 
1359
                                                        }
 
1360
 
 
1361
                                                        Report.SymbolRelatedToPreviousError (ce);
 
1362
                                                        Report.Error (764, member.Location,
 
1363
                                                                "A partial method declaration and partial method implementation must be both `unsafe' or neither");
 
1364
                                                        return false;
 
1365
                                                }
 
1366
 
 
1367
                                                Report.SymbolRelatedToPreviousError (ce);
 
1368
                                                if (method_a.IsPartialDefinition) {
 
1369
                                                        Report.Error (756, member.Location, "A partial method `{0}' declaration is already defined",
 
1370
                                                                member.GetSignatureForError ());
 
1371
                                                }
 
1372
 
 
1373
                                                Report.Error (757, member.Location, "A partial method `{0}' implementation is already defined",
 
1374
                                                        member.GetSignatureForError ());
 
1375
                                                return false;
 
1376
                                        }
 
1377
 
 
1378
                                        Report.SymbolRelatedToPreviousError (ce);
 
1379
 
 
1380
                                        bool is_reserved_a = member is AbstractPropertyEventMethod || member is Operator;
 
1381
                                        bool is_reserved_b = ((MethodSpec) ce).IsReservedMethod;
 
1382
 
 
1383
                                        if (is_reserved_a || is_reserved_b) {
 
1384
                                                Report.Error (82, member.Location, "A member `{0}' is already reserved",
 
1385
                                                        is_reserved_a ?
 
1386
                                                        ce.GetSignatureForError () :
 
1387
                                                        member.GetSignatureForError ());
 
1388
                                                return false;
 
1389
                                        }
 
1390
                                } else {
 
1391
                                        Report.SymbolRelatedToPreviousError (ce);
 
1392
                                }
 
1393
 
 
1394
                                if (member is Operator && ce.Kind == MemberKind.Operator) {
 
1395
                                        Report.Error (557, member.Location, "Duplicate user-defined conversion in type `{0}'",
 
1396
                                                member.Parent.GetSignatureForError ());
 
1397
                                        return false;
 
1398
                                }
 
1399
 
 
1400
                                Report.Error (111, member.Location,
 
1401
                                        "A member `{0}' is already defined. Rename this member or use different parameter types",
 
1402
                                        member.GetSignatureForError ());
 
1403
                                return false;
 
1404
                        }
 
1405
 
 
1406
                        return true;
 
1407
                }
 
1408
        }
 
1409
}