Browse Source

DefaultResolvedTypeDefinition: lazily initialize the list of members.

This makes creating a DefaultResolvedTypeDefinition much cheaper, so we no longer need to use Lazy<ITypeDefinition> in CSharpAssembly.
newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
59c9e99921
  1. 30
      ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs
  2. 277
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs
  3. 114
      ICSharpCode.NRefactory/Utils/ProjectedList.cs

30
ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs

@ -179,9 +179,9 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -179,9 +179,9 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
return fullAssemblyName.Substring(0, pos);
}
Dictionary<FullNameAndTypeParameterCount, Lazy<ITypeDefinition>> typeDict;
Dictionary<FullNameAndTypeParameterCount, ITypeDefinition> typeDict;
Dictionary<FullNameAndTypeParameterCount, Lazy<ITypeDefinition>> GetTypes()
Dictionary<FullNameAndTypeParameterCount, ITypeDefinition> GetTypes()
{
var dict = this.typeDict;
if (dict != null) {
@ -199,26 +199,24 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -199,26 +199,24 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
}
}
Lazy<ITypeDefinition> CreateResolvedTypeDefinition(IUnresolvedTypeDefinition[] parts)
ITypeDefinition CreateResolvedTypeDefinition(IUnresolvedTypeDefinition[] parts)
{
return new Lazy<ITypeDefinition>(
() => new DefaultResolvedTypeDefinition(context, parts),
LazyThreadSafetyMode.PublicationOnly);
return new DefaultResolvedTypeDefinition(context, parts);
}
public ITypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount)
{
var key = new FullNameAndTypeParameterCount(ns ?? string.Empty, name, typeParameterCount);
Lazy<ITypeDefinition> def;
ITypeDefinition def;
if (GetTypes().TryGetValue(key, out def))
return def.Value;
return def;
else
return null;
}
public IEnumerable<ITypeDefinition> TopLevelTypeDefinitions {
get {
return GetTypes().Values.Select(t => t.Value);
return GetTypes().Values;
}
}
@ -234,7 +232,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -234,7 +232,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
readonly string fullName;
readonly string name;
internal readonly List<NS> childNamespaces = new List<NS>();
internal readonly Dictionary<FullNameAndTypeParameterCount, Lazy<ITypeDefinition>> types;
internal readonly Dictionary<FullNameAndTypeParameterCount, ITypeDefinition> types;
public NS(CSharpAssembly assembly)
{
@ -244,7 +242,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -244,7 +242,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
// Our main dictionary for the CSharpAssembly is using an ordinal comparer.
// If the compilation's comparer isn't ordinal, we need to create a new dictionary with the compilation's comparer.
if (assembly.compilation.NameComparer != StringComparer.Ordinal) {
this.types = new Dictionary<FullNameAndTypeParameterCount, Lazy<ITypeDefinition>>(new FullNameAndTypeParameterCountComparer(assembly.compilation.NameComparer));
this.types = new Dictionary<FullNameAndTypeParameterCount, ITypeDefinition>(new FullNameAndTypeParameterCountComparer(assembly.compilation.NameComparer));
}
}
@ -255,7 +253,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -255,7 +253,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
this.fullName = fullName;
this.name = name;
if (parentNamespace.types != null)
this.types = new Dictionary<FullNameAndTypeParameterCount, Lazy<ITypeDefinition>>(parentNamespace.types.Comparer);
this.types = new Dictionary<FullNameAndTypeParameterCount, ITypeDefinition>(parentNamespace.types.Comparer);
}
string INamespace.ExternAlias {
@ -281,12 +279,12 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -281,12 +279,12 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
IEnumerable<ITypeDefinition> INamespace.Types {
get {
if (types != null)
return types.Values.Select(t => t.Value);
return types.Values;
else
return (
from t in assembly.GetTypes()
where t.Key.Namespace == fullName
select t.Value.Value
select t.Value
);
}
}
@ -309,9 +307,9 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -309,9 +307,9 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
{
if (types != null) {
var key = new FullNameAndTypeParameterCount(fullName, name, typeParameterCount);
Lazy<ITypeDefinition> typeDef;
ITypeDefinition typeDef;
if (types.TryGetValue(key, out typeDef))
return typeDef.Value;
return typeDef;
else
return null;
} else {

277
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs

@ -33,8 +33,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -33,8 +33,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
readonly ITypeResolveContext parentContext;
readonly IUnresolvedTypeDefinition[] parts;
Accessibility accessibility = Accessibility.Internal;
List<IUnresolvedMember> unresolvedMembers = new List<IUnresolvedMember>();
ProjectedListWithContextPerElement<ITypeResolveContext, IUnresolvedMember, IMember> resolvedMembers;
bool isAbstract, isSealed, isShadowing;
bool isSynthetic = true; // true if all parts are synthetic
@ -46,68 +44,70 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -46,68 +44,70 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
throw new ArgumentException("No parts were specified", "parts");
this.parentContext = parentContext;
this.parts = parts;
ITypeResolveContext contextForTypeParameters = parts[0].CreateResolveContext(parentContext);
contextForTypeParameters = contextForTypeParameters.WithCurrentTypeDefinition(this);
if (parentContext.CurrentTypeDefinition == null || parentContext.CurrentTypeDefinition.TypeParameterCount == 0) {
this.TypeParameters = parts[0].TypeParameters.CreateResolvedTypeParameters(contextForTypeParameters);
} else {
// This is a nested class inside a generic class; copy type parameters from outer class if we can:
var outerClass = parentContext.CurrentTypeDefinition;
ITypeParameter[] typeParameters = new ITypeParameter[parts[0].TypeParameters.Count];
for (int i = 0; i < typeParameters.Length; i++) {
var unresolvedTP = parts[0].TypeParameters[i];
if (i < outerClass.TypeParameterCount && outerClass.TypeParameters[i].Name == unresolvedTP.Name)
typeParameters[i] = outerClass.TypeParameters[i];
else
typeParameters[i] = unresolvedTP.CreateResolvedTypeParameter(contextForTypeParameters);
}
this.TypeParameters = Array.AsReadOnly(typeParameters);
}
List<IUnresolvedAttribute> unresolvedAttributes = new List<IUnresolvedAttribute>();
List<ITypeResolveContext> contextPerAttribute = new List<ITypeResolveContext>();
List<ITypeResolveContext> contextPerMember = new List<ITypeResolveContext>();
bool addDefaultConstructorIfRequired = false;
foreach (IUnresolvedTypeDefinition part in parts) {
ITypeResolveContext parentContextForPart = part.CreateResolveContext(parentContext);
ITypeResolveContext contextForPart = parentContextForPart.WithCurrentTypeDefinition(this);
foreach (var attr in part.Attributes) {
unresolvedAttributes.Add(attr);
contextPerAttribute.Add(parentContextForPart);
}
foreach (var member in part.Members) {
unresolvedMembers.Add(member);
contextPerMember.Add(contextForPart);
}
isAbstract |= part.IsAbstract;
isSealed |= part.IsSealed;
isShadowing |= part.IsShadowing;
isSynthetic &= part.IsSynthetic; // true if all parts are synthetic
DefaultUnresolvedTypeDefinition dutd = part as DefaultUnresolvedTypeDefinition;
if (dutd != null) {
addDefaultConstructorIfRequired |= dutd.AddDefaultConstructorIfRequired;
}
// internal is the default, so use another part's accessibility until we find a non-internal accessibility
if (accessibility == Accessibility.Internal)
accessibility = part.Accessibility;
}
if (addDefaultConstructorIfRequired) {
TypeKind kind = this.Kind;
if (kind == TypeKind.Class && !this.IsStatic && !unresolvedMembers.Any(m => m.EntityType == EntityType.Constructor && !m.IsStatic)
|| kind == TypeKind.Enum || kind == TypeKind.Struct)
{
contextPerMember.Add(parts[0].CreateResolveContext(parentContext).WithCurrentTypeDefinition(this));
unresolvedMembers.Add(DefaultUnresolvedMethod.CreateDefaultConstructor(parts[0]));
}
IList<ITypeParameter> typeParameters;
public IList<ITypeParameter> TypeParameters {
get {
var result = this.typeParameters;
if (result != null) {
LazyInit.ReadBarrier();
return result;
}
ITypeResolveContext contextForTypeParameters = parts[0].CreateResolveContext(parentContext);
contextForTypeParameters = contextForTypeParameters.WithCurrentTypeDefinition(this);
if (parentContext.CurrentTypeDefinition == null || parentContext.CurrentTypeDefinition.TypeParameterCount == 0) {
result = parts[0].TypeParameters.CreateResolvedTypeParameters(contextForTypeParameters);
} else {
// This is a nested class inside a generic class; copy type parameters from outer class if we can:
var outerClass = parentContext.CurrentTypeDefinition;
ITypeParameter[] typeParameters = new ITypeParameter[parts[0].TypeParameters.Count];
for (int i = 0; i < typeParameters.Length; i++) {
var unresolvedTP = parts[0].TypeParameters[i];
if (i < outerClass.TypeParameterCount && outerClass.TypeParameters[i].Name == unresolvedTP.Name)
typeParameters[i] = outerClass.TypeParameters[i];
else
typeParameters[i] = unresolvedTP.CreateResolvedTypeParameter(contextForTypeParameters);
}
result = Array.AsReadOnly(typeParameters);
}
return LazyInit.GetOrSet(ref this.typeParameters, result);
}
this.Attributes = new ProjectedListWithContextPerElement<ITypeResolveContext, IUnresolvedAttribute, IAttribute>(contextPerAttribute, unresolvedAttributes, (c, a) => a.CreateResolvedAttribute(c));
this.resolvedMembers = new ProjectedListWithContextPerElement<ITypeResolveContext, IUnresolvedMember, IMember>(contextPerMember, unresolvedMembers, (c, m) => m.CreateResolved(c));
}
public IList<ITypeParameter> TypeParameters { get; private set; }
public IList<IAttribute> Attributes { get; private set; }
IList<IAttribute> attributes;
public IList<IAttribute> Attributes {
get {
var result = this.attributes;
if (result != null) {
LazyInit.ReadBarrier();
return result;
}
result = new List<IAttribute>();
foreach (IUnresolvedTypeDefinition part in parts) {
ITypeResolveContext parentContextForPart = part.CreateResolveContext(parentContext);
foreach (var attr in part.Attributes) {
result.Add(attr.CreateResolvedAttribute(parentContextForPart));
}
}
if (result.Count == 0)
result = EmptyList<IAttribute>.Instance;
return LazyInit.GetOrSet(ref this.attributes, result);
}
}
public IList<IUnresolvedTypeDefinition> Parts {
get { return parts; }
@ -121,6 +121,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -121,6 +121,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return parts[0].Kind; }
}
#region NestedTypes
IList<ITypeDefinition> nestedTypes;
public IList<ITypeDefinition> NestedTypes {
@ -140,37 +141,170 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -140,37 +141,170 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
}
}
#endregion
#region Members
sealed class MemberList : IList<IMember>
{
internal readonly ITypeResolveContext[] contextPerMember;
internal readonly IUnresolvedMember[] unresolvedMembers;
internal readonly IMember[] resolvedMembers;
public MemberList(ITypeResolveContext[] contextPerMember, IUnresolvedMember[] unresolvedMembers)
{
this.contextPerMember = contextPerMember;
this.unresolvedMembers = unresolvedMembers;
this.resolvedMembers = new IMember[unresolvedMembers.Length];
}
public IMember this[int index] {
get {
IMember output = resolvedMembers[index];
if (output != null) {
LazyInit.ReadBarrier();
return output;
}
return LazyInit.GetOrSet(ref resolvedMembers[index], unresolvedMembers[index].CreateResolved(contextPerMember[index]));
}
set { throw new NotSupportedException(); }
}
public int Count {
get { return unresolvedMembers.Length; }
}
bool ICollection<IMember>.IsReadOnly {
get { return true; }
}
public int IndexOf(IMember item)
{
for (int i = 0; i < this.Count; i++) {
if (this[i].Equals(item))
return i;
}
return -1;
}
void IList<IMember>.Insert(int index, IMember item)
{
throw new NotSupportedException();
}
void IList<IMember>.RemoveAt(int index)
{
throw new NotSupportedException();
}
void ICollection<IMember>.Add(IMember item)
{
throw new NotSupportedException();
}
void ICollection<IMember>.Clear()
{
throw new NotSupportedException();
}
bool ICollection<IMember>.Contains(IMember item)
{
return IndexOf(item) >= 0;
}
void ICollection<IMember>.CopyTo(IMember[] array, int arrayIndex)
{
for (int i = 0; i < this.Count; i++) {
array[arrayIndex + i] = this[i];
}
}
bool ICollection<IMember>.Remove(IMember item)
{
throw new NotSupportedException();
}
public IEnumerator<IMember> GetEnumerator()
{
for (int i = 0; i < this.Count; i++) {
yield return this[i];
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
MemberList memberList;
MemberList GetMemberList()
{
var result = this.memberList;
if (result != null) {
LazyInit.ReadBarrier();
return result;
}
List<IUnresolvedMember> unresolvedMembers = new List<IUnresolvedMember>();
List<ITypeResolveContext> contextPerMember = new List<ITypeResolveContext>();
bool addDefaultConstructorIfRequired = false;
foreach (IUnresolvedTypeDefinition part in parts) {
ITypeResolveContext parentContextForPart = part.CreateResolveContext(parentContext);
ITypeResolveContext contextForPart = parentContextForPart.WithCurrentTypeDefinition(this);
foreach (var member in part.Members) {
unresolvedMembers.Add(member);
contextPerMember.Add(contextForPart);
}
DefaultUnresolvedTypeDefinition dutd = part as DefaultUnresolvedTypeDefinition;
if (dutd != null) {
addDefaultConstructorIfRequired |= dutd.AddDefaultConstructorIfRequired;
}
}
if (addDefaultConstructorIfRequired) {
TypeKind kind = this.Kind;
if (kind == TypeKind.Class && !this.IsStatic && !unresolvedMembers.Any(m => m.EntityType == EntityType.Constructor && !m.IsStatic)
|| kind == TypeKind.Enum || kind == TypeKind.Struct)
{
contextPerMember.Add(parts[0].CreateResolveContext(parentContext).WithCurrentTypeDefinition(this));
unresolvedMembers.Add(DefaultUnresolvedMethod.CreateDefaultConstructor(parts[0]));
}
}
return LazyInit.GetOrSet(ref this.memberList, new MemberList(contextPerMember.ToArray(), unresolvedMembers.ToArray()));
}
public IList<IMember> Members {
get { return resolvedMembers; }
get { return GetMemberList(); }
}
public IEnumerable<IField> Fields {
get {
for (int i = 0; i < unresolvedMembers.Count; i++) {
if (unresolvedMembers[i].EntityType == EntityType.Field)
yield return (IField)resolvedMembers[i];
var members = GetMemberList();
for (int i = 0; i < members.Count; i++) {
if (members.unresolvedMembers[i].EntityType == EntityType.Field)
yield return (IField)members[i];
}
}
}
public IEnumerable<IMethod> Methods {
get {
for (int i = 0; i < unresolvedMembers.Count; i++) {
if (unresolvedMembers[i] is IUnresolvedMethod)
yield return (IMethod)resolvedMembers[i];
var members = GetMemberList();
for (int i = 0; i < members.Count; i++) {
if (members.unresolvedMembers[i] is IUnresolvedMethod)
yield return (IMethod)members[i];
}
}
}
public IEnumerable<IProperty> Properties {
get {
for (int i = 0; i < unresolvedMembers.Count; i++) {
switch (unresolvedMembers[i].EntityType) {
var members = GetMemberList();
for (int i = 0; i < members.Count; i++) {
switch (members.unresolvedMembers[i].EntityType) {
case EntityType.Property:
case EntityType.Indexer:
yield return (IProperty)resolvedMembers[i];
yield return (IProperty)members[i];
break;
}
}
@ -179,9 +313,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -179,9 +313,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IEnumerable<IEvent> Events {
get {
for (int i = 0; i < unresolvedMembers.Count; i++) {
if (unresolvedMembers[i].EntityType == EntityType.Event)
yield return (IEvent)resolvedMembers[i];
var members = GetMemberList();
for (int i = 0; i < members.Count; i++) {
if (members.unresolvedMembers[i].EntityType == EntityType.Event)
yield return (IEvent)members[i];
}
}
}
@ -289,7 +424,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -289,7 +424,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
public int TypeParameterCount {
get { return this.TypeParameters.Count; }
get { return parts[0].TypeParameters.Count; }
}
#region DirectBaseTypes
@ -504,19 +639,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -504,19 +639,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
#region GetMembers()
IEnumerable<IMember> GetFilteredMembers(Predicate<IUnresolvedMember> filter)
{
for (int i = 0; i < unresolvedMembers.Count; i++) {
if (filter == null || filter(unresolvedMembers[i])) {
yield return resolvedMembers[i];
var members = GetMemberList();
for (int i = 0; i < members.Count; i++) {
if (filter == null || filter(members.unresolvedMembers[i])) {
yield return members[i];
}
}
}
IEnumerable<TResolved> GetFilteredMembers<TUnresolved, TResolved>(Predicate<TUnresolved> filter) where TUnresolved : class, IUnresolvedMember where TResolved : class, IMember
{
for (int i = 0; i < unresolvedMembers.Count; i++) {
TUnresolved unresolved = unresolvedMembers[i] as TUnresolved;
var members = GetMemberList();
for (int i = 0; i < members.Count; i++) {
TUnresolved unresolved = members.unresolvedMembers[i] as TUnresolved;
if (unresolved != null && (filter == null || filter(unresolved))) {
yield return (TResolved)resolvedMembers[i];
yield return (TResolved)members[i];
}
}
}

114
ICSharpCode.NRefactory/Utils/ProjectedList.cs

@ -238,118 +238,4 @@ namespace ICSharpCode.NRefactory.Utils @@ -238,118 +238,4 @@ namespace ICSharpCode.NRefactory.Utils
return GetEnumerator();
}
}
public sealed class ProjectedListWithContextPerElement<TContext, TInput, TOutput> : IList<TOutput> where TOutput : class
{
readonly IList<TInput> input;
readonly IList<TContext> context;
readonly Func<TContext, TInput, TOutput> projection;
readonly TOutput[] items;
public ProjectedListWithContextPerElement(IList<TContext> context, IList<TInput> input, Func<TContext, TInput, TOutput> projection)
{
if (context == null)
throw new ArgumentNullException("context");
if (input == null)
throw new ArgumentNullException("input");
if (projection == null)
throw new ArgumentNullException("projection");
if (context.Count != input.Count)
throw new ArgumentException("context list must have same length as input list");
this.input = input;
this.context = context;
this.projection = projection;
this.items = new TOutput[input.Count];
}
public TOutput this[int index] {
get {
TOutput output = items[index];
if (output != null) {
LazyInit.ReadBarrier();
return output;
}
return LazyInit.GetOrSet(ref items[index], projection(context[index], input[index]));
}
}
TOutput IList<TOutput>.this[int index] {
get { return this[index]; }
set {
throw new NotSupportedException();
}
}
public int Count {
get { return items.Length; }
}
bool ICollection<TOutput>.IsReadOnly {
get { return true; }
}
int IList<TOutput>.IndexOf(TOutput item)
{
var comparer = EqualityComparer<TOutput>.Default;
for (int i = 0; i < this.Count; i++) {
if (comparer.Equals(this[i], item))
return i;
}
return -1;
}
void IList<TOutput>.Insert(int index, TOutput item)
{
throw new NotSupportedException();
}
void IList<TOutput>.RemoveAt(int index)
{
throw new NotSupportedException();
}
void ICollection<TOutput>.Add(TOutput item)
{
throw new NotSupportedException();
}
void ICollection<TOutput>.Clear()
{
throw new NotSupportedException();
}
bool ICollection<TOutput>.Contains(TOutput item)
{
var comparer = EqualityComparer<TOutput>.Default;
for (int i = 0; i < this.Count; i++) {
if (comparer.Equals(this[i], item))
return true;
}
return false;
}
void ICollection<TOutput>.CopyTo(TOutput[] array, int arrayIndex)
{
for (int i = 0; i < items.Length; i++) {
array[arrayIndex + i] = this[i];
}
}
bool ICollection<TOutput>.Remove(TOutput item)
{
throw new NotSupportedException();
}
public IEnumerator<TOutput> GetEnumerator()
{
for (int i = 0; i < this.Count; i++) {
yield return this[i];
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

Loading…
Cancel
Save