Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / mcs / namespace.cs
1 //
2 // namespace.cs: Tracks namespaces
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Marek Safar (marek.safar@seznam.cz)
7 //
8 // Copyright 2001 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc
11 //
12 using System;
13 using System.Collections.Generic;
14 using System.Linq;
15 using Mono.CompilerServices.SymbolWriter;
16
17 namespace Mono.CSharp {
18
19         public class RootNamespace : Namespace {
20
21                 readonly string alias_name;
22                 readonly Dictionary<string, Namespace> all_namespaces;
23
24                 public RootNamespace (string alias_name)
25                         : base ()
26                 {
27                         this.alias_name = alias_name;
28                         RegisterNamespace (this);
29
30                         all_namespaces = new Dictionary<string, Namespace> ();
31                         all_namespaces.Add ("", this);
32                 }
33
34                 public string Alias {
35                         get {
36                                 return alias_name;
37                         }
38                 }
39
40                 public static void Error_GlobalNamespaceRedefined (Report report, Location loc)
41                 {
42                         report.Error (1681, loc, "The global extern alias cannot be redefined");
43                 }
44
45                 //
46                 // For better error reporting where we try to guess missing using directive
47                 //
48                 public List<string> FindTypeNamespaces (IMemberContext ctx, string name, int arity)
49                 {
50                         List<string> res = null;
51
52                         foreach (var ns in all_namespaces) {
53                                 var type = ns.Value.LookupType (ctx, name, arity, LookupMode.Normal, Location.Null);
54                                 if (type != null) {
55                                         if (res == null)
56                                                 res = new List<string> ();
57
58                                         res.Add (ns.Key);
59                                 }
60                         }
61
62                         return res;
63                 }
64
65                 //
66                 // For better error reporting where compiler tries to guess missing using directive
67                 //
68                 public List<string> FindExtensionMethodNamespaces (IMemberContext ctx, string name, int arity)
69                 {
70                         List<string> res = null;
71
72                         foreach (var ns in all_namespaces) {
73                                 var methods = ns.Value.LookupExtensionMethod (ctx, name, arity);
74                                 if (methods != null) {
75                                         if (res == null)
76                                                 res = new List<string> ();
77
78                                         res.Add (ns.Key);
79                                 }
80                         }
81
82                         return res;
83                 }
84
85                 public void RegisterNamespace (Namespace child)
86                 {
87                         if (child != this)
88                                 all_namespaces.Add (child.Name, child);
89                 }
90
91                 public override string GetSignatureForError ()
92                 {
93                         return alias_name + "::";
94                 }
95         }
96
97         public sealed class GlobalRootNamespace : RootNamespace
98         {
99                 public GlobalRootNamespace ()
100                         : base ("global")
101                 {
102                 }
103         }
104
105         //
106         // Namespace cache for imported and compiled namespaces
107         //
108         public class Namespace
109         {
110                 readonly Namespace parent;
111                 string fullname;
112                 protected Dictionary<string, Namespace> namespaces;
113                 protected Dictionary<string, IList<TypeSpec>> types;
114                 List<TypeSpec> extension_method_types;
115                 Dictionary<string, TypeSpec> cached_types;
116                 bool cls_checked;
117
118                 /// <summary>
119                 ///   Constructor Takes the current namespace and the
120                 ///   name.  This is bootstrapped with parent == null
121                 ///   and name = ""
122                 /// </summary>
123                 public Namespace (Namespace parent, string name)
124                         : this ()
125                 {
126                         if (name == null)
127                                 throw new ArgumentNullException ("name");
128
129                         this.parent = parent;
130
131                         string pname = parent != null ? parent.fullname : null;
132                                 
133                         if (pname == null)
134                                 fullname = name;
135                         else
136                                 fullname = pname + "." + name;
137
138                         while (parent.parent != null)
139                                 parent = parent.parent;
140
141                         var root = parent as RootNamespace;
142                         if (root == null)
143                                 throw new InternalErrorException ("Root namespaces must be created using RootNamespace");
144
145                         root.RegisterNamespace (this);
146                 }
147
148                 protected Namespace ()
149                 {
150                         namespaces = new Dictionary<string, Namespace> ();
151                         cached_types = new Dictionary<string, TypeSpec> ();
152                 }
153
154                 #region Properties
155
156                 /// <summary>
157                 ///   The qualified name of the current namespace
158                 /// </summary>
159                 public string Name {
160                         get { return fullname; }
161                 }
162
163                 /// <summary>
164                 ///   The parent of this namespace, used by the parser to "Pop"
165                 ///   the current namespace declaration
166                 /// </summary>
167                 public Namespace Parent {
168                         get { return parent; }
169                 }
170
171                 #endregion
172
173                 public Namespace AddNamespace (MemberName name)
174                 {
175                         var ns_parent = name.Left == null ? this : AddNamespace (name.Left);
176                         return ns_parent.TryAddNamespace (name.Basename);
177                 }
178
179                 Namespace TryAddNamespace (string name)
180                 {
181                         Namespace ns;
182
183                         if (!namespaces.TryGetValue (name, out ns)) {
184                                 ns = new Namespace (this, name);
185                                 namespaces.Add (name, ns);
186                         }
187
188                         return ns;
189                 }
190
191                 public bool TryGetNamespace (string name, out Namespace ns)
192                 {
193                         return namespaces.TryGetValue (name, out ns);
194                 }
195
196                 // TODO: Replace with CreateNamespace where MemberName is created for the method call
197                 public Namespace GetNamespace (string name, bool create)
198                 {
199                         int pos = name.IndexOf ('.');
200
201                         Namespace ns;
202                         string first;
203                         if (pos >= 0)
204                                 first = name.Substring (0, pos);
205                         else
206                                 first = name;
207
208                         if (!namespaces.TryGetValue (first, out ns)) {
209                                 if (!create)
210                                         return null;
211
212                                 ns = new Namespace (this, first);
213                                 namespaces.Add (first, ns);
214                         }
215
216                         if (pos >= 0)
217                                 ns = ns.GetNamespace (name.Substring (pos + 1), create);
218
219                         return ns;
220                 }
221
222                 public IList<TypeSpec> GetAllTypes (string name)
223                 {
224                         IList<TypeSpec> found;
225                         if (types == null || !types.TryGetValue (name, out found))
226                                 return null;
227
228                         return found;
229                 }
230
231                 public virtual string GetSignatureForError ()
232                 {
233                         return fullname;
234                 }
235
236                 public TypeSpec LookupType (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
237                 {
238                         if (types == null)
239                                 return null;
240
241                         TypeSpec best = null;
242                         if (arity == 0 && cached_types.TryGetValue (name, out best)) {
243                                 if (best != null || mode != LookupMode.IgnoreAccessibility)
244                                         return best;
245                         }
246
247                         IList<TypeSpec> found;
248                         if (!types.TryGetValue (name, out found))
249                                 return null;
250
251                         foreach (var ts in found) {
252                                 if (ts.Arity == arity) {
253                                         if (best == null) {
254                                                 if ((ts.Modifiers & Modifiers.INTERNAL) != 0 && !ts.MemberDefinition.IsInternalAsPublic (ctx.Module.DeclaringAssembly) && mode != LookupMode.IgnoreAccessibility)
255                                                         continue;
256
257                                                 best = ts;
258                                                 continue;
259                                         }
260
261                                         if (best.MemberDefinition.IsImported && ts.MemberDefinition.IsImported) {
262                                                 if (ts.Kind == MemberKind.MissingType)
263                                                         continue;
264
265                                                 if (best.Kind == MemberKind.MissingType) {
266                                                         best = ts;
267                                                         continue;
268                                                 }
269
270                                                 if (mode == LookupMode.Normal) {
271                                                         ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (best);
272                                                         ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (ts);
273                                                         ctx.Module.Compiler.Report.Error (433, loc, "The imported type `{0}' is defined multiple times", ts.GetSignatureForError ());
274                                                 }
275
276                                                 break;
277                                         }
278
279                                         if (best.MemberDefinition.IsImported)
280                                                 best = ts;
281
282                                         if ((best.Modifiers & Modifiers.INTERNAL) != 0 && !best.MemberDefinition.IsInternalAsPublic (ctx.Module.DeclaringAssembly))
283                                                 continue;
284
285                                         if (mode != LookupMode.Normal)
286                                                 continue;
287
288                                         if (ts.MemberDefinition.IsImported) {
289                                                 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (best);
290                                                 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (ts);
291                                         }
292
293                                         ctx.Module.Compiler.Report.Warning (436, 2, loc,
294                                                 "The type `{0}' conflicts with the imported type of same name'. Ignoring the imported type definition",
295                                                 best.GetSignatureForError ());
296                                 }
297
298                                 //
299                                 // Lookup for the best candidate with the closest arity match
300                                 //
301                                 if (arity < 0) {
302                                         if (best == null) {
303                                                 best = ts;
304                                         } else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (best.Arity + arity)) {
305                                                 best = ts;
306                                         }
307                                 }
308                         }
309
310                         // TODO MemberCache: Cache more
311                         if (arity == 0 && mode == LookupMode.Normal)
312                                 cached_types.Add (name, best);
313
314                         return best;
315                 }
316
317                 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
318                 {
319                         var texpr = LookupType (ctx, name, arity, mode, loc);
320
321                         Namespace ns;
322                         if (arity == 0 && namespaces.TryGetValue (name, out ns)) {
323                                 if (texpr == null)
324                                         return new NamespaceExpression (ns, loc);
325
326                                 if (mode != LookupMode.Probing) {
327                                         //ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (texpr.Type);
328                                         // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (ns.loc, "");
329                                         ctx.Module.Compiler.Report.Warning (437, 2, loc,
330                                                 "The type `{0}' conflicts with the imported namespace `{1}'. Using the definition found in the source file",
331                                                 texpr.GetSignatureForError (), ns.GetSignatureForError ());
332                                 }
333
334                                 if (texpr.MemberDefinition.IsImported)
335                                         return new NamespaceExpression (ns, loc);
336                         }
337
338                         if (texpr == null)
339                                 return null;
340
341                         return new TypeExpression (texpr, loc);
342                 }
343
344                 //
345                 // Completes types with the given `prefix'
346                 //
347                 public IEnumerable<string> CompletionGetTypesStartingWith (string prefix)
348                 {
349                         if (types == null)
350                                 return Enumerable.Empty<string> ();
351
352                         var res = from item in types
353                                           where item.Key.StartsWith (prefix) && item.Value.Any (l => (l.Modifiers & Modifiers.PUBLIC) != 0)
354                                           select item.Key;
355
356                         if (namespaces != null)
357                                 res = res.Concat (from item in namespaces where item.Key.StartsWith (prefix) select item.Key);
358
359                         return res;
360                 }
361
362                 // 
363                 // Looks for extension method in this namespace
364                 //
365                 public List<MethodSpec> LookupExtensionMethod (IMemberContext invocationContext, string name, int arity)
366                 {
367                         if (extension_method_types == null)
368                                 return null;
369
370                         List<MethodSpec> found = null;
371                         for (int i = 0; i < extension_method_types.Count; ++i) {
372                                 var ts = extension_method_types[i];
373
374                                 //
375                                 // When the list was built we didn't know what members the type
376                                 // contains
377                                 //
378                                 if ((ts.Modifiers & Modifiers.METHOD_EXTENSION) == 0) {
379                                         if (extension_method_types.Count == 1) {
380                                                 extension_method_types = null;
381                                                 return found;
382                                         }
383
384                                         extension_method_types.RemoveAt (i--);
385                                         continue;
386                                 }
387
388                                 var res = ts.MemberCache.FindExtensionMethods (invocationContext, name, arity);
389                                 if (res == null)
390                                         continue;
391
392                                 if (found == null) {
393                                         found = res;
394                                 } else {
395                                         found.AddRange (res);
396                                 }
397                         }
398
399                         return found;
400                 }
401
402                 public void AddType (ModuleContainer module, TypeSpec ts)
403                 {
404                         if (types == null) {
405                                 types = new Dictionary<string, IList<TypeSpec>> (64);
406                         }
407
408                         if (ts.IsClass && ts.Arity == 0) {
409                                 var extension_method_allowed = ts.MemberDefinition.IsImported ? (ts.Modifiers & Modifiers.METHOD_EXTENSION) != 0 : (ts.IsStatic || ts.MemberDefinition.IsPartial);
410                                 if (extension_method_allowed) {
411                                         if (extension_method_types == null)
412                                                 extension_method_types = new List<TypeSpec> ();
413
414                                         extension_method_types.Add (ts);
415                                 }
416                         }
417
418                         var name = ts.Name;
419                         IList<TypeSpec> existing;
420                         if (types.TryGetValue (name, out existing)) {
421                                 TypeSpec better_type;
422                                 TypeSpec found;
423                                 if (existing.Count == 1) {
424                                         found = existing[0];
425                                         if (ts.Arity == found.Arity) {
426                                                 better_type = IsImportedTypeOverride (module, ts, found);
427                                                 if (better_type == found)
428                                                         return;
429
430                                                 if (better_type != null) {
431                                                         existing [0] = better_type;
432                                                         return;
433                                                 }
434                                         }
435
436                                         existing = new List<TypeSpec> ();
437                                         existing.Add (found);
438                                         types[name] = existing;
439                                 } else {
440                                         for (int i = 0; i < existing.Count; ++i) {
441                                                 found = existing[i];
442                                                 if (ts.Arity != found.Arity)
443                                                         continue;
444
445                                                 better_type = IsImportedTypeOverride (module, ts, found);
446                                                 if (better_type == found)
447                                                         return;
448
449                                                 if (better_type != null) {
450                                                         existing.RemoveAt (i);
451                                                         --i;
452                                                         continue;
453                                                 }
454                                         }
455                                 }
456
457                                 existing.Add (ts);
458                         } else {
459                                 types.Add (name, new TypeSpec[] { ts });
460                         }
461                 }
462
463                 //
464                 // We import any types but in the situation there are same types
465                 // but one has better visibility (either public or internal with friend)
466                 // the less visible type is removed from the namespace cache
467                 //
468                 public static TypeSpec IsImportedTypeOverride (ModuleContainer module, TypeSpec ts, TypeSpec found)
469                 {
470                         var ts_accessible = (ts.Modifiers & Modifiers.PUBLIC) != 0 || ts.MemberDefinition.IsInternalAsPublic (module.DeclaringAssembly);
471                         var found_accessible = (found.Modifiers & Modifiers.PUBLIC) != 0 || found.MemberDefinition.IsInternalAsPublic (module.DeclaringAssembly);
472
473                         if (ts_accessible && !found_accessible)
474                                 return ts;
475
476                         // found is better always better for accessible or inaccessible ts
477                         if (!ts_accessible)
478                                 return found;
479
480                         return null;
481                 }
482
483                 public void RemoveContainer (TypeContainer tc)
484                 {
485                         types.Remove (tc.Basename);
486                         cached_types.Remove (tc.Basename);
487                 }
488
489                 public void SetBuiltinType (BuiltinTypeSpec pts)
490                 {
491                         var found = types[pts.Name];
492                         cached_types.Remove (pts.Name);
493                         if (found.Count == 1) {
494                                 types[pts.Name][0] = pts;
495                         } else {
496                                 throw new NotImplementedException ();
497                         }
498                 }
499
500                 public void VerifyClsCompliance ()
501                 {
502                         if (types == null || cls_checked)
503                                 return;
504
505                         cls_checked = true;
506
507                         // TODO: This is quite ugly way to check for CLS compliance at namespace level
508
509                         var locase_types = new Dictionary<string, List<TypeSpec>> (StringComparer.OrdinalIgnoreCase);
510                         foreach (var tgroup in types.Values) {
511                                 foreach (var tm in tgroup) {
512                                         if ((tm.Modifiers & Modifiers.PUBLIC) == 0 || !tm.IsCLSCompliant ())
513                                                 continue;
514
515                                         List<TypeSpec> found;
516                                         if (!locase_types.TryGetValue (tm.Name, out found)) {
517                                                 found = new List<TypeSpec> ();
518                                                 locase_types.Add (tm.Name, found);
519                                         }
520
521                                         found.Add (tm);
522                                 }
523                         }
524
525                         foreach (var locase in locase_types.Values) {
526                                 if (locase.Count < 2)
527                                         continue;
528
529                                 bool all_same = true;
530                                 foreach (var notcompliant in locase) {
531                                         all_same = notcompliant.Name == locase[0].Name;
532                                         if (!all_same)
533                                                 break;
534                                 }
535
536                                 if (all_same)
537                                         continue;
538
539                                 TypeContainer compiled = null;
540                                 foreach (var notcompliant in locase) {
541                                         if (!notcompliant.MemberDefinition.IsImported) {
542                                                 if (compiled != null)
543                                                         compiled.Compiler.Report.SymbolRelatedToPreviousError (compiled);
544
545                                                 compiled = notcompliant.MemberDefinition as TypeContainer;
546                                         } else {
547                                                 compiled.Compiler.Report.SymbolRelatedToPreviousError (notcompliant);
548                                         }
549                                 }
550
551                                 compiled.Compiler.Report.Warning (3005, 1, compiled.Location,
552                                         "Identifier `{0}' differing only in case is not CLS-compliant", compiled.GetSignatureForError ());
553                         }
554                 }
555         }
556
557         public class CompilationSourceFile : NamespaceContainer
558         {
559                 readonly SourceFile file;
560                 CompileUnitEntry comp_unit;
561                 Dictionary<string, SourceFile> include_files;
562                 Dictionary<string, bool> conditionals;
563
564                 public CompilationSourceFile (ModuleContainer parent, SourceFile sourceFile)
565                         : this (parent)
566                 {
567                         this.file = sourceFile;
568                 }
569
570                 public CompilationSourceFile (ModuleContainer parent)
571                         : base (parent)
572                 {
573                 }
574
575                 public CompileUnitEntry SymbolUnitEntry {
576                         get {
577                                 return comp_unit;
578                         }
579                 }
580
581                 public string FileName {
582                         get {
583                                 return file.Name;
584                         }
585                 }
586
587                 public SourceFile SourceFile {
588                         get {
589                                 return file;
590                         }
591                 }
592
593                 public void AddIncludeFile (SourceFile file)
594                 {
595                         if (file == this.file)
596                                 return;
597
598                         if (include_files == null)
599                                 include_files = new Dictionary<string, SourceFile> ();
600
601                         if (!include_files.ContainsKey (file.FullPathName))
602                                 include_files.Add (file.FullPathName, file);
603                 }
604
605                 public void AddDefine (string value)
606                 {
607                         if (conditionals == null)
608                                 conditionals = new Dictionary<string, bool> (2);
609
610                         conditionals[value] = true;
611                 }
612
613                 public void AddUndefine (string value)
614                 {
615                         if (conditionals == null)
616                                 conditionals = new Dictionary<string, bool> (2);
617
618                         conditionals[value] = false;
619                 }
620
621                 public override void PrepareEmit ()
622                 {
623                         var sw = Module.DeclaringAssembly.SymbolWriter;
624                         if (sw != null) {
625                                 CreateUnitSymbolInfo (sw);
626                         }
627
628                         base.PrepareEmit ();
629                 }
630
631                 //
632                 // Creates symbol file index in debug symbol file
633                 //
634                 void CreateUnitSymbolInfo (MonoSymbolFile symwriter)
635                 {
636                         var si = file.CreateSymbolInfo (symwriter);
637                         comp_unit = new CompileUnitEntry (symwriter, si);
638
639                         if (include_files != null) {
640                                 foreach (SourceFile include in include_files.Values) {
641                                         si = include.CreateSymbolInfo (symwriter);
642                                         comp_unit.AddFile (si);
643                                 }
644                         }
645                 }
646
647                 public bool IsConditionalDefined (string value)
648                 {
649                         if (conditionals != null) {
650                                 bool res;
651                                 if (conditionals.TryGetValue (value, out res))
652                                         return res;
653
654                                 // When conditional was undefined
655                                 if (conditionals.ContainsKey (value))
656                                         return false;
657                         }
658
659                         return Compiler.Settings.IsConditionalSymbolDefined (value);
660                 }
661
662                 public override void Accept (StructuralVisitor visitor)
663                 {
664                         visitor.Visit (this);
665                 }
666         }
667
668
669         //
670         // Namespace block as created by the parser
671         //
672         public class NamespaceContainer : TypeContainer, IMemberContext
673         {
674                 static readonly Namespace[] empty_namespaces = new Namespace[0];
675
676                 readonly Namespace ns;
677
678                 public new readonly NamespaceContainer Parent;
679
680                 List<UsingNamespace> clauses;
681
682                 // Used by parsed to check for parser errors
683                 public bool DeclarationFound;
684
685                 Namespace[] namespace_using_table;
686                 Dictionary<string, UsingAliasNamespace> aliases;
687
688                 public NamespaceContainer (MemberName name, NamespaceContainer parent)
689                         : base (parent, name, null, MemberKind.Namespace)
690                 {
691                         this.Parent = parent;
692                         this.ns = parent.NS.AddNamespace (name);
693
694                         containers = new List<TypeContainer> ();
695                 }
696
697                 protected NamespaceContainer (ModuleContainer parent)
698                         : base (parent, null, null, MemberKind.Namespace)
699                 {
700                         ns = parent.GlobalRootNamespace;
701                         containers = new List<TypeContainer> (2);
702                 }
703
704                 #region Properties
705
706                 public override AttributeTargets AttributeTargets {
707                         get {
708                                 throw new NotSupportedException ();
709                         }
710                 }
711
712                 public override string DocCommentHeader {
713                         get {
714                                 throw new NotSupportedException ();
715                         }
716                 }
717
718                 public Namespace NS {
719                         get {
720                                 return ns;
721                         }
722                 }
723
724                 public List<UsingNamespace> Usings {
725                         get {
726                                 return clauses;
727                         }
728                 }
729
730                 public override string[] ValidAttributeTargets {
731                         get {
732                                 throw new NotSupportedException ();
733                         }
734                 }
735
736                 #endregion
737
738                 public void AddUsing (UsingNamespace un)
739                 {
740                         if (DeclarationFound){
741                                 Compiler.Report.Error (1529, un.Location, "A using clause must precede all other namespace elements except extern alias declarations");
742                         }
743
744                         if (clauses == null)
745                                 clauses = new List<UsingNamespace> ();
746
747                         clauses.Add (un);
748                 }
749
750                 public void AddUsing (UsingAliasNamespace un)
751                 {
752                         if (DeclarationFound){
753                                 Compiler.Report.Error (1529, un.Location, "A using clause must precede all other namespace elements except extern alias declarations");
754                         }
755
756                         AddAlias (un);
757                 }
758
759                 void AddAlias (UsingAliasNamespace un)
760                 {
761                         if (clauses == null) {
762                                 clauses = new List<UsingNamespace> ();
763                         } else {
764                                 foreach (var entry in clauses) {
765                                         var a = entry as UsingAliasNamespace;
766                                         if (a != null && a.Alias.Value == un.Alias.Value) {
767                                                 Compiler.Report.SymbolRelatedToPreviousError (a.Location, "");
768                                                 Compiler.Report.Error (1537, un.Location,
769                                                         "The using alias `{0}' appeared previously in this namespace", un.Alias.Value);
770                                         }
771                                 }
772                         }
773
774                         clauses.Add (un);
775                 }
776
777                 public override void AddPartial (TypeDefinition next_part)
778                 {
779                         var existing = ns.LookupType (this, next_part.MemberName.Name, next_part.MemberName.Arity, LookupMode.Probing, Location.Null);
780                         var td = existing != null ? existing.MemberDefinition as TypeDefinition : null;
781                         AddPartial (next_part, td);
782                 }
783
784                 public override void AddTypeContainer (TypeContainer tc)
785                 {
786                         string name = tc.Basename;
787
788                         var mn = tc.MemberName;
789                         while (mn.Left != null) {
790                                 mn = mn.Left;
791                                 name = mn.Name;
792                         }
793
794                         var names_container = Parent == null ? Module : (TypeContainer) this;
795
796                         MemberCore mc;
797                         if (names_container.DefinedNames.TryGetValue (name, out mc)) {
798                                 if (tc is NamespaceContainer && mc is NamespaceContainer) {
799                                         AddTypeContainerMember (tc);
800                                         return;
801                                 }
802
803                                 Report.SymbolRelatedToPreviousError (mc);
804                                 if ((mc.ModFlags & Modifiers.PARTIAL) != 0 && (tc is ClassOrStruct || tc is Interface)) {
805                                         Error_MissingPartialModifier (tc);
806                                 } else {
807                                         Report.Error (101, tc.Location, "The namespace `{0}' already contains a definition for `{1}'",
808                                                 GetSignatureForError (), mn.GetSignatureForError ());
809                                 }
810                         } else {
811                                 names_container.DefinedNames.Add (name, tc);
812
813                                 var tdef = tc.PartialContainer;
814                                 if (tdef != null) {
815                                         //
816                                         // Same name conflict in different namespace containers
817                                         //
818                                         var conflict = ns.GetAllTypes (name);
819                                         if (conflict != null) {
820                                                 foreach (var e in conflict) {
821                                                         if (e.Arity == mn.Arity) {
822                                                                 mc = (MemberCore) e.MemberDefinition;
823                                                                 break;
824                                                         }
825                                                 }
826                                         }
827
828                                         if (mc != null) {
829                                                 Report.SymbolRelatedToPreviousError (mc);
830                                                 Report.Error (101, tc.Location, "The namespace `{0}' already contains a definition for `{1}'",
831                                                         GetSignatureForError (), mn.GetSignatureForError ());
832                                         } else {
833                                                 ns.AddType (Module, tdef.Definition);
834                                         }
835                                 }
836                         }
837
838                         base.AddTypeContainer (tc);
839                 }
840
841                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
842                 {
843                         throw new NotSupportedException ();
844                 }
845
846                 public override void EmitContainer ()
847                 {
848                         VerifyClsCompliance ();
849
850                         base.EmitContainer ();
851                 }
852
853                 public ExtensionMethodCandidates LookupExtensionMethod (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity, int position)
854                 {
855                         //
856                         // Here we try to resume the search for extension method at the point
857                         // where the last bunch of candidates was found. It's more tricky than
858                         // it seems as we have to check both namespace containers and namespace
859                         // in correct order.
860                         //
861                         // Consider:
862                         // 
863                         // namespace A {
864                         //      using N1;
865                         //  namespace B.C.D {
866                         //              <our first search found candidates in A.B.C.D
867                         //  }
868                         // }
869                         //
870                         // In the example above namespace A.B.C.D, A.B.C and A.B have to be
871                         // checked before we hit A.N1 using
872                         //
873                         ExtensionMethodCandidates candidates;
874                         var container = this;
875                         do {
876                                 candidates = container.LookupExtensionMethodCandidates (invocationContext, name, arity, ref position);
877                                 if (candidates != null || container.MemberName == null)
878                                         return candidates;
879
880                                 var container_ns = container.ns.Parent;
881                                 var mn = container.MemberName.Left;
882                                 int already_checked = position - 2;
883                                 while (already_checked-- > 0) {
884                                         mn = mn.Left;
885                                         container_ns = container_ns.Parent;
886                                 }
887
888                                 while (mn != null) {
889                                         ++position;
890
891                                         var methods = container_ns.LookupExtensionMethod (invocationContext, name, arity);
892                                         if (methods != null) {
893                                                 return new ExtensionMethodCandidates (invocationContext, methods, container, position);
894                                         }
895
896                                         mn = mn.Left;
897                                         container_ns = container_ns.Parent;
898                                 }
899
900                                 position = 0;
901                                 container = container.Parent;
902                         } while (container != null);
903
904                         return null;
905                 }
906
907                 ExtensionMethodCandidates LookupExtensionMethodCandidates (IMemberContext invocationContext, string name, int arity, ref int position)
908                 {
909                         List<MethodSpec> candidates = null;
910
911                         if (position == 0) {
912                                 ++position;
913
914                                 candidates = ns.LookupExtensionMethod (invocationContext, name, arity);
915                                 if (candidates != null) {
916                                         return new ExtensionMethodCandidates (invocationContext, candidates, this, position);
917                                 }
918                         }
919
920                         if (position == 1) {
921                                 ++position;
922
923                                 foreach (Namespace n in namespace_using_table) {
924                                         var a = n.LookupExtensionMethod (invocationContext, name, arity);
925                                         if (a == null)
926                                                 continue;
927
928                                         if (candidates == null)
929                                                 candidates = a;
930                                         else
931                                                 candidates.AddRange (a);
932                                 }
933
934                                 if (candidates != null)
935                                         return new ExtensionMethodCandidates (invocationContext, candidates, this, position);
936                         }
937
938                         return null;
939                 }
940
941                 public override FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
942                 {
943                         //
944                         // Only simple names (no dots) will be looked up with this function
945                         //
946                         FullNamedExpression resolved;
947                         for (NamespaceContainer container = this; container != null; container = container.Parent) {
948                                 resolved = container.Lookup (name, arity, mode, loc);
949                                 if (resolved != null || container.MemberName == null)
950                                         return resolved;
951
952                                 var container_ns = container.ns.Parent;
953                                 var mn = container.MemberName.Left;
954                                 while (mn != null) {
955                                         resolved = container_ns.LookupTypeOrNamespace (this, name, arity, mode, loc);
956                                         if (resolved != null)
957                                                 return resolved;
958
959                                         mn = mn.Left;
960                                         container_ns = container_ns.Parent;
961                                 }
962                         }
963
964                         return null;
965                 }
966
967                 public override void GetCompletionStartingWith (string prefix, List<string> results)
968                 {
969                         if (Usings == null)
970                                 return;
971
972                         foreach (var un in Usings) {
973                                 if (un.Alias != null)
974                                         continue;
975
976                                 var name = un.NamespaceExpression.Name;
977                                 if (name.StartsWith (prefix))
978                                         results.Add (name);
979                         }
980
981
982                         IEnumerable<string> all = Enumerable.Empty<string> ();
983
984                         foreach (Namespace using_ns in namespace_using_table) {
985                                 if (prefix.StartsWith (using_ns.Name)) {
986                                         int ld = prefix.LastIndexOf ('.');
987                                         if (ld != -1) {
988                                                 string rest = prefix.Substring (ld + 1);
989
990                                                 all = all.Concat (using_ns.CompletionGetTypesStartingWith (rest));
991                                         }
992                                 }
993                                 all = all.Concat (using_ns.CompletionGetTypesStartingWith (prefix));
994                         }
995
996                         results.AddRange (all);
997
998                         base.GetCompletionStartingWith (prefix, results);
999                 }
1000
1001                 
1002                 //
1003                 // Looks-up a alias named @name in this and surrounding namespace declarations
1004                 //
1005                 public FullNamedExpression LookupExternAlias (string name)
1006                 {
1007                         if (aliases == null)
1008                                 return null;
1009
1010                         UsingAliasNamespace uan;
1011                         if (aliases.TryGetValue (name, out uan) && uan is UsingExternAlias)
1012                                 return uan.ResolvedExpression;
1013
1014                         return null;
1015                 }
1016                 
1017                 //
1018                 // Looks-up a alias named @name in this and surrounding namespace declarations
1019                 //
1020                 public override FullNamedExpression LookupNamespaceAlias (string name)
1021                 {
1022                         for (NamespaceContainer n = this; n != null; n = n.Parent) {
1023                                 if (n.aliases == null)
1024                                         continue;
1025
1026                                 UsingAliasNamespace uan;
1027                                 if (n.aliases.TryGetValue (name, out uan))
1028                                         return uan.ResolvedExpression;
1029                         }
1030
1031                         return null;
1032                 }
1033
1034                 FullNamedExpression Lookup (string name, int arity, LookupMode mode, Location loc)
1035                 {
1036                         //
1037                         // Check whether it's in the namespace.
1038                         //
1039                         FullNamedExpression fne = ns.LookupTypeOrNamespace (this, name, arity, mode, loc);
1040
1041                         //
1042                         // Check aliases. 
1043                         //
1044                         if (aliases != null && arity == 0) {
1045                                 UsingAliasNamespace uan;
1046                                 if (aliases.TryGetValue (name, out uan)) {
1047                                         if (fne != null && mode != LookupMode.Probing) {
1048                                                 // TODO: Namespace has broken location
1049                                                 //Report.SymbolRelatedToPreviousError (fne.Location, null);
1050                                                 Compiler.Report.SymbolRelatedToPreviousError (uan.Location, null);
1051                                                 Compiler.Report.Error (576, loc,
1052                                                         "Namespace `{0}' contains a definition with same name as alias `{1}'",
1053                                                         GetSignatureForError (), name);
1054                                         }
1055
1056                                         return uan.ResolvedExpression;
1057                                 }
1058                         }
1059
1060                         if (fne != null)
1061                                 return fne;
1062
1063                         //
1064                         // Lookup can be called before the namespace is defined from different namespace using alias clause
1065                         //
1066                         if (namespace_using_table == null) {
1067                                 DoDefineNamespace ();
1068                         }
1069
1070                         //
1071                         // Check using entries.
1072                         //
1073                         FullNamedExpression match = null;
1074                         foreach (Namespace using_ns in namespace_using_table) {
1075                                 //
1076                                 // A using directive imports only types contained in the namespace, it
1077                                 // does not import any nested namespaces
1078                                 //
1079                                 var t = using_ns.LookupType (this, name, arity, mode, loc);
1080                                 if (t == null)
1081                                         continue;
1082
1083                                 fne = new TypeExpression (t, loc);
1084                                 if (match == null) {
1085                                         match = fne;
1086                                         continue;
1087                                 }
1088
1089                                 // Prefer types over namespaces
1090                                 var texpr_fne = fne as TypeExpr;
1091                                 var texpr_match = match as TypeExpr;
1092                                 if (texpr_fne != null && texpr_match == null) {
1093                                         match = fne;
1094                                         continue;
1095                                 } else if (texpr_fne == null) {
1096                                         continue;
1097                                 }
1098
1099                                 // It can be top level accessibility only
1100                                 var better = Namespace.IsImportedTypeOverride (Module, texpr_match.Type, texpr_fne.Type);
1101                                 if (better == null) {
1102                                         if (mode == LookupMode.Normal) {
1103                                                 Compiler.Report.SymbolRelatedToPreviousError (texpr_match.Type);
1104                                                 Compiler.Report.SymbolRelatedToPreviousError (texpr_fne.Type);
1105                                                 Compiler.Report.Error (104, loc, "`{0}' is an ambiguous reference between `{1}' and `{2}'",
1106                                                         name, texpr_match.GetSignatureForError (), texpr_fne.GetSignatureForError ());
1107                                         }
1108
1109                                         return match;
1110                                 }
1111
1112                                 if (better == texpr_fne.Type)
1113                                         match = texpr_fne;
1114                         }
1115
1116                         return match;
1117                 }
1118
1119                 protected override void DefineNamespace ()
1120                 {
1121                         if (namespace_using_table == null)
1122                                 DoDefineNamespace ();
1123
1124                         base.DefineNamespace ();
1125                 }
1126
1127                 void DoDefineNamespace ()
1128                 {
1129                         namespace_using_table = empty_namespaces;
1130
1131                         if (clauses != null) {
1132                                 var list = new List<Namespace> (clauses.Count);
1133                                 bool post_process_using_aliases = false;
1134
1135                                 for (int i = 0; i < clauses.Count; ++i) {
1136                                         var entry = clauses[i];
1137
1138                                         if (entry.Alias != null) {
1139                                                 if (aliases == null)
1140                                                         aliases = new Dictionary<string, UsingAliasNamespace> ();
1141
1142                                                 //
1143                                                 // Aliases are not available when resolving using section
1144                                                 // except extern aliases
1145                                                 //
1146                                                 if (entry is UsingExternAlias) {
1147                                                         entry.Define (this);
1148                                                         if (entry.ResolvedExpression != null)
1149                                                                 aliases.Add (entry.Alias.Value, (UsingExternAlias) entry);
1150
1151                                                         clauses.RemoveAt (i--);
1152                                                 } else {
1153                                                         post_process_using_aliases = true;
1154                                                 }
1155
1156                                                 continue;
1157                                         }
1158
1159                                         entry.Define (this);
1160
1161                                         //
1162                                         // It's needed for repl only, when using clause cannot be resolved don't hold it in
1163                                         // global list which is resolved for each evaluation
1164                                         //
1165                                         if (entry.ResolvedExpression == null) {
1166                                                 clauses.RemoveAt (i--);
1167                                                 continue;
1168                                         }
1169
1170                                         var using_ns = entry.ResolvedExpression as NamespaceExpression;
1171                                         if (using_ns == null)
1172                                                 continue;
1173
1174                                         if (list.Contains (using_ns.Namespace)) {
1175                                                 // Ensure we don't report the warning multiple times in repl
1176                                                 clauses.RemoveAt (i--);
1177
1178                                                 Compiler.Report.Warning (105, 3, entry.Location,
1179                                                         "The using directive for `{0}' appeared previously in this namespace", using_ns.GetSignatureForError ());
1180                                         } else {
1181                                                 list.Add (using_ns.Namespace);
1182                                         }
1183                                 }
1184
1185                                 namespace_using_table = list.ToArray ();
1186
1187                                 if (post_process_using_aliases) {
1188                                         for (int i = 0; i < clauses.Count; ++i) {
1189                                                 var entry = clauses[i];
1190                                                 if (entry.Alias != null) {
1191                                                         entry.Define (this);
1192                                                         if (entry.ResolvedExpression != null) {
1193                                                                 aliases.Add (entry.Alias.Value, (UsingAliasNamespace) entry);
1194                                                         }
1195
1196                                                         clauses.RemoveAt (i--);
1197                                                 }
1198                                         }
1199                                 }
1200                         }
1201                 }
1202
1203                 public void EnableRedefinition ()
1204                 {
1205                         is_defined = false;
1206                         namespace_using_table = null;
1207                 }
1208
1209                 internal override void GenerateDocComment (DocumentationBuilder builder)
1210                 {
1211                         if (containers != null) {
1212                                 foreach (var tc in containers)
1213                                         tc.GenerateDocComment (builder);
1214                         }
1215                 }
1216
1217                 public override string GetSignatureForError ()
1218                 {
1219                         return MemberName == null ? "global::" : base.GetSignatureForError ();
1220                 }
1221
1222                 public override void RemoveContainer (TypeContainer cont)
1223                 {
1224                         base.RemoveContainer (cont);
1225                         NS.RemoveContainer (cont);
1226                 }
1227
1228                 protected override bool VerifyClsCompliance ()
1229                 {
1230                         if (Module.IsClsComplianceRequired ()) {
1231                                 if (MemberName != null && MemberName.Name[0] == '_') {
1232                                         Warning_IdentifierNotCompliant ();
1233                                 }
1234
1235                                 ns.VerifyClsCompliance ();
1236                                 return true;
1237                         }
1238
1239                         return false;
1240                 }
1241
1242                 public override void Accept (StructuralVisitor visitor)
1243                 {
1244                         visitor.Visit (this);
1245                 }
1246         }
1247
1248         public class UsingNamespace
1249         {
1250                 readonly ATypeNameExpression expr;
1251                 readonly Location loc;
1252                 protected FullNamedExpression resolved;
1253
1254                 public UsingNamespace (ATypeNameExpression expr, Location loc)
1255                 {
1256                         this.expr = expr;
1257                         this.loc = loc;
1258                 }
1259
1260                 #region Properties
1261
1262                 public virtual SimpleMemberName Alias {
1263                         get {
1264                                 return null;
1265                         }
1266                 }
1267
1268                 public Location Location {
1269                         get {
1270                                 return loc;
1271                         }
1272                 }
1273
1274                 public ATypeNameExpression NamespaceExpression  {
1275                         get {
1276                                 return expr;
1277                         }
1278                 }
1279
1280                 public FullNamedExpression ResolvedExpression {
1281                         get {
1282                                 return resolved;
1283                         }
1284                 }
1285
1286                 #endregion
1287
1288                 public string GetSignatureForError ()
1289                 {
1290                         return expr.GetSignatureForError ();
1291                 }
1292
1293                 public virtual void Define (NamespaceContainer ctx)
1294                 {
1295                         resolved = expr.ResolveAsTypeOrNamespace (ctx);
1296                         var ns = resolved as NamespaceExpression;
1297                         if (ns == null) {
1298                                 if (resolved != null) {
1299                                         ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (resolved.Type);
1300                                         ctx.Module.Compiler.Report.Error (138, Location,
1301                                                 "`{0}' is a type not a namespace. A using namespace directive can only be applied to namespaces",
1302                                                 GetSignatureForError ());
1303                                 }
1304                         }
1305                 }
1306
1307                 public override string ToString()
1308                 {
1309                         return resolved.ToString();
1310                 }
1311         }
1312
1313         public class UsingExternAlias : UsingAliasNamespace
1314         {
1315                 public UsingExternAlias (SimpleMemberName alias, Location loc)
1316                         : base (alias, null, loc)
1317                 {
1318                 }
1319
1320                 public override void Define (NamespaceContainer ctx)
1321                 {
1322                         var ns = ctx.Module.GetRootNamespace (Alias.Value);
1323                         if (ns == null) {
1324                                 ctx.Module.Compiler.Report.Error (430, Location,
1325                                         "The extern alias `{0}' was not specified in -reference option",
1326                                         Alias.Value);
1327                                 return;
1328                         }
1329
1330                         resolved = new NamespaceExpression (ns, Location);
1331                 }
1332         }
1333
1334         public class UsingAliasNamespace : UsingNamespace
1335         {
1336                 readonly SimpleMemberName alias;
1337
1338                 public struct AliasContext : IMemberContext
1339                 {
1340                         readonly NamespaceContainer ns;
1341
1342                         public AliasContext (NamespaceContainer ns)
1343                         {
1344                                 this.ns = ns;
1345                         }
1346
1347                         public TypeSpec CurrentType {
1348                                 get {
1349                                         return null;
1350                                 }
1351                         }
1352
1353                         public TypeParameters CurrentTypeParameters {
1354                                 get {
1355                                         return null;
1356                                 }
1357                         }
1358
1359                         public MemberCore CurrentMemberDefinition {
1360                                 get {
1361                                         return null;
1362                                 }
1363                         }
1364
1365                         public bool IsObsolete {
1366                                 get {
1367                                         return false;
1368                                 }
1369                         }
1370
1371                         public bool IsUnsafe {
1372                                 get {
1373                                         throw new NotImplementedException ();
1374                                 }
1375                         }
1376
1377                         public bool IsStatic {
1378                                 get {
1379                                         throw new NotImplementedException ();
1380                                 }
1381                         }
1382
1383                         public ModuleContainer Module {
1384                                 get {
1385                                         return ns.Module;
1386                                 }
1387                         }
1388
1389                         public string GetSignatureForError ()
1390                         {
1391                                 throw new NotImplementedException ();
1392                         }
1393
1394                         public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
1395                         {
1396                                 return null;
1397                         }
1398
1399                         public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
1400                         {
1401                                 var fne = ns.NS.LookupTypeOrNamespace (ns, name, arity, mode, loc);
1402                                 if (fne != null)
1403                                         return fne;
1404
1405                                 //
1406                                 // Only extern aliases are allowed in this context
1407                                 //
1408                                 fne = ns.LookupExternAlias (name);
1409                                 if (fne != null || ns.MemberName == null)
1410                                         return fne;
1411
1412                                 var container_ns = ns.NS.Parent;
1413                                 var mn = ns.MemberName.Left;
1414                                 while (mn != null) {
1415                                         fne = container_ns.LookupTypeOrNamespace (this, name, arity, mode, loc);
1416                                         if (fne != null)
1417                                                 return fne;
1418
1419                                         mn = mn.Left;
1420                                         container_ns = container_ns.Parent;
1421                                 }
1422
1423                                 if (ns.Parent != null)
1424                                         return ns.Parent.LookupNamespaceOrType (name, arity, mode, loc);
1425
1426                                 return null;
1427                         }
1428
1429                         public FullNamedExpression LookupNamespaceAlias (string name)
1430                         {
1431                                 return ns.LookupNamespaceAlias (name);
1432                         }
1433                 }
1434
1435                 public UsingAliasNamespace (SimpleMemberName alias, ATypeNameExpression expr, Location loc)
1436                         : base (expr, loc)
1437                 {
1438                         this.alias = alias;
1439                 }
1440
1441                 public override SimpleMemberName Alias {
1442                         get {
1443                                 return alias;
1444                         }
1445                 }
1446
1447                 public override void Define (NamespaceContainer ctx)
1448                 {
1449                         //
1450                         // The namespace-or-type-name of a using-alias-directive is resolved as if
1451                         // the immediately containing compilation unit or namespace body had no
1452                         // using-directives. A using-alias-directive may however be affected
1453                         // by extern-alias-directives in the immediately containing compilation
1454                         // unit or namespace body
1455                         //
1456                         // We achieve that by introducing alias-context which redirect any local
1457                         // namespace or type resolve calls to parent namespace
1458                         //
1459                         resolved = NamespaceExpression.ResolveAsTypeOrNamespace (new AliasContext (ctx));
1460                 }
1461         }
1462 }