Browse Source

Add support for non-custom attributes to CecilLoader.

pull/100/head
Daniel Grunwald 15 years ago
parent
commit
1c80484a85
  1. 28
      NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs
  2. 101
      NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  3. 258
      NRefactory/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
  4. 5
      NRefactory/ICSharpCode.NRefactory/TypeSystem/IAccessor.cs
  5. 6
      NRefactory/ICSharpCode.NRefactory/TypeSystem/IAttribute.cs
  6. 2
      NRefactory/ICSharpCode.NRefactory/TypeSystem/IMethod.cs
  7. 6
      NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs
  8. 17
      NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAccessor.cs
  9. 60
      NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs
  10. 9
      NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs

28
NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices;
[assembly: ICSharpCode.NRefactory.TypeSystem.TestCase.TypeTestAttribute( [assembly: ICSharpCode.NRefactory.TypeSystem.TestCase.TypeTestAttribute(
42, typeof(System.Action<>), typeof(IDictionary<string, IList<NUnit.Framework.TestAttribute>>))] 42, typeof(System.Action<>), typeof(IDictionary<string, IList<NUnit.Framework.TestAttribute>>))]
@ -65,4 +66,31 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase
{ {
public MyStructWithCtor(int a) {} public MyStructWithCtor(int a) {}
} }
[Serializable]
public class NonCustomAttributes
{
[NonSerialized]
public readonly int NonSerializedField;
[DllImport("unmanaged.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DllMethod([In, Out] ref int p);
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 8)]
public struct ExplicitFieldLayoutStruct
{
[FieldOffset(0)]
public int Field0;
[FieldOffset(100)]
public int Field100;
}
public class ParameterTests
{
public void MethodWithOutParameter(out int x) { x = 0; }
public void MethodWithParamsArray(params object[] x) {}
}
} }

