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

« back to all changes in this revision

Viewing changes to contrib/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
 
                public void AddInterface (TypeSpec iface)
244
 
                {
245
 
                        var cache = iface.MemberCache;
246
 
 
247
 
                        IList<MemberSpec> list;
248
 
                        foreach (var entry in cache.member_hash) {
249
 
                                if (!member_hash.TryGetValue (entry.Key, out list)) {
250
 
                                        if (entry.Value.Count == 1) {
251
 
                                                list = entry.Value;
252
 
                                        } else {
253
 
                                                list = new List<MemberSpec> (entry.Value);
254
 
                                        }
255
 
 
256
 
                                        member_hash.Add (entry.Key, list);
257
 
                                        continue;
258
 
                                }
259
 
 
260
 
                                foreach (var ce in entry.Value) {
261
 
                                        if (list.Contains (ce))
262
 
                                                continue;
263
 
 
264
 
                                        if (AddInterfaceMember (ce, ref list))
265
 
                                                member_hash[entry.Key] = list;
266
 
                                }
267
 
                        }
268
 
 
269
 
                        // Add also all base interfaces
270
 
                        if (iface.Interfaces != null) {
271
 
                                foreach (var base_iface in iface.Interfaces)
272
 
                                        AddInterface (base_iface);
273
 
                        }
274
 
                }
275
 
 
276
 
                public void AddMember (InterfaceMemberBase imb, string exlicitName, MemberSpec ms)
277
 
                {
278
 
                        // Explicit names cannot be looked-up but can be used for
279
 
                        // collision checking (no name mangling needed)
280
 
                        if (imb.IsExplicitImpl)
281
 
                                AddMember (exlicitName, ms, false);
282
 
                        else
283
 
                                AddMember (ms);
284
 
                }
285
 
 
286
 
                //
287
 
                // Add non-explicit member to member cache
288
 
                //
289
 
                public void AddMember (MemberSpec ms)
290
 
                {
291
 
                        AddMember (GetLookupName (ms), ms, false);
292
 
                }
293
 
 
294
 
                void AddMember (string name, MemberSpec member, bool removeHiddenMembers)
295
 
                {
296
 
                        if (member.Kind == MemberKind.Operator) {
297
 
                                var dt = member.DeclaringType;
298
 
 
299
 
                                //
300
 
                                // Some core types have user operators but they cannot be used like normal
301
 
                                // user operators as they are predefined and therefore having different
302
 
                                // rules (e.g. binary operators) by not setting the flag we hide them for
303
 
                                // user conversions
304
 
                                //
305
 
                                if (!BuiltinTypeSpec.IsPrimitiveType (dt)) {
306
 
                                        switch (dt.BuiltinType) {
307
 
                                        case BuiltinTypeSpec.Type.String:
308
 
                                        case BuiltinTypeSpec.Type.Delegate:
309
 
                                        case BuiltinTypeSpec.Type.MulticastDelegate:
310
 
                                                break;
311
 
                                        default:
312
 
                                                if (name == Operator.GetMetadataName (Operator.OpType.Implicit) || name == Operator.GetMetadataName (Operator.OpType.Explicit)) {
313
 
                                                        state |= StateFlags.HasConversionOperator;
314
 
                                                } else {
315
 
                                                        state |= StateFlags.HasUserOperator;
316
 
                                                }
317
 
 
318
 
                                                break;
319
 
                                        }
320
 
                                }
321
 
                        }
322
 
 
323
 
                        IList<MemberSpec> list;
324
 
                        if (!member_hash.TryGetValue (name, out list)) {
325
 
                                member_hash.Add (name, new MemberSpec[] { member });
326
 
                                return;
327
 
                        }
328
 
 
329
 
                        if (removeHiddenMembers && member.DeclaringType.IsInterface) {
330
 
                                if (AddInterfaceMember (member, ref list))
331
 
                                        member_hash[name] = list;
332
 
                        } else {
333
 
                                if (list.Count == 1) {
334
 
                                        list = new List<MemberSpec> () { list[0] };
335
 
                                        member_hash[name] = list;
336
 
                                }
337
 
 
338
 
                                list.Add (member);
339
 
                        }
340
 
                }
341
 
 
342
 
                public void AddMemberImported (MemberSpec ms)
343
 
                {
344
 
                        AddMember (GetLookupName (ms), ms, true);
345
 
                }
346
 
 
347
 
                //
348
 
                // Ignores any base interface member which can be hidden
349
 
                // by this interface
350
 
                //
351
 
                static bool AddInterfaceMember (MemberSpec member, ref IList<MemberSpec> existing)
352
 
                {
353
 
                        var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : ParametersCompiled.EmptyReadOnlyParameters;
354
 
 
355
 
                        //
356
 
                        // interface IA : IB { int Prop { set; } }
357
 
                        // interface IB { bool Prop { get; } }
358
 
                        //
359
 
                        // IB.Prop is never accessible from IA interface
360
 
                        //
361
 
                        for (int i = 0; i < existing.Count; ++i) {
362
 
                                var entry = existing[i];
363
 
 
364
 
                                if (entry.Arity != member.Arity)
365
 
                                        continue;
366
 
 
367
 
                                if (entry is IParametersMember) {
368
 
                                        var entry_param = ((IParametersMember) entry).Parameters;
369
 
                                        if (!TypeSpecComparer.Override.IsEqual (entry_param, member_param))
370
 
                                                continue;
371
 
                                }
372
 
 
373
 
                                if (member.DeclaringType.ImplementsInterface (entry.DeclaringType, false)) {
374
 
                                        if (existing.Count == 1) {
375
 
                                                existing = new MemberSpec[] { member };
376
 
                                                return true;
377
 
                                        }
378
 
 
379
 
                                        existing.RemoveAt (i--);
380
 
                                        continue;
381
 
                                }
382
 
 
383
 
                                if ((entry.DeclaringType == member.DeclaringType && entry.IsAccessor == member.IsAccessor) ||
384
 
                                        entry.DeclaringType.ImplementsInterface (member.DeclaringType, false))
385
 
                                        return false;
386
 
                        }
387
 
 
388
 
                        if (existing.Count == 1) {
389
 
                                existing = new List<MemberSpec> () { existing[0], member };
390
 
                                return true;
391
 
                        }
392
 
 
393
 
                        existing.Add (member);
394
 
                        return false;
395
 
                }
396
 
 
397
 
                public static MemberSpec FindMember (TypeSpec container, MemberFilter filter, BindingRestriction restrictions)
398
 
                {
399
 
                        do {
400
 
                                IList<MemberSpec> applicable;
401
 
                                if (container.MemberCache.member_hash.TryGetValue (filter.Name, out applicable)) {
402
 
                                        // Start from the end because interface members are in reverse order
403
 
                                        for (int i = applicable.Count - 1; i >= 0; i--) {
404
 
                                                var entry = applicable [i];
405
 
 
406
 
                                                if ((restrictions & BindingRestriction.InstanceOnly) != 0 && entry.IsStatic)
407
 
                                                        continue;
408
 
 
409
 
                                                if ((restrictions & BindingRestriction.NoAccessors) != 0 && entry.IsAccessor)
410
 
                                                        continue;
411
 
 
412
 
                                                if ((restrictions & BindingRestriction.OverrideOnly) != 0 && (entry.Modifiers & Modifiers.OVERRIDE) == 0)
413
 
                                                        continue;
414
 
 
415
 
                                                if (!filter.Equals (entry))
416
 
                                                        continue;
417
 
 
418
 
                                                if ((restrictions & BindingRestriction.DeclaredOnly) != 0 && container.IsInterface && entry.DeclaringType != container)
419
 
                                                        continue;
420
 
 
421
 
                                                return entry;
422
 
                                        }
423
 
                                }
424
 
 
425
 
                                if ((restrictions & BindingRestriction.DeclaredOnly) != 0)
426
 
                                        break;
427
 
 
428
 
                                container = container.BaseType;
429
 
                        } while (container != null);
430
 
 
431
 
                        return null;
432
 
                }
433
 
 
434
 
                //
435
 
                // A special method to work with member lookup only. It returns a list of all members named @name
436
 
                // starting from @container. It's very performance sensitive
437
 
                //
438
 
                public static IList<MemberSpec> FindMembers (TypeSpec container, string name, bool declaredOnly)
439
 
                {
440
 
                        IList<MemberSpec> applicable;
441
 
 
442
 
                        do {
443
 
                                if (container.MemberCache.member_hash.TryGetValue (name, out applicable) || declaredOnly)
444
 
                                        return applicable;
445
 
 
446
 
                                container = container.BaseType;
447
 
                        } while (container != null);
448
 
 
449
 
                        return null;
450
 
                }
451
 
 
452
 
                //
453
 
                // Finds the nested type in container
454
 
                //
455
 
                public static TypeSpec FindNestedType (TypeSpec container, string name, int arity)
456
 
                {
457
 
                        IList<MemberSpec> applicable;
458
 
                        TypeSpec best_match = null;
459
 
                        do {
460
 
                                // TODO: Don't know how to handle this yet
461
 
                                // When resolving base type of nested type, parent type must have
462
 
                                // base type resolved to scan full hierarchy correctly
463
 
                                // Similarly MemberCacheTypes will inflate BaseType and Interfaces
464
 
                                // based on type definition
465
 
                                var tc = container.MemberDefinition as TypeContainer;
466
 
                                if (tc != null)
467
 
                                        tc.DefineContainer ();
468
 
 
469
 
                                if (container.MemberCacheTypes.member_hash.TryGetValue (name, out applicable)) {
470
 
                                        for (int i = applicable.Count - 1; i >= 0; i--) {
471
 
                                                var entry = applicable[i];
472
 
                                                if ((entry.Kind & MemberKind.NestedMask) == 0)
473
 
                                                        continue;
474
 
 
475
 
                                                var ts = (TypeSpec) entry;
476
 
                                                if (arity == ts.Arity)
477
 
                                                        return ts;
478
 
 
479
 
                                                if (arity < 0) {
480
 
                                                        if (best_match == null) {
481
 
                                                                best_match = ts;
482
 
                                                        } else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (ts.Arity + arity)) {
483
 
                                                                best_match = ts;
484
 
                                                        }
485
 
                                                }
486
 
                                        }
487
 
                                }
488
 
 
489
 
                                container = container.BaseType;
490
 
                        } while (container != null);
491
 
 
492
 
                        return best_match;
493
 
                }
494
 
 
495
 
                //
496
 
                // Looks for extension methods with defined name and extension type
497
 
                //
498
 
                public List<MethodSpec> FindExtensionMethods (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity)
499
 
                {
500
 
                        IList<MemberSpec> entries;
501
 
                        if (!member_hash.TryGetValue (name, out entries))
502
 
                                return null;
503
 
 
504
 
                        List<MethodSpec> candidates = null;
505
 
                        foreach (var entry in entries) {
506
 
                                if (entry.Kind != MemberKind.Method || (arity > 0 && entry.Arity != arity))
507
 
                                        continue;
508
 
 
509
 
                                var ms = (MethodSpec) entry;
510
 
                                if (!ms.IsExtensionMethod)
511
 
                                        continue;
512
 
 
513
 
                                if (!ms.IsAccessible (invocationContext))
514
 
                                        continue;
515
 
 
516
 
                                //
517
 
                                // Extension methods cannot be nested hence checking parent is enough
518
 
                                //
519
 
                                if ((ms.DeclaringType.Modifiers & Modifiers.INTERNAL) != 0 && !ms.DeclaringType.MemberDefinition.IsInternalAsPublic (invocationContext.Module.DeclaringAssembly))
520
 
                                        continue;
521
 
 
522
 
                                if (candidates == null)
523
 
                                        candidates = new List<MethodSpec> ();
524
 
                                candidates.Add (ms);
525
 
                        }
526
 
 
527
 
                        return candidates;
528
 
                }
529
 
 
530
 
                //
531
 
                // Returns base members of @member member if no exact match is found @bestCandidate returns
532
 
                // the best match
533
 
                //
534
 
                public static MemberSpec FindBaseMember (MemberCore member, out MemberSpec bestCandidate, ref bool overrides)
