From 5f1dfe8037e106beac3366791068d49eff907f67 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 4 Aug 2010 19:03:51 +0200 Subject: [PATCH] Started implementation of CecilProjectContent.ReadTypeReference. --- .../ICSharpCode.NRefactory.csproj | 3 + .../TypeSystem/CecilProjectContent.cs | 106 +++++++++++++++++- ICSharpCode.NRefactory/TypeSystem/IMember.cs | 1 + ICSharpCode.NRefactory/TypeSystem/IType.cs | 18 --- .../TypeSystem/ITypeReference.cs | 2 +- .../TypeSystem/Implementation/AbstractType.cs | 8 -- .../TypeSystem/Implementation/ArrayType.cs | 82 ++++++++++++++ .../Implementation/DefaultTypeDefinition.cs | 14 +-- .../Implementation/NestedTypeReference.cs | 24 ++-- .../TypeSystem/Implementation/PointerType.cs | 65 +++++++++++ .../Implementation/TypeWithElementType.cs | 45 ++++++++ .../TypeSystem/SharedTypes.cs | 3 + 12 files changed, 322 insertions(+), 49 deletions(-) create mode 100644 ICSharpCode.NRefactory/TypeSystem/Implementation/ArrayType.cs create mode 100644 ICSharpCode.NRefactory/TypeSystem/Implementation/PointerType.cs create mode 100644 ICSharpCode.NRefactory/TypeSystem/Implementation/TypeWithElementType.cs diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index cc57d509d1..681529f4ae 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -147,13 +147,16 @@ + + + diff --git a/ICSharpCode.NRefactory/TypeSystem/CecilProjectContent.cs b/ICSharpCode.NRefactory/TypeSystem/CecilProjectContent.cs index ba1842d60b..341e18a4cb 100644 --- a/ICSharpCode.NRefactory/TypeSystem/CecilProjectContent.cs +++ b/ICSharpCode.NRefactory/TypeSystem/CecilProjectContent.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.Contracts; +using System.Text; using ICSharpCode.NRefactory.TypeSystem.Implementation; using Mono.Cecil; @@ -95,15 +96,14 @@ namespace ICSharpCode.NRefactory.TypeSystem ITypeResolveContext earlyBindContext = null) { int typeIndex = 0; - return ReadTypeReference(type, typeAttributes, entity, earlyBindContext, ref typeIndex); + return CreateType(type, entity, earlyBindContext, typeAttributes, ref typeIndex); } - static ITypeReference ReadTypeReference( + static ITypeReference CreateType( TypeReference type, - ICustomAttributeProvider typeAttributes, IEntity entity , ITypeResolveContext earlyBindContext, - ref int typeIndex) + ICustomAttributeProvider typeAttributes, ref int typeIndex) { while (type is OptionalModifierType || type is RequiredModifierType) { type = ((TypeSpecification)type).ElementType; @@ -111,7 +111,103 @@ namespace ICSharpCode.NRefactory.TypeSystem if (type == null) { return SharedTypes.UnknownType; } - throw new NotImplementedException(); + + if (type is ByReferenceType) { + throw new NotImplementedException(); + } else if (type is Mono.Cecil.PointerType) { + typeIndex++; + return PointerTypeReference.Create( + CreateType( + (type as Mono.Cecil.PointerType).ElementType, + entity, + earlyBindContext, + typeAttributes, ref typeIndex)); + } else if (type is Mono.Cecil.ArrayType) { + typeIndex++; + return ArrayTypeReference.Create( + CreateType( + (type as Mono.Cecil.ArrayType).ElementType, + entity, + earlyBindContext, + typeAttributes, ref typeIndex), + (type as Mono.Cecil.ArrayType).Rank); + } else if (type is GenericInstanceType) { + GenericInstanceType gType = (GenericInstanceType)type; + /*IReturnType baseType = CreateType(pc, member, gType.ElementType, attributeProvider, ref typeIndex); + IReturnType[] para = new IReturnType[gType.GenericArguments.Count]; + for (int i = 0; i < para.Length; ++i) { + typeIndex++; + para[i] = CreateType(pc, member, gType.GenericArguments[i], attributeProvider, ref typeIndex); + } + return new ConstructedReturnType(baseType, para);*/ + throw new NotImplementedException(); + } else if (type is GenericParameter) { + throw new NotImplementedException(); + /*GenericParameter typeGP = type as GenericParameter; + if (typeGP.Owner is MethodDefinition) { + IMethod method = entity as IMethod; + if (method != null) { + if (typeGP.Position < method.TypeParameters.Count) { + return method.TypeParameters[typeGP.Position]; + } + } + return SharedTypes.UnknownType; + } else { + ITypeDefinition c = (entity as ITypeDefinition) ?? (entity is IMember ? ((IMember)entity).DeclaringTypeDefinition : null); + if (c != null && typeGP.Position < c.TypeParameters.Count) { + if (c.TypeParameters[typeGP.Position].Name == type.Name) { + return c.TypeParameters[typeGP.Position]; + } + } + return SharedTypes.UnknownType; + }*/ + } else { + string name = type.FullName; + if (name == null) + throw new ApplicationException("type.FullName returned null. Type: " + type.ToString()); + + if (name.IndexOf('/') > 0) { + string[] nameparts = name.Split('/'); + ITypeReference typeRef = GetSimpleType(nameparts[0], earlyBindContext); + for (int i = 1; i < nameparts.Length; i++) { + int partTypeParameterCount; + string namepart = SplitTypeParameterCountFromReflectionName(nameparts[i], out partTypeParameterCount); + typeRef = new NestedTypeReference(typeRef, namepart, partTypeParameterCount); + } + return typeRef; + } else if (name == "System.Object" && HasDynamicAttribute(typeAttributes, typeIndex)) { + return SharedTypes.Dynamic; + } else { + return GetSimpleType(name, earlyBindContext); + } + } + } + + static ITypeReference GetSimpleType(string reflectionName, ITypeResolveContext earlyBindContext) + { + int typeParameterCount; + string name = SplitTypeParameterCountFromReflectionName(reflectionName, out typeParameterCount); + if (earlyBindContext != null) { + IType c = earlyBindContext.GetClass(name, typeParameterCount, StringComparer.Ordinal); + if (c != null) + return c; + } + return new GetClassTypeReference(name, typeParameterCount); + } + + static string SplitTypeParameterCountFromReflectionName(string reflectionName, out int typeParameterCount) + { + int pos = reflectionName.LastIndexOf('`'); + if (pos < 0) { + typeParameterCount = 0; + return reflectionName; + } else { + string typeCount = reflectionName.Substring(pos + 1); + if (int.TryParse(typeCount, out typeParameterCount)) + return reflectionName.Substring(0, pos); + else + return reflectionName; + } } static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex) diff --git a/ICSharpCode.NRefactory/TypeSystem/IMember.cs b/ICSharpCode.NRefactory/TypeSystem/IMember.cs index 3aa3672730..0c64a6c76a 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IMember.cs @@ -13,6 +13,7 @@ namespace ICSharpCode.NRefactory.TypeSystem [ContractClass(typeof(IMemberContract))] public interface IMember : IEntity { + // redeclare IEntity.DeclaringTypeDefinition to clarify the documentation: /// /// Gets the type definition that contains the member. This property never returns null. /// diff --git a/ICSharpCode.NRefactory/TypeSystem/IType.cs b/ICSharpCode.NRefactory/TypeSystem/IType.cs index a4bb020688..abd68dbb85 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IType.cs @@ -40,16 +40,6 @@ namespace ICSharpCode.NRefactory.TypeSystem /// IType DeclaringType { get; } - /// - /// Gets whether this type is an array type. - /// - bool IsArrayType { get; } - - /// - /// Gets whether this type is a pointer type. - /// - bool IsPointerType { get; } - /// /// Gets the number of type parameters. /// @@ -63,14 +53,6 @@ namespace ICSharpCode.NRefactory.TypeSystem get { return null; } } - bool IType.IsArrayType { - get { return false; } - } - - bool IType.IsPointerType { - get { return false; } - } - int IType.TypeParameterCount { get { Contract.Ensures(Contract.Result() >= 0); diff --git a/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs b/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs index e297e29275..772af2daf4 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs @@ -24,7 +24,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// Gets inner classes (including inherited inner classes). /// IList GetNestedTypes(ITypeResolveContext context); - + /// /// Gets all methods that can be called on this return type. /// diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs index 70b7b9d13b..2080495803 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs @@ -42,14 +42,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public abstract bool? IsReferenceType { get; } - public virtual bool IsArrayType { - get { return false; } - } - - public virtual bool IsPointerType { - get { return false; } - } - public virtual int TypeParameterCount { get { return 0; } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/ArrayType.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/ArrayType.cs new file mode 100644 index 0000000000..48c0780d59 --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/ArrayType.cs @@ -0,0 +1,82 @@ +// Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Represents an array type. + /// + public class ArrayType : TypeWithElementType + { + int dimensions; + + public ArrayType(IType elementType, int dimensions) : base(elementType) + { + if (dimensions <= 0) + throw new ArgumentOutOfRangeException("dimensions", dimensions, "dimensions must be positive"); + this.dimensions = dimensions; + } + + public int Dimensions { + get { return dimensions; } + } + + public override string NameSuffix { + get { + if (dimensions == 0) + return "[]"; + else + return "[" + new string(',', dimensions-1) + "]"; + } + } + + public override Nullable IsReferenceType { + get { return true; } + } + + public override int GetHashCode() + { + return unchecked(GetElementType().GetHashCode() * 71681 + dimensions); + } + + public override bool Equals(IType other) + { + ArrayType a = other as ArrayType; + return a != null && elementType.Equals(a.elementType) && a.dimensions == dimensions; + } + } + + public class ArrayTypeReference : AbstractTypeReference + { + ITypeReference elementType; + int dimensions; + + public ArrayTypeReference(ITypeReference elementType, int dimensions) + { + if (elementType == null) + throw new ArgumentNullException("elementType"); + this.elementType = elementType; + this.dimensions = dimensions; + } + + public override IType Resolve(ITypeResolveContext context) + { + return new ArrayType(elementType.Resolve(context), dimensions); + } + + public override string ToString() + { + return elementType.ToString() + "[" + new string(',', dimensions - 1) + "]"; + } + + public static ITypeReference Create(ITypeReference elementType, int dimensions) + { + if (elementType is IType) + return new ArrayType((IType)elementType, dimensions); + else + return new ArrayTypeReference(elementType, dimensions); + } + } +} diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs index b421aeb4f6..ce97d5ae63 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs @@ -157,14 +157,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } - bool IType.IsArrayType { - get { return false; } - } - - bool IType.IsPointerType { - get { return false; } - } - public string FullName { get { if (declaringTypeDefinition != null) { @@ -390,8 +382,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation && this.Name == other.Name && this.TypeParameterCount == other.TypeParameterCount; } else { + // We do not check the project content because assemblies might or might not + // be equivalent depending on compiler settings and runtime assembly + // redirection. return other.DeclaringTypeDefinition == null - && this.ProjectContent == other.ProjectContent && this.Namespace == other.Namespace && this.Name == other.Name && this.TypeParameterCount == other.TypeParameterCount; @@ -403,7 +397,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (declaringTypeDefinition != null) { return declaringTypeDefinition.GetHashCode() ^ name.GetHashCode(); } else { - return ns.GetHashCode() ^ name.GetHashCode() ^ projectContent.GetHashCode(); + return ns.GetHashCode() ^ name.GetHashCode() ^ this.TypeParameterCount; } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/NestedTypeReference.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/NestedTypeReference.cs index bedddacc2a..f42e25b057 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/NestedTypeReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/NestedTypeReference.cs @@ -13,9 +13,17 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// public class NestedTypeReference : AbstractTypeReference { - ITypeReference baseTypeRef; string name; int typeParameterCount; + ITypeReference baseTypeRef; + string name; + int additionalTypeParameterCount; - public NestedTypeReference(ITypeReference baseTypeRef, string name, int typeParameterCount) + /// + /// Creates a new NestedTypeReference. + /// + /// Reference to the base type. + /// + /// + public NestedTypeReference(ITypeReference baseTypeRef, string name, int additionalTypeParameterCount) { if (baseTypeRef == null) throw new ArgumentNullException("baseTypeRef"); @@ -23,13 +31,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation throw new ArgumentNullException("name"); this.baseTypeRef = baseTypeRef; this.name = name; - this.typeParameterCount = typeParameterCount; + this.additionalTypeParameterCount = additionalTypeParameterCount; } public override IType Resolve(ITypeResolveContext context) { - foreach (IType type in baseTypeRef.GetNestedTypes(context)) { - if (type.Name == name && type.TypeParameterCount == typeParameterCount) + IType baseType = baseTypeRef.Resolve(context); + int tpc = baseType.TypeParameterCount; + foreach (IType type in baseType.GetNestedTypes(context)) { + if (type.Name == name && type.TypeParameterCount == tpc + additionalTypeParameterCount) return type; } return SharedTypes.UnknownType; @@ -37,10 +47,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public override string ToString() { - if (typeParameterCount == 0) + if (additionalTypeParameterCount == 0) return baseTypeRef + "+" + name; else - return baseTypeRef + "+" + name + "`" + typeParameterCount; + return baseTypeRef + "+" + name + "`" + additionalTypeParameterCount; } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/PointerType.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/PointerType.cs new file mode 100644 index 0000000000..3762428913 --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/PointerType.cs @@ -0,0 +1,65 @@ +// Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + public class PointerType : TypeWithElementType + { + public PointerType(IType elementType) : base(elementType) + { + } + + public override string NameSuffix { + get { + return "*"; + } + } + + public override Nullable IsReferenceType { + get { return null; } + } + + public override int GetHashCode() + { + return elementType.GetHashCode() ^ 91725811; + } + + public override bool Equals(IType other) + { + PointerType a = other as PointerType; + return a != null && elementType.Equals(a.elementType); + } + } + + public class PointerTypeReference : AbstractTypeReference + { + ITypeReference elementType; + + public PointerTypeReference(ITypeReference elementType) + { + if (elementType == null) + throw new ArgumentNullException("elementType"); + this.elementType = elementType; + } + + public override IType Resolve(ITypeResolveContext context) + { + return new PointerType(elementType.Resolve(context)); + } + + public override string ToString() + { + return elementType.ToString() + "*"; + } + + public static ITypeReference Create(ITypeReference elementType) + { + if (elementType is IType) + return new PointerType((IType)elementType); + else + return new PointerTypeReference(elementType); + } + } +} diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeWithElementType.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeWithElementType.cs new file mode 100644 index 0000000000..99947c76a3 --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeWithElementType.cs @@ -0,0 +1,45 @@ +// +// +// +// +// $Revision$ +// +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + public abstract class TypeWithElementType : AbstractType + { + protected readonly IType elementType; + + protected TypeWithElementType(IType elementType) + { + if (elementType == null) + throw new ArgumentNullException("elementType"); + this.elementType = elementType; + } + + public override string Name { + get { return elementType.Name + NameSuffix; } + } + + public override string Namespace { + get { return elementType.Namespace; } + } + + public override string FullName { + get { return elementType.FullName + NameSuffix; } + } + + public override string DotNetName { + get { return elementType.DotNetName + NameSuffix; } + } + + public abstract string NameSuffix { get; } + + public override IType GetElementType() + { + return elementType; + } + } +} diff --git a/ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs b/ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs index c30988d05b..4c186ef1c7 100644 --- a/ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs +++ b/ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs @@ -23,6 +23,9 @@ namespace ICSharpCode.NRefactory.TypeSystem [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "It's immutable")] public readonly static IType Null = new NullType(); + // TODO: implement DynamicType + public readonly static IType Dynamic = new UnknownType(); + /* * I'd like to define static instances for common types like * void, int, etc.; but there are two problems with this: