Browse Source

Implemented constraint inheritance.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
69360a2c1c
  1. 23
      ICSharpCode.NRefactory.CSharp/Parser/TypeSystemConvertVisitor.cs
  2. 15
      ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs
  3. 11
      ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs
  4. 21
      ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs
  5. 10
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs
  6. 28
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  7. 4
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  8. 43
      ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs
  9. 332
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractTypeParameter.cs
  10. 303
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs
  11. 57
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameterConstraints.cs
  12. 99
      ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterWithInheritedConstraints.cs
  13. 167
      ICSharpCode.NRefactory/TypeSystem/InheritanceHelper.cs
  14. 9
      ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs

23
ICSharpCode.NRefactory.CSharp/Parser/TypeSystemConvertVisitor.cs

@ -398,8 +398,18 @@ namespace ICSharpCode.NRefactory.CSharp @@ -398,8 +398,18 @@ namespace ICSharpCode.NRefactory.CSharp
m.Region = MakeRegion(methodDeclaration);
m.BodyRegion = MakeRegion(methodDeclaration.Body);
ConvertTypeParameters(m.TypeParameters, methodDeclaration.TypeParameters, methodDeclaration.Constraints, EntityType.Method);
if (InheritsConstraints(methodDeclaration) && methodDeclaration.Constraints.Count == 0) {
int index = 0;
foreach (TypeParameterDeclaration tpDecl in methodDeclaration.TypeParameters) {
var tp = new TypeParameterWithInheritedConstraints(m, index++, tpDecl.Name);
tp.Region = MakeRegion(tpDecl);
ConvertAttributes(tp.Attributes, tpDecl.Attributes);
tp.Variance = tpDecl.Variance;
m.TypeParameters.Add(tp);
}
} else {
ConvertTypeParameters(m.TypeParameters, methodDeclaration.TypeParameters, methodDeclaration.Constraints, EntityType.Method);
}
m.ReturnType = ConvertType(methodDeclaration.ReturnType);
ConvertAttributes(m.Attributes, methodDeclaration.Attributes.Where(s => s.AttributeTarget != "return"));
ConvertAttributes(m.ReturnTypeAttributes, methodDeclaration.Attributes.Where(s => s.AttributeTarget == "return"));
@ -421,6 +431,14 @@ namespace ICSharpCode.NRefactory.CSharp @@ -421,6 +431,14 @@ namespace ICSharpCode.NRefactory.CSharp
return m;
}
bool InheritsConstraints(MethodDeclaration methodDeclaration)
{
// overrides and explicit interface implementations inherit constraints
if ((methodDeclaration.Modifiers & Modifiers.Override) == Modifiers.Override)
return true;
return !methodDeclaration.PrivateImplementationType.IsNull;
}
void ConvertTypeParameters(IList<ITypeParameter> output, AstNodeCollection<TypeParameterDeclaration> typeParameters, AstNodeCollection<Constraint> constraints, EntityType ownerType)
{
// output might be non-empty when type parameters were copied from an outer class
@ -428,6 +446,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -428,6 +446,7 @@ namespace ICSharpCode.NRefactory.CSharp
List<DefaultTypeParameter> list = new List<DefaultTypeParameter>();
foreach (TypeParameterDeclaration tpDecl in typeParameters) {
DefaultTypeParameter tp = new DefaultTypeParameter(ownerType, index++, tpDecl.Name);
tp.Region = MakeRegion(tpDecl);
ConvertAttributes(tp.Attributes, tpDecl.Attributes);
tp.Variance = tpDecl.Variance;
list.Add(tp);

15
ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs

@ -608,7 +608,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -608,7 +608,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
decl.Parameters.Add(ConvertParameter(p));
}
if (this.ShowTypeParameters && this.ShowTypeParameterConstraints) {
if (this.ShowTypeParameters && this.ShowTypeParameterConstraints && !method.IsOverride) {
foreach (ITypeParameter tp in method.TypeParameters) {
var constraint = ConvertTypeParameterConstraint(tp);
if (constraint != null)
@ -709,20 +709,21 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -709,20 +709,21 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
Constraint ConvertTypeParameterConstraint(ITypeParameter tp)
{
if (tp.Constraints.Count == 0 && !tp.HasDefaultConstructorConstraint && !tp.HasReferenceTypeConstraint && !tp.HasValueTypeConstraint) {
ITypeParameterConstraints constraints = tp.GetConstraints(context);
if (constraints.Count == 0 && !constraints.HasDefaultConstructorConstraint && !constraints.HasReferenceTypeConstraint && !constraints.HasValueTypeConstraint) {
return null;
}
Constraint c = new Constraint();
c.TypeParameter = tp.Name;
if (tp.HasReferenceTypeConstraint) {
if (constraints.HasReferenceTypeConstraint) {
c.BaseTypes.Add(new PrimitiveType("class"));
} else if (tp.HasValueTypeConstraint) {
} else if (constraints.HasValueTypeConstraint) {
c.BaseTypes.Add(new PrimitiveType("struct"));
}
foreach (ITypeReference tr in tp.Constraints) {
c.BaseTypes.Add(ConvertTypeReference(tr));
foreach (IType t in constraints) {
c.BaseTypes.Add(ConvertType(t));
}
if (tp.HasDefaultConstructorConstraint) {
if (constraints.HasDefaultConstructorConstraint) {
c.BaseTypes.Add(new PrimitiveType("new"));
}
return c;

11
ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs

@ -409,15 +409,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -409,15 +409,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ConstraintsValid = false;
break;
}
if (tp.HasReferenceTypeConstraint) {
ITypeParameterConstraints constraints = tp.GetConstraints(context);
if (constraints.HasReferenceTypeConstraint) {
if (typeArg.IsReferenceType(context) != true)
ConstraintsValid = false;
}
if (tp.HasValueTypeConstraint) {
if (constraints.HasValueTypeConstraint) {
if (!NullableType.IsNonNullableValueType(typeArg, context))
ConstraintsValid = false;
}
if (tp.HasDefaultConstructorConstraint) {
if (constraints.HasDefaultConstructorConstraint) {
ITypeDefinition def = typeArg.GetDefinition();
if (def != null && def.IsAbstract)
ConstraintsValid = false;
@ -427,8 +428,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -427,8 +428,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions
).Any();
}
foreach (IType constraintType in tp.Constraints) {
IType c = newParameterizedType.SubstituteInType(constraintType);
foreach (IType constraintType in constraints) {
IType c = constraintType.AcceptVisitor(newParameterizedType.GetSubstitution());
ConstraintsValid &= conversions.IsConstraintConvertible(typeArg, c);
}
}

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

@ -831,22 +831,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -831,22 +831,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
get { return EntityType.Method; }
}
IList<ITypeReference> ITypeParameter.Constraints {
get { return EmptyList<ITypeReference>.Instance; }
}
bool ITypeParameter.HasDefaultConstructorConstraint {
get { return false; }
}
bool ITypeParameter.HasReferenceTypeConstraint {
get { return false; }
}
bool ITypeParameter.HasValueTypeConstraint {
get { return false; }
}
VarianceModifier ITypeParameter.Variance {
get { return VarianceModifier.Invariant; }
}
@ -867,6 +851,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -867,6 +851,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
get { return TypeKind.TypeParameter; }
}
ITypeParameterConstraints ITypeParameter.GetConstraints(ITypeResolveContext context)
{
return DefaultTypeParameterConstraints.Empty;
}
IType ITypeParameter.GetEffectiveBaseClass(ITypeResolveContext context)
{
return KnownTypeReference.Object.Resolve(context);

10
ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs

@ -77,10 +77,16 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase @@ -77,10 +77,16 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase
CombinedFlags = Flag1 | Flag2
}
public class Base<T> {
public class Base<T>
{
public class Nested<X> {}
public virtual void GenericMethodWithConstraints<X>(T a) where X : IComparer<T>, new() {}
}
public class Derived<A, B> : Base<B>
{
public override void GenericMethodWithConstraints<Y>(B a) { }
}
public class Derived<A, B> : Base<B> {}
public struct MyStructWithCtor
{

28
ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs

@ -167,7 +167,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -167,7 +167,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
var testClass = testCasePC.GetTypeDefinition(typeof(GenericClass<,>));
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));
Assert.AreSame(testClass.TypeParameters[1], testClass.TypeParameters[0].GetConstraints(ctx)[0].Resolve(ctx));
}
[Test]
@ -181,8 +181,8 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -181,8 +181,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
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));
Assert.AreEqual("System.IComparable`1[[``1]]", m.TypeParameters[0].GetConstraints(ctx)[0].Resolve(ctx).ReflectionName);
Assert.AreSame(m.TypeParameters[0], m.TypeParameters[1].GetConstraints(ctx)[0].Resolve(ctx));
}
[Test]
@ -194,7 +194,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -194,7 +194,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreEqual("T", m.TypeParameters[0].Name);
Assert.AreEqual(EntityType.Method, m.TypeParameters[0].OwnerType);
ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].Constraints[0].Resolve(ctx);
ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].GetConstraints(ctx)[0].Resolve(ctx);
Assert.AreEqual("IEquatable", constraint.Name);
Assert.AreEqual(1, constraint.TypeParameterCount);
Assert.AreEqual(1, constraint.TypeArguments.Count);
@ -305,6 +305,20 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -305,6 +305,20 @@ namespace ICSharpCode.NRefactory.TypeSystem
d.GetNestedTypes(ctx).Select(n => n.ReflectionName).ToArray());
}
[Test]
public void ConstraintsOnOverrideAreInherited()
{
ITypeDefinition d = ctx.GetTypeDefinition(typeof(Derived<,>));
ITypeParameter tp = d.Methods.Single(m => m.Name == "GenericMethodWithConstraints").TypeParameters.Single();
Assert.AreEqual("Y", tp.Name);
ITypeParameterConstraints constraints = tp.GetConstraints(ctx);
Assert.IsFalse(constraints.HasValueTypeConstraint);
Assert.IsFalse(constraints.HasReferenceTypeConstraint);
Assert.IsTrue(constraints.HasDefaultConstructorConstraint);
Assert.AreEqual(1, constraints.Count);
Assert.AreEqual("System.Collections.Generic.IComparer`1[[`1]]", constraints[0].ReflectionName);
}
[Test]
public void DefaultConstructorAddedToStruct()
{
@ -421,15 +435,15 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -421,15 +435,15 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreEqual(VarianceModifier.Contravariant, type.TypeParameters[0].Variance);
Assert.AreEqual(VarianceModifier.Covariant, type.TypeParameters[1].Variance);
Assert.AreSame(type.TypeParameters[1], type.TypeParameters[0].Constraints[0].Resolve(ctx));
Assert.AreSame(type.TypeParameters[1], type.TypeParameters[0].GetConstraints(ctx)[0].Resolve(ctx));
}
[Test]
public void GenericDelegate_ReferenceTypeConstraints()
{
ITypeDefinition type = ctx.GetTypeDefinition(typeof(GenericDelegate<,>));
Assert.IsFalse(type.TypeParameters[0].HasReferenceTypeConstraint);
Assert.IsTrue(type.TypeParameters[1].HasReferenceTypeConstraint);
Assert.IsFalse(type.TypeParameters[0].GetConstraints(ctx).HasReferenceTypeConstraint);
Assert.IsTrue(type.TypeParameters[1].GetConstraints(ctx).HasReferenceTypeConstraint);
Assert.IsNull(type.TypeParameters[0].IsReferenceType(ctx));
Assert.AreEqual(true, type.TypeParameters[1].IsReferenceType(ctx));

4
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -118,6 +118,7 @@ @@ -118,6 +118,7 @@
<Compile Include="TypeSystem\Implementation\AbstractFreezable.cs" />
<Compile Include="TypeSystem\Implementation\AbstractMember.cs" />
<Compile Include="TypeSystem\Implementation\AbstractType.cs" />
<Compile Include="TypeSystem\Implementation\AbstractTypeParameter.cs" />
<Compile Include="TypeSystem\Implementation\BaseTypeCollector.cs" />
<Compile Include="TypeSystem\Implementation\CompoundTypeDefinition.cs" />
<Compile Include="TypeSystem\Implementation\DefaultAccessor.cs" />
@ -129,6 +130,7 @@ @@ -129,6 +130,7 @@
<Compile Include="TypeSystem\Implementation\DefaultParameter.cs" />
<Compile Include="TypeSystem\Implementation\DefaultProperty.cs" />
<Compile Include="TypeSystem\Implementation\DefaultTypeParameter.cs" />
<Compile Include="TypeSystem\Implementation\DefaultTypeParameterConstraints.cs" />
<Compile Include="TypeSystem\Implementation\GetClassTypeReference.cs" />
<Compile Include="TypeSystem\Implementation\CompositeTypeResolveContext.cs" />
<Compile Include="TypeSystem\Implementation\GetMembersHelper.cs" />
@ -146,10 +148,12 @@ @@ -146,10 +148,12 @@
<Compile Include="TypeSystem\Implementation\SpecializedMethod.cs" />
<Compile Include="TypeSystem\Implementation\SpecializedProperty.cs" />
<Compile Include="TypeSystem\Implementation\SubstitutionTypeReference.cs" />
<Compile Include="TypeSystem\Implementation\TypeParameterWithInheritedConstraints.cs" />
<Compile Include="TypeSystem\Implementation\TypeStorage.cs" />
<Compile Include="TypeSystem\Implementation\TypeWithElementType.cs" />
<Compile Include="TypeSystem\Implementation\VoidTypeDefinition.cs" />
<Compile Include="TypeSystem\INamedElement.cs" />
<Compile Include="TypeSystem\InheritanceHelper.cs" />
<Compile Include="TypeSystem\IntersectionType.cs" />
<Compile Include="TypeSystem\IParameter.cs" />
<Compile Include="TypeSystem\IParameterizedMember.cs" />

43
ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs

@ -48,44 +48,55 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -48,44 +48,55 @@ namespace ICSharpCode.NRefactory.TypeSystem
IList<IAttribute> Attributes { get; }
/// <summary>
/// Gets the constraints of this type parameter.
/// Gets the variance of this type parameter.
/// </summary>
IList<ITypeReference> Constraints { get; }
VarianceModifier Variance { get; }
/// <summary>
/// Gets if the type parameter has the 'new()' constraint.
/// Gets the region where the type parameter is defined.
/// </summary>
bool HasDefaultConstructorConstraint { get; }
DomRegion Region { get; }
/// <summary>
/// Gets if the type parameter has the 'class' constraint.
/// Gets the effective base class of this type parameter.
/// </summary>
bool HasReferenceTypeConstraint { get; }
IType GetEffectiveBaseClass(ITypeResolveContext context);
/// <summary>
/// Gets if the type parameter has the 'struct' constraint.
/// Gets the effective interface set of this type parameter.
/// </summary>
bool HasValueTypeConstraint { get; }
IEnumerable<IType> GetEffectiveInterfaceSet(ITypeResolveContext context);
/// <summary>
/// Gets the variance of this type parameter.
/// Gets the constraints of this type parameter.
/// </summary>
VarianceModifier Variance { get; }
ITypeParameterConstraints GetConstraints(ITypeResolveContext context);
}
/// <summary>
/// Represents the constraints on a type parameter.
/// </summary>
public interface ITypeParameterConstraints : IList<IType>
{
/// <summary>
/// Gets if the type parameter has the 'new()' constraint.
/// </summary>
bool HasDefaultConstructorConstraint { get; }
/// <summary>
/// Gets the region where the type parameter is defined.
/// Gets if the type parameter has the 'class' constraint.
/// </summary>
DomRegion Region { get; }
bool HasReferenceTypeConstraint { get; }
/// <summary>
/// Gets the effective base class of this type parameter.
/// Gets if the type parameter has the 'struct' constraint.
/// </summary>
IType GetEffectiveBaseClass(ITypeResolveContext context);
bool HasValueTypeConstraint { get; }
/// <summary>
/// Gets the effective interface set of this type parameter.
/// Applies a substitution to the constraints.
/// </summary>
IEnumerable<IType> GetEffectiveInterfaceSet(ITypeResolveContext context);
ITypeParameterConstraints ApplySubstitution(TypeVisitor substitution);
}
/// <summary>

