Browse Source

Add GetEffectiveBaseClass() and GetEffectiveInterfaceSet() to ITypeParameter, and fixed a bug in DefaultTypeParameter.IsReferenceType().

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
4d73e48488
  1. 10
      ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs
  2. 2
      ICSharpCode.NRefactory.Tests/CSharp/CSharpAmbienceTests.cs
  3. 1
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  4. 87
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeParameterTests.cs
  5. 22
      ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs
  6. 79
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs

10
ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs

@ -866,6 +866,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public override TypeKind Kind { public override TypeKind Kind {
get { return TypeKind.TypeParameter; } get { return TypeKind.TypeParameter; }
} }
IType ITypeParameter.GetEffectiveBaseClass(ITypeResolveContext context)
{
return KnownTypeReference.Object.Resolve(context);
}
IEnumerable<IType> ITypeParameter.GetEffectiveInterfaceSet(ITypeResolveContext context)
{
return EmptyList<IType>.Instance;
}
} }
#endregion #endregion

2
ICSharpCode.NRefactory.Tests/CSharp/CSharpAmbienceTests.cs

@ -171,7 +171,7 @@ namespace ICSharpCode.NRefactory.CSharp
#endregion #endregion
#region Test types #region Test types
#pragma warning disable 169 #pragma warning disable 169, 67
class Test {} class Test {}

1
ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -177,6 +177,7 @@
<Compile Include="TypeSystem\SerializedCecilLoaderTests.cs" /> <Compile Include="TypeSystem\SerializedCecilLoaderTests.cs" />
<Compile Include="TypeSystem\StructureTests.cs" /> <Compile Include="TypeSystem\StructureTests.cs" />
<Compile Include="TypeSystem\TestInterningProvider.cs" /> <Compile Include="TypeSystem\TestInterningProvider.cs" />
<Compile Include="TypeSystem\TypeParameterTests.cs" />
<Compile Include="TypeSystem\TypeSystemTests.cs" /> <Compile Include="TypeSystem\TypeSystemTests.cs" />
<Compile Include="TypeSystem\TypeSystemTests.TestCase.cs" /> <Compile Include="TypeSystem\TypeSystemTests.TestCase.cs" />
<EmbeddedResource Include="TypeSystem\TypeSystemTests.TestCase.cs" /> <EmbeddedResource Include="TypeSystem\TypeSystemTests.TestCase.cs" />

87
ICSharpCode.NRefactory.Tests/TypeSystem/TypeParameterTests.cs

@ -0,0 +1,87 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// 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 ICSharpCode.NRefactory.TypeSystem.Implementation;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.TypeSystem
{
[TestFixture]
public class TypeParameterTests
{
[Test]
public void TypeParameterDerivingFromOtherTypeParameterDoesNotInheritReferenceConstraint()
{
// class C<T, U> where T : class where U : T
DefaultTypeDefinition c = new DefaultTypeDefinition(MinimalResolveContext.Instance, string.Empty, "C");
DefaultTypeParameter t = new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T");
DefaultTypeParameter u = new DefaultTypeParameter(EntityType.TypeDefinition, 1, "U");
c.TypeParameters.Add(t);
c.TypeParameters.Add(u);
t.HasReferenceTypeConstraint = true;
u.Constraints.Add(t);
// At runtime, we might have T=System.ValueType and U=int, so C# can't inherit the 'class' constraint
// from one type parameter to another.
Assert.AreEqual(true, t.IsReferenceType(MinimalResolveContext.Instance));
Assert.IsNull(u.IsReferenceType(MinimalResolveContext.Instance));
}
[Test]
public void ValueTypeParameterDerivingFromReferenceTypeParameter()
{
// class C<T, U> where T : class where U : T
DefaultTypeDefinition c = new DefaultTypeDefinition(MinimalResolveContext.Instance, string.Empty, "C");
DefaultTypeParameter t = new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T");
DefaultTypeParameter u = new DefaultTypeParameter(EntityType.TypeDefinition, 1, "U");
c.TypeParameters.Add(t);
c.TypeParameters.Add(u);
t.HasReferenceTypeConstraint = true;
u.HasValueTypeConstraint = true;
u.Constraints.Add(t);
// At runtime, we might have T=System.ValueType and U=int, so C# can't inherit the 'class' constraint
// from one type parameter to another.
Assert.AreEqual(true, t.IsReferenceType(MinimalResolveContext.Instance));
Assert.AreEqual(false, u.IsReferenceType(MinimalResolveContext.Instance));
}
[Test]
public void TypeParameterDerivingFromOtherTypeParameterInheritsEffectiveBaseClass()
{
// class C<T, U> where T : class where U : T
ITypeResolveContext context = CecilLoaderTests.Mscorlib;
DefaultTypeDefinition c = new DefaultTypeDefinition(CecilLoaderTests.Mscorlib, string.Empty, "C");
DefaultTypeParameter t = new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T");
DefaultTypeParameter u = new DefaultTypeParameter(EntityType.TypeDefinition, 1, "U");
c.TypeParameters.Add(t);
c.TypeParameters.Add(u);
t.Constraints.Add(typeof(List<string>).ToTypeReference());
u.Constraints.Add(t);
// At runtime, we might have T=System.ValueType and U=int, so C# can't inherit the 'class' constraint
// from one type parameter to another.
Assert.AreEqual(true, t.IsReferenceType(context));
Assert.AreEqual(true, u.IsReferenceType(context));
Assert.AreEqual("System.Collections.Generic.List`1[[System.String]]", t.GetEffectiveBaseClass(context).ReflectionName);
Assert.AreEqual("System.Collections.Generic.List`1[[System.String]]", u.GetEffectiveBaseClass(context).ReflectionName);
}
}
}

