}
set {
attributes = value;
+ if (attributes != null)
+ attributes.CheckTargets (ValidAttributeTargets);
}
}
public abstract bool IsClsCompliaceRequired (DeclSpace ds);
/// <summary>
- /// Gets list of valid attribute targets for explicit target declaration
+ /// Gets list of valid attribute targets for explicit target declaration.
+ /// The first array item is default target. Don't break this rule.
/// </summary>
protected abstract string[] ValidAttributeTargets { get; }
};
public class Attribute {
- public readonly string Target;
+ public string Target;
public readonly string Name;
public readonly ArrayList Arguments;
get { return ImplOptions == MethodImplOptions.InternalCall; }
}
- protected virtual bool CanIgnoreInvalidAttribute (Attributable ias)
- {
- return false;
- }
-
/// <summary>
/// Emit attribute for Attributable symbol
/// </summary>
AttributeUsageAttribute usage_attr = GetAttributeUsage ();
if ((usage_attr.ValidOn & ias.AttributeTargets) == 0) {
- // The parser applies toplevel attributes both to the assembly and
- // to a top-level class, if any. So, be silent about them.
- if (! CanIgnoreInvalidAttribute (ias))
- Error_AttributeNotValidForElement (this, Location);
+ Error_AttributeNotValidForElement (this, Location);
return;
}
ias.ApplyAttributeBuilder (this, cb);
- // Because default target is null (we save some space). We need to transform it here
- // for distinction between "default" and "doesn't exist"
- string target = Target == null ? "default" : Target;
- string emitted = emitted_attr [Type] as string;
- if (emitted == target && !usage_attr.AllowMultiple) {
+ if (!usage_attr.AllowMultiple && emitted_attr.Contains (Target)) {
Report.Error (579, Location, "Duplicate '" + Name + "' attribute");
}
- emitted_attr [Type] = target;
+ emitted_attr [Type] = Target;
// Here we are testing attribute arguments for array usage (error 3016)
if (ias.IsClsCompliaceRequired (ec.DeclSpace)) {
ec.DeclSpace.NamespaceEntry = ns;
return base.CheckAttributeType (ec, complain);
}
-
- protected override bool CanIgnoreInvalidAttribute (Attributable ias)
- {
- // Ignore error if this attribute is shared between the Assembly
- // and a top-level class. The parser couldn't figure out which entity
- // this attribute belongs to. If this attribute is erroneous, it should
- // be caught when it is processed by the top-level class.
-
- return (Target == null && ias is CommonAssemblyModulClass);
- }
}
public class Attributes {
public void CheckTargets (string[] possible_targets)
{
foreach (Attribute a in Attrs) {
- if (a.Target == null)
+ if (a.Target == null) {
+ a.Target = possible_targets [0];
continue;
+ }
if (((IList) possible_targets).Contains (a.Target))
continue;
compilation_unit
: outer_declarations opt_EOF
- | outer_declarations attribute_sections opt_EOF
- | attribute_sections opt_EOF
+ | outer_declarations global_attributes opt_EOF
+ | global_attributes opt_EOF
| opt_EOF /* allow empty files */
;
// Attributes 17.2
//
+global_attributes
+ : attribute_sections
+{
+ if ($1 != null)
+ CodeGen.Assembly.SetAttributes ((Attributes)$1);
+
+ $$ = $1;
+}
+
opt_attributes
: /* empty */
{
CodeGen.Assembly.AddAttributes (sect);
$$ = null;
} else {
-
- // Because we don't know if target should be on assembly or type
- // we add it to both. This leads error CS0657 is reported twice
- // for this case but it is better than mistification.
- CodeGen.Assembly.AddAttributes (sect);
$$ = new Attributes (sect);
}
} else {
}
opt_attribute_arguments
{
- if (current_attr_target == "assembly" || current_attr_target == "module"
- || (global_attrs_enabled && current_attr_target == null))
+ if (current_attr_target == "assembly" || current_attr_target == "module")
$$ = new GlobalAttribute (current_container, current_attr_target, (string) ($1).ToString (), (ArrayList) $3, (Location) $2);
else
$$ = new Attribute (current_attr_target, (string) ($1).ToString (), (ArrayList) $3, (Location) $2);