Merge pull request #498 from Unroll-Me/master
[mono.git] / mcs / mcs / namespace.cs
index 3d7f204abbb3fd8085312dfe9965f510b2ca0abb..7dd44807f6810e358d40b258aed1bbce65ddb369 100644 (file)
@@ -12,6 +12,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using Mono.CompilerServices.SymbolWriter;
 
 namespace Mono.CSharp {
 
@@ -40,6 +41,46 @@ namespace Mono.CSharp {
                        report.Error (1681, loc, "The global extern alias cannot be redefined");
                }
 
+               //
+               // For better error reporting where we try to guess missing using directive
+               //
+               public List<string> FindTypeNamespaces (IMemberContext ctx, string name, int arity)
+               {
+                       List<string> res = null;
+
+                       foreach (var ns in all_namespaces) {
+                               var type = ns.Value.LookupType (ctx, name, arity, LookupMode.Normal, Location.Null);
+                               if (type != null) {
+                                       if (res == null)
+                                               res = new List<string> ();
+
+                                       res.Add (ns.Key);
+                               }
+                       }
+
+                       return res;
+               }
+
+               //
+               // For better error reporting where compiler tries to guess missing using directive
+               //
+               public List<string> FindExtensionMethodNamespaces (IMemberContext ctx, TypeSpec extensionType, string name, int arity)
+               {
+                       List<string> res = null;
+
+                       foreach (var ns in all_namespaces) {
+                               var methods = ns.Value.LookupExtensionMethod (ctx, extensionType, name, arity);
+                               if (methods != null) {
+                                       if (res == null)
+                                               res = new List<string> ();
+
+                                       res.Add (ns.Key);
+                               }
+                       }
+
+                       return res;
+               }
+
                public void RegisterNamespace (Namespace child)
                {
                        if (child != this)
@@ -83,10 +124,10 @@ namespace Mono.CSharp {
                string fullname;
                protected Dictionary<string, Namespace> namespaces;
                protected Dictionary<string, IList<TypeSpec>> types;
+               List<TypeSpec> extension_method_types;
                Dictionary<string, TypeExpr> cached_types;
                RootNamespace root;
                bool cls_checked;
-               bool? has_extension_method;
 
                public readonly MemberName MemberName;
 
@@ -180,14 +221,51 @@ namespace Mono.CSharp {
                                return;
                        }
 
+                       string assembly = null;
+                       string possible_name = fullname + "." + name;
+
+                       // Only assembly unique name should be added
+                       switch (possible_name) {
+                       case "System.Drawing":
+                       case "System.Web.Services":
+                       case "System.Web":
+                       case "System.Data":
+                       case "System.Configuration":
+                       case "System.Data.Services":
+                       case "System.DirectoryServices":
+                       case "System.Json":
+                       case "System.Net.Http":
+                       case "System.Numerics":
+                       case "System.Runtime.Caching":
+                       case "System.ServiceModel":
+                       case "System.Transactions":
+                       case "System.Web.Routing":
+                       case "System.Xml.Linq":
+                       case "System.Xml":
+                               assembly = possible_name;
+                               break;
+
+                       case "System.Linq":
+                       case "System.Linq.Expressions":
+                               assembly = "System.Core";
+                               break;
+
+                       case "System.Windows.Forms":
+                       case "System.Windows.Forms.Layout":
+                               assembly = "System.Windows.Name";
+                               break;
+                       }
+
+                       assembly = assembly == null ? "an" : "`" + assembly + "'";
+
                        if (this is GlobalRootNamespace) {
                                ctx.Module.Compiler.Report.Error (400, loc,
-                                       "The type or namespace name `{0}' could not be found in the global namespace (are you missing an assembly reference?)",
-                                       name);
+                                       "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
+                                       name, assembly);
                        } else {
                                ctx.Module.Compiler.Report.Error (234, loc,
-                                       "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing an assembly reference?",
-                                       name, GetSignatureForError ());
+                                       "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
+                                       name, GetSignatureForError (), assembly);
                        }
                }
 
@@ -208,10 +286,16 @@ namespace Mono.CSharp {
                                ns_parent = this;
                        }
 