332
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractTypeParameter.cs

@ -0,0 +1,332 @@ @@ -0,0 +1,332 @@
// 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 System.Linq;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
/// <summary>
/// Base class for <see cref="ITypeParameter"/> implementations.
/// </summary>
[Serializable]
public abstract class AbstractTypeParameter : AbstractFreezable, ITypeParameter
{
EntityType ownerType;
int index;
string name;
IList<IAttribute> attributes;
DomRegion region;
VarianceModifier variance;
protected override void FreezeInternal()
{
attributes = FreezeList(attributes);
base.FreezeInternal();
}
protected AbstractTypeParameter(EntityType ownerType, int index, string name)
{
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.ownerType = ownerType;
this.index = index;
this.name = name;
}
public EntityType OwnerType {
get { return ownerType; }
}
public int Index {
get { return index; }
}
public TypeKind Kind {
get { return TypeKind.TypeParameter; }
}
public string Name {
get { return name; }
}
string INamedElement.FullName {
get { return name; }
}
string INamedElement.Namespace {
get { return string.Empty; }
}
public string ReflectionName {
get {
if (this.OwnerType == EntityType.Method)
return "``" + index.ToString();
else
return "`" + index.ToString();
}
}
public abstract bool? IsReferenceType(ITypeResolveContext context);
protected bool? IsReferenceTypeHelper(IType effectiveBaseClass)
{
// A type parameter is known to be a reference type if it has the reference type constraint
// or its effective base class is not object or System.ValueType.
if (effectiveBaseClass.Kind == TypeKind.Class || effectiveBaseClass.Kind == TypeKind.Delegate) {
if (effectiveBaseClass.Namespace == "System" && effectiveBaseClass.TypeParameterCount == 0) {
switch (effectiveBaseClass.Name) {
case "Object":
case "ValueType":
case "Enum":
return null;
}
}
return true;
} else if (effectiveBaseClass.Kind == TypeKind.Struct || effectiveBaseClass.Kind == TypeKind.Enum) {
return false;
}
return null;
}
int IType.TypeParameterCount {
get { return 0; }
}
IType IType.DeclaringType {
get { return null; }
}
ITypeDefinition IType.GetDefinition()
{
return null;
}
IType ITypeReference.Resolve(ITypeResolveContext context)
{
return this;
}
public virtual bool Equals(IType other)
{
// Use reference equality for type parameters. While we could consider any types with same
// ownerType + index as equal for the type system, doing so makes it difficult to cache calculation
// results based on types - e.g. the cache in the Conversions class.
return this == other;
// We can still consider type parameters of different methods/classes to be equal to each other,
// if they have been interned. But then also all constraints are equal, so caching conversions
// are valid in that case.
}
public IList<IAttribute> Attributes {
get {
if (attributes == null)
attributes = new List<IAttribute>();
return attributes;
}
}
public VarianceModifier Variance {
get { return variance; }
set {
CheckBeforeMutation();
variance = value;
}
}
public DomRegion Region {
get { return region; }
set {
CheckBeforeMutation();
region = value;
}
}
public IType AcceptVisitor(TypeVisitor visitor)
{
return visitor.VisitTypeParameter(this);
}
public IType VisitChildren(TypeVisitor visitor)
{
return this;
}
static readonly SimpleProjectContent dummyProjectContent = new SimpleProjectContent();
DefaultTypeDefinition GetDummyClassForTypeParameter(ITypeParameterConstraints constraints)
{
DefaultTypeDefinition c = new DefaultTypeDefinition(dummyProjectContent, string.Empty, this.Name);
c.Region = this.Region;
if (constraints.HasValueTypeConstraint) {
c.Kind = TypeKind.Struct;
} else if (constraints.HasDefaultConstructorConstraint) {
c.Kind = TypeKind.Class;
} else {
c.Kind = TypeKind.Interface;
}
return c;
}
public IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) {
ITypeParameterConstraints constraints = GetConstraints(context);
if (constraints.HasDefaultConstructorConstraint || constraints.HasValueTypeConstraint) {
DefaultMethod m = DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter(constraints));
if (filter(m))
return new [] { m };
}
return EmptyList<IMethod>.Instance;
} else {
return GetMembersHelper.GetConstructors(this, context, filter, options);
}
}
public IEnumerable<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IMethod>.Instance;
else
return GetMembersHelper.GetMethods(this, context, FilterNonStatic(filter), options);
}
public IEnumerable<IMethod> GetMethods(IList<IType> typeArguments, ITypeResolveContext context, Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IMethod>.Instance;
else
return GetMembersHelper.GetMethods(this, typeArguments, context, FilterNonStatic(filter), options);
}
public IEnumerable<IProperty> GetProperties(ITypeResolveContext context, Predicate<IProperty> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IProperty>.Instance;
else
return GetMembersHelper.GetProperties(this, context, FilterNonStatic(filter), options);
}
public IEnumerable<IField> GetFields(ITypeResolveContext context, Predicate<IField> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IField>.Instance;
else
return GetMembersHelper.GetFields(this, context, FilterNonStatic(filter), options);
}
public IEnumerable<IEvent> GetEvents(ITypeResolveContext context, Predicate<IEvent> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IEvent>.Instance;
else
return GetMembersHelper.GetEvents(this, context, FilterNonStatic(filter), options);
}
public IEnumerable<IMember> GetMembers(ITypeResolveContext context, Predicate<IMember> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IMember>.Instance;
else
return GetMembersHelper.GetMembers(this, context, FilterNonStatic(filter), options);
}
static Predicate<T> FilterNonStatic<T>(Predicate<T> filter) where T : class, IMember
{
if (filter == null)
return member => !member.IsStatic;
else
return member => !member.IsStatic && filter(member);
}
IEnumerable<IType> IType.GetNestedTypes(ITypeResolveContext context, Predicate<ITypeDefinition> filter, GetMemberOptions options)
{
return EmptyList<IType>.Instance;
}
IEnumerable<IType> IType.GetNestedTypes(IList<IType> typeArguments, ITypeResolveContext context, Predicate<ITypeDefinition> filter, GetMemberOptions options)
{
return EmptyList<IType>.Instance;
}
public abstract IType GetEffectiveBaseClass(ITypeResolveContext context);
public abstract IEnumerable<IType> GetEffectiveInterfaceSet(ITypeResolveContext context);
public abstract ITypeParameterConstraints GetConstraints(ITypeResolveContext context);
public virtual IEnumerable<IType> GetBaseTypes(ITypeResolveContext context)
{
ITypeParameterConstraints constraints = GetConstraints(context);
bool hasNonInterfaceConstraint = false;
foreach (IType c in constraints) {
yield return c;
if (c.Kind != TypeKind.Interface)
hasNonInterfaceConstraint = true;
}
// Do not add the 'System.Object' constraint if there is another constraint with a base class.
if (constraints.HasValueTypeConstraint || !hasNonInterfaceConstraint) {
IType defaultBaseType = context.GetTypeDefinition("System", constraints.HasValueTypeConstraint ? "ValueType" : "Object", 0, StringComparer.Ordinal);
if (defaultBaseType != null)
yield return defaultBaseType;
}
}
protected virtual void PrepareForInterning(IInterningProvider provider)
{
name = provider.Intern(name);
attributes = provider.InternList(attributes);
}
protected virtual int GetHashCodeForInterning()
{
unchecked {
int hashCode = index + name.GetHashCode();
if (ownerType == EntityType.Method)
hashCode += 7613561;
if (attributes != null)
hashCode += attributes.GetHashCode();
hashCode += 900103 * (int)variance;
return hashCode;
}
}
protected bool EqualsForInterning(AbstractTypeParameter other)
{
return other != null
&& this.attributes == other.attributes
&& this.name == other.name
&& this.ownerType == other.ownerType
&& this.index == other.index
&& this.variance == other.variance;
}
public override string ToString()
{
return this.ReflectionName;
}
}
}

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

