**** Merged from MCS ****
[mono.git] / mcs / gmcs / ecore.cs
index 0b2d62e9e29584f1f1fd3640d5af1e0506924926..6782334b960e92ac2a6a39565ae87848b52740e2 100755 (executable)
@@ -61,7 +61,10 @@ namespace Mono.CSharp {
 
                // Disable control flow analysis while resolving the expression.
                // This is used when resolving the instance expression of a field expression.
-               DisableFlowAnalysis     = 16
+               DisableFlowAnalysis     = 16,
+
+               // Set if this is resolving the first part of a MemberAccess.
+               Intermediate            = 32
        }
 
        //
@@ -221,6 +224,18 @@ namespace Mono.CSharp {
                                Warning (warning, s);
                }
 
+               /// <summary>
+               /// Tests presence of ObsoleteAttribute and report proper error
+               /// </summary>
+               protected void CheckObsoleteAttribute (Type type)
+               {
+                       ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (type);
+                       if (obsolete_attr == null)
+                               return;
+
+                       AttributeTester.Report_ObsoleteMessage (obsolete_attr, type.FullName, loc);
+               }
+
                /// <summary>
                ///   Performs semantic analysis on the Expression
                /// </summary>
@@ -293,8 +308,10 @@ namespace Mono.CSharp {
                                ec.DoFlowAnalysis = false;
 
                        Expression e;
+                       bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
                        if (this is SimpleName)
-                               e = ((SimpleName) this).DoResolveAllowStatic (ec);
+                               e = ((SimpleName) this).DoResolveAllowStatic (ec, intermediate);
+
                        else 
                                e = DoResolve (ec);
 
@@ -515,6 +532,9 @@ namespace Mono.CSharp {
                        return null;
                }
 
+
+               private static ArrayList almostMatchedMembers = new ArrayList (4);
+
                //
                // FIXME: Probably implement a cache for (t,name,current_access_set)?
                //
@@ -559,8 +579,11 @@ namespace Mono.CSharp {
                                                       string name, MemberTypes mt,
                                                       BindingFlags bf, Location loc)
                {
+                       almostMatchedMembers.Clear ();
+
                        MemberInfo [] mi = TypeManager.MemberLookup (
-                               container_type, qualifier_type,queried_type, mt, bf, name);
+                               container_type, qualifier_type,queried_type, mt, bf, name,
+                               almostMatchedMembers);
 
                        if (mi == null)
                                return null;
@@ -636,25 +659,50 @@ namespace Mono.CSharp {
                        e = MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type,
                                          name, mt, bf, loc);
 
-                       if (e != null)
-                               return e;
-
-                       // Error has already been reported.
-                       if (errors < Report.Errors)
-                               return null;
+                       if (e == null && errors == Report.Errors)
+                               // No errors were reported by MemberLookup, but there was an error.
+                               MemberLookupFailed (ec, qualifier_type, queried_type, name,
+                                                   null, loc);
 
-                       MemberLookupFailed (ec, qualifier_type, queried_type, name,
-                                           null, loc);
-                       return null;
+                       return e;
                }
 
                public static void MemberLookupFailed (EmitContext ec, Type qualifier_type,
                                                       Type queried_type, string name,
                                                       string class_name, Location loc)
                {
+                       if (almostMatchedMembers.Count != 0) {
+                               if (qualifier_type == null) {
+                                       foreach (MemberInfo m in almostMatchedMembers)
+                                               Report.Error (38, loc, 
+                                                             "Cannot access non-static member `{0}' via nested type `{1}'", 
+                                                             TypeManager.GetFullNameSignature (m),
+                                                             TypeManager.CSharpName (ec.ContainerType));
+                                       return;
+                               }
+
+
+                               if (qualifier_type != ec.ContainerType) {
+                                       // Although a derived class can access protected members of
+                                       // its base class it cannot do so through an instance of the
+                                       // base class (CS1540).  If the qualifier_type is a parent of the
+                                       // ec.ContainerType and the lookup succeeds with the latter one,
+                                       // then we are in this situation.
+                                       foreach (MemberInfo m in almostMatchedMembers)
+                                               Report.Error (1540, loc, 
+                                                             "Cannot access protected member `{0}' via a qualifier of type `{1}';"
+                                                             + " the qualifier must be of type `{2}' (or derived from it)", 
+                                                             TypeManager.GetFullNameSignature (m),
+                                                             TypeManager.CSharpName (qualifier_type),
+                                                             TypeManager.CSharpName (ec.ContainerType));
+                                       return;
+                               }
+                               almostMatchedMembers.Clear ();
+                       }
+
                        MemberInfo[] mi = TypeManager.MemberLookup (queried_type, null, queried_type,
                                                                    AllMemberTypes, AllBindingFlags |
-                                                                   BindingFlags.NonPublic, name);
+                                                                   BindingFlags.NonPublic, name, null);
 
                        if (mi == null) {
                                if (class_name != null)
@@ -669,7 +717,7 @@ namespace Mono.CSharp {
 
                        if (TypeManager.MemberLookup (queried_type, null, queried_type,
                                                      AllMemberTypes, AllBindingFlags |
-                                                     BindingFlags.NonPublic, name) == null) {
+                                                     BindingFlags.NonPublic, name, null) == null) {
                                if ((mi.Length == 1) && (mi [0] is Type)) {
                                        Type t = (Type) mi [0];
 
@@ -682,42 +730,15 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       if ((qualifier_type != null) && (qualifier_type != ec.ContainerType) &&
-                           ec.ContainerType.IsSubclassOf (qualifier_type)) {
-                               // Although a derived class can access protected members of
-                               // its base class it cannot do so through an instance of the
-                               // base class (CS1540).  If the qualifier_type is a parent of the
-                               // ec.ContainerType and the lookup succeeds with the latter one,
-                               // then we are in this situation.
-
-                               mi = TypeManager.MemberLookup (
-                                       ec.ContainerType, ec.ContainerType, ec.ContainerType,
-                                       AllMemberTypes, AllBindingFlags, name);
 
-                               if (mi != null) {
-                                       Report.Error (
-                                               1540, loc, "Cannot access protected member `" +
-                                               TypeManager.CSharpName (qualifier_type) + "." +
-                                               name + "' " + "via a qualifier of type `" +
-                                               TypeManager.CSharpName (qualifier_type) + "'; the " +
-                                               "qualifier must be of type `" +
-                                               TypeManager.CSharpName (ec.ContainerType) + "' " +
-                                               "(or derived from it)");
-                                       return;
-                               }
-                       }
 
                        if (qualifier_type != null)
-                               Report.Error (
-                                       122, loc, "`" + TypeManager.CSharpName (qualifier_type) + "." +
-                                       name + "' is inaccessible due to its protection level");
+                               Report.Error_T (122, loc, TypeManager.CSharpName (qualifier_type) + "." + name);
                        else if (name == ".ctor") {
                                Report.Error (143, loc, String.Format ("The type {0} has no constructors defined",
                                                                       TypeManager.CSharpName (queried_type)));
                        } else {
-                               Report.Error (
-                                       122, loc, "`" + name + "' is inaccessible due to its " +
-                                       "protection level");
+                               Report.Error_T (122, loc, name);
                }
                }
 
@@ -1262,7 +1283,7 @@ namespace Mono.CSharp {
                //
                // Default implementation of IAssignMethod.CacheTemporaries
                //
-               public void CacheTemporaries (EmitContext ec)
+               public virtual void CacheTemporaries (EmitContext ec)
                {
                }
 
@@ -2010,18 +2031,18 @@ namespace Mono.CSharp {
                
                public override Expression DoResolve (EmitContext ec)
                {
-                       return SimpleNameResolve (ec, null, false);
+                       return SimpleNameResolve (ec, null, false, false);
                }
 
                public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
                {
-                       return SimpleNameResolve (ec, right_side, false);
+                       return SimpleNameResolve (ec, right_side, false, false);
                }
                
 
-               public Expression DoResolveAllowStatic (EmitContext ec)
+               public Expression DoResolveAllowStatic (EmitContext ec, bool intermediate)
                {
-                       return SimpleNameResolve (ec, null, true);
+                       return SimpleNameResolve (ec, null, true, intermediate);
                }
 
                public override Expression ResolveAsTypeStep (EmitContext ec)
@@ -2088,6 +2109,33 @@ namespace Mono.CSharp {
                        return this;
                }
 
+               Expression SimpleNameResolve (EmitContext ec, Expression right_side,
+                                             bool allow_static, bool intermediate)
+               {
+                       Expression e = DoSimpleNameResolve (ec, right_side, allow_static, intermediate);
+                       if (e == null)
+                               return null;
+
+                       Block current_block = ec.CurrentBlock;
+                       if (current_block != null){
+                               LocalInfo vi = current_block.GetLocalInfo (Name);
+                               if (is_base &&
+                                   current_block.IsVariableNameUsedInChildBlock(Name)) {
+                                       Report.Error (135, Location,
+                                                     "'{0}' has a different meaning in a " +
+                                                     "child block", Name);
+                                       return null;
+                               }
+                       }
+
+                       if (e.Type != null && e.Type.IsPointer && !ec.InUnsafe) {
+                               UnsafeError (loc);
+                               return null;
+                       }
+
+                       return e;
+               }
+
                /// <remarks>
                ///   7.5.2: Simple Names. 
                ///
@@ -2105,7 +2153,7 @@ namespace Mono.CSharp {
                ///   Type is both an instance variable and a Type;  Type.GetType
                ///   is the static method not an instance method of type.
                /// </remarks>
-               Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool allow_static)
+               Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool allow_static, bool intermediate)
                {
                        Expression e = null;
 
@@ -2114,11 +2162,6 @@ namespace Mono.CSharp {
                        //
                        Block current_block = ec.CurrentBlock;
                        if (current_block != null){
-                               if (is_base && current_block.IsVariableNameUsedInChildBlock(Name)) {
-                                       Report.Error (135, Location, "'" + Name + "' has a different meaning in a child block");
-                                       return null;
-                               }
-
                                LocalInfo vi = current_block.GetLocalInfo (Name);
                                if (vi != null){
                                        Expression var;
@@ -2219,24 +2262,23 @@ namespace Mono.CSharp {
 
                                // This fails if ResolveMemberAccess() was unable to decide whether
                                // it's a field or a type of the same name.
+                               
                                if (!me.IsStatic && (me.InstanceExpression == null))
                                        return e;
 
                                if (!me.IsStatic &&
                                    TypeManager.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType) &&
-                                   !me.InstanceExpression.Type.IsSubclassOf (me.DeclaringType)) {
+                                   !me.InstanceExpression.Type.IsSubclassOf (me.DeclaringType) &&
+                                   (!intermediate || !MemberAccess.IdenticalNameAndTypeName (ec, this, e, loc))) {
                                        Error (38, "Cannot access nonstatic member `" + me.Name + "' of " +
                                               "outer type `" + me.DeclaringType + "' via nested type `" +
                                               me.InstanceExpression.Type + "'");
                                        return null;
                                }
 
-                               if (right_side != null)
-                                       e = e.DoResolveLValue (ec, right_side);
-                               else
-                                       e = e.DoResolve (ec);
-
-                               return e;                               
+                               return (right_side != null)
+                                       ? e.DoResolveLValue (ec, right_side)
+                                       : e.DoResolve (ec);
                        }
 
                        if (ec.IsStatic || ec.IsFieldInitializer){
@@ -2550,6 +2592,7 @@ namespace Mono.CSharp {
                Expression instance_expression = null;
                bool is_explicit_impl = false;
                bool has_type_arguments = false;
+               bool identical_type_name = false;
                
                public MethodGroupExpr (MemberInfo [] mi, Location l)
                {
@@ -2624,6 +2667,16 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool IdenticalTypeName {
+                       get {
+                               return identical_type_name;
+                       }
+
+                       set {
+                               identical_type_name = value;
+                       }
+               }
+
                public string Name {
                        get {
                                 return TypeManager.CSharpSignature (
@@ -2770,6 +2823,10 @@ namespace Mono.CSharp {
                Expression instance_expr;
                VariableInfo variable_info;
                
+               LocalTemporary temporary;
+               IMemoryLocation instance_ml;
+               bool have_temporary;
+               
                public FieldExpr (FieldInfo fi, Location l)
                {
                        FieldInfo = fi;
@@ -2839,6 +2896,19 @@ namespace Mono.CSharp {
                                        return null;
                        }
 
+                       ObsoleteAttribute oa;
+                       FieldBase f = TypeManager.GetField (FieldInfo);
+                       if (f != null) {
+                               oa = f.GetObsoleteAttribute (ec.DeclSpace);
+                               if (oa != null)
+                                       AttributeTester.Report_ObsoleteMessage (oa, f.GetSignatureForError (), loc);
+                               // To be sure that type is external because we do not register generated fields
+                        } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {                                
+                               oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
+                               if (oa != null)
+                                       AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
+                       }
+
                        // If the instance expression is a local variable or parameter.
                        IVariable var = instance_expr as IVariable;
                        if ((var == null) || (var.VariableInfo == null))
@@ -2922,6 +2992,35 @@ namespace Mono.CSharp {
                        return true;
                }
 
+               public override void CacheTemporaries (EmitContext ec)
+               {
+                       if (!FieldInfo.IsStatic && (temporary == null))
+                               temporary = new LocalTemporary (ec, instance_expr.Type);
+               }
+
+               void EmitInstance (EmitContext ec)
+               {
+                       if (instance_expr.Type.IsValueType)
+                               CacheTemporaries (ec);
+
+                       if ((temporary == null) || have_temporary)
+                               return;
+
+                       if (instance_expr.Type.IsValueType) {
+                               instance_ml = instance_expr as IMemoryLocation;
+                               if (instance_ml == null) {
+                                       instance_expr.Emit (ec);
+                                       temporary.Store (ec);
+                                       instance_ml = temporary;
+                               }
+                       } else {
+                               instance_expr.Emit (ec);
+                               temporary.Store (ec);
+                       }
+
+                       have_temporary = true;
+               }
+
                override public void Emit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
@@ -2945,23 +3044,14 @@ namespace Mono.CSharp {
                                return;
                        }
                        
-                       if (instance_expr.Type.IsValueType){
-                               IMemoryLocation ml;
-                               LocalTemporary tempo = null;
-                               
-                               if (!(instance_expr is IMemoryLocation)){
-                                       tempo = new LocalTemporary (ec, instance_expr.Type);
-                                       
-                                       InstanceExpression.Emit (ec);
-                                       tempo.Store (ec);
-                                       ml = tempo;
-                               } else
-                                       ml = (IMemoryLocation) instance_expr;
-                               
-                               ml.AddressOf (ec, AddressOp.Load);
-                       } else {
+                       EmitInstance (ec);
+                       if (instance_ml != null)
+                               instance_ml.AddressOf (ec, AddressOp.Load);
+                       else if (temporary != null)
+                               temporary.Emit (ec);
+                       else
                                instance_expr.Emit (ec);
-                       }
+
                        if (is_volatile)
                                ig.Emit (OpCodes.Volatile);
                        
@@ -2981,15 +3071,13 @@ namespace Mono.CSharp {
                        }
 
                        if (!is_static){
-                               Expression instance = instance_expr;
-
-                               if (instance.Type.IsValueType){
-                                       IMemoryLocation ml = (IMemoryLocation) instance;
-
-                                       ml.AddressOf (ec, AddressOp.Store);
-                               } else {
-                                       instance.Emit (ec);
-                               }
+                               EmitInstance (ec);
+                               if (instance_ml != null)
+                                       instance_ml.AddressOf (ec, AddressOp.Store);
+                               else if (temporary != null)
+                                       temporary.Emit (ec);
+                               else
+                                       instance_expr.Emit (ec);
                        }
 
                        source.Emit (ec);
@@ -3064,26 +3152,15 @@ namespace Mono.CSharp {
                                // only load the pointer, and not perform an Ldobj immediately after
                                // the value has been loaded into the stack.
                                //
-                               if (instance_expr is This)
+                               EmitInstance (ec);
+                               if (instance_ml != null)
+                                       instance_ml.AddressOf (ec, AddressOp.LoadStore);
+                               else if (temporary != null)
+                                       temporary.Emit (ec);
+                               else if (instance_expr is This)
                                        ((This)instance_expr).AddressOf (ec, AddressOp.LoadStore);
-                               else if (instance_expr.Type.IsValueType && instance_expr is IMemoryLocation){
-                                       IMemoryLocation ml = (IMemoryLocation) instance_expr;
-
-                                       ml.AddressOf (ec, AddressOp.LoadStore);
-                               } else {
+                               else
                                        instance_expr.Emit (ec);
-
-                                       if (instance_expr.Type.IsValueType) {
-                                               LocalBuilder local = ig.DeclareLocal (instance_expr.Type);
-                                               ig.Emit(OpCodes.Stloc, local);
-                                               ig.Emit(OpCodes.Ldloca, local);
-                                               ig.Emit(OpCodes.Ldfld, FieldInfo);
-                                               LocalBuilder local2 = ig.DeclareLocal(type);
-                                               ig.Emit(OpCodes.Stloc, local2);
-                                               ig.Emit(OpCodes.Ldloca, local2);
-                                               return;
-                                       }
-                               }
                                ig.Emit (OpCodes.Ldflda, FieldInfo);
                        }
                }
@@ -3122,6 +3199,8 @@ namespace Mono.CSharp {
                bool must_do_cs1540_check;
                
                Expression instance_expr;
+               LocalTemporary temporary;
+               bool have_temporary;
 
                public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
                {
@@ -3194,7 +3273,7 @@ namespace Mono.CSharp {
                        for (; current != null; current = current.BaseType) {
                                MemberInfo[] group = TypeManager.MemberLookup (
                                        invocation_type, invocation_type, current,
-                                       MemberTypes.Property, flags, PropertyInfo.Name);
+                                       MemberTypes.Property, flags, PropertyInfo.Name, null);
 
                                if (group == null)
                                        continue;
@@ -3299,9 +3378,7 @@ namespace Mono.CSharp {
                                is_static = true;
 
                        if (setter == null && getter == null){
-                               Error (122, "`" + PropertyInfo.Name + "' " +
-                                      "is inaccessible because of its protection level");
-                               
+                               Report.Error_T (122, loc, PropertyInfo.Name);
                        }
                }
 
@@ -3420,8 +3497,29 @@ namespace Mono.CSharp {
                        return this;
                }
 
+               public override void CacheTemporaries (EmitContext ec)
+               {
+                       if (!is_static)
+                               temporary = new LocalTemporary (ec, instance_expr.Type);
+               }
+
+               Expression EmitInstance (EmitContext ec)
+               {
+                       if (temporary != null){
+                               if (!have_temporary){
+                                       instance_expr.Emit (ec);
+                                       temporary.Store (ec);
+                                       have_temporary = true;
+                               }
+                               return temporary;
+                       } else
+                               return instance_expr;
+               }
+
                override public void Emit (EmitContext ec)
                {
+                       Expression expr = EmitInstance (ec);
+
                        //
                        // Special case: length of single dimension array property is turned into ldlen
                        //
@@ -3434,14 +3532,14 @@ namespace Mono.CSharp {
                                // support invoking GetArrayRank, so test for that case first
                                //
                                if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)){
-                                       instance_expr.Emit (ec);
+                                       expr.Emit (ec);
                                        ec.ig.Emit (OpCodes.Ldlen);
                                        ec.ig.Emit (OpCodes.Conv_I4);
                                        return;
                                }
                        }
 
-                       Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, getter, null, loc);
+                       Invocation.EmitCall (ec, IsBase, IsStatic, expr, getter, null, loc);
                        
                }
 
@@ -3450,11 +3548,13 @@ namespace Mono.CSharp {
                //
                public void EmitAssign (EmitContext ec, Expression source)
                {
+                       Expression expr = EmitInstance (ec);
+
                        Argument arg = new Argument (source, Argument.AType.Expression);
                        ArrayList args = new ArrayList ();
 
                        args.Add (arg);
-                       Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, setter, args, loc);
+                       Invocation.EmitCall (ec, IsBase, IsStatic, expr, setter, args, loc);
                }
 
                override public void EmitStatement (EmitContext ec)
@@ -3469,7 +3569,7 @@ namespace Mono.CSharp {
        /// </summary>
        public class EventExpr : Expression, IMemberExpr {
                public readonly EventInfo EventInfo;
-               public Expression instance_expr;
+               Expression instance_expr;
 
                bool is_static;
                MethodInfo add_accessor, remove_accessor;