2 // namespace.cs: Tracks namespaces
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc
13 using System.Collections.Generic;
15 using Mono.CompilerServices.SymbolWriter;
17 namespace Mono.CSharp {
19 public class RootNamespace : Namespace {
21 readonly string alias_name;
22 readonly Dictionary<string, Namespace> all_namespaces;
24 public RootNamespace (string alias_name)
27 this.alias_name = alias_name;
28 RegisterNamespace (this);
30 all_namespaces = new Dictionary<string, Namespace> ();
31 all_namespaces.Add ("", this);
40 public static void Error_GlobalNamespaceRedefined (Report report, Location loc)
42 report.Error (1681, loc, "The global extern alias cannot be redefined");
46 // For better error reporting where we try to guess missing using directive
48 public List<string> FindTypeNamespaces (IMemberContext ctx, string name, int arity)
50 List<string> res = null;
52 foreach (var ns in all_namespaces) {
53 var type = ns.Value.LookupType (ctx, name, arity, LookupMode.Normal, Location.Null);
56 res = new List<string> ();
66 // For better error reporting where compiler tries to guess missing using directive
68 public List<string> FindExtensionMethodNamespaces (IMemberContext ctx, string name, int arity)
70 List<string> res = null;
72 foreach (var ns in all_namespaces) {
73 if (ns.Key.Length == 0)
76 var methods = ns.Value.LookupExtensionMethod (ctx, name, arity);
77 if (methods != null) {
79 res = new List<string> ();
88 public void RegisterNamespace (Namespace child)
91 all_namespaces.Add (child.Name, child);
94 public override string GetSignatureForError ()
96 return alias_name + "::";
100 public sealed class GlobalRootNamespace : RootNamespace
102 public GlobalRootNamespace ()
109 // Namespace cache for imported and compiled namespaces
111 public class Namespace
113 readonly Namespace parent;
115 protected Dictionary<string, Namespace> namespaces;
116 protected Dictionary<string, IList<TypeSpec>> types;
117 List<TypeSpec> extension_method_types;
118 Dictionary<string, TypeSpec> cached_types;
122 /// Constructor Takes the current namespace and the
123 /// name. This is bootstrapped with parent == null
126 public Namespace (Namespace parent, string name)
130 throw new ArgumentNullException ("name");
132 this.parent = parent;
134 string pname = parent != null ? parent.fullname : null;
139 fullname = pname + "." + name;
141 while (parent.parent != null)
142 parent = parent.parent;
144 var root = parent as RootNamespace;
146 throw new InternalErrorException ("Root namespaces must be created using RootNamespace");
148 root.RegisterNamespace (this);
151 protected Namespace ()
153 namespaces = new Dictionary<string, Namespace> ();
154 cached_types = new Dictionary<string, TypeSpec> ();
160 /// The qualified name of the current namespace
163 get { return fullname; }
167 /// The parent of this namespace, used by the parser to "Pop"
168 /// the current namespace declaration
170 public Namespace Parent {
171 get { return parent; }
176 public Namespace AddNamespace (MemberName name)
178 var ns_parent = name.Left == null ? this : AddNamespace (name.Left);
179 return ns_parent.TryAddNamespace (name.Basename);
182 Namespace TryAddNamespace (string name)
186 if (!namespaces.TryGetValue (name, out ns)) {
187 ns = new Namespace (this, name);
188 namespaces.Add (name, ns);
194 public bool TryGetNamespace (string name, out Namespace ns)
196 return namespaces.TryGetValue (name, out ns);
199 // TODO: Replace with CreateNamespace where MemberName is created for the method call
200 public Namespace GetNamespace (string name, bool create)
202 int pos = name.IndexOf ('.');
207 first = name.Substring (0, pos);
211 if (!namespaces.TryGetValue (first, out ns)) {
215 ns = new Namespace (this, first);
216 namespaces.Add (first, ns);
220 ns = ns.GetNamespace (name.Substring (pos + 1), create);
225 public IList<TypeSpec> GetAllTypes (string name)
227 IList<TypeSpec> found;
228 if (types == null || !types.TryGetValue (name, out found))
234 public virtual string GetSignatureForError ()
239 public TypeSpec LookupType (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
244 TypeSpec best = null;
245 if (arity == 0 && cached_types.TryGetValue (name, out best)) {
246 if (best != null || mode != LookupMode.IgnoreAccessibility)
250 IList<TypeSpec> found;
251 if (!types.TryGetValue (name, out found))
254 foreach (var ts in found) {
255 if (ts.Arity == arity) {
257 if ((ts.Modifiers & Modifiers.INTERNAL) != 0 && !ts.MemberDefinition.IsInternalAsPublic (ctx.Module.DeclaringAssembly) && mode != LookupMode.IgnoreAccessibility)
264 if (best.MemberDefinition.IsImported && ts.MemberDefinition.IsImported) {
265 if (ts.Kind == MemberKind.MissingType)
268 if (best.Kind == MemberKind.MissingType) {
273 if (mode == LookupMode.Normal) {
274 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (best);
275 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (ts);
276 ctx.Module.Compiler.Report.Error (433, loc, "The imported type `{0}' is defined multiple times", ts.GetSignatureForError ());
282 if (ts.Kind == MemberKind.MissingType)
285 if (best.MemberDefinition.IsImported)
288 if ((best.Modifiers & Modifiers.INTERNAL) != 0 && !best.MemberDefinition.IsInternalAsPublic (ctx.Module.DeclaringAssembly))
291 if (mode != LookupMode.Normal)
294 if (ts.MemberDefinition.IsImported) {
295 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (best);
296 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (ts);
299 ctx.Module.Compiler.Report.Warning (436, 2, loc,
300 "The type `{0}' conflicts with the imported type of same name'. Ignoring the imported type definition",
301 best.GetSignatureForError ());
305 // Lookup for the best candidate with the closest arity match
310 } else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (best.Arity + arity)) {
316 // TODO MemberCache: Cache more
317 if (arity == 0 && mode == LookupMode.Normal)
318 cached_types.Add (name, best);
321 var dep = best.GetMissingDependencies ();
323 ImportedTypeDefinition.Error_MissingDependency (ctx, dep, loc);
329 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
331 var texpr = LookupType (ctx, name, arity, mode, loc);
334 if (arity == 0 && namespaces.TryGetValue (name, out ns)) {
336 return new NamespaceExpression (ns, loc);
338 if (mode != LookupMode.Probing) {
339 //ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (texpr.Type);
340 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (ns.loc, "");
341 ctx.Module.Compiler.Report.Warning (437, 2, loc,
342 "The type `{0}' conflicts with the imported namespace `{1}'. Using the definition found in the source file",
343 texpr.GetSignatureForError (), ns.GetSignatureForError ());
346 if (texpr.MemberDefinition.IsImported)
347 return new NamespaceExpression (ns, loc);
353 return new TypeExpression (texpr, loc);
357 // Completes types with the given `prefix'
359 public IEnumerable<string> CompletionGetTypesStartingWith (string prefix)
362 return Enumerable.Empty<string> ();
364 var res = from item in types
365 where item.Key.StartsWith (prefix) && item.Value.Any (l => (l.Modifiers & Modifiers.PUBLIC) != 0)
368 if (namespaces != null)
369 res = res.Concat (from item in namespaces where item.Key.StartsWith (prefix) select item.Key);
375 // Looks for extension method in this namespace
377 public List<MethodSpec> LookupExtensionMethod (IMemberContext invocationContext, string name, int arity)
379 if (extension_method_types == null)
382 List<MethodSpec> found = null;
383 for (int i = 0; i < extension_method_types.Count; ++i) {
384 var ts = extension_method_types[i];
387 // When the list was built we didn't know what members the type
390 if ((ts.Modifiers & Modifiers.METHOD_EXTENSION) == 0) {
391 if (extension_method_types.Count == 1) {
392 extension_method_types = null;
396 extension_method_types.RemoveAt (i--);
400 var res = ts.MemberCache.FindExtensionMethods (invocationContext, name, arity);
407 found.AddRange (res);
414 public void AddType (ModuleContainer module, TypeSpec ts)
417 types = new Dictionary<string, IList<TypeSpec>> (64);
420 if (ts.IsClass && ts.Arity == 0) {
421 var extension_method_allowed = ts.MemberDefinition.IsImported ? (ts.Modifiers & Modifiers.METHOD_EXTENSION) != 0 : (ts.IsStatic || ts.MemberDefinition.IsPartial);
422 if (extension_method_allowed) {
423 if (extension_method_types == null)
424 extension_method_types = new List<TypeSpec> ();
426 extension_method_types.Add (ts);
431 IList<TypeSpec> existing;
432 if (types.TryGetValue (name, out existing)) {
433 TypeSpec better_type;
435 if (existing.Count == 1) {
437 if (ts.Arity == found.Arity) {
438 better_type = IsImportedTypeOverride (module, ts, found);
439 if (better_type == found)
442 if (better_type != null) {
443 existing [0] = better_type;
448 existing = new List<TypeSpec> ();
449 existing.Add (found);
450 types[name] = existing;
452 for (int i = 0; i < existing.Count; ++i) {
454 if (ts.Arity != found.Arity)
457 better_type = IsImportedTypeOverride (module, ts, found);
458 if (better_type == found)
461 if (better_type != null) {
462 existing.RemoveAt (i);
471 types.Add (name, new TypeSpec[] { ts });
476 // We import any types but in the situation there are same types
477 // but one has better visibility (either public or internal with friend)
478 // the less visible type is removed from the namespace cache
480 public static TypeSpec IsImportedTypeOverride (ModuleContainer module, TypeSpec ts, TypeSpec found)
482 var ts_accessible = (ts.Modifiers & Modifiers.PUBLIC) != 0 || ts.MemberDefinition.IsInternalAsPublic (module.DeclaringAssembly);
483 var found_accessible = (found.Modifiers & Modifiers.PUBLIC) != 0 || found.MemberDefinition.IsInternalAsPublic (module.DeclaringAssembly);
485 if (ts_accessible && !found_accessible)
488 // found is better always better for accessible or inaccessible ts
495 public void RemoveContainer (TypeContainer tc)
497 IList<TypeSpec> found;
498 if (types.TryGetValue (tc.MemberName.Name, out found)) {
499 for (int i = 0; i < found.Count; ++i) {
500 if (tc.MemberName.Arity != found [i].Arity)
503 if (found.Count == 1)
504 types.Remove (tc.MemberName.Name);
512 cached_types.Remove (tc.MemberName.Basename);
515 public void SetBuiltinType (BuiltinTypeSpec pts)
517 var found = types[pts.Name];
518 cached_types.Remove (pts.Name);
519 if (found.Count == 1) {
520 types[pts.Name][0] = pts;
522 throw new NotImplementedException ();
526 public void VerifyClsCompliance ()
528 if (types == null || cls_checked)
533 // TODO: This is quite ugly way to check for CLS compliance at namespace level
535 var locase_types = new Dictionary<string, List<TypeSpec>> (StringComparer.OrdinalIgnoreCase);
536 foreach (var tgroup in types.Values) {
537 foreach (var tm in tgroup) {
538 if ((tm.Modifiers & Modifiers.PUBLIC) == 0 || !tm.IsCLSCompliant ())
541 List<TypeSpec> found;
542 if (!locase_types.TryGetValue (tm.Name, out found)) {
543 found = new List<TypeSpec> ();
544 locase_types.Add (tm.Name, found);
551 foreach (var locase in locase_types.Values) {
552 if (locase.Count < 2)
555 bool all_same = true;
556 foreach (var notcompliant in locase) {
557 all_same = notcompliant.Name == locase[0].Name;
565 TypeContainer compiled = null;
566 foreach (var notcompliant in locase) {
567 if (!notcompliant.MemberDefinition.IsImported) {
568 if (compiled != null)
569 compiled.Compiler.Report.SymbolRelatedToPreviousError (compiled);
571 compiled = notcompliant.MemberDefinition as TypeContainer;
573 compiled.Compiler.Report.SymbolRelatedToPreviousError (notcompliant);
577 compiled.Compiler.Report.Warning (3005, 1, compiled.Location,
578 "Identifier `{0}' differing only in case is not CLS-compliant", compiled.GetSignatureForError ());
583 public class CompilationSourceFile : NamespaceContainer
585 readonly SourceFile file;
586 CompileUnitEntry comp_unit;
587 Dictionary<string, SourceFile> include_files;
588 Dictionary<string, bool> conditionals;
590 public CompilationSourceFile (ModuleContainer parent, SourceFile sourceFile)
593 this.file = sourceFile;
596 public CompilationSourceFile (ModuleContainer parent)
601 public CompileUnitEntry SymbolUnitEntry {
607 public string FileName {
613 public SourceFile SourceFile {
619 public void AddIncludeFile (SourceFile file)
621 if (file == this.file)
624 if (include_files == null)
625 include_files = new Dictionary<string, SourceFile> ();
627 if (!include_files.ContainsKey (file.OriginalFullPathName))
628 include_files.Add (file.OriginalFullPathName, file);
631 public void AddDefine (string value)
633 if (conditionals == null)
634 conditionals = new Dictionary<string, bool> (2);
636 conditionals[value] = true;
639 public void AddUndefine (string value)
641 if (conditionals == null)
642 conditionals = new Dictionary<string, bool> (2);
644 conditionals[value] = false;
647 public override void PrepareEmit ()
649 var sw = Module.DeclaringAssembly.SymbolWriter;
651 CreateUnitSymbolInfo (sw, Compiler.Settings.PathMap);
658 // Creates symbol file index in debug symbol file
660 void CreateUnitSymbolInfo (MonoSymbolFile symwriter, List<KeyValuePair<string, string>> pathMap)
662 var si = file.CreateSymbolInfo (symwriter, pathMap);
663 comp_unit = new CompileUnitEntry (symwriter, si);
665 if (include_files != null) {
666 foreach (SourceFile include in include_files.Values) {
667 si = include.CreateSymbolInfo (symwriter, pathMap);
668 comp_unit.AddFile (si);
673 public bool IsConditionalDefined (string value)
675 if (conditionals != null) {
677 if (conditionals.TryGetValue (value, out res))
680 // When conditional was undefined
681 if (conditionals.ContainsKey (value))
685 return Compiler.Settings.IsConditionalSymbolDefined (value);
688 public override void Accept (StructuralVisitor visitor)
690 visitor.Visit (this);
696 // Namespace block as created by the parser
698 public class NamespaceContainer : TypeContainer, IMemberContext
700 static readonly Namespace[] empty_namespaces = new Namespace[0];
702 readonly Namespace ns;
704 public new readonly NamespaceContainer Parent;
706 List<UsingClause> clauses;
708 // Used by parsed to check for parser errors
709 public bool DeclarationFound;
711 Namespace[] namespace_using_table;
712 TypeSpec[] types_using_table;
713 Dictionary<string, UsingAliasNamespace> aliases;
715 public NamespaceContainer (MemberName name, NamespaceContainer parent)
716 : base (parent, name, null, MemberKind.Namespace)
718 this.Parent = parent;
719 this.ns = parent.NS.AddNamespace (name);
721 containers = new List<TypeContainer> ();
724 protected NamespaceContainer (ModuleContainer parent)
725 : base (parent, null, null, MemberKind.Namespace)
727 ns = parent.GlobalRootNamespace;
728 containers = new List<TypeContainer> (2);
733 public override AttributeTargets AttributeTargets {
735 throw new NotSupportedException ();
739 public override string DocCommentHeader {
741 throw new NotSupportedException ();
745 public Namespace NS {
751 public List<UsingClause> Usings {
757 public override string[] ValidAttributeTargets {
759 throw new NotSupportedException ();
765 public void AddUsing (UsingClause un)
767 if (DeclarationFound){
768 Compiler.Report.Error (1529, un.Location, "A using clause must precede all other namespace elements except extern alias declarations");
772 clauses = new List<UsingClause> ();
777 public void AddUsing (UsingAliasNamespace un)
779 if (DeclarationFound){
780 Compiler.Report.Error (1529, un.Location, "A using clause must precede all other namespace elements except extern alias declarations");
786 void AddAlias (UsingAliasNamespace un)
788 if (clauses == null) {
789 clauses = new List<UsingClause> ();
791 foreach (var entry in clauses) {
792 var a = entry as UsingAliasNamespace;
793 if (a != null && a.Alias.Value == un.Alias.Value) {
794 Compiler.Report.SymbolRelatedToPreviousError (a.Location, "");
795 Compiler.Report.Error (1537, un.Location,
796 "The using alias `{0}' appeared previously in this namespace", un.Alias.Value);
804 public override void AddPartial (TypeDefinition next_part)
806 var existing = ns.LookupType (this, next_part.MemberName.Name, next_part.MemberName.Arity, LookupMode.Probing, Location.Null);
807 var td = existing != null ? existing.MemberDefinition as TypeDefinition : null;
808 AddPartial (next_part, td);
811 public override void AddTypeContainer (TypeContainer tc)
813 var mn = tc.MemberName;
814 var name = mn.Basename;
815 while (mn.Left != null) {
820 var names_container = Parent == null ? Module : (TypeContainer) this;
823 if (names_container.DefinedNames.TryGetValue (name, out mc)) {
824 if (tc is NamespaceContainer && mc is NamespaceContainer) {
825 AddTypeContainerMember (tc);
829 Report.SymbolRelatedToPreviousError (mc);
830 if ((mc.ModFlags & Modifiers.PARTIAL) != 0 && (tc is ClassOrStruct || tc is Interface)) {
831 Error_MissingPartialModifier (tc);
833 Report.Error (101, tc.Location, "The namespace `{0}' already contains a definition for `{1}'",
834 GetSignatureForError (), mn.GetSignatureForError ());
837 names_container.DefinedNames.Add (name, tc);
839 var tdef = tc.PartialContainer;
842 // Same name conflict in different namespace containers
844 var conflict = ns.GetAllTypes (mn.Name);
845 if (conflict != null) {
846 foreach (var e in conflict) {
847 if (e.Arity == mn.Arity) {
848 mc = (MemberCore) e.MemberDefinition;
855 Report.SymbolRelatedToPreviousError (mc);
856 Report.Error (101, tc.Location, "The namespace `{0}' already contains a definition for `{1}'",
857 GetSignatureForError (), mn.GetSignatureForError ());
859 ns.AddType (Module, tdef.Definition);
864 base.AddTypeContainer (tc);
867 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
869 throw new NotSupportedException ();
872 public override void EmitContainer ()
874 VerifyClsCompliance ();
876 base.EmitContainer ();
879 public ExtensionMethodCandidates LookupExtensionMethod (IMemberContext invocationContext, string name, int arity, int position)
882 // Here we try to resume the search for extension method at the point
883 // where the last bunch of candidates was found. It's more tricky than
884 // it seems as we have to check both namespace containers and namespace
892 // <our first search found candidates in A.B.C.D
896 // In the example above namespace A.B.C.D, A.B.C and A.B have to be
897 // checked before we hit A.N1 using
899 ExtensionMethodCandidates candidates;
900 var container = this;
902 candidates = container.LookupExtensionMethodCandidates (invocationContext, name, arity, ref position);
903 if (candidates != null || container.MemberName == null)
906 var container_ns = container.ns.Parent;
907 var mn = container.MemberName.Left;
908 int already_checked = position - 2;
909 while (already_checked-- > 0) {
911 container_ns = container_ns.Parent;
917 var methods = container_ns.LookupExtensionMethod (invocationContext, name, arity);
918 if (methods != null) {
919 return new ExtensionMethodCandidates (invocationContext, methods, container, position);
923 container_ns = container_ns.Parent;
927 container = container.Parent;
928 } while (container != null);
933 ExtensionMethodCandidates LookupExtensionMethodCandidates (IMemberContext invocationContext, string name, int arity, ref int position)
935 List<MethodSpec> candidates = null;
940 candidates = ns.LookupExtensionMethod (invocationContext, name, arity);
941 if (candidates != null) {
942 return new ExtensionMethodCandidates (invocationContext, candidates, this, position);
949 foreach (Namespace n in namespace_using_table) {
950 var a = n.LookupExtensionMethod (invocationContext, name, arity);
954 if (candidates == null)
957 candidates.AddRange (a);
960 if (types_using_table != null) {
961 foreach (var t in types_using_table) {
963 var res = t.MemberCache.FindExtensionMethods (invocationContext, name, arity);
967 if (candidates == null)
970 candidates.AddRange (res);
974 if (candidates != null)
975 return new ExtensionMethodCandidates (invocationContext, candidates, this, position);
981 public override FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
984 // Only simple names (no dots) will be looked up with this function
986 FullNamedExpression resolved;
987 for (NamespaceContainer container = this; container != null; container = container.Parent) {
988 resolved = container.Lookup (name, arity, mode, loc);
989 if (resolved != null || container.MemberName == null)
992 var container_ns = container.ns.Parent;
993 var mn = container.MemberName.Left;
995 resolved = container_ns.LookupTypeOrNamespace (this, name, arity, mode, loc);
996 if (resolved != null)
1000 container_ns = container_ns.Parent;
1007 public override void GetCompletionStartingWith (string prefix, List<string> results)
1012 foreach (var un in Usings) {
1013 if (un.Alias != null)
1016 var name = un.NamespaceExpression.Name;
1017 if (name.StartsWith (prefix))
1022 IEnumerable<string> all = Enumerable.Empty<string> ();
1024 foreach (Namespace using_ns in namespace_using_table) {
1025 if (prefix.StartsWith (using_ns.Name)) {
1026 int ld = prefix.LastIndexOf ('.');
1028 string rest = prefix.Substring (ld + 1);
1030 all = all.Concat (using_ns.CompletionGetTypesStartingWith (rest));
1033 all = all.Concat (using_ns.CompletionGetTypesStartingWith (prefix));
1036 results.AddRange (all);
1038 base.GetCompletionStartingWith (prefix, results);
1043 // Looks-up a alias named @name in this and surrounding namespace declarations
1045 public FullNamedExpression LookupExternAlias (string name)
1047 if (aliases == null)
1050 UsingAliasNamespace uan;
1051 if (aliases.TryGetValue (name, out uan) && uan is UsingExternAlias)
1052 return uan.ResolvedExpression;
1058 // Looks-up a alias named @name in this and surrounding namespace declarations
1060 public override FullNamedExpression LookupNamespaceAlias (string name)
1062 for (NamespaceContainer n = this; n != null; n = n.Parent) {
1063 if (n.aliases == null)
1066 UsingAliasNamespace uan;
1067 if (n.aliases.TryGetValue (name, out uan)) {
1068 if (uan.ResolvedExpression == null)
1071 return uan.ResolvedExpression;
1078 FullNamedExpression Lookup (string name, int arity, LookupMode mode, Location loc)
1081 // Check whether it's in the namespace.
1083 FullNamedExpression fne = ns.LookupTypeOrNamespace (this, name, arity, mode, loc);
1088 if (aliases != null && arity == 0) {
1089 UsingAliasNamespace uan;
1090 if (aliases.TryGetValue (name, out uan)) {
1091 if (fne != null && mode != LookupMode.Probing) {
1092 // TODO: Namespace has broken location
1093 //Report.SymbolRelatedToPreviousError (fne.Location, null);
1094 Compiler.Report.SymbolRelatedToPreviousError (uan.Location, null);
1095 Compiler.Report.Error (576, loc,
1096 "Namespace `{0}' contains a definition with same name as alias `{1}'",
1097 GetSignatureForError (), name);
1100 if (uan.ResolvedExpression == null)
1103 return uan.ResolvedExpression;
1111 // Lookup can be called before the namespace is defined from different namespace using alias clause
1113 if (namespace_using_table == null) {
1114 DoDefineNamespace ();
1118 // Check using entries.
1120 FullNamedExpression match = null;
1121 foreach (Namespace using_ns in namespace_using_table) {
1123 // A using directive imports only types contained in the namespace, it
1124 // does not import any nested namespaces
1126 var t = using_ns.LookupType (this, name, arity, mode, loc);
1130 fne = new TypeExpression (t, loc);
1131 if (match == null) {
1136 // Prefer types over namespaces
1137 var texpr_fne = fne as TypeExpr;
1138 var texpr_match = match as TypeExpr;
1139 if (texpr_fne != null && texpr_match == null) {
1142 } else if (texpr_fne == null) {
1146 // It can be top level accessibility only
1147 var better = Namespace.IsImportedTypeOverride (Module, texpr_match.Type, texpr_fne.Type);
1148 if (better == null) {
1149 if (mode == LookupMode.Normal) {
1150 Error_AmbiguousReference (name, texpr_match, texpr_fne, loc);
1156 if (better == texpr_fne.Type)
1160 if (types_using_table != null && (mode & LookupMode.IgnoreStaticUsing) == 0) {
1161 foreach (var using_type in types_using_table) {
1162 var type = MemberCache.FindNestedType (using_type, name, arity, true);
1166 fne = new TypeExpression (type, loc);
1167 if (match == null) {
1172 if (mode == LookupMode.Normal) {
1173 Error_AmbiguousReference (name, match, fne, loc);
1181 void Error_AmbiguousReference (string name, FullNamedExpression a, FullNamedExpression b, Location loc)
1183 var report = Compiler.Report;
1184 report.SymbolRelatedToPreviousError (a.Type);
1185 report.SymbolRelatedToPreviousError (b.Type);
1186 report.Error (104, loc, "`{0}' is an ambiguous reference between `{1}' and `{2}'",
1187 name, a.GetSignatureForError (), b.GetSignatureForError ());
1190 public static Expression LookupStaticUsings (IMemberContext mc, string name, int arity, Location loc)
1192 for (var m = mc.CurrentMemberDefinition; m != null; m = m.Parent) {
1194 var nc = m as NamespaceContainer;
1198 List<MemberSpec> candidates = null;
1199 if (nc.types_using_table != null) {
1200 foreach (var using_type in nc.types_using_table) {
1201 var members = MemberCache.FindMembers (using_type, name, true);
1202 if (members == null)
1205 foreach (var member in members) {
1206 if ((member.Kind & MemberKind.NestedMask) != 0) {
1207 // non-static nested type is included with using static
1209 if ((member.Modifiers & Modifiers.STATIC) == 0)
1212 if ((member.Modifiers & Modifiers.METHOD_EXTENSION) != 0)
1216 if (arity > 0 && member.Arity != arity)
1219 if (candidates == null)
1220 candidates = new List<MemberSpec> ();
1222 candidates.Add (member);
1227 if (candidates != null) {
1228 var expr = Expression.MemberLookupToExpression (mc, candidates, false, null, name, arity, Expression.MemberLookupRestrictions.None, loc);
1237 protected override void DefineNamespace ()
1239 if (namespace_using_table == null)
1240 DoDefineNamespace ();
1242 base.DefineNamespace ();
1245 void DoDefineNamespace ()
1247 namespace_using_table = empty_namespaces;
1249 if (clauses != null) {
1250 List<Namespace> namespaces = null;
1251 List<TypeSpec> types = null;
1253 bool post_process_using_aliases = false;
1255 for (int i = 0; i < clauses.Count; ++i) {
1256 var entry = clauses[i];
1258 if (entry.Alias != null) {
1259 if (aliases == null)
1260 aliases = new Dictionary<string, UsingAliasNamespace> ();
1263 // Aliases are not available when resolving using section
1264 // except extern aliases
1266 if (entry is UsingExternAlias) {
1267 entry.Define (this);
1268 if (entry.ResolvedExpression != null)
1269 aliases.Add (entry.Alias.Value, (UsingExternAlias) entry);
1271 clauses.RemoveAt (i--);
1273 post_process_using_aliases = true;
1280 entry.Define (this);
1283 // It's needed for repl only, when using clause cannot be resolved don't hold it in
1284 // global list which is resolved for every evaluation
1286 if (entry.ResolvedExpression == null) {
1287 clauses.RemoveAt (i--);
1291 if (entry.ResolvedExpression == null)
1294 var using_ns = entry.ResolvedExpression as NamespaceExpression;
1295 if (using_ns == null) {
1297 var type = entry.ResolvedExpression.Type;
1300 types = new List<TypeSpec> ();
1302 if (types.Contains (type)) {
1303 Warning_DuplicateEntry (entry);
1308 if (namespaces == null)
1309 namespaces = new List<Namespace> ();
1311 if (namespaces.Contains (using_ns.Namespace)) {
1312 // Ensure we don't report the warning multiple times in repl
1313 clauses.RemoveAt (i--);
1315 Warning_DuplicateEntry (entry);
1317 namespaces.Add (using_ns.Namespace);
1322 namespace_using_table = namespaces == null ? new Namespace [0] : namespaces.ToArray ();
1324 types_using_table = types.ToArray ();
1326 if (post_process_using_aliases) {
1327 for (int i = 0; i < clauses.Count; ++i) {
1328 var entry = clauses[i];
1329 if (entry.Alias != null) {
1330 aliases[entry.Alias.Value] = (UsingAliasNamespace) entry;
1337 protected override void DoDefineContainer ()
1339 base.DoDefineContainer ();
1341 if (clauses != null) {
1342 for (int i = 0; i < clauses.Count; ++i) {
1343 var entry = clauses[i];
1346 // Finish definition of using aliases not visited during container
1349 if (entry.Alias != null && entry.ResolvedExpression == null) {
1350 entry.Define (this);
1356 public void EnableRedefinition ()
1359 namespace_using_table = null;
1362 internal override void GenerateDocComment (DocumentationBuilder builder)
1364 if (containers != null) {
1365 foreach (var tc in containers)
1366 tc.GenerateDocComment (builder);
1370 public override string GetSignatureForError ()
1372 return MemberName == null ? "global::" : base.GetSignatureForError ();
1375 public override void RemoveContainer (TypeContainer cont)
1377 base.RemoveContainer (cont);
1378 NS.RemoveContainer (cont);
1381 protected override bool VerifyClsCompliance ()
1383 if (Module.IsClsComplianceRequired ()) {
1384 if (MemberName != null && MemberName.Name[0] == '_') {
1385 Warning_IdentifierNotCompliant ();
1388 ns.VerifyClsCompliance ();
1395 void Warning_DuplicateEntry (UsingClause entry)
1397 Compiler.Report.Warning (105, 3, entry.Location,
1398 "The using directive for `{0}' appeared previously in this namespace",
1399 entry.ResolvedExpression.GetSignatureForError ());
1402 public override void Accept (StructuralVisitor visitor)
1404 visitor.Visit (this);
1408 public class UsingNamespace : UsingClause
1410 public UsingNamespace (ATypeNameExpression expr, Location loc)
1415 public override void Define (NamespaceContainer ctx)
1419 var ns = resolved as NamespaceExpression;
1423 if (resolved != null) {
1424 var compiler = ctx.Module.Compiler;
1425 var type = resolved.Type;
1428 compiler.Report.SymbolRelatedToPreviousError (type);
1429 compiler.Report.Error (138, Location,
1430 "A `using' directive can only be applied to namespaces but `{0}' denotes a type. Consider using a `using static' instead",
1431 type.GetSignatureForError ());
1436 public class UsingType : UsingClause
1438 public UsingType (ATypeNameExpression expr, Location loc)
1443 public override void Define (NamespaceContainer ctx)
1447 if (resolved == null)
1450 var ns = resolved as NamespaceExpression;
1452 var compiler = ctx.Module.Compiler;
1453 compiler.Report.Error (7007, Location,
1454 "A 'using static' directive can only be applied to types but `{0}' denotes a namespace. Consider using a `using' directive instead",
1455 ns.GetSignatureForError ());
1459 // TODO: Need to move it to post_process_using_aliases
1460 //ObsoleteAttribute obsolete_attr = resolved.Type.GetAttributeObsolete ();
1461 //if (obsolete_attr != null) {
1462 // AttributeTester.Report_ObsoleteMessage (obsolete_attr, resolved.GetSignatureForError (), Location, ctx.Compiler.Report);
1467 public class UsingClause
1469 readonly ATypeNameExpression expr;
1470 readonly Location loc;
1471 protected FullNamedExpression resolved;
1473 public UsingClause (ATypeNameExpression expr, Location loc)
1481 public virtual SimpleMemberName Alias {
1487 public Location Location {
1493 public ATypeNameExpression NamespaceExpression {
1499 public FullNamedExpression ResolvedExpression {
1507 public string GetSignatureForError ()
1509 return expr.GetSignatureForError ();
1512 public virtual void Define (NamespaceContainer ctx)
1514 resolved = expr.ResolveAsTypeOrNamespace (ctx, false);
1517 public override string ToString()
1519 return resolved.ToString();
1523 public class UsingExternAlias : UsingAliasNamespace
1525 public UsingExternAlias (SimpleMemberName alias, Location loc)
1526 : base (alias, null, loc)
1530 public override void Define (NamespaceContainer ctx)
1532 var ns = ctx.Module.GetRootNamespace (Alias.Value);
1534 ctx.Module.Compiler.Report.Error (430, Location,
1535 "The extern alias `{0}' was not specified in -reference option",
1540 resolved = new NamespaceExpression (ns, Location);
1544 public class UsingAliasNamespace : UsingNamespace
1546 readonly SimpleMemberName alias;
1548 public struct AliasContext : IMemberContext
1550 readonly NamespaceContainer ns;
1552 public AliasContext (NamespaceContainer ns)
1557 public TypeSpec CurrentType {
1563 public TypeParameters CurrentTypeParameters {
1569 public MemberCore CurrentMemberDefinition {
1575 public bool IsObsolete {
1581 public bool IsUnsafe {
1583 throw new NotImplementedException ();
1587 public bool IsStatic {
1589 throw new NotImplementedException ();
1593 public ModuleContainer Module {
1599 public string GetSignatureForError ()
1601 throw new NotImplementedException ();
1604 public ExtensionMethodCandidates LookupExtensionMethod (string name, int arity)
1609 public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
1611 var fne = ns.NS.LookupTypeOrNamespace (ns, name, arity, mode, loc);
1616 // Only extern aliases are allowed in this context
1618 fne = ns.LookupExternAlias (name);
1619 if (fne != null || ns.MemberName == null)
1622 var container_ns = ns.NS.Parent;
1623 var mn = ns.MemberName.Left;
1624 while (mn != null) {
1625 fne = container_ns.LookupTypeOrNamespace (this, name, arity, mode, loc);
1630 container_ns = container_ns.Parent;
1633 if (ns.Parent != null)
1634 return ns.Parent.LookupNamespaceOrType (name, arity, mode, loc);
1639 public FullNamedExpression LookupNamespaceAlias (string name)
1641 return ns.LookupNamespaceAlias (name);
1645 public UsingAliasNamespace (SimpleMemberName alias, ATypeNameExpression expr, Location loc)
1651 public override SimpleMemberName Alias {
1657 public override void Define (NamespaceContainer ctx)
1660 // The namespace-or-type-name of a using-alias-directive is resolved as if
1661 // the immediately containing compilation unit or namespace body had no
1662 // using-directives. A using-alias-directive may however be affected
1663 // by extern-alias-directives in the immediately containing compilation
1664 // unit or namespace body
1666 // We achieve that by introducing alias-context which redirect any local
1667 // namespace or type resolve calls to parent namespace
1669 resolved = NamespaceExpression.ResolveAsTypeOrNamespace (new AliasContext (ctx), false) ??
1670 new TypeExpression (InternalType.ErrorType, NamespaceExpression.Location);