101
NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.TypeSystem.TestCase; using ICSharpCode.NRefactory.TypeSystem.TestCase;
using NUnit.Framework; using NUnit.Framework;
@ -261,5 +262,105 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreEqual(2, ctors.Count()); Assert.AreEqual(2, ctors.Count());
Assert.IsFalse(ctors.Any(c => c.IsStatic)); Assert.IsFalse(ctors.Any(c => c.IsStatic));
} }
[Test]
public void SerializableAttribute()
{
IAttribute attr = ctx.GetClass(typeof(NonCustomAttributes)).Attributes.Single();
Assert.AreEqual("System.SerializableAttribute", attr.AttributeType.Resolve(ctx).FullName);
}
[Test]
public void NonSerializedAttribute()
{
IField field = ctx.GetClass(typeof(NonCustomAttributes)).Fields.Single(f => f.Name == "NonSerializedField");
Assert.AreEqual("System.NonSerializedAttribute", field.Attributes.Single().AttributeType.Resolve(ctx).FullName);
}
[Test]
public void ExplicitStructLayoutAttribute()
{
IAttribute attr = ctx.GetClass(typeof(ExplicitFieldLayoutStruct)).Attributes.Single();
Assert.AreEqual("System.Runtime.InteropServices.StructLayoutAttribute", attr.AttributeType.Resolve(ctx).FullName);
IConstantValue arg1 = attr.PositionalArguments.Single();
Assert.AreEqual("System.Runtime.InteropServices.LayoutKind", arg1.GetValueType(ctx).FullName);
Assert.AreEqual((int)LayoutKind.Explicit, arg1.GetValue(ctx));
var arg2 = attr.NamedArguments[0];
Assert.AreEqual("CharSet", arg2.Key);
Assert.AreEqual("System.Runtime.InteropServices.CharSet", arg2.Value.GetValueType(ctx).FullName);
Assert.AreEqual((int)CharSet.Unicode, arg2.Value.GetValue(ctx));
var arg3 = attr.NamedArguments[1];
Assert.AreEqual("Pack", arg3.Key);
Assert.AreEqual("System.Int32", arg3.Value.GetValueType(ctx).FullName);
Assert.AreEqual(8, arg3.Value.GetValue(ctx));
}
[Test]
public void FieldOffsetAttribute()
{
IField field = ctx.GetClass(typeof(ExplicitFieldLayoutStruct)).Fields.Single(f => f.Name == "Field0");
Assert.AreEqual("System.Runtime.InteropServices.FieldOffsetAttribute", field.Attributes.Single().AttributeType.Resolve(ctx).FullName);
IConstantValue arg = field.Attributes.Single().PositionalArguments.Single();
Assert.AreEqual("System.Int32", arg.GetValueType(ctx).FullName);
Assert.AreEqual(0, arg.GetValue(ctx));
field = ctx.GetClass(typeof(ExplicitFieldLayoutStruct)).Fields.Single(f => f.Name == "Field100");
Assert.AreEqual("System.Runtime.InteropServices.FieldOffsetAttribute", field.Attributes.Single().AttributeType.Resolve(ctx).FullName);
arg = field.Attributes.Single().PositionalArguments.Single();
Assert.AreEqual("System.Int32", arg.GetValueType(ctx).FullName);
Assert.AreEqual(100, arg.GetValue(ctx));
}
[Test]
public void DllImportAttribute()
{
IMethod method = ctx.GetClass(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod");
IAttribute dllImport = method.Attributes.Single();
Assert.AreEqual("System.Runtime.InteropServices.DllImportAttribute", dllImport.AttributeType.Resolve(ctx).FullName);
Assert.AreEqual("unmanaged.dll", dllImport.PositionalArguments[0].GetValue(ctx));
Assert.AreEqual((int)CharSet.Unicode, dllImport.NamedArguments.Single().Value.GetValue(ctx));
}
[Test]
public void InOutParametersOnRefMethod()
{
IParameter p = ctx.GetClass(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod").Parameters.Single();
Assert.IsTrue(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(2, p.Attributes.Count);
Assert.AreEqual("System.Runtime.InteropServices.InAttribute", p.Attributes[0].AttributeType.Resolve(ctx).FullName);
Assert.AreEqual("System.Runtime.InteropServices.OutAttribute", p.Attributes[1].AttributeType.Resolve(ctx).FullName);
}
[Test]
public void MarshalAsAttributeOnMethod()
{
IMethod method = ctx.GetClass(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod");
IAttribute marshalAs = method.ReturnTypeAttributes.Single();
Assert.AreEqual((int)UnmanagedType.Bool, marshalAs.PositionalArguments.Single().GetValue(ctx));
}
[Test]
public void MethodWithOutParameter()
{
IParameter p = ctx.GetClass(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOutParameter").Parameters.Single();
Assert.IsFalse(p.IsRef);
Assert.IsTrue(p.IsOut);
Assert.AreEqual(0, p.Attributes.Count);
Assert.IsTrue(p.Type is ByReferenceTypeReference);
}
[Test]
public void MethodWithParamsArray()
{
IParameter p = ctx.GetClass(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithParamsArray").Parameters.Single();
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.IsTrue(p.IsParams);
Assert.AreEqual(0, p.Attributes.Count);
Assert.IsTrue(p.Type is ArrayTypeReference);
}
} }
} }

258
NRefactory/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -46,6 +46,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
#endregion #endregion
#region Load From AssemblyDefinition #region Load From AssemblyDefinition
/// <summary>
/// Loads the assembly definition into a project content.
/// </summary>
/// <returns>IProjectContent that represents the assembly</returns>
public IProjectContent LoadAssembly(AssemblyDefinition assemblyDefinition) public IProjectContent LoadAssembly(AssemblyDefinition assemblyDefinition)
{ {
if (assemblyDefinition == null) if (assemblyDefinition == null)
@ -144,7 +148,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
public void Dispose() public void Dispose()
{ {
// Disposibng the synchronization context has no effect // Disposing the synchronization context has no effect
} }
string IDocumentationProvider.GetDocumentation(IEntity entity) string IDocumentationProvider.GetDocumentation(IEntity entity)
@ -297,14 +301,13 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
} }
const string DynamicAttributeFullName = "System.Runtime.CompilerServices.DynamicAttribute";
static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex) static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex)
{ {
if (attributeProvider == null || !attributeProvider.HasCustomAttributes) if (attributeProvider == null || !attributeProvider.HasCustomAttributes)
return false; return false;
foreach (CustomAttribute a in attributeProvider.CustomAttributes) { foreach (CustomAttribute a in attributeProvider.CustomAttributes) {
if (a.Constructor.DeclaringType.FullName == DynamicAttributeFullName) { TypeReference type = a.AttributeType;
if (type.Name == "DynamicAttribute" && type.Namespace == "System.Runtime.CompilerServices") {
if (a.ConstructorArguments.Count == 1) { if (a.ConstructorArguments.Count == 1) {
CustomAttributeArgument[] values = a.ConstructorArguments[0].Value as CustomAttributeArgument[]; CustomAttributeArgument[] values = a.ConstructorArguments[0].Value as CustomAttributeArgument[];
if (values != null && typeIndex < values.Length && values[typeIndex].Value is bool) if (values != null && typeIndex < values.Length && values[typeIndex].Value is bool)
@ -325,21 +328,150 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
} }
static readonly IAttribute inAttribute = new DefaultAttribute(typeof(InAttribute).ToTypeReference(), null);
static readonly IAttribute outAttribute = new DefaultAttribute(typeof(OutAttribute).ToTypeReference(), null);
void AddAttributes(ParameterDefinition parameter, DefaultParameter targetParameter) void AddAttributes(ParameterDefinition parameter, DefaultParameter targetParameter)
{ {
if (!targetParameter.IsOut) {
if (parameter.IsIn)
targetParameter.Attributes.Add(inAttribute);
if (parameter.IsOut)
targetParameter.Attributes.Add(outAttribute);
}
if (parameter.HasCustomAttributes) { if (parameter.HasCustomAttributes) {
AddCustomAttributes(parameter.CustomAttributes, targetParameter.Attributes); AddCustomAttributes(parameter.CustomAttributes, targetParameter.Attributes);
} }
} }
void AddAttributes(MethodDefinition accessorMethod, DefaultAccessor targetAccessor) static readonly ITypeReference dllImportAttributeTypeRef = typeof(DllImportAttribute).ToTypeReference();
static readonly SimpleConstantValue trueValue = new SimpleConstantValue(KnownTypeReference.Boolean, true);
static readonly SimpleConstantValue falseValue = new SimpleConstantValue(KnownTypeReference.Boolean, true);
static readonly ITypeReference callingConventionTypeRef = typeof(CallingConvention).ToTypeReference();
static readonly IAttribute preserveSigAttribute = new DefaultAttribute(typeof(PreserveSigAttribute).ToTypeReference(), null);
static readonly ITypeReference methodImplAttributeTypeRef = typeof(MethodImplAttribute).ToTypeReference();
static readonly ITypeReference methodImplOptionsTypeRef = typeof(MethodImplOptions).ToTypeReference();
bool HasAnyAttributes(MethodDefinition methodDefinition)
{ {
if (accessorMethod.HasCustomAttributes) { if (methodDefinition.HasPInvokeInfo)
AddCustomAttributes(accessorMethod.CustomAttributes, targetAccessor.Attributes); return true;
if ((methodDefinition.ImplAttributes & ~MethodImplAttributes.CodeTypeMask) != 0)
return true;
if (methodDefinition.MethodReturnType.HasFieldMarshal)
return true;
return methodDefinition.HasCustomAttributes || methodDefinition.MethodReturnType.HasCustomAttributes;
}
void AddAttributes(MethodDefinition methodDefinition, IList<IAttribute> attributes, IList<IAttribute> returnTypeAttributes)
{
MethodImplAttributes implAttributes = methodDefinition.ImplAttributes & ~MethodImplAttributes.CodeTypeMask;
#region DllImportAttribute
if (methodDefinition.HasPInvokeInfo) {
PInvokeInfo info = methodDefinition.PInvokeInfo;
DefaultAttribute dllImport = new DefaultAttribute(dllImportAttributeTypeRef, new[] { KnownTypeReference.String });
dllImport.PositionalArguments.Add(new SimpleConstantValue(KnownTypeReference.String, info.Module.Name));
if (info.IsBestFitDisabled)
AddNamedArgument(dllImport, "BestFitMapping", falseValue);
if (info.IsBestFitEnabled)
AddNamedArgument(dllImport, "BestFitMapping", trueValue);
CallingConvention callingConvention;
switch (info.Attributes & PInvokeAttributes.CallConvMask) {
case PInvokeAttributes.CallConvCdecl:
callingConvention = CallingConvention.Cdecl;
break;
case PInvokeAttributes.CallConvFastcall:
callingConvention = CallingConvention.FastCall;
break;
case PInvokeAttributes.CallConvStdCall:
callingConvention = CallingConvention.StdCall;
break;
case PInvokeAttributes.CallConvThiscall:
callingConvention = CallingConvention.ThisCall;
break;
case PInvokeAttributes.CallConvWinapi:
callingConvention = CallingConvention.Winapi;
break;
default:
throw new NotSupportedException("unknown calling convention");
}
if (callingConvention != CallingConvention.Winapi)
AddNamedArgument(dllImport, "CallingConvention", new SimpleConstantValue(callingConventionTypeRef, (int)callingConvention));
CharSet charSet = CharSet.None;
switch (info.Attributes & PInvokeAttributes.CharSetMask) {
case PInvokeAttributes.CharSetAnsi:
charSet = CharSet.Ansi;
break;
case PInvokeAttributes.CharSetAuto:
charSet = CharSet.Auto;
break;
case PInvokeAttributes.CharSetUnicode:
charSet = CharSet.Unicode;
break;
}
if (charSet != CharSet.None)
dllImport.NamedArguments.Add(new KeyValuePair<string, IConstantValue>(
"CharSet", new SimpleConstantValue(charSetTypeRef, (int)charSet)));
if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != methodDefinition.Name)
AddNamedArgument(dllImport, "EntryPoint", new SimpleConstantValue(KnownTypeReference.String, info.EntryPoint));
if (info.IsNoMangle)
AddNamedArgument(dllImport, "ExactSpelling", trueValue);
if ((implAttributes & MethodImplAttributes.PreserveSig) == MethodImplAttributes.PreserveSig)
implAttributes &= ~MethodImplAttributes.PreserveSig;
else
AddNamedArgument(dllImport, "PreserveSig", falseValue);
if (info.SupportsLastError)
AddNamedArgument(dllImport, "SetLastError", trueValue);
if (info.IsThrowOnUnmappableCharDisabled)
AddNamedArgument(dllImport, "ThrowOnUnmappableChar", falseValue);
if (info.IsThrowOnUnmappableCharEnabled)
AddNamedArgument(dllImport, "ThrowOnUnmappableChar", trueValue);
attributes.Add(dllImport);
}
#endregion
#region PreserveSigAttribute
if (implAttributes == MethodImplAttributes.PreserveSig) {
attributes.Add(preserveSigAttribute);
implAttributes = 0;
}
#endregion
#region MethodImplAttribute
if (implAttributes != 0) {
DefaultAttribute methodImpl = new DefaultAttribute(methodImplAttributeTypeRef, new[] { methodImplOptionsTypeRef });
methodImpl.PositionalArguments.Add(new SimpleConstantValue(methodImplOptionsTypeRef, (int)implAttributes));
attributes.Add(methodImpl);
}
#endregion
if (methodDefinition.HasCustomAttributes) {
AddCustomAttributes(methodDefinition.CustomAttributes, attributes);
}
if (methodDefinition.MethodReturnType.HasMarshalInfo) {
returnTypeAttributes.Add(ConvertMarshalInfo(methodDefinition.MethodReturnType.MarshalInfo));
} }
if (methodDefinition.MethodReturnType.HasCustomAttributes) {
AddCustomAttributes(methodDefinition.MethodReturnType.CustomAttributes, returnTypeAttributes);
}
}
static void AddNamedArgument(DefaultAttribute attribute, string name, IConstantValue value)
{
attribute.NamedArguments.Add(new KeyValuePair<string, IConstantValue>(name, value));
} }
static readonly DefaultAttribute serializableAttribute = new DefaultAttribute(typeof(SerializableAttribute).ToTypeReference()); static readonly DefaultAttribute serializableAttribute = new DefaultAttribute(typeof(SerializableAttribute).ToTypeReference(), null);
static readonly ITypeReference structLayoutAttributeTypeRef = typeof(StructLayoutAttribute).ToTypeReference(); static readonly ITypeReference structLayoutAttributeTypeRef = typeof(StructLayoutAttribute).ToTypeReference();
static readonly ITypeReference layoutKindTypeRef = typeof(LayoutKind).ToTypeReference(); static readonly ITypeReference layoutKindTypeRef = typeof(LayoutKind).ToTypeReference();
static readonly ITypeReference charSetTypeRef = typeof(CharSet).ToTypeReference(); static readonly ITypeReference charSetTypeRef = typeof(CharSet).ToTypeReference();
@ -373,8 +505,9 @@ namespace ICSharpCode.NRefactory.TypeSystem
charSet = CharSet.Unicode; charSet = CharSet.Unicode;
break; break;
} }
if (layoutKind != LayoutKind.Auto || charSet != CharSet.Ansi || typeDefinition.PackingSize > 0 || typeDefinition.ClassSize > 0) { LayoutKind defaultLayoutKind = (typeDefinition.IsValueType && !typeDefinition.IsEnum) ? LayoutKind.Sequential: LayoutKind.Auto;
DefaultAttribute structLayout = new DefaultAttribute(structLayoutAttributeTypeRef); if (layoutKind != defaultLayoutKind || charSet != CharSet.Ansi || typeDefinition.PackingSize > 0 || typeDefinition.ClassSize > 0) {
DefaultAttribute structLayout = new DefaultAttribute(structLayoutAttributeTypeRef, new[] { layoutKindTypeRef });
structLayout.PositionalArguments.Add(new SimpleConstantValue(layoutKindTypeRef, (int)layoutKind)); structLayout.PositionalArguments.Add(new SimpleConstantValue(layoutKindTypeRef, (int)layoutKind));
if (charSet != CharSet.Ansi) { if (charSet != CharSet.Ansi) {
structLayout.NamedArguments.Add(new KeyValuePair<string, IConstantValue>( structLayout.NamedArguments.Add(new KeyValuePair<string, IConstantValue>(
@ -400,12 +533,58 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
} }
static readonly ITypeReference fieldOffsetAttributeTypeRef = typeof(FieldOffsetAttribute).ToTypeReference();
static readonly DefaultAttribute nonSerializedAttribute = new DefaultAttribute(typeof(NonSerializedAttribute).ToTypeReference(), null);
void AddAttributes(FieldDefinition fieldDefinition, IEntity targetEntity)
{
#region FieldOffsetAttribute
if (fieldDefinition.HasLayoutInfo) {
DefaultAttribute fieldOffset = new DefaultAttribute(fieldOffsetAttributeTypeRef, new[] { KnownTypeReference.Int32 });
fieldOffset.PositionalArguments.Add(new SimpleConstantValue(KnownTypeReference.Int32, fieldDefinition.Offset));
targetEntity.Attributes.Add(fieldOffset);
}
#endregion
#region NonSerializedAttribute
if (fieldDefinition.IsNotSerialized) {
targetEntity.Attributes.Add(nonSerializedAttribute);
}
#endregion
if (fieldDefinition.HasMarshalInfo) {
targetEntity.Attributes.Add(ConvertMarshalInfo(fieldDefinition.MarshalInfo));
}
if (fieldDefinition.HasCustomAttributes) {
AddCustomAttributes(fieldDefinition.CustomAttributes, targetEntity.Attributes);
}
}
#region MarshalAsAttribute (ConvertMarshalInfo)
static readonly ITypeReference marshalAsAttributeTypeRef = typeof(MarshalAsAttribute).ToTypeReference();
static readonly ITypeReference unmanagedTypeTypeRef = typeof(UnmanagedType).ToTypeReference();
static IAttribute ConvertMarshalInfo(MarshalInfo marshalInfo)
{
DefaultAttribute attr = new DefaultAttribute(marshalAsAttributeTypeRef, new[] { unmanagedTypeTypeRef });
attr.PositionalArguments.Add(new SimpleConstantValue(unmanagedTypeTypeRef, (int)marshalInfo.NativeType));
// TODO: handle classes derived from MarshalInfo
return attr;
}
#endregion
void AddCustomAttributes(Mono.Collections.Generic.Collection<CustomAttribute> attributes, IList<IAttribute> targetCollection) void AddCustomAttributes(Mono.Collections.Generic.Collection<CustomAttribute> attributes, IList<IAttribute> targetCollection)
{ {
foreach (var cecilAttribute in attributes) { foreach (var cecilAttribute in attributes) {
if (cecilAttribute.AttributeType.FullName != DynamicAttributeFullName) { TypeReference type = cecilAttribute.AttributeType;
targetCollection.Add(ReadAttribute(cecilAttribute)); if (type.Namespace == "System.Runtime.CompilerServices") {
if (type.Name == "DynamicAttribute" || type.Name == "ExtensionAttribute")
continue;
} else if (type.Name == "ParamArrayAttribute" && type.Namespace == "System") {
continue;
} }
targetCollection.Add(ReadAttribute(cecilAttribute));
} }
} }
@ -413,7 +592,15 @@ namespace ICSharpCode.NRefactory.TypeSystem
{ {
if (attribute == null) if (attribute == null)
throw new ArgumentNullException("attribute"); throw new ArgumentNullException("attribute");
DefaultAttribute a = new DefaultAttribute(ReadTypeReference(attribute.AttributeType)); MethodReference ctor = attribute.Constructor;
ITypeReference[] ctorParameters = null;
if (ctor.HasParameters) {
ctorParameters = new ITypeReference[ctor.Parameters.Count];
for (int i = 0; i < ctorParameters.Length; i++) {
ctorParameters[i] = ReadTypeReference(ctor.Parameters[i].ParameterType);
}
}
DefaultAttribute a = new DefaultAttribute(ReadTypeReference(attribute.AttributeType), ctorParameters);
try { try {
if (attribute.HasConstructorArguments) { if (attribute.HasConstructorArguments) {
foreach (var arg in attribute.ConstructorArguments) { foreach (var arg in attribute.ConstructorArguments) {
@ -442,8 +629,13 @@ namespace ICSharpCode.NRefactory.TypeSystem
#region Read Constant Value #region Read Constant Value
public IConstantValue ReadConstantValue(CustomAttributeArgument arg) public IConstantValue ReadConstantValue(CustomAttributeArgument arg)
{ {
ITypeReference type = ReadTypeReference(arg.Type);
object value = arg.Value; object value = arg.Value;
if (value is CustomAttributeArgument) {
// Cecil uses this representation for boxed values
arg = (CustomAttributeArgument)value;
value = arg.Value;
}
ITypeReference type = ReadTypeReference(arg.Type);
CustomAttributeArgument[] array = value as CustomAttributeArgument[]; CustomAttributeArgument[] array = value as CustomAttributeArgument[];
if (array != null) { if (array != null) {
// TODO: write unit test for this // TODO: write unit test for this
@ -500,9 +692,9 @@ namespace ICSharpCode.NRefactory.TypeSystem
InitNestedTypes(loader); // nested types can be initialized only after generic parameters were created InitNestedTypes(loader); // nested types can be initialized only after generic parameters were created
if (typeDefinition.HasCustomAttributes) { loader.AddAttributes(typeDefinition, this);
loader.AddAttributes(typeDefinition, this);
} this.HasExtensionMethods = HasExtensionAttribute(typeDefinition);
// set base classes // set base classes
if (typeDefinition.IsEnum) { if (typeDefinition.IsEnum) {
@ -699,7 +891,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
else else
m.ReturnType = ReadTypeReference(method.ReturnType, typeAttributes: method.MethodReturnType, entity: m); m.ReturnType = ReadTypeReference(method.ReturnType, typeAttributes: method.MethodReturnType, entity: m);
AddAttributes(method, m); if (HasAnyAttributes(method))
AddAttributes(method, m.Attributes, m.ReturnTypeAttributes);
TranslateModifiers(method, m); TranslateModifiers(method, m);
if (method.HasParameters) { if (method.HasParameters) {
@ -708,18 +901,26 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
} }
// mark as extension method is the attribute is set // mark as extension method if the attribute is set
if (method.IsStatic && method.HasCustomAttributes) { if (method.IsStatic && HasExtensionAttribute(method)) {
foreach (var attr in method.CustomAttributes) { m.IsExtensionMethod = true;
if (attr.AttributeType.FullName == typeof(ExtensionAttribute).FullName)
m.IsExtensionMethod = true;
}
} }
FinishReadMember(m); FinishReadMember(m);
return m; return m;
} }
static bool HasExtensionAttribute(ICustomAttributeProvider provider)
{
if (provider.HasCustomAttributes) {
foreach (var attr in provider.CustomAttributes) {
if (attr.AttributeType.Name == "ExtensionAttribute" && attr.AttributeType.Namespace == "System.Runtime.CompilerServices")
return true;
}
}
return false;
}
bool IsVisible(MethodAttributes att) bool IsVisible(MethodAttributes att)
{ {
att &= MethodAttributes.MemberAccessMask; att &= MethodAttributes.MemberAccessMask;
@ -782,14 +983,13 @@ namespace ICSharpCode.NRefactory.TypeSystem
var type = ReadTypeReference(parameter.ParameterType, typeAttributes: parameter, entity: parentMember); var type = ReadTypeReference(parameter.ParameterType, typeAttributes: parameter, entity: parentMember);
DefaultParameter p = new DefaultParameter(type, parameter.Name); DefaultParameter p = new DefaultParameter(type, parameter.Name);
AddAttributes(parameter, p);
if (parameter.ParameterType is Mono.Cecil.ByReferenceType) { if (parameter.ParameterType is Mono.Cecil.ByReferenceType) {
if (parameter.IsOut) if (!parameter.IsIn && parameter.IsOut)
p.IsOut = true; p.IsOut = true;
else else
p.IsRef = true; p.IsRef = true;
} }
AddAttributes(parameter, p);
if (parameter.IsOptional) { if (parameter.IsOptional) {
p.DefaultValue = ReadConstantValue(new CustomAttributeArgument(parameter.ParameterType, parameter.Constant)); p.DefaultValue = ReadConstantValue(new CustomAttributeArgument(parameter.ParameterType, parameter.Constant));
@ -917,10 +1117,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
{ {
if (accessorMethod != null && IsVisible(accessorMethod.Attributes)) { if (accessorMethod != null && IsVisible(accessorMethod.Attributes)) {
Accessibility accessibility = GetAccessibility(accessorMethod.Attributes); Accessibility accessibility = GetAccessibility(accessorMethod.Attributes);
if (accessorMethod.HasCustomAttributes) { if (HasAnyAttributes(accessorMethod)) {
DefaultAccessor a = new DefaultAccessor(); DefaultAccessor a = new DefaultAccessor();
a.Accessibility = accessibility; a.Accessibility = accessibility;
AddAttributes(accessorMethod, a); AddAttributes(accessorMethod, a.Attributes, a.ReturnTypeAttributes);
return a; return a;
} else { } else {
return DefaultAccessor.GetFromAccessibility(accessibility); return DefaultAccessor.GetFromAccessibility(accessibility);

5
NRefactory/ICSharpCode.NRefactory/TypeSystem/IAccessor.cs

@ -21,6 +21,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
IList<IAttribute> Attributes { get; } IList<IAttribute> Attributes { get; }
/// <summary>
/// Gets the attributes defined on the return type of the accessor. (e.g. [return: MarshalAs(...)])
/// </summary>
IList<IAttribute> ReturnTypeAttributes { get; }
/// <summary> /// <summary>
/// Gets the accessibility of this accessor. /// Gets the accessibility of this accessor.
/// </summary> /// </summary>

6
NRefactory/ICSharpCode.NRefactory/TypeSystem/IAttribute.cs

@ -35,6 +35,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// Gets the named arguments passed to the attribute. /// Gets the named arguments passed to the attribute.
/// </summary> /// </summary>
IList<KeyValuePair<string, IConstantValue>> NamedArguments { get; } IList<KeyValuePair<string, IConstantValue>> NamedArguments { get; }
/// <summary>
/// Resolves the constructor method used for this attribute invocation.
/// Returns null if the constructor cannot be found.
/// </summary>
IMethod ResolveConstructor(ITypeResolveContext context);
} }
#if WITH_CONTRACTS #if WITH_CONTRACTS

2
NRefactory/ICSharpCode.NRefactory/TypeSystem/IMethod.cs

@ -16,7 +16,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
public interface IMethod : IParameterizedMember public interface IMethod : IParameterizedMember
{ {
/// <summary> /// <summary>
/// Gets the attributes associated with the return type. /// Gets the attributes associated with the return type. (e.g. [return: MarshalAs(...)])
/// </summary> /// </summary>
IList<IAttribute> ReturnTypeAttributes { get; } IList<IAttribute> ReturnTypeAttributes { get; }

6
NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs

@ -44,6 +44,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// Gets all members declared in this class. This is the union of Fields,Properties,Methods and Events. /// Gets all members declared in this class. This is the union of Fields,Properties,Methods and Events.
/// </summary> /// </summary>
IEnumerable<IMember> Members { get; } IEnumerable<IMember> Members { get; }
/// <summary>
/// Gets whether this type contains extension methods.
/// </summary>
/// <remarks>This property is used to speed up the search for extension methods.</remarks>
bool HasExtensionMethods { get; }
} }
#if WITH_CONTRACTS #if WITH_CONTRACTS

17
NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAccessor.cs

@ -44,6 +44,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
Accessibility accessibility; Accessibility accessibility;
DomRegion region; DomRegion region;
IList<IAttribute> attributes; IList<IAttribute> attributes;
IList<IAttribute> returnTypeAttributes;
protected override void FreezeInternal() protected override void FreezeInternal()
{ {
@ -75,20 +76,32 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
} }
public IList<IAttribute> ReturnTypeAttributes {
get {
if (returnTypeAttributes == null)
returnTypeAttributes = new List<IAttribute>();
return returnTypeAttributes;
}
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider) void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{ {
attributes = provider.InternList(attributes); attributes = provider.InternList(attributes);
returnTypeAttributes = provider.InternList(returnTypeAttributes);
} }
int ISupportsInterning.GetHashCodeForInterning() int ISupportsInterning.GetHashCodeForInterning()
{ {
return (attributes != null ? attributes.GetHashCode() : 0) ^ region.GetHashCode() ^ (int)accessibility; return (attributes != null ? attributes.GetHashCode() : 0)
^ (returnTypeAttributes != null ? returnTypeAttributes.GetHashCode() : 0)
^ region.GetHashCode() ^ (int)accessibility;
} }
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{ {
DefaultAccessor a = other as DefaultAccessor; DefaultAccessor a = other as DefaultAccessor;
return a != null && (attributes == a.attributes && accessibility == a.accessibility && region == a.region); return a != null && (attributes == a.attributes && returnTypeAttributes == a.returnTypeAttributes
&& accessibility == a.accessibility && region == a.region);
} }
} }
} }

60
NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -13,8 +14,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// </summary> /// </summary>
public sealed class DefaultAttribute : AbstractFreezable, IAttribute, ISupportsInterning public sealed class DefaultAttribute : AbstractFreezable, IAttribute, ISupportsInterning
{ {
DomRegion region;
ITypeReference attributeType; ITypeReference attributeType;
readonly ITypeReference[] constructorParameterTypes;
DomRegion region;
IList<IConstantValue> positionalArguments; IList<IConstantValue> positionalArguments;
IList<KeyValuePair<string, IConstantValue>> namedArguments; IList<KeyValuePair<string, IConstantValue>> namedArguments;
@ -34,11 +36,20 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
base.FreezeInternal(); base.FreezeInternal();
} }
public DefaultAttribute(ITypeReference attributeType) public DefaultAttribute(ITypeReference attributeType, IEnumerable<ITypeReference> constructorParameterTypes)
{ {
if (attributeType == null) if (attributeType == null)
throw new ArgumentNullException("attributeType"); throw new ArgumentNullException("attributeType");
this.attributeType = attributeType; this.attributeType = attributeType;
this.constructorParameterTypes = constructorParameterTypes != null ? constructorParameterTypes.ToArray() : null;
}
public ITypeReference AttributeType {
get { return attributeType; }
}
public ReadOnlyCollection<ITypeReference> ConstructorParameterTypes {
get { return Array.AsReadOnly(constructorParameterTypes); }
} }
public DomRegion Region { public DomRegion Region {
@ -49,14 +60,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
} }
public ITypeReference AttributeType {
get { return attributeType; }
set {
CheckBeforeMutation();
attributeType = value;
}
}
public IList<IConstantValue> PositionalArguments { public IList<IConstantValue> PositionalArguments {
get { get {
if (positionalArguments == null) if (positionalArguments == null)
@ -73,6 +76,38 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
} }
public IMethod ResolveConstructor(ITypeResolveContext context)
{
IType[] parameterTypes = null;
if (constructorParameterTypes != null && constructorParameterTypes.Length > 0) {
parameterTypes = new IType[constructorParameterTypes.Length];
for (int i = 0; i < parameterTypes.Length; i++) {
parameterTypes[i] = constructorParameterTypes[i].Resolve(context);
}
}
IMethod bestMatch = null;
foreach (IMethod ctor in attributeType.Resolve(context).GetConstructors(context)) {
if (ctor.IsStatic)
continue;
if (parameterTypes == null) {
if (ctor.Parameters.Count == 0)
return ctor;
} else if (ctor.Parameters.Count == parameterTypes.Length) {
bestMatch = ctor;
bool ok = true;
for (int i = 0; i < parameterTypes.Length; i++) {
if (ctor.Parameters[i].Type != parameterTypes[i]) {
ok = false;
break;
}
}
if (ok)
return ctor;
}
}
return bestMatch;
}
public override string ToString() public override string ToString()
{ {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
@ -100,6 +135,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
void ISupportsInterning.PrepareForInterning(IInterningProvider provider) void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{ {
attributeType = provider.Intern(attributeType); attributeType = provider.Intern(attributeType);
if (constructorParameterTypes != null) {
for (int i = 0; i < constructorParameterTypes.Length; i++) {
constructorParameterTypes[i] = provider.Intern(constructorParameterTypes[i]);
}
}
positionalArguments = provider.InternList(positionalArguments); positionalArguments = provider.InternList(positionalArguments);
} }

9
NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs

@ -40,6 +40,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
const ushort FlagShadowing = 0x0004; const ushort FlagShadowing = 0x0004;
const ushort FlagSynthetic = 0x0008; const ushort FlagSynthetic = 0x0008;
const ushort FlagAddDefaultConstructorIfRequired = 0x0010; const ushort FlagAddDefaultConstructorIfRequired = 0x0010;
const ushort FlagHasExtensionMethods = 0x0020;
protected override void FreezeInternal() protected override void FreezeInternal()
{ {
@ -312,6 +313,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
} }
public bool HasExtensionMethods {
get { return flags[FlagHasExtensionMethods]; }
set {
CheckBeforeMutation();
flags[FlagHasExtensionMethods] = value;
}
}
public IProjectContent ProjectContent { public IProjectContent ProjectContent {
get { return projectContent; } get { return projectContent; }
} }

Loading…
Cancel
Save