@ -28,18 +28,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -28,18 +28,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// Default implementation of <see cref="ITypeParameter"/>.
/// </summary>
[Serializable]
public sealed class DefaultTypeParameter : AbstractFreezable, ITypeParameter, ISupportsInterning
public sealed class DefaultTypeParameter : AbstractTypeParameter, ISupportsInterning
{
string name;
int index;
IList<ITypeReference> constraints;
IList<IAttribute> attributes;
DomRegion region;
// Small fields: byte+byte+short
VarianceModifier variance;
EntityType ownerType;
BitVector16 flags;
const ushort FlagReferenceTypeConstraint = 0x0001;
@ -49,131 +41,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -49,131 +41,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
protected override void FreezeInternal()
{
constraints = FreezeList(constraints);
attributes = FreezeList(attributes);
base.FreezeInternal();
}
public DefaultTypeParameter(EntityType ownerType, int index, string name)
: base(ownerType, index, name)
{
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.ownerType = ownerType;
this.index = index;
this.name = name;
}
public TypeKind Kind {
get { return TypeKind.TypeParameter; }
}
public string Name {
get { return name; }
}
string INamedElement.FullName {
get { return name; }
}
string INamedElement.Namespace {
get { return string.Empty; }
}
public string ReflectionName {
get {
if (ownerType == EntityType.Method)
return "``" + index.ToString();
else
return "`" + index.ToString();
}
}
public bool? IsReferenceType(ITypeResolveContext context)
{
switch (flags.Data & (FlagReferenceTypeConstraint | FlagValueTypeConstraint)) {
case FlagReferenceTypeConstraint:
return true;
case FlagValueTypeConstraint:
return false;
}
// A type parameter is known to be a reference type if it has the reference type constraint
// or its effective base class is not object or System.ValueType.
IType baseClass = GetEffectiveBaseClass(context);
if (baseClass.Kind == TypeKind.Class) {
if (baseClass.Namespace == "System" && baseClass.TypeParameterCount == 0) {
switch (baseClass.Name) {
case "Object":
case "ValueType":
case "Enum":
return null;
}
}
return true;
}
return null;
}
int IType.TypeParameterCount {
get { return 0; }
}
IType IType.DeclaringType {
get { return null; }
}
ITypeDefinition IType.GetDefinition()
{
return null;
}
IType ITypeReference.Resolve(ITypeResolveContext context)
{
return this;
}
// public override int GetHashCode()
// {
// unchecked {
// return (int)ownerType * 178256151 + index;
// }
// }
//
// public override bool Equals(object obj)
// {
// return Equals(obj as IType);
// }
public bool Equals(IType other)
{
// Use reference equality for type parameters. While we could consider any types with same
// ownerType + index as equal for the type system, doing so makes it difficult to cache calculation
// results based on types - e.g. the cache in the Conversions class.
return this == other;
// We can still consider type parameters of different methods/classes to be equal to each other,
// if they have been interned. But then also all constraints are equal, so caching conversions
// is valid in that case.
}
public EntityType OwnerType {
get {
return ownerType;
}
}
public int Index {
get { return index; }
}
public IList<IAttribute> Attributes {
get {
if (attributes == null)
attributes = new List<IAttribute>();
return attributes;
}
}
public IList<ITypeReference> Constraints {
@ -208,129 +81,19 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -208,129 +81,19 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
}
public VarianceModifier Variance {
get { return variance; }
set {
CheckBeforeMutation();
variance = value;
}
}
public DomRegion Region {
get { return region; }
set {
CheckBeforeMutation();
region = value;
}
}
public IType AcceptVisitor(TypeVisitor visitor)
{
return visitor.VisitTypeParameter(this);
}
public IType VisitChildren(TypeVisitor visitor)
{
return this;
}
static readonly SimpleProjectContent dummyProjectContent = new SimpleProjectContent();
DefaultTypeDefinition GetDummyClassForTypeParameter()
{
DefaultTypeDefinition c = new DefaultTypeDefinition(dummyProjectContent, string.Empty, this.Name);
c.Region = this.Region;
if (HasValueTypeConstraint) {
c.Kind = TypeKind.Struct;
} else if (HasDefaultConstructorConstraint) {
c.Kind = TypeKind.Class;
} else {
c.Kind = TypeKind.Interface;
}
return c;
}
public IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers)
public override bool? IsReferenceType(ITypeResolveContext context)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) {
if (HasDefaultConstructorConstraint || HasValueTypeConstraint) {
DefaultMethod m = DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter());
if (filter(m))
return new [] { m };
}
return EmptyList<IMethod>.Instance;
} else {
return GetMembersHelper.GetConstructors(this, context, filter, options);
switch (flags.Data & (FlagReferenceTypeConstraint | FlagValueTypeConstraint)) {
case FlagReferenceTypeConstraint:
return true;
case FlagValueTypeConstraint:
return false;
}
return base.IsReferenceTypeHelper(GetEffectiveBaseClass(context));
}
public IEnumerable<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IMethod>.Instance;
else
return GetMembersHelper.GetMethods(this, context, FilterNonStatic(filter), options);
}
public IEnumerable<IMethod> GetMethods(IList<IType> typeArguments, ITypeResolveContext context, Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IMethod>.Instance;
else
return GetMembersHelper.GetMethods(this, typeArguments, context, FilterNonStatic(filter), options);
}
public IEnumerable<IProperty> GetProperties(ITypeResolveContext context, Predicate<IProperty> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IProperty>.Instance;
else
return GetMembersHelper.GetProperties(this, context, FilterNonStatic(filter), options);
}
public IEnumerable<IField> GetFields(ITypeResolveContext context, Predicate<IField> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IField>.Instance;
else
return GetMembersHelper.GetFields(this, context, FilterNonStatic(filter), options);
}
public IEnumerable<IEvent> GetEvents(ITypeResolveContext context, Predicate<IEvent> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IEvent>.Instance;
else
return GetMembersHelper.GetEvents(this, context, FilterNonStatic(filter), options);
}
public IEnumerable<IMember> GetMembers(ITypeResolveContext context, Predicate<IMember> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers)
return EmptyList<IMember>.Instance;
else
return GetMembersHelper.GetMembers(this, context, FilterNonStatic(filter), options);
}
static Predicate<T> FilterNonStatic<T>(Predicate<T> filter) where T : class, IMember
{
if (filter == null)
return member => !member.IsStatic;
else
return member => !member.IsStatic && filter(member);
}
IEnumerable<IType> IType.GetNestedTypes(ITypeResolveContext context, Predicate<ITypeDefinition> filter, GetMemberOptions options)
{
return EmptyList<IType>.Instance;
}
IEnumerable<IType> IType.GetNestedTypes(IList<IType> typeArguments, ITypeResolveContext context, Predicate<ITypeDefinition> filter, GetMemberOptions options)
{
return EmptyList<IType>.Instance;
}
public IType GetEffectiveBaseClass(ITypeResolveContext context)
public override IType GetEffectiveBaseClass(ITypeResolveContext context)
{
// protect against cyclic type parameters
using (var busyLock = BusyManager.Enter(this)) {
@ -363,7 +126,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -363,7 +126,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
}
public IEnumerable<IType> GetEffectiveInterfaceSet(ITypeResolveContext context)
public override IEnumerable<IType> GetEffectiveInterfaceSet(ITypeResolveContext context)
{
List<IType> result = new List<IType>();
// protect against cyclic type parameters
@ -382,21 +145,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -382,21 +145,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return result.Distinct();
}
public IEnumerable<IType> GetBaseTypes(ITypeResolveContext context)
public override ITypeParameterConstraints GetConstraints(ITypeResolveContext context)
{
bool hasNonInterfaceConstraint = false;
foreach (ITypeReference constraint in this.Constraints) {
IType c = constraint.Resolve(context);
yield return c;
if (c.Kind != TypeKind.Interface)
hasNonInterfaceConstraint = true;
}
// Do not add the 'System.Object' constraint if there is another constraint with a base class.
if (HasValueTypeConstraint || !hasNonInterfaceConstraint) {
IType defaultBaseType = context.GetTypeDefinition("System", HasValueTypeConstraint ? "ValueType" : "Object", 0, StringComparer.Ordinal);
if (defaultBaseType != null)
yield return defaultBaseType;
}
return new DefaultTypeParameterConstraints(
this.Constraints.Select(c => c.Resolve(context)),
this.HasDefaultConstructorConstraint, this.HasReferenceTypeConstraint, this.HasValueTypeConstraint);
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
@ -405,7 +158,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -405,7 +158,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) {
constraints = provider.InternList(constraints);
attributes = provider.InternList(attributes);
base.PrepareForInterning(provider);
}
}
}
@ -413,14 +166,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -413,14 +166,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
int ISupportsInterning.GetHashCodeForInterning()
{
unchecked {
int hashCode = GetHashCode();
if (name != null)
hashCode += name.GetHashCode();
if (attributes != null)
hashCode += attributes.GetHashCode();
int hashCode = base.GetHashCodeForInterning();
if (constraints != null)
hashCode += constraints.GetHashCode();
hashCode += 771 * flags.Data + 900103 * (int)variance;
hashCode += 771 * flags.Data;
return hashCode;
}
}
@ -428,19 +177,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -428,19 +177,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
DefaultTypeParameter o = other as DefaultTypeParameter;
return o != null
&& this.attributes == o.attributes
return base.EqualsForInterning(o)
&& this.constraints == o.constraints
&& this.name == o.name
&& this.flags == o.flags
&& this.ownerType == o.ownerType
&& this.index == o.index
&& this.variance == o.variance;
}
public override string ToString()
{
return this.ReflectionName;
&& this.flags == o.flags;
}
}
}