+                       return ns_parent.TryAddNamespace (name.Basename);
+               }
+
+               Namespace TryAddNamespace (string name)
+               {
                        Namespace ns;
-                       if (!ns_parent.namespaces.TryGetValue (name.Basename, out ns)) {
-                               ns = new Namespace (ns_parent, name.Basename);
-                               ns_parent.namespaces.Add (name.Basename, ns);
+
+                       if (!namespaces.TryGetValue (name, out ns)) {
+                               ns = new Namespace (this, name);
+                               namespaces.Add (name, ns);
                        }
 
                        return ns;
@@ -326,37 +410,6 @@ namespace Mono.CSharp {
                        return te;
                }
 
-               TypeSpec LookupType (string name, int arity)
-               {
-                       if (types == null)
-                               return null;
-
-                       IList<TypeSpec> found;
-                       if (types.TryGetValue (name, out found)) {
-                               TypeSpec best = null;
-
-                               foreach (var ts in found) {
-                                       if (ts.Arity == arity)
-                                               return ts;
-
-                                       //
-                                       // Lookup for the best candidate with closest arity match
-                                       //
-                                       if (arity < 0) {
-                                               if (best == null) {
-                                                       best = ts;
-                                               } else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (best.Arity + arity)) {
-                                                       best = ts;
-                                               }
-                                       }
-                               }
-                               
-                               return best;
-                       }
-
-                       return null;
-               }
-
                public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
                {
                        var texpr = LookupType (ctx, name, arity, mode, loc);
@@ -404,34 +457,38 @@ namespace Mono.CSharp {
                //
                public List<MethodSpec> LookupExtensionMethod (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity)
                {
-                       if (has_extension_method == false)
+                       if (extension_method_types == null)
                                return null;
 
                        List<MethodSpec> found = null;
-                       if (types != null) {
-                               foreach (var tgroup in types.Values) {
-                                       foreach (var ts in tgroup) {
-                                               if ((ts.Modifiers & Modifiers.METHOD_EXTENSION) == 0)
-                                                       continue;
+                       for (int i = 0; i < extension_method_types.Count; ++i) {
+                               var ts = extension_method_types[i];
 
-                                               has_extension_method = true;
+                               //
+                               // When the list was built we didn't know what members the type
+                               // contains
+                               //
+                               if ((ts.Modifiers & Modifiers.METHOD_EXTENSION) == 0) {
+                                       if (extension_method_types.Count == 1) {
+                                               extension_method_types = null;
+                                               return found;
+                                       }
 
-                                               var res = ts.MemberCache.FindExtensionMethods (invocationContext, extensionType, name, arity);
-                                               if (res == null)
-                                                       continue;
+                                       extension_method_types.RemoveAt (i--);
+                                       continue;
+                               }
 
-                                               if (found == null) {
-                                                       found = res;
-                                               } else {
-                                                       found.AddRange (res);
-                                               }
-                                       }
+                               var res = ts.MemberCache.FindExtensionMethods (invocationContext, extensionType, name, arity);
+                               if (res == null)
+                                       continue;
+
+                               if (found == null) {
+                                       found = res;
+                               } else {
+                                       found.AddRange (res);
                                }
                        }
 
-                       if (has_extension_method == null)
-                               has_extension_method = false;
-
                        return found;
                }
 
@@ -441,6 +498,16 @@ namespace Mono.CSharp {
                                types = new Dictionary<string, IList<TypeSpec>> (64);
                        }
 
+                       if (ts.IsClass && ts.Arity == 0) {
+                               var extension_method_allowed = ts.MemberDefinition.IsImported ? (ts.Modifiers & Modifiers.METHOD_EXTENSION) != 0 : (ts.IsStatic || ts.MemberDefinition.IsPartial);
+                               if (extension_method_allowed) {
+                                       if (extension_method_types == null)
+                                               extension_method_types = new List<TypeSpec> ();
+
+                                       extension_method_types.Add (ts);
+                               }
+                       }
+
                        var name = ts.Name;
                        IList<TypeSpec> existing;
                        if (types.TryGetValue (name, out existing)) {
@@ -583,25 +650,131 @@ namespace Mono.CSharp {
                                        "Identifier `{0}' differing only in case is not CLS-compliant", compiled.GetSignatureForError ());
                        }
                }
+
+               public override string ToString ()
+               {
+                       return Name;
+               }
        }
 
+       public class CompilationSourceFile : NamespaceContainer
+       {
+               readonly SourceFile file;
+               CompileUnitEntry comp_unit;
+               Dictionary<string, SourceFile> include_files;
+               Dictionary<string, bool> conditionals;
+
+               public CompilationSourceFile (ModuleContainer parent, SourceFile sourceFile)
+                       : this (parent)
+               {
+                       this.file = sourceFile;
+               }
+
+               public CompilationSourceFile (ModuleContainer parent)
+                       : base (parent)
+               {
+               }
+
+               public CompileUnitEntry SymbolUnitEntry {
+                       get {
+                               return comp_unit;
+                       }
+               }
+
+               public string FileName {
+                       get {
+                               return file.Name;
+                       }
+               }
+
+               public SourceFile SourceFile {
+                       get {
+                               return file;
+                       }
+               }
+
+               public void AddIncludeFile (SourceFile file)
+               {
+                       if (file == this.file)
+                               return;
+
+                       if (include_files == null)
+                               include_files = new Dictionary<string, SourceFile> ();
+
+                       if (!include_files.ContainsKey (file.FullPathName))
+                               include_files.Add (file.FullPathName, file);
+               }
+
+               public void AddDefine (string value)
+               {
+                       if (conditionals == null)
+                               conditionals = new Dictionary<string, bool> (2);
+
+                       conditionals[value] = true;
+               }
+
+               public void AddUndefine (string value)
+               {
+                       if (conditionals == null)
+                               conditionals = new Dictionary<string, bool> (2);
+
+                       conditionals[value] = false;
+               }
+
+               public override void PrepareEmit ()
+               {
+                       var sw = Module.DeclaringAssembly.SymbolWriter;
+                       if (sw != null) {
+                               CreateUnitSymbolInfo (sw);
+                       }
+
+                       base.PrepareEmit ();
+               }
+
+               //
+               // Creates symbol file index in debug symbol file
+               //
+               void CreateUnitSymbolInfo (MonoSymbolFile symwriter)
+               {
+                       var si = file.CreateSymbolInfo (symwriter);
+                       comp_unit = new CompileUnitEntry (symwriter, si);;
+
+                       if (include_files != null) {
+                               foreach (SourceFile include in include_files.Values) {
+                                       si = include.CreateSymbolInfo (symwriter);
+                                       comp_unit.AddFile (si);
+                               }
+                       }
+               }
+
+               public bool IsConditionalDefined (string value)
+               {
+                       if (conditionals != null) {
+                               bool res;
+                               if (conditionals.TryGetValue (value, out res))
+                                       return res;
+
+                               // When conditional was undefined
+                               if (conditionals.ContainsKey (value))
+                                       return false;
+                       }
+
+                       return Compiler.Settings.IsConditionalSymbolDefined (value);
+               }
+       }
+
+
        //
        // Namespace block as created by the parser
        //
        public class NamespaceContainer : TypeContainer, IMemberContext
        {
                static readonly Namespace[] empty_namespaces = new Namespace[0];
-               static readonly string[] empty_using_list = new string[0];
-
-               Namespace ns;
 
-               readonly ModuleContainer module;
-               readonly CompilationSourceFile file;
+               readonly Namespace ns;
 
                public new readonly NamespaceContainer Parent;
 
-               int symfile_id;
-
                List<UsingNamespace> clauses;
 
                // Used by parsed to check for parser errors
@@ -610,23 +783,22 @@ namespace Mono.CSharp {
                Namespace[] namespace_using_table;
                Dictionary<string, UsingAliasNamespace> aliases;
 
-               public NamespaceContainer (MemberName name, ModuleContainer module, NamespaceContainer parent, CompilationSourceFile sourceFile)
-                       : base ((TypeContainer) parent ?? module, name, null, MemberKind.Namespace)
+               public NamespaceContainer (MemberName name, NamespaceContainer parent)
+                       : base (parent, name, null, MemberKind.Namespace)
                {
-                       this.module = module;
                        this.Parent = parent;
-                       this.file = sourceFile;
-
-                       if (parent != null)
-                               ns = parent.NS.AddNamespace (name);
-                       else if (name != null)
-                               ns = module.GlobalRootNamespace.AddNamespace (name);
-                       else
-                               ns = module.GlobalRootNamespace;
+                       this.ns = parent.NS.AddNamespace (name);
 
                        containers = new List<TypeContainer> ();
                }
 
+               protected NamespaceContainer (ModuleContainer parent)
+                       : base (parent, null, null, MemberKind.Namespace)
+               {
+                       ns = parent.GlobalRootNamespace;
+                       containers = new List<TypeContainer> (2);
+               }
+
                #region Properties
 
                public override AttributeTargets AttributeTargets {
@@ -647,18 +819,6 @@ namespace Mono.CSharp {
                        }
                }
 
-               public override ModuleContainer Module {
-                       get {
-                               return module;
-                       }
-               }
-
-               public CompilationSourceFile SourceFile {
-                       get {
-                               return file;
-                       }
-               }
-
                public List<UsingNamespace> Usings {
                        get {
                                return clauses;
@@ -729,8 +889,10 @@ namespace Mono.CSharp {
                                name = mn.Name;
                        }
 
+                       var names_container = Parent == null ? Module : (TypeContainer) this;
+
                        MemberCore mc;
-                       if (defined_names.TryGetValue (name, out mc)) {
+                       if (names_container.DefinedNames.TryGetValue (name, out mc)) {
                                if (tc is NamespaceContainer && mc is NamespaceContainer) {
                                        containers.Add (tc);
                                        return;
@@ -744,14 +906,34 @@ namespace Mono.CSharp {
                                                GetSignatureForError (), mn.GetSignatureForError ());
                                }
                        } else {
-                               defined_names.Add (name, tc);
+                               names_container.DefinedNames.Add (name, tc);
+
+                               var tdef = tc.PartialContainer;
+                               if (tdef != null) {
+                                       //
+                                       // Same name conflict in different namespace containers
+                                       //
+                                       var conflict = ns.GetAllTypes (name);
+                                       if (conflict != null) {
+                                               foreach (var e in conflict) {
+                                                       if (e.Arity == mn.Arity) {
+                                                               mc = (MemberCore) e.MemberDefinition;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+
+                                       if (mc != null) {
+                                               Report.SymbolRelatedToPreviousError (mc);
+                                               Report.Error (101, tc.Location, "The namespace `{0}' already contains a definition for `{1}'",
+                                                       GetSignatureForError (), mn.GetSignatureForError ());
+                                       } else {
+                                               ns.AddType (Module, tdef.Definition);
+                                       }
+                               }
                        }
 
                        base.AddTypeContainer (tc);
-
-                       var tdef = tc.PartialContainer;
-                       if (tdef != null)
-                               ns.AddType (module, tdef.Definition);
                }
 
                public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
@@ -766,16 +948,7 @@ namespace Mono.CSharp {
                        base.EmitContainer ();
                }
 
-               //
-               // Does extension methods look up to find a method which matches name and extensionType.
-               // Search starts from this namespace and continues hierarchically up to top level.
-               //
-               protected override ExtensionMethodCandidates LookupExtensionMethod (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity)
-               {
-                       return LookupExtensionMethod (invocationContext, extensionType, name, arity, this, 0);
-               }
-
-               public ExtensionMethodCandidates LookupExtensionMethod (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity, NamespaceContainer container, int position)
+               public ExtensionMethodCandidates LookupExtensionMethod (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity, int position)
                {
                        //
                        // Here we try to resume the search for extension method at the point
@@ -796,7 +969,8 @@ namespace Mono.CSharp {
                        // checked before we hit A.N1 using
                        //
                        ExtensionMethodCandidates candidates;
-                       for (; container != null; container = container.Parent) {
+                       var container = this;
+                       do {
                                candidates = container.LookupExtensionMethodCandidates (invocationContext, extensionType, name, arity, ref position);
                                if (candidates != null || container.MemberName == null)
                                        return candidates;
@@ -822,7 +996,8 @@ namespace Mono.CSharp {
                                }
 
                                position = 0;
-                       }
+                               container = container.Parent;
+                       } while (container != null);
 
                        return null;
                }
@@ -1016,7 +1191,7 @@ namespace Mono.CSharp {
                                }
 
                                // It can be top level accessibility only
-                               var better = Namespace.IsImportedTypeOverride (module, texpr_match.Type, texpr_fne.Type);
+                               var better = Namespace.IsImportedTypeOverride (Module, texpr_match.Type, texpr_fne.Type);
                                if (better == null) {
                                        if (mode == LookupMode.Normal) {
                                                Compiler.Report.SymbolRelatedToPreviousError (texpr_match.Type);
@@ -1035,66 +1210,6 @@ namespace Mono.CSharp {
                        return match;
                }
 
-               public int SymbolFileID {
-                       get {
-                               if (symfile_id == 0 && file.SourceFileEntry != null) {
-                                       int parent_id = Parent == null ? 0 : Parent.SymbolFileID;
-
-                                       string [] using_list = empty_using_list;
-                                       if (clauses != null) {
-                                               // TODO: Why is it needed, what to do with aliases
-                                               var ul = new List<string> ();
-                                               foreach (var c in clauses) {
-                                                       ul.Add (c.ResolvedExpression.GetSignatureForError ());
-                                               }
-                                               
-                                               using_list = ul.ToArray ();
-                                       }
-
-                                       symfile_id = SymbolWriter.DefineNamespace (ns.Name, file.CompileUnitEntry, using_list, parent_id);
-                               }
-                               return symfile_id;
-                       }
-               }
-
-               static void MsgtryRef (string s)
-               {
-                       Console.WriteLine ("    Try using -r:" + s);
-               }
-
-               static void MsgtryPkg (string s)
-               {
-                       Console.WriteLine ("    Try using -pkg:" + s);
-               }
-
-               public static void Error_NamespaceNotFound (Location loc, string name, Report Report)
-               {
-                       Report.Error (246, loc, "The type or namespace name `{0}' could not be found. Are you missing a using directive or an assembly reference?",
-                               name);
-
-                       switch (name) {
-                       case "Gtk": case "GtkSharp":
-                               MsgtryPkg ("gtk-sharp-2.0");
-                               break;
-
-                       case "Gdk": case "GdkSharp":
-                               MsgtryPkg ("gdk-sharp-2.0");
-                               break;
-
-                       case "Glade": case "GladeSharp":
-                               MsgtryPkg ("glade-sharp-2.0");
-                               break;
-
-                       case "System.Drawing":
-                       case "System.Web.Services":
-                       case "System.Web":
-                       case "System.Data":
-                       case "System.Windows.Forms":
-                               MsgtryRef (name);
-                               break;
-                       }
-               }
-
                protected override void DefineNamespace ()
                {
                        if (namespace_using_table == null)
@@ -1137,11 +1252,23 @@ namespace Mono.CSharp {
 
                                        entry.Define (this);
 
+                                       //
+                                       // It's needed for repl only, when using clause cannot be resolved don't hold it in
+                                       // global list which is resolved for each evaluation
+                                       //
+                                       if (entry.ResolvedExpression == null) {
+                                               clauses.RemoveAt (i--);
+                                               continue;
+                                       }
+
                                        Namespace using_ns = entry.ResolvedExpression as Namespace;
                                        if (using_ns == null)
                                                continue;
 
                                        if (list.Contains (using_ns)) {
+                                               // Ensure we don't report the warning multiple times in repl
+                                               clauses.RemoveAt (i--);
+
                                                Compiler.Report.Warning (105, 3, entry.Location,
                                                        "The using directive for `{0}' appeared previously in this namespace", using_ns.GetSignatureForError ());
                                        } else {
@@ -1167,8 +1294,9 @@ namespace Mono.CSharp {
                        }
                }
 
-               public void EnableUsingClausesRedefinition ()
+               public void EnableRedefinition ()
                {
+                       is_defined = false;
                        namespace_using_table = null;
                }
 
@@ -1185,10 +1313,10 @@ namespace Mono.CSharp {
                        return MemberName == null ? "global::" : base.GetSignatureForError ();
                }
 
-               public override void RemoveContainer (TypeContainer next_part)
+               public override void RemoveContainer (TypeContainer cont)
                {
-                       base.RemoveContainer (next_part);
-                       NS.RemoveContainer (next_part);
+                       base.RemoveContainer (cont);
+                       NS.RemoveContainer (cont);
                }
 
                protected override bool VerifyClsCompliance ()
@@ -1264,6 +1392,11 @@ namespace Mono.CSharp {
                                }
                        }
                }
+
+               public override string ToString()
+               {
+                       return resolved.ToString();
+               }
        }
 
        public class UsingExternAlias : UsingAliasNamespace