7d7f676260
Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
2308 lines
66 KiB
C#
2308 lines
66 KiB
C#
//
|
|
// attribute.cs: Attributes handling
|
|
//
|
|
// Author: Ravi Pratap (ravi@ximian.com)
|
|
// Marek Safar (marek.safar@gmail.com)
|
|
//
|
|
// Dual licensed under the terms of the MIT X11 or GNU GPL
|
|
//
|
|
// Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
|
|
// Copyright 2003-2008 Novell, Inc.
|
|
// Copyright 2011-2013 Xamarin Inc
|
|
//
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Security;
|
|
using System.Security.Permissions;
|
|
using System.Text;
|
|
using System.IO;
|
|
|
|
#if STATIC
|
|
using SecurityType = System.Collections.Generic.List<IKVM.Reflection.Emit.CustomAttributeBuilder>;
|
|
using BadImageFormat = IKVM.Reflection.BadImageFormatException;
|
|
using IKVM.Reflection;
|
|
using IKVM.Reflection.Emit;
|
|
#else
|
|
using SecurityType = System.Collections.Generic.Dictionary<System.Security.Permissions.SecurityAction, System.Security.PermissionSet>;
|
|
using BadImageFormat = System.BadImageFormatException;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
#endif
|
|
|
|
namespace Mono.CSharp {
|
|
|
|
/// <summary>
|
|
/// Base class for objects that can have Attributes applied to them.
|
|
/// </summary>
|
|
public abstract class Attributable {
|
|
//
|
|
// Holds all attributes attached to this element
|
|
//
|
|
protected Attributes attributes;
|
|
|
|
public void AddAttributes (Attributes attrs, IMemberContext context)
|
|
{
|
|
if (attrs == null)
|
|
return;
|
|
|
|
if (attributes == null)
|
|
attributes = attrs;
|
|
else
|
|
attributes.AddAttributes (attrs.Attrs);
|
|
|
|
attrs.AttachTo (this, context);
|
|
}
|
|
|
|
public Attributes OptAttributes {
|
|
get {
|
|
return attributes;
|
|
}
|
|
set {
|
|
attributes = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
|
|
/// </summary>
|
|
public abstract void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa);
|
|
|
|
/// <summary>
|
|
/// Returns one AttributeTarget for this element.
|
|
/// </summary>
|
|
public abstract AttributeTargets AttributeTargets { get; }
|
|
|
|
public abstract bool IsClsComplianceRequired ();
|
|
|
|
/// <summary>
|
|
/// Gets list of valid attribute targets for explicit target declaration.
|
|
/// The first array item is default target. Don't break this rule.
|
|
/// </summary>
|
|
public abstract string[] ValidAttributeTargets { get; }
|
|
};
|
|
|
|
public class Attribute
|
|
{
|
|
public readonly string ExplicitTarget;
|
|
public AttributeTargets Target;
|
|
readonly ATypeNameExpression expression;
|
|
|
|
Arguments pos_args, named_args;
|
|
|
|
bool resolve_error;
|
|
bool arg_resolved;
|
|
readonly bool nameEscaped;
|
|
readonly Location loc;
|
|
public TypeSpec Type;
|
|
|
|
//
|
|
// An attribute can be attached to multiple targets (e.g. multiple fields)
|
|
//
|
|
Attributable[] targets;
|
|
|
|
//
|
|
// A member context for the attribute, it's much easier to hold it here
|
|
// than trying to pull it during resolve
|
|
//
|
|
IMemberContext context;
|
|
|
|
public static readonly AttributeUsageAttribute DefaultUsageAttribute = new AttributeUsageAttribute (AttributeTargets.All);
|
|
public static readonly object[] EmptyObject = new object [0];
|
|
|
|
List<KeyValuePair<MemberExpr, NamedArgument>> named_values;
|
|
|
|
public Attribute (string target, ATypeNameExpression expr, Arguments[] args, Location loc, bool nameEscaped)
|
|
{
|
|
this.expression = expr;
|
|
if (args != null) {
|
|
pos_args = args[0];
|
|
named_args = args[1];
|
|
}
|
|
this.loc = loc;
|
|
ExplicitTarget = target;
|
|
this.nameEscaped = nameEscaped;
|
|
}
|
|
|
|
public Location Location {
|
|
get {
|
|
return loc;
|
|
}
|
|
}
|
|
|
|
public Arguments NamedArguments {
|
|
get {
|
|
return named_args;
|
|
}
|
|
}
|
|
|
|
public Arguments PositionalArguments {
|
|
get {
|
|
return pos_args;
|
|
}
|
|
}
|
|
|
|
public bool ResolveError {
|
|
get {
|
|
return resolve_error;
|
|
}
|
|
}
|
|
|
|
public ATypeNameExpression TypeExpression {
|
|
get {
|
|
return expression;
|
|
}
|
|
}
|
|
|
|
void AddModuleCharSet (ResolveContext rc)
|
|
{
|
|
const string dll_import_char_set = "CharSet";
|
|
|
|
//
|
|
// Only when not customized by user
|
|
//
|
|
if (HasField (dll_import_char_set))
|
|
return;
|
|
|
|
if (!rc.Module.PredefinedTypes.CharSet.Define ()) {
|
|
return;
|
|
}
|
|
|
|
if (NamedArguments == null)
|
|
named_args = new Arguments (1);
|
|
|
|
var value = Constant.CreateConstantFromValue (rc.Module.PredefinedTypes.CharSet.TypeSpec, rc.Module.DefaultCharSet, Location);
|
|
NamedArguments.Add (new NamedArgument (dll_import_char_set, loc, value));
|
|
}
|
|
|
|
public Attribute Clone ()
|
|
{
|
|
Attribute a = new Attribute (ExplicitTarget, expression, null, loc, nameEscaped);
|
|
a.pos_args = pos_args;
|
|
a.named_args = NamedArguments;
|
|
return a;
|
|
}
|
|
|
|
//
|
|
// When the same attribute is attached to multiple fiels
|
|
// we use @target field as a list of targets. The attribute
|
|
// has to be resolved only once but emitted for each target.
|
|
//
|
|
public void AttachTo (Attributable target, IMemberContext context)
|
|
{
|
|
if (this.targets == null) {
|
|
this.targets = new Attributable[] { target };
|
|
this.context = context;
|
|
return;
|
|
}
|
|
|
|
// When re-attaching global attributes
|
|
if (context is NamespaceContainer) {
|
|
this.targets[0] = target;
|
|
this.context = context;
|
|
return;
|
|
}
|
|
|
|
// Resize target array
|
|
Attributable[] new_array = new Attributable [this.targets.Length + 1];
|
|
targets.CopyTo (new_array, 0);
|
|
new_array [targets.Length] = target;
|
|
this.targets = new_array;
|
|
|
|
// No need to update context, different targets cannot have
|
|
// different contexts, it's enough to remove same attributes
|
|
// from secondary members.
|
|
|
|
target.OptAttributes = null;
|
|
}
|
|
|
|
public ResolveContext CreateResolveContext ()
|
|
{
|
|
return new ResolveContext (context, ResolveContext.Options.ConstantScope);
|
|
}
|
|
|
|
static void Error_InvalidNamedArgument (ResolveContext rc, NamedArgument name)
|
|
{
|
|
rc.Report.Error (617, name.Location, "`{0}' is not a valid named attribute argument. Named attribute arguments " +
|
|
"must be fields which are not readonly, static, const or read-write properties which are " +
|
|
"public and not static",
|
|
name.Name);
|
|
}
|
|
|
|
static void Error_InvalidNamedArgumentType (ResolveContext rc, NamedArgument name)
|
|
{
|
|
rc.Report.Error (655, name.Location,
|
|
"`{0}' is not a valid named attribute argument because it is not a valid attribute parameter type",
|
|
name.Name);
|
|
}
|
|
|
|
public static void Error_AttributeArgumentIsDynamic (IMemberContext context, Location loc)
|
|
{
|
|
context.Module.Compiler.Report.Error (1982, loc, "An attribute argument cannot be dynamic expression");
|
|
}
|
|
|
|
public void Error_MissingGuidAttribute ()
|
|
{
|
|
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 ());
|
|
}
|
|
|
|
public void Error_MisusedDynamicAttribute ()
|
|
{
|
|
Report.Error (1970, loc, "Do not use `{0}' directly. Use `dynamic' keyword instead", GetSignatureForError ());
|
|
}
|
|
|
|
public void Error_MisusedTupleAttribute ()
|
|
{
|
|
Report.Error (8138, loc, "Do not use `{0}' directly. Use the tuple syntax instead", GetSignatureForError ());
|
|
}
|
|
|
|
void Error_AttributeEmitError (string inner)
|
|
{
|
|
Report.Error (647, Location, "Error during emitting `{0}' attribute. The reason is `{1}'",
|
|
Type.GetSignatureForError (), inner);
|
|
}
|
|
|
|
public void Error_InvalidArgumentValue (TypeSpec attributeType)
|
|
{
|
|
Report.Error (591, Location, "Invalid value for argument to `{0}' attribute", attributeType.GetSignatureForError ());
|
|
}
|
|
|
|
public void Error_InvalidSecurityParent ()
|
|
{
|
|
Report.Error (7070, Location,
|
|
"Security attribute `{0}' is not valid on this declaration type. Security attributes are only valid on assembly, type and method declarations",
|
|
Type.GetSignatureForError ());
|
|
}
|
|
|
|
Attributable Owner {
|
|
get {
|
|
return targets [0];
|
|
}
|
|
}
|
|
|
|
public void SetOwner (Attributable owner)
|
|
{
|
|
targets [0] = owner;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
|
|
/// </summary>
|
|
void ResolveAttributeType (bool comparisonOnly)
|
|
{
|
|
var resolve_printer = new SessionReportPrinter ();
|
|
SessionReportPrinter secondary_printer = null;
|
|
ReportPrinter prev_recorder = Report.SetPrinter (resolve_printer);
|
|
|
|
bool t1_is_attr = false;
|
|
bool t2_is_attr = false;
|
|
TypeSpec t1, t2;
|
|
ATypeNameExpression expanded = null;
|
|
|
|
// TODO: Additional warnings such as CS0436 are swallowed because we don't
|
|
// print on success
|
|
|
|
try {
|
|
t1 = expression.ResolveAsType (context);
|
|
resolve_printer.EndSession ();
|
|
|
|
if (t1 != null && resolve_printer.ErrorsCount == 0)
|
|
t1_is_attr = t1.IsAttribute;
|
|
|
|
if (nameEscaped) {
|
|
t2 = null;
|
|
} else {
|
|
expanded = (ATypeNameExpression) expression.Clone (null);
|
|
expanded.Name += "Attribute";
|
|
|
|
secondary_printer = new SessionReportPrinter ();
|
|
Report.SetPrinter (secondary_printer);
|
|
t2 = expanded.ResolveAsType (context);
|
|
secondary_printer.EndSession ();
|
|
if (t2 != null && secondary_printer.ErrorsCount == 0)
|
|
t2_is_attr = t2.IsAttribute;
|
|
|
|
secondary_printer.EndSession ();
|
|
}
|
|
} finally {
|
|
context.Module.Compiler.Report.SetPrinter (prev_recorder);
|
|
}
|
|
|
|
if (t1_is_attr && t2_is_attr && t1 != t2) {
|
|
if (!comparisonOnly) {
|
|
Report.Error (1614, Location, "`{0}' is ambiguous between `{1}' and `{2}'. Use either `@{0}' or `{0}Attribute'",
|
|
GetSignatureForError (), expression.GetSignatureForError (), expanded.GetSignatureForError ());
|
|
resolve_error = true;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (t1_is_attr) {
|
|
Type = t1;
|
|
return;
|
|
}
|
|
|
|
if (t2_is_attr) {
|
|
Type = t2;
|
|
return;
|
|
}
|
|
|
|
if (comparisonOnly)
|
|
return;
|
|
|
|
resolve_error = true;
|
|
|
|
if (t1 != null) {
|
|
if (resolve_printer.IsEmpty) {
|
|
Report.SymbolRelatedToPreviousError (t1);
|
|
Report.Error (616, Location, "`{0}': is not an attribute class", t1.GetSignatureForError ());
|
|
} else {
|
|
resolve_printer.Merge (prev_recorder);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (t2 != null) {
|
|
if (secondary_printer.IsEmpty) {
|
|
Report.SymbolRelatedToPreviousError (t2);
|
|
Report.Error (616, Location, "`{0}': is not an attribute class", t2.GetSignatureForError ());
|
|
} else {
|
|
secondary_printer.Merge (prev_recorder);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
resolve_printer.Merge (prev_recorder);
|
|
}
|
|
|
|
public TypeSpec ResolveTypeForComparison ()
|
|
{
|
|
if (Type == null && !resolve_error)
|
|
ResolveAttributeType (true);
|
|
return Type;
|
|
}
|
|
|
|
public string GetSignatureForError ()
|
|
{
|
|
if (Type != null)
|
|
return Type.GetSignatureForError ();
|
|
|
|
return expression.GetSignatureForError ();
|
|
}
|
|
|
|
public bool HasSecurityAttribute {
|
|
get {
|
|
PredefinedAttribute pa = context.Module.PredefinedAttributes.Security;
|
|
return pa.IsDefined && TypeSpec.IsBaseClass (Type, pa.TypeSpec, false);
|
|
}
|
|
}
|
|
|
|
public bool IsValidSecurityAttribute ()
|
|
{
|
|
return HasSecurityAttribute && IsSecurityActionValid ();
|
|
}
|
|
|
|
static bool IsValidMethodImplOption (int value)
|
|
{
|
|
//
|
|
// Allow to use AggressiveInlining on any runtime/corlib
|
|
//
|
|
MethodImplOptions all = (MethodImplOptions) 256;
|
|
foreach (MethodImplOptions v in System.Enum.GetValues (typeof (MethodImplOptions))) {
|
|
all |= v;
|
|
}
|
|
|
|
return ((MethodImplOptions) value | all) == all;
|
|
}
|
|
|
|
public static bool IsValidArgumentType (TypeSpec t)
|
|
{
|
|
if (t.IsArray) {
|
|
var ac = (ArrayContainer) t;
|
|
if (ac.Rank > 1)
|
|
return false;
|
|
|
|
t = ac.Element;
|
|
}
|
|
|
|
switch (t.BuiltinType) {
|
|
case BuiltinTypeSpec.Type.Int:
|
|
case BuiltinTypeSpec.Type.UInt:
|
|
case BuiltinTypeSpec.Type.Long:
|
|
case BuiltinTypeSpec.Type.ULong:
|
|
case BuiltinTypeSpec.Type.Float:
|
|
case BuiltinTypeSpec.Type.Double:
|
|
case BuiltinTypeSpec.Type.Char:
|
|
case BuiltinTypeSpec.Type.Short:
|
|
case BuiltinTypeSpec.Type.Bool:
|
|
case BuiltinTypeSpec.Type.SByte:
|
|
case BuiltinTypeSpec.Type.Byte:
|
|
case BuiltinTypeSpec.Type.UShort:
|
|
|
|
case BuiltinTypeSpec.Type.String:
|
|
case BuiltinTypeSpec.Type.Object:
|
|
case BuiltinTypeSpec.Type.Dynamic:
|
|
case BuiltinTypeSpec.Type.Type:
|
|
return true;
|
|
}
|
|
|
|
return t.IsEnum;
|
|
}
|
|
|
|
// TODO: Don't use this ambiguous value
|
|
public string Name {
|
|
get { return expression.Name; }
|
|
}
|
|
|
|
public Report Report {
|
|
get { return context.Module.Compiler.Report; }
|
|
}
|
|
|
|
public MethodSpec Resolve ()
|
|
{
|
|
if (resolve_error)
|
|
return null;
|
|
|
|
resolve_error = true;
|
|
arg_resolved = true;
|
|
|
|
if (Type == null) {
|
|
ResolveAttributeType (false);
|
|
if (Type == null)
|
|
return null;
|
|
}
|
|
|
|
if (Type.IsAbstract) {
|
|
Report.Error (653, Location, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
|
|
return null;
|
|
}
|
|
|
|
Type.CheckObsoleteness (context, expression.StartLocation);
|
|
|
|
ResolveContext rc = null;
|
|
|
|
MethodSpec ctor;
|
|
// Try if the attribute is simple and has been resolved before
|
|
if (pos_args != null || !context.Module.AttributeConstructorCache.TryGetValue (Type, out ctor)) {
|
|
rc = CreateResolveContext ();
|
|
ctor = ResolveConstructor (rc);
|
|
if (ctor == null) {
|
|
return null;
|
|
}
|
|
|
|
if (pos_args == null && ctor.Parameters.IsEmpty)
|
|
context.Module.AttributeConstructorCache.Add (Type, ctor);
|
|
}
|
|
|
|
//
|
|
// Add [module: DefaultCharSet] to all DllImport import attributes
|
|
//
|
|
var module = context.Module;
|
|
if ((Type == module.PredefinedAttributes.DllImport || Type == module.PredefinedAttributes.UnmanagedFunctionPointer) && module.HasDefaultCharSet) {
|
|
if (rc == null)
|
|
rc = CreateResolveContext ();
|
|
|
|
AddModuleCharSet (rc);
|
|
}
|
|
|
|
if (NamedArguments != null) {
|
|
if (rc == null)
|
|
rc = CreateResolveContext ();
|
|
|
|
if (!ResolveNamedArguments (rc))
|
|
return null;
|
|
}
|
|
|
|
resolve_error = false;
|
|
return ctor;
|
|
}
|
|
|
|
MethodSpec ResolveConstructor (ResolveContext ec)
|
|
{
|
|
if (pos_args != null) {
|
|
bool dynamic;
|
|
pos_args.Resolve (ec, out dynamic);
|
|
if (dynamic) {
|
|
Error_AttributeArgumentIsDynamic (ec.MemberContext, loc);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return Expression.ConstructorLookup (ec, Type, ref pos_args, loc);
|
|
}
|
|
|
|
bool ResolveNamedArguments (ResolveContext ec)
|
|
{
|
|
int named_arg_count = NamedArguments.Count;
|
|
var seen_names = new List<string> (named_arg_count);
|
|
|
|
named_values = new List<KeyValuePair<MemberExpr, NamedArgument>> (named_arg_count);
|
|
|
|
foreach (NamedArgument a in NamedArguments) {
|
|
string name = a.Name;
|
|
if (seen_names.Contains (name)) {
|
|
ec.Report.Error (643, a.Location, "Duplicate named attribute `{0}' argument", name);
|
|
continue;
|
|
}
|
|
|
|
seen_names.Add (name);
|
|
|
|
a.Resolve (ec);
|
|
|
|
Expression member = Expression.MemberLookup (ec, false, Type, name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
|
|
|
|
if (member == null) {
|
|
member = Expression.MemberLookup (ec, true, Type, name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
|
|
|
|
if (member != null) {
|
|
// TODO: ec.Report.SymbolRelatedToPreviousError (member);
|
|
Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (member == null){
|
|
Expression.Error_TypeDoesNotContainDefinition (ec, Location, Type, name);
|
|
return false;
|
|
}
|
|
|
|
if (!(member is PropertyExpr || member is FieldExpr)) {
|
|
Error_InvalidNamedArgument (ec, a);
|
|
return false;
|
|
}
|
|
|
|
if (member is PropertyExpr) {
|
|
var pi = ((PropertyExpr) member).PropertyInfo;
|
|
|
|
if (!pi.HasSet || !pi.HasGet || pi.IsStatic || !pi.Get.IsPublic || !pi.Set.IsPublic) {
|
|
ec.Report.SymbolRelatedToPreviousError (pi);
|
|
Error_InvalidNamedArgument (ec, a);
|
|
return false;
|
|
}
|
|
|
|
if (!IsValidArgumentType (member.Type)) {
|
|
ec.Report.SymbolRelatedToPreviousError (pi);
|
|
Error_InvalidNamedArgumentType (ec, a);
|
|
return false;
|
|
}
|
|
|
|
// if (!context.IsObsolete)
|
|
pi.CheckObsoleteness (ec, member.StartLocation);
|
|
|
|
pi.MemberDefinition.SetIsAssigned ();
|
|
} else {
|
|
var fi = ((FieldExpr) member).Spec;
|
|
|
|
if (fi.IsReadOnly || fi.IsStatic || !fi.IsPublic) {
|
|
Error_InvalidNamedArgument (ec, a);
|
|
return false;
|
|
}
|
|
|
|
if (!IsValidArgumentType (member.Type)) {
|
|
ec.Report.SymbolRelatedToPreviousError (fi);
|
|
Error_InvalidNamedArgumentType (ec, a);
|
|
return false;
|
|
}
|
|
|
|
// if (!context.IsObsolete)
|
|
fi.CheckObsoleteness (ec, member.StartLocation);
|
|
|
|
fi.MemberDefinition.SetIsAssigned ();
|
|
}
|
|
|
|
if (a.Type != member.Type) {
|
|
a.Expr = Convert.ImplicitConversionRequired (ec, a.Expr, member.Type, a.Expr.Location);
|
|
}
|
|
|
|
if (a.Expr != null)
|
|
named_values.Add (new KeyValuePair<MemberExpr, NamedArgument> ((MemberExpr) member, a));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a string containing a list of valid targets for the attribute 'attr'
|
|
/// </summary>
|
|
public string GetValidTargets ()
|
|
{
|
|
StringBuilder sb = new StringBuilder ();
|
|
AttributeTargets targets = Type.GetAttributeUsage (context.Module.PredefinedAttributes.AttributeUsage).ValidOn;
|
|
|
|
if ((targets & AttributeTargets.Assembly) != 0)
|
|
sb.Append ("assembly, ");
|
|
|
|
if ((targets & AttributeTargets.Module) != 0)
|
|
sb.Append ("module, ");
|
|
|
|
if ((targets & AttributeTargets.Class) != 0)
|
|
sb.Append ("class, ");
|
|
|
|
if ((targets & AttributeTargets.Struct) != 0)
|
|
sb.Append ("struct, ");
|
|
|
|
if ((targets & AttributeTargets.Enum) != 0)
|
|
sb.Append ("enum, ");
|
|
|
|
if ((targets & AttributeTargets.Constructor) != 0)
|
|
sb.Append ("constructor, ");
|
|
|
|
if ((targets & AttributeTargets.Method) != 0)
|
|
sb.Append ("method, ");
|
|
|
|
if ((targets & AttributeTargets.Property) != 0)
|
|
sb.Append ("property, indexer, ");
|
|
|
|
if ((targets & AttributeTargets.Field) != 0)
|
|
sb.Append ("field, ");
|
|
|
|
if ((targets & AttributeTargets.Event) != 0)
|
|
sb.Append ("event, ");
|
|
|
|
if ((targets & AttributeTargets.Interface) != 0)
|
|
sb.Append ("interface, ");
|
|
|
|
if ((targets & AttributeTargets.Parameter) != 0)
|
|
sb.Append ("parameter, ");
|
|
|
|
if ((targets & AttributeTargets.Delegate) != 0)
|
|
sb.Append ("delegate, ");
|
|
|
|
if ((targets & AttributeTargets.ReturnValue) != 0)
|
|
sb.Append ("return, ");
|
|
|
|
if ((targets & AttributeTargets.GenericParameter) != 0)
|
|
sb.Append ("type parameter, ");
|
|
|
|
return sb.Remove (sb.Length - 2, 2).ToString ();
|
|
}
|
|
|
|
public AttributeUsageAttribute GetAttributeUsageAttribute ()
|
|
{
|
|
if (!arg_resolved)
|
|
// 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 ();
|
|
|
|
if (resolve_error)
|
|
return DefaultUsageAttribute;
|
|
|
|
AttributeUsageAttribute usage_attribute = new AttributeUsageAttribute ((AttributeTargets) ((Constant) pos_args[0].Expr).GetValue ());
|
|
|
|
var field = GetNamedValue ("AllowMultiple") as BoolConstant;
|
|
if (field != null)
|
|
usage_attribute.AllowMultiple = field.Value;
|
|
|
|
field = GetNamedValue ("Inherited") as BoolConstant;
|
|
if (field != null)
|
|
usage_attribute.Inherited = field.Value;
|
|
|
|
return usage_attribute;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns custom name of indexer
|
|
/// </summary>
|
|
public string GetIndexerAttributeValue ()
|
|
{
|
|
if (!arg_resolved)
|
|
// 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 ();
|
|
|
|
if (resolve_error || pos_args.Count != 1 || !(pos_args[0].Expr is Constant))
|
|
return null;
|
|
|
|
return ((Constant) pos_args[0].Expr).GetValue () as string;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns condition of ConditionalAttribute
|
|
/// </summary>
|
|
public string GetConditionalAttributeValue ()
|
|
{
|
|
if (!arg_resolved)
|
|
// 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 ();
|
|
|
|
if (resolve_error)
|
|
return null;
|
|
|
|
return ((Constant) pos_args[0].Expr).GetValue () as string;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the instance of ObsoleteAttribute from this attribute instance
|
|
/// </summary>
|
|
public ObsoleteAttribute GetObsoleteAttribute ()
|
|
{
|
|
if (!arg_resolved) {
|
|
// corlib only case when obsolete is used before is resolved
|
|
var c = Type.MemberDefinition as Class;
|
|
if (c != null && !c.HasMembersDefined)
|
|
c.Define ();
|
|
|
|
// 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 ();
|
|
}
|
|
|
|
if (resolve_error)
|
|
return null;
|
|
|
|
if (pos_args == null)
|
|
return new ObsoleteAttribute ();
|
|
|
|
string msg = ((Constant) pos_args[0].Expr).GetValue () as string;
|
|
if (pos_args.Count == 1)
|
|
return new ObsoleteAttribute (msg);
|
|
|
|
return new ObsoleteAttribute (msg, ((BoolConstant) pos_args[1].Expr).Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
|
|
/// before ApplyAttribute. We need to resolve the arguments.
|
|
/// This situation occurs when class deps is differs from Emit order.
|
|
/// </summary>
|
|
public bool GetClsCompliantAttributeValue ()
|
|
{
|
|
if (!arg_resolved)
|
|
// 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 ();
|
|
|
|
if (resolve_error)
|
|
return false;
|
|
|
|
return ((BoolConstant) pos_args[0].Expr).Value;
|
|
}
|
|
|
|
public TypeSpec GetAsyncMethodBuilderValue ()
|
|
{
|
|
if (!arg_resolved)
|
|
Resolve ();
|
|
|
|
if (resolve_error)
|
|
return null;
|
|
|
|
return GetArgumentType ();
|
|
}
|
|
|
|
public TypeSpec GetCoClassAttributeValue ()
|
|
{
|
|
if (!arg_resolved)
|
|
Resolve ();
|
|
|
|
if (resolve_error)
|
|
return null;
|
|
|
|
return GetArgumentType ();
|
|
}
|
|
|
|
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 (Array.Exists (valid_targets, i => i == 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;
|
|
case "module": Target = AttributeTargets.Module; 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.Warning (657, 1, Location,
|
|
"`{0}' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are `{1}'. All attributes in this section will be ignored",
|
|
ExplicitTarget, sb.ToString ());
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests permitted SecurityAction for assembly or other types
|
|
/// </summary>
|
|
bool IsSecurityActionValid ()
|
|
{
|
|
Constant c = null;
|
|
var action = GetSecurityActionValue (ref c);
|
|
bool for_assembly = Target == AttributeTargets.Assembly || Target == AttributeTargets.Module;
|
|
|
|
switch (action) {
|
|
#pragma warning disable 618
|
|
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;
|
|
#pragma warning restore 618
|
|
case null:
|
|
Report.Error (7048, loc, "First argument of a security attribute `{0}' must be a valid SecurityAction",
|
|
Type.GetSignatureForError ());
|
|
return false;
|
|
|
|
default:
|
|
Report.Error (7049, c.Location, "Security attribute `{0}' has an invalid SecurityAction value `{1}'",
|
|
Type.GetSignatureForError (), c.GetValueAsLiteral());
|
|
return false;
|
|
}
|
|
|
|
switch (Target) {
|
|
case AttributeTargets.Assembly:
|
|
Report.Error (7050, c.Location, "SecurityAction value `{0}' is invalid for security attributes applied to an assembly",
|
|
c.GetSignatureForError ());
|
|
break;
|
|
default:
|
|
Report.Error (7051, c.Location, "SecurityAction value `{0}' is invalid for security attributes applied to a type or a method",
|
|
c.GetSignatureForError ());
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
SecurityAction? GetSecurityActionValue (ref Constant value)
|
|
{
|
|
if (pos_args == null) {
|
|
var predefined = context.Module.PredefinedAttributes;
|
|
|
|
//
|
|
// BCL defines System.Security.Permissions.HostProtectionAttribute with parameterless
|
|
// contructor which should not be valid but it's already part of the framework
|
|
//
|
|
if (Type == predefined.HostProtection.TypeSpec) {
|
|
value = new IntConstant (context.Module.Compiler.BuiltinTypes, (int)SecurityAction.LinkDemand, loc);
|
|
return SecurityAction.LinkDemand;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
value = (Constant) pos_args [0].Expr;
|
|
return (SecurityAction) value.GetValue ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public void ExtractSecurityPermissionSet (MethodSpec ctor, ref SecurityType permissions)
|
|
{
|
|
#if STATIC
|
|
object[] values;
|
|
if (pos_args != null) {
|
|
values = new object[pos_args.Count];
|
|
for (int i = 0; i < values.Length; ++i)
|
|
values[i] = ((Constant) pos_args[i].Expr).GetValue ();
|
|
} else {
|
|
values = null;
|
|
}
|
|
|
|
PropertyInfo[] prop;
|
|
object[] prop_values;
|
|
if (named_values == null) {
|
|
prop = null;
|
|
prop_values = null;
|
|
} else {
|
|
prop = new PropertyInfo[named_values.Count];
|
|
prop_values = new object [named_values.Count];
|
|
for (int i = 0; i < prop.Length; ++i) {
|
|
prop [i] = ((PropertyExpr) named_values [i].Key).PropertyInfo.MetaInfo;
|
|
prop_values [i] = ((Constant) named_values [i].Value.Expr).GetValue ();
|
|
}
|
|
}
|
|
|
|
if (permissions == null)
|
|
permissions = new SecurityType ();
|
|
|
|
var cab = new CustomAttributeBuilder ((ConstructorInfo) ctor.GetMetaInfo (), values, prop, prop_values);
|
|
permissions.Add (cab);
|
|
#else
|
|
throw new NotSupportedException ();
|
|
#endif
|
|
}
|
|
|
|
public Constant GetNamedValue (string name)
|
|
{
|
|
if (named_values == null)
|
|
return null;
|
|
|
|
for (int i = 0; i < named_values.Count; ++i) {
|
|
if (named_values [i].Value.Name == name)
|
|
return named_values [i].Value.Expr as Constant;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public CharSet GetCharSetValue ()
|
|
{
|
|
return (CharSet) System.Enum.Parse (typeof (CharSet), ((Constant) pos_args[0].Expr).GetValue ().ToString ());
|
|
}
|
|
|
|
public bool HasField (string fieldName)
|
|
{
|
|
if (named_values == null)
|
|
return false;
|
|
|
|
foreach (var na in named_values) {
|
|
if (na.Value.Name == fieldName)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Returns true for MethodImplAttribute with MethodImplOptions.InternalCall value
|
|
//
|
|
public bool IsInternalCall ()
|
|
{
|
|
return (GetMethodImplOptions () & MethodImplOptions.InternalCall) != 0;
|
|
}
|
|
|
|
public MethodImplOptions GetMethodImplOptions ()
|
|
{
|
|
MethodImplOptions options = 0;
|
|
if (pos_args.Count == 1) {
|
|
options = (MethodImplOptions) System.Enum.Parse (typeof (MethodImplOptions), ((Constant) pos_args[0].Expr).GetValue ().ToString ());
|
|
} else if (HasField ("Value")) {
|
|
var named = GetNamedValue ("Value");
|
|
options = (MethodImplOptions) System.Enum.Parse (typeof (MethodImplOptions), named.GetValue ().ToString ());
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
//
|
|
// Returns true for StructLayoutAttribute with LayoutKind.Explicit value
|
|
//
|
|
public bool IsExplicitLayoutKind ()
|
|
{
|
|
if (pos_args == null || pos_args.Count != 1)
|
|
return false;
|
|
|
|
var value = (LayoutKind) System.Enum.Parse (typeof (LayoutKind), ((Constant) pos_args[0].Expr).GetValue ().ToString ());
|
|
return value == LayoutKind.Explicit;
|
|
}
|
|
|
|
public Expression GetParameterDefaultValue ()
|
|
{
|
|
if (pos_args == null)
|
|
return null;
|
|
|
|
return pos_args[0].Expr;
|
|
}
|
|
|
|
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 Type.GetHashCode () ^ Target.GetHashCode ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Emit attribute for Attributable symbol
|
|
/// </summary>
|
|
public void Emit (Dictionary<Attribute, List<Attribute>> allEmitted)
|
|
{
|
|
var ctor = Resolve ();
|
|
if (ctor == null)
|
|
return;
|
|
|
|
var predefined = context.Module.PredefinedAttributes;
|
|
|
|
AttributeUsageAttribute usage_attr = Type.GetAttributeUsage (predefined.AttributeUsage);
|
|
if ((usage_attr.ValidOn & Target) == 0) {
|
|
Report.Error (592, Location, "The attribute `{0}' is not valid on this declaration type. " +
|
|
"It is valid on `{1}' declarations only",
|
|
GetSignatureForError (), GetValidTargets ());
|
|
return;
|
|
}
|
|
|
|
byte[] cdata;
|
|
List<Assembly> references;
|
|
if (pos_args == null && named_values == null) {
|
|
cdata = AttributeEncoder.Empty;
|
|
references = null;
|
|
} else {
|
|
AttributeEncoder encoder = new AttributeEncoder ();
|
|
|
|
if (pos_args != null) {
|
|
var param_types = ctor.Parameters.Types;
|
|
for (int j = 0; j < pos_args.Count; ++j) {
|
|
var pt = param_types[j];
|
|
var arg_expr = pos_args[j].Expr;
|
|
if (j == 0) {
|
|
if ((Type == predefined.IndexerName || Type == predefined.Conditional) && arg_expr is Constant) {
|
|
string v = ((Constant) arg_expr).GetValue () as string;
|
|
if (!Tokenizer.IsValidIdentifier (v) || (Type == predefined.IndexerName && Tokenizer.IsKeyword (v))) {
|
|
context.Module.Compiler.Report.Error (633, arg_expr.Location,
|
|
"The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
|
|
return;
|
|
}
|
|
} else if (Type == predefined.Guid) {
|
|
string v = ((StringConstant) arg_expr).Value;
|
|
try {
|
|
new Guid (v);
|
|
} catch {
|
|
Error_InvalidArgumentValue (Type);
|
|
return;
|
|
}
|
|
} else if (Type == predefined.AttributeUsage) {
|
|
int v = ((IntConstant) ((EnumConstant) arg_expr).Child).Value;
|
|
if (v == 0)
|
|
Error_InvalidArgumentValue (Type);
|
|
} else if (Type == predefined.MarshalAs) {
|
|
if (pos_args.Count == 1) {
|
|
var u_type = (UnmanagedType) System.Enum.Parse (typeof (UnmanagedType), ((Constant) pos_args[0].Expr).GetValue ().ToString ());
|
|
if (u_type == UnmanagedType.ByValArray && !(Owner is FieldBase)) {
|
|
Report.Error (7055, pos_args [0].Expr.Location, "Unmanaged type `ByValArray' is only valid for fields");
|
|
}
|
|
}
|
|
} else if (Type == predefined.DllImport) {
|
|
if (pos_args.Count == 1 && pos_args[0].Expr is Constant) {
|
|
var value = ((Constant) pos_args[0].Expr).GetValue () as string;
|
|
if (string.IsNullOrEmpty (value))
|
|
Error_InvalidArgumentValue (Type);
|
|
}
|
|
} else if (Type == predefined.MethodImpl) {
|
|
if (pos_args.Count == 1) {
|
|
var value = (int) ((Constant) arg_expr).GetValueAsLong ();
|
|
|
|
if (!IsValidMethodImplOption (value)) {
|
|
Error_InvalidArgumentValue (Type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
arg_expr.EncodeAttributeValue (context, encoder, pt, pt);
|
|
}
|
|
}
|
|
|
|
if (named_values != null) {
|
|
encoder.Encode ((ushort) named_values.Count);
|
|
foreach (var na in named_values) {
|
|
if (na.Key is FieldExpr)
|
|
encoder.Encode ((byte) 0x53);
|
|
else
|
|
encoder.Encode ((byte) 0x54);
|
|
|
|
encoder.Encode (na.Key.Type);
|
|
encoder.Encode (na.Value.Name);
|
|
na.Value.Expr.EncodeAttributeValue (context, encoder, na.Key.Type, na.Key.Type);
|
|
}
|
|
} else {
|
|
encoder.EncodeEmptyNamedArguments ();
|
|
}
|
|
|
|
cdata = encoder.ToArray (out references);
|
|
}
|
|
|
|
if (!IsConditionallyExcluded (ctor.DeclaringType)) {
|
|
if (Type == predefined.TupleElementNames) {
|
|
Error_MisusedTupleAttribute ();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
foreach (Attributable target in targets)
|
|
target.ApplyAttributeBuilder (this, ctor, cdata, predefined);
|
|
} catch (Exception e) {
|
|
if (e is BadImageFormat && Report.Errors > 0)
|
|
return;
|
|
|
|
Error_AttributeEmitError (e.Message);
|
|
return;
|
|
}
|
|
|
|
context.Module.AddAssemblyReferences (references);
|
|
}
|
|
|
|
if (!usage_attr.AllowMultiple && allEmitted != null) {
|
|
if (allEmitted.ContainsKey (this)) {
|
|
var a = allEmitted [this];
|
|
if (a == null) {
|
|
a = new List<Attribute> (2);
|
|
allEmitted [this] = a;
|
|
}
|
|
a.Add (this);
|
|
} else {
|
|
allEmitted.Add (this, null);
|
|
}
|
|
}
|
|
|
|
if (!context.Module.Compiler.Settings.VerifyClsCompliance)
|
|
return;
|
|
|
|
// Here we are testing attribute arguments for array usage (error 3016)
|
|
if (Owner.IsClsComplianceRequired ()) {
|
|
if (pos_args != null)
|
|
pos_args.CheckArrayAsAttribute (context.Module.Compiler);
|
|
|
|
if (NamedArguments == null)
|
|
return;
|
|
|
|
NamedArguments.CheckArrayAsAttribute (context.Module.Compiler);
|
|
}
|
|
}
|
|
|
|
bool IsConditionallyExcluded (TypeSpec type)
|
|
{
|
|
do {
|
|
if (type.IsConditionallyExcluded (context))
|
|
return true;
|
|
|
|
type = type.BaseType;
|
|
} while (type != null);
|
|
|
|
return false;
|
|
}
|
|
|
|
private Expression GetValue ()
|
|
{
|
|
if (pos_args == null || pos_args.Count < 1)
|
|
return null;
|
|
|
|
return pos_args[0].Expr;
|
|
}
|
|
|
|
public string GetString ()
|
|
{
|
|
Expression e = GetValue ();
|
|
if (e is StringConstant)
|
|
return ((StringConstant)e).Value;
|
|
return null;
|
|
}
|
|
|
|
public bool GetBoolean ()
|
|
{
|
|
Expression e = GetValue ();
|
|
if (e is BoolConstant)
|
|
return ((BoolConstant)e).Value;
|
|
return false;
|
|
}
|
|
|
|
public TypeSpec GetArgumentType ()
|
|
{
|
|
TypeOf e = GetValue () as TypeOf;
|
|
if (e == null)
|
|
return null;
|
|
return e.TypeArgument;
|
|
}
|
|
}
|
|
|
|
public class Attributes
|
|
{
|
|
public readonly List<Attribute> Attrs;
|
|
|
|
public Attributes (Attribute a)
|
|
{
|
|
Attrs = new List<Attribute> ();
|
|
Attrs.Add (a);
|
|
}
|
|
|
|
public Attributes (List<Attribute> attrs)
|
|
{
|
|
Attrs = attrs ?? new List<Attribute> ();
|
|
}
|
|
|
|
public void AddAttribute (Attribute attr)
|
|
{
|
|
Attrs.Add (attr);
|
|
}
|
|
|
|
public void AddAttributes (List<Attribute> attrs)
|
|
{
|
|
Attrs.AddRange (attrs);
|
|
}
|
|
|
|
public static void AttachFromPartial (Attributable target, Attributable partialSrc)
|
|
{
|
|
if (target.OptAttributes == null) {
|
|
target.OptAttributes = partialSrc.OptAttributes;
|
|
} else {
|
|
target.OptAttributes.Attrs.AddRange (partialSrc.OptAttributes.Attrs);
|
|
}
|
|
|
|
foreach (var attr in partialSrc.OptAttributes.Attrs) {
|
|
attr.SetOwner (target);
|
|
}
|
|
}
|
|
|
|
public void AttachTo (Attributable attributable, IMemberContext context)
|
|
{
|
|
foreach (Attribute a in Attrs)
|
|
a.AttachTo (attributable, context);
|
|
}
|
|
|
|
public Attributes Clone ()
|
|
{
|
|
var al = new List<Attribute> (Attrs.Count);
|
|
foreach (Attribute a in Attrs)
|
|
al.Add (a.Clone ());
|
|
|
|
return new Attributes (al);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether attribute target is valid for the current element
|
|
/// </summary>
|
|
public bool CheckTargets ()
|
|
{
|
|
for (int i = 0; i < Attrs.Count; ++i) {
|
|
if (!Attrs [i].CheckTarget ())
|
|
Attrs.RemoveAt (i--);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public void ConvertGlobalAttributes (TypeContainer member, NamespaceContainer currentNamespace, bool isGlobal)
|
|
{
|
|
var member_explicit_targets = member.ValidAttributeTargets;
|
|
for (int i = 0; i < Attrs.Count; ++i) {
|
|
var attr = Attrs[0];
|
|
if (attr.ExplicitTarget == null)
|
|
continue;
|
|
|
|
int ii;
|
|
for (ii = 0; ii < member_explicit_targets.Length; ++ii) {
|
|
if (attr.ExplicitTarget == member_explicit_targets[ii]) {
|
|
ii = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ii < 0 || !isGlobal)
|
|
continue;
|
|
|
|
member.Module.AddAttribute (attr, currentNamespace);
|
|
Attrs.RemoveAt (i);
|
|
--i;
|
|
}
|
|
}
|
|
|
|
public bool HasResolveError()
|
|
{
|
|
foreach (var a in Attrs) {
|
|
if (a.ResolveError)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public Attribute Search (PredefinedAttribute t)
|
|
{
|
|
return Search (null, t);
|
|
}
|
|
|
|
public Attribute Search (string explicitTarget, PredefinedAttribute t)
|
|
{
|
|
foreach (Attribute a in Attrs) {
|
|
if (explicitTarget != null && a.ExplicitTarget != explicitTarget)
|
|
continue;
|
|
|
|
if (a.ResolveTypeForComparison () == t)
|
|
return a;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
|
|
/// </summary>
|
|
public Attribute[] SearchMulti (PredefinedAttribute t)
|
|
{
|
|
List<Attribute> ar = null;
|
|
|
|
foreach (Attribute a in Attrs) {
|
|
if (a.ResolveTypeForComparison () == t) {
|
|
if (ar == null)
|
|
ar = new List<Attribute> (Attrs.Count);
|
|
ar.Add (a);
|
|
}
|
|
}
|
|
|
|
return ar == null ? null : ar.ToArray ();
|
|
}
|
|
|
|
public void Emit ()
|
|
{
|
|
CheckTargets ();
|
|
|
|
Dictionary<Attribute, List<Attribute>> ld = Attrs.Count > 1 ? new Dictionary<Attribute, List<Attribute>> () : null;
|
|
|
|
foreach (Attribute a in Attrs)
|
|
a.Emit (ld);
|
|
|
|
if (ld == null || ld.Count == 0)
|
|
return;
|
|
|
|
foreach (var d in ld) {
|
|
if (d.Value == null)
|
|
continue;
|
|
|
|
Attribute a = d.Key;
|
|
|
|
foreach (Attribute collision in d.Value)
|
|
a.Report.SymbolRelatedToPreviousError (collision.Location, "");
|
|
|
|
a.Report.Error (579, a.Location, "The attribute `{0}' cannot be applied multiple times",
|
|
a.GetSignatureForError ());
|
|
}
|
|
}
|
|
|
|
public bool Contains (PredefinedAttribute t)
|
|
{
|
|
return Search (t) != null;
|
|
}
|
|
}
|
|
|
|
public sealed class AttributeEncoder
|
|
{
|
|
[Flags]
|
|
public enum EncodedTypeProperties
|
|
{
|
|
None = 0,
|
|
DynamicType = 1,
|
|
TypeParameter = 1 << 1
|
|
}
|
|
|
|
public static readonly byte[] Empty;
|
|
|
|
byte[] buffer;
|
|
int pos;
|
|
const ushort Version = 1;
|
|
List<Assembly> imports;
|
|
|
|
static AttributeEncoder ()
|
|
{
|
|
Empty = new byte[4];
|
|
Empty[0] = (byte) Version;
|
|
}
|
|
|
|
public AttributeEncoder ()
|
|
{
|
|
buffer = new byte[32];
|
|
Encode (Version);
|
|
}
|
|
|
|
public void Encode (bool value)
|
|
{
|
|
Encode (value ? (byte) 1 : (byte) 0);
|
|
}
|
|
|
|
public void Encode (byte value)
|
|
{
|
|
if (pos == buffer.Length)
|
|
Grow (1);
|
|
|
|
buffer [pos++] = value;
|
|
}
|
|
|
|
public void Encode (sbyte value)
|
|
{
|
|
Encode ((byte) value);
|
|
}
|
|
|
|
public void Encode (short value)
|
|
{
|
|
if (pos + 2 > buffer.Length)
|
|
Grow (2);
|
|
|
|
buffer[pos++] = (byte) value;
|
|
buffer[pos++] = (byte) (value >> 8);
|
|
}
|
|
|
|
public void Encode (ushort value)
|
|
{
|
|
Encode ((short) value);
|
|
}
|
|
|
|
public void Encode (int value)
|
|
{
|
|
if (pos + 4 > buffer.Length)
|
|
Grow (4);
|
|
|
|
buffer[pos++] = (byte) value;
|
|
buffer[pos++] = (byte) (value >> 8);
|
|
buffer[pos++] = (byte) (value >> 16);
|
|
buffer[pos++] = (byte) (value >> 24);
|
|
}
|
|
|
|
public void Encode (uint value)
|
|
{
|
|
Encode ((int) value);
|
|
}
|
|
|
|
public void Encode (long value)
|
|
{
|
|
if (pos + 8 > buffer.Length)
|
|
Grow (8);
|
|
|
|
buffer[pos++] = (byte) value;
|
|
buffer[pos++] = (byte) (value >> 8);
|
|
buffer[pos++] = (byte) (value >> 16);
|
|
buffer[pos++] = (byte) (value >> 24);
|
|
buffer[pos++] = (byte) (value >> 32);
|
|
buffer[pos++] = (byte) (value >> 40);
|
|
buffer[pos++] = (byte) (value >> 48);
|
|
buffer[pos++] = (byte) (value >> 56);
|
|
}
|
|
|
|
public void Encode (ulong value)
|
|
{
|
|
Encode ((long) value);
|
|
}
|
|
|
|
public void Encode (float value)
|
|
{
|
|
Encode (SingleConverter.SingleToInt32Bits (value));
|
|
}
|
|
|
|
public void Encode (double value)
|
|
{
|
|
Encode (BitConverter.DoubleToInt64Bits (value));
|
|
}
|
|
|
|
public void Encode (string value)
|
|
{
|
|
if (value == null) {
|
|
Encode ((byte) 0xFF);
|
|
return;
|
|
}
|
|
|
|
var buf = Encoding.UTF8.GetBytes(value);
|
|
WriteCompressedValue (buf.Length);
|
|
|
|
if (pos + buf.Length > buffer.Length)
|
|
Grow (buf.Length);
|
|
|
|
Buffer.BlockCopy (buf, 0, buffer, pos, buf.Length);
|
|
pos += buf.Length;
|
|
}
|
|
|
|
public EncodedTypeProperties Encode (TypeSpec type)
|
|
{
|
|
switch (type.BuiltinType) {
|
|
case BuiltinTypeSpec.Type.Bool:
|
|
Encode ((byte) 0x02);
|
|
break;
|
|
case BuiltinTypeSpec.Type.Char:
|
|
Encode ((byte) 0x03);
|
|
break;
|
|
case BuiltinTypeSpec.Type.SByte:
|
|
Encode ((byte) 0x04);
|
|
break;
|
|
case BuiltinTypeSpec.Type.Byte:
|
|
Encode ((byte) 0x05);
|
|
break;
|
|
case BuiltinTypeSpec.Type.Short:
|
|
Encode ((byte) 0x06);
|
|
break;
|
|
case BuiltinTypeSpec.Type.UShort:
|
|
Encode ((byte) 0x07);
|
|
break;
|
|
case BuiltinTypeSpec.Type.Int:
|
|
Encode ((byte) 0x08);
|
|
break;
|
|
case BuiltinTypeSpec.Type.UInt:
|
|
Encode ((byte) 0x09);
|
|
break;
|
|
case BuiltinTypeSpec.Type.Long:
|
|
Encode ((byte) 0x0A);
|
|
break;
|
|
case BuiltinTypeSpec.Type.ULong:
|
|
Encode ((byte) 0x0B);
|
|
break;
|
|
case BuiltinTypeSpec.Type.Float:
|
|
Encode ((byte) 0x0C);
|
|
break;
|
|
case BuiltinTypeSpec.Type.Double:
|
|
Encode ((byte) 0x0D);
|
|
break;
|
|
case BuiltinTypeSpec.Type.String:
|
|
Encode ((byte) 0x0E);
|
|
break;
|
|
case BuiltinTypeSpec.Type.Type:
|
|
Encode ((byte) 0x50);
|
|
break;
|
|
case BuiltinTypeSpec.Type.Object:
|
|
Encode ((byte) 0x51);
|
|
break;
|
|
case BuiltinTypeSpec.Type.Dynamic:
|
|
Encode ((byte) 0x51);
|
|
return EncodedTypeProperties.DynamicType;
|
|
default:
|
|
if (type.IsArray) {
|
|
Encode ((byte) 0x1D);
|
|
return Encode (TypeManager.GetElementType (type));
|
|
}
|
|
|
|
if (type.Kind == MemberKind.Enum) {
|
|
Encode ((byte) 0x55);
|
|
EncodeTypeName (type);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return EncodedTypeProperties.None;
|
|
}
|
|
|
|
public void EncodeTypeName (TypeSpec type)
|
|
{
|
|
var old_type = type.GetMetaInfo ();
|
|
if (type.MemberDefinition.IsImported) {
|
|
if (imports == null)
|
|
imports = new List<Assembly> ();
|
|
|
|
imports.Add (old_type.Assembly);
|
|
Encode (old_type.AssemblyQualifiedName);
|
|
} else {
|
|
Encode (old_type.FullName);
|
|
}
|
|
}
|
|
|
|
public void EncodeTypeName (TypeContainer type)
|
|
{
|
|
Encode (type.GetSignatureForMetadata ());
|
|
}
|
|
|
|
|
|
//
|
|
// Encodes single property named argument per call
|
|
//
|
|
public void EncodeNamedPropertyArgument (PropertySpec property, Constant value)
|
|
{
|
|
Encode ((ushort) 1); // length
|
|
Encode ((byte) 0x54); // property
|
|
Encode (property.MemberType);
|
|
Encode (property.Name);
|
|
value.EncodeAttributeValue (null, this, property.MemberType, property.MemberType);
|
|
}
|
|
|
|
//
|
|
// Encodes single field named argument per call
|
|
//
|
|
public void EncodeNamedFieldArgument (FieldSpec field, Constant value)
|
|
{
|
|
Encode ((ushort) 1); // length
|
|
Encode ((byte) 0x53); // field
|
|
Encode (field.MemberType);
|
|
Encode (field.Name);
|
|
value.EncodeAttributeValue (null, this, field.MemberType, field.MemberType);
|
|
}
|
|
|
|
public void EncodeNamedArguments<T> (T[] members, Constant[] values) where T : MemberSpec, IInterfaceMemberSpec
|
|
{
|
|
Encode ((ushort) members.Length);
|
|
|
|
for (int i = 0; i < members.Length; ++i)
|
|
{
|
|
var member = members[i];
|
|
|
|
if (member.Kind == MemberKind.Field)
|
|
Encode ((byte) 0x53);
|
|
else if (member.Kind == MemberKind.Property)
|
|
Encode ((byte) 0x54);
|
|
else
|
|
throw new NotImplementedException (member.Kind.ToString ());
|
|
|
|
Encode (member.MemberType);
|
|
Encode (member.Name);
|
|
values [i].EncodeAttributeValue (null, this, member.MemberType, member.MemberType);
|
|
}
|
|
}
|
|
|
|
public void EncodeEmptyNamedArguments ()
|
|
{
|
|
Encode ((ushort) 0);
|
|
}
|
|
|
|
void Grow (int inc)
|
|
{
|
|
int size = System.Math.Max (pos * 4, pos + inc + 2);
|
|
Array.Resize (ref buffer, size);
|
|
}
|
|
|
|
void WriteCompressedValue (int value)
|
|
{
|
|
if (value < 0x80) {
|
|
Encode ((byte) value);
|
|
return;
|
|
}
|
|
|
|
if (value < 0x4000) {
|
|
Encode ((byte) (0x80 | (value >> 8)));
|
|
Encode ((byte) value);
|
|
return;
|
|
}
|
|
|
|
Encode (value);
|
|
}
|
|
|
|
public byte[] ToArray (out List<Assembly> assemblyReferences)
|
|
{
|
|
assemblyReferences = imports;
|
|
|
|
byte[] buf = new byte[pos];
|
|
Array.Copy (buffer, buf, pos);
|
|
return buf;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Helper class for attribute verification routine.
|
|
/// </summary>
|
|
static class AttributeTester
|
|
{
|
|
/// <summary>
|
|
/// Common method for Obsolete error/warning reporting.
|
|
/// </summary>
|
|
public static void Report_ObsoleteMessage (ObsoleteAttribute oa, string member, Location loc, Report Report)
|
|
{
|
|
if (oa.IsError) {
|
|
Report.Error (619, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
|
|
return;
|
|
}
|
|
|
|
if (oa.Message == null || oa.Message.Length == 0) {
|
|
Report.Warning (612, 1, loc, "`{0}' is obsolete", member);
|
|
return;
|
|
}
|
|
Report.Warning (618, 2, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Predefined attribute types
|
|
//
|
|
public class PredefinedAttributes
|
|
{
|
|
// Build-in attributes
|
|
public readonly PredefinedAttribute ParamArray;
|
|
public readonly PredefinedAttribute Out;
|
|
|
|
// Optional attributes
|
|
public readonly PredefinedAttribute Obsolete;
|
|
public readonly PredefinedAttribute DllImport;
|
|
public readonly PredefinedAttribute MethodImpl;
|
|
public readonly PredefinedAttribute MarshalAs;
|
|
public readonly PredefinedAttribute In;
|
|
public readonly PredefinedAttribute IndexerName;
|
|
public readonly PredefinedAttribute Conditional;
|
|
public readonly PredefinedAttribute CLSCompliant;
|
|
public readonly PredefinedAttribute Security;
|
|
public readonly PredefinedAttribute Required;
|
|
public readonly PredefinedAttribute Guid;
|
|
public readonly PredefinedAttribute AssemblyCulture;
|
|
public readonly PredefinedAttribute AssemblyVersion;
|
|
public readonly PredefinedAttribute AssemblyAlgorithmId;
|
|
public readonly PredefinedAttribute AssemblyFlags;
|
|
public readonly PredefinedAttribute AssemblyFileVersion;
|
|
public readonly PredefinedAttribute AssemblyInformationalVersion;
|
|
public readonly PredefinedAttribute ComImport;
|
|
public readonly PredefinedAttribute CoClass;
|
|
public readonly PredefinedAttribute AttributeUsage;
|
|
public readonly PredefinedAttribute DefaultParameterValue;
|
|
public readonly PredefinedAttribute OptionalParameter;
|
|
public readonly PredefinedAttribute UnverifiableCode;
|
|
public readonly PredefinedAttribute DefaultCharset;
|
|
public readonly PredefinedAttribute TypeForwarder;
|
|
public readonly PredefinedAttribute FixedBuffer;
|
|
public readonly PredefinedAttribute CompilerGenerated;
|
|
public readonly PredefinedAttribute InternalsVisibleTo;
|
|
public readonly PredefinedAttribute RuntimeCompatibility;
|
|
public readonly PredefinedAttribute DebuggerHidden;
|
|
public readonly PredefinedAttribute UnsafeValueType;
|
|
public readonly PredefinedAttribute UnmanagedFunctionPointer;
|
|
public readonly PredefinedDebuggerBrowsableAttribute DebuggerBrowsable;
|
|
public readonly PredefinedAttribute DebuggerStepThrough;
|
|
public readonly PredefinedDebuggableAttribute Debuggable;
|
|
public readonly PredefinedAttribute HostProtection;
|
|
|
|
// New in .NET 3.5
|
|
public readonly PredefinedAttribute Extension;
|
|
|
|
// New in .NET 4.0
|
|
public readonly PredefinedDynamicAttribute Dynamic;
|
|
|
|
// New in .NET 4.5
|
|
public readonly PredefinedStateMachineAttribute AsyncStateMachine;
|
|
|
|
// New in .NET 4.7
|
|
public readonly PredefinedTupleElementNamesAttribute TupleElementNames;
|
|
public readonly PredefinedAttribute AsyncMethodBuilder;
|
|
|
|
// New in .NET 4.7.1
|
|
public readonly PredefinedAttribute IsReadOnly;
|
|
public readonly PredefinedAttribute IsByRefLike;
|
|
|
|
//
|
|
// Optional types which are used as types and for member lookup
|
|
//
|
|
public readonly PredefinedAttribute DefaultMember;
|
|
public readonly PredefinedDecimalAttribute DecimalConstant;
|
|
public readonly PredefinedAttribute StructLayout;
|
|
public readonly PredefinedAttribute FieldOffset;
|
|
public readonly PredefinedAttribute AssemblyProduct;
|
|
public readonly PredefinedAttribute AssemblyCompany;
|
|
public readonly PredefinedAttribute AssemblyCopyright;
|
|
public readonly PredefinedAttribute AssemblyTrademark;
|
|
public readonly PredefinedAttribute CallerMemberNameAttribute;
|
|
public readonly PredefinedAttribute CallerLineNumberAttribute;
|
|
public readonly PredefinedAttribute CallerFilePathAttribute;
|
|
|
|
public PredefinedAttributes (ModuleContainer module)
|
|
{
|
|
ParamArray = new PredefinedAttribute (module, "System", "ParamArrayAttribute");
|
|
Out = new PredefinedAttribute (module, "System.Runtime.InteropServices", "OutAttribute");
|
|
ParamArray.Resolve ();
|
|
Out.Resolve ();
|
|
|
|
Obsolete = new PredefinedAttribute (module, "System", "ObsoleteAttribute");
|
|
DllImport = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DllImportAttribute");
|
|
MethodImpl = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "MethodImplAttribute");
|
|
MarshalAs = new PredefinedAttribute (module, "System.Runtime.InteropServices", "MarshalAsAttribute");
|
|
In = new PredefinedAttribute (module, "System.Runtime.InteropServices", "InAttribute");
|
|
IndexerName = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "IndexerNameAttribute");
|
|
Conditional = new PredefinedAttribute (module, "System.Diagnostics", "ConditionalAttribute");
|
|
CLSCompliant = new PredefinedAttribute (module, "System", "CLSCompliantAttribute");
|
|
Security = new PredefinedAttribute (module, "System.Security.Permissions", "SecurityAttribute");
|
|
Required = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "RequiredAttributeAttribute");
|
|
Guid = new PredefinedAttribute (module, "System.Runtime.InteropServices", "GuidAttribute");
|
|
AssemblyCulture = new PredefinedAttribute (module, "System.Reflection", "AssemblyCultureAttribute");
|
|
AssemblyVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyVersionAttribute");
|
|
AssemblyAlgorithmId = new PredefinedAttribute (module, "System.Reflection", "AssemblyAlgorithmIdAttribute");
|
|
AssemblyFlags = new PredefinedAttribute (module, "System.Reflection", "AssemblyFlagsAttribute");
|
|
AssemblyFileVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyFileVersionAttribute");
|
|
ComImport = new PredefinedAttribute (module, "System.Runtime.InteropServices", "ComImportAttribute");
|
|
CoClass = new PredefinedAttribute (module, "System.Runtime.InteropServices", "CoClassAttribute");
|
|
AttributeUsage = new PredefinedAttribute (module, "System", "AttributeUsageAttribute");
|
|
DefaultParameterValue = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DefaultParameterValueAttribute");
|
|
OptionalParameter = new PredefinedAttribute (module, "System.Runtime.InteropServices", "OptionalAttribute");
|
|
UnverifiableCode = new PredefinedAttribute (module, "System.Security", "UnverifiableCodeAttribute");
|
|
HostProtection = new PredefinedAttribute (module, "System.Security.Permissions", "HostProtectionAttribute");
|
|
|
|
DefaultCharset = new PredefinedAttribute (module, "System.Runtime.InteropServices", "DefaultCharSetAttribute");
|
|
TypeForwarder = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "TypeForwardedToAttribute");
|
|
FixedBuffer = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "FixedBufferAttribute");
|
|
CompilerGenerated = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
|
|
InternalsVisibleTo = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
|
|
RuntimeCompatibility = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
|
|
DebuggerHidden = new PredefinedAttribute (module, "System.Diagnostics", "DebuggerHiddenAttribute");
|
|
UnsafeValueType = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "UnsafeValueTypeAttribute");
|
|
UnmanagedFunctionPointer = new PredefinedAttribute (module, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
|
|
DebuggerBrowsable = new PredefinedDebuggerBrowsableAttribute (module, "System.Diagnostics", "DebuggerBrowsableAttribute");
|
|
DebuggerStepThrough = new PredefinedAttribute (module, "System.Diagnostics", "DebuggerStepThroughAttribute");
|
|
Debuggable = new PredefinedDebuggableAttribute (module, "System.Diagnostics", "DebuggableAttribute");
|
|
|
|
Extension = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "ExtensionAttribute");
|
|
|
|
Dynamic = new PredefinedDynamicAttribute (module, "System.Runtime.CompilerServices", "DynamicAttribute");
|
|
|
|
DefaultMember = new PredefinedAttribute (module, "System.Reflection", "DefaultMemberAttribute");
|
|
DecimalConstant = new PredefinedDecimalAttribute (module, "System.Runtime.CompilerServices", "DecimalConstantAttribute");
|
|
StructLayout = new PredefinedAttribute (module, "System.Runtime.InteropServices", "StructLayoutAttribute");
|
|
FieldOffset = new PredefinedAttribute (module, "System.Runtime.InteropServices", "FieldOffsetAttribute");
|
|
AssemblyProduct = new PredefinedAttribute (module, "System.Reflection", "AssemblyProductAttribute");
|
|
AssemblyCompany = new PredefinedAttribute (module, "System.Reflection", "AssemblyCompanyAttribute");
|
|
AssemblyCopyright = new PredefinedAttribute (module, "System.Reflection", "AssemblyCopyrightAttribute");
|
|
AssemblyTrademark = new PredefinedAttribute (module, "System.Reflection", "AssemblyTrademarkAttribute");
|
|
AssemblyInformationalVersion = new PredefinedAttribute (module, "System.Reflection", "AssemblyInformationalVersionAttribute");
|
|
|
|
AsyncStateMachine = new PredefinedStateMachineAttribute (module, "System.Runtime.CompilerServices", "AsyncStateMachineAttribute");
|
|
|
|
CallerMemberNameAttribute = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CallerMemberNameAttribute");
|
|
CallerLineNumberAttribute = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CallerLineNumberAttribute");
|
|
CallerFilePathAttribute = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CallerFilePathAttribute");
|
|
|
|
AsyncMethodBuilder = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "AsyncMethodBuilderAttribute");
|
|
TupleElementNames = new PredefinedTupleElementNamesAttribute (module, "System.Runtime.CompilerServices", "TupleElementNamesAttribute");
|
|
IsReadOnly = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "IsReadOnlyAttribute");
|
|
IsByRefLike = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "IsByRefLikeAttribute");
|
|
|
|
// TODO: Should define only attributes which are used for comparison
|
|
const System.Reflection.BindingFlags all_fields = System.Reflection.BindingFlags.Public |
|
|
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly;
|
|
|
|
foreach (var fi in GetType ().GetFields (all_fields)) {
|
|
((PredefinedAttribute) fi.GetValue (this)).Define ();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class PredefinedAttribute : PredefinedType
|
|
{
|
|
protected MethodSpec ctor;
|
|
|
|
public PredefinedAttribute (ModuleContainer module, string ns, string name)
|
|
: base (module, MemberKind.Class, ns, name)
|
|
{
|
|
}
|
|
|
|
#region Properties
|
|
|
|
public MethodSpec Constructor {
|
|
get {
|
|
return ctor;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public static bool operator == (TypeSpec type, PredefinedAttribute pa)
|
|
{
|
|
return type == pa.type && pa.type != null;
|
|
}
|
|
|
|
public static bool operator != (TypeSpec type, PredefinedAttribute pa)
|
|
{
|
|
return type != pa.type;
|
|
}
|
|
|
|
public override int GetHashCode ()
|
|
{
|
|
return base.GetHashCode ();
|
|
}
|
|
|
|
public override bool Equals (object obj)
|
|
{
|
|
throw new NotSupportedException ();
|
|
}
|
|
|
|
public void EmitAttribute (ConstructorBuilder builder)
|
|
{
|
|
if (ResolveBuilder ())
|
|
builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
|
|
}
|
|
|
|
public void EmitAttribute (MethodBuilder builder)
|
|
{
|
|
if (ResolveBuilder ())
|
|
builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
|
|
}
|
|
|
|
public void EmitAttribute (PropertyBuilder builder)
|
|
{
|
|
if (ResolveBuilder ())
|
|
builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
|
|
}
|
|
|
|
public void EmitAttribute (FieldBuilder builder)
|
|
{
|
|
if (ResolveBuilder ())
|
|
builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
|
|
}
|
|
|
|
public void EmitAttribute (TypeBuilder builder)
|
|
{
|
|
if (ResolveBuilder ())
|
|
builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
|
|
}
|
|
|
|
public void EmitAttribute (AssemblyBuilder builder)
|
|
{
|
|
if (ResolveBuilder ())
|
|
builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
|
|
}
|
|
|
|
public void EmitAttribute (ModuleBuilder builder)
|
|
{
|
|
if (ResolveBuilder ())
|
|
builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
|
|
}
|
|
|
|
public void EmitAttribute (ParameterBuilder builder)
|
|
{
|
|
if (ResolveBuilder ())
|
|
builder.SetCustomAttribute (GetCtorMetaInfo (), AttributeEncoder.Empty);
|
|
}
|
|
|
|
ConstructorInfo GetCtorMetaInfo ()
|
|
{
|
|
return (ConstructorInfo) ctor.GetMetaInfo ();
|
|
}
|
|
|
|
public bool ResolveBuilder ()
|
|
{
|
|
if (ctor != null)
|
|
return true;
|
|
|
|
//
|
|
// Handle all parameter-less attributes as optional
|
|
//
|
|
if (!Define ())
|
|
return false;
|
|
|
|
ctor = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (ParametersCompiled.EmptyReadOnlyParameters), BindingRestriction.DeclaredOnly);
|
|
return ctor != null;
|
|
}
|
|
}
|
|
|
|
public class PredefinedDebuggerBrowsableAttribute : PredefinedAttribute
|
|
{
|
|
public PredefinedDebuggerBrowsableAttribute (ModuleContainer module, string ns, string name)
|
|
: base (module, ns, name)
|
|
{
|
|
}
|
|
|
|
public void EmitAttribute (FieldBuilder builder, System.Diagnostics.DebuggerBrowsableState state)
|
|
{
|
|
var ctor = module.PredefinedMembers.DebuggerBrowsableAttributeCtor.Get ();
|
|
if (ctor == null)
|
|
return;
|
|
|
|
AttributeEncoder encoder = new AttributeEncoder ();
|
|
encoder.Encode ((int) state);
|
|
encoder.EncodeEmptyNamedArguments ();
|
|
|
|
builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray (out var references));
|
|
module.AddAssemblyReferences (references);
|
|
}
|
|
}
|
|
|
|
public class PredefinedDebuggableAttribute : PredefinedAttribute
|
|
{
|
|
public PredefinedDebuggableAttribute (ModuleContainer module, string ns, string name)
|
|
: base (module, ns, name)
|
|
{
|
|
}
|
|
|
|
public void EmitAttribute (AssemblyBuilder builder, System.Diagnostics.DebuggableAttribute.DebuggingModes modes)
|
|
{
|
|
var atype = module.PredefinedAttributes.Debuggable;
|
|
if (!atype.Define ())
|
|
return;
|
|
|
|
MethodSpec ctor = null;
|
|
foreach (MethodSpec m in MemberCache.FindMembers (atype.TypeSpec, CSharp.Constructor.ConstructorName, true)) {
|
|
if (m.Parameters.Count != 1)
|
|
continue;
|
|
|
|
if (m.Parameters.Types[0].Kind == MemberKind.Enum) {
|
|
ctor = m;
|
|
}
|
|
}
|
|
|
|
if (ctor == null)
|
|
return;
|
|
|
|
AttributeEncoder encoder = new AttributeEncoder ();
|
|
encoder.Encode ((int) modes);
|
|
encoder.EncodeEmptyNamedArguments ();
|
|
|
|
builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray (out var references));
|
|
module.AddAssemblyReferences (references);
|
|
}
|
|
}
|
|
|
|
public class PredefinedDecimalAttribute : PredefinedAttribute
|
|
{
|
|
public PredefinedDecimalAttribute (ModuleContainer module, string ns, string name)
|
|
: base (module, ns, name)
|
|
{
|
|
}
|
|
|
|
public void EmitAttribute (ParameterBuilder builder, decimal value, Location loc)
|
|
{
|
|
var ctor = module.PredefinedMembers.DecimalConstantAttributeCtor.Resolve (loc);
|
|
if (ctor == null)
|
|
return;
|
|
|
|
int[] bits = decimal.GetBits (value);
|
|
AttributeEncoder encoder = new AttributeEncoder ();
|
|
encoder.Encode ((byte) (bits[3] >> 16));
|
|
encoder.Encode ((byte) (bits[3] >> 31));
|
|
encoder.Encode ((uint) bits[2]);
|
|
encoder.Encode ((uint) bits[1]);
|
|
encoder.Encode ((uint) bits[0]);
|
|
encoder.EncodeEmptyNamedArguments ();
|
|
|
|
builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray (out var references));
|
|
module.AddAssemblyReferences (references);
|
|
}
|
|
|
|
public void EmitAttribute (FieldBuilder builder, decimal value, Location loc)
|
|
{
|
|
var ctor = module.PredefinedMembers.DecimalConstantAttributeCtor.Resolve (loc);
|
|
if (ctor == null)
|
|
return;
|
|
|
|
int[] bits = decimal.GetBits (value);
|
|
AttributeEncoder encoder = new AttributeEncoder ();
|
|
encoder.Encode ((byte) ((bits[3] & 0xFF0000) >> 16)); // Scale
|
|
encoder.Encode ((byte) ((bits[3] >> 31) << 7)); // Sign encoded as 0x80 for negative, 0x0 for possitive
|
|
encoder.Encode ((uint) bits[2]);
|
|
encoder.Encode ((uint) bits[1]);
|
|
encoder.Encode ((uint) bits[0]);
|
|
encoder.EncodeEmptyNamedArguments ();
|
|
|
|
builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray (out var references));
|
|
module.AddAssemblyReferences (references);
|
|
}
|
|
}
|
|
|
|
public class PredefinedStateMachineAttribute : PredefinedAttribute
|
|
{
|
|
public PredefinedStateMachineAttribute (ModuleContainer module, string ns, string name)
|
|
: base (module, ns, name)
|
|
{
|
|
}
|
|
|
|
public void EmitAttribute (MethodBuilder builder, StateMachine type)
|
|
{
|
|
var predefined_ctor = module.PredefinedMembers.AsyncStateMachineAttributeCtor;
|
|
|
|
var ctor = predefined_ctor.Get ();
|
|
|
|
if (ctor == null)
|
|
return;
|
|
|
|
AttributeEncoder encoder = new AttributeEncoder ();
|
|
encoder.EncodeTypeName (type);
|
|
encoder.EncodeEmptyNamedArguments ();
|
|
|
|
builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), encoder.ToArray (out var references));
|
|
module.AddAssemblyReferences (references);
|
|
}
|
|
}
|
|
|
|
public class PredefinedDynamicAttribute : PredefinedAttribute
|
|
{
|
|
MethodSpec tctor;
|
|
|
|
public PredefinedDynamicAttribute (ModuleContainer module, string ns, string name)
|
|
: base (module, ns, name)
|
|
{
|
|
}
|
|
|
|
public void EmitAttribute (FieldBuilder builder, TypeSpec type, Location loc)
|
|
{
|
|
if (ResolveTransformationCtor (loc)) {
|
|
var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
|
|
builder.SetCustomAttribute (cab);
|
|
}
|
|
}
|
|
|
|
public void EmitAttribute (ParameterBuilder builder, TypeSpec type, Location loc)
|
|
{
|
|
if (ResolveTransformationCtor (loc)) {
|
|
var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
|
|
builder.SetCustomAttribute (cab);
|
|
}
|
|
}
|
|
|
|
public void EmitAttribute (PropertyBuilder builder, TypeSpec type, Location loc)
|
|
{
|
|
if (ResolveTransformationCtor (loc)) {
|
|
var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
|
|
builder.SetCustomAttribute (cab);
|
|
}
|
|
}
|
|
|
|
public void EmitAttribute (TypeBuilder builder, TypeSpec type, Location loc)
|
|
{
|
|
if (ResolveTransformationCtor (loc)) {
|
|
var cab = new CustomAttributeBuilder ((ConstructorInfo) tctor.GetMetaInfo (), new object[] { GetTransformationFlags (type) });
|
|
builder.SetCustomAttribute (cab);
|
|
}
|
|
}
|
|
|
|
//
|
|
// When any element of the type is a dynamic type
|
|
//
|
|
// This method builds a transformation array for dynamic types
|
|
// used in places where DynamicAttribute cannot be applied to.
|
|
// It uses bool flag when type is of dynamic type and each
|
|
// section always starts with "false" for some reason.
|
|
//
|
|
// LAMESPEC: This should be part of C# specification
|
|
//
|
|
// Example: Func<dynamic, int, dynamic[]>
|
|
// Transformation: { false, true, false, false, true }
|
|
//
|
|
static bool[] GetTransformationFlags (TypeSpec t)
|
|
{
|
|
bool[] element;
|
|
var ac = t as ArrayContainer;
|
|
if (ac != null) {
|
|
element = GetTransformationFlags (ac.Element);
|
|
if (element == null)
|
|
return new bool[] { false, false };
|
|
|
|
bool[] res = new bool[element.Length + 1];
|
|
res[0] = false;
|
|
Array.Copy (element, 0, res, 1, element.Length);
|
|
return res;
|
|
}
|
|
|
|
if (t == null)
|
|
return null;
|
|
|
|
if (t.IsGeneric) {
|
|
List<bool> transform = null;
|
|
var targs = t.TypeArguments;
|
|
for (int i = 0; i < targs.Length; ++i) {
|
|
element = GetTransformationFlags (targs[i]);
|
|
if (element != null) {
|
|
if (transform == null) {
|
|
transform = new List<bool> ();
|
|
for (int ii = 0; ii <= i; ++ii)
|
|
transform.Add (false);
|
|
}
|
|
|
|
transform.AddRange (element);
|
|
} else if (transform != null) {
|
|
transform.Add (false);
|
|
}
|
|
}
|
|
|
|
if (transform != null)
|
|
return transform.ToArray ();
|
|
}
|
|
|
|
if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
|
|
return new bool[] { true };
|
|
|
|
return null;
|
|
}
|
|
|
|
bool ResolveTransformationCtor (Location loc)
|
|
{
|
|
if (tctor != null)
|
|
return true;
|
|
|
|
tctor = module.PredefinedMembers.DynamicAttributeCtor.Resolve (loc);
|
|
return tctor != null;
|
|
}
|
|
}
|
|
|
|
public class PredefinedTupleElementNamesAttribute : PredefinedAttribute
|
|
{
|
|
MethodSpec tctor;
|
|
|
|
public PredefinedTupleElementNamesAttribute (ModuleContainer module, string ns, string name)
|
|
: base (module, ns, name)
|
|
{
|
|
}
|
|
|
|
public void EmitAttribute (FieldBuilder builder, TypeSpec type, Location loc)
|
|
{
|
|
var cab = CreateCustomAttributeBuilder (type, loc);
|
|
if (cab != null)
|
|
builder.SetCustomAttribute (cab);
|
|
}
|
|
|
|
public void EmitAttribute (ParameterBuilder builder, TypeSpec type, Location loc)
|
|
{
|
|
var cab = CreateCustomAttributeBuilder (type, loc);
|
|
if (cab != null)
|
|
builder.SetCustomAttribute (cab);
|
|
}
|
|
|
|
public void EmitAttribute (PropertyBuilder builder, TypeSpec type, Location loc)
|
|
{
|
|
var cab = CreateCustomAttributeBuilder (type, loc);
|
|
if (cab != null)
|
|
builder.SetCustomAttribute (cab);
|
|
}
|
|
|
|
public void EmitAttribute (TypeBuilder builder, TypeSpec type, Location loc)
|
|
{
|
|
var cab = CreateCustomAttributeBuilder (type, loc);
|
|
if (cab != null)
|
|
builder.SetCustomAttribute (cab);
|
|
}
|
|
|
|
CustomAttributeBuilder CreateCustomAttributeBuilder (TypeSpec type, Location loc)
|
|
{
|
|
if (tctor == null) {
|
|
tctor = module.PredefinedMembers.TupleElementNamesAttributeCtor.Resolve (loc);
|
|
if (tctor == null)
|
|
return null;
|
|
}
|
|
|
|
var names = new List<string> (type.TypeArguments.Length);
|
|
BuildStringElements (type, names);
|
|
return new CustomAttributeBuilder ((ConstructorInfo)tctor.GetMetaInfo (), new object [] { names.ToArray () });
|
|
}
|
|
|
|
//
|
|
// Returns an array of names when any element of the type is
|
|
// tuple with named element. The array is built for top level
|
|
// type therefore it can contain multiple tuple types
|
|
//
|
|
// Example: Func<(int, int), int, (int a, int b)[]>
|
|
// Output: { null, null, "a", "b" }
|
|
//
|
|
static void BuildStringElements (TypeSpec type, List<string> names)
|
|
{
|
|
while (type is ArrayContainer) {
|
|
type = ((ArrayContainer)type).Element;
|
|
}
|
|
|
|
var nts = type as NamedTupleSpec;
|
|
if (nts != null) {
|
|
names.AddRange (nts.Elements);
|
|
} else {
|
|
for (int i = 0; i < type.Arity; ++i) {
|
|
names.Add (null);
|
|
}
|
|
}
|
|
|
|
foreach (var ta in type.TypeArguments) {
|
|
BuildStringElements (ta, names);
|
|
}
|
|
}
|
|
}
|
|
}
|