535
 
                {
536
 
                        bestCandidate = null;
537
 
                        var container = member.Parent.PartialContainer.Definition;
538
 
                        if (!container.IsInterface) {
539
 
                                container = container.BaseType;
540
 
 
541
 
                                // It can happen for a user definition of System.Object
542
 
                                if (container == null)
543
 
                                        return null;
544
 
                        }
545
 
 
546
 
                        string name = GetLookupName (member);
547
 
                        var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : null;
548
 
 
549
 
                        var mkind = GetMemberCoreKind (member);
550
 
                        bool member_with_accessors = mkind == MemberKind.Indexer || mkind == MemberKind.Property;
551
 
 
552
 
                        IList<MemberSpec> applicable;
553
 
                        MemberSpec ambig_candidate = null;
554
 
 
555
 
                        do {
556
 
                                if (container.MemberCache.member_hash.TryGetValue (name, out applicable)) {
557
 
                                        for (int i = 0; i < applicable.Count; ++i) {
558
 
                                                var entry = applicable [i];
559
 
 
560
 
                                                if ((entry.Modifiers & Modifiers.PRIVATE) != 0)
561
 
                                                        continue;
562
 
 
563
 
                                                if ((entry.Modifiers & Modifiers.AccessibilityMask) == Modifiers.INTERNAL &&
564
 
                                                        !entry.DeclaringType.MemberDefinition.IsInternalAsPublic (member.Module.DeclaringAssembly))
565
 
                                                        continue;
566
 
 
567
 
                                                //
568
 
                                                // Isn't the member of same kind ?
569
 
                                                //
570
 
                                                if ((entry.Kind & ~MemberKind.Destructor & mkind & MemberKind.MaskType) == 0) {
571
 
                                                        // Destructors are ignored as they cannot be overridden by user
572
 
                                                        if ((entry.Kind & MemberKind.Destructor) != 0)
573
 
                                                                continue;
574
 
 
575
 
                                                        // A method with different arity does not hide base member
576
 
                                                        if (mkind != MemberKind.Method && member.MemberName.Arity != entry.Arity)
577
 
                                                                continue;
578
 
 
579
 
                                                        bestCandidate = entry;
580
 
                                                        return null;
581
 
                                                }
582
 
 
583
 
                                                //
584
 
                                                // Same kind of different arity is valid
585
 
                                                //
586
 
                                                if (member.MemberName.Arity != entry.Arity) {
587
 
                                                        continue;
588
 
                                                }
589
 
 
590
 
                                                if ((entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) {
591
 
                                                        if (entry.IsAccessor != member is AbstractPropertyEventMethod)
592
 
                                                                continue;
593
 
 
594
 
                                                        var pm = entry as IParametersMember;
595
 
                                                        if (!TypeSpecComparer.Override.IsEqual (pm.Parameters, member_param))
596
 
                                                                continue;
597
 
                                                }
598
 
 
599
 
                                                //
600
 
                                                // Skip override for member with accessors. It may not fully implement the base member
601
 
                                                // but keep flag we found an implementation in case the base member is abstract
602
 
                                                //
603
 
                                                if (member_with_accessors && ((entry.Modifiers & (Modifiers.OVERRIDE | Modifiers.SEALED)) == Modifiers.OVERRIDE)) {
604
 
                                                        //
605
 
                                                        // Set candidate to override implementation to flag we found an implementation
606
 
                                                        //
607
 
                                                        overrides = true;
608
 
                                                        continue;
609
 
                                                }
610
 
 
611
 
                                                //
612
 
                                                // For members with parameters we can encounter an ambiguous candidates (they match exactly)
613
 
                                                // because generic type parameters could be inflated into same types
614
 
                                                //
615
 
                                                if (ambig_candidate == null && (entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) {
616
 
                                                        bestCandidate = null;
617
 
                                                        ambig_candidate = entry;
618
 
                                                        continue;
619
 
                                                }
620
 
 
621
 
                                                bestCandidate = ambig_candidate;
622
 
                                                return entry;
623
 
                                        }
624
 
                                }
625
 
 
626
 
                                if (container.IsInterface || ambig_candidate != null)
627
 
                                        break;
628
 
 
629
 
                                container = container.BaseType;
630
 
                        } while (container != null);
631
 
 
632
 
                        return ambig_candidate;
633
 
                }
634
 
 
635
 
                //
636
 
                // Returns inflated version of MemberSpec, it works similarly to
637
 
                // SRE TypeBuilder.GetMethod
638
 
                //
639
 
                public static T GetMember<T> (TypeSpec container, T spec) where T : MemberSpec
640
 
                {
641
 
                        IList<MemberSpec> applicable;
642
 
                        if (container.MemberCache.member_hash.TryGetValue (GetLookupName (spec), out applicable)) {
643
 
                                for (int i = applicable.Count - 1; i >= 0; i--) {
644
 
                                        var entry = applicable[i];
645
 
                                        if (entry.MemberDefinition == spec.MemberDefinition)
646
 
                                                return (T) entry;
647
 
                                }
648
 
                        }
649
 
 
650
 
                        throw new InternalErrorException ("Missing member `{0}' on inflated type `{1}'",
651
 
                                spec.GetSignatureForError (), container.GetSignatureForError ());
652
 
                }
653
 
 
654
 
                static MemberKind GetMemberCoreKind (MemberCore member)
655
 
                {
656
 
                        if (member is FieldBase)
657
 
                                return MemberKind.Field;
658
 
                        if (member is Indexer)
659
 
                                return MemberKind.Indexer;
660
 
                        if (member is Class)
661
 
                                return MemberKind.Class;
662
 
                        if (member is Struct)
663
 
                                return MemberKind.Struct;
664
 
                        if (member is Destructor)
665
 
                                return MemberKind.Destructor;
666
 
                        if (member is Method)
667
 
                                return MemberKind.Method;
668
 
                        if (member is Property)
669
 
                                return MemberKind.Property;
670
 
                        if (member is EventField)
671
 
                                return MemberKind.Event;
672
 
                        if (member is Interface)
673
 
                                return MemberKind.Interface;
674
 
                        if (member is EventProperty)
675
 
                                return MemberKind.Event;
676
 
                        if (member is Delegate)
677
 
                                return MemberKind.Delegate;
678
 
                        if (member is Enum)
679
 
                                return MemberKind.Enum;
680
 
 
681
 
                        throw new NotImplementedException (member.GetType ().ToString ());
682
 
                }
683
 
 
684
 
                public static List<FieldSpec> GetAllFieldsForDefiniteAssignment (TypeSpec container)
685
 
                {
686
 
                        List<FieldSpec> fields = null;
687
 
                        foreach (var entry in container.MemberCache.member_hash) {
688
 
                                foreach (var name_entry in entry.Value) {
689
 
                                        if (name_entry.Kind != MemberKind.Field)
690
 
                                                continue;
691
 
 
692
 
                                        if ((name_entry.Modifiers & Modifiers.STATIC) != 0)
693
 
                                                continue;
694
 
 
695
 
                                        //
696
 
                                        // Fixed size buffers are not subject to definite assignment checking
697
 
                                        //
698
 
                                        if (name_entry is FixedFieldSpec || name_entry is ConstSpec)
699
 
                                                continue;
700
 
 
701
 
                                        var fs = (FieldSpec) name_entry;
702
 
 
703
 
                                        //
704
 
                                        // LAMESPEC: Very bizzare hack, definitive assignment is not done
705
 
                                        // for imported non-public reference fields except array. No idea what the
706
 
                                        // actual csc rule is
707
 
                                        //
708
 
                                        if (!fs.IsPublic && container.MemberDefinition.IsImported && (!fs.MemberType.IsArray && TypeSpec.IsReferenceType (fs.MemberType)))
709
 
                                                continue;
710
 
 
711
 
                                        if (fields == null)
712
 
                                                fields = new List<FieldSpec> ();
713
 
 
714
 
                                        fields.Add (fs);
715
 
                                        break;
716
 
                                }
717
 
                        }
718
 
 
719
 
                        return fields ?? new List<FieldSpec> (0);
720
 
                }
721
 
 
722
 
                public static IList<MemberSpec> GetCompletitionMembers (IMemberContext ctx, TypeSpec container, string name)
723
 
                {
724
 
                        var matches = new List<MemberSpec> ();
725
 
                        foreach (var entry in container.MemberCache.member_hash) {
726
 
                                foreach (var name_entry in entry.Value) {
727
 
                                        if (name_entry.IsAccessor)
728
 
                                                continue;
729
 
 
730
 
                                        if ((name_entry.Kind & (MemberKind.Constructor | MemberKind.Destructor | MemberKind.Operator)) != 0)
731
 
                                                continue;
732
 
 
733
 
                                        if (!name_entry.IsAccessible (ctx))
734
 
                                                continue;
735
 
 
736
 
                                        if (name == null || name_entry.Name.StartsWith (name)) {
737
 
                                                matches.Add (name_entry);
738
 
                                        }
739
 
                                }
740
 
                        }
741
 
 
742
 
                        return matches;
743
 
                }
744
 
 
745
 
                //
746
 
                // Returns members of @iface only, base members are ignored
747
 
                //
748
 
                public static List<MethodSpec> GetInterfaceMethods (TypeSpec iface)
749
 
                {
750
 
                        //
751
 
                        // MemberCache flatten interfaces, therefore in cases like this one
752
 
                        // 
753
 
                        // interface IA : IB {}
754
 
                        // interface IB { void Foo () }
755
 
                        //
756
 
                        // we would return Foo inside IA which is not expected in this case
757
 
                        //
758
 
                        var methods = new List<MethodSpec> ();
759
 
                        foreach (var entry in iface.MemberCache.member_hash.Values) {
760
 
                                foreach (var name_entry in entry) {
761
 
                                        if (iface == name_entry.DeclaringType) {
762
 
                                                if (name_entry.Kind == MemberKind.Method) {
763
 
                                                        methods.Add ((MethodSpec) name_entry);
764
 
                                                }
765
 
                                        }
766
 
                                }
767
 
                        }
768
 
 
769
 
                        return methods;
770
 
                }
771
 
 
772
 
                //
773
 
                // Returns all not implememted abstract members inside abstract type
774
 
                // NOTE: Returned list is shared and must not be modified
775
 
                //
776
 
                public static IList<MethodSpec> GetNotImplementedAbstractMethods (TypeSpec type)
777
 
                {
778
 
                        if (type.MemberCache.missing_abstract != null)
779
 
                                return type.MemberCache.missing_abstract;
780
 
                                
781
 
                        var abstract_methods = new List<MethodSpec> ();
782
 
                        List<TypeSpec> hierarchy = null;
783
 
 
784
 
                        //
785
 
                        // Stage 1: top-to-bottom scan for abstract members
786
 
                        //
787
 
                        var abstract_type = type;
788
 
                        while (true) {
789
 
                                foreach (var entry in abstract_type.MemberCache.member_hash) {
790
 
                                        foreach (var name_entry in entry.Value) {
791
 
                                                if ((name_entry.Modifiers & (Modifiers.ABSTRACT | Modifiers.OVERRIDE)) != Modifiers.ABSTRACT)
792
 
                                                        continue;
793
 
 
794
 
                                                if (name_entry.Kind != MemberKind.Method)
795
 
                                                        continue;
796
 
 
797
 
                                                abstract_methods.Add ((MethodSpec) name_entry);
798
 
                                        }
799
 
                                }
800
 
 
801
 
                                var base_type = abstract_type.BaseType;
802
 
                                if (!base_type.IsAbstract)
803
 
                                        break;
804
 
 
805
 
                                if (hierarchy == null)
806
 
                                        hierarchy = new List<TypeSpec> ();
807
 
 
808
 
                                hierarchy.Add (abstract_type);
809
 
                                abstract_type = base_type;
810
 
                        }
811
 
 
812
 
                        int not_implemented_count = abstract_methods.Count;
813
 
                        if (not_implemented_count == 0 || hierarchy == null) {
814
 
                                type.MemberCache.missing_abstract = abstract_methods;
815
 
                                return type.MemberCache.missing_abstract;
816
 
                        }
817
 
 
818
 
                        //
819
 
                        // Stage 2: Remove already implemented methods
820
 
                        //
821
 
                        foreach (var type_up in hierarchy) {
822
 
                                var members = type_up.MemberCache.member_hash;
823
 
                                if (members.Count == 0)
824
 
                                        continue;
825
 
 
826
 
                                for (int i = 0; i < abstract_methods.Count; ++i) {
827
 
                                        var candidate = abstract_methods [i];
828
 
                                        if (candidate == null)
829
 
                                                continue;
830
 
 
831
 
                                        IList<MemberSpec> applicable;
832
 
                                        if (!members.TryGetValue (candidate.Name, out applicable))
833
 
                                                continue;
834
 
 
835
 
                                        var filter = new MemberFilter (candidate);
836
 
                                        foreach (var item in applicable) {
837
 
                                                if ((item.Modifiers & (Modifiers.OVERRIDE | Modifiers.VIRTUAL)) == 0)
838
 
                                                        continue;
839
 
 
840
 
                                                //
841
 
                                                // Abstract override does not override anything
842
 
                                                //
843
 
                                                if ((item.Modifiers & Modifiers.ABSTRACT) != 0)
844
 
                                                        continue;
845
 
 
846
 
                                                if (filter.Equals (item)) {
847
 
                                                        --not_implemented_count;
848
 
                                                        abstract_methods [i] = null;
849
 
                                                        break;
850
 
                                                }
851
 
                                        }
852
 
                                }
853
 
                        }
854
 
 
855
 
                        if (not_implemented_count == abstract_methods.Count) {
856
 
                                type.MemberCache.missing_abstract = abstract_methods;
857
 
                                return type.MemberCache.missing_abstract;
858
 
                        }
859
 
 
860
 
                        var not_implemented = new MethodSpec[not_implemented_count];
861
 
                        int counter = 0;
862
 
                        foreach (var m in abstract_methods) {
863
 
                                if (m == null)
864
 
                                        continue;
865
 
 
866
 
                                not_implemented[counter++] = m;
867
 
                        }
868
 
 
869
 
                        type.MemberCache.missing_abstract = not_implemented;
870
 
                        return type.MemberCache.missing_abstract;
871
 
                }
872
 
 
873
 
                static string GetLookupName (MemberSpec ms)
874
 
                {
875
 
                        if (ms.Kind == MemberKind.Indexer)
876
 
                                return IndexerNameAlias;
877
 
 
878
 
                        if (ms.Kind == MemberKind.Constructor) {
879
 
                                if (ms.IsStatic)
880
 
                                        return Constructor.TypeConstructorName;
881
 
 
882
 
                                return Constructor.ConstructorName;
883
 
                        }
884
 
 
885
 
                        return ms.Name;
886
 
                }
887
 
 
888
 
                static string GetLookupName (MemberCore mc)
889
 
                {
890
 
                        if (mc is Indexer)
891
 
                                return IndexerNameAlias;
892
 
 
893
 
                        if (mc is Constructor)
894
 
                                return mc.IsStatic ? Constructor.TypeConstructorName : Constructor.ConstructorName;
895
 
 
896
 
                        return mc.MemberName.Name;
897
 
                }
898
 
 
899
 
                //
900
 
                // Returns all operators declared on container and its base types (until declaredOnly is used)
901
 
                //
902
 
                public static IList<MemberSpec> GetUserOperator (TypeSpec container, Operator.OpType op, bool declaredOnly)
903
 
                {
904
 
                        IList<MemberSpec> found = null;
905
 
 
906
 
                        IList<MemberSpec> applicable;
907
 
                        do {
908
 
                                var mc = container.MemberCache;
909
 
 
910
 
                                if (((op == Operator.OpType.Implicit || op == Operator.OpType.Explicit) && (mc.state & StateFlags.HasConversionOperator) != 0) ||
911
 
                                         (mc.state & StateFlags.HasUserOperator) != 0) {
912
 
 
913
 
                                        if (mc.member_hash.TryGetValue (Operator.GetMetadataName (op), out applicable)) {
914
 
                                                int i;
915
 
                                                for (i = 0; i < applicable.Count; ++i) {
916
 
                                                        if (applicable[i].Kind != MemberKind.Operator) {
917
 
                                                                break;
918
 
                                                        }
919
 
                                                }
920
 
 
921
 
                                                //
922
 
                                                // Handles very rare case where a method with same name as operator (op_xxxx) exists
923
 
                                                // and we have to resize the applicable list
924
 
                                                //
925
 
                                                if (i != applicable.Count) {
926
 
                                                        for (i = 0; i < applicable.Count; ++i) {
927
 
                                                                if (applicable[i].Kind != MemberKind.Operator) {
928
 
                                                                        continue;
929
 
                                                                }
930
 
 
931
 
                                                                if (found == null) {
932
 
                                                                        found = new List<MemberSpec> ();
933
 
                                                                        found.Add (applicable[i]);
934
 
                                                                } else {
935
 
                                                                        var prev = found as List<MemberSpec>;
936
 
                                                                        if (prev == null) {
937
 
                                                                                prev = new List<MemberSpec> (found.Count + 1);
938
 
                                                                                prev.AddRange (found);
939
 
                                                                        }
940
 
 
941
 
                                                                        prev.Add (applicable[i]);
942
 
                                                                }
943
 
                                                        }
944
 
                                                } else {
945
 
                                                        if (found == null) {
946
 
                                                                found = applicable;
947
 
                                                        } else {
948
 
                                                                var merged = found as List<MemberSpec>;
949
 
                                                                if (merged == null) {
950
 
                                                                        merged = new List<MemberSpec> (found.Count + applicable.Count);
951
 
                                                                        merged.AddRange (found);
952
 
                                                                        found = merged;
953
 
                                                                }
954
 
 
955
 
                                                                merged.AddRange (applicable);
956
 
                                                        }
957
 
                                                }
958
 
                                        }
959
 
                                }
960
 
 
961
 
                                // BaseType call can be expensive
962
 
                                if (declaredOnly)
963
 
                                        break;
964
 
 
965
 
                                container = container.BaseType;
966
 
                        } while (container != null);
967
 
 
968
 
                        return found;
969
 
                }
970
 
 
971
 
                //
972
 
                // Inflates all member cache nested types
973
 
                //
974
 
                public void InflateTypes (MemberCache inflated_cache, TypeParameterInflator inflator)
975
 
                {
976
 
                        foreach (var item in member_hash) {
977
 
                                IList<MemberSpec> inflated_members = null;
978
 
                                for (int i = 0; i < item.Value.Count; ++i ) {
979
 
                                        var member = item.Value[i];
980
 
 
981
 
                                        // FIXME: When inflating members refering nested types before they are inflated
982
 
                                        if (member == null)
983
 
                                                continue;
984
 
 
985
 
                                        if ((member.Kind & MemberKind.NestedMask) != 0 &&
986
 
                                                (member.Modifiers & Modifiers.COMPILER_GENERATED) == 0) {
987
 
                                                if (inflated_members == null) {
988
 
                                                        inflated_members = new MemberSpec[item.Value.Count];
989
 
                                                        inflated_cache.member_hash.Add (item.Key, inflated_members);
990
 
                                                }
991
 
 
992
 
                                                inflated_members [i] = member.InflateMember (inflator);
993
 
                                        }
994
 
                                }
995
 
                        }
996
 
                }
997
 
 
998
 
                //
999
 
                // Inflates all open type members, requires InflateTypes to be called before
1000
 
                //
1001
 
                public void InflateMembers (MemberCache cacheToInflate, TypeSpec inflatedType, TypeParameterInflator inflator)
1002
 
                {
1003
 
                        var inflated_member_hash = cacheToInflate.member_hash;
1004
 
                        Dictionary<MemberSpec, MethodSpec> accessor_relation = null;
1005
 
                        List<MemberSpec> accessor_members = null;
1006
 
 
1007
 
                        // Copy member specific flags when all members were added
1008
 
                        cacheToInflate.state = state;
1009
 
 
1010
 
                        foreach (var item in member_hash) {
1011
 
                                var members = item.Value;
1012
 
                                IList<MemberSpec> inflated_members = null;
1013
 
                                for (int i = 0; i < members.Count; ++i ) {
1014
 
                                        var member = members[i];
1015
 
 
1016
 
                                        //
1017
 
                                        // All nested types have been inflated earlier except for
1018
 
                                        // compiler types which are created later and could miss InflateTypes
1019
 
                                        //
1020
 
                                        if ((member.Kind & MemberKind.NestedMask) != 0 &&
1021
 
                                                (member.Modifiers & Modifiers.COMPILER_GENERATED) == 0) {
1022
 
                                                if (inflated_members == null)
1023
 
                                                        inflated_members = inflated_member_hash[item.Key];
1024
 
 
1025
 
                                                continue;
1026
 
                                        }
1027
 
 
1028
 
                                        //
1029
 
                                        // Clone the container first
1030
 
                                        //
1031
 
                                        if (inflated_members == null) {
1032
 
                                                inflated_members = new MemberSpec [item.Value.Count];
1033
 
                                                inflated_member_hash.Add (item.Key, inflated_members);
1034
 
                                        }
1035
 
 
1036
 
                                        var local_inflator = inflator;
1037
 
 
1038
 
                                        if (member.DeclaringType != inflatedType) {
1039
 
                                                //
1040
 
                                                // Don't inflate top-level non-generic interface members
1041
 
                                                // merged into generic interface
1042
 
                                                //
1043
 
                                                if (!member.DeclaringType.IsGeneric && !member.DeclaringType.IsNested) {
1044
 
                                                        inflated_members [i] = member;
1045
 
                                                        continue;
1046
 
                                                }
1047
 
 
1048
 
                                                //
1049
 
                                                // Needed when inflating flatten interfaces. It inflates
1050
 
                                                // container type only, type parameters are already done
1051
 
                                                //
1052
 
                                                // Handles cases like:
1053
 
                                                //
1054
 
                                                // interface I<T> {}
1055
 
                                                // interface I<U, V> : I<U> {}
1056
 
                                                // 
1057
 
                                                // class C: I<int, bool> {}
1058
 
                                                //
1059
 
                                                var inflated_parent = inflator.Inflate (member.DeclaringType);
1060
 
                                                if (inflated_parent != inflator.TypeInstance)
1061
 
                                                        local_inflator = new TypeParameterInflator (inflator, inflated_parent);
1062
 
                                        }
1063
 
 
1064
 
                                        //
1065
 
                                        // Inflate every member, its parent is now different
1066
 
                                        //
1067
 
                                        var inflated = member.InflateMember (local_inflator);
1068
 
                                        inflated_members [i] = inflated;
1069
 
 
1070
 
                                        if (member is PropertySpec || member is EventSpec) {
1071
 
                                                if (accessor_members == null)
1072
 
                                                        accessor_members = new List<MemberSpec> ();
1073
 
 
1074
 
                                                accessor_members.Add (inflated);
1075
 
                                                continue;
1076
 
                                        }
1077
 
 
1078
 
                                        if (member.IsAccessor) {
1079
 
                                                if (accessor_relation == null)
1080
 
                                                        accessor_relation = new Dictionary<MemberSpec, MethodSpec> ();
1081
 
                                                accessor_relation.Add (member, (MethodSpec) inflated);
1082
 
                                        }
1083
 
                                }
1084
 
                        }
1085
 
 
1086
 
                        if (accessor_members != null) {
1087
 
                                foreach (var member in accessor_members) {
1088
 
                                        var prop = member as PropertySpec;
1089
 
                                        if (prop != null) {
1090
 
                                                if (prop.Get != null)
1091
 
                                                        prop.Get = accessor_relation[prop.Get];
1092
 
                                                if (prop.Set != null)
1093
 
                                                        prop.Set = accessor_relation[prop.Set];
1094
 
 
1095
 
                                                continue;
1096
 
                                        }
1097
 
 
1098
 
                                        var ev = (EventSpec) member;
1099
 
                                        ev.AccessorAdd = accessor_relation[ev.AccessorAdd];
1100
 
                                        ev.AccessorRemove = accessor_relation[ev.AccessorRemove];
1101
 
                                }
1102
 
                        }
1103
 
                }
1104
 
 
1105
 
                //
1106
 
                // Removes hidden base members of an interface. For compiled interfaces we cannot
1107
 
                // do name filtering during Add (as we do for import) because we need all base
1108
 
                // names to be valid during type definition.
1109
 
                // Add replaces hidden base member with current one which means any name collision
1110
 
                // (CS0108) of non-first name would be unnoticed because the name was replaced
1111
 
                // with the one from compiled type
1112
 
                //
1113
 
                public void RemoveHiddenMembers (TypeSpec container)
1114
 
                {
1115
 
                        foreach (var entry in member_hash) {
1116
 
                                var values = entry.Value;
1117
 
 
1118
 
                                int container_members_start_at = 0;
1119
 
                                while (values[container_members_start_at].DeclaringType != container && ++container_members_start_at < entry.Value.Count);
1120
 
 
1121
 
                                if (container_members_start_at == 0 || container_members_start_at == values.Count)
1122
 
                                        continue;
1123
 
 
1124
 
                                for (int i = 0; i < container_members_start_at; ++i) {
1125
 
                                        var member = values[i];
1126
 
 
1127
 
                                        if (!container.ImplementsInterface (member.DeclaringType, false))
1128
 
                                                continue;
1129
 
 
1130
 
                                        var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : ParametersCompiled.EmptyReadOnlyParameters;
1131
 
 
1132
 
                                        for (int ii = container_members_start_at; ii < values.Count; ++ii) {
1133
 
                                                var container_entry = values[ii];
1134
 
 
1135
 
                                                if (container_entry.Arity != member.Arity)
1136
 
                                                        continue;
1137
 
 
1138
 
                                                if (container_entry is IParametersMember) {
1139
 
                                                        if (!TypeSpecComparer.Override.IsEqual (((IParametersMember) container_entry).Parameters, member_param))
1140
 
                                                                continue;
1141
 
                                                }
1142
 
 
1143
 
                                                values.RemoveAt (i);
1144
 
                                                --container_members_start_at;
1145
 
                                                --ii;
1146
 
                                                --i;
1147
 
                                        }
1148
 
                                }
1149
 
                        }
1150
 
                }
1151
 
 
1152
 
                //
1153
 
                // Checks all appropriate container members for CLS compliance
1154
 
                //
1155
 
                public void VerifyClsCompliance (TypeSpec container, Report report)
1156
 
                {
1157
 
                        if (locase_members != null)
1158
 
                                return;
1159
 
 
1160
 
                        if (container.BaseType == null) {
1161
 
                                locase_members = new Dictionary<string, MemberSpec[]> (member_hash.Count); // StringComparer.OrdinalIgnoreCase);
1162
 
                        } else {
1163
 
                                var btype = container.BaseType.GetDefinition ();
1164
 
                                btype.MemberCache.VerifyClsCompliance (btype, report);
1165
 
                                locase_members = new Dictionary<string, MemberSpec[]> (btype.MemberCache.locase_members); //, StringComparer.OrdinalIgnoreCase);
1166
 
                        }
1167
 
 
1168
 
                        var is_imported_type = container.MemberDefinition.IsImported;
1169
 
                        foreach (var entry in container.MemberCache.member_hash) {
1170
 
                                for (int i = 0; i < entry.Value.Count; ++i ) {
1171
 
                                        var name_entry = entry.Value[i];
1172
 
                                        if ((name_entry.Modifiers & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
1173
 
                                                continue;
1174
 
 
1175
 
                                        if ((name_entry.Modifiers & (Modifiers.OVERRIDE | Modifiers.COMPILER_GENERATED)) != 0)
1176
 
                                                continue;
1177
 
 
1178
 
                                        if ((name_entry.Kind & MemberKind.MaskType) == 0)
1179
 
                                                continue;
1180
 
 
1181
 
                                        if (name_entry.MemberDefinition.CLSAttributeValue == false)
1182
 
                                            continue;
1183
 
 
1184
 
                                        IParametersMember p_a = null;
1185
 
                                        if (!is_imported_type) {
1186
 
                                                p_a = name_entry as IParametersMember;
1187
 
                                                if (p_a != null && !name_entry.IsAccessor) {
1188
 
                                                        var p_a_pd = p_a.Parameters;
1189
 
                                                        //
1190
 
                                                        // Check differing overloads in @container
1191
 
                                                        //
1192
 
                                                        for (int ii = i + 1; ii < entry.Value.Count; ++ii) {
1193
 
                                                                var checked_entry = entry.Value[ii];
1194
 
                                                                IParametersMember p_b = checked_entry as IParametersMember;
1195
 
                                                                if (p_b == null)
1196
 
                                                                        continue;
1197
 
 
1198
 
                                                                if (p_a_pd.Count != p_b.Parameters.Count)
1199
 
                                                                        continue;
1200
 
 
1201
 
                                                                if (checked_entry.IsAccessor)
1202
 
                                                                        continue;
1203
 
 
1204
 
                                                                var res = ParametersCompiled.IsSameClsSignature (p_a.Parameters, p_b.Parameters);
1205
 
                                                                if (res != 0) {
1206
 
                                                                        ReportOverloadedMethodClsDifference (name_entry, checked_entry, res, report);
1207
 
                                                                }
1208
 
                                                        }
1209
 
                                                }
1210
 
                                        }
1211
 
 
1212
 
                                        if (i > 0 || name_entry.Kind == MemberKind.Constructor || name_entry.Kind == MemberKind.Indexer)
1213
 
                                                continue;
1214
 
 
1215
 
                                        var name_entry_locase = name_entry.Name.ToLowerInvariant ();
1216
 
 
1217
 
                                        MemberSpec[] found;
1218
 
                                        if (!locase_members.TryGetValue (name_entry_locase, out found)) {
1219
 
                                                found = new MemberSpec[] { name_entry };
1220
 
                                                locase_members.Add (name_entry_locase, found);
1221
 
                                        } else {
1222
 
                                                bool same_names_only = true;
1223
 
                                                foreach (var f in found) {
1224
 
                                                        if (f.Name == name_entry.Name) {
1225
 
                                                                if (p_a != null) {
1226
 
                                                                        IParametersMember p_b = f as IParametersMember;
1227
 
                                                                        if (p_b == null)
1228
 
                                                                                continue;
1229
 
 
1230
 
                                                                        if (p_a.Parameters.Count != p_b.Parameters.Count)
1231
 
                                                                                continue;
1232
 
 
1233
 
                                                                        if (f.IsAccessor)
1234
 
                                                                                continue;
1235
 
 
1236
 
                                                                        var res = ParametersCompiled.IsSameClsSignature (p_a.Parameters, p_b.Parameters);
1237
 
                                                                        if (res != 0) {
1238
 
                                                                                ReportOverloadedMethodClsDifference (f, name_entry, res, report);
1239
 
                                                                        }
1240
 
                                                                }
1241
 
 
1242
 
                                                                continue;
1243
 
                                                        }
1244
 
 
1245
 
                                                        same_names_only = false;
1246
 
                                                        if (!is_imported_type) {
1247
 
                                                                var last = GetLaterDefinedMember (f, name_entry);
1248
 
                                                                if (last == f.MemberDefinition) {
1249
 
                                                                        report.SymbolRelatedToPreviousError (name_entry);
1250
 
                                                                } else {
1251
 
                                                                        report.SymbolRelatedToPreviousError (f);
1252
 
                                                                }
1253
 
 
1254
 
                                                                report.Warning (3005, 1, last.Location,
1255
 
                                                                        "Identifier `{0}' differing only in case is not CLS-compliant", last.GetSignatureForError ());
1256
 
                                                        }
1257
 
                                                }
1258
 
 
1259
 
                                                if (!same_names_only) {
1260
 
                                                        Array.Resize (ref found, found.Length + 1);
1261
 
                                                        found[found.Length - 1] = name_entry;
1262
 
                                                        locase_members[name_entry_locase] = found;
1263
 
                                                }
1264
 
                                        }
1265
 
                                }
1266
 
                        }
1267
 
                }
1268
 
 
1269
 
                //
1270
 
                // Local report helper to issue correctly ordered members stored in hashtable
1271
 
                //
1272
 
                static MemberCore GetLaterDefinedMember (MemberSpec a, MemberSpec b)
1273
 
                {
1274
 
                        var mc_a = a.MemberDefinition as MemberCore;
1275
 
                        var mc_b = b.MemberDefinition as MemberCore;
1276
 
                        if (mc_a == null)
1277
 
                                return mc_b;
1278
 
 
1279
 
                        if (mc_b == null)
1280
 
                                return mc_a;
1281
 
 
1282
 
                        if (a.DeclaringType.MemberDefinition != b.DeclaringType.MemberDefinition)
1283
 
                                return mc_b;
1284
 
 
1285
 
                        if (mc_a.Location.File != mc_a.Location.File)
1286
 
                                return mc_b;
1287
 
 
1288
 
                        return mc_b.Location.Row > mc_a.Location.Row ? mc_b : mc_a;
1289
 
                }
1290
 
 
1291
 
                static void ReportOverloadedMethodClsDifference (MemberSpec a, MemberSpec b, int res, Report report)
1292
 
                {
1293
 
                        var last = GetLaterDefinedMember (a, b);
1294
 
                        if (last == a.MemberDefinition) {
1295
 
                                report.SymbolRelatedToPreviousError (b);
1296
 
                        } else {
1297
 
                                report.SymbolRelatedToPreviousError (a);
1298
 
                        }
1299
 
 
1300
 
                        if ((res & 1) != 0) {
1301
 
                                report.Warning (3006, 1, last.Location,
1302
 
                                                "Overloaded method `{0}' differing only in ref or out, or in array rank, is not CLS-compliant",
1303
 
                                                last.GetSignatureForError ());
1304
 
                        }
1305
 
 
1306
 
                        if ((res & 2) != 0) {
1307
 
                                report.Warning (3007, 1, last.Location,
1308
 
                                        "Overloaded method `{0}' differing only by unnamed array types is not CLS-compliant",
1309
 
                                        last.GetSignatureForError ());
1310
 
                        }
1311
 
                }
1312
 
 
1313
 
                public bool CheckExistingMembersOverloads (MemberCore member, AParametersCollection parameters)
1314
 
                {
1315
 
                        var name = GetLookupName (member);
1316
 
                        var imb = member as InterfaceMemberBase;
1317
 
                        if (imb != null && imb.IsExplicitImpl) {
1318
 
                                name = imb.GetFullName (name);
1319
 
                        }
1320
 
 
1321
 
                        return CheckExistingMembersOverloads (member, name, parameters);
1322
 
                }
1323
 
 
1324
 
                public bool CheckExistingMembersOverloads (MemberCore member, string name, AParametersCollection parameters)
1325
 
                {
1326
 
                        IList<MemberSpec> entries;
1327
 
                        if (!member_hash.TryGetValue (name, out entries))
1328
 
                                return false;
1329
 
 
1330
 
                        var Report = member.Compiler.Report;
1331
 
 
1332
 
                        int method_param_count = parameters.Count;
1333
 
                        for (int i = entries.Count - 1; i >= 0; --i) {
1334
 
                                var ce = entries[i];
1335
 
                                var pm = ce as IParametersMember;
1336
 
                                var pd = pm == null ? ParametersCompiled.EmptyReadOnlyParameters : pm.Parameters;
1337
 
                                if (pd.Count != method_param_count)
1338
 
                                        continue;
1339
 
 
1340
 
                                if (ce.Arity != member.MemberName.Arity)
1341
 
                                        continue;
1342
 
 
1343
 
                                // Ignore merged interface members
1344
 
                                if (member.Parent.PartialContainer != ce.DeclaringType.MemberDefinition)
1345
 
                                        continue;
1346
 
 
1347
 
                                var p_types = pd.Types;
1348
 
                                if (method_param_count > 0) {
1349
 
                                        int ii = method_param_count - 1;
1350
 
                                        TypeSpec type_a, type_b;
1351
 
                                        do {
1352
 
                                                type_a = parameters.Types [ii];
1353
 
                                                type_b = p_types [ii];
1354
 
 
1355
 
                                                var a_byref = (pd.FixedParameters[ii].ModFlags & Parameter.Modifier.RefOutMask) != 0;
1356
 
                                                var b_byref = (parameters.FixedParameters[ii].ModFlags & Parameter.Modifier.RefOutMask) != 0;
1357
 
 
1358
 
                                                if (a_byref != b_byref)
1359
 
                                                        break;
1360
 
 
1361
 
                                        } while (TypeSpecComparer.Override.IsEqual (type_a, type_b) && ii-- != 0);
1362
 
 
1363
 
                                        if (ii >= 0)
1364
 
                                                continue;
1365
 
 
1366
 
                                        //
1367
 
                                        // Operators can differ in return type only
1368
 
                                        //
1369
 
                                        if (member is Operator && ce.Kind == MemberKind.Operator && ((MethodSpec) ce).ReturnType != ((Operator) member).ReturnType)
1370
 
                                                continue;
1371
 
 
1372
 
                                        //
1373
 
                                        // Report difference in parameter modifiers only
1374
 
                                        //
1375
 
                                        if (pd != null && member is MethodCore) {
1376
 
                                                ii = method_param_count;
1377
 
                                                while (ii-- != 0 &&
1378
 
                                                        (parameters.FixedParameters[ii].ModFlags & Parameter.Modifier.ModifierMask) ==
1379
 
                                                        (pd.FixedParameters[ii].ModFlags & Parameter.Modifier.ModifierMask) &&
1380
 
                                                        parameters.ExtensionMethodType == pd.ExtensionMethodType) ;
1381
 
 
1382
 
                                                if (ii >= 0) {
1383
 
                                                        var mc = ce as MethodSpec;
1384
 
                                                        member.Compiler.Report.SymbolRelatedToPreviousError (ce);
1385
 
                                                        if ((member.ModFlags & Modifiers.PARTIAL) != 0 && (mc.Modifiers & Modifiers.PARTIAL) != 0) {
1386
 
                                                                if (parameters.HasParams || pd.HasParams) {
1387
 
                                                                        Report.Error (758, member.Location,
1388
 
                                                                                "A partial method declaration and partial method implementation cannot differ on use of `params' modifier");
1389
 
                                                                } else {
1390
 
                                                                        Report.Error (755, member.Location,
1391
 
                                                                                "A partial method declaration and partial method implementation must be both an extension method or neither");
1392
 
                                                                }
1393
 
                                                        } else if (member is Constructor) {
1394
 
                                                                Report.Error (851, member.Location,
1395
 
                                                                        "Overloaded contructor `{0}' cannot differ on use of parameter modifiers only",
1396
 
                                                                        member.GetSignatureForError ());
1397
 
                                                        } else {
1398
 
                                                                Report.Error (663, member.Location,
1399
 
                                                                        "Overloaded method `{0}' cannot differ on use of parameter modifiers only",
1400
 
                                                                        member.GetSignatureForError ());
1401
 
                                                        }
1402
 
                                                        return false;
1403
 
                                                }
1404
 
                                        }
1405
 
                                }
1406
 
 
1407
 
                                if ((ce.Kind & MemberKind.Method) != 0) {
1408
 
                                        Method method_a = member as Method;
1409
 
                                        Method method_b = ce.MemberDefinition as Method;
1410
 
                                        if (method_a != null && method_b != null && (method_a.ModFlags & method_b.ModFlags & Modifiers.PARTIAL) != 0) {
1411
 
                                                const Modifiers partial_modifiers = Modifiers.STATIC | Modifiers.UNSAFE;
1412
 
                                                if (method_a.IsPartialDefinition == method_b.IsPartialImplementation) {
1413
 
                                                        if ((method_a.ModFlags & partial_modifiers) == (method_b.ModFlags & partial_modifiers) ||
1414
 
                                                                method_a.Parent.IsUnsafe && method_b.Parent.IsUnsafe) {
1415
 
                                                                if (method_a.IsPartialImplementation) {
1416
 
                                                                        method_a.SetPartialDefinition (method_b);
1417
 
                                                                        if (entries.Count == 1)
1418
 
                                                                                member_hash.Remove (name);
1419
 
                                                                        else
1420
 
                                                                                entries.RemoveAt (i);
1421
 
                                                                } else {
1422
 
                                                                        method_b.SetPartialDefinition (method_a);
1423
 
                                                                        method_a.caching_flags |= MemberCore.Flags.PartialDefinitionExists;
1424
 
                                                                }
1425
 
                                                                continue;
1426
 
                                                        }
1427
 
 
1428
 
                                                        if (method_a.IsStatic != method_b.IsStatic) {
1429
 
                                                                Report.SymbolRelatedToPreviousError (ce);
1430
 
                                                                Report.Error (763, member.Location,
1431
 
                                                                        "A partial method declaration and partial method implementation must be both `static' or neither");
1432
 
                                                        }
1433
 
 
1434
 
                                                        Report.SymbolRelatedToPreviousError (ce);
1435
 
                                                        Report.Error (764, member.Location,
1436
 
                                                                "A partial method declaration and partial method implementation must be both `unsafe' or neither");
1437
 
                                                        return false;
1438
 
                                                }
1439
 
 
1440
 
                                                Report.SymbolRelatedToPreviousError (ce);
1441
 
                                                if (method_a.IsPartialDefinition) {
1442
 
                                                        Report.Error (756, member.Location, "A partial method `{0}' declaration is already defined",
1443
 
                                                                member.GetSignatureForError ());
1444
 
                                                }
1445
 
 
1446
 
                                                Report.Error (757, member.Location, "A partial method `{0}' implementation is already defined",
1447
 
                                                        member.GetSignatureForError ());
1448
 
                                                return false;
1449
 
                                        }
1450
 
 
1451
 
                                        Report.SymbolRelatedToPreviousError (ce);
1452
 
 
1453
 
                                        bool is_reserved_a = member is AbstractPropertyEventMethod || member is Operator;
1454
 
                                        bool is_reserved_b = ((MethodSpec) ce).IsReservedMethod;
1455
 
 
1456
 
                                        if (is_reserved_a || is_reserved_b) {
1457
 
                                                Report.Error (82, member.Location, "A member `{0}' is already reserved",
1458
 
                                                        is_reserved_a ?
1459
 
                                                        ce.GetSignatureForError () :
1460
 
                                                        member.GetSignatureForError ());
1461
 
                                                return false;
1462
 
                                        }
1463
 
                                } else {
1464
 
                                        Report.SymbolRelatedToPreviousError (ce);
1465
 
                                }
1466
 
 
1467
 
                                if (member is Operator && ce.Kind == MemberKind.Operator) {
1468
 
                                        Report.Error (557, member.Location, "Duplicate user-defined conversion in type `{0}'",
1469
 
                                                member.Parent.GetSignatureForError ());
1470
 
                                        return false;
1471
 
                                }
1472
 
 
1473
 
                                Report.Error (111, member.Location,
1474
 
                                        "A member `{0}' is already defined. Rename this member or use different parameter types",
1475
 
                                        member.GetSignatureForError ());
1476
 
                                return false;
1477
 
                        }
1478
 
 
1479
 
                        return true;
1480
 
                }
1481
 
        }
1482
 
}