**** Merged from MCS ****
[mono.git] / mcs / gmcs / attribute.cs
index 73985960ea92685e702ef9d3d4ced01339e25984..7f1ba59e480d24cb77609caaa042471f2ba16e84 100644 (file)
@@ -2,6 +2,7 @@
 // attribute.cs: Attribute Handler
 //
 // Author: Ravi Pratap (ravi@ximian.com)
+//         Marek Safar (marek.safar@seznam.cz)
 //
 // Licensed under the terms of the GNU GPL
 //
@@ -569,10 +570,10 @@ namespace Mono.CSharp {
                /// <summary>
                ///   Get a string containing a list of valid targets for the attribute 'attr'
                /// </summary>
-               static string GetValidTargets (Attribute attr)
+               public string GetValidTargets ()
                {
                        StringBuilder sb = new StringBuilder ();
-                       AttributeTargets targets = attr.GetAttributeUsage ().ValidOn;
+                       AttributeTargets targets = GetAttributeUsage ().ValidOn;
 
                        if ((targets & AttributeTargets.Assembly) != 0)
                                sb.Append ("'assembly' ");
@@ -620,15 +621,6 @@ namespace Mono.CSharp {
 
                }
 
-               public static void Error_AttributeNotValidForElement (Attribute a, Location loc)
-               {
-                       Report.Error (
-                               592, loc, "Attribute '" + a.Name +
-                               "' is not valid on this declaration type. " +
-                               "It is valid on " + GetValidTargets (a) + "declarations only.");
-               }
-
-
                /// <summary>
                /// Returns AttributeUsage attribute for this type
                /// </summary>
@@ -650,35 +642,6 @@ namespace Mono.CSharp {
                        return attr_class.AttributeUsage;
                }
 
-
-               //
-               // This pulls the condition name out of a Conditional attribute
-               //
-               public string Conditional_GetConditionName ()
-               {
-                       //
-                       // So we have a Conditional, pull the data out.
-                       //
-                       if (Arguments == null || Arguments [0] == null){
-                               Error_AttributeConstructorMismatch ();
-                               return null;
-                       }
-
-                       ArrayList pos_args = (ArrayList) Arguments [0];
-                       if (pos_args.Count != 1){
-                               Error_AttributeConstructorMismatch ();
-                               return null;
-                       }
-
-                       Argument arg = (Argument) pos_args [0]; 
-                       if (!(arg.Expr is StringConstant)){
-                               Error_AttributeConstructorMismatch ();
-                               return null;
-                       }
-
-                       return ((StringConstant) arg.Expr).Value;
-               }
-
                public string IndexerName_GetIndexerName (EmitContext ec)
                {
                        if (Arguments == null || Arguments [0] == null){
@@ -704,6 +667,26 @@ namespace Mono.CSharp {
                        return sc.Value;
                }
 
+               /// <summary>
+               /// Returns condition of ConditionalAttribute
+               /// </summary>
+               public string GetConditionalAttributeValue (DeclSpace ds)
+               {
+                       if (pos_values == null) {
+                               EmitContext ec = new EmitContext (ds, ds, Location, null, null, 0, false);
+
+                               // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
+                               // But because a lot of attribute class code must be rewritten will be better to wait...
+                               Resolve (ec);
+                       }
+
+                       // Some error occurred
+                       if (pos_values [0] == null)
+                               return null;
+
+                       return (string)pos_values [0];
+               }
+
                /// <summary>
                /// Creates the instance of ObsoleteAttribute from this attribute instance
                /// </summary>
@@ -823,18 +806,25 @@ namespace Mono.CSharp {
 
                        AttributeUsageAttribute usage_attr = GetAttributeUsage ();
                        if ((usage_attr.ValidOn & ias.AttributeTargets) == 0) {
-                                       Error_AttributeNotValidForElement (this, Location);
+                               // "Attribute '{0}' is not valid on this declaration type. It is valid on {1} declarations only.";
+                               Report.Error_T (592, Location, Name, GetValidTargets ());
                                return;
                        }
 
                        ias.ApplyAttributeBuilder (this, cb);
 
-                       if (!usage_attr.AllowMultiple && emitted_attr.Contains (Target)) {
+                       if (!usage_attr.AllowMultiple) {
+                               ArrayList emitted_targets = (ArrayList)emitted_attr [Type];
+                               if (emitted_targets == null) {
+                                       emitted_targets = new ArrayList ();
+                                       emitted_attr.Add (Type, emitted_targets);
+                               } else if (emitted_targets.Contains (Target)) {
                                Report.Error (579, Location, "Duplicate '" + Name + "' attribute");
+                                       return;
+                               }
+                               emitted_targets.Add (Target);
                        }
 
-                       emitted_attr [Type] = Target;
-
                        // Here we are testing attribute arguments for array usage (error 3016)
                        if (ias.IsClsCompliaceRequired (ec.DeclSpace)) {
                                if (Arguments == null)
@@ -1122,6 +1112,24 @@ namespace Mono.CSharp {
                        return Search (t, ec, true);
                }
 
+               /// <summary>
+               /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
+               /// </summary>
+               public Attribute[] SearchMulti (Type t, EmitContext ec)
+               {
+                       ArrayList ar = null;
+
+                       foreach (Attribute a in Attrs) {
+                               if (a.ResolveType (ec, false) == t) {
+                                       if (ar == null)
+                                               ar = new ArrayList ();
+                                       ar.Add (a);
+                               }
+                       }
+
+                       return ar == null ? null : ar.ToArray (typeof (Attribute)) as Attribute[];
+               }
+
                public void Emit (EmitContext ec, Attributable ias)
                {
                        ListDictionary ld = new ListDictionary ();
@@ -1166,6 +1174,7 @@ namespace Mono.CSharp {
                static PtrHashtable analyzed_types = new PtrHashtable ();
                static PtrHashtable analyzed_types_obsolete = new PtrHashtable ();
                static PtrHashtable analyzed_member_obsolete = new PtrHashtable ();
+               static PtrHashtable analyzed_method_excluded = new PtrHashtable ();
 
                private AttributeTester ()
                {
@@ -1344,7 +1353,9 @@ namespace Mono.CSharp {
                        ObsoleteAttribute result = null;
                        if (type.IsByRef || type.IsArray || type.IsPointer) {
                                result = GetObsoleteAttribute (TypeManager.GetElementType (type));
-                       } else {
+                       } else if (type.IsGenericParameter || type.IsGenericInstance)
+                               return null;
+                       else {
                                DeclSpace type_ds = TypeManager.LookupDeclSpace (type);
 
                                // Type is external, we can get attribute directly
@@ -1370,10 +1381,6 @@ namespace Mono.CSharp {
                        if (mc != null) 
                                return mc.GetObsoleteAttribute ();
 
-                       // TODO: remove after Constructor will be ready for IMethodData
-                       if ((mb.DeclaringType is TypeBuilder) || mb.DeclaringType.IsGenericInstance)
-                               return null;
-
                        return GetMemberObsoleteAttribute (mb);
                }
 
@@ -1389,6 +1396,9 @@ namespace Mono.CSharp {
                        if (type_obsolete != null)
                                return (ObsoleteAttribute)type_obsolete;
 
+                       if ((mi.DeclaringType is TypeBuilder) || mi.DeclaringType.IsGenericInstance)
+                               return null;
+
                        ObsoleteAttribute oa = System.Attribute.GetCustomAttribute (mi, TypeManager.obsolete_attribute_type, false) as ObsoleteAttribute;
                        analyzed_member_obsolete.Add (mi, oa == null ? FALSE : oa);
                        return oa;
@@ -1410,5 +1420,30 @@ namespace Mono.CSharp {
                        }
                        Report.Warning_T (618, loc, member, oa.Message);
                }
+
+               public static bool IsConditionalMethodExcluded (MethodBase mb)
+               {
+                       object excluded = analyzed_method_excluded [mb];
+                       if (excluded != null)
+                               return excluded == TRUE ? true : false;
+
+                       if (mb.Mono_IsInflatedMethod)
+                               return false;
+                       
+                       ConditionalAttribute[] attrs = mb.GetCustomAttributes (TypeManager.conditional_attribute_type, true) as ConditionalAttribute[];
+                       if (attrs.Length == 0) {
+                               analyzed_method_excluded.Add (mb, FALSE);
+                               return false;
+                       }
+
+                       foreach (ConditionalAttribute a in attrs) {
+                               if (RootContext.AllDefines.Contains (a.ConditionString)) {
+                                       analyzed_method_excluded.Add (mb, FALSE);
+                                       return false;
+                               }
+                       }
+                       analyzed_method_excluded.Add (mb, TRUE);
+                       return true;
+               }
        }
 }