2010-05-27 Marek Safar <marek.safar@gmail.com>
[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 //
11 using System;
12 using System.Collections.Generic;
13 using System.Reflection;
14 using System.Linq;
15
16 namespace Mono.CSharp {
17
18         public class RootNamespace : Namespace {
19
20                 protected readonly string alias_name;
21                 protected Assembly [] referenced_assemblies;
22
23                 Dictionary<string, Namespace> all_namespaces;
24
25                 public RootNamespace (string alias_name)
26                         : base (null, String.Empty)
27                 {
28                         this.alias_name = alias_name;
29                         referenced_assemblies = new Assembly [0];
30
31                         all_namespaces = new Dictionary<string, Namespace> ();
32                         all_namespaces.Add ("", this);
33                 }
34
35                 public void AddAssemblyReference (Assembly a)
36                 {
37                         foreach (Assembly assembly in referenced_assemblies) {
38                                 if (a == assembly)
39                                         return;
40                         }
41
42                         int top = referenced_assemblies.Length;
43                         Assembly [] n = new Assembly [top + 1];
44                         referenced_assemblies.CopyTo (n, 0);
45                         n [top] = a;
46                         referenced_assemblies = n;
47                 }
48
49                 public void ImportTypes (CompilerContext ctx)
50                 {
51                         foreach (Assembly a in referenced_assemblies) {
52                                 try {
53                                         ImportAssembly (a);
54                                 } catch (TypeLoadException e) {
55                                         ctx.Report.Error (11, Location.Null, e.Message);
56                                 } catch (System.IO.FileNotFoundException) {
57                                         ctx.Report.Error (12, Location.Null, "An assembly `{0}' is used without being referenced",
58                                                 a.FullName);
59                                 }
60                         }
61                 }
62
63                 public void RegisterNamespace (Namespace child)
64                 {
65                         if (child != this)
66                                 all_namespaces.Add (child.Name, child);
67                 }
68
69                 public bool IsNamespace (string name)
70                 {
71                         return all_namespaces.ContainsKey (name);
72                 }
73
74                 protected void RegisterNamespace (string dotted_name)
75                 {
76                         if (dotted_name != null && dotted_name.Length != 0 && ! IsNamespace (dotted_name))
77                                 GetNamespace (dotted_name, true);
78                 }
79
80                 public void ImportAssembly (Assembly assembly)
81                 {
82                         Type extension_type = null;
83                         var all_attributes = CustomAttributeData.GetCustomAttributes (assembly);
84                         foreach (var attr in all_attributes) {
85                                 var dt = attr.Constructor.DeclaringType;
86                                 if (dt.Name == "ExtensionAttribute" && dt.Namespace == "System.Runtime.CompilerServices") {
87                                         extension_type = dt;
88                                         break;
89                                 }
90                         }
91
92                         Namespace ns = this;
93                         string prev_namespace = null;
94                         foreach (var t in assembly.GetTypes ()) {
95                                 if (t.IsNested)
96                                         continue;
97
98                                 if (t.Name[0] == '<')
99                                         continue;
100
101                                 var it = Import.CreateType (t);
102                                 if (it == null)
103                                         continue;
104
105                                 if (prev_namespace != t.Namespace) {
106                                         ns = t.Namespace == null ? this : GetNamespace (t.Namespace, true);
107                                         prev_namespace = t.Namespace;
108                                 }
109
110                                 ns.AddType (it);
111
112                                 if (it.IsStatic && extension_type != null && t.IsDefined (extension_type, false)) {
113                                         it.SetExtensionMethodContainer ();
114                                 }
115                         }
116                 }
117
118                 public override string GetSignatureForError ()
119                 {
120                         return alias_name + "::";
121                 }
122         }
123
124         public class GlobalRootNamespace : RootNamespace {
125                 Module [] modules;
126                 Dictionary<string, RootNamespace> root_namespaces;
127
128                 public static GlobalRootNamespace Instance = new GlobalRootNamespace ();
129
130                 GlobalRootNamespace ()
131                         : base ("global")
132                 {
133                         root_namespaces = new Dictionary<string, RootNamespace> ();
134                         root_namespaces.Add (alias_name, this);
135                 }
136
137                 public static void Reset ()
138                 {
139                         Instance = new GlobalRootNamespace ();
140                 }
141
142                 public Assembly [] Assemblies {
143                     get { return referenced_assemblies; }
144                 }
145
146                 public Module [] Modules {
147                         get { return modules; }
148                 }
149
150                 public void AddModuleReference (Module m)
151                 {
152                         int top = modules != null ? modules.Length : 0;
153                         Module [] n = new Module [top + 1];
154                         if (modules != null)
155                                 modules.CopyTo (n, 0);
156                         n [top] = m;
157                         modules = n;
158
159                         if (m == RootContext.ToplevelTypes.Builder)
160                                 return;
161
162                         foreach (var t in m.GetTypes ())
163                                 RegisterNamespace (t.Namespace);
164                 }
165
166                 public void ComputeNamespaces (CompilerContext ctx)
167                 {
168                         foreach (RootNamespace rn in root_namespaces.Values) {
169                                 rn.ImportTypes (ctx);
170                         }
171                 }
172
173                 public void DefineRootNamespace (string alias, Assembly assembly, CompilerContext ctx)
174                 {
175                         if (alias == alias_name) {
176                                 NamespaceEntry.Error_GlobalNamespaceRedefined (Location.Null, ctx.Report);
177                                 return;
178                         }
179
180                         RootNamespace retval = GetRootNamespace (alias);
181                         if (retval == null) {
182                                 retval = new RootNamespace (alias);
183                                 root_namespaces.Add (alias, retval);
184                         }
185
186                         retval.AddAssemblyReference (assembly);
187                 }
188
189                 public override void Error_NamespaceDoesNotExist (Location loc, string name, int arity, IMemberContext ctx)
190                 {
191                         ctx.Compiler.Report.Error (400, loc,
192                                 "The type or namespace name `{0}' could not be found in the global namespace (are you missing an assembly reference?)",
193                                 name);
194                 }
195
196                 public RootNamespace GetRootNamespace (string name)
197                 {
198                         RootNamespace rn;
199                         if (!root_namespaces.TryGetValue (name, out rn))
200                                 return null;
201
202                         return rn;
203                 }
204         }
205
206         /// <summary>
207         ///   Keeps track of the namespaces defined in the C# code.
208         ///
209         ///   This is an Expression to allow it to be referenced in the
210         ///   compiler parse/intermediate tree during name resolution.
211         /// </summary>
212         public class Namespace : FullNamedExpression {
213                 
214                 Namespace parent;
215                 string fullname;
216                 protected Dictionary<string, Namespace> namespaces;
217                 protected Dictionary<string, IList<TypeSpec>> types;
218                 Dictionary<string, TypeExpr> cached_types;
219                 RootNamespace root;
220                 bool cls_checked;
221
222                 public readonly MemberName MemberName;
223
224                 /// <summary>
225                 ///   Constructor Takes the current namespace and the
226                 ///   name.  This is bootstrapped with parent == null
227                 ///   and name = ""
228                 /// </summary>
229                 public Namespace (Namespace parent, string name)
230                 {
231                         // Expression members.
232                         this.eclass = ExprClass.Namespace;
233                         this.Type = InternalType.FakeInternalType;
234                         this.loc = Location.Null;
235
236                         this.parent = parent;
237
238                         if (parent != null)
239                                 this.root = parent.root;
240                         else
241                                 this.root = this as RootNamespace;
242
243                         if (this.root == null)
244                                 throw new InternalErrorException ("Root namespaces must be created using RootNamespace");
245                         
246                         string pname = parent != null ? parent.fullname : "";
247                                 
248                         if (pname == "")
249                                 fullname = name;
250                         else
251                                 fullname = parent.fullname + "." + name;
252
253                         if (fullname == null)
254                                 throw new InternalErrorException ("Namespace has a null fullname");
255
256                         if (parent != null && parent.MemberName != MemberName.Null)
257                                 MemberName = new MemberName (parent.MemberName, name);
258                         else if (name.Length == 0)
259                                 MemberName = MemberName.Null;
260                         else
261                                 MemberName = new MemberName (name);
262
263                         namespaces = new Dictionary<string, Namespace> ();
264                         cached_types = new Dictionary<string, TypeExpr> ();
265
266                         root.RegisterNamespace (this);
267                 }
268
269                 #region Properties
270
271                 /// <summary>
272                 ///   The qualified name of the current namespace
273                 /// </summary>
274                 public string Name {
275                         get { return fullname; }
276                 }
277
278                 /// <summary>
279                 ///   The parent of this namespace, used by the parser to "Pop"
280                 ///   the current namespace declaration
281                 /// </summary>
282                 public Namespace Parent {
283                         get { return parent; }
284                 }
285
286                 #endregion
287
288                 protected override Expression DoResolve (ResolveContext ec)
289                 {
290                         return this;
291                 }
292
293                 public virtual void Error_NamespaceDoesNotExist (Location loc, string name, int arity, IMemberContext ctx)
294                 {
295                         FullNamedExpression retval = Lookup (ctx.Compiler, name, -System.Math.Max (1, arity), loc);
296                         if (retval != null) {
297                                 Error_TypeArgumentsCannotBeUsed (ctx.Compiler.Report, loc, retval.Type, arity);
298                                 return;
299                         }
300
301                         Namespace ns;
302                         if (arity > 0 && namespaces.TryGetValue (name, out ns)) {
303                                 ns.Error_TypeArgumentsCannotBeUsed (ctx.Compiler.Report, loc, null, arity);
304                                 return;
305                         }
306
307                         ctx.Compiler.Report.Error (234, loc,
308                                 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing an assembly reference?",
309                                 name, GetSignatureForError ());
310                 }
311
312                 public override string GetSignatureForError ()
313                 {
314                         return fullname;
315                 }
316                 
317                 public Namespace GetNamespace (string name, bool create)
318                 {
319                         int pos = name.IndexOf ('.');
320
321                         Namespace ns;
322                         string first;
323                         if (pos >= 0)
324                                 first = name.Substring (0, pos);
325                         else
326                                 first = name;
327
328                         if (!namespaces.TryGetValue (first, out ns)) {
329                                 if (!create)
330                                         return null;
331
332                                 ns = new Namespace (this, first);
333                                 namespaces.Add (first, ns);
334                         }
335
336                         if (pos >= 0)
337                                 ns = ns.GetNamespace (name.Substring (pos + 1), create);
338
339                         return ns;
340                 }
341
342                 TypeExpr LookupType (CompilerContext ctx, string name, int arity, Location loc)
343                 {
344                         if (types == null)
345                                 return null;
346
347                         TypeExpr te;
348                         if (arity == 0 && cached_types.TryGetValue (name, out te))
349                                 return te;
350
351                         IList<TypeSpec> found;
352                         if (!types.TryGetValue (name, out found))
353                                 return null;
354
355                         TypeSpec best = null;
356                         foreach (var ts in found) {
357                                 if (ts.Arity == arity) {
358                                         if (best == null) {
359                                                 best = ts;
360                                                 continue;
361                                         }
362
363                                         if (best.MemberDefinition.IsImported && ts.MemberDefinition.IsImported) {
364                                                 ctx.Report.SymbolRelatedToPreviousError (best);
365                                                 ctx.Report.SymbolRelatedToPreviousError (ts);
366                                                 ctx.Report.Error (433, loc, "The imported type `{0}' is defined multiple times", ts.GetSignatureForError ());
367                                                 break;
368                                         }
369
370                                         var pts = best as PredefinedTypeSpec;
371                                         if (pts == null)
372                                                 pts = ts as PredefinedTypeSpec;
373
374                                         if (pts != null) {
375                                                 ctx.Report.SymbolRelatedToPreviousError (best);
376                                                 ctx.Report.SymbolRelatedToPreviousError (ts);
377                                                 ctx.Report.Warning (1685, 1, loc,
378                                                         "The predefined type `{0}.{1}' is redefined in the source code. Ignoring the local type definition",
379                                                         pts.Namespace, pts.Name);
380                                                 best = pts;
381                                                 continue;
382                                         }
383
384                                         if (best.MemberDefinition.IsImported)
385                                                 best = ts;
386
387                                         if ((best.Modifiers & Modifiers.INTERNAL) != 0 && !TypeManager.IsThisOrFriendAssembly (CodeGen.Assembly.Builder, best.MemberDefinition.Assembly))
388                                                 continue;
389
390                                         if (ts.MemberDefinition.IsImported)
391                                                 ctx.Report.SymbolRelatedToPreviousError (ts);
392
393                                         ctx.Report.Warning (436, 2, loc,
394                                                 "The type `{0}' conflicts with the imported type of same name'. Ignoring the imported type definition",
395                                                 best.GetSignatureForError ());
396                                 }
397
398                                 //
399                                 // Lookup for the best candidate with closest arity match
400                                 //
401                                 if (arity < 0) {
402                                         if (best == null) {
403                                                 best = ts;
404                                         } else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (best.Arity + arity)) {
405                                                 best = ts;
406                                         }
407                                 }
408                         }
409
410                         if (best == null)
411                                 return null;
412
413                         te = new TypeExpression (best, Location.Null);
414
415                         // TODO MemberCache: Cache more
416                         if (arity == 0)
417                                 cached_types.Add (name, te);
418
419                         return te;
420                 }
421
422                 TypeSpec LookupType (string name, int arity)
423                 {
424                         if (types == null)
425                                 return null;
426
427                         IList<TypeSpec> found;
428                         if (types.TryGetValue (name, out found)) {
429                                 TypeSpec best = null;
430
431                                 foreach (var ts in found) {
432                                         if (ts.Arity == arity)
433                                                 return ts;
434
435                                         //
436                                         // Lookup for the best candidate with closest arity match
437                                         //
438                                         if (arity < 0) {
439                                                 if (best == null) {
440                                                         best = ts;
441                                                 } else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (best.Arity + arity)) {
442                                                         best = ts;
443                                                 }
444                                         }
445                                 }
446                                 
447                                 return best;
448                         }
449
450                         return null;
451                 }
452
453                 public FullNamedExpression Lookup (CompilerContext ctx, string name, int arity, Location loc)
454                 {
455                         if (arity == 0 && namespaces.ContainsKey (name))
456                                 return namespaces [name];
457
458                         return LookupType (ctx, name, arity, loc);
459                 }
460
461                 //
462                 // Completes types with the given `prefix'
463                 //
464                 public IEnumerable<string> CompletionGetTypesStartingWith (string prefix)
465                 {
466                         if (types == null)
467                                 return Enumerable.Empty<string> ();
468
469                         var res = from item in types
470                                           where item.Key.StartsWith (prefix) && item.Value.Any (l => (l.Modifiers & Modifiers.PUBLIC) != 0)
471                                           select item.Key;
472
473                         if (namespaces != null)
474                                 res = res.Concat (from item in namespaces where item.Key.StartsWith (prefix) select item.Key);
475
476                         return res;
477                 }
478
479                 /// 
480                 /// Looks for extension method in this namespace
481                 /// 
482                 public List<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, ClassOrStruct currentClass, string name, int arity)
483                 {
484                         if (types == null)
485                                 return null;
486
487                         List<MethodSpec> found = null;
488
489                         var invocation_type = currentClass == null ? InternalType.FakeInternalType : currentClass.CurrentType;
490
491                         // TODO: Add per namespace flag when at least 1 type has extension
492
493                         foreach (var tgroup in types.Values) {
494                                 foreach (var ts in tgroup) {
495                                         if ((ts.Modifiers & Modifiers.METHOD_EXTENSION) == 0)
496                                                 continue;
497
498                                         var res = ts.MemberCache.FindExtensionMethods (invocation_type, extensionType, name, arity);
499                                         if (res == null)
500                                                 continue;
501
502                                         if (found == null) {
503                                                 found = res;
504                                         } else {
505                                                 found.AddRange (res);
506                                         }
507                                 }
508                         }
509
510                         return found;
511                 }
512
513                 public void AddType (TypeSpec ts)
514                 {
515                         if (types == null) {
516                                 types = new Dictionary<string, IList<TypeSpec>> (64);
517                         }
518
519                         var name = ts.Name;
520                         IList<TypeSpec> existing;
521                         if (types.TryGetValue (name, out existing)) {
522                                 TypeSpec better_type;
523                                 TypeSpec found;
524                                 if (existing.Count == 1) {
525                                         found = existing[0];
526                                         if (ts.Arity == found.Arity) {
527                                                 better_type = IsImportedTypeOverride (ts, found);
528                                                 if (better_type == found)
529                                                         return;
530
531                                                 if (better_type != null) {
532                                                         existing [0] = better_type;
533                                                         return;
534                                                 }
535                                         }
536
537                                         existing = new List<TypeSpec> ();
538                                         existing.Add (found);
539                                         types[name] = existing;
540                                 } else {
541                                         for (int i = 0; i < existing.Count; ++i) {
542                                                 found = existing[i];
543                                                 if (ts.Arity != found.Arity)
544                                                         continue;
545
546                                                 better_type = IsImportedTypeOverride (ts, found);
547                                                 if (better_type == found)
548                                                         return;
549
550                                                 if (better_type != null) {
551                                                         existing.RemoveAt (i);
552                                                         --i;
553                                                         continue;
554                                                 }
555                                         }
556                                 }
557
558                                 existing.Add (ts);
559                         } else {
560                                 types.Add (name, new TypeSpec[] { ts });
561                         }
562                 }
563
564                 //
565                 // We import any types but in the situation there are same types
566                 // but one has better visibility (either public or internal with friend)
567                 // the less visible type is removed from the namespace cache
568                 //
569                 public static TypeSpec IsImportedTypeOverride (TypeSpec ts, TypeSpec found)
570                 {
571                         var ts_accessible = (ts.Modifiers & Modifiers.PUBLIC) != 0 || TypeManager.IsThisOrFriendAssembly (CodeGen.Assembly.Builder, ts.MemberDefinition.Assembly);
572                         var found_accessible = (found.Modifiers & Modifiers.PUBLIC) != 0 || TypeManager.IsThisOrFriendAssembly (CodeGen.Assembly.Builder, found.MemberDefinition.Assembly);
573
574                         if (ts_accessible && !found_accessible)
575                                 return ts;
576
577                         // found is better always better for accessible or inaccessible ts
578                         if (!ts_accessible)
579                                 return found;
580
581                         return null;
582                 }
583
584                 public void RemoveDeclSpace (string name)
585                 {
586                         types.Remove (name);
587                 }
588
589                 public void ReplaceTypeWithPredefined (TypeSpec ts, PredefinedTypeSpec pts)
590                 {
591                         var found = types [ts.Name];
592                         cached_types.Remove (ts.Name);
593                         if (found.Count == 1) {
594                                 types[ts.Name][0] = pts;
595                         } else {
596                                 throw new NotImplementedException ();
597                         }
598                 }
599
600                 public void VerifyClsCompliance ()
601                 {
602                         if (types == null || cls_checked)
603                                 return;
604
605                         cls_checked = true;
606
607                         // TODO: This is quite ugly way to check for CLS compliance at namespace level
608
609                         var locase_types = new Dictionary<string, List<TypeSpec>> (StringComparer.OrdinalIgnoreCase);
610                         foreach (var tgroup in types.Values) {
611                                 foreach (var tm in tgroup) {
612                                         if ((tm.Modifiers & Modifiers.PUBLIC) == 0 || !tm.IsCLSCompliant ())
613                                                 continue;
614
615                                         List<TypeSpec> found;
616                                         if (!locase_types.TryGetValue (tm.Name, out found)) {
617                                                 found = new List<TypeSpec> ();
618                                                 locase_types.Add (tm.Name, found);
619                                         }
620
621                                         found.Add (tm);
622                                 }
623                         }
624
625                         foreach (var locase in locase_types.Values) {
626                                 if (locase.Count < 2)
627                                         continue;
628
629                                 bool all_same = true;
630                                 foreach (var notcompliant in locase) {
631                                         all_same = notcompliant.Name == locase[0].Name;
632                                         if (!all_same)
633                                                 break;
634                                 }
635
636                                 if (all_same)
637                                         continue;
638
639                                 TypeContainer compiled = null;
640                                 foreach (var notcompliant in locase) {
641                                         if (!notcompliant.MemberDefinition.IsImported) {
642                                                 if (compiled != null)
643                                                         compiled.Compiler.Report.SymbolRelatedToPreviousError (compiled);
644
645                                                 compiled = notcompliant.MemberDefinition as TypeContainer;
646                                         } else {
647                                                 compiled.Compiler.Report.SymbolRelatedToPreviousError (notcompliant);
648                                         }
649                                 }
650
651                                 compiled.Compiler.Report.Warning (3005, 1, compiled.Location,
652                                         "Identifier `{0}' differing only in case is not CLS-compliant", compiled.GetSignatureForError ());
653                         }
654                 }
655         }
656
657         //
658         // Namespace container as created by the parser
659         //
660         public class NamespaceEntry : IMemberContext {
661
662                 public class UsingEntry {
663                         readonly MemberName name;
664                         Namespace resolved;
665                         
666                         public UsingEntry (MemberName name)
667                         {
668                                 this.name = name;
669                         }
670
671                         public string GetSignatureForError ()
672                         {
673                                 return name.GetSignatureForError ();
674                         }
675
676                         public Location Location {
677                                 get { return name.Location; }
678                         }
679
680                         public MemberName MemberName {
681                                 get { return name; }
682                         }
683                         
684                         public string Name {
685                                 get { return GetSignatureForError (); }
686                         }
687
688                         public Namespace Resolve (IMemberContext rc)
689                         {
690                                 if (resolved != null)
691                                         return resolved;
692
693                                 FullNamedExpression fne = name.GetTypeExpression ().ResolveAsTypeStep (rc, false);
694                                 if (fne == null)
695                                         return null;
696
697                                 resolved = fne as Namespace;
698                                 if (resolved == null) {
699                                         rc.Compiler.Report.SymbolRelatedToPreviousError (fne.Type);
700                                         rc.Compiler.Report.Error (138, Location,
701                                                 "`{0}' is a type not a namespace. A using namespace directive can only be applied to namespaces",
702                                                 GetSignatureForError ());
703                                 }
704                                 return resolved;
705                         }
706
707                         public override string ToString ()
708                         {
709                                 return Name;
710                         }
711                 }
712
713                 public class UsingAliasEntry {
714                         public readonly string Alias;
715                         public Location Location;
716
717                         public UsingAliasEntry (string alias, Location loc)
718                         {
719                                 this.Alias = alias;
720                                 this.Location = loc;
721                         }
722
723                         public virtual FullNamedExpression Resolve (IMemberContext rc)
724                         {
725                                 FullNamedExpression fne = GlobalRootNamespace.Instance.GetRootNamespace (Alias);
726                                 if (fne == null) {
727                                         rc.Compiler.Report.Error (430, Location,
728                                                 "The extern alias `{0}' was not specified in -reference option",
729                                                 Alias);
730                                 }
731
732                                 return fne;
733                         }
734
735                         public override string ToString ()
736                         {
737                                 return Alias;
738                         }
739                         
740                 }
741
742                 class LocalUsingAliasEntry : UsingAliasEntry {
743                         FullNamedExpression resolved;
744                         MemberName value;
745
746                         public LocalUsingAliasEntry (string alias, MemberName name, Location loc)
747                                 : base (alias, loc)
748                         {
749                                 this.value = name;
750                         }
751
752                         public override FullNamedExpression Resolve (IMemberContext rc)
753                         {
754                                 if (resolved != null || value == null)
755                                         return resolved;
756
757                                 if (rc == null)
758                                         return null;
759
760                                 resolved = value.GetTypeExpression ().ResolveAsTypeStep (rc, false);
761                                 if (resolved == null) {
762                                         value = null;
763                                         return null;
764                                 }
765
766                                 if (resolved is TypeExpr)
767                                         resolved = resolved.ResolveAsTypeTerminal (rc, false);
768
769                                 return resolved;
770                         }
771
772                         public override string ToString ()
773                         {
774                                 return String.Format ("{0} = {1}", Alias, value.GetSignatureForError ());
775                         }
776                 }
777
778                 Namespace ns;
779                 NamespaceEntry parent, implicit_parent;
780                 CompilationUnit file;
781                 int symfile_id;
782
783                 // Namespace using import block
784                 List<UsingAliasEntry> using_aliases;
785                 List<UsingEntry> using_clauses;
786                 public bool DeclarationFound;
787                 // End
788
789                 public readonly bool IsImplicit;
790                 public readonly DeclSpace SlaveDeclSpace;
791                 static readonly Namespace [] empty_namespaces = new Namespace [0];
792                 Namespace [] namespace_using_table;
793
794                 static List<NamespaceEntry> entries = new List<NamespaceEntry> ();
795
796                 public static void Reset ()
797                 {
798                         entries = new List<NamespaceEntry> ();
799                 }
800
801                 public NamespaceEntry (NamespaceEntry parent, CompilationUnit file, string name)
802                 {
803                         this.parent = parent;
804                         this.file = file;
805                         entries.Add (this);
806
807                         if (parent != null)
808                                 ns = parent.NS.GetNamespace (name, true);
809                         else if (name != null)
810                                 ns = GlobalRootNamespace.Instance.GetNamespace (name, true);
811                         else
812                                 ns = GlobalRootNamespace.Instance;
813                         SlaveDeclSpace = new RootDeclSpace (this);
814                 }
815
816                 private NamespaceEntry (NamespaceEntry parent, CompilationUnit file, Namespace ns, bool slave)
817                 {
818                         this.parent = parent;
819                         this.file = file;
820                         this.IsImplicit = true;
821                         this.ns = ns;
822                         this.SlaveDeclSpace = slave ? new RootDeclSpace (this) : null;
823                 }
824
825                 //
826                 // Populates the Namespace with some using declarations, used by the
827                 // eval mode. 
828                 //
829                 public void Populate (List<UsingAliasEntry> source_using_aliases, List<UsingEntry> source_using_clauses)
830                 {
831                         foreach (UsingAliasEntry uae in source_using_aliases){
832                                 if (using_aliases == null)
833                                         using_aliases = new List<UsingAliasEntry> ();
834                                 
835                                 using_aliases.Add (uae);
836                         }
837
838                         foreach (UsingEntry ue in source_using_clauses){
839                                 if (using_clauses == null)
840                                         using_clauses = new List<UsingEntry> ();
841                                 
842                                 using_clauses.Add (ue);
843                         }
844                 }
845
846                 //
847                 // Extracts the using alises and using clauses into a couple of
848                 // arrays that might already have the same information;  Used by the
849                 // C# Eval mode.
850                 //
851                 public void Extract (List<UsingAliasEntry> out_using_aliases, List<UsingEntry> out_using_clauses)
852                 {
853                         if (using_aliases != null){
854                                 foreach (UsingAliasEntry uae in using_aliases){
855                                         bool replaced = false;
856                                         
857                                         for (int i = 0; i < out_using_aliases.Count; i++){
858                                                 UsingAliasEntry out_uea = (UsingAliasEntry) out_using_aliases [i];
859                                                 
860                                                 if (out_uea.Alias == uae.Alias){
861                                                         out_using_aliases [i] = uae;
862                                                         replaced = true;
863                                                         break;
864                                                 }
865                                         }
866                                         if (!replaced)
867                                                 out_using_aliases.Add (uae);
868                                 }
869                         }
870
871                         if (using_clauses != null){
872                                 foreach (UsingEntry ue in using_clauses){
873                                         bool found = false;
874                                         
875                                         foreach (UsingEntry out_ue in out_using_clauses)
876                                                 if (out_ue.Name == ue.Name){
877                                                         found = true;
878                                                         break;
879                                                 }
880                                         if (!found)
881                                                 out_using_clauses.Add (ue);
882                                 }
883                         }
884                 }
885                 
886                 //
887                 // According to section 16.3.1 (using-alias-directive), the namespace-or-type-name is
888                 // resolved as if the immediately containing namespace body has no using-directives.
889                 //
890                 // Section 16.3.2 says that the same rule is applied when resolving the namespace-name
891                 // in the using-namespace-directive.
892                 //
893                 // To implement these rules, the expressions in the using directives are resolved using 
894                 // the "doppelganger" (ghostly bodiless duplicate).
895                 //
896                 NamespaceEntry doppelganger;
897                 NamespaceEntry Doppelganger {
898                         get {
899                                 if (!IsImplicit && doppelganger == null) {
900                                         doppelganger = new NamespaceEntry (ImplicitParent, file, ns, true);
901                                         doppelganger.using_aliases = using_aliases;
902                                 }
903                                 return doppelganger;
904                         }
905                 }
906
907                 public Namespace NS {
908                         get { return ns; }
909                 }
910
911                 public NamespaceEntry Parent {
912                         get { return parent; }
913                 }
914
915                 public NamespaceEntry ImplicitParent {
916                         get {
917                                 if (parent == null)
918                                         return null;
919                                 if (implicit_parent == null) {
920                                         implicit_parent = (parent.NS == ns.Parent)
921                                                 ? parent
922                                                 : new NamespaceEntry (parent, file, ns.Parent, false);
923                                 }
924                                 return implicit_parent;
925                         }
926                 }
927
928                 /// <summary>
929                 ///   Records a new namespace for resolving name references
930                 /// </summary>
931                 public void AddUsing (MemberName name, Location loc)
932                 {
933                         if (DeclarationFound){
934                                 Compiler.Report.Error (1529, loc, "A using clause must precede all other namespace elements except extern alias declarations");
935                         }
936
937                         if (using_clauses == null) {
938                                 using_clauses = new List<UsingEntry> ();
939                         } else {
940                                 foreach (UsingEntry old_entry in using_clauses) {
941                                         if (name.Equals (old_entry.MemberName)) {
942                                                 Compiler.Report.SymbolRelatedToPreviousError (old_entry.Location, old_entry.GetSignatureForError ());
943                                                 Compiler.Report.Warning (105, 3, loc, "The using directive for `{0}' appeared previously in this namespace", name.GetSignatureForError ());
944                                                 return;
945                                         }
946                                 }
947                         }
948
949                         using_clauses.Add (new UsingEntry (name));
950                 }
951
952                 public void AddUsingAlias (string alias, MemberName name, Location loc)
953                 {
954                         // TODO: This is parser bussines
955                         if (DeclarationFound){
956                                 Compiler.Report.Error (1529, loc, "A using clause must precede all other namespace elements except extern alias declarations");
957                         }
958
959                         if (RootContext.Version != LanguageVersion.ISO_1 && alias == "global")
960                                 Compiler.Report.Warning (440, 2, loc, "An alias named `global' will not be used when resolving 'global::';" +
961                                         " the global namespace will be used instead");
962
963                         AddUsingAlias (new LocalUsingAliasEntry (alias, name, loc));
964                 }
965
966                 public void AddUsingExternalAlias (string alias, Location loc, Report Report)
967                 {
968                         // TODO: Do this in parser
969                         bool not_first = using_clauses != null || DeclarationFound;
970                         if (using_aliases != null && !not_first) {
971                                 foreach (UsingAliasEntry uae in using_aliases) {
972                                         if (uae is LocalUsingAliasEntry) {
973                                                 not_first = true;
974                                                 break;
975                                         }
976                                 }
977                         }
978
979                         if (not_first)
980                                 Report.Error (439, loc, "An extern alias declaration must precede all other elements");
981
982                         if (alias == "global") {
983                                 Error_GlobalNamespaceRedefined (loc, Report);
984                                 return;
985                         }
986
987                         AddUsingAlias (new UsingAliasEntry (alias, loc));
988                 }
989
990                 void AddUsingAlias (UsingAliasEntry uae)
991                 {
992                         if (using_aliases == null) {
993                                 using_aliases = new List<UsingAliasEntry> ();
994                         } else {
995                                 foreach (UsingAliasEntry entry in using_aliases) {
996                                         if (uae.Alias == entry.Alias) {
997                                                 Compiler.Report.SymbolRelatedToPreviousError (uae.Location, uae.Alias);
998                                                 Compiler.Report.Error (1537, entry.Location, "The using alias `{0}' appeared previously in this namespace",
999                                                         entry.Alias);
1000                                                 return;
1001                                         }
1002                                 }
1003                         }
1004
1005                         using_aliases.Add (uae);
1006                 }
1007
1008                 ///
1009                 /// Does extension methods look up to find a method which matches name and extensionType.
1010                 /// Search starts from this namespace and continues hierarchically up to top level.
1011                 ///
1012                 public ExtensionMethodGroupExpr LookupExtensionMethod (TypeSpec extensionType, string name, int arity, Location loc)
1013                 {
1014                         List<MethodSpec> candidates = null;
1015                         foreach (Namespace n in GetUsingTable ()) {
1016                                 var a = n.LookupExtensionMethod (extensionType, null, name, arity);
1017                                 if (a == null)
1018                                         continue;
1019
1020                                 if (candidates == null)
1021                                         candidates = a;
1022                                 else
1023                                         candidates.AddRange (a);
1024                         }
1025
1026                         if (candidates != null)
1027                                 return new ExtensionMethodGroupExpr (candidates, parent, extensionType, loc);
1028
1029                         if (parent == null)
1030                                 return null;
1031
1032                         //
1033                         // Inspect parent namespaces in namespace expression
1034                         //
1035                         Namespace parent_ns = ns.Parent;
1036                         do {
1037                                 candidates = parent_ns.LookupExtensionMethod (extensionType, null, name, arity);
1038                                 if (candidates != null)
1039                                         return new ExtensionMethodGroupExpr (candidates, parent, extensionType, loc);
1040
1041                                 parent_ns = parent_ns.Parent;
1042                         } while (parent_ns != null);
1043
1044                         //
1045                         // Continue in parent scope
1046                         //
1047                         return parent.LookupExtensionMethod (extensionType, name, arity, loc);
1048                 }
1049
1050                 public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
1051                 {
1052                         // Precondition: Only simple names (no dots) will be looked up with this function.
1053                         FullNamedExpression resolved = null;
1054                         for (NamespaceEntry curr_ns = this; curr_ns != null; curr_ns = curr_ns.ImplicitParent) {
1055                                 if ((resolved = curr_ns.Lookup (name, arity, loc, ignore_cs0104)) != null)
1056                                         break;
1057                         }
1058
1059                         return resolved;
1060                 }
1061
1062                 public IList<string> CompletionGetTypesStartingWith (string prefix)
1063                 {
1064                         IEnumerable<string> all = Enumerable.Empty<string> ();
1065                         
1066                         for (NamespaceEntry curr_ns = this; curr_ns != null; curr_ns = curr_ns.ImplicitParent){
1067                                 foreach (Namespace using_ns in GetUsingTable ()){
1068                                         if (prefix.StartsWith (using_ns.Name)){
1069                                                 int ld = prefix.LastIndexOf ('.');
1070                                                 if (ld != -1){
1071                                                         string rest = prefix.Substring (ld+1);
1072
1073                                                         all = all.Concat (using_ns.CompletionGetTypesStartingWith (rest));
1074                                                 }
1075                                         }
1076                                         all = all.Concat (using_ns.CompletionGetTypesStartingWith (prefix));
1077                                 }
1078                         }
1079
1080                         return all.Distinct ().ToList ();
1081                 }
1082                 
1083                 // Looks-up a alias named @name in this and surrounding namespace declarations
1084                 public FullNamedExpression LookupNamespaceAlias (string name)
1085                 {
1086                         for (NamespaceEntry n = this; n != null; n = n.ImplicitParent) {
1087                                 if (n.using_aliases == null)
1088                                         continue;
1089
1090                                 foreach (UsingAliasEntry ue in n.using_aliases) {
1091                                         if (ue.Alias == name)
1092                                                 return ue.Resolve (Doppelganger);
1093                                 }
1094                         }
1095
1096                         return null;
1097                 }
1098
1099                 private FullNamedExpression Lookup (string name, int arity, Location loc, bool ignore_cs0104)
1100                 {
1101                         //
1102                         // Check whether it's in the namespace.
1103                         //
1104                         FullNamedExpression fne = ns.Lookup (Compiler, name, arity, loc);
1105
1106                         //
1107                         // Check aliases. 
1108                         //
1109                         if (using_aliases != null && arity == 0) {
1110                                 foreach (UsingAliasEntry ue in using_aliases) {
1111                                         if (ue.Alias == name) {
1112                                                 if (fne != null) {
1113                                                         if (Doppelganger != null) {
1114                                                                 // TODO: Namespace has broken location
1115                                                                 //Report.SymbolRelatedToPreviousError (fne.Location, null);
1116                                                                 Compiler.Report.SymbolRelatedToPreviousError (ue.Location, null);
1117                                                                 Compiler.Report.Error (576, loc,
1118                                                                         "Namespace `{0}' contains a definition with same name as alias `{1}'",
1119                                                                         GetSignatureForError (), name);
1120                                                         } else {
1121                                                                 return fne;
1122                                                         }
1123                                                 }
1124
1125                                                 return ue.Resolve (Doppelganger);
1126                                         }
1127                                 }
1128                         }
1129
1130                         if (fne != null) {
1131                                 if (!((fne.Type.Modifiers & Modifiers.INTERNAL) != 0 && !TypeManager.IsThisOrFriendAssembly (CodeGen.Assembly.Builder, fne.Type.Assembly)))
1132                                         return fne;
1133                         }
1134
1135                         if (IsImplicit)
1136                                 return null;
1137
1138                         //
1139                         // Check using entries.
1140                         //
1141                         FullNamedExpression match = null;
1142                         foreach (Namespace using_ns in GetUsingTable ()) {
1143                                 fne = using_ns.Lookup (Compiler, name, arity, loc);
1144                                 if (fne == null)
1145                                         continue;
1146
1147                                 if (match == null) {
1148                                         match = fne;
1149                                         continue;
1150                                 }
1151
1152                                 // Prefer types over namespaces
1153                                 var texpr_fne = fne as TypeExpr;
1154                                 var texpr_match = match as TypeExpr;
1155                                 if (texpr_fne != null && texpr_match == null) {
1156                                         match = fne;
1157                                         continue;
1158                                 } else if (texpr_fne == null && texpr_match != null) {
1159                                         continue;
1160                                 }
1161
1162                                 if (ignore_cs0104)
1163                                         return match;
1164
1165                                 // It can be top level accessibility only
1166                                 var better = Namespace.IsImportedTypeOverride (texpr_match.Type, texpr_fne.Type);
1167                                 if (better == null) {
1168                                         Compiler.Report.SymbolRelatedToPreviousError (texpr_match.Type);
1169                                         Compiler.Report.SymbolRelatedToPreviousError (texpr_fne.Type);
1170                                         Compiler.Report.Error (104, loc, "`{0}' is an ambiguous reference between `{1}' and `{2}'",
1171                                                 name, texpr_match.GetSignatureForError (), texpr_fne.GetSignatureForError ());
1172                                         return match;
1173                                 }
1174
1175                                 if (better == texpr_fne.Type)
1176                                         match = texpr_fne;
1177                         }
1178
1179                         return match;
1180                 }
1181
1182                 Namespace [] GetUsingTable ()
1183                 {
1184                         if (namespace_using_table != null)
1185                                 return namespace_using_table;
1186
1187                         if (using_clauses == null) {
1188                                 namespace_using_table = empty_namespaces;
1189                                 return namespace_using_table;
1190                         }
1191
1192                         var list = new List<Namespace> (using_clauses.Count);
1193
1194                         foreach (UsingEntry ue in using_clauses) {
1195                                 Namespace using_ns = ue.Resolve (Doppelganger);
1196                                 if (using_ns == null)
1197                                         continue;
1198
1199                                 list.Add (using_ns);
1200                         }
1201
1202                         namespace_using_table = list.ToArray ();
1203                         return namespace_using_table;
1204                 }
1205
1206                 static readonly string [] empty_using_list = new string [0];
1207
1208                 public int SymbolFileID {
1209                         get {
1210                                 if (symfile_id == 0 && file.SourceFileEntry != null) {
1211                                         int parent_id = parent == null ? 0 : parent.SymbolFileID;
1212
1213                                         string [] using_list = empty_using_list;
1214                                         if (using_clauses != null) {
1215                                                 using_list = new string [using_clauses.Count];
1216                                                 for (int i = 0; i < using_clauses.Count; i++)
1217                                                         using_list [i] = ((UsingEntry) using_clauses [i]).MemberName.GetName ();
1218                                         }
1219
1220                                         symfile_id = SymbolWriter.DefineNamespace (ns.Name, file.CompileUnitEntry, using_list, parent_id);
1221                                 }
1222                                 return symfile_id;
1223                         }
1224                 }
1225
1226                 static void MsgtryRef (string s)
1227                 {
1228                         Console.WriteLine ("    Try using -r:" + s);
1229                 }
1230
1231                 static void MsgtryPkg (string s)
1232                 {
1233                         Console.WriteLine ("    Try using -pkg:" + s);
1234                 }
1235
1236                 public static void Error_GlobalNamespaceRedefined (Location loc, Report Report)
1237                 {
1238                         Report.Error (1681, loc, "You cannot redefine the global extern alias");
1239                 }
1240
1241                 public static void Error_NamespaceNotFound (Location loc, string name, Report Report)
1242                 {
1243                         Report.Error (246, loc, "The type or namespace name `{0}' could not be found. Are you missing a using directive or an assembly reference?",
1244                                 name);
1245
1246                         switch (name) {
1247                         case "Gtk": case "GtkSharp":
1248                                 MsgtryPkg ("gtk-sharp");
1249                                 break;
1250
1251                         case "Gdk": case "GdkSharp":
1252                                 MsgtryPkg ("gdk-sharp");
1253                                 break;
1254
1255                         case "Glade": case "GladeSharp":
1256                                 MsgtryPkg ("glade-sharp");
1257                                 break;
1258
1259                         case "System.Drawing":
1260                         case "System.Web.Services":
1261                         case "System.Web":
1262                         case "System.Data":
1263                         case "System.Windows.Forms":
1264                                 MsgtryRef (name);
1265                                 break;
1266                         }
1267                 }
1268
1269                 /// <summary>
1270                 ///   Used to validate that all the using clauses are correct
1271                 ///   after we are finished parsing all the files.  
1272                 /// </summary>
1273                 void VerifyUsing ()
1274                 {
1275                         if (using_aliases != null) {
1276                                 foreach (UsingAliasEntry ue in using_aliases)
1277                                         ue.Resolve (Doppelganger);
1278                         }
1279
1280                         if (using_clauses != null) {
1281                                 foreach (UsingEntry ue in using_clauses)
1282                                         ue.Resolve (Doppelganger);
1283                         }
1284                 }
1285
1286                 /// <summary>
1287                 ///   Used to validate that all the using clauses are correct
1288                 ///   after we are finished parsing all the files.  
1289                 /// </summary>
1290                 static public void VerifyAllUsing ()
1291                 {
1292                         foreach (NamespaceEntry entry in entries)
1293                                 entry.VerifyUsing ();
1294                 }
1295
1296                 public string GetSignatureForError ()
1297                 {
1298                         return ns.GetSignatureForError ();
1299                 }
1300
1301                 public override string ToString ()
1302                 {
1303                         return ns.ToString ();
1304                 }
1305
1306                 #region IMemberContext Members
1307
1308                 public CompilerContext Compiler {
1309                         get { return RootContext.ToplevelTypes.Compiler; }
1310                 }
1311
1312                 public TypeSpec CurrentType {
1313                         get { return SlaveDeclSpace.CurrentType; }
1314                 }
1315
1316                 public MemberCore CurrentMemberDefinition {
1317                         get { return SlaveDeclSpace.CurrentMemberDefinition; }
1318                 }
1319
1320                 public TypeParameter[] CurrentTypeParameters {
1321                         get { return SlaveDeclSpace.CurrentTypeParameters; }
1322                 }
1323
1324                 public bool HasUnresolvedConstraints {
1325                         get { return false; }
1326                 }
1327
1328                 public bool IsObsolete {
1329                         get { return SlaveDeclSpace.IsObsolete; }
1330                 }
1331
1332                 public bool IsUnsafe {
1333                         get { return SlaveDeclSpace.IsUnsafe; }
1334                 }
1335
1336                 public bool IsStatic {
1337                         get { return SlaveDeclSpace.IsStatic; }
1338                 }
1339
1340                 #endregion
1341         }
1342 }