diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index f8a29082aa5..9449e42459b 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.ComponentModel.Composition; using System.IO; using System.Linq; @@ -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; @@ -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; @@ -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 builder = new List(); + + 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 GetAttributes() => Enumerable.Empty(); + + + 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 signature) : IMethod + { + public IEnumerable GetReturnTypeAttributes() => Enumerable.Empty(); + + public bool ReturnTypeIsRefReadOnly => false; + public bool IsInitOnly => false; + public bool ThisIsRefReadOnly => false; + public IReadOnlyList TypeParameters { get; } + = Enumerable.Range(0, signature.GenericParameterCount) + .Select(DummyTypeParameter.GetMethodTypeParameter) + .ToImmutableList(); + public IReadOnlyList TypeArguments => Array.Empty(); + + 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? _parameters; + public IReadOnlyList 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 ExplicitlyImplementedInterfaceMembers => Array.Empty(); + 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 GetAttributes() => Enumerable.Empty(); + + 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; @@ -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; } diff --git a/ILSpy/TreeNodes/MemberReferenceTreeNode.cs b/ILSpy/TreeNodes/MemberReferenceTreeNode.cs index 5a2564ec7b6..c355502e64e 100644 --- a/ILSpy/TreeNodes/MemberReferenceTreeNode.cs +++ b/ILSpy/TreeNodes/MemberReferenceTreeNode.cs @@ -42,7 +42,7 @@ 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, @@ -50,7 +50,7 @@ public MemberReferenceTreeNode(PEFile module, MemberReference r) _ => 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) { diff --git a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs index cf9c8482072..9b87613c2e9 100644 --- a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs +++ b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs @@ -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];