2 // namespace.cs: Tracks namespaces
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
10 using System
.Collections
;
11 using System
.Collections
.Specialized
;
12 using System
.Reflection
;
14 namespace Mono
.CSharp
{
16 public class RootNamespace
: Namespace
{
17 static MethodInfo get_namespaces_method
;
20 Assembly referenced_assembly
;
22 Hashtable all_namespaces
;
24 static Hashtable root_namespaces
;
25 public static GlobalRootNamespace Global
;
27 static RootNamespace ()
29 get_namespaces_method
= typeof (Assembly
).GetMethod ("GetNamespaces", BindingFlags
.Instance
| BindingFlags
.NonPublic
);
34 public static void Reset ()
36 root_namespaces
= new Hashtable ();
37 Global
= new GlobalRootNamespace ();
38 root_namespaces
["global"] = Global
;
41 protected RootNamespace (string alias_name
, Assembly assembly
)
42 : base (null, String
.Empty
)
44 this.alias_name
= alias_name
;
45 referenced_assembly
= assembly
;
47 all_namespaces
= new Hashtable ();
48 all_namespaces
.Add ("", this);
50 if (referenced_assembly
!= null)
51 ComputeNamespaces (this.referenced_assembly
);
54 public static void DefineRootNamespace (string name
, Assembly assembly
)
56 if (name
== "global") {
57 // FIXME: Add proper error number
58 Report
.Error (-42, "Cannot define an external alias named `global'");
61 RootNamespace retval
= GetRootNamespace (name
);
62 if (retval
== null || retval
.referenced_assembly
!= assembly
)
63 root_namespaces
[name
] = new RootNamespace (name
, assembly
);
66 public static RootNamespace
GetRootNamespace (string name
)
68 return (RootNamespace
) root_namespaces
[name
];
71 public virtual Type
LookupTypeReflection (string name
, Location loc
)
73 return GetTypeInAssembly (referenced_assembly
, name
);
76 public void RegisterNamespace (Namespace child
)
79 all_namespaces
.Add (child
.Name
, child
);
82 public bool IsNamespace (string name
)
84 return all_namespaces
.Contains (name
);
87 protected void EnsureNamespace (string dotted_name
)
89 if (dotted_name
!= null && dotted_name
!= "" && ! IsNamespace (dotted_name
))
90 GetNamespace (dotted_name
, true);
93 protected void ComputeNamespaces (Assembly assembly
)
95 if (get_namespaces_method
!= null) {
96 string [] namespaces
= (string []) get_namespaces_method
.Invoke (assembly
, null);
97 foreach (string ns
in namespaces
)
102 foreach (Type t
in assembly
.GetExportedTypes ())
103 EnsureNamespace (t
.Namespace
);
106 protected static Type
GetTypeInAssembly (Assembly assembly
, string name
)
108 Type t
= assembly
.GetType (name
);
113 throw new InternalErrorException ("Use GetPointerType() to get a pointer");
116 TypeAttributes ta
= t
.Attributes
& TypeAttributes
.VisibilityMask
;
117 if (ta
== TypeAttributes
.NestedPrivate
)
120 if (ta
== TypeAttributes
.NotPublic
||
121 ta
== TypeAttributes
.NestedAssembly
||
122 ta
== TypeAttributes
.NestedFamANDAssem
)
123 if (!TypeManager
.IsFriendAssembly (t
.Assembly
))
129 public override string ToString ()
131 return String
.Format ("RootNamespace ({0}::)", alias_name
);
134 public override string GetSignatureForError ()
136 return alias_name
+ "::";
140 public class GlobalRootNamespace
: RootNamespace
{
141 Assembly
[] assemblies
;
144 public GlobalRootNamespace ()
145 : base ("global", null)
147 assemblies
= new Assembly
[0];
150 public Assembly
[] Assemblies
{
151 get { return assemblies; }
154 public Module
[] Modules
{
155 get { return modules; }
158 public void AddAssemblyReference (Assembly a
)
160 foreach (Assembly assembly
in assemblies
) {
165 int top
= assemblies
.Length
;
166 Assembly
[] n
= new Assembly
[top
+ 1];
167 assemblies
.CopyTo (n
, 0);
171 ComputeNamespaces (a
);
174 public void AddModuleReference (Module m
)
176 int top
= modules
!= null ? modules
.Length
: 0;
177 Module
[] n
= new Module
[top
+ 1];
179 modules
.CopyTo (n
, 0);
183 if (m
== CodeGen
.Module
.Builder
)
186 foreach (Type t
in m
.GetTypes ())
187 EnsureNamespace (t
.Namespace
);
190 public override Type
LookupTypeReflection (string name
, Location loc
)
192 Type found_type
= null;
194 foreach (Assembly a
in assemblies
) {
195 Type t
= GetTypeInAssembly (a
, name
);
199 if (found_type
== null) {
204 Report
.SymbolRelatedToPreviousError (found_type
);
205 Report
.SymbolRelatedToPreviousError (t
);
206 Report
.Error (433, loc
, "The imported type `{0}' is defined multiple times", name
);
211 if (modules
!= null) {
212 foreach (Module module
in modules
) {
213 Type t
= module
.GetType (name
);
217 if (found_type
== null) {
222 Report
.SymbolRelatedToPreviousError (t
);
223 Report
.SymbolRelatedToPreviousError (found_type
);
224 Report
.Warning (436, 2, loc
, "Ignoring imported type `{0}' since the current assembly already has a declaration with the same name",
225 TypeManager
.CSharpName (t
));
235 /// Keeps track of the namespaces defined in the C# code.
237 /// This is an Expression to allow it to be referenced in the
238 /// compiler parse/intermediate tree during name resolution.
240 public class Namespace
: FullNamedExpression
{
244 Hashtable namespaces
;
245 IDictionary declspaces
;
246 Hashtable cached_types
;
249 public readonly MemberName MemberName
;
252 /// Constructor Takes the current namespace and the
253 /// name. This is bootstrapped with parent == null
256 public Namespace (Namespace parent
, string name
)
258 // Expression members.
259 this.eclass
= ExprClass
.Namespace
;
261 this.loc
= Location
.Null
;
263 this.parent
= parent
;
266 this.root
= parent
.root
;
268 this.root
= this as RootNamespace
;
270 if (this.root
== null)
271 throw new InternalErrorException ("Root namespaces must be created using RootNamespace");
273 string pname
= parent
!= null ? parent
.Name
: "";
278 fullname
= parent
.Name
+ "." + name
;
280 if (fullname
== null)
281 throw new InternalErrorException ("Namespace has a null fullname");
283 if (parent
!= null && parent
.MemberName
!= MemberName
.Null
)
284 MemberName
= new MemberName (
285 parent
.MemberName
, name
, parent
.MemberName
.Location
);
287 MemberName
= MemberName
.Null
;
289 MemberName
= new MemberName (name
, Location
.Null
);
291 namespaces
= new Hashtable ();
292 cached_types
= new Hashtable ();
294 root
.RegisterNamespace (this);
297 public override Expression
DoResolve (EmitContext ec
)
302 public override void Emit (EmitContext ec
)
304 throw new InternalErrorException ("Expression tree referenced namespace " + fullname
+ " during Emit ()");
307 public override string GetSignatureForError ()
312 public Namespace
GetNamespace (string name
, bool create
)
314 int pos
= name
.IndexOf ('.');
319 first
= name
.Substring (0, pos
);
323 ns
= (Namespace
) namespaces
[first
];
328 ns
= new Namespace (this, first
);
329 namespaces
.Add (first
, ns
);
333 ns
= ns
.GetNamespace (name
.Substring (pos
+ 1), create
);
338 TypeExpr
LookupType (string name
, Location loc
)
340 if (cached_types
.Contains (name
))
341 return cached_types
[name
] as TypeExpr
;
344 if (declspaces
!= null) {
345 DeclSpace tdecl
= declspaces
[name
] as DeclSpace
;
348 // Note that this is not:
350 // t = tdecl.DefineType ()
352 // This is to make it somewhat more useful when a DefineType
353 // fails due to problems in nested types (more useful in the sense
354 // of fewer misleading error messages)
357 t
= tdecl
.TypeBuilder
;
360 string lookup
= t
!= null ? t
.FullName
: (fullname
== "" ? name
: fullname
+ "." + name
);
361 Type rt
= root
.LookupTypeReflection (lookup
, loc
);
365 TypeExpr te
= t
== null ? null : new TypeExpression (t
, Location
.Null
);
366 cached_types
[name
] = te
;
370 public FullNamedExpression
Lookup (DeclSpace ds
, string name
, Location loc
)
372 if (namespaces
.Contains (name
))
373 return (Namespace
) namespaces
[name
];
375 TypeExpr te
= LookupType (name
, loc
);
376 if (te
== null || !ds
.CheckAccessLevel (te
.Type
))
382 public void AddDeclSpace (string name
, DeclSpace ds
)
384 if (declspaces
== null)
385 declspaces
= new HybridDictionary ();
386 declspaces
.Add (name
, ds
);
390 /// The qualified name of the current namespace
393 get { return fullname; }
396 public override string FullName
{
397 get { return fullname; }
401 /// The parent of this namespace, used by the parser to "Pop"
402 /// the current namespace declaration
404 public Namespace Parent
{
405 get { return parent; }
408 public override string ToString ()
410 return String
.Format ("Namespace ({0})", Name
);
414 public class NamespaceEntry
{
416 NamespaceEntry parent
, implicit_parent
;
420 ArrayList using_clauses
;
421 public bool DeclarationFound
= false;
424 ListDictionary extern_aliases
;
426 static ArrayList entries
= new ArrayList ();
428 public static void Reset ()
430 entries
= new ArrayList ();
434 // This class holds the location where a using definition is
435 // done, and whether it has been used by the program or not.
437 // We use this to flag using clauses for namespaces that do not
440 public class UsingEntry
{
441 public readonly MemberName Name
;
442 readonly Expression Expr
;
443 readonly NamespaceEntry NamespaceEntry
;
444 readonly Location Location
;
446 public UsingEntry (NamespaceEntry entry
, MemberName name
, Location loc
)
449 Expr
= name
.GetTypeExpression ();
450 NamespaceEntry
= entry
;
454 internal Namespace resolved
;
456 public Namespace
Resolve ()
458 if (resolved
!= null)
461 DeclSpace root
= RootContext
.Tree
.Types
;
462 root
.NamespaceEntry
= NamespaceEntry
;
463 FullNamedExpression fne
= Expr
.ResolveAsTypeStep (root
.EmitContext
, false);
464 root
.NamespaceEntry
= null;
467 Error_NamespaceNotFound (Location
, Name
.ToString ());
471 resolved
= fne
as Namespace
;
472 if (resolved
== null) {
473 Report
.Error (138, Location
,
474 "`{0} is a type not a namespace. A using namespace directive can only be applied to namespaces", Name
.ToString ());
480 public abstract class AliasEntry
{
481 public readonly string Name
;
482 public readonly NamespaceEntry NamespaceEntry
;
483 public readonly Location Location
;
485 protected AliasEntry (NamespaceEntry entry
, string name
, Location loc
)
488 NamespaceEntry
= entry
;
492 protected FullNamedExpression resolved
;
495 public FullNamedExpression
Resolve ()
497 if (resolved
!= null || error
)
499 resolved
= DoResolve ();
500 if (resolved
== null)
505 protected abstract FullNamedExpression
DoResolve ();
508 public class LocalAliasEntry
: AliasEntry
510 public readonly Expression Alias
;
512 public LocalAliasEntry (NamespaceEntry entry
, string name
, MemberName
alias, Location loc
) :
513 base (entry
, name
, loc
)
515 Alias
= alias.GetTypeExpression ();
518 protected override FullNamedExpression
DoResolve ()
520 DeclSpace root
= RootContext
.Tree
.Types
;
521 root
.NamespaceEntry
= NamespaceEntry
;
522 resolved
= Alias
.ResolveAsTypeStep (root
.EmitContext
, false);
523 root
.NamespaceEntry
= null;
525 if (resolved
== null)
526 Error_NamespaceNotFound (Location
, Alias
.ToString ());
531 public class ExternAliasEntry
: AliasEntry
533 public ExternAliasEntry (NamespaceEntry entry
, string name
, Location loc
) :
534 base (entry
, name
, loc
)
538 protected override FullNamedExpression
DoResolve ()
540 resolved
= RootNamespace
.GetRootNamespace (Name
);
541 if (resolved
== null)
542 Report
.Error (430, Location
, "The extern alias '" + Name
+
543 "' was not specified in a /reference option");
549 public NamespaceEntry (NamespaceEntry parent
, SourceFile file
, string name
, Location loc
)
551 this.parent
= parent
;
554 this.ID
= entries
.Count
;
557 ns
= parent
.NS
.GetNamespace (name
, true);
558 else if (name
!= null)
559 ns
= RootNamespace
.Global
.GetNamespace (name
, true);
561 ns
= RootNamespace
.Global
;
564 private NamespaceEntry (NamespaceEntry parent
, SourceFile file
, Namespace ns
)
566 this.parent
= parent
;
568 // no need to add self to 'entries', since we don't have any aliases or using entries.
570 this.IsImplicit
= true;
575 // According to section 16.3.1 (using-alias-directive), the namespace-or-type-name is
576 // resolved as if the immediately containing namespace body has no using-directives.
578 // Section 16.3.2 says that the same rule is applied when resolving the namespace-name
579 // in the using-namespace-directive.
581 // To implement these rules, the expressions in the using directives are resolved using
582 // the "doppelganger" (ghostly bodiless duplicate).
584 NamespaceEntry doppelganger
;
585 NamespaceEntry Doppelganger
{
587 if (!IsImplicit
&& doppelganger
== null)
588 doppelganger
= new NamespaceEntry (ImplicitParent
, file
, ns
);
593 public readonly int ID
;
594 public readonly bool IsImplicit
;
596 public Namespace NS
{
600 public NamespaceEntry Parent
{
601 get { return parent; }
604 public NamespaceEntry ImplicitParent
{
608 if (implicit_parent
== null) {
609 implicit_parent
= (parent
.NS
== ns
.Parent
)
611 : new NamespaceEntry (parent
, file
, ns
.Parent
);
613 return implicit_parent
;
618 /// Records a new namespace for resolving name references
620 public void Using (MemberName name
, Location loc
)
622 if (DeclarationFound
){
623 Report
.Error (1529, loc
, "A using clause must precede all other namespace elements except extern alias declarations");
629 if (name
.Equals (ns
.MemberName
))
632 if (using_clauses
== null)
633 using_clauses
= new ArrayList ();
635 foreach (UsingEntry old_entry
in using_clauses
) {
636 if (name
.Equals (old_entry
.Name
)) {
637 Report
.Warning (105, 3, loc
, "The using directive for `{0}' appeared previously in this namespace", name
.GetName ());
642 UsingEntry ue
= new UsingEntry (Doppelganger
, name
, loc
);
643 using_clauses
.Add (ue
);
646 public void UsingAlias (string name
, MemberName
alias, Location loc
)
648 if (DeclarationFound
){
649 Report
.Error (1529, loc
, "A using clause must precede all other namespace elements except extern alias declarations");
656 aliases
= new Hashtable ();
658 if (aliases
.Contains (name
)) {
659 AliasEntry ae
= (AliasEntry
)aliases
[name
];
660 Report
.SymbolRelatedToPreviousError (ae
.Location
, ae
.Name
);
661 Report
.Error (1537, loc
, "The using alias `" + name
+
662 "' appeared previously in this namespace");
666 if (RootContext
.Version
== LanguageVersion
.Default
&&
667 name
== "global" && RootContext
.WarningLevel
>= 2)
668 Report
.Warning (440, 2, loc
, "An alias named `global' will not be used when resolving 'global::';" +
669 " the global namespace will be used instead");
671 aliases
[name
] = new LocalAliasEntry (Doppelganger
, name
, alias, loc
);
674 public void UsingExternalAlias (string name
, Location loc
)
676 if (UsingFound
|| DeclarationFound
) {
677 Report
.Error (439, loc
, "An extern alias declaration must precede all other elements");
682 aliases
= new Hashtable ();
684 // Share the extern_aliases field with the Doppelganger
685 if (extern_aliases
== null) {
686 extern_aliases
= new ListDictionary ();
687 Doppelganger
.extern_aliases
= extern_aliases
;
690 if (aliases
.Contains (name
)) {
691 AliasEntry ae
= (AliasEntry
) aliases
[name
];
692 Report
.SymbolRelatedToPreviousError (ae
.Location
, ae
.Name
);
693 Report
.Error (1537, loc
, "The using alias `" + name
+
694 "' appeared previously in this namespace");
698 if (name
== "global") {
699 Report
.Error (1681, loc
, "You cannot redefine the global extern alias");
703 // Register the alias in aliases and extern_aliases, since we need both of them
704 // to keep things simple (different resolution scenarios)
705 ExternAliasEntry
alias = new ExternAliasEntry (Doppelganger
, name
, loc
);
706 aliases
[name
] = alias;
707 extern_aliases
[name
] = alias;
710 public FullNamedExpression
LookupNamespaceOrType (DeclSpace ds
, string name
, Location loc
, bool ignore_cs0104
)
712 // Precondition: Only simple names (no dots) will be looked up with this function.
713 FullNamedExpression resolved
= null;
714 for (NamespaceEntry curr_ns
= this; curr_ns
!= null; curr_ns
= curr_ns
.ImplicitParent
) {
715 if ((resolved
= curr_ns
.Lookup (ds
, name
, loc
, ignore_cs0104
)) != null)
721 static void Error_AmbiguousTypeReference (Location loc
, string name
, FullNamedExpression t1
, FullNamedExpression t2
)
723 Report
.Error (104, loc
, "`{0}' is an ambiguous reference between `{1}' and `{2}'",
724 name
, t1
.FullName
, t2
.FullName
);
727 // Looks-up a alias named @name in this and surrounding namespace declarations
728 public FullNamedExpression
LookupAlias (string name
)
730 AliasEntry entry
= null;
731 // We use Parent rather than ImplicitParent since we know implicit namespace declarations
732 // cannot have using entries.
733 for (NamespaceEntry n
= this; n
!= null; n
= n
.Parent
) {
734 if (n
.aliases
== null)
736 entry
= n
.aliases
[name
] as AliasEntry
;
738 return entry
.Resolve ();
743 private FullNamedExpression
Lookup (DeclSpace ds
, string name
, Location loc
, bool ignore_cs0104
)
746 // Check whether it's in the namespace.
748 FullNamedExpression fne
= NS
.Lookup (ds
, name
, loc
);
752 if (extern_aliases
!= null) {
753 AliasEntry entry
= extern_aliases
[name
] as AliasEntry
;
755 return entry
.Resolve ();
764 if (aliases
!= null) {
765 AliasEntry entry
= aliases
[name
] as AliasEntry
;
767 return entry
.Resolve ();
771 // Check using entries.
773 FullNamedExpression match
= null;
774 foreach (Namespace using_ns
in GetUsingTable ()) {
775 match
= using_ns
.Lookup (ds
, name
, loc
);
776 if (match
== null || !(match
is TypeExpr
))
780 Error_AmbiguousTypeReference (loc
, name
, fne
, match
);
789 // Our cached computation.
790 readonly Namespace
[] empty_namespaces
= new Namespace
[0];
791 Namespace
[] namespace_using_table
;
792 Namespace
[] GetUsingTable ()
794 if (namespace_using_table
!= null)
795 return namespace_using_table
;
797 if (using_clauses
== null) {
798 namespace_using_table
= empty_namespaces
;
799 return namespace_using_table
;
802 ArrayList list
= new ArrayList (using_clauses
.Count
);
804 foreach (UsingEntry ue
in using_clauses
) {
805 Namespace using_ns
= ue
.Resolve ();
806 if (using_ns
== null)
812 namespace_using_table
= new Namespace
[list
.Count
];
813 list
.CopyTo (namespace_using_table
, 0);
814 return namespace_using_table
;
817 readonly string [] empty_using_list
= new string [0];
819 public int SymbolFileID
{
821 if (symfile_id
== 0 && file
.SourceFileEntry
!= null) {
822 int parent_id
= parent
== null ? 0 : parent
.SymbolFileID
;
824 string [] using_list
= empty_using_list
;
825 if (using_clauses
!= null) {
826 using_list
= new string [using_clauses
.Count
];
827 for (int i
= 0; i
< using_clauses
.Count
; i
++)
828 using_list
[i
] = ((UsingEntry
) using_clauses
[i
]).Name
.ToString ();
831 symfile_id
= CodeGen
.SymbolWriter
.DefineNamespace (ns
.Name
, file
.SourceFileEntry
, using_list
, parent_id
);
837 static void MsgtryRef (string s
)
839 Console
.WriteLine (" Try using -r:" + s
);
842 static void MsgtryPkg (string s
)
844 Console
.WriteLine (" Try using -pkg:" + s
);
847 public static void Error_NamespaceNotFound (Location loc
, string name
)
849 Report
.Error (246, loc
, "The type or namespace name `{0}' could not be found. Are you missing a using directive or an assembly reference?",
853 case "Gtk": case "GtkSharp":
854 MsgtryPkg ("gtk-sharp");
857 case "Gdk": case "GdkSharp":
858 MsgtryPkg ("gdk-sharp");
861 case "Glade": case "GladeSharp":
862 MsgtryPkg ("glade-sharp");
865 case "System.Drawing":
866 case "System.Web.Services":
869 case "System.Windows.Forms":
876 /// Used to validate that all the using clauses are correct
877 /// after we are finished parsing all the files.
881 if (using_clauses
!= null) {
882 foreach (UsingEntry ue
in using_clauses
)
886 if (aliases
!= null) {
887 foreach (DictionaryEntry de
in aliases
)
888 ((AliasEntry
) de
.Value
).Resolve ();
893 /// Used to validate that all the using clauses are correct
894 /// after we are finished parsing all the files.
896 static public void VerifyAllUsing ()
898 foreach (NamespaceEntry entry
in entries
)
899 entry
.VerifyUsing ();
902 public string GetSignatureForError ()
904 return ns
.GetSignatureForError ();
907 public override string ToString ()
909 return ns
.ToString ();