22
ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs

@ -76,6 +76,16 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// Gets the region where the type parameter is defined. /// Gets the region where the type parameter is defined.
/// </summary> /// </summary>
DomRegion Region { get; } DomRegion Region { get; }
/// <summary>
/// Gets the effective base class of this type parameter.
/// </summary>
IType GetEffectiveBaseClass(ITypeResolveContext context);
/// <summary>
/// Gets the effective interface set of this type parameter.
/// </summary>
IEnumerable<IType> GetEffectiveInterfaceSet(ITypeResolveContext context);
} }
/// <summary> /// <summary>
@ -165,6 +175,18 @@ namespace ICSharpCode.NRefactory.TypeSystem
DomRegion ITypeParameter.Region { DomRegion ITypeParameter.Region {
get { return DomRegion.Empty; } get { return DomRegion.Empty; }
} }
IType ITypeParameter.GetEffectiveBaseClass(ITypeResolveContext context)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result<IType>() != null);
}
IEnumerable<IType> ITypeParameter.GetEffectiveInterfaceSet(ITypeResolveContext context)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result<IEnumerable<IType>>() != null);
}
} }
#endif #endif
} }

79
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs

@ -99,23 +99,20 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
case FlagValueTypeConstraint: case FlagValueTypeConstraint:
return false; return false;
} }
// protect against cyclic dependencies between type parameters
using (var busyLock = BusyManager.Enter(this)) { // A type parameter is known to be a reference type if it has the reference type constraint
if (busyLock.Success) { // or its effective base class is not object or System.ValueType.
foreach (ITypeReference constraintRef in this.Constraints) { IType baseClass = GetEffectiveBaseClass(context);
IType constraint = constraintRef.Resolve(context); if (baseClass.Kind == TypeKind.Class) {
ITypeDefinition constraintDef = constraint.GetDefinition(); if (baseClass.Namespace == "System" && baseClass.TypeParameterCount == 0) {
// While interfaces are reference types, an interface constraint does not switch (baseClass.Name) {
// force the type parameter to be a reference type; so we need to explicitly look for classes here. case "Object":
if (constraintDef != null && constraintDef.Kind == TypeKind.Class) case "ValueType":
return true; case "Enum":
if (constraint is ITypeParameter) { return null;
bool? isReferenceType = constraint.IsReferenceType(context);
if (isReferenceType.HasValue)
return isReferenceType.Value;
}
} }
} }
return true;
} }
return null; return null;
} }
@ -333,6 +330,58 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return EmptyList<IType>.Instance; return EmptyList<IType>.Instance;
} }
public IType GetEffectiveBaseClass(ITypeResolveContext context)
{
// protect against cyclic type parameters
using (var busyLock = BusyManager.Enter(this)) {
if (!busyLock.Success)
return SharedTypes.UnknownType;
if (HasValueTypeConstraint)
return context.GetTypeDefinition("System", "ValueType", 0, StringComparer.Ordinal) ?? SharedTypes.UnknownType;
List<IType> classTypeConstraints = new List<IType>();
foreach (ITypeReference constraintRef in this.Constraints) {
IType constraint = constraintRef.Resolve(context);
if (constraint.Kind == TypeKind.Class) {
classTypeConstraints.Add(constraint);
} else if (constraint.Kind == TypeKind.TypeParameter) {
IType baseClass = ((ITypeParameter)constraint).GetEffectiveBaseClass(context);
if (baseClass.Kind == TypeKind.Class)
classTypeConstraints.Add(baseClass);
}
}
if (classTypeConstraints.Count == 0)
return KnownTypeReference.Object.Resolve(context);
// Find the derived-most type in the resulting set:
IType result = classTypeConstraints[0];
for (int i = 1; i < classTypeConstraints.Count; i++) {
if (classTypeConstraints[i].GetDefinition().IsDerivedFrom(result.GetDefinition(), context))
result = classTypeConstraints[i];
}
return result;
}
}
public IEnumerable<IType> GetEffectiveInterfaceSet(ITypeResolveContext context)
{
List<IType> result = new List<IType>();
// protect against cyclic type parameters
using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) {
foreach (ITypeReference constraintRef in this.Constraints) {
IType constraint = constraintRef.Resolve(context);
if (constraint.Kind == TypeKind.Interface) {
result.Add(constraint);
} else if (constraint.Kind == TypeKind.TypeParameter) {
result.AddRange(((ITypeParameter)constraint).GetEffectiveInterfaceSet(context));
}
}
}
}
return result.Distinct();
}
public IEnumerable<IType> GetBaseTypes(ITypeResolveContext context) public IEnumerable<IType> GetBaseTypes(ITypeResolveContext context)
{ {
bool hasNonInterfaceConstraint = false; bool hasNonInterfaceConstraint = false;

Loading…
Cancel
Save