Merge pull request #495 from nicolas-raoul/fix-for-issue2907-with-no-formatting-changes
[mono.git] / mcs / mcs / import.cs
index 541a407fa0444fc6efa4d3467444d6bd5ed358cf..8474e29a5b44c1467bd04008a1afdc3dbb9169dd 100644 (file)
@@ -6,7 +6,7 @@
 // Dual licensed under the terms of the MIT X11 or GNU GPL
 //
 // Copyright 2009-2011 Novell, Inc
-// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+// Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
 //
 
 using System;
@@ -32,7 +32,7 @@ namespace Mono.CSharp
                // Dynamic types reader with additional logic to reconstruct a dynamic
                // type using DynamicAttribute values
                //
-               struct DynamicTypeReader
+               protected struct DynamicTypeReader
                {
                        static readonly bool[] single_attribute = { true };
 
@@ -90,7 +90,7 @@ namespace Mono.CSharp
                                if (cad.Count > 0) {
                                        foreach (var ca in cad) {
                                                var dt = ca.Constructor.DeclaringType;
-                                               if (dt.Name != "DynamicAttribute" && dt.Namespace != CompilerServicesNamespace)
+                                               if (dt.Name != "DynamicAttribute" || dt.Namespace != CompilerServicesNamespace)
                                                        continue;
 
                                                if (ca.ConstructorArguments.Count == 0) {
@@ -120,7 +120,7 @@ namespace Mono.CSharp
                protected readonly Dictionary<MetaType, TypeSpec> import_cache;
                protected readonly Dictionary<MetaType, TypeSpec> compiled_types;
                protected readonly Dictionary<Assembly, IAssemblyDefinition> assembly_2_definition;
-               readonly ModuleContainer module;
+               protected readonly ModuleContainer module;
 
                public static readonly string CompilerServicesNamespace = "System.Runtime.CompilerServices";
 
@@ -191,7 +191,9 @@ namespace Mono.CSharp
                        var definition = new ImportedMemberDefinition (fi, field_type, this);
 
                        if ((fa & FieldAttributes.Literal) != 0) {
-                               var c = Constant.CreateConstantFromValue (field_type, fi.GetRawConstantValue (), Location.Null);
+                               Constant c = field_type.Kind == MemberKind.MissingType ?
+                                       new NullConstant (InternalType.ErrorType, Location.Null) :
+                                       Constant.CreateConstantFromValue (field_type, fi.GetRawConstantValue (), Location.Null);
                                return new ConstSpec (declaringType, definition, field_type, fi, mod, c);
                        }
 
@@ -390,18 +392,21 @@ namespace Mono.CSharp
                                if ((mod & Modifiers.OVERRIDE) != 0) {
                                        bool is_real_override = false;
                                        if (kind == MemberKind.Method && declaringType.BaseType != null) {
-                                               var filter = MemberFilter.Method (name, tparams != null ? tparams.Length : 0, parameters, null);
-                                               var candidate = MemberCache.FindMember (declaringType.BaseType, filter, BindingRestriction.None);
-
-                                               //
-                                               // For imported class method do additional validation to be sure that metadata
-                                               // override flag was correct
-                                               // 
-                                               // Difference between protected internal and protected is ok
-                                               //
-                                               const Modifiers conflict_mask = Modifiers.AccessibilityMask & ~Modifiers.INTERNAL;
-                                               if (candidate != null && (candidate.Modifiers & conflict_mask) == (mod & conflict_mask) && !candidate.IsStatic) {
-                                                       is_real_override = true;
+                                               var btype = declaringType.BaseType;
+                                               if (IsOverrideMethodBaseTypeAccessible (btype)) {
+                                                       var filter = MemberFilter.Method (name, tparams != null ? tparams.Length : 0, parameters, null);
+                                                       var candidate = MemberCache.FindMember (btype, filter, BindingRestriction.None);
+
+                                                       //
+                                                       // For imported class method do additional validation to be sure that metadata
+                                                       // override flag was correct
+                                                       // 
+                                                       // Difference between protected internal and protected is ok
+                                                       //
+                                                       const Modifiers conflict_mask = Modifiers.AccessibilityMask & ~Modifiers.INTERNAL;
+                                                       if (candidate != null && (candidate.Modifiers & conflict_mask) == (mod & conflict_mask) && !candidate.IsStatic) {
+                                                               is_real_override = true;
+                                                       }
                                                }
                                        }
 
@@ -434,6 +439,30 @@ namespace Mono.CSharp
                        return ms;
                }
 
+               bool IsOverrideMethodBaseTypeAccessible (TypeSpec baseType)
+               {
+                       switch (baseType.Modifiers & Modifiers.AccessibilityMask) {
+                       case Modifiers.PUBLIC:
+                               return true;
+                       case Modifiers.INTERNAL:
+                               //
+                               // Check whether imported method in base type is accessible from compiled
+                               // context
+                               //
+                               return baseType.MemberDefinition.IsInternalAsPublic (module.DeclaringAssembly);
+                       case Modifiers.PRIVATE:
+                               return false;
+                       default:
+                               // protected
+                               // protected internal
+                               // 
+                               // Method accessibility checks will be done later based on context
+                               // where the method is called (CS0122 error will be reported for inaccessible)
+                               //
+                               return true;
+                       }
+               }
+
                //
                // Imports System.Reflection parameters
                //
@@ -462,7 +491,7 @@ namespace Mono.CSharp
                                        //
                                        var el = p.ParameterType.GetElementType ();
                                        types[i] = ImportType (el, new DynamicTypeReader (p));  // TODO: 1-based positio to be csc compatible
-                               } else if (i == 0 && method.IsStatic && parent.IsStatic && parent.MemberDefinition.DeclaringAssembly.HasExtensionMethod &&
+                               } else if (i == 0 && method.IsStatic && (parent.Modifiers & Modifiers.METHOD_EXTENSION) != 0 &&
                                        HasAttribute (CustomAttributeData.GetCustomAttributes (method), "ExtensionAttribute", CompilerServicesNamespace)) {
                                        mod = Parameter.Modifier.This;
                                        types[i] = ImportType (p.ParameterType);
@@ -591,26 +620,41 @@ namespace Mono.CSharp
 
                        PropertySpec spec = null;
                        if (!param.IsEmpty) {
-                               var index_name = declaringType.MemberDefinition.GetAttributeDefaultMember ();
-                               if (index_name == null) {
-                                       is_valid_property = false;
-                               } else {
-                                       if (get != null) {
-                                               if (get.IsStatic)
-                                                       is_valid_property = false;
-                                               if (get.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
-                                                       is_valid_property = false;
+                               if (is_valid_property) {
+                                       var index_name = declaringType.MemberDefinition.GetAttributeDefaultMember ();
+                                       if (index_name == null) {
+                                               is_valid_property = false;
+                                       } else {
+                                               if (get != null) {
+                                                       if (get.IsStatic)
+                                                               is_valid_property = false;
+                                                       if (get.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
+                                                               is_valid_property = false;
+                                               }
+                                               if (set != null) {
+                                                       if (set.IsStatic)
+                                                               is_valid_property = false;
+                                                       if (set.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
+                                                               is_valid_property = false;
+                                               }
                                        }
-                                       if (set != null) {
-                                               if (set.IsStatic)
-                                                       is_valid_property = false;
-                                               if (set.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
-                                                       is_valid_property = false;
+
+                                       if (is_valid_property) {
+                                               spec = new IndexerSpec (declaringType, new ImportedParameterMemberDefinition (pi, type, param, this), type, param, pi, mod);
+                                       } else if (declaringType.MemberDefinition.IsComImport && param.FixedParameters[0].HasDefaultValue) {
+                                               //
+                                               // Enables support for properties with parameters (must have default value) of COM-imported types
+                                               //
+                                               is_valid_property = true;
+
+                                               for (int i = 0; i < param.FixedParameters.Length; ++i) {
+                                                       if (!param.FixedParameters[i].HasDefaultValue) {
+                                                               is_valid_property = false;
+                                                               break;
+                                                       }
+                                               }
                                        }
                                }
-
-                               if (is_valid_property)
-                                       spec = new IndexerSpec (declaringType, new ImportedParameterMemberDefinition (pi, type, param, this), type, param, pi, mod);
                        }
 
                        if (spec == null)
@@ -650,7 +694,7 @@ namespace Mono.CSharp
                        return CreateType (type, declaring_type, dtype, canImportBaseType);
                }
 
-               TypeSpec CreateType (MetaType type, TypeSpec declaringType, DynamicTypeReader dtype, bool canImportBaseType)
+               protected TypeSpec CreateType (MetaType type, TypeSpec declaringType, DynamicTypeReader dtype, bool canImportBaseType)
                {
                        TypeSpec spec;
                        if (import_cache.TryGetValue (type, out spec)) {
@@ -835,6 +879,13 @@ namespace Mono.CSharp
 
                        import_cache.Add (type, spec);
 
+                       if (kind == MemberKind.TypeParameter) {
+                               if (canImportBaseType)
+                                       ImportTypeParameterTypeConstraints ((TypeParameterSpec) spec, type);
+
+                               return spec;
+                       }
+
                        //
                        // Two stage setup as the base type can be inflated declaring type or
                        // another nested type inside same declaring type which has not been
@@ -992,10 +1043,9 @@ namespace Mono.CSharp
                                        ImportTypeParameterTypeConstraints (tp, tp.GetMetaInfo ());
                                }
                        }
-
                }
 
-               protected void ImportTypes (MetaType[] types, Namespace targetNamespace, bool hasExtensionTypes)
+               protected void ImportTypes (MetaType[] types, Namespace targetNamespace, bool importExtensionTypes)
                {
                        Namespace ns = targetNamespace;
                        string prev_namespace = null;
@@ -1019,12 +1069,14 @@ namespace Mono.CSharp
                                        prev_namespace = t.Namespace;
                                }
 
-                               ns.AddType (module, it);
-
-                               if (it.IsStatic && hasExtensionTypes &&
+                               // Cannot rely on assembly level Extension attribute or static modifier because they
+                               // are not followed by other compilers (e.g. F#).
+                               if (it.IsClass && it.Arity == 0 && importExtensionTypes &&
                                        HasAttribute (CustomAttributeData.GetCustomAttributes (t), "ExtensionAttribute", CompilerServicesNamespace)) {
                                        it.SetExtensionMethodContainer ();
                                }
+
+                               ns.AddType (module, it);
                        }
                }
 
@@ -1041,12 +1093,13 @@ namespace Mono.CSharp
                                        continue;
                                }
 
-                               if (!IsMissingType (ct) && ct.IsClass) {
-                                       spec.BaseType = CreateType (ct);
+                               var constraint_type = CreateType (ct);
+                               if (constraint_type.IsClass) {
+                                       spec.BaseType = constraint_type;
                                        continue;
                                }
 
-                               spec.AddInterface (CreateType (ct));
+                               spec.AddInterface (constraint_type);
                        }
 
                        if (spec.BaseType == null)
@@ -1487,7 +1540,6 @@ namespace Mono.CSharp
                readonly Assembly assembly;
                readonly AssemblyName aname;
                bool cls_compliant;
-               bool contains_extension_methods;
 
                List<AssemblyName> internals_visible_to;
                Dictionary<IAssemblyDefinition, AssemblyName> internals_visible_to_cache;
@@ -1512,12 +1564,6 @@ namespace Mono.CSharp
                        }
                }
 
-               public bool HasExtensionMethod {
-                       get {
-                               return contains_extension_methods;
-                       }
-               }
-
                public bool HasStrongName {
                        get {
                                return aname.GetPublicKey ().Length != 0;
@@ -1635,13 +1681,6 @@ namespace Mono.CSharp
                                        internals_visible_to.Add (an);
                                        continue;
                                }
-
-                               if (name == "ExtensionAttribute") {
-                                       if (dt.Namespace == MetadataImporter.CompilerServicesNamespace)
-                                               contains_extension_methods = true;
-
-                                       continue;
-                               }
                        }
                }
 
@@ -1744,12 +1783,29 @@ namespace Mono.CSharp
                        }
                }
 
+               bool ITypeDefinition.IsComImport {
+                       get {
+                               return ((MetaType) provider).IsImport;
+                       }
+               }
+
+
                bool ITypeDefinition.IsPartial {
                        get {
                                return false;
                        }
                }
 
+               bool ITypeDefinition.IsTypeForwarder {
+                       get {
+#if STATIC
+                               return ((MetaType) provider).__IsTypeForwarder;
+#else
+                               return false;
+#endif
+                       }
+               }
+
                public override string Name {
                        get {
                                if (name == null) {
@@ -1796,7 +1852,15 @@ namespace Mono.CSharp
                        // or referenced from the user core in which case compilation error has to
                        // be reported because compiler cannot continue anyway
                        //
-                       foreach (var t in types) {
+                       for (int i = 0; i < types.Count; ++i) {
+                               var t = types [i];
+
+                               //
+                               // Report missing types only once per type
+                               //
+                               if (i > 0 && types.IndexOf (t) < i)
+                                       continue;
+
                                string name = t.GetSignatureForError ();
 
                                if (t.MemberDefinition.DeclaringAssembly == ctx.Module.DeclaringAssembly) {
@@ -1804,9 +1868,15 @@ namespace Mono.CSharp
                                                "Reference to type `{0}' claims it is defined in this assembly, but it is not defined in source or any added modules",
                                                name);
                                } else if (t.MemberDefinition.DeclaringAssembly.IsMissing) {
-                                       ctx.Module.Compiler.Report.Error (12, loc,
-                                               "The type `{0}' is defined in an assembly that is not referenced. Consider adding a reference to assembly `{1}'",
-                                               name, t.MemberDefinition.DeclaringAssembly.FullName);
+                                       if (t.MemberDefinition.IsTypeForwarder) {
+                                               ctx.Module.Compiler.Report.Error (1070, loc,
+                                                       "The type `{0}' has been forwarded to an assembly that is not referenced. Consider adding a reference to assembly `{1}'",
+                                                       name, t.MemberDefinition.DeclaringAssembly.FullName);
+                                       } else {
+                                               ctx.Module.Compiler.Report.Error (12, loc,
+                                                       "The type `{0}' is defined in an assembly that is not referenced. Consider adding a reference to assembly `{1}'",
+                                                       name, t.MemberDefinition.DeclaringAssembly.FullName);
+                                       }
                                } else {
                                        ctx.Module.Compiler.Report.Error (1684, loc,
                                                "Reference to type `{0}' claims it is defined assembly `{1}', but it could not be found",
@@ -1933,6 +2003,10 @@ namespace Mono.CSharp
                                foreach (var member in all) {
                                        switch (member.MemberType) {
                                        case MemberTypes.Constructor:
+                                               if (declaringType.IsInterface)
+                                                       continue;
+
+                                               goto case MemberTypes.Method;
                                        case MemberTypes.Method:
                                                MethodBase mb = (MethodBase) member;
                                                var attrs = mb.Attributes;
@@ -2053,6 +2127,9 @@ namespace Mono.CSharp
                                                throw new NotImplementedException (member.ToString ());
                                        }
 
+                                       if (imported.IsStatic && declaringType.IsInterface)
+                                               continue;
+
                                        cache.AddMemberImported (imported);
                                }
                        }
@@ -2074,12 +2151,24 @@ namespace Mono.CSharp
                        }
                }
 
+               bool ITypeDefinition.IsComImport {
+                       get {
+                               return false;
+                       }
+               }
+
                bool ITypeDefinition.IsPartial {
                        get {
                                return false;
                        }
                }
 
+               bool ITypeDefinition.IsTypeForwarder {
+                       get {
+                               return false;
+                       }
+               }
+
                public string Namespace {
                        get {
                                return null;