57
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameterConstraints.cs

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
// 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 System.Collections.ObjectModel;
using System.Linq;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
/// <summary>
/// Implementation of <see cref="ITypeParameterConstraints".
/// </summary>
public sealed class DefaultTypeParameterConstraints : ReadOnlyCollection<IType>, ITypeParameterConstraints
{
public static readonly ITypeParameterConstraints Empty = new DefaultTypeParameterConstraints(new IType[0], false, false, false);
public bool HasDefaultConstructorConstraint { get; private set; }
public bool HasReferenceTypeConstraint { get; private set; }
public bool HasValueTypeConstraint { get; private set; }
public DefaultTypeParameterConstraints(IEnumerable<IType> constraints, bool hasDefaultConstructorConstraint, bool hasReferenceTypeConstraint, bool hasValueTypeConstraint)
: base(constraints.ToArray())
{
this.HasDefaultConstructorConstraint = hasDefaultConstructorConstraint;
this.HasReferenceTypeConstraint = hasReferenceTypeConstraint;
this.HasValueTypeConstraint = hasValueTypeConstraint;
}
public ITypeParameterConstraints ApplySubstitution(TypeVisitor substitution)
{
if (substitution == null)
throw new ArgumentNullException("substitution");
if (this.Count == 0)
return this;
else
return new DefaultTypeParameterConstraints(
this.Select(c => c.AcceptVisitor(substitution)),
this.HasDefaultConstructorConstraint, this.HasReferenceTypeConstraint, this.HasValueTypeConstraint);
}
}
}

