X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fattribute.cs;h=64ca04c520fba7cfeca088138ba694c1b1587b05;hb=f131b2a601976ad30bb0633b57cf33ab92aa2ec7;hp=a9ab03c6f14377bc5be96c4564dae01710de2d48;hpb=1de8680fe357e5db2a78f90a944e9bb95d576c01;p=mono.git diff --git a/mcs/mcs/attribute.cs b/mcs/mcs/attribute.cs index a9ab03c6f14..64ca04c520f 100644 --- a/mcs/mcs/attribute.cs +++ b/mcs/mcs/attribute.cs @@ -32,11 +32,12 @@ namespace Mono.CSharp { /// /// Attributes for this type /// - Attributes attributes; + protected Attributes attributes; public Attributable (Attributes attrs) { - attributes = attrs; + if (attrs != null) + OptAttributes = attrs; } public Attributes OptAttributes @@ -46,6 +47,10 @@ namespace Mono.CSharp { } set { attributes = value; + + if (attributes != null) { + attributes.AttachTo (this); + } } } @@ -59,7 +64,9 @@ namespace Mono.CSharp { /// public abstract AttributeTargets AttributeTargets { get; } - public abstract bool IsClsCompliaceRequired (DeclSpace ds); + public abstract IResolveContext ResolveContext { get; } + + public abstract bool IsClsComplianceRequired (); /// /// Gets list of valid attribute targets for explicit target declaration. @@ -68,7 +75,8 @@ namespace Mono.CSharp { public abstract string[] ValidAttributeTargets { get; } }; - public class Attribute { + public class Attribute : Expression + { public readonly string ExplicitTarget; public AttributeTargets Target; @@ -77,18 +85,18 @@ namespace Mono.CSharp { public readonly Expression LeftExpr; public readonly string Identifier; - public readonly ArrayList Arguments; - - public readonly Location Location; - - public Type Type; + readonly ArrayList PosArguments; + ArrayList NamedArguments; bool resolve_error; - readonly bool nameEscaped; - static AttributeUsageAttribute DefaultUsageAttribute = new AttributeUsageAttribute (AttributeTargets.All); + // It can contain more onwers when the attribute is applied to multiple fiels. + protected Attributable[] owners; + + static readonly AttributeUsageAttribute DefaultUsageAttribute = new AttributeUsageAttribute (AttributeTargets.All); static Assembly orig_sec_assembly; + public static readonly object[] EmptyObject = new object [0]; // non-null if named args present after Resolve () is called PropertyInfo [] prop_info_arr; @@ -97,19 +105,53 @@ namespace Mono.CSharp { object [] prop_values_arr; object [] pos_values; - static PtrHashtable usage_attr_cache = new PtrHashtable (); + static PtrHashtable usage_attr_cache; + // Cache for parameter-less attributes + static PtrHashtable att_cache; - public Attribute (string target, Expression left_expr, string identifier, ArrayList args, Location loc, bool nameEscaped) + public Attribute (string target, Expression left_expr, string identifier, object[] args, Location loc, bool nameEscaped) { LeftExpr = left_expr; Identifier = identifier; Name = LeftExpr == null ? identifier : LeftExpr + "." + identifier; - Arguments = args; - Location = loc; + if (args != null) { + PosArguments = (ArrayList)args [0]; + NamedArguments = (ArrayList)args [1]; + } + this.loc = loc; ExplicitTarget = target; this.nameEscaped = nameEscaped; } + static Attribute () + { + Reset (); + } + + public static void Reset () + { + usage_attr_cache = new PtrHashtable (); + att_cache = new PtrHashtable (); + } + + public virtual void AttachTo (Attributable owner) + { + if (this.owners == null) { + this.owners = new Attributable[1] { owner }; + return; + } + + // When the same attribute is attached to multiple fiels + // we use this extra_owners as a list of owners. The attribute + // then can be removed because will be emitted when first owner + // is served + Attributable[] new_array = new Attributable [this.owners.Length + 1]; + owners.CopyTo (new_array, 0); + new_array [owners.Length] = owner; + this.owners = new_array; + owner.OptAttributes = null; + } + void Error_InvalidNamedArgument (string name) { Report.Error (617, Location, "`{0}' is not a valid named attribute argument. Named attribute arguments " + @@ -124,18 +166,28 @@ namespace Mono.CSharp { "attribute parameter type", name); } - static void Error_AttributeArgumentNotValid (string extra, Location loc) + public static void Error_AttributeArgumentNotValid (Location loc) { Report.Error (182, loc, "An attribute argument must be a constant expression, typeof " + - "expression or array creation expression" + extra); + "expression or array creation expression"); + } + + static void Error_TypeParameterInAttribute (Location loc) + { + Report.Error ( + -202, loc, "Can not use a type parameter in an attribute"); } - static void Error_AttributeArgumentNotValid (Location loc) + public void Error_MissingGuidAttribute () { - Error_AttributeArgumentNotValid ("", loc); + Report.Error (596, Location, "The Guid attribute must be specified with the ComImport attribute"); + } + + public void Error_MisusedExtensionAttribute () + { + Report.Error (1112, Location, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ()); } - /// /// This is rather hack. We report many emit attribute error with same error to be compatible with @@ -152,34 +204,33 @@ namespace Mono.CSharp { Error_AttributeEmitError ("it is attached to invalid parent"); } - protected virtual FullNamedExpression ResolveAsTypeTerminal (Expression expr, EmitContext ec, bool silent) - { - return expr.ResolveAsTypeTerminal (ec, silent); + Attributable Owner { + get { + return owners [0]; + } } - protected virtual FullNamedExpression ResolveAsTypeStep (Expression expr, EmitContext ec, bool silent) + protected virtual TypeExpr ResolveAsTypeTerminal (Expression expr, IResolveContext ec, bool silent) { - return expr.ResolveAsTypeStep (ec, silent); + return expr.ResolveAsTypeTerminal (ec, silent); } - Type ResolvePossibleAttributeType (EmitContext ec, string name, bool silent, ref bool is_attr) + Type ResolvePossibleAttributeType (string name, bool silent, ref bool is_attr) { - FullNamedExpression fn; + IResolveContext rc = Owner.ResolveContext; + + TypeExpr te; if (LeftExpr == null) { - fn = ResolveAsTypeTerminal (new SimpleName (name, Location), ec, silent); + te = ResolveAsTypeTerminal (new SimpleName (name, Location), rc, silent); } else { - fn = ResolveAsTypeStep (LeftExpr, ec, silent); - if (fn == null) - return null; - fn = new MemberAccess (fn, name, Location).ResolveAsTypeTerminal (ec, silent); + te = ResolveAsTypeTerminal (new MemberAccess (LeftExpr, name), rc, silent); } - TypeExpr te = fn as TypeExpr; if (te == null) return null; Type t = te.Type; - if (t.IsSubclassOf (TypeManager.attribute_type)) { + if (TypeManager.IsSubclassOf (t, TypeManager.attribute_type)) { is_attr = true; } else if (!silent) { Report.SymbolRelatedToPreviousError (t); @@ -191,14 +242,14 @@ namespace Mono.CSharp { /// /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true. /// - void ResolveAttributeType (EmitContext ec) + void ResolveAttributeType () { bool t1_is_attr = false; - Type t1 = ResolvePossibleAttributeType (ec, Identifier, true, ref t1_is_attr); + Type t1 = ResolvePossibleAttributeType (Identifier, true, ref t1_is_attr); bool t2_is_attr = false; Type t2 = nameEscaped ? null : - ResolvePossibleAttributeType (ec, Identifier + "Attribute", true, ref t2_is_attr); + ResolvePossibleAttributeType (Identifier + "Attribute", true, ref t2_is_attr); if (t1_is_attr && t2_is_attr) { Report.Error (1614, Location, "`{0}' is ambiguous between `{0}' and `{0}Attribute'. " + @@ -218,60 +269,28 @@ namespace Mono.CSharp { } if (t1 == null && t2 == null) - ResolvePossibleAttributeType (ec, Identifier, false, ref t1_is_attr); + ResolvePossibleAttributeType (Identifier, false, ref t1_is_attr); if (t1 != null) - ResolvePossibleAttributeType (ec, Identifier, false, ref t1_is_attr); + ResolvePossibleAttributeType (Identifier, false, ref t1_is_attr); if (t2 != null) - ResolvePossibleAttributeType (ec, Identifier + "Attribute", false, ref t2_is_attr); + ResolvePossibleAttributeType (Identifier + "Attribute", false, ref t2_is_attr); resolve_error = true; } - public virtual Type ResolveType (EmitContext ec) + public virtual Type ResolveType () { if (Type == null && !resolve_error) - ResolveAttributeType (ec); + ResolveAttributeType (); return Type; } - public string GetSignatureForError () - { - return LeftExpr == null ? Identifier : LeftExpr.GetSignatureForError () + "." + Identifier; - } - - // - // Given an expression, if the expression is a valid attribute-argument-expression - // returns an object that can be used to encode it, or null on failure. - // - public static bool GetAttributeArgumentExpression (Expression e, Location loc, Type arg_type, out object result) + public override string GetSignatureForError () { - Constant constant = e as Constant; - if (constant != null) { - constant = constant.ToType (arg_type, loc); - if (constant == null) { - result = null; - return false; - } - result = constant.GetTypedValue (); - return true; - } else if (e is TypeOf) { - result = ((TypeOf) e).TypeArg; - return true; - } else if (e is ArrayCreation){ - result = ((ArrayCreation) e).EncodeAsAttribute (); - if (result != null) - return true; - } else if (e is EmptyCast) { - Expression child = ((EmptyCast)e).Child; - return GetAttributeArgumentExpression (child, loc, child.Type, out result); - } else if (e is As) { - As as_e = (As) e; - return GetAttributeArgumentExpression (as_e.Expr, loc, as_e.ProbeType.Type, out result); - } + if (Type != null) + return TypeManager.CSharpName (Type); - result = null; - Error_AttributeArgumentNotValid (loc); - return false; + return LeftExpr == null ? Identifier : LeftExpr.GetSignatureForError () + "." + Identifier; } bool IsValidArgumentType (Type t) @@ -286,10 +305,30 @@ namespace Mono.CSharp { t == TypeManager.type_type; } - // Cache for parameter-less attributes - static PtrHashtable att_cache = new PtrHashtable (); + [Conditional ("GMCS_SOURCE")] + void ApplyModuleCharSet () + { + if (Type != TypeManager.dllimport_type) + return; - public CustomAttributeBuilder Resolve (EmitContext ec) + if (!CodeGen.Module.HasDefaultCharSet) + return; + + const string CharSetEnumMember = "CharSet"; + if (NamedArguments == null) { + NamedArguments = new ArrayList (1); + } else { + foreach (DictionaryEntry de in NamedArguments) { + if ((string)de.Key == CharSetEnumMember) + return; + } + } + + NamedArguments.Add (new DictionaryEntry (CharSetEnumMember, + new Argument (Constant.CreateConstant (typeof (CharSet), CodeGen.Module.DefaultCharSet, Location)))); + } + + public CustomAttributeBuilder Resolve () { if (resolve_error) return null; @@ -297,7 +336,7 @@ namespace Mono.CSharp { resolve_error = true; if (Type == null) { - ResolveAttributeType (ec); + ResolveAttributeType (); if (Type == null) return null; } @@ -312,7 +351,7 @@ namespace Mono.CSharp { AttributeTester.Report_ObsoleteMessage (obsolete_attr, TypeManager.CSharpName (Type), Location); } - if (Arguments == null) { + if (PosArguments == null && NamedArguments == null) { object o = att_cache [Type]; if (o != null) { resolve_error = false; @@ -320,298 +359,308 @@ namespace Mono.CSharp { } } - ConstructorInfo ctor = ResolveArguments (ec); - if (ctor == null) + Attributable owner = Owner; + DeclSpace ds = owner.ResolveContext as DeclSpace; + if (ds == null) + ds = owner.ResolveContext.DeclContainer; + + EmitContext ec = new EmitContext (owner.ResolveContext, ds, owner.ResolveContext.DeclContainer, + Location, null, typeof (Attribute), owner.ResolveContext.DeclContainer.ModFlags, false); + ec.IsAnonymousMethodAllowed = false; + + ConstructorInfo ctor = ResolveConstructor (ec); + if (ctor == null) { + if (Type is TypeBuilder && + TypeManager.LookupDeclSpace (Type).MemberCache == null) + // The attribute type has been DefineType'd, but not Defined. Let's not treat it as an error. + // It'll be resolved again when the attached-to entity is emitted. + resolve_error = false; return null; + } - CustomAttributeBuilder cb; + ApplyModuleCharSet (); + CustomAttributeBuilder cb; try { - if (prop_info_arr != null || field_info_arr != null) { - cb = new CustomAttributeBuilder ( - ctor, pos_values, - prop_info_arr, prop_values_arr, - field_info_arr, field_values_arr); - } else { - cb = new CustomAttributeBuilder ( - ctor, pos_values); + // SRE does not allow private ctor but we want to report all source code errors + if (ctor.IsPrivate) + return null; + + if (NamedArguments == null) { + cb = new CustomAttributeBuilder (ctor, pos_values); if (pos_values.Length == 0) att_cache.Add (Type, cb); + + resolve_error = false; + return cb; } + + if (!ResolveNamedArguments (ec)) { + return null; + } + + cb = new CustomAttributeBuilder (ctor, pos_values, + prop_info_arr, prop_values_arr, + field_info_arr, field_values_arr); + + resolve_error = false; + return cb; } catch (Exception) { Error_AttributeArgumentNotValid (Location); return null; } - - resolve_error = false; - return cb; } - protected virtual ConstructorInfo ResolveArguments (EmitContext ec) + protected virtual ConstructorInfo ResolveConstructor (EmitContext ec) { - // Now we extract the positional and named arguments + if (PosArguments != null) { + for (int i = 0; i < PosArguments.Count; i++) { + Argument a = (Argument) PosArguments [i]; + + if (!a.Resolve (ec, Location)) + return null; + } + } - ArrayList pos_args = null; - ArrayList named_args = null; - int pos_arg_count = 0; - int named_arg_count = 0; + MethodGroupExpr mg = MemberLookupFinal (ec, ec.ContainerType, + Type, ".ctor", MemberTypes.Constructor, + BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, + Location) as MethodGroupExpr; + + if (mg == null) + return null; + + mg = mg.OverloadResolve (ec, PosArguments, false, Location); + if (mg == null) + return null; - 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]; - named_arg_count = named_args.Count; - } + ConstructorInfo constructor = (ConstructorInfo)mg; + + // TODO: move to OverloadResolve + ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (constructor); + if (oa != null && !Owner.ResolveContext.IsInObsoleteScope) { + AttributeTester.Report_ObsoleteMessage (oa, mg.GetSignatureForError (), mg.Location); + } + + if (PosArguments == null) { + pos_values = EmptyObject; + return constructor; } + ParameterData pd = TypeManager.GetParameterData (constructor); + + int pos_arg_count = PosArguments.Count; + int last_real_param = pd.Count; + pos_values = new object [pos_arg_count]; - // - // First process positional arguments - // + if (pd.HasParams) { + // When the params is not filled we need to put one + if (last_real_param > pos_arg_count) { + object [] new_pos_values = new object [pos_arg_count + 1]; + pos_values.CopyTo (new_pos_values, 0); + new_pos_values [pos_arg_count] = new object [] {} ; + pos_values = new_pos_values; + } + last_real_param--; + } - int i; - for (i = 0; i < pos_arg_count; i++) { - Argument a = (Argument) pos_args [i]; - Expression e; + for (int j = 0; j < pos_arg_count; ++j) { + Argument a = (Argument) PosArguments [j]; - if (!a.Resolve (ec, Location)) + if (!a.Expr.GetAttributableValue (a.Type, out pos_values [j])) return null; + + if (j < last_real_param) + continue; + + if (j == last_real_param) { + object [] array = new object [pos_arg_count - last_real_param]; + array [0] = pos_values [j]; + pos_values [j] = array; + continue; + } + + object [] params_array = (object []) pos_values [last_real_param]; + params_array [j - last_real_param] = pos_values [j]; + } - e = a.Expr; + // Adjust the size of the pos_values if it had params + if (last_real_param != pos_arg_count) { + object [] new_pos_values = new object [last_real_param + 1]; + Array.Copy (pos_values, new_pos_values, last_real_param + 1); + pos_values = new_pos_values; + } - object val; - if (!GetAttributeArgumentExpression (e, Location, a.Type, out val)) + // Here we do the checks which should be done by corlib or by runtime. + // However Zoltan doesn't like it and every Mono compiler has to do it again. + + if (Type == TypeManager.guid_attr_type) { + try { + new Guid ((string)pos_values [0]); + } + catch (Exception e) { + Error_AttributeEmitError (e.Message); return null; + } + } - pos_values [i] = val; + if (Type == TypeManager.attribute_usage_type && (int)pos_values [0] == 0) { + Report.Error (591, Location, "Invalid value for argument to `System.AttributeUsage' attribute"); + return null; + } - if (i == 0 && Type == TypeManager.attribute_usage_type && (int)val == 0) { - Report.Error (591, Location, "Invalid value for argument to 'System.AttributeUsage' attribute"); + if (Type == TypeManager.indexer_name_type || Type == TypeManager.conditional_attribute_type) { + if (!Tokenizer.IsValidIdentifier ((string)pos_values [0])) { + Report.Error (633, ((Argument)PosArguments[0]).Expr.Location, + "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ()); return null; } } - // - // Now process named arguments - // + if (Type == TypeManager.methodimpl_attr_type && pos_values.Length == 1 && + pd.ParameterType (0) == TypeManager.short_type && + !System.Enum.IsDefined (typeof (MethodImplOptions), pos_values [0].ToString ())) { + Error_AttributeEmitError ("Incorrect argument value."); + return null; + } - ArrayList field_infos = null; - ArrayList prop_infos = null; - ArrayList field_values = null; - ArrayList prop_values = null; - Hashtable seen_names = null; + return (ConstructorInfo)constructor; + } - if (named_arg_count > 0) { - field_infos = new ArrayList (); - prop_infos = new ArrayList (); - field_values = new ArrayList (); - prop_values = new ArrayList (); + protected virtual bool ResolveNamedArguments (EmitContext ec) + { + int named_arg_count = NamedArguments.Count; - seen_names = new Hashtable(); - } + ArrayList field_infos = new ArrayList (named_arg_count); + ArrayList prop_infos = new ArrayList (named_arg_count); + ArrayList field_values = new ArrayList (named_arg_count); + ArrayList prop_values = new ArrayList (named_arg_count); + + ArrayList seen_names = new ArrayList(named_arg_count); - for (i = 0; i < named_arg_count; i++) { - DictionaryEntry de = (DictionaryEntry) named_args [i]; + foreach (DictionaryEntry de in NamedArguments) { string member_name = (string) de.Key; - Argument a = (Argument) de.Value; - Expression e; if (seen_names.Contains(member_name)) { Report.Error(643, Location, "'" + member_name + "' duplicate named attribute argument"); - return null; + return false; } - seen_names.Add(member_name, 1); - + seen_names.Add(member_name); + + Argument a = (Argument) de.Value; if (!a.Resolve (ec, Location)) - return null; + return false; Expression member = Expression.MemberLookup ( - ec, Type, member_name, + ec.ContainerType, Type, member_name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, Location); if (member == null) { - member = Expression.MemberLookup (ec, Type, member_name, + member = Expression.MemberLookup (ec.ContainerType, Type, member_name, MemberTypes.Field | MemberTypes.Property, BindingFlags.NonPublic | BindingFlags.Instance, Location); if (member != null) { + Report.SymbolRelatedToPreviousError (member.Type); Expression.ErrorIsInaccesible (Location, member.GetSignatureForError ()); - return null; + return false; } } if (member == null){ - Report.Error (117, Location, "`{0}' does not contain a definition for `{1}'", - TypeManager.CSharpName (Type), member_name); - return null; + Expression.Error_TypeDoesNotContainDefinition (Location, Type, member_name); + return false; } if (!(member is PropertyExpr || member is FieldExpr)) { Error_InvalidNamedArgument (member_name); - return null; + return false; } - e = a.Expr; + if (a.Expr is TypeParameterExpr){ + Error_TypeParameterInAttribute (Location); + return false; + } + + ObsoleteAttribute obsolete_attr; + if (member is PropertyExpr) { - PropertyExpr pe = (PropertyExpr) member; - PropertyInfo pi = pe.PropertyInfo; + PropertyInfo pi = ((PropertyExpr) member).PropertyInfo; if (!pi.CanWrite || !pi.CanRead) { Report.SymbolRelatedToPreviousError (pi); Error_InvalidNamedArgument (member_name); - return null; + return false; } if (!IsValidArgumentType (pi.PropertyType)) { Report.SymbolRelatedToPreviousError (pi); Error_InvalidNamedAgrumentType (member_name); - return null; + return false; } object value; - if (!GetAttributeArgumentExpression (e, Location, pi.PropertyType, out value)) - return null; + if (!a.Expr.GetAttributableValue (pi.PropertyType, out value)) + return false; + + PropertyBase pb = TypeManager.GetProperty (pi); + if (pb != null) + obsolete_attr = pb.GetObsoleteAttribute (); + else + obsolete_attr = AttributeTester.GetMemberObsoleteAttribute (pi); prop_values.Add (value); prop_infos.Add (pi); - } else if (member is FieldExpr) { - FieldExpr fe = (FieldExpr) member; - FieldInfo fi = fe.FieldInfo; + } else { + FieldInfo fi = ((FieldExpr) member).FieldInfo; if (fi.IsInitOnly) { Error_InvalidNamedArgument (member_name); - return null; + return false; } if (!IsValidArgumentType (fi.FieldType)) { Report.SymbolRelatedToPreviousError (fi); Error_InvalidNamedAgrumentType (member_name); - return null; + return false; } object value; - if (!GetAttributeArgumentExpression (e, Location, fi.FieldType, out value)) - return null; + if (!a.Expr.GetAttributableValue (fi.FieldType, out value)) + return false; + + FieldBase fb = TypeManager.GetField (fi); + if (fb != null) + obsolete_attr = fb.GetObsoleteAttribute (); + else + obsolete_attr = AttributeTester.GetMemberObsoleteAttribute (fi); field_values.Add (value); field_infos.Add (fi); } - } - Expression mg = Expression.MemberLookup ( - ec, Type, ".ctor", MemberTypes.Constructor, - BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, - Location); - - MethodBase constructor = Invocation.OverloadResolve ( - ec, (MethodGroupExpr) mg, pos_args, false, Location); - - if (constructor == null) { - return null; - } - - - // Here we do the checks which should be done by corlib or by runtime. - // However Zoltan doesn't like it and every Mono compiler has to do it again. - - if (Type == TypeManager.guid_attr_type) { - try { - new Guid ((string)pos_values [0]); - } - catch (Exception e) { - Error_AttributeEmitError (e.Message); - return null; - } + if (obsolete_attr != null && !Owner.ResolveContext.IsInObsoleteScope) + AttributeTester.Report_ObsoleteMessage (obsolete_attr, member.GetSignatureForError (), member.Location); } - if (Type == TypeManager.methodimpl_attr_type && - pos_values.Length == 1 && ((Argument)pos_args [0]).Type == TypeManager.short_type && - !System.Enum.IsDefined (typeof (MethodImplOptions), pos_values [0])) { - Error_AttributeEmitError ("Incorrect argument value."); - return null; - } + prop_info_arr = new PropertyInfo [prop_infos.Count]; + field_info_arr = new FieldInfo [field_infos.Count]; + field_values_arr = new object [field_values.Count]; + prop_values_arr = new object [prop_values.Count]; - // - // Now we perform some checks on the positional args as they - // cannot be null for a constructor which expects a parameter - // of type object - // + field_infos.CopyTo (field_info_arr, 0); + field_values.CopyTo (field_values_arr, 0); - ParameterData pd = TypeManager.GetParameterData (constructor); + prop_values.CopyTo (prop_values_arr, 0); + prop_infos.CopyTo (prop_info_arr, 0); - int last_real_param = pd.Count; - if (pd.HasParams) { - // When the params is not filled we need to put one - if (last_real_param > pos_arg_count) { - object [] new_pos_values = new object [pos_arg_count + 1]; - pos_values.CopyTo (new_pos_values, 0); - new_pos_values [pos_arg_count] = new object [] {} ; - pos_values = new_pos_values; - } - last_real_param--; - } - - 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 (Location); - return null; - } - - object value = pos_values [j]; - if (value != null && a.Type != value.GetType () && TypeManager.IsPrimitiveType (a.Type)) { - bool fail; - pos_values [j] = TypeManager.ChangeType (value, a.Type, out fail); - if (fail) { - // TODO: Can failed ? - throw new NotImplementedException (); - } - } - - if (j < last_real_param) - continue; - - if (j == last_real_param) { - object [] array = new object [pos_arg_count - last_real_param]; - array [0] = pos_values [j]; - pos_values [j] = array; - continue; - } - - object [] params_array = (object []) pos_values [last_real_param]; - params_array [j - last_real_param] = pos_values [j]; - } - - // Adjust the size of the pos_values if it had params - if (last_real_param != pos_arg_count) { - object [] new_pos_values = new object [last_real_param + 1]; - Array.Copy (pos_values, new_pos_values, last_real_param + 1); - pos_values = new_pos_values; - } - - if (named_arg_count > 0) { - prop_info_arr = new PropertyInfo [prop_infos.Count]; - field_info_arr = new FieldInfo [field_infos.Count]; - field_values_arr = new object [field_values.Count]; - prop_values_arr = new object [prop_values.Count]; - - field_infos.CopyTo (field_info_arr, 0); - field_values.CopyTo (field_values_arr, 0); - - prop_values.CopyTo (prop_values_arr, 0); - prop_infos.CopyTo (prop_info_arr, 0); - } - - return (ConstructorInfo) constructor; + return true; } /// @@ -620,7 +669,7 @@ namespace Mono.CSharp { public string GetValidTargets () { StringBuilder sb = new StringBuilder (); - AttributeTargets targets = GetAttributeUsage (null).ValidOn; + AttributeTargets targets = GetAttributeUsage (Type).ValidOn; if ((targets & AttributeTargets.Assembly) != 0) sb.Append ("assembly, "); @@ -672,41 +721,46 @@ namespace Mono.CSharp { } /// - /// Returns AttributeUsage attribute for this type + /// Returns AttributeUsage attribute based on types hierarchy /// - AttributeUsageAttribute GetAttributeUsage (EmitContext ec) + static AttributeUsageAttribute GetAttributeUsage (Type type) { - AttributeUsageAttribute ua = usage_attr_cache [Type] as AttributeUsageAttribute; + AttributeUsageAttribute ua = usage_attr_cache [type] as AttributeUsageAttribute; if (ua != null) return ua; - Class attr_class = TypeManager.LookupClass (Type); + Class attr_class = TypeManager.LookupClass (type); if (attr_class == null) { - object[] usage_attr = Type.GetCustomAttributes (TypeManager.attribute_usage_type, true); + object[] usage_attr = type.GetCustomAttributes (TypeManager.attribute_usage_type, true); ua = (AttributeUsageAttribute)usage_attr [0]; - usage_attr_cache.Add (Type, ua); + usage_attr_cache.Add (type, ua); return ua; } - Attribute a = attr_class.OptAttributes == null - ? null - : attr_class.OptAttributes.Search (TypeManager.attribute_usage_type, attr_class.EmitContext); + Attribute a = null; + if (attr_class.OptAttributes != null) + a = attr_class.OptAttributes.Search (TypeManager.attribute_usage_type); - ua = a == null - ? DefaultUsageAttribute - : a.GetAttributeUsageAttribute (attr_class.EmitContext); + if (a == null) { + if (attr_class.TypeBuilder.BaseType != TypeManager.attribute_type) + ua = GetAttributeUsage (attr_class.TypeBuilder.BaseType); + else + ua = DefaultUsageAttribute; + } else { + ua = a.GetAttributeUsageAttribute (); + } - usage_attr_cache.Add (Type, ua); + usage_attr_cache.Add (type, ua); return ua; } - AttributeUsageAttribute GetAttributeUsageAttribute (EmitContext ec) + AttributeUsageAttribute GetAttributeUsageAttribute () { if (pos_values == null) // 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); + Resolve (); if (resolve_error) return DefaultUsageAttribute; @@ -727,12 +781,12 @@ namespace Mono.CSharp { /// /// Returns custom name of indexer /// - public string GetIndexerAttributeValue (EmitContext ec) + public string GetIndexerAttributeValue () { if (pos_values == null) // 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); + Resolve (); if (resolve_error) return null; @@ -743,12 +797,12 @@ namespace Mono.CSharp { /// /// Returns condition of ConditionalAttribute /// - public string GetConditionalAttributeValue (EmitContext ec) + public string GetConditionalAttributeValue () { if (pos_values == null) // 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); + Resolve (); if (resolve_error) return null; @@ -759,12 +813,12 @@ namespace Mono.CSharp { /// /// Creates the instance of ObsoleteAttribute from this attribute instance /// - public ObsoleteAttribute GetObsoleteAttribute (EmitContext ec) + public ObsoleteAttribute GetObsoleteAttribute () { if (pos_values == null) // 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); + Resolve (); if (resolve_error) return null; @@ -783,12 +837,12 @@ namespace Mono.CSharp { /// before ApplyAttribute. We need to resolve the arguments. /// This situation occurs when class deps is differs from Emit order. /// - public bool GetClsCompliantAttributeValue (EmitContext ec) + public bool GetClsCompliantAttributeValue () { if (pos_values == null) // 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); + Resolve (); if (resolve_error) return false; @@ -796,10 +850,10 @@ namespace Mono.CSharp { return (bool)pos_values [0]; } - public Type GetCoClassAttributeValue (EmitContext ec) + public Type GetCoClassAttributeValue () { if (pos_values == null) - Resolve (ec); + Resolve (); if (resolve_error) return null; @@ -807,29 +861,68 @@ namespace Mono.CSharp { return (Type)pos_values [0]; } + public bool CheckTarget () + { + string[] valid_targets = Owner.ValidAttributeTargets; + if (ExplicitTarget == null || ExplicitTarget == valid_targets [0]) { + Target = Owner.AttributeTargets; + return true; + } + + // TODO: we can skip the first item + if (((IList) valid_targets).Contains (ExplicitTarget)) { + switch (ExplicitTarget) { + case "return": Target = AttributeTargets.ReturnValue; return true; + case "param": Target = AttributeTargets.Parameter; return true; + case "field": Target = AttributeTargets.Field; return true; + case "method": Target = AttributeTargets.Method; return true; + case "property": Target = AttributeTargets.Property; return true; + } + throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget); + } + + StringBuilder sb = new StringBuilder (); + foreach (string s in valid_targets) { + sb.Append (s); + sb.Append (", "); + } + sb.Remove (sb.Length - 2, 2); + Report.Error (657, Location, "`{0}' is not a valid attribute location for this declaration. " + + "Valid attribute locations for this declaration are `{1}'", ExplicitTarget, sb.ToString ()); + return false; + } + /// /// Tests permitted SecurityAction for assembly or other types /// public bool CheckSecurityActionValidity (bool for_assembly) { - SecurityAction action = GetSecurityActionValue (); + SecurityAction action = GetSecurityActionValue (); - if ((action == SecurityAction.RequestMinimum || action == SecurityAction.RequestOptional || - action == SecurityAction.RequestRefuse) && for_assembly) - return true; - - if (!for_assembly) { - if (action < SecurityAction.Demand || action > SecurityAction.InheritanceDemand) { - Error_AttributeEmitError ("SecurityAction is out of range"); - return false; - } - - if ((action != SecurityAction.RequestMinimum && action != SecurityAction.RequestOptional && - action != SecurityAction.RequestRefuse) && !for_assembly) + switch (action) { + case SecurityAction.Demand: + case SecurityAction.Assert: + case SecurityAction.Deny: + case SecurityAction.PermitOnly: + case SecurityAction.LinkDemand: + case SecurityAction.InheritanceDemand: + if (!for_assembly) + return true; + break; + + case SecurityAction.RequestMinimum: + case SecurityAction.RequestOptional: + case SecurityAction.RequestRefuse: + if (for_assembly) return true; + break; + + default: + Error_AttributeEmitError ("SecurityAction is out of range"); + return false; } - Error_AttributeEmitError (String.Concat ("SecurityAction '", action, "' is not valid for this declaration")); + Error_AttributeEmitError (String.Concat ("SecurityAction `", action, "' is not valid for this declaration")); return false; } @@ -934,7 +1027,7 @@ namespace Mono.CSharp { ps.AddPermission (perm); } - object GetValue (object value) + static object GetValue (object value) { if (value is EnumConstant) return ((EnumConstant) value).GetValue (); @@ -1032,7 +1125,7 @@ namespace Mono.CSharp { return UnmanagedMarshal.DefineSafeArray (array_sub_type); case UnmanagedType.ByValArray: - FieldMember fm = attr as FieldMember; + FieldBase fm = attr as FieldBase; if (fm == null) { Error_AttributeEmitError ("Specified unmanaged type is only valid on fields"); return null; @@ -1052,11 +1145,19 @@ namespace Mono.CSharp { return (CharSet)System.Enum.Parse (typeof (CharSet), pos_values [0].ToString ()); } - public MethodImplOptions GetMethodImplOptions () - { - if (pos_values [0].GetType () != typeof (MethodImplOptions)) - return (MethodImplOptions)System.Enum.ToObject (typeof (MethodImplOptions), pos_values [0]); - return (MethodImplOptions)pos_values [0]; + public bool IsInternalMethodImplAttribute { + get { + if (Type != TypeManager.methodimpl_attr_type) + return false; + + MethodImplOptions options; + if (pos_values[0].GetType () != typeof (MethodImplOptions)) + options = (MethodImplOptions)System.Enum.ToObject (typeof (MethodImplOptions), pos_values[0]); + else + options = (MethodImplOptions)pos_values[0]; + + return (options & MethodImplOptions.InternalCall) != 0; + } } public LayoutKind GetLayoutKindValue () @@ -1067,54 +1168,71 @@ namespace Mono.CSharp { return (LayoutKind)pos_values [0]; } + public object GetParameterDefaultValue () + { + return pos_values [0]; + } + + public override bool Equals (object obj) + { + Attribute a = obj as Attribute; + if (a == null) + return false; + + return Type == a.Type && Target == a.Target; + } + + public override int GetHashCode () + { + return base.GetHashCode (); + } + /// /// Emit attribute for Attributable symbol /// - public void Emit (EmitContext ec, Attributable ias, ListDictionary emitted_attr) + public void Emit (ListDictionary allEmitted) { - CustomAttributeBuilder cb = Resolve (ec); + CustomAttributeBuilder cb = Resolve (); if (cb == null) return; - AttributeUsageAttribute usage_attr = GetAttributeUsage (ec); + AttributeUsageAttribute usage_attr = GetAttributeUsage (Type); if ((usage_attr.ValidOn & Target) == 0) { - Report.Error (592, Location, "Attribute `{0}' is not valid on this declaration type. " + + Report.Error (592, Location, "The attribute `{0}' is not valid on this declaration type. " + "It is valid on `{1}' declarations only", GetSignatureForError (), GetValidTargets ()); return; } try { - ias.ApplyAttributeBuilder (this, cb); + foreach (Attributable owner in owners) + owner.ApplyAttributeBuilder (this, cb); } catch (Exception e) { Error_AttributeEmitError (e.Message); return; } - 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 `{0}' attribute", GetSignatureForError ()); - return; + if (!usage_attr.AllowMultiple && allEmitted != null) { + if (allEmitted.Contains (this)) { + ArrayList a = allEmitted [this] as ArrayList; + if (a == null) { + a = new ArrayList (2); + allEmitted [this] = a; + } + a.Add (this); + } else { + allEmitted.Add (this, null); } - emitted_targets.Add (Target); } if (!RootContext.VerifyClsCompliance) return; // Here we are testing attribute arguments for array usage (error 3016) - if (ias.IsClsCompliaceRequired (ec.DeclSpace)) { - if (Arguments == null) - return; - - ArrayList pos_args = (ArrayList) Arguments [0]; - if (pos_args != null) { - foreach (Argument arg in pos_args) { + if (Owner.IsClsComplianceRequired ()) { + if (PosArguments != null) { + foreach (Argument arg in PosArguments) { // Type is undefined (was error 246) if (arg.Type == null) return; @@ -1126,11 +1244,10 @@ namespace Mono.CSharp { } } - if (Arguments.Count < 2) + if (NamedArguments == null) return; - ArrayList named_args = (ArrayList) Arguments [1]; - foreach (DictionaryEntry de in named_args) { + foreach (DictionaryEntry de in NamedArguments) { Argument arg = (Argument) de.Value; // Type is undefined (was error 246) @@ -1144,150 +1261,48 @@ namespace Mono.CSharp { } } } - - public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name, - MethodAttributes flags, Type ret_type, Type [] param_types) - { - if (pos_values == null) - // 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); - - if (resolve_error) - return null; - - string dll_name = (string)pos_values [0]; - - // Default settings - CallingConvention cc = CallingConvention.Winapi; - CharSet charset = CodeGen.Module.DefaultCharSet; - bool preserve_sig = true; - string entry_point = name; - bool best_fit_mapping = false; - bool throw_on_unmappable = false; - bool exact_spelling = false; - bool set_last_error = false; - - bool best_fit_mapping_set = false; - bool throw_on_unmappable_set = false; - bool exact_spelling_set = false; - bool set_last_error_set = false; - - MethodInfo set_best_fit = null; - MethodInfo set_throw_on = null; - MethodInfo set_exact_spelling = null; - MethodInfo set_set_last_error = null; - - if (field_info_arr != null) { - - for (int i = 0; i < field_info_arr.Length; i++) { - switch (field_info_arr [i].Name) { - case "BestFitMapping": - best_fit_mapping = (bool) field_values_arr [i]; - best_fit_mapping_set = true; - break; - case "CallingConvention": - cc = (CallingConvention) field_values_arr [i]; - break; - case "CharSet": - charset = (CharSet) field_values_arr [i]; - break; - case "EntryPoint": - entry_point = (string) field_values_arr [i]; - break; - case "ExactSpelling": - exact_spelling = (bool) field_values_arr [i]; - exact_spelling_set = true; - break; - case "PreserveSig": - preserve_sig = (bool) field_values_arr [i]; - break; - case "SetLastError": - set_last_error = (bool) field_values_arr [i]; - set_last_error_set = true; - break; - case "ThrowOnUnmappableChar": - throw_on_unmappable = (bool) field_values_arr [i]; - throw_on_unmappable_set = true; - break; - default: - throw new InternalErrorException (field_info_arr [i].ToString ()); - } - } - } - - if (throw_on_unmappable_set || best_fit_mapping_set || exact_spelling_set || set_last_error_set) { - set_best_fit = typeof (MethodBuilder). - GetMethod ("set_BestFitMapping", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - set_throw_on = typeof (MethodBuilder). - GetMethod ("set_ThrowOnUnmappableChar", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - set_exact_spelling = typeof (MethodBuilder). - GetMethod ("set_ExactSpelling", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - set_set_last_error = typeof (MethodBuilder). - GetMethod ("set_SetLastError", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - - if ((set_best_fit == null) || (set_throw_on == null) || - (set_exact_spelling == null) || (set_set_last_error == null)) { - Report.Error (-1, Location, - "The ThrowOnUnmappableChar, BestFitMapping, SetLastError, " + - "and ExactSpelling attributes can only be emitted when running on the mono runtime."); - return null; - } - } - - try { - MethodBuilder mb = builder.DefinePInvokeMethod ( - name, dll_name, entry_point, flags | MethodAttributes.HideBySig | MethodAttributes.PinvokeImpl, - CallingConventions.Standard, ret_type, param_types, cc, charset); - - if (preserve_sig) - mb.SetImplementationFlags (MethodImplAttributes.PreserveSig); - - if (throw_on_unmappable_set) - set_throw_on.Invoke (mb, 0, null, new object [] { throw_on_unmappable }, null); - if (best_fit_mapping_set) - set_best_fit.Invoke (mb, 0, null, new object [] { best_fit_mapping }, null); - if (exact_spelling_set) - set_exact_spelling.Invoke (mb, 0, null, new object [] { exact_spelling }, null); - if (set_last_error_set) - set_set_last_error.Invoke (mb, 0, null, new object [] { set_last_error }, null); - - return mb; - } - catch (ArgumentException e) { - Error_AttributeEmitError (e.Message); - return null; - } - } private Expression GetValue () { - if ((Arguments == null) || (Arguments.Count < 1)) + if (PosArguments == null || PosArguments.Count < 1) return null; - ArrayList al = (ArrayList) Arguments [0]; - if ((al == null) || (al.Count < 1)) - return null; - Argument arg = (Argument) al [0]; - if ((arg == null) || (arg.Expr == null)) - return null; - return arg.Expr; + + return ((Argument) PosArguments [0]).Expr; } public string GetString () { Expression e = GetValue (); - if (e is StringLiteral) - return (e as StringLiteral).Value; + if (e is StringConstant) + return ((StringConstant)e).Value; return null; } public bool GetBoolean () { Expression e = GetValue (); - if (e is BoolLiteral) - return (e as BoolLiteral).Value; + if (e is BoolConstant) + return ((BoolConstant)e).Value; return false; } + + public Type GetArgumentType () + { + TypeOf e = GetValue () as TypeOf; + if (e == null) + return null; + return e.TypeArgument; + } + + public override Expression DoResolve (EmitContext ec) + { + throw new NotImplementedException (); + } + + public override void Emit (EmitContext ec) + { + throw new NotImplementedException (); + } } @@ -1299,61 +1314,74 @@ namespace Mono.CSharp { { public readonly NamespaceEntry ns; - public GlobalAttribute (TypeContainer container, string target, - Expression left_expr, string identifier, ArrayList args, Location loc, bool nameEscaped): + public GlobalAttribute (NamespaceEntry ns, string target, + Expression left_expr, string identifier, object[] args, Location loc, bool nameEscaped): base (target, left_expr, identifier, args, loc, nameEscaped) { - ns = container.NamespaceEntry; + this.ns = ns; + this.owners = new Attributable[1]; + } + + public override void AttachTo (Attributable owner) + { + if (ExplicitTarget == "assembly") { + owners [0] = CodeGen.Assembly; + return; + } + if (ExplicitTarget == "module") { + owners [0] = CodeGen.Module; + return; + } + throw new NotImplementedException ("Unknown global explicit target " + ExplicitTarget); } void Enter () { - // RootContext.Tree.Types has a single NamespaceEntry which gets overwritten + // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten // each time a new file is parsed. However, we need to use the NamespaceEntry // in effect where the attribute was used. Since code elsewhere cannot assume // that the NamespaceEntry is right, just overwrite it. // - // Precondition: RootContext.Tree.Types == null + // Precondition: RootContext.ToplevelTypes == null - if (RootContext.Tree.Types.NamespaceEntry != null) + if (RootContext.ToplevelTypes.NamespaceEntry != null) throw new InternalErrorException (Location + " non-null NamespaceEntry"); - RootContext.Tree.Types.NamespaceEntry = ns; + RootContext.ToplevelTypes.NamespaceEntry = ns; } void Leave () { - RootContext.Tree.Types.NamespaceEntry = null; + RootContext.ToplevelTypes.NamespaceEntry = null; } - protected override FullNamedExpression ResolveAsTypeStep (Expression expr, EmitContext ec, bool silent) + protected override TypeExpr ResolveAsTypeTerminal (Expression expr, IResolveContext ec, bool silent) { try { Enter (); - return base.ResolveAsTypeStep (expr, ec, silent); + return base.ResolveAsTypeTerminal (expr, ec, silent); } finally { Leave (); } } - - protected override FullNamedExpression ResolveAsTypeTerminal (Expression expr, EmitContext ec, bool silent) + protected override ConstructorInfo ResolveConstructor (EmitContext ec) { try { Enter (); - return base.ResolveAsTypeTerminal (expr, ec, silent); + return base.ResolveConstructor (ec); } finally { Leave (); } } - protected override ConstructorInfo ResolveArguments (EmitContext ec) + protected override bool ResolveNamedArguments (EmitContext ec) { try { Enter (); - return base.ResolveArguments (ec); + return base.ResolveNamedArguments (ec); } finally { Leave (); @@ -1362,7 +1390,7 @@ namespace Mono.CSharp { } public class Attributes { - public ArrayList Attrs; + public readonly ArrayList Attrs; public Attributes (Attribute a) { @@ -1380,47 +1408,28 @@ namespace Mono.CSharp { Attrs.AddRange (attrs); } + public void AttachTo (Attributable attributable) + { + foreach (Attribute a in Attrs) + a.AttachTo (attributable); + } + /// /// Checks whether attribute target is valid for the current element /// - public bool CheckTargets (Attributable member) + public bool CheckTargets () { - string[] valid_targets = member.ValidAttributeTargets; foreach (Attribute a in Attrs) { - if (a.ExplicitTarget == null || a.ExplicitTarget == valid_targets [0]) { - a.Target = member.AttributeTargets; - continue; - } - - // TODO: we can skip the first item - if (((IList) valid_targets).Contains (a.ExplicitTarget)) { - switch (a.ExplicitTarget) { - case "return": a.Target = AttributeTargets.ReturnValue; continue; - case "param": a.Target = AttributeTargets.Parameter; continue; - case "field": a.Target = AttributeTargets.Field; continue; - case "method": a.Target = AttributeTargets.Method; continue; - case "property": a.Target = AttributeTargets.Property; continue; - } - throw new InternalErrorException ("Unknown explicit target: " + a.ExplicitTarget); - } - - StringBuilder sb = new StringBuilder (); - foreach (string s in valid_targets) { - sb.Append (s); - sb.Append (", "); - } - sb.Remove (sb.Length - 2, 2); - Report.Error (657, a.Location, "`{0}' is not a valid attribute location for this declaration. " + - "Valid attribute locations for this declaration are `{1}'", a.ExplicitTarget, sb.ToString ()); - return false; + if (!a.CheckTarget ()) + return false; } return true; } - public Attribute Search (Type t, EmitContext ec) + public Attribute Search (Type t) { foreach (Attribute a in Attrs) { - if (a.ResolveType (ec) == t) + if (a.ResolveType () == t) return a; } return null; @@ -1429,12 +1438,12 @@ namespace Mono.CSharp { /// /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true /// - public Attribute[] SearchMulti (Type t, EmitContext ec) + public Attribute[] SearchMulti (Type t) { ArrayList ar = null; foreach (Attribute a in Attrs) { - if (a.ResolveType (ec) == t) { + if (a.ResolveType () == t) { if (ar == null) ar = new ArrayList (); ar.Add (a); @@ -1444,19 +1453,34 @@ namespace Mono.CSharp { return ar == null ? null : ar.ToArray (typeof (Attribute)) as Attribute[]; } - public void Emit (EmitContext ec, Attributable ias) + public void Emit () { - CheckTargets (ias); + CheckTargets (); - ListDictionary ld = new ListDictionary (); + ListDictionary ld = Attrs.Count > 1 ? new ListDictionary () : null; foreach (Attribute a in Attrs) - a.Emit (ec, ias, ld); + a.Emit (ld); + + if (ld == null || ld.Count == 0) + return; + + foreach (DictionaryEntry d in ld) { + if (d.Value == null) + continue; + + foreach (Attribute collision in (ArrayList)d.Value) + Report.SymbolRelatedToPreviousError (collision.Location, ""); + + Attribute a = (Attribute)d.Key; + Report.Error (579, a.Location, "The attribute `{0}' cannot be applied multiple times", + a.GetSignatureForError ()); + } } - public bool Contains (Type t, EmitContext ec) + public bool Contains (Type t) { - return Search (t, ec) != null; + return Search (t) != null; } } @@ -1465,22 +1489,38 @@ namespace Mono.CSharp { /// sealed class AttributeTester { - 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 (); + static PtrHashtable analyzed_types; + static PtrHashtable analyzed_types_obsolete; + static PtrHashtable analyzed_member_obsolete; + static PtrHashtable analyzed_method_excluded; #if NET_2_0 - static PtrHashtable fixed_buffer_cache = new PtrHashtable (); + static PtrHashtable fixed_buffer_cache; #endif static object TRUE = new object (); static object FALSE = new object (); + static AttributeTester () + { + Reset (); + } + private AttributeTester () { } + public static void Reset () + { + analyzed_types = new PtrHashtable (); + analyzed_types_obsolete = new PtrHashtable (); + analyzed_member_obsolete = new PtrHashtable (); + analyzed_method_excluded = new PtrHashtable (); +#if NET_2_0 + fixed_buffer_cache = new PtrHashtable (); +#endif + } + public enum Result { Ok, RefOutArrayError, @@ -1542,24 +1582,6 @@ namespace Mono.CSharp { return result; } - /// - /// Goes through all parameters and test if they are CLS-Compliant. - /// - public static bool AreParametersCompliant (Parameter[] fixedParameters, Location loc) - { - if (fixedParameters == null) - return true; - - foreach (Parameter arg in fixedParameters) { - if (!AttributeTester.IsClsCompliant (arg.ParameterType)) { - Report.Error (3001, loc, "Argument type `{0}' is not CLS-compliant", arg.GetSignatureForError ()); - return false; - } - } - return true; - } - - /// /// This method tests the CLS compliance of external types. It doesn't test type visibility. /// @@ -1578,8 +1600,10 @@ namespace Mono.CSharp { } bool result; - if (type.IsArray || type.IsByRef) { + if (type.IsArray || type.IsByRef) { result = IsClsCompliant (TypeManager.GetElementType (type)); + } else if (TypeManager.IsNullableType (type)) { + result = IsClsCompliant (TypeManager.GetTypeArguments (type) [0]); } else { result = AnalyzeTypeCompliance (type); } @@ -1592,15 +1616,22 @@ namespace Mono.CSharp { /// public static IFixedBuffer GetFixedBuffer (FieldInfo fi) { + // Fixed buffer helper type is generated as value type + if (!fi.FieldType.IsValueType) + return null; + FieldBase fb = TypeManager.GetField (fi); if (fb != null) { return fb as IFixedBuffer; } + + if (TypeManager.GetConstant (fi) != null) + return null; #if NET_2_0 object o = fixed_buffer_cache [fi]; if (o == null) { - if (System.Attribute.GetCustomAttribute (fi, TypeManager.fixed_buffer_attr_type) == null) { + if (!fi.IsDefined (TypeManager.fixed_buffer_attr_type, false)) { fixed_buffer_cache.Add (fi, FALSE); return null; } @@ -1616,7 +1647,7 @@ namespace Mono.CSharp { return (IFixedBuffer)o; #else return null; -#endif +#endif } public static void VerifyModulesClsCompliance () @@ -1660,11 +1691,15 @@ namespace Mono.CSharp { static bool AnalyzeTypeCompliance (Type type) { + type = TypeManager.DropGenericTypeArguments (type); DeclSpace ds = TypeManager.LookupDeclSpace (type); if (ds != null) { - return ds.IsClsCompliaceRequired (ds.Parent); + return ds.IsClsComplianceRequired (); } + if (TypeManager.IsGenericParameter (type)) + return true; + object[] CompliantAttribute = type.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false); if (CompliantAttribute.Length == 0) return IsClsCompliant (type.Assembly); @@ -1672,6 +1707,13 @@ namespace Mono.CSharp { return ((CLSCompliantAttribute)CompliantAttribute[0]).IsCompliant; } + // Registers the core type as we assume that they will never be obsolete which + // makes things easier for bootstrap and faster (we don't need to query Obsolete attribute). + public static void RegisterNonObsoleteType (Type type) + { + analyzed_types_obsolete [type] = FALSE; + } + /// /// Returns instance of ObsoleteAttribute when type is obsolete /// @@ -1685,9 +1727,11 @@ namespace Mono.CSharp { return (ObsoleteAttribute)type_obsolete; ObsoleteAttribute result = null; - if (type.IsByRef || type.IsArray || type.IsPointer) { + if (TypeManager.HasElementType (type)) { result = GetObsoleteAttribute (TypeManager.GetElementType (type)); - } else { + } else if (TypeManager.IsGenericParameter (type) || TypeManager.IsGenericType (type)) + return null; + else { DeclSpace type_ds = TypeManager.LookupDeclSpace (type); // Type is external, we can get attribute directly @@ -1718,14 +1762,13 @@ namespace Mono.CSharp { if (mb.DeclaringType is TypeBuilder) return null; - if (mb.IsSpecialName) { - PropertyInfo pi = PropertyExpr.AccessorTable [mb] as PropertyInfo; - if (pi != null) { - // FIXME: This is buggy as properties from this assembly are included as well - return null; - //return GetMemberObsoleteAttribute (pi); - } - } + MemberInfo mi = TypeManager.GetPropertyFromAccessor (mb); + if (mi != null) + return GetMemberObsoleteAttribute (mi); + + mi = TypeManager.GetEventFromAccessor (mb); + if (mi != null) + return GetMemberObsoleteAttribute (mi); return GetMemberObsoleteAttribute (mb); } @@ -1742,6 +1785,9 @@ namespace Mono.CSharp { if (type_obsolete != null) return (ObsoleteAttribute)type_obsolete; + if ((mi.DeclaringType is TypeBuilder) || TypeManager.IsGenericType (mi.DeclaringType)) + return null; + ObsoleteAttribute oa = System.Attribute.GetCustomAttribute (mi, TypeManager.obsolete_attribute_type, false) as ObsoleteAttribute; analyzed_member_obsolete.Add (mi, oa == null ? FALSE : oa); @@ -1758,7 +1804,7 @@ namespace Mono.CSharp { return; } - if (oa.Message == null) { + if (oa.Message == null || oa.Message.Length == 0) { Report.Warning (612, 1, loc, "`{0}' is obsolete", member); return; } @@ -1770,7 +1816,7 @@ namespace Mono.CSharp { object excluded = analyzed_method_excluded [mb]; if (excluded != null) return excluded == TRUE ? true : false; - + ConditionalAttribute[] attrs = mb.GetCustomAttributes (TypeManager.conditional_attribute_type, true) as ConditionalAttribute[]; if (attrs.Length == 0) { @@ -1818,17 +1864,19 @@ namespace Mono.CSharp { TypeContainer tc = TypeManager.LookupInterface (type); if (tc == null) { object[] o = type.GetCustomAttributes (TypeManager.coclass_attr_type, false); + if (o.Length < 1) + return null; return ((System.Runtime.InteropServices.CoClassAttribute)o[0]).CoClass; } if (tc.OptAttributes == null) return null; - Attribute a = tc.OptAttributes.Search (TypeManager.coclass_attr_type, tc.EmitContext); + Attribute a = tc.OptAttributes.Search (TypeManager.coclass_attr_type); if (a == null) return null; - return a.GetCoClassAttributeValue (tc.EmitContext); + return a.GetCoClassAttributeValue (); } } }