From b8330bebd6a1cb3a2895fc924f472292bc1cf85e Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 15 Apr 2011 14:18:20 +0200 Subject: [PATCH] Remove parent pointer from ITypeParameter and enable sharing type parameters. --- .../Resolver/OverloadResolutionTests.cs | 8 +- .../TypeSystem/GetAllBaseTypesTest.cs | 2 +- .../TypeSystem/TestInterningProvider.cs | 25 +++++- .../TypeSystem/TypeSystemTests.cs | 10 +-- .../CSharp/Resolver/ResolveVisitor.cs | 2 +- .../CSharp/Resolver/TypeInference.cs | 16 ++-- .../TypeSystem/CecilLoader.cs | 14 +-- .../TypeSystem/ITypeParameter.cs | 48 +++------- .../Implementation/DefaultTypeParameter.cs | 90 ++++++++++--------- .../MethodTypeParameterSubstitution.cs | 2 +- .../TypeSystem/ParameterizedType.cs | 2 +- 11 files changed, 110 insertions(+), 109 deletions(-) diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs index eaf63795ba..f1701156ce 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs @@ -138,7 +138,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver // static void Foo(T? ignored = default(T?)) where T : struct var m1 = MakeMethod(); - m1.TypeParameters.Add(new DefaultTypeParameter(m1, 0, "T") { HasValueTypeConstraint = true }); + m1.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T") { HasValueTypeConstraint = true }); m1.Parameters.Add(MakeOptionalParameter( NullableType.Create(m1.TypeParameters[0], context), "ignored" @@ -146,12 +146,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver // class ClassConstraint where T : class {} DefaultTypeDefinition classConstraint = new DefaultTypeDefinition(dummyClass, "ClassConstraint"); - classConstraint.TypeParameters.Add(new DefaultTypeParameter(classConstraint, 0, "T") { HasReferenceTypeConstraint = true }); + classConstraint.TypeParameters.Add(new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T") { HasReferenceTypeConstraint = true }); // static void Foo(ClassConstraint ignored = default(ClassConstraint)) // where T : class var m2 = MakeMethod(); - m2.TypeParameters.Add(new DefaultTypeParameter(m2, 0, "T") { HasReferenceTypeConstraint = true }); + m2.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T") { HasReferenceTypeConstraint = true }); m2.Parameters.Add(MakeOptionalParameter( new ParameterizedType(classConstraint, new[] { m2.TypeParameters[0] }), "ignored" @@ -159,7 +159,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver // static void Foo() var m3 = MakeMethod(); - m3.TypeParameters.Add(new DefaultTypeParameter(m3, 0, "T")); + m3.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T")); // Call: Foo(); OverloadResolution o; diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs index 88e9cb8b19..af7453b70f 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs @@ -84,7 +84,7 @@ namespace ICSharpCode.NRefactory.TypeSystem { // class C : C> {} DefaultTypeDefinition c = new DefaultTypeDefinition(mscorlib, string.Empty, "C"); - c.TypeParameters.Add(new DefaultTypeParameter(c, 0, "X")); + c.TypeParameters.Add(new DefaultTypeParameter(EntityType.TypeDefinition, 0, "X")); c.BaseTypes.Add(new ParameterizedType(c, new [] { new ParameterizedType(c, new [] { c.TypeParameters[0] }) })); Assert.AreEqual(new [] { c }, c.GetAllBaseTypes(context).ToArray()); } diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs index 098298bb72..8df59cf462 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs @@ -140,15 +140,36 @@ namespace ICSharpCode.NRefactory.TypeSystem } } + IProjectContent[] LoadProjects(CecilLoader loader) + { + const string dir = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\"; + return new IProjectContent[] { + loader.LoadAssemblyFile(dir + "mscorlib.dll"), + loader.LoadAssemblyFile(dir + "System.dll"), + loader.LoadAssemblyFile(dir + "System.Core.dll"), + loader.LoadAssemblyFile(dir + "System.Xml.dll"), + loader.LoadAssemblyFile(dir + "System.Xml.Linq.dll"), + loader.LoadAssemblyFile(dir + "System.Data.dll"), + loader.LoadAssemblyFile(dir + "System.Drawing.dll"), + loader.LoadAssemblyFile(dir + "System.Windows.Forms.dll"), + loader.LoadAssemblyFile(dir + "WindowsBase.dll"), + loader.LoadAssemblyFile(dir + "PresentationCore.dll"), + loader.LoadAssemblyFile(dir + "PresentationFramework.dll") + }; + } + [Test] public void PrintStatistics() { long startMemory = GC.GetTotalMemory(true); - IProjectContent pc = new CecilLoader().LoadAssemblyFile(typeof(object).Assembly.Location); + IProjectContent[] pc = LoadProjects(new CecilLoader()); long memoryWithFullPC = GC.GetTotalMemory(true) - startMemory; InterningProvider p = new InterningProvider(); - p.InternProject(pc); + CecilLoader loader = new CecilLoader(); + loader.InterningProvider = p; + pc = LoadProjects(loader); PrintStatistics(p); + loader = null; p = null; long memoryWithInternedPC = GC.GetTotalMemory(true) - startMemory; GC.KeepAlive(pc); diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs index 2959f00ed9..6432046df4 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs @@ -134,8 +134,8 @@ namespace ICSharpCode.NRefactory.TypeSystem public void TestClassTypeParameters() { var testClass = testCasePC.GetClass(typeof(GenericClass<,>)); - Assert.AreSame(testClass, testClass.TypeParameters[0].ParentClass); - Assert.AreSame(testClass, testClass.TypeParameters[1].ParentClass); + Assert.AreEqual(EntityType.TypeDefinition, testClass.TypeParameters[0].OwnerType); + Assert.AreEqual(EntityType.TypeDefinition, testClass.TypeParameters[1].OwnerType); Assert.AreSame(testClass.TypeParameters[1], testClass.TypeParameters[0].Constraints[0].Resolve(ctx)); } @@ -147,8 +147,8 @@ namespace ICSharpCode.NRefactory.TypeSystem IMethod m = testClass.Methods.Single(me => me.Name == "TestMethod"); Assert.AreEqual("K", m.TypeParameters[0].Name); Assert.AreEqual("V", m.TypeParameters[1].Name); - Assert.AreSame(m, m.TypeParameters[0].ParentMethod); - Assert.AreSame(m, m.TypeParameters[1].ParentMethod); + Assert.AreEqual(EntityType.Method, m.TypeParameters[0].OwnerType); + Assert.AreEqual(EntityType.Method, m.TypeParameters[1].OwnerType); Assert.AreEqual("System.IComparable`1[[``1]]", m.TypeParameters[0].Constraints[0].Resolve(ctx).ReflectionName); Assert.AreSame(m.TypeParameters[0], m.TypeParameters[1].Constraints[0].Resolve(ctx)); @@ -161,7 +161,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IMethod m = testClass.Methods.Single(me => me.Name == "GetIndex"); Assert.AreEqual("T", m.TypeParameters[0].Name); - Assert.AreSame(m, m.TypeParameters[0].ParentMethod); + Assert.AreEqual(EntityType.Method, m.TypeParameters[0].OwnerType); ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].Constraints[0].Resolve(ctx); Assert.AreEqual("IEquatable", constraint.Name); diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index 92b15d92b0..1403107ad0 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -497,7 +497,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver throw new NotImplementedException(); } - public object VisitUndocumentedExpression(UndocumentedExpression undocumentedExpression, object data) + public override ResolveResult VisitUndocumentedExpression(UndocumentedExpression undocumentedExpression, object data) { // TODO: ? ScanChildren(undocumentedExpression); diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs b/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs index 488a6c31fc..ced1e1f024 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs @@ -712,16 +712,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver get { return EmptyList.Instance; } } - IEntity ITypeParameter.Parent { - get { throw new NotSupportedException(); } - } - - IMethod ITypeParameter.ParentMethod { - get { throw new NotSupportedException(); } - } - - ITypeDefinition ITypeParameter.ParentClass { - get { throw new NotSupportedException(); } + EntityType ITypeParameter.OwnerType { + get { return EntityType.Method; } } IList ITypeParameter.Constraints { @@ -759,6 +751,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver void IFreezable.Freeze() { } + + DomRegion ITypeParameter.Region { + get { return DomRegion.Empty; } + } } #endregion diff --git a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs index 26d79e4a9b..80a5227069 100644 --- a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs +++ b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs @@ -676,7 +676,8 @@ namespace ICSharpCode.NRefactory.TypeSystem for (int i = 0; i < typeDefinition.GenericParameters.Count; i++) { if (typeDefinition.GenericParameters[i].Position != i) throw new InvalidOperationException("g.Position != i"); - this.TypeParameters.Add(new DefaultTypeParameter(this, i, typeDefinition.GenericParameters[i].Name)); + this.TypeParameters.Add(new DefaultTypeParameter( + EntityType.TypeDefinition, i, typeDefinition.GenericParameters[i].Name)); } } @@ -686,7 +687,7 @@ namespace ICSharpCode.NRefactory.TypeSystem if (typeDefinition.HasGenericParameters) { for (int i = 0; i < typeDefinition.GenericParameters.Count; i++) { - loader.AddConstraints((DefaultTypeParameter)this.TypeParameters[i], typeDefinition.GenericParameters[i]); + loader.AddConstraints(this, (DefaultTypeParameter)this.TypeParameters[i], typeDefinition.GenericParameters[i]); } } @@ -879,10 +880,11 @@ namespace ICSharpCode.NRefactory.TypeSystem for (int i = 0; i < method.GenericParameters.Count; i++) { if (method.GenericParameters[i].Position != i) throw new InvalidOperationException("g.Position != i"); - m.TypeParameters.Add(new DefaultTypeParameter(m, i, method.GenericParameters[i].Name)); + m.TypeParameters.Add(new DefaultTypeParameter( + EntityType.Method, i, method.GenericParameters[i].Name)); } for (int i = 0; i < method.GenericParameters.Count; i++) { - AddConstraints((DefaultTypeParameter)m.TypeParameters[i], method.GenericParameters[i]); + AddConstraints(m, (DefaultTypeParameter)m.TypeParameters[i], method.GenericParameters[i]); } } @@ -1064,7 +1066,7 @@ namespace ICSharpCode.NRefactory.TypeSystem #endregion #region Type Parameter Constraints - void AddConstraints(DefaultTypeParameter tp, GenericParameter g) + void AddConstraints(IEntity parentEntity, DefaultTypeParameter tp, GenericParameter g) { switch (g.Attributes & GenericParameterAttributes.VarianceMask) { case GenericParameterAttributes.Contravariant: @@ -1081,7 +1083,7 @@ namespace ICSharpCode.NRefactory.TypeSystem if (g.HasConstraints) { foreach (TypeReference constraint in g.Constraints) { - tp.Constraints.Add(ReadTypeReference(constraint, entity: tp.Parent)); + tp.Constraints.Add(ReadTypeReference(constraint, entity: parentEntity)); } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs b/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs index 75d6d4cb4d..222c06ff10 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs @@ -16,6 +16,12 @@ namespace ICSharpCode.NRefactory.TypeSystem #endif public interface ITypeParameter : IType, IFreezable { + /// + /// Get the type of this type parameter's owner. + /// + /// EntityType.TypeDefinition or EntityType.Method + EntityType OwnerType { get; } + /// /// Gets the index of the type parameter in the type parameter list of the owning method/class. /// @@ -26,24 +32,6 @@ namespace ICSharpCode.NRefactory.TypeSystem /// IList Attributes { get; } - /// - /// Gets the class or method for which this type parameter is defined. - /// This property never returns null. - /// - IEntity Parent { get; } - - /// - /// The method this type parameter is defined for. - /// This property returns null if the type parameter belongs to a class. - /// - IMethod ParentMethod { get; } - - /// - /// The class this type parameter is defined for. - /// This property returns null if the type parameter belongs to a method. - /// - ITypeDefinition ParentClass { get; } - /// /// Gets the contraints of this type parameter. /// @@ -80,6 +68,11 @@ namespace ICSharpCode.NRefactory.TypeSystem /// If this type parameter was bound, returns the unbound version of it. /// ITypeParameter UnboundTypeParameter { get; } + + /// + /// Gets the region where the type parameter is defined. + /// + DomRegion Region { get; } } /// @@ -119,25 +112,6 @@ namespace ICSharpCode.NRefactory.TypeSystem } } - IEntity ITypeParameter.Parent { - get { - Contract.Ensures(Contract.Result() != null); - return null; - } - } - - IMethod ITypeParameter.ParentMethod { - get { - return null; - } - } - - ITypeDefinition ITypeParameter.ParentClass { - get { - return null; - } - } - IList ITypeParameter.Constraints { get { Contract.Ensures(Contract.Result>() != null); diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs index cd9338213d..f1ddcc5c07 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs @@ -14,13 +14,16 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// public class DefaultTypeParameter : AbstractFreezable, ITypeParameter, ISupportsInterning { - IEntity parent; - string name; int index; IList constraints; IList attributes; + + DomRegion region; + + // Small fields: byte+byte+short VarianceModifier variance; + EntityType ownerType; BitVector16 flags; const ushort FlagReferenceTypeConstraint = 0x0001; @@ -34,28 +37,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation base.FreezeInternal(); } - public DefaultTypeParameter(IMethod parentMethod, int index, string name) + public DefaultTypeParameter(EntityType ownerType, int index, string name) { - if (parentMethod == null) - throw new ArgumentNullException("parentMethod"); + if (!(ownerType == EntityType.TypeDefinition || ownerType == EntityType.Method)) + throw new ArgumentException("owner must be a type or a method", "ownerType"); if (index < 0) throw new ArgumentOutOfRangeException("index", index, "Value must not be negative"); if (name == null) throw new ArgumentNullException("name"); - this.parent = parentMethod; - this.index = index; - this.name = name; - } - - public DefaultTypeParameter(ITypeDefinition parentClass, int index, string name) - { - if (parentClass == null) - throw new ArgumentNullException("parentClass"); - if (index < 0) - throw new ArgumentOutOfRangeException("index", index, "Value must not be negative"); - if (name == null) - throw new ArgumentNullException("name"); - this.parent = parentClass; + this.ownerType = ownerType; this.index = index; this.name = name; } @@ -74,7 +64,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public string ReflectionName { get { - if (parent is IMethod) + if (ownerType == EntityType.Method) return "``" + index.ToString(); else return "`" + index.ToString(); @@ -114,11 +104,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public override int GetHashCode() { - int hashCode = parent.GetHashCode(); unchecked { - hashCode += 1000000033 * index.GetHashCode(); + return (int)ownerType * 178256151 + index; } - return hashCode; } public override bool Equals(object obj) @@ -131,8 +119,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation DefaultTypeParameter p = other as DefaultTypeParameter; if (p == null) return false; - return parent.Equals(p.parent) - && index == p.index; + return ownerType == p.ownerType && index == p.index; + } + + public EntityType OwnerType { + get { + return ownerType; + } } public int Index { @@ -147,18 +140,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } - public IEntity Parent { - get { return parent; } - } - - public IMethod ParentMethod { - get { return parent as IMethod; } - } - - public ITypeDefinition ParentClass { - get { return parent as ITypeDefinition; } - } - public IList Constraints { get { if (constraints == null) @@ -199,6 +180,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } + public DomRegion Region { + get { return region; } + set { + CheckBeforeMutation(); + region = value; + } + } + public virtual IType BoundTo { get { return null; } } @@ -217,10 +206,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return this; } + static readonly SimpleProjectContent dummyProjectContent = new SimpleProjectContent(); + DefaultTypeDefinition GetDummyClassForTypeParameter() { - DefaultTypeDefinition c = new DefaultTypeDefinition(ParentClass ?? ParentMethod.DeclaringTypeDefinition, this.Name); - c.Region = new DomRegion(parent.Region.FileName, parent.Region.BeginLine, parent.Region.BeginColumn); + DefaultTypeDefinition c = new DefaultTypeDefinition(dummyProjectContent, string.Empty, this.Name); + c.Region = this.Region; if (HasValueTypeConstraint) { c.ClassType = ClassType.Struct; } else if (HasDefaultConstructorConstraint) { @@ -294,12 +285,29 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation int ISupportsInterning.GetHashCodeForInterning() { - return GetHashCode(); + unchecked { + int hashCode = GetHashCode(); + if (name != null) + hashCode += name.GetHashCode(); + if (attributes != null) + hashCode += attributes.GetHashCode(); + if (constraints != null) + hashCode += constraints.GetHashCode(); + hashCode += 771 * flags.Data + 900103 * (int)variance; + return hashCode; + } } bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) { - return this == other; + DefaultTypeParameter o = other as DefaultTypeParameter; + return o != null + && this.attributes == o.attributes + && this.constraints == o.constraints + && this.flags == o.flags + && this.ownerType == o.ownerType + && this.index == o.index + && this.variance == o.variance; } public override string ToString() diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/MethodTypeParameterSubstitution.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/MethodTypeParameterSubstitution.cs index aa386ebe6f..1a5d048f03 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/MethodTypeParameterSubstitution.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/MethodTypeParameterSubstitution.cs @@ -21,7 +21,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public override IType VisitTypeParameter(ITypeParameter type) { int index = type.Index; - if (type.ParentMethod != null) { + if (type.OwnerType == EntityType.Method) { if (index >= 0 && index < typeArguments.Count) return typeArguments[index]; else diff --git a/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs b/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs index 0d0bb77f49..f51fb1ea8a 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs @@ -35,7 +35,7 @@ namespace ICSharpCode.NRefactory.TypeSystem public override IType VisitTypeParameter(ITypeParameter type) { int index = type.Index; - if (type.ParentClass != null) { + if (type.OwnerType == EntityType.TypeDefinition) { if (index >= 0 && index < typeArguments.Length) return typeArguments[index]; else