99
ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterWithInheritedConstraints.cs

@ -0,0 +1,99 @@ @@ -0,0 +1,99 @@
// 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 System.Linq;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
/// <summary>
/// Represents a type parameter that inherits its constraints from the overridden method in the base class.
/// </summary>
public sealed class TypeParameterWithInheritedConstraints : AbstractTypeParameter
{
readonly IMethod parentMethod;
public TypeParameterWithInheritedConstraints(IMethod parentMethod, int index, string name)
: base(EntityType.Method, index, name)
{
if (parentMethod == null)
throw new ArgumentNullException("parentMethod");
this.parentMethod = parentMethod;
}
ITypeParameter ResolveBaseTypeParameter(ITypeResolveContext context)
{
IMethod baseMethod = null;
if (parentMethod.IsOverride) {
foreach (IMethod m in InheritanceHelper.GetBaseMembers(parentMethod, context, false).OfType<IMethod>()) {
if (!m.IsOverride) {
baseMethod = m;
break;
}
}
} else if (parentMethod.InterfaceImplementations.Count == 1) {
IType interfaceType = parentMethod.InterfaceImplementations[0].InterfaceType.Resolve(context);
baseMethod = InheritanceHelper.GetMatchingMethodInBaseType(parentMethod, interfaceType, context);
}
if (baseMethod != null && this.Index < baseMethod.TypeParameters.Count)
return baseMethod.TypeParameters[this.Index];
else
return null;
}
public override bool? IsReferenceType(ITypeResolveContext context)
{
ITypeParameter baseTp = ResolveBaseTypeParameter(context);
if (baseTp == null)
return null;
bool? result = baseTp.IsReferenceType(context);
if (result != null)
return result;
IType effectiveBaseClass = baseTp.GetEffectiveBaseClass(context);
return IsReferenceTypeHelper(effectiveBaseClass);
}
public override IEnumerable<IType> GetEffectiveInterfaceSet(ITypeResolveContext context)
{
ITypeParameter baseTp = ResolveBaseTypeParameter(context);
if (baseTp == null)
return EmptyList<IType>.Instance;
else
return baseTp.GetEffectiveInterfaceSet(context);
}
public override IType GetEffectiveBaseClass(ITypeResolveContext context)
{
ITypeParameter baseTp = ResolveBaseTypeParameter(context);
if (baseTp == null)
return SharedTypes.UnknownType;
else
return baseTp.GetEffectiveBaseClass(context);
}
public override ITypeParameterConstraints GetConstraints(ITypeResolveContext context)
{
ITypeParameter baseTp = ResolveBaseTypeParameter(context);
if (baseTp == null)
return DefaultTypeParameterConstraints.Empty;
else
return baseTp.GetConstraints(context);
}
}
}

