X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fattribute.cs;h=b939cf436ba46b09f46ef580e6a2f015cf3f41a5;hb=f282c09a4f474c0994bf739e0b300043fd342b80;hp=d3b1ad64b2df886ee5e92c85a63ab73d9dd1fbc0;hpb=3b1343dc026203180d86e80fbaa69aade46f7256;p=mono.git diff --git a/mcs/mcs/attribute.cs b/mcs/mcs/attribute.cs index d3b1ad64b2d..b939cf436ba 100644 --- a/mcs/mcs/attribute.cs +++ b/mcs/mcs/attribute.cs @@ -10,10 +10,12 @@ // using System; +using System.Diagnostics; using System.Collections; using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; using System.Text; namespace Mono.CSharp { @@ -30,11 +32,15 @@ namespace Mono.CSharp { // The following are only meaningful when the attribute // being emitted is one of the builtin ones // - public AttributeTargets Targets; - public bool AllowMultiple; - public bool Inherited; + AttributeTargets Targets; + bool AllowMultiple; + bool Inherited; - public bool UsageAttr = false; + bool UsageAttr = false; + + MethodImplOptions ImplOptions; + UnmanagedType UnmanagedType; + CustomAttributeBuilder cb; public Attribute (string name, ArrayList args, Location loc) { @@ -43,7 +49,7 @@ namespace Mono.CSharp { Location = loc; } - void error617 (string name) + void Error_InvalidNamedArgument (string name) { Report.Error (617, Location, "'" + name + "' is not a valid named attribute " + "argument. Named attribute arguments must be fields which are not " + @@ -51,55 +57,97 @@ namespace Mono.CSharp { "are not static."); } - void error182 () + void Error_AttributeArgumentNotValid () { Report.Error (182, Location, "An attribute argument must be a constant expression, typeof " + "expression or array creation expression"); } - public CustomAttributeBuilder Resolve (EmitContext ec) + static void Error_AttributeConstructorMismatch (Location loc) { - string name = Name; + Report.Error ( + -6, loc, + "Could not find a constructor for this argument list."); + } + + private Type CheckAttributeType (EmitContext ec) { + Type t; + bool isattributeclass = true; + + t = RootContext.LookupType (ec.DeclSpace, Name, true, Location); + if (t != null) { + isattributeclass = t.IsSubclassOf (TypeManager.attribute_type); + if (isattributeclass) + return t; + } + t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location); + if (t != null) { + if (t.IsSubclassOf (TypeManager.attribute_type)) + return t; + } + if (!isattributeclass) { + Report.Error (616, Location, "'" + Name + "': is not an attribute class"); + return null; + } + if (t != null) { + Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class"); + return null; + } + Report.Error ( + 246, Location, "Could not find attribute '" + Name + "' (are you" + + " missing a using directive or an assembly reference ?)"); + return null; + } - UsageAttr = false; + public Type ResolveType (EmitContext ec) + { + Type = CheckAttributeType (ec); + return Type; + } - if (Name.IndexOf ("Attribute") == -1) - name = Name + "Attribute"; - else if (Name.LastIndexOf ("Attribute") == 0) - name = Name + "Attribute"; + + public CustomAttributeBuilder Resolve (EmitContext ec) + { + if (Type == null) + Type = CheckAttributeType (ec); + if (Type == null) + return null; - Type = RootContext.LookupType (ec.TypeContainer, name, false, Location); + bool MethodImplAttr = false; + bool MarshalAsAttr = false; - if (Type == null) { - Report.Error ( - 246, Location, "Could not find attribute '" + Name + "' (are you" + - " missing a using directive or an assembly reference ?)"); - return null; - } + UsageAttr = false; if (Type == TypeManager.attribute_usage_type) UsageAttr = true; - + if (Type == TypeManager.methodimpl_attr_type) + MethodImplAttr = true; + if (Type == TypeManager.marshal_as_attr_type) + MarshalAsAttr = true; + // Now we extract the positional and named arguments ArrayList pos_args = new ArrayList (); ArrayList named_args = new ArrayList (); + int pos_arg_count = 0; if (Arguments != null) { pos_args = (ArrayList) Arguments [0]; + if (pos_args != null) + pos_arg_count = pos_args.Count; if (Arguments.Count > 1) named_args = (ArrayList) Arguments [1]; } - - object [] pos_values = new object [pos_args.Count]; + + object [] pos_values = new object [pos_arg_count]; // // First process positional arguments // - + int i; - for (i = 0; i < pos_args.Count; i++) { + for (i = 0; i < pos_arg_count; i++) { Argument a = (Argument) pos_args [i]; Expression e; @@ -107,15 +155,25 @@ namespace Mono.CSharp { return null; e = a.Expr; + if (e is Constant) { pos_values [i] = ((Constant) e).GetValue (); - - if (UsageAttr) - this.Targets = (AttributeTargets) pos_values [0]; - } else { - error182 (); + } else if (e is TypeOf) { + pos_values [i] = ((TypeOf) e).TypeArg; + } else { + Error_AttributeArgumentNotValid (); return null; } + + if (UsageAttr) + this.Targets = (AttributeTargets) pos_values [0]; + + if (MethodImplAttr) + this.ImplOptions = (MethodImplOptions) pos_values [0]; + + if (MarshalAsAttr) + this.UnmanagedType = + (System.Runtime.InteropServices.UnmanagedType) pos_values [0]; } // @@ -126,7 +184,7 @@ namespace Mono.CSharp { ArrayList prop_infos = new ArrayList (); ArrayList field_values = new ArrayList (); ArrayList prop_values = new ArrayList (); - + for (i = 0; i < named_args.Count; i++) { DictionaryEntry de = (DictionaryEntry) named_args [i]; string member_name = (string) de.Key; @@ -137,13 +195,13 @@ namespace Mono.CSharp { return null; Expression member = Expression.MemberLookup ( - ec, Type, member_name, false, + ec, Type, member_name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, Location); if (member == null || !(member is PropertyExpr || member is FieldExpr)) { - error617 (member_name); + Error_InvalidNamedArgument (member_name); return null; } @@ -153,7 +211,7 @@ namespace Mono.CSharp { PropertyInfo pi = pe.PropertyInfo; if (!pi.CanWrite) { - error617 (member_name); + Error_InvalidNamedArgument (member_name); return null; } @@ -168,8 +226,10 @@ namespace Mono.CSharp { this.Inherited = (bool) o; } - } else { - error182 (); + } else if (e is TypeOf) { + prop_values.Add (((TypeOf) e).TypeArg); + } else { + Error_AttributeArgumentNotValid (); return null; } @@ -180,29 +240,34 @@ namespace Mono.CSharp { FieldInfo fi = fe.FieldInfo; if (fi.IsInitOnly) { - error617 (member_name); + Error_InvalidNamedArgument (member_name); return null; } - if (e is Constant) - field_values.Add (((Constant) e).GetValue ()); - else { - error182 (); + // + // Handle charset here, and set the TypeAttributes + + if (e is Constant){ + object value = ((Constant) e).GetValue (); + + field_values.Add (value); + } else if (e is TypeOf) { + field_values.Add (((TypeOf) e).TypeArg); + } else { + Error_AttributeArgumentNotValid (); return null; } field_infos.Add (fi); } } - + Expression mg = Expression.MemberLookup ( - ec, Type, ".ctor", false, MemberTypes.Constructor, + ec, Type, ".ctor", MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance, Location); if (mg == null) { - Report.Error ( - -6, Location, - "Could not find a constructor for this argument list."); + Error_AttributeConstructorMismatch (Location); return null; } @@ -210,11 +275,26 @@ namespace Mono.CSharp { ec, (MethodGroupExpr) mg, pos_args, Location); if (constructor == null) { - Report.Error ( - -6, Location, - "Could not find a constructor for this argument list."); + Error_AttributeConstructorMismatch (Location); return null; } + + // + // Now we perform some checks on the positional args as they + // cannot be null for a constructor which expects a parameter + // of type object + // + + ParameterData pd = Invocation.GetParameterData (constructor); + + for (int j = 0; j < pos_arg_count; ++j) { + Argument a = (Argument) pos_args [j]; + + if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) { + Error_AttributeArgumentNotValid (); + return null; + } + } PropertyInfo [] prop_info_arr = new PropertyInfo [prop_infos.Count]; FieldInfo [] field_info_arr = new FieldInfo [field_infos.Count]; @@ -226,11 +306,31 @@ namespace Mono.CSharp { prop_values.CopyTo (prop_values_arr, 0); prop_infos.CopyTo (prop_info_arr, 0); - - CustomAttributeBuilder cb = new CustomAttributeBuilder ( - (ConstructorInfo) constructor, pos_values, - prop_info_arr, prop_values_arr, - field_info_arr, field_values_arr); + + try { + cb = new CustomAttributeBuilder ( + (ConstructorInfo) constructor, pos_values, + prop_info_arr, prop_values_arr, + field_info_arr, field_values_arr); + + } catch (NullReferenceException) { + // + // Don't know what to do here + // + Report.Warning ( + -100, Location, "NullReferenceException while trying to create attribute. Something's wrong!"); + } catch { + // + // Sample: + // using System.ComponentModel; + // [DefaultValue (CollectionChangeAction.Add)] + // class X { static void Main () {} } + // + Report.Warning ( + -23, Location, + "The compiler can not encode this attribute in .NET due to\n" + + "\ta bug in the .NET runtime. Try the Mono runtime"); + } return cb; } @@ -243,11 +343,24 @@ namespace Mono.CSharp { TypeContainer a = TypeManager.LookupAttr (attr.Type); if (a == null) { - System.Attribute [] attrs = System.Attribute.GetCustomAttributes (attr.Type); + System.Attribute [] attrs = null; + + try { + attrs = System.Attribute.GetCustomAttributes (attr.Type); + + } catch { + Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name + + " (maybe you forgot to set the usage using the" + + " AttributeUsage attribute ?)."); + return null; + } + foreach (System.Attribute tmp in attrs) - if (tmp is AttributeUsageAttribute) + if (tmp is AttributeUsageAttribute) { targets = ((AttributeUsageAttribute) tmp).ValidOn; + break; + } } else targets = a.Targets; @@ -298,20 +411,34 @@ namespace Mono.CSharp { } - public static void error592 (Attribute a, Location loc) + 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 " + GetValidPlaces (a) + "declarations only."); + Report.Error ( + 592, loc, "Attribute '" + a.Name + + "' is not valid on this declaration type. " + + "It is valid on " + GetValidPlaces (a) + "declarations only."); } public static bool CheckAttribute (Attribute a, object element) { TypeContainer attr = TypeManager.LookupAttr (a.Type); AttributeTargets targets = 0; + if (attr == null) { - System.Attribute [] attrs = System.Attribute.GetCustomAttributes (a.Type); + System.Attribute [] attrs = null; + + try { + attrs = System.Attribute.GetCustomAttributes (a.Type); + + } catch { + Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name + + " (maybe you forgot to set the usage using the" + + " AttributeUsage attribute ?)."); + return false; + } + foreach (System.Attribute tmp in attrs) if (tmp is AttributeUsageAttribute) targets = ((AttributeUsageAttribute) tmp).ValidOn; @@ -344,12 +471,12 @@ namespace Mono.CSharp { return true; else return false; - } else if (element is Event) { + } else if (element is Event || element is InterfaceEvent) { if ((targets & AttributeTargets.Event) != 0) return true; else return false; - } else if (element is Field) { + } else if (element is Field || element is FieldBuilder) { if ((targets & AttributeTargets.Field) != 0) return true; else @@ -359,76 +486,218 @@ namespace Mono.CSharp { return true; else return false; - } else if (element is Method) { + } else if (element is Method || element is Operator || element is InterfaceMethod || element is Accessor) { if ((targets & AttributeTargets.Method) != 0) return true; else return false; - } else if (element is Parameter) { + } else if (element is ParameterBuilder) { if ((targets & AttributeTargets.Parameter) != 0) return true; else return false; - } else if (element is Property) { + } else if (element is Property || element is Indexer || + element is InterfaceProperty || element is InterfaceIndexer) { if ((targets & AttributeTargets.Property) != 0) return true; else return false; + } else if (element is AssemblyBuilder){ + if ((targets & AttributeTargets.Assembly) != 0) + return true; + else + return false; } return false; } + // + // This method should be invoked to pull the IndexerName attribute from an + // Indexer if it exists. + // + public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs) + { + if (opt_attrs == null) + return null; + if (opt_attrs.AttributeSections == null) + return null; + + foreach (AttributeSection asec in opt_attrs.AttributeSections) { + if (asec.Attributes == null) + continue; + + foreach (Attribute a in asec.Attributes){ + if (a.ResolveType (ec) == null) + return null; + + if (a.Type != TypeManager.indexer_name_type) + continue; + + // + // So we have found an IndexerName, pull the data out. + // + if (a.Arguments == null || a.Arguments [0] == null){ + Error_AttributeConstructorMismatch (a.Location); + return null; + } + ArrayList pos_args = (ArrayList) a.Arguments [0]; + if (pos_args.Count == 0){ + Error_AttributeConstructorMismatch (a.Location); + return null; + } + + Argument arg = (Argument) pos_args [0]; + if (!arg.Resolve (ec, a.Location)) + return null; + + Expression e = arg.Expr; + if (!(e is StringConstant)){ + Error_AttributeConstructorMismatch (a.Location); + return null; + } + + // + // Remove the attribute from the list + // + asec.Attributes.Remove (a); + + return (((StringConstant) e).Value); + } + } + return null; + } + + // + // 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 (Location); + return null; + } + + ArrayList pos_args = (ArrayList) Arguments [0]; + if (pos_args.Count != 1){ + Error_AttributeConstructorMismatch (Location); + return null; + } + + Argument arg = (Argument) pos_args [0]; + if (!(arg.Expr is StringConstant)){ + Error_AttributeConstructorMismatch (Location); + return null; + } + + return ((StringConstant) arg.Expr).Value; + } + + // + // This pulls the obsolete message and error flag out of an Obsolete attribute + // + public string Obsolete_GetObsoleteMessage (out bool is_error) + { + is_error = false; + // + // So we have an Obsolete, pull the data out. + // + if (Arguments == null || Arguments [0] == null) + return ""; + + ArrayList pos_args = (ArrayList) Arguments [0]; + if (pos_args.Count == 0) + return ""; + else if (pos_args.Count > 2){ + Error_AttributeConstructorMismatch (Location); + return null; + } + + Argument arg = (Argument) pos_args [0]; + if (!(arg.Expr is StringConstant)){ + Error_AttributeConstructorMismatch (Location); + return null; + } + + if (pos_args.Count == 2){ + Argument arg2 = (Argument) pos_args [1]; + if (!(arg2.Expr is BoolConstant)){ + Error_AttributeConstructorMismatch (Location); + return null; + } + is_error = ((BoolConstant) arg2.Expr).Value; + } + + return ((StringConstant) arg.Expr).Value; + } + + // + // Applies the attributes to the `builder'. + // public static void ApplyAttributes (EmitContext ec, object builder, object kind, Attributes opt_attrs, Location loc) { if (opt_attrs == null) return; - if (opt_attrs.AttributeSections == null) return; foreach (AttributeSection asec in opt_attrs.AttributeSections) { - if (asec.Attributes == null) continue; + if (asec.Target == "assembly" && !(builder is AssemblyBuilder)) + continue; + foreach (Attribute a in asec.Attributes) { CustomAttributeBuilder cb = a.Resolve (ec); + if (cb == null) continue; if (!(kind is TypeContainer)) if (!CheckAttribute (a, kind)) { - error592 (a, loc); + Error_AttributeNotValidForElement (a, loc); return; } - - if (kind is Method) { - if (a.Type != TypeManager.dllimport_type) + if (kind is Method || kind is Operator || kind is InterfaceMethod || + kind is Accessor) { + if (a.Type == TypeManager.methodimpl_attr_type) { + if (a.ImplOptions == MethodImplOptions.InternalCall) + ((MethodBuilder) builder). + SetImplementationFlags ( + MethodImplAttributes.InternalCall | + MethodImplAttributes.Runtime); + } else if (a.Type != TypeManager.dllimport_type){ ((MethodBuilder) builder).SetCustomAttribute (cb); - + } } else if (kind is Constructor) { ((ConstructorBuilder) builder).SetCustomAttribute (cb); - } else if (kind is Field) { ((FieldBuilder) builder).SetCustomAttribute (cb); - - } else if (kind is Property || kind is Indexer) { + } else if (kind is Property || kind is Indexer || + kind is InterfaceProperty || kind is InterfaceIndexer) { ((PropertyBuilder) builder).SetCustomAttribute (cb); + } else if (kind is Event || kind is InterfaceEvent) { + ((MyEventBuilder) builder).SetCustomAttribute (cb); + } else if (kind is ParameterBuilder) { - } else if (kind is Event) { - ((EventBuilder) builder).SetCustomAttribute (cb); - - } else if (kind is Operator) { - ((MethodBuilder) builder).SetCustomAttribute (cb); - + if (a.Type == TypeManager.marshal_as_attr_type) { + UnmanagedMarshal marshal = + UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType); + + ((ParameterBuilder) builder).SetMarshal (marshal); + } else + ((ParameterBuilder) builder).SetCustomAttribute (cb); + } else if (kind is Enum) { ((TypeBuilder) builder).SetCustomAttribute (cb); } else if (kind is TypeContainer) { - TypeContainer tc = (TypeContainer) kind; if (a.UsageAttr) { @@ -436,19 +705,59 @@ namespace Mono.CSharp { tc.AllowMultiple = a.AllowMultiple; tc.Inherited = a.Inherited; - RootContext.TypeManager.RegisterAttrType ( - (TypeBuilder) builder, tc); + } else if (a.Type == TypeManager.default_member_type) { + if (tc.Indexers != null) { + Report.Error (646, loc, + "Cannot specify the DefaultMember attribute on" + + " a type containing an indexer"); + return; + } } else { if (!CheckAttribute (a, kind)) { - error592 (a, loc); + Error_AttributeNotValidForElement (a, loc); return; } } + + try { + ((TypeBuilder) builder).SetCustomAttribute (cb); + } catch (System.ArgumentException) { + Report.Warning ( + -21, loc, + "The CharSet named property on StructLayout\n"+ + "\tdoes not work correctly on Microsoft.NET\n"+ + "\tYou might want to remove the CharSet declaration\n"+ + "\tor compile using the Mono runtime instead of the\n"+ + "\tMicrosoft .NET runtime"); + } + } else if (kind is Interface) { + Interface iface = (Interface) kind; + + if ((a.Type == TypeManager.default_member_type) && + (iface.InterfaceIndexers != null)) { + Report.Error ( + 646, loc, + "Cannot specify the DefaultMember attribute on" + + " a type containing an indexer"); + return; + } + + if (!CheckAttribute (a, kind)) { + Error_AttributeNotValidForElement (a, loc); + return; + } + ((TypeBuilder) builder).SetCustomAttribute (cb); - - } + } else if (kind is AssemblyBuilder){ + ((AssemblyBuilder) builder).SetCustomAttribute (cb); + } else if (kind is ModuleBuilder) { + ((ModuleBuilder) builder).SetCustomAttribute (cb); + } else if (kind is FieldBuilder) { + ((FieldBuilder) builder).SetCustomAttribute (cb); + } else + throw new Exception ("Unknown kind: " + kind); } } } @@ -465,20 +774,9 @@ namespace Mono.CSharp { return null; } - string attr_name = Name; - - if (Name.IndexOf ("Attribute") == -1) - attr_name = Name + "Attribute"; - else if (Name.LastIndexOf ("Attribute") == 0) - attr_name = Name + "Attribute"; - - Type = RootContext.LookupType (ec.TypeContainer, attr_name, false, Location); - - if (Type == null) { - Report.Error (246, Location, "Could not find attribute '" + Name + "' (are you" + - " missing a using directive or an assembly reference ?)"); + Type = CheckAttributeType (ec); + if (Type == null) return null; - } ArrayList named_args = new ArrayList (); @@ -497,18 +795,18 @@ namespace Mono.CSharp { if (tmp.Expr is Constant) dll_name = (string) ((Constant) tmp.Expr).GetValue (); else { - error182 (); + Error_AttributeArgumentNotValid (); return null; } // Now we process the named arguments - CallingConvention cc = 0; - CharSet charset = 0; - bool preserve_sig = false; + CallingConvention cc = CallingConvention.Winapi; + CharSet charset = CharSet.Ansi; + bool preserve_sig = true; bool exact_spelling = false; bool set_last_err = false; string entry_point = null; - + for (int i = 0; i < named_args.Count; i++) { DictionaryEntry de = (DictionaryEntry) named_args [i]; @@ -519,13 +817,14 @@ namespace Mono.CSharp { if (!a.Resolve (ec, Location)) return null; - Expression member = Expression.MemberLookup (ec, Type, member_name, false, - MemberTypes.Field | MemberTypes.Property, - BindingFlags.Public | BindingFlags.Instance, - Location); + Expression member = Expression.MemberLookup ( + ec, Type, member_name, + MemberTypes.Field | MemberTypes.Property, + BindingFlags.Public | BindingFlags.Instance, + Location); if (member == null || !(member is FieldExpr)) { - error617 (member_name); + Error_InvalidNamedArgument (member_name); return null; } @@ -534,7 +833,7 @@ namespace Mono.CSharp { FieldInfo fi = fe.FieldInfo; if (fi.IsInitOnly) { - error617 (member_name); + Error_InvalidNamedArgument (member_name); return null; } @@ -554,20 +853,26 @@ namespace Mono.CSharp { else if (member_name == "PreserveSig") preserve_sig = (bool) c.GetValue (); } else { - error182 (); + Error_AttributeArgumentNotValid (); return null; } } } + if (entry_point == null) + entry_point = name; + MethodBuilder mb = builder.DefinePInvokeMethod ( - name, dll_name, flags, + name, dll_name, entry_point, flags | MethodAttributes.HideBySig, CallingConventions.Standard, ret_type, param_types, cc, - charset); + charset); + + if (preserve_sig) + mb.SetImplementationFlags (MethodImplAttributes.PreserveSig); return mb; } @@ -588,10 +893,10 @@ namespace Mono.CSharp { } public class Attributes { - public ArrayList AttributeSections; + public Location Location; - public Attributes (AttributeSection a) + public Attributes (AttributeSection a, Location loc) { AttributeSections = new ArrayList (); AttributeSections.Add (a);