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