167
ICSharpCode.NRefactory/TypeSystem/InheritanceHelper.cs

@ -0,0 +1,167 @@ @@ -0,0 +1,167 @@
// 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 System.Linq;
namespace ICSharpCode.NRefactory.TypeSystem
{
/// <summary>
/// Provides helper methods for inheritance.
/// </summary>
public class InheritanceHelper
{
// TODO: maybe these should be extension methods?
#region GetBaseMember
/// <summary>
/// Gets the base member that has the same signature.
/// </summary>
public static IMember GetBaseMember(IMember member, ITypeResolveContext context)
{
return GetBaseMembers(member, context, false).FirstOrDefault();
}
/// <summary>
/// Gets all base members that have the same signature.
/// </summary>
/// <returns>
/// List of base members with the same signature. The member from the derived-most base class is returned first.
/// </returns>
public static IEnumerable<IMember> GetBaseMembers(IMember member, ITypeResolveContext context, bool includeImplementedInterfaces)
{
if (member == null)
throw new ArgumentNullException("member");
if (context == null)
throw new ArgumentNullException("context");
member = member.MemberDefinition;
IMethod method = member as IMethod;
IProperty property = member as IProperty;
IEvent ev = member as IEvent;
IField field = member as IField;
using (var ctx = context.Synchronize()) {
IEnumerable<IType> allBaseTypes;
if (includeImplementedInterfaces) {
allBaseTypes = member.DeclaringTypeDefinition.GetAllBaseTypes(ctx);
} else {
allBaseTypes = member.DeclaringTypeDefinition.GetNonInterfaceBaseTypes(ctx);
}
foreach (IType baseType in allBaseTypes.Reverse()) {
if (baseType == member.DeclaringTypeDefinition)
continue;
if (method != null) {
IMethod baseMethod = GetMatchingMethodInBaseType(method, baseType, ctx);
if (baseMethod != null)
yield return baseMethod;
}
if (property != null) {
foreach (IProperty baseProperty in baseType.GetProperties(
ctx, p => p.Name == property.Name && p.Parameters.Count == property.Parameters.Count,
GetMemberOptions.IgnoreInheritedMembers))
{
if (ParameterListComparer.Compare(ctx, property, baseProperty))
yield return baseProperty;
}
}
if (ev != null) {
IEvent baseEvent = baseType.GetEvents(ctx, e => e.Name == ev.Name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
if (baseEvent != null)
yield return baseEvent;
}
// Fields can't be overridden, but we handle them anyways, just for consistence
if (field != null) {
IField baseField = baseType.GetFields(ctx, f => f.Name == field.Name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
if (baseField != null)
yield return baseField;
}
}
}
}
internal static IMethod GetMatchingMethodInBaseType(IMethod method, IType baseType, ITypeResolveContext context)
{
foreach (IMethod baseMethod in baseType.GetMethods(
context, m => m.Name == method.Name && m.Parameters.Count == method.Parameters.Count && m.TypeParameters.Count == method.TypeParameters.Count,
GetMemberOptions.IgnoreInheritedMembers))
{
if (ParameterListComparer.Compare(context, method, baseMethod))
return baseMethod;
}
return null;
}
#endregion
#region GetDerivedMember
/// <summary>
/// Finds the member declared in 'derivedType' that has the same signature (could override) 'baseMember'.
/// </summary>
public static IMember GetDerivedMember(IMember baseMember, ITypeDefinition derivedType, ITypeResolveContext context)
{
if (baseMember == null)
throw new ArgumentNullException("baseMember");
if (derivedType == null)
throw new ArgumentNullException("derivedType");
if (context == null)
throw new ArgumentNullException("context");
baseMember = baseMember.MemberDefinition;
bool includeInterfaces = baseMember.DeclaringTypeDefinition.Kind == TypeKind.Interface;
IMethod method = baseMember as IMethod;
if (method != null) {
using (var ctx = context.Synchronize()) {
foreach (IMethod derivedMethod in derivedType.Methods) {
if (derivedMethod.Name == method.Name && derivedMethod.Parameters.Count == method.Parameters.Count) {
if (derivedMethod.TypeParameters.Count == method.TypeParameters.Count) {
// The method could override the base method:
if (GetBaseMembers(derivedMethod, ctx, includeInterfaces).Any(m => m.MemberDefinition == baseMember))
return derivedMethod;
}
}
}
}
}
IProperty property = baseMember as IProperty;
if (property != null) {
using (var ctx = context.Synchronize()) {
foreach (IProperty derivedProperty in derivedType.Properties) {
if (derivedProperty.Name == property.Name && derivedProperty.Parameters.Count == property.Parameters.Count) {
// The property could override the base property:
if (GetBaseMembers(derivedProperty, ctx, includeInterfaces).Any(m => m.MemberDefinition == baseMember))
return derivedProperty;
}
}
}
}
if (baseMember is IEvent) {
foreach (IEvent derivedEvent in derivedType.Events) {
if (derivedEvent.Name == baseMember.Name)
return derivedEvent;
}
}
if (baseMember is IField) {
foreach (IField derivedField in derivedType.Fields) {
if (derivedField.Name == baseMember.Name)
return derivedField;
}
}
return null;
}
#endregion
}
}

9
ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs

@ -155,15 +155,6 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -155,15 +155,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
return this;
}
/// <summary>
/// Substitutes the class type parameters in the <paramref name="type"/> with the
/// type arguments of this parameterized type.
/// </summary>
public IType SubstituteInType(IType type)
{
return type.AcceptVisitor(new TypeParameterSubstitution(typeArguments, null));
}
/// <summary>
/// Gets a type visitor that performs the substitution of class type parameters with the type arguments
/// of this parameterized type.

Loading…
Cancel
Save