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