Browse Source

update to latest code mappings

pull/219/head
Eusebiu Marcu 14 years ago
parent
commit
207af4eced
  1. 35
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 133
      ICSharpCode.Decompiler/CodeMappings.cs
  3. 34
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  4. 9
      ICSharpCode.Decompiler/PlainTextOutput.cs

35
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.Ast
IncludeTypeParameterDefinitions = 2
}
public class AstBuilder : ICodeMappings
public class AstBuilder : BaseCodeMappings
{
DecompilerContext context;
CompilationUnit astCompileUnit = new CompilationUnit();
@ -46,6 +46,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -46,6 +46,8 @@ namespace ICSharpCode.Decompiler.Ast
this.DecompileMethodBodies = true;
this.LocalVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>();
this.CodeMappings = new Dictionary<int, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<int, MemberReference>();
}
public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings)
@ -196,10 +198,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -196,10 +198,6 @@ namespace ICSharpCode.Decompiler.Ast
/// <returns>TypeDeclaration or DelegateDeclaration.</returns>
public AttributedNode CreateType(TypeDefinition typeDef)
{
// create CSharp code mappings - used for debugger
if (this.CodeMappings == null)
this.CodeMappings = new Tuple<string, List<MemberMapping>>(typeDef.FullName, new List<MemberMapping>());
// create type
TypeDefinition oldCurrentType = context.CurrentType;
context.CurrentType = typeDef;
@ -627,7 +625,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -627,7 +625,8 @@ namespace ICSharpCode.Decompiler.Ast
AttributedNode CreateMethod(MethodDefinition methodDef)
{
// Create mapping - used in debugger
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings);
CreateCodeMappings(methodDef.MetadataToken.ToInt32(), methodDef);
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[methodDef.MetadataToken.ToInt32()]);
MethodDeclaration astMethod = new MethodDeclaration().WithAnnotation(methodMapping);
astMethod.AddAnnotation(methodDef);
@ -715,7 +714,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -715,7 +714,8 @@ namespace ICSharpCode.Decompiler.Ast
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef)
{
// Create mapping - used in debugger
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings);
CreateCodeMappings(methodDef.MetadataToken.ToInt32(), methodDef);
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[methodDef.MetadataToken.ToInt32()]);
ConstructorDeclaration astMethod = new ConstructorDeclaration();
astMethod.AddAnnotation(methodDef);
@ -776,9 +776,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -776,9 +776,11 @@ namespace ICSharpCode.Decompiler.Ast
}
astProp.Name = CleanName(propDef.Name);
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) {
// Create mapping - used in debugger
MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings);
CreateCodeMappings(propDef.GetMethod.MetadataToken.ToInt32(), propDef);
MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings[propDef.GetMethod.MetadataToken.ToInt32()], propDef);
astProp.Getter = new Accessor();
astProp.Getter.Body = CreateMethodBody(propDef.GetMethod);
@ -792,7 +794,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -792,7 +794,8 @@ namespace ICSharpCode.Decompiler.Ast
}
if (propDef.SetMethod != null) {
// Create mapping - used in debugger
MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings);
CreateCodeMappings(propDef.SetMethod.MetadataToken.ToInt32(), propDef);
MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings[propDef.SetMethod.MetadataToken.ToInt32()], propDef);
astProp.Setter = new Accessor();
astProp.Setter.Body = CreateMethodBody(propDef.SetMethod);
@ -853,9 +856,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -853,9 +856,11 @@ namespace ICSharpCode.Decompiler.Ast
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
else
astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType);
if (eventDef.AddMethod != null) {
// Create mapping - used in debugger
MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings);
CreateCodeMappings(eventDef.AddMethod.MetadataToken.ToInt32(), eventDef);
MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings[eventDef.AddMethod.MetadataToken.ToInt32()], eventDef);
astEvent.AddAccessor = new Accessor {
Body = CreateMethodBody(eventDef.AddMethod)
@ -866,7 +871,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -866,7 +871,8 @@ namespace ICSharpCode.Decompiler.Ast
}
if (eventDef.RemoveMethod != null) {
// Create mapping - used in debugger
MemberMapping methodMapping = eventDef.RemoveMethod.CreateCodeMapping(this.CodeMappings);
CreateCodeMappings(eventDef.RemoveMethod.MetadataToken.ToInt32(), eventDef);
MemberMapping methodMapping = eventDef.RemoveMethod.CreateCodeMapping(this.CodeMappings[eventDef.RemoveMethod.MetadataToken.ToInt32()], eventDef);
astEvent.RemoveAccessor = new Accessor {
Body = CreateMethodBody(eventDef.RemoveMethod)
@ -895,6 +901,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -895,6 +901,8 @@ namespace ICSharpCode.Decompiler.Ast
FieldDeclaration CreateField(FieldDefinition fieldDef)
{
this.DecompiledMemberReferences.Add(fieldDef.MetadataToken.ToInt32(), fieldDef);
FieldDeclaration astField = new FieldDeclaration();
astField.AddAnnotation(fieldDef);
VariableInitializer initializer = new VariableInitializer(CleanName(fieldDef.Name));
@ -1451,11 +1459,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -1451,11 +1459,6 @@ namespace ICSharpCode.Decompiler.Ast
&& TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType));
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public Tuple<string, List<MemberMapping>> CodeMappings { get; private set; }
/// <summary>
/// Gets the local variables for the current decompiled type, method, etc.
/// <remarks>The key is the metadata token.</remarks>

133
ICSharpCode.Decompiler/CodeMappings.cs

@ -35,14 +35,36 @@ namespace ICSharpCode.Decompiler @@ -35,14 +35,36 @@ namespace ICSharpCode.Decompiler
}
/// <summary>
/// Interface for decompliler classes : AstBuilder & ReflectionDisassembler.
/// Base class for decompliler classes : AstBuilder & ReflectionDisassembler.
/// </summary>
public interface ICodeMappings
public abstract class BaseCodeMappings
{
/// <summary>
/// Gets the code mappings.
/// <remarks>Key is the metadata token.</remarks>
/// </summary>
Tuple<string, List<MemberMapping>> CodeMappings { get; }
public Dictionary<int, List<MemberMapping>> CodeMappings { get; protected set; }
/// <summary>
/// Gets the MembeReference that is decompiled (a MethodDefinition, PropertyDefinition etc.)
/// <remarks>Key is the metadata token.</remarks>
/// </summary>
public Dictionary<int, MemberReference> DecompiledMemberReferences { get; protected set; }
/// <summary>
/// Create data in the CodeMappings and DecompiledMemberReferences.
/// </summary>
/// <param name="token">Token of the current method.</param>
/// <param name="member">Current member (MethodDefinition, PropertyDefinition, EventDefinition).</param>
/// <remarks>The token is used in CodeMappings; member (and its token) is used in DecompiledMemberReferences.</remarks>
protected virtual void CreateCodeMappings(int token, MemberReference member)
{
this.CodeMappings.Add(token, new List<MemberMapping>());
int t = member.MetadataToken.ToInt32();
if (!this.DecompiledMemberReferences.ContainsKey(t))
this.DecompiledMemberReferences.Add(t, member);
}
}
/// <summary>
@ -112,9 +134,9 @@ namespace ICSharpCode.Decompiler @@ -112,9 +134,9 @@ namespace ICSharpCode.Decompiler
public MemberReference MemberReference { get; internal set; }
/// <summary>
/// Metadata token of the method.
/// Metadata token of the member.
/// </summary>
public uint MetadataToken { get; internal set; }
public int MetadataToken { get; internal set; }
/// <summary>
/// Gets or sets the code size for the member mapping.
@ -148,15 +170,17 @@ namespace ICSharpCode.Decompiler @@ -148,15 +170,17 @@ namespace ICSharpCode.Decompiler
/// Code mappings helper class.
/// </summary>
public static class CodeMappings
{
{
/// <summary>
/// Create code mapping for a method.
/// </summary>
/// <param name="method">Method to create the mapping for.</param>
/// <param name="sourceCodeMappings">Source code mapping storage.</param>
/// <param name="codeMappings">Source code mapping storage.</param>
/// <param name="actualMemberReference">The actual member reference.</param>
internal static MemberMapping CreateCodeMapping(
this MethodDefinition member,
Tuple<string, List<MemberMapping>> codeMappings)
List<MemberMapping> codeMappings,
MemberReference actualMemberReference = null)
{
if (member == null || !member.HasBody)
return null;
@ -166,17 +190,16 @@ namespace ICSharpCode.Decompiler @@ -166,17 +190,16 @@ namespace ICSharpCode.Decompiler
// create IL/CSharp code mappings - used in debugger
MemberMapping currentMemberMapping = null;
if (codeMappings.Item1 == member.DeclaringType.FullName) {
var mapping = codeMappings.Item2;
if (mapping.Find(map => (int)map.MetadataToken == member.MetadataToken.ToInt32()) == null) {
currentMemberMapping = new MemberMapping() {
MetadataToken = (uint)member.MetadataToken.ToInt32(),
MemberReference = member.DeclaringType.Resolve(),
MemberCodeMappings = new List<SourceCodeMapping>(),
CodeSize = member.Body.CodeSize
};
mapping.Add(currentMemberMapping);
}
if (codeMappings.Find(map => map.MetadataToken == member.MetadataToken.ToInt32()) == null) {
currentMemberMapping = new MemberMapping() {
MetadataToken = member.MetadataToken.ToInt32(),
MemberCodeMappings = new List<SourceCodeMapping>(),
MemberReference = actualMemberReference ?? member,
CodeSize = member.Body.CodeSize
};
codeMappings.Add(currentMemberMapping);
}
return currentMemberMapping;
@ -186,31 +209,19 @@ namespace ICSharpCode.Decompiler @@ -186,31 +209,19 @@ namespace ICSharpCode.Decompiler
/// Gets source code mapping and metadata token based on type name and line number.
/// </summary>
/// <param name="codeMappings">Code mappings storage.</param>
/// <param name="typeName">Type name.</param>
/// <param name="typeName">Member reference name.</param>
/// <param name="lineNumber">Line number.</param>
/// <param name="metadataToken">Metadata token.</param>
/// <returns></returns>
public static SourceCodeMapping GetInstructionByTypeAndLine(
this Tuple<string, List<MemberMapping>> codeMappings,
string memberReferenceName,
public static SourceCodeMapping GetInstructionByLineNumber(
this List<MemberMapping> codeMappings,
int lineNumber,
out uint metadataToken)
out int metadataToken)
{
if (codeMappings == null)
throw new ArgumentNullException("CodeMappings storage must be valid!");
throw new ArgumentException("CodeMappings storage must be valid!");
if (codeMappings.Item1 != memberReferenceName) {
metadataToken = 0;
return null;
}
if (lineNumber <= 0) {
metadataToken = 0;
return null;
}
var methodMappings = codeMappings.Item2;
foreach (var maping in methodMappings) {
foreach (var maping in codeMappings) {
var map = maping.MemberCodeMappings.Find(m => m.SourceCodeLine == lineNumber);
if (map != null) {
metadataToken = maping.MetadataToken;
@ -226,40 +237,32 @@ namespace ICSharpCode.Decompiler @@ -226,40 +237,32 @@ namespace ICSharpCode.Decompiler
/// Gets a mapping given a type, a token and an IL offset.
/// </summary>
/// <param name="codeMappings">Code mappings storage.</param>
/// <param name="typeName">Type name.</param>
/// <param name="token">Token.</param>
/// <param name="ilOffset">IL offset.</param>
/// <param name="isMatch">True, if perfect match.</param>
/// <returns>A code mapping.</returns>
public static SourceCodeMapping GetInstructionByTypeTokenAndOffset(
this Tuple<string, List<MemberMapping>> codeMappings,
string memberReferenceName,
uint token,
int ilOffset, out bool isMatch)
public static SourceCodeMapping GetInstructionByTokenAndOffset(
this List<MemberMapping> codeMappings,
int token,
int ilOffset,
out bool isMatch)
{
isMatch = false;
memberReferenceName = memberReferenceName.Replace("+", "/");
if (codeMappings == null)
throw new ArgumentNullException("CodeMappings storage must be valid!");
if (codeMappings.Item1 != memberReferenceName) {
return null;
}
var methodMappings = codeMappings.Item2;
var maping = methodMappings.Find(m => m.MetadataToken == token);
var maping = codeMappings.Find(m => m.MetadataToken == token);
if (maping == null) {
if (maping == null)
return null;
}
// try find an exact match
var map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To);
if (map == null) {
// get the immediate next one
map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From >= ilOffset);
map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From > ilOffset);
isMatch = false;
if (map == null)
map = maping.MemberCodeMappings.LastOrDefault(); // get the last
@ -275,38 +278,32 @@ namespace ICSharpCode.Decompiler @@ -275,38 +278,32 @@ namespace ICSharpCode.Decompiler
/// Gets the source code and type name from metadata token and offset.
/// </summary>
/// <param name="codeMappings">Code mappings storage.</param>
/// <param name="typeName">Current type name.</param>
/// <param name="token">Metadata token.</param>
/// <param name="ilOffset">IL offset.</param>
/// <param name="typeName">Type definition.</param>
/// <param name="line">Line number.</param>
/// <remarks>It is possible to exist to different types from different assemblies with the same metadata token.</remarks>
public static bool GetSourceCodeFromMetadataTokenAndOffset(
this Tuple<string, List<MemberMapping>> codeMappings,
string memberReferenceName,
uint token,
public static bool GetInstructionByTokenAndOffset(
this List<MemberMapping> codeMappings,
int token,
int ilOffset,
out MemberReference type,
out MemberReference member,
out int line)
{
type = null;
member = null;
line = 0;
if (codeMappings == null)
throw new ArgumentNullException("CodeMappings storage must be valid!");
memberReferenceName = memberReferenceName.Replace("+", "/");
if (codeMappings.Item1 != memberReferenceName)
return false;
throw new ArgumentException("CodeMappings storage must be valid!");
var mapping = codeMappings.Item2.Find(m => m.MetadataToken == token);
var mapping = codeMappings.Find(m => m.MetadataToken == token);
if (mapping == null)
return false;
var codeMapping = mapping.MemberCodeMappings.Find(
cm => cm.ILInstructionOffset.From <= ilOffset && ilOffset <= cm.ILInstructionOffset.To - 1);
if (codeMapping == null) {
codeMapping = mapping.MemberCodeMappings.Find(cm => (cm.ILInstructionOffset.From >= ilOffset));
codeMapping = mapping.MemberCodeMappings.Find(cm => cm.ILInstructionOffset.From > ilOffset);
if (codeMapping == null) {
codeMapping = mapping.MemberCodeMappings.LastOrDefault();
if (codeMapping == null)
@ -314,7 +311,7 @@ namespace ICSharpCode.Decompiler @@ -314,7 +311,7 @@ namespace ICSharpCode.Decompiler
}
}
type = mapping.MemberReference;
member = mapping.MemberReference;
line = codeMapping.SourceCodeLine;
return true;
}

34
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -28,13 +28,14 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -28,13 +28,14 @@ namespace ICSharpCode.Decompiler.Disassembler
/// <summary>
/// Disassembles type and member definitions.
/// </summary>
public sealed class ReflectionDisassembler : ICodeMappings
public sealed class ReflectionDisassembler : BaseCodeMappings
{
ITextOutput output;
CancellationToken cancellationToken;
bool detectControlStructure;
bool isInType; // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings)
MethodBodyDisassembler methodBodyDisassembler;
MemberReference currentMember;
public ReflectionDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken)
{
@ -44,6 +45,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -44,6 +45,9 @@ namespace ICSharpCode.Decompiler.Disassembler
this.cancellationToken = cancellationToken;
this.detectControlStructure = detectControlStructure;
this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken);
this.CodeMappings = new Dictionary<int, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<int, MemberReference>();
}
#region Disassemble Method
@ -94,6 +98,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -94,6 +98,9 @@ namespace ICSharpCode.Decompiler.Disassembler
public void DisassembleMethod(MethodDefinition method)
{
// set current member
currentMember = method;
// write method header
output.WriteDefinition(".method ", method);
DisassembleMethodInternal(method);
@ -118,7 +125,6 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -118,7 +125,6 @@ namespace ICSharpCode.Decompiler.Disassembler
//call convention
WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, callingConvention);
//return type
method.ReturnType.WriteTo(output);
output.Write(' ');
@ -149,7 +155,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -149,7 +155,9 @@ namespace ICSharpCode.Decompiler.Disassembler
if (method.HasBody) {
// create IL code mappings - used in debugger
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings);
CreateCodeMappings(method.MetadataToken.ToInt32(), currentMember);
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings[method.MetadataToken.ToInt32()], currentMember);
methodBodyDisassembler.Disassemble(method.Body, methodMapping);
}
@ -194,6 +202,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -194,6 +202,9 @@ namespace ICSharpCode.Decompiler.Disassembler
public void DisassembleField(FieldDefinition field)
{
// create mappings for decompiled fields only
this.DecompiledMemberReferences.Add(field.MetadataToken.ToInt32(), field);
output.WriteDefinition(".field ", field);
WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility);
WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | FieldAttributes.HasDefault), fieldAttributes);
@ -223,6 +234,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -223,6 +234,9 @@ namespace ICSharpCode.Decompiler.Disassembler
public void DisassembleProperty(PropertyDefinition property)
{
// set current member
currentMember = property;
output.WriteDefinition(".property ", property);
WriteFlags(property.Attributes, propertyAttributes);
property.PropertyType.WriteTo(output);
@ -232,6 +246,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -232,6 +246,7 @@ namespace ICSharpCode.Decompiler.Disassembler
WriteAttributes(property.CustomAttributes);
WriteNestedMethod(".get", property.GetMethod);
WriteNestedMethod(".set", property.SetMethod);
foreach (var method in property.OtherMethods) {
WriteNestedMethod(".method", method);
}
@ -263,6 +278,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -263,6 +278,9 @@ namespace ICSharpCode.Decompiler.Disassembler
public void DisassembleEvent(EventDefinition ev)
{
// set current member
currentMember = ev;
output.WriteDefinition(".event ", ev);
WriteFlags(ev.Attributes, eventAttributes);
ev.EventType.WriteTo(output);
@ -316,10 +334,6 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -316,10 +334,6 @@ namespace ICSharpCode.Decompiler.Disassembler
public void DisassembleType(TypeDefinition type)
{
// create IL code mappings - used for debugger
if (this.CodeMappings == null)
this.CodeMappings = new Tuple<string, List<MemberMapping>>(type.FullName, new List<MemberMapping>());
// start writing IL
output.WriteDefinition(".class ", type);
@ -604,11 +618,5 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -604,11 +618,5 @@ namespace ICSharpCode.Decompiler.Disassembler
WriteAttributes(asm.CustomAttributes);
CloseBlock();
}
/// <inheritdoc/>
public Tuple<string, List<MemberMapping>> CodeMappings {
get;
private set;
}
}
}

9
ICSharpCode.Decompiler/PlainTextOutput.cs

@ -26,22 +26,23 @@ namespace ICSharpCode.Decompiler @@ -26,22 +26,23 @@ namespace ICSharpCode.Decompiler
readonly TextWriter writer;
int indent;
bool needsIndent;
int lineNumber = 1;
public PlainTextOutput(TextWriter writer)
{
if (writer == null)
throw new ArgumentNullException("writer");
this.writer = writer;
CurrentLine = 1;
}
public PlainTextOutput()
{
this.writer = new StringWriter();
CurrentLine = 1;
}
public int CurrentLine { get; set; }
public int CurrentLine {
get { return lineNumber; }
}
public override string ToString()
{
@ -82,9 +83,9 @@ namespace ICSharpCode.Decompiler @@ -82,9 +83,9 @@ namespace ICSharpCode.Decompiler
public void WriteLine()
{
lineNumber++;
writer.WriteLine();
needsIndent = true;
++CurrentLine;
}
public void WriteDefinition(string text, object definition)

Loading…
Cancel
Save