|
|
@ -94,48 +94,73 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation |
|
|
|
|
|
|
|
|
|
|
|
public IType EffectiveBaseClass { |
|
|
|
public IType EffectiveBaseClass { |
|
|
|
get { |
|
|
|
get { |
|
|
|
if (effectiveBaseClass == null) |
|
|
|
if (effectiveBaseClass == null) { |
|
|
|
effectiveBaseClass = CalculateEffectiveBaseClass(); |
|
|
|
// protect against cyclic type parameters
|
|
|
|
|
|
|
|
using (var busyLock = BusyManager.Enter(this)) { |
|
|
|
|
|
|
|
if (!busyLock.Success) |
|
|
|
|
|
|
|
return SpecialType.UnknownType; // don't cache this error
|
|
|
|
|
|
|
|
effectiveBaseClass = CalculateEffectiveBaseClass(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
return effectiveBaseClass; |
|
|
|
return effectiveBaseClass; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
IType CalculateEffectiveBaseClass() |
|
|
|
IType CalculateEffectiveBaseClass() |
|
|
|
{ |
|
|
|
{ |
|
|
|
// protect against cyclic type parameters
|
|
|
|
if (HasValueTypeConstraint) |
|
|
|
using (var busyLock = BusyManager.Enter(this)) { |
|
|
|
return this.Compilation.FindType(KnownTypeCode.ValueType); |
|
|
|
if (!busyLock.Success) |
|
|
|
|
|
|
|
return SpecialType.UnknownType; |
|
|
|
List<IType> classTypeConstraints = new List<IType>(); |
|
|
|
|
|
|
|
foreach (IType constraint in this.DirectBaseTypes) { |
|
|
|
if (HasValueTypeConstraint) |
|
|
|
if (constraint.Kind == TypeKind.Class) { |
|
|
|
return this.Compilation.FindType(KnownTypeCode.ValueType); |
|
|
|
classTypeConstraints.Add(constraint); |
|
|
|
|
|
|
|
} else if (constraint.Kind == TypeKind.TypeParameter) { |
|
|
|
List<IType> classTypeConstraints = new List<IType>(); |
|
|
|
IType baseClass = ((ITypeParameter)constraint).EffectiveBaseClass; |
|
|
|
foreach (IType constraint in this.DirectBaseTypes) { |
|
|
|
if (baseClass.Kind == TypeKind.Class) |
|
|
|
if (constraint.Kind == TypeKind.Class) { |
|
|
|
classTypeConstraints.Add(baseClass); |
|
|
|
classTypeConstraints.Add(constraint); |
|
|
|
|
|
|
|
} else if (constraint.Kind == TypeKind.TypeParameter) { |
|
|
|
|
|
|
|
IType baseClass = ((ITypeParameter)constraint).EffectiveBaseClass; |
|
|
|
|
|
|
|
if (baseClass.Kind == TypeKind.Class) |
|
|
|
|
|
|
|
classTypeConstraints.Add(baseClass); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (classTypeConstraints.Count == 0) |
|
|
|
|
|
|
|
return this.Compilation.FindType(KnownTypeCode.Object); |
|
|
|
|
|
|
|
// 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())) |
|
|
|
|
|
|
|
result = classTypeConstraints[i]; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (classTypeConstraints.Count == 0) |
|
|
|
|
|
|
|
return this.Compilation.FindType(KnownTypeCode.Object); |
|
|
|
|
|
|
|
// 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())) |
|
|
|
|
|
|
|
result = classTypeConstraints[i]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public IList<IType> EffectiveInterfaceSet { |
|
|
|
ICollection<IType> effectiveInterfaceSet; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ICollection<IType> EffectiveInterfaceSet { |
|
|
|
get { |
|
|
|
get { |
|
|
|
throw new NotImplementedException(); |
|
|
|
var result = LazyInit.VolatileRead(ref effectiveInterfaceSet); |
|
|
|
|
|
|
|
if (result != null) { |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// protect against cyclic type parameters
|
|
|
|
|
|
|
|
using (var busyLock = BusyManager.Enter(this)) { |
|
|
|
|
|
|
|
if (!busyLock.Success) |
|
|
|
|
|
|
|
return EmptyList<IType>.Instance; // don't cache this error
|
|
|
|
|
|
|
|
return LazyInit.GetOrSet(ref effectiveInterfaceSet, CalculateEffectiveInterfaceSet()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ICollection<IType> CalculateEffectiveInterfaceSet() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
HashSet<IType> result = new HashSet<IType>(); |
|
|
|
|
|
|
|
foreach (IType constraint in this.DirectBaseTypes) { |
|
|
|
|
|
|
|
if (constraint.Kind == TypeKind.Interface) { |
|
|
|
|
|
|
|
result.Add(constraint); |
|
|
|
|
|
|
|
} else if (constraint.Kind == TypeKind.TypeParameter) { |
|
|
|
|
|
|
|
result.UnionWith(((ITypeParameter)constraint).EffectiveInterfaceSet); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public abstract bool HasDefaultConstructorConstraint { get; } |
|
|
|
public abstract bool HasDefaultConstructorConstraint { get; } |
|
|
|