mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
5.1 KiB
158 lines
5.1 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Collections.Immutable; |
|
using System.Diagnostics; |
|
using System.Linq; |
|
using System.Reflection.Metadata; |
|
using ICSharpCode.Decompiler.CSharp.Syntax; |
|
using ICSharpCode.Decompiler.Metadata; |
|
using ICSharpCode.Decompiler.Util; |
|
|
|
using FullTypeName = ICSharpCode.Decompiler.TypeSystem.FullTypeName; |
|
using TopLevelTypeName = ICSharpCode.Decompiler.TypeSystem.TopLevelTypeName; |
|
|
|
namespace ICSharpCode.Decompiler.CSharp |
|
{ |
|
[Flags] |
|
public enum ConvertTypeOptions |
|
{ |
|
None = 0, |
|
IncludeNamespace = 1, |
|
IncludeTypeParameterDefinitions = 2, |
|
DoNotUsePrimitiveTypeNames = 4, |
|
IncludeOuterTypeName = 8, |
|
} |
|
|
|
public class AstTypeBuilder : ISignatureTypeProvider<AstType, GenericContext> |
|
{ |
|
readonly ConvertTypeOptions options; |
|
|
|
public AstTypeBuilder(ConvertTypeOptions options) |
|
{ |
|
this.options = options; |
|
} |
|
|
|
public AstType GetArrayType(AstType elementType, ArrayShape shape) |
|
{ |
|
return elementType.MakeArrayType(shape.Rank); |
|
} |
|
|
|
public AstType GetByReferenceType(AstType elementType) |
|
{ |
|
return elementType.MakeRefType(); |
|
} |
|
|
|
public AstType GetFunctionPointerType(MethodSignature<AstType> signature) |
|
{ |
|
if ((options & ConvertTypeOptions.IncludeNamespace) == 0) |
|
return AstType.Create("IntPtr"); |
|
return AstType.Create("System.IntPtr"); |
|
} |
|
|
|
static readonly FullTypeName systemNullable = new TopLevelTypeName("System", "Nullable", 1); |
|
|
|
public AstType GetGenericInstantiation(AstType genericType, ImmutableArray<AstType> typeArguments) |
|
{ |
|
var typeName = genericType.Annotations.OfType<FullTypeName>().FirstOrDefault(); |
|
if (typeName == systemNullable && typeArguments.Length == 1) { |
|
return typeArguments[0].MakeNullableType(); |
|
} |
|
if (typeName.IsNested && genericType is MemberType mt && typeArguments.Length > typeName.TypeParameterCount) { |
|
// Some type arguments belong to the outer type: |
|
int outerTpc = typeArguments.Length - typeName.TypeParameterCount; |
|
Debug.Assert(outerTpc > 0); |
|
GetGenericInstantiation(mt.Target, typeArguments.Slice(0, outerTpc).ToImmutableArray()); |
|
foreach (var ta in typeArguments.Slice(typeArguments.Length - typeName.TypeParameterCount)) { |
|
mt.AddChild(ta, Roles.TypeArgument); |
|
} |
|
} else { |
|
foreach (var ta in typeArguments) { |
|
genericType.AddChild(ta, Roles.TypeArgument); |
|
} |
|
} |
|
return genericType; |
|
} |
|
|
|
public AstType GetGenericMethodParameter(GenericContext genericContext, int index) |
|
{ |
|
return new SimpleType(genericContext.GetGenericMethodTypeParameterName(index)); |
|
} |
|
|
|
public AstType GetGenericTypeParameter(GenericContext genericContext, int index) |
|
{ |
|
return new SimpleType(genericContext.GetGenericTypeParameterName(index)); |
|
} |
|
|
|
public AstType GetModifiedType(AstType modifier, AstType unmodifiedType, bool isRequired) |
|
{ |
|
return unmodifiedType; |
|
} |
|
|
|
public AstType GetPinnedType(AstType elementType) |
|
{ |
|
return elementType; |
|
} |
|
|
|
public AstType GetPointerType(AstType elementType) |
|
{ |
|
return elementType.MakePointerType(); |
|
} |
|
|
|
public AstType GetPrimitiveType(PrimitiveTypeCode typeCode) |
|
{ |
|
var knownTypeCode = typeCode.ToKnownTypeCode(); |
|
var ktr = Decompiler.TypeSystem.KnownTypeReference.Get(knownTypeCode); |
|
if ((options & ConvertTypeOptions.DoNotUsePrimitiveTypeNames) == 0) { |
|
string keyword = Decompiler.TypeSystem.KnownTypeReference.GetCSharpNameByTypeCode(knownTypeCode); |
|
if (keyword != null) |
|
return new PrimitiveType(keyword); |
|
} |
|
if ((options & ConvertTypeOptions.IncludeNamespace) == 0) |
|
return new SimpleType(ktr.Name); |
|
return AstType.Create(ktr.Namespace).MemberType(ktr.Name); |
|
} |
|
|
|
public AstType GetSZArrayType(AstType elementType) |
|
{ |
|
return elementType.MakeArrayType(); |
|
} |
|
|
|
public AstType GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) |
|
{ |
|
return MakeAstType(handle.GetFullTypeName(reader)); |
|
} |
|
|
|
public AstType GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) |
|
{ |
|
return MakeAstType(handle.GetFullTypeName(reader)); |
|
} |
|
|
|
public AstType GetTypeFromSpecification(MetadataReader reader, GenericContext genericContext, TypeSpecificationHandle handle, byte rawTypeKind) |
|
{ |
|
var ts = reader.GetTypeSpecification(handle); |
|
return ts.DecodeSignature(this, genericContext); |
|
} |
|
|
|
AstType MakeAstType(FullTypeName fullTypeName) |
|
{ |
|
if (fullTypeName.IsNested) { |
|
int count = fullTypeName.GetNestedTypeAdditionalTypeParameterCount(fullTypeName.NestingLevel - 1); |
|
var outerType = MakeAstType(fullTypeName.GetDeclaringType()); |
|
// Note: we must always emit the outer type name here; |
|
// if not desired it can only be cleaned up after InsertDynamicTypeVisitor. |
|
var nestedType = new MemberType(outerType, fullTypeName.Name); |
|
nestedType.AddAnnotation(fullTypeName); |
|
return nestedType; |
|
} |
|
AstType baseType; |
|
var topLevel = fullTypeName.TopLevelTypeName; |
|
if ((options & ConvertTypeOptions.IncludeNamespace) != 0) { |
|
baseType = AstType.Create(topLevel.Namespace + "." + topLevel.Name); |
|
} else { |
|
baseType = AstType.Create(topLevel.Name); |
|
} |
|
baseType.AddAnnotation(fullTypeName); |
|
return baseType; |
|
} |
|
} |
|
}
|
|
|