Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
James May authored and siegfriedpammer committed Jan 20, 2024
1 parent eceb981 commit f4d21b5
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 5 deletions.
216 changes: 214 additions & 2 deletions ILSpy/Languages/CSharpLanguage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
Expand All @@ -38,6 +39,7 @@
using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
Expand Down Expand Up @@ -611,6 +613,76 @@ public override string EventToString(IEvent @event, bool includeDeclaringTypeNam
return EntityToString(@event, includeDeclaringTypeName, includeNamespace, includeNamespaceOfDeclaringTypeName);
}

private string ToCSharpString(PEFile module, MetadataReader metadata, MemberReferenceHandle handle, bool fullName, bool omitGenerics)
{
var md = metadata.GetMemberReference(handle);
var declaringTypeName = GetEntityName(module, md.Parent, fullName, omitGenerics);
string memberName = metadata.GetString(md.Name);

switch (md.GetKind())
{
case MemberReferenceKind.Method:


var methodSignature = md.DecodeMethodSignature(MetadataExtensions.MinimalSignatureTypeProvider, default);

return MethodToString(new MethodReferenceMethod(memberName, methodSignature), includeDeclaringTypeName: fullName, includeNamespace: fullName, includeNamespaceOfDeclaringTypeName: false);

switch (memberName)
{
case ".ctor":
case ".cctor":
memberName = GetEntityName(module, md.Parent, fullName: false, omitGenerics: omitGenerics);
break;
case "Finalize":
if ((methodSignature.Header.Attributes & SignatureAttributes.Instance) != SignatureAttributes.Instance)
goto default;
if (methodSignature.GenericParameterCount != 0 || methodSignature.ParameterTypes.Length != 0)
goto default;

memberName = "~" + declaringTypeName;
break;

default:
if (!omitGenerics && methodSignature.GenericParameterCount > 0)
{
memberName += "<";

for (int i = 1; i < methodSignature.GenericParameterCount; i++)
{
memberName += ",";
}

memberName += ">";
}
break;
}

memberName += "(";
memberName += string.Join(", ", methodSignature.ParameterTypes
.Where(paramType => paramType.Kind != TypeKind.TypeParameter)
.Select(paramType => TypeToString(paramType, includeNamespace: fullName))
);

memberName += ")";

memberName += " : " + TypeToString(methodSignature.ReturnType, fullName);
break;

case MemberReferenceKind.Field:
var fieldSignature = md.DecodeFieldSignature(MetadataExtensions.MinimalSignatureTypeProvider, default);
memberName += " : " + TypeToString(fieldSignature, fullName);
break;

default:
break;
}

if (fullName)
return declaringTypeName + "." + memberName;
return memberName;
}

static string ToCSharpString(MetadataReader metadata, TypeDefinitionHandle handle, bool fullName, bool omitGenerics)
{
var currentTypeDefHandle = handle;
Expand Down Expand Up @@ -664,6 +736,145 @@ static string ToCSharpString(MetadataReader metadata, TypeDefinitionHandle handl
}
}

static string ToCSharpString(MetadataReader metadata, TypeReferenceHandle handle, bool fullName, bool omitGenerics)
{
var currentTypeRefHandle = handle;
var typeRef = metadata.GetTypeReference(currentTypeRefHandle);
List<string> builder = new List<string>();

while (!currentTypeRefHandle.IsNil)
{
if (builder.Count > 0)
builder.Add(".");
typeRef = metadata.GetTypeReference(currentTypeRefHandle);
var part = ReflectionHelper.SplitTypeParameterCountFromReflectionName(metadata.GetString(typeRef.Name), out int typeParamCount);
if (!omitGenerics && typeParamCount > 0)
{
builder.Add(">");
for (int i = 0; i < typeParamCount; i++)
{
builder.Add(","); // a TypeRef doesn't name the parameters
}
builder.Add("<");
}
builder.Add(part);
currentTypeRefHandle = typeRef.GetDeclaringType();
if (!fullName)
break;
}

if (fullName && !typeRef.Namespace.IsNil)
{
builder.Add(".");
builder.Add(metadata.GetString(typeRef.Namespace));
}

return string.Concat(builder.AsEnumerable().Reverse());
}

sealed class MethodReferenceMethodParameter(IMethod method, IType type) : IParameter
{
public IEnumerable<IAttribute> GetAttributes() => Enumerable.Empty<IAttribute>();


public ReferenceKind ReferenceKind => default;
public LifetimeAnnotation Lifetime => default;
public bool IsRef => type.IsByRefLike;
public bool IsOut => ReferenceKind == ReferenceKind.Out;
public bool IsIn => ReferenceKind == ReferenceKind.In;
public bool IsParams => false;
public bool IsOptional => false;
public bool HasConstantValueInSignature => false;
public IParameterizedMember Owner => method;
public string Name => null;
public IType Type => type;
public bool IsConst => false;

public object GetConstantValue(bool throwOnInvalidMetadata = false)
{
throw new NotImplementedException();
}

public SymbolKind SymbolKind => type.Kind == TypeKind.TypeParameter ? SymbolKind.TypeParameter : SymbolKind.Parameter;
}


