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