From 802f6e54fd90389773310ee293b8439ee303cc80 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 23 Jun 2018 20:17:48 +0200 Subject: [PATCH] Refactor DecompilerTypeSystem.ResolveMethod(). --- .../CSharp/Resolver/ReducedExtensionMethod.cs | 14 +- .../CSharp/Syntax/TypeSystemAstBuilder.cs | 2 - .../ICSharpCode.Decompiler.csproj | 1 + .../Metadata/SignatureBlobComparer.cs | 2 +- .../TypeSystem/DecompilerTypeSystem.cs | 311 +++++++++--------- ICSharpCode.Decompiler/TypeSystem/IMethod.cs | 12 - .../Implementation/DefaultResolvedField.cs | 9 +- .../Implementation/DefaultResolvedMethod.cs | 22 +- .../TypeSystem/Implementation/FakeMember.cs | 166 ++++++++++ .../Implementation/MetadataTypeReference.cs | 26 +- .../Implementation/SpecializedField.cs | 14 +- .../Implementation/SpecializedMethod.cs | 23 +- .../TypeSystem/VarArgInstanceMethod.cs | 10 +- 13 files changed, 375 insertions(+), 237 deletions(-) create mode 100644 ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs b/ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs index aac351c75..b0910838e 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs @@ -177,19 +177,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver return baseMethod.IsOperator; } } - - public bool IsPartial { - get { - return baseMethod.IsPartial; - } - } - - public bool IsAsync { - get { - return baseMethod.IsAsync; - } - } - + public bool HasBody { get { return baseMethod.HasBody; diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs index cca707708..0ac002e06 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs @@ -1087,8 +1087,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { MethodDeclaration decl = new MethodDeclaration(); decl.Modifiers = GetMemberModifiers(method); - if (method.IsAsync && ShowModifiers) - decl.Modifiers |= Modifiers.Async; if (ShowAttributes) { decl.Attributes.AddRange (method.Attributes.Select ((a) => new AttributeSection (ConvertAttribute (a)))); decl.Attributes.AddRange (method.ReturnTypeAttributes.Select ((a) => new AttributeSection (ConvertAttribute (a)) { diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index a66dd3eb2..1bc1d4a49 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -339,6 +339,7 @@ + diff --git a/ICSharpCode.Decompiler/Metadata/SignatureBlobComparer.cs b/ICSharpCode.Decompiler/Metadata/SignatureBlobComparer.cs index 317d35383..556839487 100644 --- a/ICSharpCode.Decompiler/Metadata/SignatureBlobComparer.cs +++ b/ICSharpCode.Decompiler/Metadata/SignatureBlobComparer.cs @@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.Metadata for (; i < totalParameterCount; i++) { if (!IsSameCompressedInteger(ref a, ref b, out typeCode)) return false; - // + // varargs sentinel if (typeCode == 65) break; if (!TypesAreEqual(ref a, ref b, contextForA, contextForB, typeCode)) diff --git a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs index 4db17bf92..21a16d3a4 100644 --- a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2018 Daniel Grunwald +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; using System.Collections.Generic; using System.Linq; using SRM = System.Reflection.Metadata; @@ -190,23 +208,27 @@ namespace ICSharpCode.Decompiler.TypeSystem if (fieldReference.Kind != SRM.HandleKind.FieldDefinition && fieldReference.Kind != SRM.HandleKind.MemberReference) throw new ArgumentException("HandleKind must be either FieldDefinition or MemberReference", nameof(fieldReference)); lock (fieldLookupCache) { - IField field; - if (!fieldLookupCache.TryGetValue(fieldReference, out field)) { + if (!fieldLookupCache.TryGetValue(fieldReference, out IField field)) { var metadata = moduleDefinition.Metadata; IType declaringType; - ITypeReference returnType; switch (fieldReference.Kind) { case SRM.HandleKind.FieldDefinition: var fieldDefHandle = (SRM.FieldDefinitionHandle)fieldReference; var fieldDef = metadata.GetFieldDefinition(fieldDefHandle); declaringType = ResolveDeclaringType(fieldDef.GetDeclaringType()); - returnType = new FieldTypeReference(fieldDefHandle, metadata, typeAttributeOptions); var declaringTypeDefinition = declaringType.GetDefinition(); - if (declaringTypeDefinition == null) - field = CreateFakeField(declaringType, metadata.GetString(fieldDef.Name), returnType); - else { - field = declaringTypeDefinition.GetFields(f => f.MetadataToken == fieldReference, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault() - ?? CreateFakeField(declaringType, metadata.GetString(fieldDef.Name), returnType); + if (declaringTypeDefinition != null) { + field = declaringTypeDefinition.GetFields(f => f.MetadataToken == fieldReference, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); + } else { + field = null; + } + if (field == null) { + field = new FakeField(compilation) { + DeclaringType = declaringType, + Name = metadata.GetString(fieldDef.Name), + ReturnType = FieldTypeReference.Resolve(fieldDefHandle, metadata, context, typeAttributeOptions), + IsStatic = (fieldDef.Attributes & System.Reflection.FieldAttributes.Static) != 0 + }; } break; case SRM.HandleKind.MemberReference: @@ -233,38 +255,19 @@ namespace ICSharpCode.Decompiler.TypeSystem var memberRef = metadata.GetMemberReference(memberRefHandle); string name = metadata.GetString(memberRef.Name); ITypeDefinition typeDef = declaringType.GetDefinition(); - ITypeReference returnType = new FieldTypeReference(memberRefHandle, metadata, typeAttributeOptions); - - if (typeDef == null) - return CreateFakeField(declaringType, name, returnType); - foreach (IField field in typeDef.Fields) - if (field.Name == name) - return field; - return CreateFakeField(declaringType, name, returnType); - } - - IField CreateFakeField(IType declaringType, string name, ITypeReference returnType) - { - var f = new DefaultUnresolvedField(); - f.Name = name; - f.ReturnType = returnType; - return new ResolvedFakeField(f, context.WithCurrentTypeDefinition(declaringType.GetDefinition()), declaringType); - } - - class ResolvedFakeField : DefaultResolvedField - { - readonly IType declaringType; - - public ResolvedFakeField(DefaultUnresolvedField unresolved, ITypeResolveContext parentContext, IType declaringType) - : base(unresolved, parentContext) - { - this.declaringType = declaringType; - } - public override IType DeclaringType - { - get { return declaringType; } + if (typeDef != null) { + foreach (IField field in typeDef.Fields) { + if (field.Name == name) + return field; + } } + var returnType = memberRef.DecodeFieldSignature(new TypeProvider(context.CurrentAssembly), context); + return new FakeField(compilation) { + DeclaringType = declaringType, + Name = name, + ReturnType = returnType + }; } #endregion @@ -276,128 +279,138 @@ namespace ICSharpCode.Decompiler.TypeSystem if (methodReference.Kind != SRM.HandleKind.MethodDefinition && methodReference.Kind != SRM.HandleKind.MemberReference && methodReference.Kind != SRM.HandleKind.MethodSpecification) throw new ArgumentException("HandleKind must be either a MethodDefinition, MemberReference or MethodSpecification", nameof(methodReference)); lock (methodLookupCache) { - IMethod method; - IType declaringType; - IReadOnlyList classTypeArguments = null; - IReadOnlyList methodTypeArguments = null; - SRM.MethodSignature? signature = null; - if (!methodLookupCache.TryGetValue(methodReference, out method)) { + if (!methodLookupCache.TryGetValue(methodReference, out IMethod method)) { var metadata = moduleDefinition.Metadata; switch (methodReference.Kind) { case SRM.HandleKind.MethodDefinition: - var methodDef = metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)methodReference); - signature = methodDef.DecodeSignature(TypeReferenceSignatureDecoder.Instance, default); - method = FindNonGenericMethod(metadata, methodReference, out declaringType); + method = ResolveMethodDefinition(metadata, (SRM.MethodDefinitionHandle)methodReference); break; case SRM.HandleKind.MemberReference: - var memberRef = metadata.GetMemberReference((SRM.MemberReferenceHandle)methodReference); - Debug.Assert(memberRef.GetKind() == SRM.MemberReferenceKind.Method); - signature = memberRef.DecodeMethodSignature(TypeReferenceSignatureDecoder.Instance, default); - var elementMethod = methodReference; - if (memberRef.Parent.Kind == SRM.HandleKind.MethodDefinition) { - elementMethod = (SRM.MethodDefinitionHandle)memberRef.Parent; - } - method = FindNonGenericMethod(metadata, elementMethod, out declaringType); + method = ResolveMethodReference(metadata, (SRM.MemberReferenceHandle)methodReference); break; case SRM.HandleKind.MethodSpecification: var methodSpec = metadata.GetMethodSpecification((SRM.MethodSpecificationHandle)methodReference); - method = FindNonGenericMethod(metadata, methodSpec.Method, out declaringType); - var typeArguments = methodSpec.DecodeSignature(new TypeProvider(context.CurrentAssembly), default); - if (typeArguments.Length > 0) { - methodTypeArguments = typeArguments; + var methodTypeArgs = methodSpec.DecodeSignature(new TypeProvider(context.CurrentAssembly), context); + if (methodSpec.Method.Kind == SRM.HandleKind.MethodDefinition) { + // generic instance of a methoddef (=generic method in non-generic class in current assembly) + method = ResolveMethodDefinition(metadata, (SRM.MethodDefinitionHandle)methodSpec.Method); + method = method.Specialize(new TypeParameterSubstitution(null, methodTypeArgs)); + } else { + method = ResolveMethodReference(metadata, (SRM.MemberReferenceHandle)methodSpec.Method, methodTypeArgs); } break; default: throw new NotSupportedException(); } - if (signature?.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) { - method = new VarArgInstanceMethod(method, signature.Value.ParameterTypes.Skip(signature.Value.RequiredParameterCount).Select(p => p.Resolve(context))); - } - if (declaringType.TypeArguments.Count > 0) { - classTypeArguments = declaringType.TypeArguments.ToList(); - } - if (classTypeArguments != null || methodTypeArguments != null) { - method = method.Specialize(new TypeParameterSubstitution(classTypeArguments, methodTypeArguments)); - } - methodLookupCache.Add(methodReference, method); } return method; } } - IMethod FindNonGenericMethod(SRM.MetadataReader metadata, SRM.EntityHandle methodReference, out IType declaringType) + IMethod ResolveMethodDefinition(SRM.MetadataReader metadata, SRM.MethodDefinitionHandle methodDefHandle, bool expandVarArgs = true) { - ITypeDefinition declaringTypeDefinition; - string name; - switch (methodReference.Kind) { - case SRM.HandleKind.MethodDefinition: - var methodDef = metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)methodReference); - declaringType = ResolveDeclaringType(methodDef.GetDeclaringType()); - declaringTypeDefinition = declaringType.GetDefinition(); - if (declaringTypeDefinition == null) { - return CreateFakeMethod(declaringType, metadata.GetString(methodDef.Name), methodDef.DecodeSignature(TypeReferenceSignatureDecoder.Instance, default)); - } - name = metadata.GetString(methodDef.Name); - IMethod method; - if (name == ".ctor") { - method = declaringTypeDefinition.GetConstructors(m => m.MetadataToken == methodReference, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); - } else if (name == ".cctor") { - method = declaringTypeDefinition.Methods.FirstOrDefault(m => m.MetadataToken == methodReference); - } else { - method = declaringTypeDefinition.GetMethods(m => m.MetadataToken == methodReference, GetMemberOptions.IgnoreInheritedMembers) - .Concat(declaringTypeDefinition.GetAccessors(m => m.MetadataToken == methodReference, GetMemberOptions.IgnoreInheritedMembers)).FirstOrDefault(); - } - return method ?? CreateFakeMethod(declaringType, metadata.GetString(methodDef.Name), methodDef.DecodeSignature(TypeReferenceSignatureDecoder.Instance, default)); - case SRM.HandleKind.MemberReference: - var memberRef = metadata.GetMemberReference((SRM.MemberReferenceHandle)methodReference); - Debug.Assert(memberRef.GetKind() == SRM.MemberReferenceKind.Method); - // TODO : Support other handles - switch (memberRef.Parent.Kind) { - case SRM.HandleKind.MethodDefinition: - FindNonGenericMethod(metadata, memberRef.Parent, out declaringType); - break; - default: - declaringType = ResolveDeclaringType(memberRef.Parent); - break; - } - declaringTypeDefinition = declaringType.GetDefinition(); - var signature = memberRef.DecodeMethodSignature(TypeReferenceSignatureDecoder.Instance, default); - if (declaringTypeDefinition == null) { - return CreateFakeMethod(declaringType, metadata.GetString(memberRef.Name), signature); - } + var methodDef = metadata.GetMethodDefinition(methodDefHandle); + var declaringType = ResolveDeclaringType(methodDef.GetDeclaringType()); + var declaringTypeDefinition = declaringType.GetDefinition(); + string name = metadata.GetString(methodDef.Name); + IMethod method; + if (declaringTypeDefinition != null) { + if (name == ".ctor") { + method = declaringTypeDefinition.GetConstructors(m => m.MetadataToken == methodDefHandle, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); + } else if (name == ".cctor") { + method = declaringTypeDefinition.Methods.FirstOrDefault(m => m.MetadataToken == methodDefHandle); + } else { + method = declaringTypeDefinition.GetMethods(m => m.MetadataToken == methodDefHandle, GetMemberOptions.IgnoreInheritedMembers) + .Concat(declaringTypeDefinition.GetAccessors(m => m.MetadataToken == methodDefHandle, GetMemberOptions.IgnoreInheritedMembers)).FirstOrDefault(); + } + } else { + method = null; + } + if (method == null) { + var signature = methodDef.DecodeSignature(new TypeProvider(context.CurrentAssembly), + context.WithCurrentTypeDefinition(declaringTypeDefinition)); + method = CreateFakeMethod(declaringType, metadata.GetString(methodDef.Name), signature); + } + if (expandVarArgs && method.Parameters.LastOrDefault()?.Type.Kind == TypeKind.ArgList) { + method = new VarArgInstanceMethod(method, EmptyList.Instance); + } + return method; + } + + /// + /// Resolves a method reference. + /// + /// + /// Class type arguments are provided by the declaring type stored in the memberRef. + /// Method type arguments are provided by the caller. + /// + IMethod ResolveMethodReference(SRM.MetadataReader metadata, SRM.MemberReferenceHandle memberRefHandle, IReadOnlyList methodTypeArguments = null) + { + var memberRef = metadata.GetMemberReference(memberRefHandle); + Debug.Assert(memberRef.GetKind() == SRM.MemberReferenceKind.Method); + SRM.MethodSignature signature; + IReadOnlyList classTypeArguments = null; + IMethod method; + if (memberRef.Parent.Kind == SRM.HandleKind.MethodDefinition) { + method = ResolveMethodDefinition(metadata, (SRM.MethodDefinitionHandle)memberRef.Parent, expandVarArgs: false); + signature = memberRef.DecodeMethodSignature(new TypeProvider(context.CurrentAssembly), context); + } else { + var declaringType = ResolveDeclaringType(memberRef.Parent); + var declaringTypeDefinition = declaringType.GetDefinition(); + if (declaringType.TypeArguments.Count > 0) { + classTypeArguments = declaringType.TypeArguments; + } + // Note: declaringType might be parameterized, but the signature is for the original method definition. + // We'll have to search the member directly on declaringTypeDefinition. + string name = metadata.GetString(memberRef.Name); + signature = memberRef.DecodeMethodSignature(new TypeProvider(context.CurrentAssembly), + context.WithCurrentTypeDefinition(declaringTypeDefinition)); + if (declaringTypeDefinition != null) { + // Find the set of overloads to search: IEnumerable methods; - name = metadata.GetString(memberRef.Name); if (name == ".ctor") { methods = declaringTypeDefinition.GetConstructors(); } else if (name == ".cctor") { - return declaringTypeDefinition.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic); + methods = declaringTypeDefinition.Methods.Where(m => m.IsConstructor && m.IsStatic); } else { methods = declaringTypeDefinition.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers) .Concat(declaringTypeDefinition.GetAccessors(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers)); } - IType[] parameterTypes; + // Determine the expected parameters from the signature: + ImmutableArray parameterTypes; if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) { parameterTypes = signature.ParameterTypes .Take(signature.RequiredParameterCount) - .Select(p => p.Resolve(context)) .Concat(new[] { SpecialType.ArgList }) - .ToArray(); + .ToImmutableArray(); } else { - parameterTypes = signature.ParameterTypes.SelectArray(p => p.Resolve(context)); + parameterTypes = signature.ParameterTypes; } - var returnType = signature.ReturnType.Resolve(context); + // Search for the matching method: + method = null; foreach (var m in methods) { if (m.TypeParameters.Count != signature.GenericParameterCount) continue; - if (!CompareSignatures(m.Parameters, parameterTypes) || !CompareTypes(m.ReturnType, returnType)) - continue; - return m; + if (CompareSignatures(m.Parameters, parameterTypes) && CompareTypes(m.ReturnType, signature.ReturnType)) { + method = m; + break; + } } - return CreateFakeMethod(declaringType, metadata.GetString(memberRef.Name), signature); - default: - throw new NotSupportedException(); + } else { + method = null; + } + if (method == null) { + method = CreateFakeMethod(declaringType, name, signature); + } } + if (classTypeArguments != null || methodTypeArguments != null) { + method = method.Specialize(new TypeParameterSubstitution(classTypeArguments, methodTypeArguments)); + } + if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) { + method = new VarArgInstanceMethod(method, signature.ParameterTypes.Skip(signature.RequiredParameterCount)); + } + return method; } static readonly NormalizeTypeVisitor normalizeTypeVisitor = new NormalizeTypeVisitor { @@ -417,7 +430,7 @@ namespace ICSharpCode.Decompiler.TypeSystem return method.Parameters.Count > 0 && method.Parameters[method.Parameters.Count - 1].Type.Kind == TypeKind.ArgList; } - static bool CompareSignatures(IReadOnlyList parameters, IType[] parameterTypes) + static bool CompareSignatures(IReadOnlyList parameters, ImmutableArray parameterTypes) { if (parameterTypes.Length != parameters.Count) return false; @@ -431,40 +444,38 @@ namespace ICSharpCode.Decompiler.TypeSystem /// /// Create a dummy IMethod from the specified MethodReference /// - IMethod CreateFakeMethod(IType declaringType, string name, SRM.MethodSignature signature) + IMethod CreateFakeMethod(IType declaringType, string name, SRM.MethodSignature signature) { - var m = new DefaultUnresolvedMethod(); + SymbolKind symbolKind = SymbolKind.Method; if (name == ".ctor" || name == ".cctor") - m.SymbolKind = SymbolKind.Constructor; + symbolKind = SymbolKind.Constructor; + var m = new FakeMethod(compilation, symbolKind); + m.DeclaringType = declaringType; m.Name = name; - m.MetadataToken = default(SRM.MethodDefinitionHandle); m.ReturnType = signature.ReturnType; m.IsStatic = !signature.Header.IsInstance; - - var metadata = moduleDefinition.Metadata; - for (int i = 0; i < signature.GenericParameterCount; i++) { - m.TypeParameters.Add(new DefaultUnresolvedTypeParameter(SymbolKind.Method, i, "")); - } - for (int i = 0; i < signature.ParameterTypes.Length; i++) { - m.Parameters.Add(new DefaultUnresolvedParameter(signature.ParameterTypes[i], "")); - } - return new ResolvedFakeMethod(m, context.WithCurrentTypeDefinition(declaringType.GetDefinition()), declaringType); - } - - class ResolvedFakeMethod : DefaultResolvedMethod - { - readonly IType declaringType; - public ResolvedFakeMethod(DefaultUnresolvedMethod unresolved, ITypeResolveContext parentContext, IType declaringType) - : base(unresolved, parentContext) - { - this.declaringType = declaringType; + var metadata = moduleDefinition.Metadata; + TypeParameterSubstitution substitution = null; + if (signature.GenericParameterCount > 0) { + var typeParameters = new List(); + for (int i = 0; i < signature.GenericParameterCount; i++) { + typeParameters.Add(new DefaultTypeParameter(m, i)); + } + m.TypeParameters = typeParameters; + substitution = new TypeParameterSubstitution(null, typeParameters); } - - public override IType DeclaringType - { - get { return declaringType; } + var parameters = new List(); + for (int i = 0; i < signature.RequiredParameterCount; i++) { + var type = signature.ParameterTypes[i]; + if (substitution != null) { + // replace the dummy method type parameters with the owned instances we just created + type = type.AcceptVisitor(substitution); + } + parameters.Add(new DefaultParameter(type, "")); } + m.Parameters = parameters; + return m; } #endregion diff --git a/ICSharpCode.Decompiler/TypeSystem/IMethod.cs b/ICSharpCode.Decompiler/TypeSystem/IMethod.cs index 38c57d2f6..be826eb32 100644 --- a/ICSharpCode.Decompiler/TypeSystem/IMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/IMethod.cs @@ -105,18 +105,6 @@ namespace ICSharpCode.Decompiler.TypeSystem bool IsDestructor { get; } bool IsOperator { get; } - /// - /// Gets whether the method is a C#-style partial method. - /// A call to such a method is ignored by the compiler if the partial method has no body. - /// - /// - bool IsPartial { get; } - - /// - /// Gets whether the method is a C#-style async method. - /// - bool IsAsync { get; } - /// /// Gets whether the method has a body. /// This property returns false for abstract or extern methods, diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedField.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedField.cs index f0f8cba79..b76499b56 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedField.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedField.cs @@ -72,14 +72,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public override IMember Specialize(TypeParameterSubstitution substitution) { - if (TypeParameterSubstitution.Identity.Equals(substitution) - || DeclaringType.TypeParameterCount == 0) - { - return this; - } - if (substitution.MethodTypeArguments != null && substitution.MethodTypeArguments.Count > 0) - substitution = new TypeParameterSubstitution(substitution.ClassTypeArguments, EmptyList.Instance); - return new SpecializedField(this, substitution); + return SpecializedField.Create(this, substitution); } } } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedMethod.cs index 130356be8..825fc28a9 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultResolvedMethod.cs @@ -198,14 +198,6 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation get { return ((IUnresolvedMethod)unresolved).IsOperator; } } - public bool IsPartial { - get { return ((IUnresolvedMethod)unresolved).IsPartial; } - } - - public bool IsAsync { - get { return ((IUnresolvedMethod)unresolved).IsAsync; } - } - public bool HasBody { get { return ((IUnresolvedMethod)unresolved).HasBody; } } @@ -230,22 +222,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public override IMember Specialize(TypeParameterSubstitution substitution) { - if (TypeParameterSubstitution.Identity.Equals(substitution)) - return this; - if (DeclaringType is ArrayType) - return new SpecializedMethod(this, substitution); - if (TypeParameters.Count == 0) { - if (DeclaringType.TypeParameterCount == 0) - return this; - if (substitution.MethodTypeArguments != null && substitution.MethodTypeArguments.Count > 0) - substitution = new TypeParameterSubstitution(substitution.ClassTypeArguments, EmptyList.Instance); - } - return new SpecializedMethod(this, substitution); + return SpecializedMethod.Create(this, substitution); } IMethod IMethod.Specialize(TypeParameterSubstitution substitution) { - return (IMethod)Specialize(substitution); + return SpecializedMethod.Create(this, substitution); } public override string ToString() diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs new file mode 100644 index 000000000..a67986d41 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs @@ -0,0 +1,166 @@ +// Copyright (c) 2018 Daniel Grunwald +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Reflection.Metadata; +using ICSharpCode.Decompiler.Util; + +namespace ICSharpCode.Decompiler.TypeSystem.Implementation +{ + /// + /// Base class for fake members. + /// + abstract class FakeMember : IMember + { + readonly ICompilation compilation; + + protected FakeMember(ICompilation compilation) + { + this.compilation = compilation ?? throw new ArgumentNullException(nameof(compilation)); + } + + IMember IMember.MemberDefinition => this; + + public IType ReturnType { get; set; } = SpecialType.UnknownType; + + IReadOnlyList IMember.ImplementedInterfaceMembers => EmptyList.Instance; + + bool IMember.IsExplicitInterfaceImplementation => false; + + bool IMember.IsVirtual => false; + bool IMember.IsOverride => false; + bool IMember.IsOverridable => false; + + TypeParameterSubstitution IMember.Substitution => TypeParameterSubstitution.Identity; + EntityHandle IEntity.MetadataToken => default; + + public string Name { get; set; } + + ITypeDefinition IEntity.DeclaringTypeDefinition => DeclaringType?.GetDefinition(); + + public IType DeclaringType { get; set; } + + IAssembly IEntity.ParentAssembly => DeclaringType?.GetDefinition()?.ParentAssembly; + + IReadOnlyList IEntity.Attributes => EmptyList.Instance; + + Accessibility IEntity.Accessibility => Accessibility.Public; + + public bool IsStatic { get; set; } + bool IEntity.IsAbstract => false; + bool IEntity.IsSealed => false; + bool IEntity.IsShadowing => false; + + public abstract SymbolKind SymbolKind { get; } + + ICompilation ICompilationProvider.Compilation => compilation; + + string INamedElement.FullName { + get { + if (DeclaringType != null) + return DeclaringType.FullName + "." + Name; + else + return Name; + } + } + + string INamedElement.ReflectionName { + get { + if (DeclaringType != null) + return DeclaringType.ReflectionName + "." + Name; + else + return Name; + } + } + + string INamedElement.Namespace => DeclaringType?.Namespace; + + bool IMember.Equals(IMember obj, TypeVisitor typeNormalization) + { + return Equals(obj); + } + + public abstract IMember Specialize(TypeParameterSubstitution substitution); + } + + class FakeField : FakeMember, IField + { + public FakeField(ICompilation compilation) : base(compilation) + { + } + + bool IField.IsReadOnly => false; + bool IField.IsVolatile => false; + bool IField.IsFixed => false; + + bool IVariable.IsConst => false; + object IVariable.ConstantValue => null; + IType IVariable.Type => ReturnType; + + public override SymbolKind SymbolKind => SymbolKind.Field; + + public override IMember Specialize(TypeParameterSubstitution substitution) + { + return SpecializedField.Create(this, substitution); + } + } + + class FakeMethod : FakeMember, IMethod + { + readonly SymbolKind symbolKind; + + public FakeMethod(ICompilation compilation, SymbolKind symbolKind) : base(compilation) + { + this.symbolKind = symbolKind; + } + + public override SymbolKind SymbolKind => symbolKind; + + IReadOnlyList IMethod.Parts => throw new NotImplementedException(); + + IReadOnlyList IMethod.ReturnTypeAttributes => EmptyList.Instance; + + public IReadOnlyList TypeParameters { get; set; } = EmptyList.Instance; + + IReadOnlyList IMethod.TypeArguments => TypeParameters; + + bool IMethod.IsExtensionMethod => false; + bool IMethod.IsConstructor => symbolKind == SymbolKind.Constructor; + bool IMethod.IsDestructor => symbolKind == SymbolKind.Destructor; + bool IMethod.IsOperator => symbolKind == SymbolKind.Operator; + + bool IMethod.HasBody => false; + bool IMethod.IsAccessor => false; + IMember IMethod.AccessorOwner => null; + + IMethod IMethod.ReducedFrom => null; + + public IReadOnlyList Parameters { get; set; } = EmptyList.Instance; + + public override IMember Specialize(TypeParameterSubstitution substitution) + { + return SpecializedMethod.Create(this, substitution); + } + + IMethod IMethod.Specialize(TypeParameterSubstitution substitution) + { + return SpecializedMethod.Create(this, substitution); + } + } +} diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeReference.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeReference.cs index 53489636c..60fb3f19f 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeReference.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeReference.cs @@ -34,8 +34,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public MetadataTypeReference(SRM.EntityHandle type, SRM.MetadataReader metadata, - SRM.CustomAttributeHandleCollection? typeAttributes = null, - TypeAttributeOptions attributeOptions = TypeAttributeOptions.Default) + SRM.CustomAttributeHandleCollection? typeAttributes, + TypeAttributeOptions attributeOptions) { this.type = type; this.metadata = metadata; @@ -52,8 +52,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public static IType Resolve(SRM.EntityHandle type, SRM.MetadataReader metadata, ITypeResolveContext context, - SRM.CustomAttributeHandleCollection? typeAttributes = null, - TypeAttributeOptions attributeOptions = TypeAttributeOptions.Default) + SRM.CustomAttributeHandleCollection? typeAttributes, + TypeAttributeOptions attributeOptions) { if (type.IsNil) return SpecialType.UnknownType; @@ -89,7 +89,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public FieldTypeReference(SRM.FieldDefinitionHandle fieldHandle, SRM.MetadataReader metadata, - TypeAttributeOptions attributeOptions = TypeAttributeOptions.Default) + TypeAttributeOptions attributeOptions) { this.fieldHandle = fieldHandle; this.metadata = metadata; @@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public FieldTypeReference(SRM.MemberReferenceHandle fieldReferenceHandle, SRM.MetadataReader metadata, - TypeAttributeOptions attributeOptions = TypeAttributeOptions.Default) + TypeAttributeOptions attributeOptions) { this.fieldHandle = fieldReferenceHandle; this.metadata = metadata; @@ -121,7 +121,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public static IType Resolve(SRM.FieldDefinitionHandle fieldHandle, SRM.MetadataReader metadata, ITypeResolveContext context, - TypeAttributeOptions attributeOptions = TypeAttributeOptions.Default) + TypeAttributeOptions attributeOptions) { var fieldDef = metadata.GetFieldDefinition(fieldHandle); IType ty = fieldDef.DecodeSignature(new TypeProvider(context.CurrentAssembly), context); @@ -141,7 +141,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation readonly TypeAttributeOptions attributeOptions; public UnresolvedMethodSignature(SRM.MethodDefinitionHandle handle, SRM.MetadataReader metadata, - TypeAttributeOptions attributeOptions = TypeAttributeOptions.Default) + TypeAttributeOptions attributeOptions) { this.handle = handle; this.metadata = metadata; @@ -149,7 +149,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation } public UnresolvedMethodSignature(SRM.PropertyDefinitionHandle handle, SRM.MetadataReader metadata, - TypeAttributeOptions attributeOptions = TypeAttributeOptions.Default) + TypeAttributeOptions attributeOptions) { this.handle = handle; this.metadata = metadata; @@ -165,12 +165,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation case SRM.HandleKind.MethodDefinition: return GetSignature( metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)handle), - metadata, context + metadata, context, attributeOptions ); case SRM.HandleKind.PropertyDefinition: return GetSignature( metadata.GetPropertyDefinition((SRM.PropertyDefinitionHandle)handle), - metadata, context + metadata, context, attributeOptions ); default: throw new InvalidOperationException(); @@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public static SRM.MethodSignature GetSignature(SRM.MethodDefinition methodDef, SRM.MetadataReader metadata, ITypeResolveContext context, - TypeAttributeOptions attributeOptions = TypeAttributeOptions.Default) + TypeAttributeOptions attributeOptions) { var typeProvider = new TypeProvider(context.CurrentAssembly); var signature = methodDef.DecodeSignature(typeProvider, context); @@ -190,7 +190,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public static SRM.MethodSignature GetSignature(SRM.PropertyDefinition propertyDef, SRM.MetadataReader metadata, ITypeResolveContext context, - TypeAttributeOptions attributeOptions = TypeAttributeOptions.Default) + TypeAttributeOptions attributeOptions) { var typeProvider = new TypeProvider(context.CurrentAssembly); var signature = propertyDef.DecodeSignature(typeProvider, context); diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedField.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedField.cs index 762f95117..986757f92 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedField.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedField.cs @@ -16,6 +16,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using ICSharpCode.Decompiler.Util; + namespace ICSharpCode.Decompiler.TypeSystem.Implementation { /// @@ -23,6 +25,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation /// public class SpecializedField : SpecializedMember, IField { + internal static IField Create(IField fieldDefinition, TypeParameterSubstitution substitution) + { + if (TypeParameterSubstitution.Identity.Equals(substitution) || fieldDefinition.DeclaringType.TypeParameterCount == 0) { + return fieldDefinition; + } + if (substitution.MethodTypeArguments != null && substitution.MethodTypeArguments.Count > 0) + substitution = new TypeParameterSubstitution(substitution.ClassTypeArguments, EmptyList.Instance); + return new SpecializedField(fieldDefinition, substitution); + } + readonly IField fieldDefinition; public SpecializedField(IField fieldDefinition, TypeParameterSubstitution substitution) @@ -31,7 +43,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation this.fieldDefinition = fieldDefinition; AddSubstitution(substitution); } - + public bool IsReadOnly { get { return fieldDefinition.IsReadOnly; } } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs index b5e23c2bc..30689c772 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs @@ -29,6 +29,21 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation /// public class SpecializedMethod : SpecializedParameterizedMember, IMethod { + internal static IMethod Create(IMethod methodDefinition, TypeParameterSubstitution substitution) + { + if (TypeParameterSubstitution.Identity.Equals(substitution)) + return methodDefinition; + if (methodDefinition.DeclaringType is ArrayType) + return new SpecializedMethod(methodDefinition, substitution); + if (methodDefinition.TypeParameters.Count == 0) { + if (methodDefinition.DeclaringType.TypeParameterCount == 0) + return methodDefinition; + if (substitution.MethodTypeArguments != null && substitution.MethodTypeArguments.Count > 0) + substitution = new TypeParameterSubstitution(substitution.ClassTypeArguments, EmptyList.Instance); + } + return new SpecializedMethod(methodDefinition, substitution); + } + readonly IMethod methodDefinition; readonly ITypeParameter[] specializedTypeParameters; readonly bool isParameterized; @@ -108,14 +123,6 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation get { return methodDefinition.IsOperator; } } - public bool IsPartial { - get { return methodDefinition.IsPartial; } - } - - public bool IsAsync { - get { return methodDefinition.IsAsync; } - } - public bool HasBody { get { return methodDefinition.HasBody; } } diff --git a/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs b/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs index 66a766d55..e8eec0c98 100644 --- a/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs @@ -143,15 +143,7 @@ namespace ICSharpCode.Decompiler.TypeSystem public bool IsOperator { get { return baseMethod.IsOperator; } } - - public bool IsPartial { - get { return baseMethod.IsPartial; } - } - - public bool IsAsync { - get { return baseMethod.IsAsync; } - } - + public bool HasBody { get { return baseMethod.HasBody; } }