sealed class MethodReferenceMethod(string Name, MethodSignature<IType> signature) : IMethod
{
public IEnumerable<IAttribute> GetReturnTypeAttributes() => Enumerable.Empty<IAttribute>();

public bool ReturnTypeIsRefReadOnly => false;
public bool IsInitOnly => false;
public bool ThisIsRefReadOnly => false;
public IReadOnlyList<ITypeParameter> TypeParameters { get; }
= Enumerable.Range(0, signature.GenericParameterCount)
.Select(DummyTypeParameter.GetMethodTypeParameter)
.ToImmutableList();
public IReadOnlyList<IType> TypeArguments => Array.Empty<IType>();

public bool IsExtensionMethod => false;
public bool IsLocalFunction => false;
public bool IsConstructor => Name is ".ctor" or ".cctor";
public bool IsDestructor => Name.StartsWith("~", StringComparison.Ordinal);
public bool IsOperator => Name.StartsWith("op_", StringComparison.Ordinal);
public bool HasBody => false;
public bool IsAccessor => false;
public IMember AccessorOwner => null;
public MethodSemanticsAttributes AccessorKind => default;
public IMethod ReducedFrom => null;

public IMethod Specialize(TypeParameterSubstitution substitution)
=> throw new NotImplementedException();

IReadOnlyList<IParameter>? _parameters;
public IReadOnlyList<IParameter> Parameters => _parameters
??= signature.ParameterTypes.Select(t => new MethodReferenceMethodParameter(this, t)).ToImmutableList();

public IMember MemberDefinition => this;
public IType ReturnType => signature.ReturnType;
public IType DeclaringType => null; // TODO
public IEnumerable<IMember> ExplicitlyImplementedInterfaceMembers => Array.Empty<IMember>();
public bool IsExplicitInterfaceImplementation => false;
public bool IsVirtual => false;
public bool IsOverride => false;
public bool IsOverridable => false;
public TypeParameterSubstitution Substitution => TypeParameterSubstitution.Identity;

IMember IMember.Specialize(TypeParameterSubstitution substitution)
{
throw new NotImplementedException();
}

public bool Equals(IMember obj, TypeVisitor typeNormalization)
{
throw new NotImplementedException();
}

public EntityHandle MetadataToken { get; }
public string Name { get; } = Name;
public ITypeDefinition DeclaringTypeDefinition { get; }
public IModule ParentModule { get; }

public IEnumerable<IAttribute> GetAttributes() => Enumerable.Empty<IAttribute>();

public bool HasAttribute(KnownAttribute attribute) => false;

public IAttribute GetAttribute(KnownAttribute attribute)
{
throw new NotImplementedException();
}

public Decompiler.TypeSystem.Accessibility Accessibility { get; }
public bool IsStatic => !signature.Header.IsInstance;
public bool IsAbstract => false;
public bool IsSealed => false;
public SymbolKind SymbolKind => SymbolKind.Method;
public ICompilation Compilation { get; }
public string FullName => Name; // TODO
public string ReflectionName => Name; // TODO
public string Namespace { get; } // TOOD:
}

public override string GetEntityName(PEFile module, EntityHandle handle, bool fullName, bool omitGenerics)
{
MetadataReader metadata = module.Metadata;
Expand Down Expand Up @@ -731,10 +942,11 @@ public override string GetEntityName(PEFile module, EntityHandle handle, bool fu
return ToCSharpString(metadata, declaringType, fullName, omitGenerics) + "." + metadata.GetString(pd.Name);
return metadata.GetString(pd.Name);
case HandleKind.ExportedType:
return base.GetEntityName(module, handle, fullName: fullName, omitGenerics: omitGenerics);
case HandleKind.TypeReference:
return ToCSharpString(metadata, (TypeReferenceHandle)handle, fullName, omitGenerics);
case HandleKind.MemberReference:
// TODO: C# Implementation
return base.GetEntityName(module, handle, fullName: fullName, omitGenerics: omitGenerics);
return ToCSharpString(module, metadata, (MemberReferenceHandle)handle, fullName, omitGenerics);
default:
return null;
}
Expand Down
4 changes: 2 additions & 2 deletions ILSpy/TreeNodes/MemberReferenceTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ public MemberReferenceTreeNode(PEFile module, MemberReference r)
this.r = r;
}

public override object Text => r.Name + GetSuffixString(r.Handle);
public override object Text => Signature + GetSuffixString(r.Handle);

public override object Icon => r.MemberReferenceKind switch {
MemberReferenceKind.Method => Images.Method,
MemberReferenceKind.Field => Images.Field,
_ => Images.Class,
};

public string Signature => Language.GetEntityName(module, r.Handle, fullName: true, omitGenerics: false);
public string Signature => Language.GetEntityName(module, r.Handle, fullName: false, omitGenerics: false);

public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
Expand Down
1 change: 0 additions & 1 deletion ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ protected override void LoadChildren()
ImplMapTableTreeNode.ImplMap[] GetImplMap(MetadataReader metadata)
{
var length = metadata.GetTableRowCount(TableIndex.ImplMap);

var tableSpan = metadata.AsReadOnlySpan().Slice(metadata.GetTableMetadataOffset(TableIndex.ImplMap));
var reval = new ImplMapTableTreeNode.ImplMap[length];

Expand Down

0 comments on commit f4d21b5

Please sign in to comment.