Browse Source

Handle non-custom attributes:

- SerializableAttribute
- StructLayoutAttribute
- DllImportAttribute
- MethodImplAttribute
- FieldOffsetAttribute
- MarshalAsAttribute
- InAttribute
- OutAttribute
pull/70/head
Daniel Grunwald 14 years ago
parent
commit
8835b085cf
  1. 204
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 5
      ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs
  3. 4
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

204
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -1,10 +1,11 @@ @@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.Decompiler.ILAst;
@ -525,8 +526,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -525,8 +526,7 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.Modifiers = ConvertModifiers(methodDef);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context);
}
ConvertCustomAttributes(astMethod, methodDef);
ConvertCustomAttributes(astMethod, methodDef.MethodReturnType, AttributeTarget.Return);
ConvertAttributes(astMethod, methodDef);
return astMethod;
}
@ -580,6 +580,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -580,6 +580,7 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.Name = CleanName(methodDef.DeclaringType.Name);
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context);
ConvertAttributes(astMethod, methodDef);
return astMethod;
}
@ -594,15 +595,13 @@ namespace ICSharpCode.Decompiler.Ast @@ -594,15 +595,13 @@ namespace ICSharpCode.Decompiler.Ast
astProp.Getter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context)
}.WithAnnotation(propDef.GetMethod);
ConvertCustomAttributes(astProp.Getter, propDef.GetMethod);
ConvertCustomAttributes(astProp.Getter, propDef.GetMethod.MethodReturnType, AttributeTarget.Return);
ConvertAttributes(astProp.Getter, propDef.GetMethod);
}
if (propDef.SetMethod != null) {
astProp.Setter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context)
}.WithAnnotation(propDef.SetMethod);
ConvertCustomAttributes(astProp.Setter, propDef.SetMethod);
ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.MethodReturnType, AttributeTarget.Return);
ConvertAttributes(astProp.Setter, propDef.SetMethod);
ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), AttributeTarget.Param);
}
ConvertCustomAttributes(astProp, propDef);
@ -620,11 +619,13 @@ namespace ICSharpCode.Decompiler.Ast @@ -620,11 +619,13 @@ namespace ICSharpCode.Decompiler.Ast
astEvent.AddAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.AddMethod, context)
}.WithAnnotation(eventDef.AddMethod);
ConvertAttributes(astEvent.AddAccessor, eventDef.AddMethod);
}
if (eventDef.RemoveMethod != null) {
astEvent.RemoveAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.RemoveMethod, context)
}.WithAnnotation(eventDef.RemoveMethod);
ConvertAttributes(astEvent.RemoveAccessor, eventDef.RemoveMethod);
}
return astEvent;
}
@ -643,7 +644,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -643,7 +644,7 @@ namespace ICSharpCode.Decompiler.Ast
else
initializer.Initializer = new PrimitiveExpression(fieldDef.Constant);
}
ConvertCustomAttributes(astField, fieldDef);
ConvertAttributes(astField, fieldDef);
return astField;
}
@ -655,15 +656,26 @@ namespace ICSharpCode.Decompiler.Ast @@ -655,15 +656,26 @@ namespace ICSharpCode.Decompiler.Ast
astParam.Name = paramDef.Name;
if (paramDef.ParameterType is ByReferenceType) {
astParam.ParameterModifier = paramDef.IsOut ? ParameterModifier.Out : ParameterModifier.Ref;
astParam.ParameterModifier = (!paramDef.IsIn && paramDef.IsOut) ? ParameterModifier.Out : ParameterModifier.Ref;
}
// TODO: params, this
ConvertCustomAttributes(astParam, paramDef);
ModuleDefinition module = ((MethodDefinition)paramDef.Method).Module;
if (paramDef.HasMarshalInfo) {
astParam.Attributes.Add(new AttributeSection(ConvertMarshalInfo(paramDef, module)));
}
if (astParam.ParameterModifier != ParameterModifier.Out) {
if (paramDef.IsIn)
astParam.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(InAttribute), module)));
if (paramDef.IsOut)
astParam.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(OutAttribute), module)));
}
yield return astParam;
}
}
#region ConvertAttributes
void ConvertAttributes(AttributedNode attributedNode, TypeDefinition typeDefinition)
{
ConvertCustomAttributes(attributedNode, typeDefinition);
@ -671,7 +683,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -671,7 +683,7 @@ namespace ICSharpCode.Decompiler.Ast
// Handle the non-custom attributes:
#region SerializableAttribute
if (typeDefinition.IsSerializable)
attributedNode.Attributes.Add(new AttributeSection(new Ast.Attribute { Type = new SimpleType("Serializable") }));
attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(SerializableAttribute))));
#endregion
#region StructLayoutAttribute
@ -698,32 +710,166 @@ namespace ICSharpCode.Decompiler.Ast @@ -698,32 +710,166 @@ namespace ICSharpCode.Decompiler.Ast
}
LayoutKind defaultLayoutKind = (typeDefinition.IsValueType && !typeDefinition.IsEnum) ? LayoutKind.Sequential: LayoutKind.Auto;
if (layoutKind != defaultLayoutKind || charSet != CharSet.Ansi || typeDefinition.PackingSize > 0 || typeDefinition.ClassSize > 0) {
var structLayout = new Ast.Attribute();
structLayout.Type = new SimpleType("StructLayout");
var structLayout = CreateNonCustomAttribute(typeof(StructLayoutAttribute));
structLayout.Arguments.Add(new IdentifierExpression("LayoutKind").Member(layoutKind.ToString()));
if (charSet != CharSet.Ansi) {
structLayout.Arguments.Add(new AssignmentExpression(
new IdentifierExpression("CharSet"),
new IdentifierExpression("CharSet").Member(charSet.ToString())
));
structLayout.AddNamedArgument("CharSet", new IdentifierExpression("CharSet").Member(charSet.ToString()));
}
if (typeDefinition.PackingSize > 0) {
structLayout.Arguments.Add(new AssignmentExpression(
new IdentifierExpression("Pack"),
new PrimitiveExpression((int)typeDefinition.PackingSize)
));
structLayout.AddNamedArgument("Pack", new PrimitiveExpression((int)typeDefinition.PackingSize));
}
if (typeDefinition.ClassSize > 0) {
structLayout.Arguments.Add(new AssignmentExpression(
new IdentifierExpression("Size"),
new PrimitiveExpression((int)typeDefinition.ClassSize)
));
structLayout.AddNamedArgument("Size", new PrimitiveExpression((int)typeDefinition.ClassSize));
}
attributedNode.Attributes.Add(new AttributeSection(structLayout));
}
#endregion
}
void ConvertAttributes(AttributedNode attributedNode, MethodDefinition methodDefinition)
{
ConvertCustomAttributes(attributedNode, methodDefinition);
MethodImplAttributes implAttributes = methodDefinition.ImplAttributes & ~MethodImplAttributes.CodeTypeMask;
#region DllImportAttribute
if (methodDefinition.HasPInvokeInfo) {
PInvokeInfo info = methodDefinition.PInvokeInfo;
Ast.Attribute dllImport = CreateNonCustomAttribute(typeof(DllImportAttribute));
dllImport.Arguments.Add(new PrimitiveExpression(info.Module.Name));
if (info.IsBestFitDisabled)
dllImport.AddNamedArgument("BestFitMapping", new PrimitiveExpression(false));
if (info.IsBestFitEnabled)
dllImport.AddNamedArgument("BestFitMapping", new PrimitiveExpression(true));
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)
dllImport.AddNamedArgument("CallingConvention", new IdentifierExpression("CallingConvention").Member(callingConvention.ToString()));
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.AddNamedArgument("CharSet", new IdentifierExpression("CharSet").Member(charSet.ToString()));
if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != methodDefinition.Name)
dllImport.AddNamedArgument("EntryPoint", new PrimitiveExpression(info.EntryPoint));
if (info.IsNoMangle)
dllImport.AddNamedArgument("ExactSpelling", new PrimitiveExpression(true));
if ((implAttributes & MethodImplAttributes.PreserveSig) == MethodImplAttributes.PreserveSig)
implAttributes &= ~MethodImplAttributes.PreserveSig;
else
dllImport.AddNamedArgument("PreserveSig", new PrimitiveExpression(false));
if (info.SupportsLastError)
dllImport.AddNamedArgument("SetLastError", new PrimitiveExpression(true));
if (info.IsThrowOnUnmappableCharDisabled)
dllImport.AddNamedArgument("ThrowOnUnmappableChar", new PrimitiveExpression(false));
if (info.IsThrowOnUnmappableCharEnabled)
dllImport.AddNamedArgument("ThrowOnUnmappableChar", new PrimitiveExpression(true));
attributedNode.Attributes.Add(new AttributeSection(dllImport));
}
#endregion
#region MethodImplAttribute
if (implAttributes != 0) {
Ast.Attribute methodImpl = CreateNonCustomAttribute(typeof(MethodImplAttribute));
TypeReference methodImplOptions = new TypeReference(
"System.Runtime.CompilerServices", "MethodImplOptions",
methodDefinition.Module, methodDefinition.Module.TypeSystem.Corlib);
methodImpl.Arguments.Add(MakePrimitive((long)implAttributes, methodImplOptions));
attributedNode.Attributes.Add(new AttributeSection(methodImpl));
}
#endregion
ConvertCustomAttributes(attributedNode, methodDefinition.MethodReturnType, AttributeTarget.Return);
if (methodDefinition.MethodReturnType.HasMarshalInfo) {
var marshalInfo = ConvertMarshalInfo(methodDefinition.MethodReturnType, methodDefinition.Module);
attributedNode.Attributes.Add(new AttributeSection(marshalInfo) { AttributeTarget = AttributeTarget.Return });
}
}
void ConvertAttributes(AttributedNode attributedNode, FieldDefinition fieldDefinition)
{
ConvertCustomAttributes(attributedNode, fieldDefinition);
#region FieldOffsetAttribute
if (fieldDefinition.HasLayoutInfo) {
Ast.Attribute fieldOffset = CreateNonCustomAttribute(typeof(FieldOffsetAttribute));
fieldOffset.Arguments.Add(new PrimitiveExpression(fieldDefinition.Offset));
attributedNode.Attributes.Add(new AttributeSection(fieldOffset));
}
#endregion
if (fieldDefinition.HasMarshalInfo) {
attributedNode.Attributes.Add(new AttributeSection(ConvertMarshalInfo(fieldDefinition, fieldDefinition.Module)));
}
}
#region MarshalAsAttribute (ConvertMarshalInfo)
static Ast.Attribute ConvertMarshalInfo(IMarshalInfoProvider marshalInfoProvider, ModuleDefinition module)
{
MarshalInfo marshalInfo = marshalInfoProvider.MarshalInfo;
Ast.Attribute attr = CreateNonCustomAttribute(typeof(MarshalAsAttribute), module);
string memberName;
if (marshalInfo.NativeType == NativeType.Boolean)
memberName = "Bool";
else
memberName = marshalInfo.NativeType.ToString();
attr.Arguments.Add(new IdentifierExpression("UnmanagedType").Member(memberName));
return attr;
}
#endregion
Ast.Attribute CreateNonCustomAttribute(Type attributeType)
{
return CreateNonCustomAttribute(attributeType, context.CurrentType != null ? context.CurrentType.Module : null);
}
static Ast.Attribute CreateNonCustomAttribute(Type attributeType, ModuleDefinition module)
{
Debug.Assert(attributeType.Name.EndsWith("Attribute", StringComparison.Ordinal));
Ast.Attribute attr = new Ast.Attribute();
attr.Type = new SimpleType(attributeType.Name.Substring(0, attributeType.Name.Length - "Attribute".Length));
if (module != null) {
attr.Type.AddAnnotation(new TypeReference(attributeType.Namespace, attributeType.Name, module, module.TypeSystem.Corlib));
}
return attr;
}
static void ConvertCustomAttributes(AstNode attributedNode, ICustomAttributeProvider customAttributeProvider, AttributeTarget target = AttributeTarget.None)
{
if (customAttributeProvider.HasCustomAttributes) {
@ -745,8 +891,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -745,8 +891,9 @@ namespace ICSharpCode.Decompiler.Ast
}
}
if (customAttribute.HasProperties) {
TypeDefinition resolvedAttributeType = customAttribute.AttributeType.Resolve();
foreach (var propertyNamedArg in customAttribute.Properties) {
var propertyReference = customAttribute.AttributeType.Resolve().Properties.First(pr => pr.Name == propertyNamedArg.Name);
var propertyReference = resolvedAttributeType != null ? resolvedAttributeType.Properties.FirstOrDefault(pr => pr.Name == propertyNamedArg.Name) : null;
var propertyName = new IdentifierExpression(propertyNamedArg.Name).WithAnnotation(propertyReference);
var argumentValue = ConvertArgumentValue(propertyNamedArg.Argument);
attribute.Arguments.Add(new AssignmentExpression(propertyName, argumentValue));
@ -754,8 +901,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -754,8 +901,9 @@ namespace ICSharpCode.Decompiler.Ast
}
if (customAttribute.HasFields) {
TypeDefinition resolvedAttributeType = customAttribute.AttributeType.Resolve();
foreach (var fieldNamedArg in customAttribute.Fields) {
var fieldReference = customAttribute.AttributeType.Resolve().Fields.First(f => f.Name == fieldNamedArg.Name);
var fieldReference = resolvedAttributeType != null ? resolvedAttributeType.Fields.FirstOrDefault(f => f.Name == fieldNamedArg.Name) : null;
var fieldName = new IdentifierExpression(fieldNamedArg.Name).WithAnnotation(fieldReference);
var argumentValue = ConvertArgumentValue(fieldNamedArg.Argument);
attribute.Arguments.Add(new AssignmentExpression(fieldName, argumentValue));
@ -780,7 +928,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -780,7 +928,7 @@ namespace ICSharpCode.Decompiler.Ast
}
}
}
private static Expression ConvertArgumentValue(CustomAttributeArgument parameter)
{
var type = parameter.Type.Resolve();
@ -802,7 +950,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -802,7 +950,7 @@ namespace ICSharpCode.Decompiler.Ast
}
return parameterValue;
}
#endregion
internal static Expression MakePrimitive(long val, TypeReference type)
{

5
ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs

@ -28,5 +28,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -28,5 +28,10 @@ namespace ICSharpCode.Decompiler.Ast
node.Remove();
return node;
}
public static void AddNamedArgument(this NRefactory.CSharp.Attribute attribute, string name, Expression argument)
{
attribute.Arguments.Add(new AssignmentExpression(new IdentifierExpression(name), argument));
}
}
}

4
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
@ -51,6 +52,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -51,6 +52,9 @@ namespace ICSharpCode.Decompiler.ILAst
// apply block transforms
foreach (var t in blockTransforms) {
t(block, ref i);
Debug.Assert(i <= block.Body.Count && i >= 0);
if (i == block.Body.Count) // special case: retry all transforms
break;
}
}
}

Loading…
Cancel
Save