Use correct type when setting UnattachedAttributes. Fix the error message not to...
[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                 TypeSpec LookupType (string name, int arity)
331                 {
332                         if (types == null)
333                                 return null;
334
335                         IList<TypeSpec> found;
336                         if (types.TryGetValue (name, out found)) {
337                                 TypeSpec best = null;
338
339                                 foreach (var ts in found) {
340                                         if (ts.Arity == arity)
341                                                 return ts;
342
343                                         //
344                                         // Lookup for the best candidate with closest arity match
345                                         //
346                                         if (arity < 0) {
347                                                 if (best == null) {
348                                                         best = ts;
349                                                 } else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (best.Arity + arity)) {
350                                                         best = ts;
351                                                 }
352                                         }
353                                 }
354                                 
355                                 return best;
356                         }
357
358                         return null;
359                 }
360
361                 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
362                 {
363                         var texpr = LookupType (ctx, name, arity, mode, loc);
364
365                         Namespace ns;
366                         if (arity == 0 && namespaces.TryGetValue (name, out ns)) {
367                                 if (texpr == null)
368                                         return ns;
369
370                                 if (mode != LookupMode.Probing) {
371                                         ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (texpr.Type);
372                                         // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (ns.loc, "");
373                                         ctx.Module.Compiler.Report.Warning (437, 2, loc,
374                                                 "The type `{0}' conflicts with the imported namespace `{1}'. Using the definition found in the source file",
375                                                 texpr.GetSignatureForError (), ns.GetSignatureForError ());
376                                 }
377
378                                 if (texpr.Type.MemberDefinition.IsImported)
379                                         return ns;
380                         }
381
382                         return texpr;
383                 }
384
385                 //
386                 // Completes types with the given `prefix'
387                 //
388                 public IEnumerable<string> CompletionGetTypesStartingWith (string prefix)
389                 {
390                         if (types == null)
391                                 return Enumerable.Empty<string> ();
392
393                         var res = from item in types
394                                           where item.Key.StartsWith (prefix) && item.Value.Any (l => (l.Modifiers & Modifiers.PUBLIC) != 0)
395                                           select item.Key;
396
397                         if (namespaces != null)
398                                 res = res.Concat (from item in namespaces where item.Key.StartsWith (prefix) select item.Key);
399
400                         return res;
401                 }
402
403                 // 
404                 // Looks for extension method in this namespace
405                 //
406                 public List<MethodSpec> LookupExtensionMethod (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity)
407                 {
408                         if (extension_method_types == null)
409                                 return null;
410
411                         List<MethodSpec> found = null;
412                         for (int i = 0; i < extension_method_types.Count; ++i) {
413                                 var ts = extension_method_types[i];
414
415                                 //
416                                 // When the list was built we didn't know what members the type
417                                 // contains
418                                 //
419                                 if ((ts.Modifiers & Modifiers.METHOD_EXTENSION) == 0) {
420                                         if (extension_method_types.Count == 1) {
421                                                 extension_method_types = null;
422                                                 return found;
423                                         }
424
425                                         extension_method_types.RemoveAt (i--);
426                                         continue;
427                                 }
428
429                                 var res = ts.MemberCache.FindExtensionMethods (invocationContext, extensionType, name, arity);
430                                 if (res == null)
431                                         continue;
432
433                                 if (found == null) {
434                                         found = res;
435                                 } else {
436                                         found.AddRange (res);
437                                 }
438                         }
439
440                         return found;
441                 }
442
443                 public void AddType (ModuleContainer module, TypeSpec ts)
444                 {
445                         if (types == null) {
446                                 types = new Dictionary<string, IList<TypeSpec>> (64);
447                         }
448
449                         if (ts.IsStatic && ts.Arity == 0 &&
450                                 (ts.MemberDefinition.DeclaringAssembly == null || ts.MemberDefinition.DeclaringAssembly.HasExtensionMethod)) {
451                                 if (extension_method_types == null)
452                                         extension_method_types = new List<TypeSpec> ();
453
454                                 extension_method_types.Add (ts);
455                         }
456
457                         var name = ts.Name;
458                         IList<TypeSpec> existing;
459                         if (types.TryGetValue (name, out existing)) {
460                                 TypeSpec better_type;
461                                 TypeSpec found;
462                                 if (existing.Count == 1) {
463                                         found = existing[0];
464                                         if (ts.Arity == found.Arity) {
465                                                 better_type = IsImportedTypeOverride (module, ts, found);
466                                                 if (better_type == found)
467                                                         return;
468
469                                                 if (better_type != null) {
470                                                         existing [0] = better_type;
471                                                         return;
472                                                 }
473                                         }
474
475                                         existing = new List<TypeSpec> ();
476                                         existing.Add (found);
477                                         types[name] = existing;
478                                 } else {
479                                         for (int i = 0; i < existing.Count; ++i) {
480                                                 found = existing[i];
481                                                 if (ts.Arity != found.Arity)
482                                                         continue;
483
484                                                 better_type = IsImportedTypeOverride (module, ts, found);
485                                                 if (better_type == found)
486                                                         return;
487
488                                                 if (better_type != null) {
489                                                         existing.RemoveAt (i);
490                                                         --i;
491                                                         continue;
492                                                 }
493                                         }
494                                 }
495
496                                 existing.Add (ts);
497                         } else {
498                                 types.Add (name, new TypeSpec[] { ts });
499                         }
500                 }
501
502                 //
503                 // We import any types but in the situation there are same types
504                 // but one has better visibility (either public or internal with friend)
505                 // the less visible type is removed from the namespace cache
506                 //
507                 public static TypeSpec IsImportedTypeOverride (ModuleContainer module, TypeSpec ts, TypeSpec found)
508                 {
509                         var ts_accessible = (ts.Modifiers & Modifiers.PUBLIC) != 0 || ts.MemberDefinition.IsInternalAsPublic (module.DeclaringAssembly);
510                         var found_accessible = (found.Modifiers & Modifiers.PUBLIC) != 0 || found.MemberDefinition.IsInternalAsPublic (module.DeclaringAssembly);
511
512                         if (ts_accessible && !found_accessible)
513                                 return ts;
514
515                         // found is better always better for accessible or inaccessible ts
516                         if (!ts_accessible)
517                                 return found;
518
519                         return null;
520                 }
521
522                 public void RemoveContainer (TypeContainer tc)
523                 {
524                         types.Remove (tc.Basename);
525                         cached_types.Remove (tc.Basename);
526                 }
527
528                 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
529                 {
530                         return this;
531                 }
532
533                 public void SetBuiltinType (BuiltinTypeSpec pts)
534                 {
535                         var found = types[pts.Name];
536                         cached_types.Remove (pts.Name);
537                         if (found.Count == 1) {
538                                 types[pts.Name][0] = pts;
539                         } else {
540                                 throw new NotImplementedException ();
541                         }
542                 }
543
544                 public void VerifyClsCompliance ()
545                 {
546                         if (types == null || cls_checked)
547                                 return;
548
549                         cls_checked = true;
550
551                         // TODO: This is quite ugly way to check for CLS compliance at namespace level
552
553                         var locase_types = new Dictionary<string, List<TypeSpec>> (StringComparer.OrdinalIgnoreCase);
554                         foreach (var tgroup in types.Values) {
555                                 foreach (var tm in tgroup) {
556                                         if ((tm.Modifiers & Modifiers.PUBLIC) == 0 || !tm.IsCLSCompliant ())
557                                                 continue;
558
559                                         List<TypeSpec> found;
560                                         if (!locase_types.TryGetValue (tm.Name, out found)) {
561                                                 found = new List<TypeSpec> ();
562                                                 locase_types.Add (tm.Name, found);
563                                         }
564
565                                         found.Add (tm);
566                                 }
567                         }
568
569                         foreach (var locase in locase_types.Values) {
570                                 if (locase.Count < 2)
571                                         continue;
572
573                                 bool all_same = true;
574                                 foreach (var notcompliant in locase) {
575                                         all_same = notcompliant.Name == locase[0].Name;
576                                         if (!all_same)
577                                                 break;
578                                 }
579
580                                 if (all_same)
581                                         continue;
582
583                                 TypeContainer compiled = null;
584                                 foreach (var notcompliant in locase) {
585                                         if (!notcompliant.MemberDefinition.IsImported) {
586                                                 if (compiled != null)
587                                                         compiled.Compiler.Report.SymbolRelatedToPreviousError (compiled);
588
589                                                 compiled = notcompliant.MemberDefinition as TypeContainer;
590                                         } else {
591                                                 compiled.Compiler.Report.SymbolRelatedToPreviousError (notcompliant);
592                                         }
593                                 }
594
595                                 compiled.Compiler.Report.Warning (3005, 1, compiled.Location,
596                                         "Identifier `{0}' differing only in case is not CLS-compliant", compiled.GetSignatureForError ());
597                         }
598                 }
599         }
600
601         public class CompilationSourceFile : NamespaceContainer
602         {
603                 readonly SourceFile file;
604                 CompileUnitEntry comp_unit;
605                 Dictionary<string, SourceFile> include_files;
606                 Dictionary<string, bool> conditionals;
607
608                 public CompilationSourceFile (ModuleContainer parent, SourceFile sourceFile)
609                         : this (parent)
610                 {
611                         this.file = sourceFile;
612                 }
613
614                 public CompilationSourceFile (ModuleContainer parent)
615                         : base (parent)
616                 {
617                 }
618
619                 public CompileUnitEntry SymbolUnitEntry {
620                         get {
621                                 return comp_unit;
622                         }
623                 }
624
625                 public string FileName {
626                         get {
627                                 return file.Name;
628                         }
629                 }
630
631                 public SourceFile SourceFile {
632                         get {
633                                 return file;
634                         }
635                 }
636
637                 public void AddIncludeFile (SourceFile file)
638                 {
639                         if (file == this.file)
640                                 return;
641
642                         if (include_files == null)
643                                 include_files = new Dictionary<string, SourceFile> ();
644
645                         if (!include_files.ContainsKey (file.FullPathName))
646                                 include_files.Add (file.FullPathName, file);
647                 }
648
649                 public void AddDefine (string value)
650                 {
651                         if (conditionals == null)
652                                 conditionals = new Dictionary<string, bool> (2);
653
654                         conditionals[value] = true;
655                 }
656
657                 public void AddUndefine (string value)
658                 {
659                         if (conditionals == null)
660                                 conditionals = new Dictionary<string, bool> (2);
661
662                         conditionals[value] = false;
663                 }
664
665                 public override void PrepareEmit ()
666                 {
667                         // Compiler.SymbolWriter
668                         if (SymbolWriter.symwriter != null) {
669                                 CreateUnitSymbolInfo (SymbolWriter.symwriter);
670                         }
671
672                         base.PrepareEmit ();
673                 }
674
675                 //
676                 // Creates symbol file index in debug symbol file
677                 //
678                 void CreateUnitSymbolInfo (MonoSymbolWriter symwriter)
679                 {
680                         var si = file.CreateSymbolInfo (symwriter);
681                         comp_unit = symwriter.DefineCompilationUnit (si);
682
683                         if (include_files != null) {
684                                 foreach (SourceFile include in include_files.Values) {
685                                         si = include.CreateSymbolInfo (symwriter);
686                                         comp_unit.AddFile (si);
687                                 }
688                         }
689                 }
690
691                 public bool IsConditionalDefined (string value)
692                 {
693                         if (conditionals != null) {
694                                 bool res;
695                                 if (conditionals.TryGetValue (value, out res))
696                                         return res;
697
698                                 // When conditional was undefined
699                                 if (conditionals.ContainsKey (value))
700                                         return false;
701                         }
702
703                         return Compiler.Settings.IsConditionalSymbolDefined (value);
704                 }
705         }
706
707
708         //
709         // Namespace block as created by the parser
710         //
711         public class NamespaceContainer : TypeContainer, IMemberContext
712         {
713                 static readonly Namespace[] empty_namespaces = new Namespace[0];
714
715                 readonly Namespace ns;
716
717                 public new readonly NamespaceContainer Parent;
718
719                 List<UsingNamespace> clauses;
720
721                 // Used by parsed to check for parser errors
722                 public bool DeclarationFound;
723
724                 Namespace[] namespace_using_table;
725                 Dictionary<string, UsingAliasNamespace> aliases;
726
727                 public NamespaceContainer (MemberName name, NamespaceContainer parent)
728                         : base (parent, name, null, MemberKind.Namespace)
729                 {
730                         this.Parent = parent;
731                         this.ns = parent.NS.AddNamespace (name);
732
733                         containers = new List<TypeContainer> ();
734                 }
735
736                 protected NamespaceContainer (ModuleContainer parent)
737                         : base (parent, null, null, MemberKind.Namespace)
738                 {
739                         ns = parent.GlobalRootNamespace;
740                         containers = new List<TypeContainer> (2);
741                 }
742
743                 #region Properties
744
745                 public override AttributeTargets AttributeTargets {
746                         get {
747                                 throw new NotSupportedException ();
748                         }
749                 }
750
751                 public override string DocCommentHeader {
752                         get {
753                                 throw new NotSupportedException ();
754                         }
755                 }
756
757                 public Namespace NS {
758                         get {
759                                 return ns;
760                         }
761                 }
762
763                 public List<UsingNamespace> Usings {
764                         get {
765                                 return clauses;
766                         }
767                 }
768
769                 public override string[] ValidAttributeTargets {
770                         get {
771                                 throw new NotSupportedException ();
772                         }
773                 }
774
775                 #endregion
776
777                 public void AddUsing (UsingNamespace un)
778                 {
779                         if (DeclarationFound){
780                                 Compiler.Report.Error (1529, un.Location, "A using clause must precede all other namespace elements except extern alias declarations");
781                         }
782
783                         if (clauses == null)
784                                 clauses = new List<UsingNamespace> ();
785
786                         clauses.Add (un);
787                 }
788
789                 public void AddUsing (UsingAliasNamespace un)
790                 {
791                         if (DeclarationFound){
792                                 Compiler.Report.Error (1529, un.Location, "A using clause must precede all other namespace elements except extern alias declarations");
793                         }
794
795                         AddAlias (un);
796                 }
797
798                 void AddAlias (UsingAliasNamespace un)
799                 {
800                         if (clauses == null) {
801                                 clauses = new List<UsingNamespace> ();
802                         } else {
803                                 foreach (var entry in clauses) {
804                                         var a = entry as UsingAliasNamespace;
805                                         if (a != null && a.Alias.Value == un.Alias.Value) {
806                                                 Compiler.Report.SymbolRelatedToPreviousError (a.Location, "");
807                                                 Compiler.Report.Error (1537, un.Location,
808                                                         "The using alias `{0}' appeared previously in this namespace", un.Alias.Value);
809                                         }
810                                 }
811                         }
812
813                         clauses.Add (un);
814                 }
815
816                 public override void AddPartial (TypeDefinition next_part)
817                 {
818                         var existing = ns.LookupType (this, next_part.MemberName.Name, next_part.MemberName.Arity, LookupMode.Probing, Location.Null);
819                         var td = existing != null ? existing.Type.MemberDefinition as TypeDefinition : null;
820                         AddPartial (next_part, td);
821                 }
822
823                 public override void AddTypeContainer (TypeContainer tc)
824                 {
825                         string name = tc.Basename;
826
827                         var mn = tc.MemberName;
828                         while (mn.Left != null) {
829                                 mn = mn.Left;
830                                 name = mn.Name;
831                         }
832
833                         MemberCore mc;
834                         if (defined_names.TryGetValue (name, out mc)) {
835                                 if (tc is NamespaceContainer && mc is NamespaceContainer) {
836                                         containers.Add (tc);
837                                         return;
838                                 }
839
840                                 Report.SymbolRelatedToPreviousError (mc);
841                                 if ((mc.ModFlags & Modifiers.PARTIAL) != 0 && (tc is ClassOrStruct || tc is Interface)) {
842                                         Error_MissingPartialModifier (tc);
843                                 } else {
844                                         Report.Error (101, tc.Location, "The namespace `{0}' already contains a definition for `{1}'",
845                                                 GetSignatureForError (), mn.GetSignatureForError ());
846                                 }
847                         } else {
848                                 defined_names.Add (name, tc);
849                         }
850
851                         base.AddTypeContainer (tc);
852
853                         var tdef = tc.PartialContainer;
854                         if (tdef != null)
855                                 ns.AddType (Module, tdef.Definition);
856                 }
857
858                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
859                 {
860                         throw new NotSupportedException ();
861                 }
862
863                 public override void EmitContainer ()
864                 {
865                         VerifyClsCompliance ();
866
867                         base.EmitContainer ();
868                 }
869
870                 public ExtensionMethodCandidates LookupExtensionMethod (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity, NamespaceContainer container, int position)
871                 {
872                         //
873                         // Here we try to resume the search for extension method at the point
874                         // where the last bunch of candidates was found. It's more tricky than
875                         // it seems as we have to check both namespace containers and namespace
876                         // in correct order.
877                         //
878                         // Consider:
879                         // 
880                         // namespace A {
881                         //      using N1;
882                         //  namespace B.C.D {
883                         //              <our first search found candidates in A.B.C.D
884                         //  }
885                         // }
886                         //
887                         // In the example above namespace A.B.C.D, A.B.C and A.B have to be
888                         // checked before we hit A.N1 using
889                         //
890                         ExtensionMethodCandidates candidates;
891                         for (; container != null; container = container.Parent) {
892                                 candidates = container.LookupExtensionMethodCandidates (invocationContext, extensionType, name, arity, ref position);
893                                 if (candidates != null || container.MemberName == null)
894                                         return candidates;
895
896                                 var container_ns = container.ns.Parent;
897                                 var mn = container.MemberName.Left;
898                                 int already_checked = position - 2;
899                                 while (already_checked-- > 0) {
900                                         mn = mn.Left;
901                                         container_ns = container_ns.Parent;
902                                 }
903
904                                 while (mn != null) {
905                                         ++position;
906
907                                         var methods = container_ns.LookupExtensionMethod (invocationContext, extensionType, name, arity);
908                                         if (methods != null) {
909                                                 return new ExtensionMethodCandidates (invocationContext, methods, container, position);
910                                         }
911
912                                         mn = mn.Left;
913                                         container_ns = container_ns.Parent;
914                                 }
915
916                                 position = 0;
917                         }
918
919                         return null;
920                 }
921
922                 ExtensionMethodCandidates LookupExtensionMethodCandidates (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity, ref int position)
923                 {
924                         List<MethodSpec> candidates = null;
925
926                         if (position == 0) {
927                                 ++position;
928
929                                 candidates = ns.LookupExtensionMethod (invocationContext, extensionType, name, arity);
930                                 if (candidates != null) {
931                                         return new ExtensionMethodCandidates (invocationContext, candidates, this, position);
932                                 }
933                         }
934
935                         if (position == 1) {
936                                 ++position;
937
938                                 foreach (Namespace n in namespace_using_table) {
939                                         var a = n.LookupExtensionMethod (invocationContext, extensionType, name, arity);
940                                         if (a == null)
941                                                 continue;
942
943                                         if (candidates == null)
944                                                 candidates = a;
945                                         else
946                                                 candidates.AddRange (a);
947                                 }
948
949                                 if (candidates != null)
950                                         return new ExtensionMethodCandidates (invocationContext, candidates, this, position);
951                         }
952
953                         return null;
954                 }
955
956                 public override FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
957                 {
958                         //
959                         // Only simple names (no dots) will be looked up with this function
960                         //
961                         FullNamedExpression resolved;
962                         for (NamespaceContainer container = this; container != null; container = container.Parent) {
963                                 resolved = container.Lookup (name, arity, mode, loc);
964                                 if (resolved != null || container.MemberName == null)
965                                         return resolved;
966
967                                 var container_ns = container.ns.Parent;
968                                 var mn = container.MemberName.Left;
969                                 while (mn != null) {
970                                         resolved = container_ns.LookupTypeOrNamespace (this, name, arity, mode, loc);
971                                         if (resolved != null)
972                                                 return resolved;
973
974                                         mn = mn.Left;
975                                         container_ns = container_ns.Parent;
976                                 }
977                         }
978
979                         return null;
980                 }
981
982                 public override void GetCompletionStartingWith (string prefix, List<string> results)
983                 {
984                         foreach (var un in Usings) {
985                                 if (un.Alias != null)
986                                         continue;
987
988                                 var name = un.NamespaceExpression.Name;
989                                 if (name.StartsWith (prefix))
990                                         results.Add (name);
991                         }
992
993
994                         IEnumerable<string> all = Enumerable.Empty<string> ();
995
996                         foreach (Namespace using_ns in namespace_using_table) {
997                                 if (prefix.StartsWith (using_ns.Name)) {
998                                         int ld = prefix.LastIndexOf ('.');
999                                         if (ld != -1) {
1000                                                 string rest = prefix.Substring (ld + 1);
1001
1002                                                 all = all.Concat (using_ns.CompletionGetTypesStartingWith (rest));
1003                                         }
1004                                 }
1005                                 all = all.Concat (using_ns.CompletionGetTypesStartingWith (prefix));
1006                         }
1007
1008                         results.AddRange (all);
1009
1010                         base.GetCompletionStartingWith (prefix, results);
1011                 }
1012
1013                 
1014                 //
1015                 // Looks-up a alias named @name in this and surrounding namespace declarations
1016                 //
1017                 public FullNamedExpression LookupExternAlias (string name)
1018                 {
1019                         if (aliases == null)
1020                                 return null;
1021
1022                         UsingAliasNamespace uan;
1023                         if (aliases.TryGetValue (name, out uan) && uan is UsingExternAlias)
1024                                 return uan.ResolvedExpression;
1025
1026                         return null;
1027                 }
1028                 
1029                 //
1030                 // Looks-up a alias named @name in this and surrounding namespace declarations
1031                 //
1032                 public override FullNamedExpression LookupNamespaceAlias (string name)
1033                 {
1034                         for (NamespaceContainer n = this; n != null; n = n.Parent) {
1035                                 if (n.aliases == null)
1036                                         continue;
1037
1038                                 UsingAliasNamespace uan;
1039                                 if (n.aliases.TryGetValue (name, out uan))
1040                                         return uan.ResolvedExpression;
1041                         }
1042
1043                         return null;
1044                 }
1045
1046                 FullNamedExpression Lookup (string name, int arity, LookupMode mode, Location loc)
1047                 {
1048                         //
1049                         // Check whether it's in the namespace.
1050                         //
1051                         FullNamedExpression fne = ns.LookupTypeOrNamespace (this, name, arity, mode, loc);
1052
1053                         //
1054                         // Check aliases. 
1055                         //
1056                         if (aliases != null && arity == 0) {
1057                                 UsingAliasNamespace uan;
1058                                 if (aliases.TryGetValue (name, out uan)) {
1059                                         if (fne != null) {
1060                                                 // TODO: Namespace has broken location
1061                                                 //Report.SymbolRelatedToPreviousError (fne.Location, null);
1062                                                 Compiler.Report.SymbolRelatedToPreviousError (uan.Location, null);
1063                                                 Compiler.Report.Error (576, loc,
1064                                                         "Namespace `{0}' contains a definition with same name as alias `{1}'",
1065                                                         GetSignatureForError (), name);
1066                                         }
1067
1068                                         return uan.ResolvedExpression;
1069                                 }
1070                         }
1071
1072                         if (fne != null)
1073                                 return fne;
1074
1075                         //
1076                         // Lookup can be called before the namespace is defined from different namespace using alias clause
1077                         //
1078                         if (namespace_using_table == null) {
1079                                 DoDefineNamespace ();
1080                         }
1081
1082                         //
1083                         // Check using entries.
1084                         //
1085                         FullNamedExpression match = null;
1086                         foreach (Namespace using_ns in namespace_using_table) {
1087                                 //
1088                                 // A using directive imports only types contained in the namespace, it
1089                                 // does not import any nested namespaces
1090                                 //
1091                                 fne = using_ns.LookupType (this, name, arity, mode, loc);
1092                                 if (fne == null)
1093                                         continue;
1094
1095                                 if (match == null) {
1096                                         match = fne;
1097                                         continue;
1098                                 }
1099
1100                                 // Prefer types over namespaces
1101                                 var texpr_fne = fne as TypeExpr;
1102                                 var texpr_match = match as TypeExpr;
1103                                 if (texpr_fne != null && texpr_match == null) {
1104                                         match = fne;
1105                                         continue;
1106                                 } else if (texpr_fne == null) {
1107                                         continue;
1108                                 }
1109
1110                                 // It can be top level accessibility only
1111                                 var better = Namespace.IsImportedTypeOverride (Module, texpr_match.Type, texpr_fne.Type);
1112                                 if (better == null) {
1113                                         if (mode == LookupMode.Normal) {
1114                                                 Compiler.Report.SymbolRelatedToPreviousError (texpr_match.Type);
1115                                                 Compiler.Report.SymbolRelatedToPreviousError (texpr_fne.Type);
1116                                                 Compiler.Report.Error (104, loc, "`{0}' is an ambiguous reference between `{1}' and `{2}'",
1117                                                         name, texpr_match.GetSignatureForError (), texpr_fne.GetSignatureForError ());
1118                                         }
1119
1120                                         return match;
1121                                 }
1122
1123                                 if (better == texpr_fne.Type)
1124                                         match = texpr_fne;
1125                         }
1126
1127                         return match;
1128                 }
1129
1130                 static void MsgtryRef (string s)
1131                 {
1132                         Console.WriteLine ("    Try using -r:" + s);
1133                 }
1134
1135                 static void MsgtryPkg (string s)
1136                 {
1137                         Console.WriteLine ("    Try using -pkg:" + s);
1138                 }
1139
1140                 public static void Error_NamespaceNotFound (Location loc, string name, Report Report)
1141                 {
1142                         Report.Error (246, loc, "The type or namespace name `{0}' could not be found. Are you missing a using directive or an assembly reference?",
1143                                 name);
1144
1145                         switch (name) {
1146                         case "Gtk": case "GtkSharp":
1147                                 MsgtryPkg ("gtk-sharp-2.0");
1148                                 break;
1149
1150                         case "Gdk": case "GdkSharp":
1151                                 MsgtryPkg ("gdk-sharp-2.0");
1152                                 break;
1153
1154                         case "Glade": case "GladeSharp":
1155                                 MsgtryPkg ("glade-sharp-2.0");
1156                                 break;
1157
1158                         case "System.Drawing":
1159                         case "System.Web.Services":
1160                         case "System.Web":
1161                         case "System.Data":
1162                         case "System.Windows.Forms":
1163                                 MsgtryRef (name);
1164                                 break;
1165                         }
1166                 }
1167
1168                 protected override void DefineNamespace ()
1169                 {
1170                         if (namespace_using_table == null)
1171                                 DoDefineNamespace ();
1172
1173                         base.DefineNamespace ();
1174                 }
1175
1176                 void DoDefineNamespace ()
1177                 {
1178                         namespace_using_table = empty_namespaces;
1179
1180                         if (clauses != null) {
1181                                 var list = new List<Namespace> (clauses.Count);
1182                                 bool post_process_using_aliases = false;
1183
1184                                 for (int i = 0; i < clauses.Count; ++i) {
1185                                         var entry = clauses[i];
1186
1187                                         if (entry.Alias != null) {
1188                                                 if (aliases == null)
1189                                                         aliases = new Dictionary<string, UsingAliasNamespace> ();
1190
1191                                                 //
1192                                                 // Aliases are not available when resolving using section
1193                                                 // except extern aliases
1194                                                 //
1195                                                 if (entry is UsingExternAlias) {
1196                                                         entry.Define (this);
1197                                                         if (entry.ResolvedExpression != null)
1198                                                                 aliases.Add (entry.Alias.Value, (UsingExternAlias) entry);
1199
1200                                                         clauses.RemoveAt (i--);
1201                                                 } else {
1202                                                         post_process_using_aliases = true;
1203                                                 }
1204
1205                                                 continue;
1206                                         }
1207
1208                                         entry.Define (this);
1209
1210                                         Namespace using_ns = entry.ResolvedExpression as Namespace;
1211                                         if (using_ns == null)
1212                                                 continue;
1213
1214                                         if (list.Contains (using_ns)) {
1215                                                 Compiler.Report.Warning (105, 3, entry.Location,
1216                                                         "The using directive for `{0}' appeared previously in this namespace", using_ns.GetSignatureForError ());
1217                                         } else {
1218                                                 list.Add (using_ns);
1219                                         }
1220                                 }
1221
1222                                 namespace_using_table = list.ToArray ();
1223
1224                                 if (post_process_using_aliases) {
1225                                         for (int i = 0; i < clauses.Count; ++i) {
1226                                                 var entry = clauses[i];
1227                                                 if (entry.Alias != null) {
1228                                                         entry.Define (this);
1229                                                         if (entry.ResolvedExpression != null) {
1230                                                                 aliases.Add (entry.Alias.Value, (UsingAliasNamespace) entry);
1231                                                         }
1232
1233                                                         clauses.RemoveAt (i--);
1234                                                 }
1235                                         }
1236                                 }
1237                         }
1238                 }
1239
1240                 public void EnableUsingClausesRedefinition ()
1241                 {
1242                         namespace_using_table = null;
1243                 }
1244
1245                 internal override void GenerateDocComment (DocumentationBuilder builder)
1246                 {
1247                         if (containers != null) {
1248                                 foreach (var tc in containers)
1249                                         tc.GenerateDocComment (builder);
1250                         }
1251                 }
1252
1253                 public override string GetSignatureForError ()
1254                 {
1255                         return MemberName == null ? "global::" : base.GetSignatureForError ();
1256                 }
1257
1258                 public override void RemoveContainer (TypeContainer cont)
1259                 {
1260                         base.RemoveContainer (cont);
1261                         NS.RemoveContainer (cont);
1262                 }
1263
1264                 protected override bool VerifyClsCompliance ()
1265                 {
1266                         if (Module.IsClsComplianceRequired ()) {
1267                                 if (MemberName != null && MemberName.Name[0] == '_') {
1268                                         Warning_IdentifierNotCompliant ();
1269                                 }
1270
1271                                 ns.VerifyClsCompliance ();
1272                                 return true;
1273                         }
1274
1275                         return false;
1276                 }
1277         }
1278
1279         public class UsingNamespace
1280         {
1281                 readonly ATypeNameExpression expr;
1282                 readonly Location loc;
1283                 protected FullNamedExpression resolved;
1284
1285                 public UsingNamespace (ATypeNameExpression expr, Location loc)
1286                 {
1287                         this.expr = expr;
1288                         this.loc = loc;
1289                 }
1290
1291                 #region Properties
1292
1293                 public virtual SimpleMemberName Alias {
1294                         get {
1295                                 return null;
1296                         }
1297                 }
1298
1299                 public Location Location {
1300                         get {
1301                                 return loc;
1302                         }
1303                 }
1304
1305                 public ATypeNameExpression NamespaceExpression  {
1306                         get {
1307                                 return expr;
1308                         }
1309                 }
1310
1311                 public FullNamedExpression ResolvedExpression {
1312                         get {
1313                                 return resolved;
1314                         }
1315                 }
1316
1317                 #endregion
1318
1319                 public string GetSignatureForError ()
1320                 {
1321                         return expr.GetSignatureForError ();
1322                 }
1323
1324                 public virtual void Define (NamespaceContainer ctx)
1325                 {
1326                         resolved = expr.ResolveAsTypeOrNamespace (ctx);
1327                         var ns = resolved as Namespace;
1328                         if (ns == null) {
1329                                 if (resolved != null) {
1330                                         ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (resolved.Type);
1331                                         ctx.Module.Compiler.Report.Error (138, Location,
1332                                                 "`{0}' is a type not a namespace. A using namespace directive can only be applied to namespaces",
1333                                                 GetSignatureForError ());
1334                                 }
1335                         }
1336                 }
1337         }
1338
1339         public class UsingExternAlias : UsingAliasNamespace
1340         {
1341                 public UsingExternAlias (SimpleMemberName alias, Location loc)
1342                         : base (alias, null, loc)
1343                 {
1344                 }
1345
1346                 public override void Define (NamespaceContainer ctx)
1347                 {
1348                         resolved = ctx.Module.GetRootNamespace (Alias.Value);
1349                         if (resolved == null) {
1350                                 ctx.Module.Compiler.Report.Error (430, Location,
1351                                         "The extern alias `{0}' was not specified in -reference option",
1352                                         Alias.Value);
1353                         }
1354                 }
1355         }
1356
1357         public class UsingAliasNamespace : UsingNamespace
1358         {
1359                 readonly SimpleMemberName alias;
1360
1361                 public struct AliasContext : IMemberContext
1362                 {
1363                         readonly NamespaceContainer ns;
1364
1365                         public AliasContext (NamespaceContainer ns)
1366                         {
1367                                 this.ns = ns;
1368                         }
1369
1370                         public TypeSpec CurrentType {
1371                                 get {
1372                                         return null;
1373                                 }
1374                         }
1375
1376                         public TypeParameters CurrentTypeParameters {
1377                                 get {
1378                                         return null;
1379                                 }
1380                         }
1381
1382                         public MemberCore CurrentMemberDefinition {
1383                                 get {
1384                                         return null;
1385                                 }
1386                         }
1387
1388                         public bool IsObsolete {
1389                                 get {
1390                                         return false;
1391                                 }
1392                         }
1393
1394                         public bool IsUnsafe {
1395                                 get {
1396                                         throw new NotImplementedException ();
1397                                 }
1398                         }
1399
1400                         public bool IsStatic {
1401                                 get {
1402                                         throw new NotImplementedException ();
1403                                 }
1404                         }
1405
1406                         public ModuleContainer Module {
1407                                 get {
1408                                         return ns.Module;
1409                                 }
1410                         }
1411
1412                         public string GetSignatureForError ()
1413                         {
1414                                 throw new NotImplementedException ();
1415                         }
1416
1417                         public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
1418                         {
1419                                 return null;
1420                         }
1421
1422                         public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
1423                         {
1424                                 var fne = ns.NS.LookupTypeOrNamespace (ns, name, arity, mode, loc);
1425                                 if (fne != null)
1426                                         return fne;
1427
1428                                 //
1429                                 // Only extern aliases are allowed in this context
1430                                 //
1431                                 fne = ns.LookupExternAlias (name);
1432                                 if (fne != null || ns.MemberName == null)
1433                                         return fne;
1434
1435                                 var container_ns = ns.NS.Parent;
1436                                 var mn = ns.MemberName.Left;
1437                                 while (mn != null) {
1438                                         fne = container_ns.LookupTypeOrNamespace (this, name, arity, mode, loc);
1439                                         if (fne != null)
1440                                                 return fne;
1441
1442                                         mn = mn.Left;
1443                                         container_ns = container_ns.Parent;
1444                                 }
1445
1446                                 if (ns.Parent != null)
1447                                         return ns.Parent.LookupNamespaceOrType (name, arity, mode, loc);
1448
1449                                 return null;
1450                         }
1451
1452                         public FullNamedExpression LookupNamespaceAlias (string name)
1453                         {
1454                                 return ns.LookupNamespaceAlias (name);
1455                         }
1456                 }
1457
1458                 public UsingAliasNamespace (SimpleMemberName alias, ATypeNameExpression expr, Location loc)
1459                         : base (expr, loc)
1460                 {
1461                         this.alias = alias;
1462                 }
1463
1464                 public override SimpleMemberName Alias {
1465                         get {
1466                                 return alias;
1467                         }
1468                 }
1469
1470                 public override void Define (NamespaceContainer ctx)
1471                 {
1472                         //
1473                         // The namespace-or-type-name of a using-alias-directive is resolved as if
1474                         // the immediately containing compilation unit or namespace body had no
1475                         // using-directives. A using-alias-directive may however be affected
1476                         // by extern-alias-directives in the immediately containing compilation
1477                         // unit or namespace body
1478                         //
1479                         // We achieve that by introducing alias-context which redirect any local
1480                         // namespace or type resolve calls to parent namespace
1481                         //
1482                         resolved = NamespaceExpression.ResolveAsTypeOrNamespace (new AliasContext (ctx));
1483                 }
1484         }
1485 }