Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Parser/mcs/namespace.cs @ 17197

Last change on this file since 17197 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

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