diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
index 55095c94c5..593bcf5892 100644
--- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
+++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
@@ -58,6 +58,7 @@
+
diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs
new file mode 100644
index 0000000000..eb1826f9c7
--- /dev/null
+++ b/ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs
@@ -0,0 +1,44 @@
+// Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+
+using System;
+using System.Linq;
+using ICSharpCode.NRefactory.TypeSystem.Implementation;
+using NUnit.Framework;
+
+namespace ICSharpCode.NRefactory.TypeSystem
+{
+ [TestFixture]
+ public class GetMembersTests
+ {
+ IProjectContent mscorlib = CecilLoaderTests.Mscorlib;
+
+ [Test]
+ public void EmptyClassHasToString()
+ {
+ DefaultTypeDefinition c = new DefaultTypeDefinition(mscorlib, string.Empty, "C");
+ Assert.AreEqual("System.Object.ToString", c.GetMethods(mscorlib, m => m.Name == "ToString").Single().FullName);
+ }
+
+ [Test]
+ public void MultipleInheritanceTest()
+ {
+ DefaultTypeDefinition b1 = new DefaultTypeDefinition(mscorlib, string.Empty, "B1");
+ b1.ClassType = ClassType.Interface;
+ b1.Properties.Add(new DefaultProperty(b1, "P1"));
+
+ DefaultTypeDefinition b2 = new DefaultTypeDefinition(mscorlib, string.Empty, "B1");
+ b2.ClassType = ClassType.Interface;
+ b2.Properties.Add(new DefaultProperty(b1, "P2"));
+
+ DefaultTypeDefinition c = new DefaultTypeDefinition(mscorlib, string.Empty, "C");
+ c.ClassType = ClassType.Interface;
+ c.BaseTypes.Add(b1);
+ c.BaseTypes.Add(b2);
+
+ Assert.AreEqual(new[] { "P1", "P2" }, c.GetProperties(mscorlib).Select(p => p.Name).ToArray());
+ // Test that there's only one copy of ToString():
+ Assert.AreEqual(1, c.GetMethods(mscorlib, m => m.Name == "ToString").Count());
+ }
+ }
+}
diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/AmbiguousResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/AmbiguousResolveResult.cs
index 8ee3262aa5..3c17dd65f3 100644
--- a/ICSharpCode.NRefactory/CSharp/Resolver/AmbiguousResolveResult.cs
+++ b/ICSharpCode.NRefactory/CSharp/Resolver/AmbiguousResolveResult.cs
@@ -19,4 +19,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
get { return true; }
}
}
+
+ public class AmbiguousMemberResultResult : MemberResolveResult
+ {
+ public AmbiguousMemberResultResult(IMember member, IType returnType) : base(member, returnType)
+ {
+ }
+
+ public override bool IsError {
+ get { return true; }
+ }
+ }
}
diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
index 7059a293e1..fda25cb2fc 100644
--- a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
+++ b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
@@ -1341,20 +1341,28 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region ResolveSimpleName
+ enum SimpleNameLookupMode
+ {
+ Expression,
+ Type,
+ TypeInUsingDeclaration
+ }
+
public ResolveResult ResolveSimpleName(string identifier, IList typeArguments)
{
// C# 4.0 spec: §7.6.2 Simple Names
// TODO: lookup in local variables, in parameters, etc.
- return LookupSimpleNameOrTypeName(identifier, typeArguments, false);
+ return LookupSimpleNameOrTypeName(identifier, typeArguments, SimpleNameLookupMode.Expression);
}
- public ResolveResult LookupSimpleNamespaceOrTypeName(string identifier, IList typeArguments)
+ public ResolveResult LookupSimpleNamespaceOrTypeName(string identifier, IList typeArguments, bool isUsingDeclaration = false)
{
- return LookupSimpleNameOrTypeName(identifier, typeArguments, true);
+ return LookupSimpleNameOrTypeName(identifier, typeArguments,
+ isUsingDeclaration ? SimpleNameLookupMode.TypeInUsingDeclaration : SimpleNameLookupMode.Type);
}
- ResolveResult LookupSimpleNameOrTypeName(string identifier, IList typeArguments, bool typeOnly)
+ ResolveResult LookupSimpleNameOrTypeName(string identifier, IList typeArguments, SimpleNameLookupMode lookupMode)
{
// C# 4.0 spec: §3.8 Namespace and type names; §7.6.2 Simple Names
@@ -1381,11 +1389,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
- if (typeOnly) {
- // TODO: perform member lookup within the type t, restricted to finding types
+ if (lookupMode == SimpleNameLookupMode.Expression) {
+ // TODO: perform member lookup within the type t
} else {
- // TODO: perform member lookup within the type t
+ // TODO: perform member lookup within the type t, restricted to finding types
+
}
}
// look in current namespace definitions
@@ -1415,41 +1424,66 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (k == 0) {
if (n.ExternAliases.Contains(identifier)) {
// TODO: implement extern alias support
- throw new NotImplementedException();
+ return new NamespaceResolveResult(string.Empty);
}
- foreach (var pair in n.UsingAliases) {
- if (pair.Key == identifier) {
- string ns = pair.Value.ResolveNamespace(context);
- if (ns != null)
- return new NamespaceResolveResult(ns);
- else
- return new TypeResolveResult(pair.Value.Resolve(context));
+ if (lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration || n != this.UsingScope) {
+ foreach (var pair in n.UsingAliases) {
+ if (pair.Key == identifier) {
+ NamespaceResolveResult ns = pair.Value.ResolveNamespace(context);
+ if (ns != null)
+ return ns;
+ else
+ return new TypeResolveResult(pair.Value.Resolve(context));
+ }
}
}
}
// finally, look in the imported namespaces:
- IType firstResult = null;
- foreach (var u in n.Usings) {
- string ns = u.ResolveNamespace(context);
- if (ns != null) {
- fullName = NamespaceDeclaration.BuildQualifiedName(ns, identifier);
- def = context.GetClass(ns, k, StringComparer.Ordinal);
- if (firstResult == null) {
- if (k == 0)
- firstResult = def;
- else
- firstResult = new ParameterizedType(def, typeArguments);
- } else {
- return new AmbiguousTypeResolveResult(firstResult);
+ if (lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration || n != this.UsingScope) {
+ IType firstResult = null;
+ foreach (var u in n.Usings) {
+ NamespaceResolveResult ns = u.ResolveNamespace(context);
+ if (ns != null) {
+ fullName = NamespaceDeclaration.BuildQualifiedName(ns.NamespaceName, identifier);
+ def = context.GetClass(fullName, k, StringComparer.Ordinal);
+ if (firstResult == null) {
+ if (k == 0)
+ firstResult = def;
+ else
+ firstResult = new ParameterizedType(def, typeArguments);
+ } else {
+ return new AmbiguousTypeResolveResult(firstResult);
+ }
}
}
+ if (firstResult != null)
+ return new TypeResolveResult(firstResult);
}
- if (firstResult != null)
- return new TypeResolveResult(firstResult);
// if we didn't find anything: repeat lookup with parent namespace
}
return ErrorResult;
}
+
+ ///
+ /// Looks up an alias (identifier in front of :: operator)
+ ///
+ public ResolveResult ResolveAlias(string identifier)
+ {
+ if (identifier == "global")
+ return new NamespaceResolveResult(string.Empty);
+ for (UsingScope n = this.UsingScope; n != null; n = n.Parent) {
+ if (n.ExternAliases.Contains(identifier)) {
+ // TODO: implement extern alias support
+ return new NamespaceResolveResult(string.Empty);
+ }
+ foreach (var pair in n.UsingAliases) {
+ if (pair.Key == identifier) {
+ return pair.Value.ResolveNamespace(context) ?? ErrorResult;
+ }
+ }
+ }
+ return ErrorResult;
+ }
#endregion
}
}
diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ITypeOrNamespaceReference.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ITypeOrNamespaceReference.cs
index 53a4abf3de..fb8b80eda4 100644
--- a/ICSharpCode.NRefactory/CSharp/Resolver/ITypeOrNamespaceReference.cs
+++ b/ICSharpCode.NRefactory/CSharp/Resolver/ITypeOrNamespaceReference.cs
@@ -11,6 +11,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
///
public interface ITypeOrNamespaceReference : ITypeReference
{
- string ResolveNamespace(ITypeResolveContext context);
+ ///
+ /// Returns the namespace that is referenced; or null if no such namespace is found.
+ ///
+ NamespaceResolveResult ResolveNamespace(ITypeResolveContext context);
}
}
diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs b/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs
index 57285f6317..e3611030d6 100644
--- a/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs
+++ b/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs
@@ -3,6 +3,8 @@
using System;
using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -27,7 +29,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return true;
return member.ReturnType.Resolve(context).IsDelegate();
}
-
#endregion
ITypeResolveContext context;
@@ -48,9 +49,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Gets whether is accessible in the current class.
///
/// The entity to test
- /// The type used to access the member, or null if no target is used (e.g. static method call)
- /// true if the member is accessible
- public bool IsAccessible(IEntity entity, IType typeOfReference)
+ /// Whether protected access is allowed.
+ /// True if the type of the reference is derived from the current class.
+ public bool IsAccessible(IEntity entity, bool allowProtectedAccess)
{
if (entity == null)
throw new ArgumentNullException("entity");
@@ -63,14 +64,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
case Accessibility.Public:
return true;
case Accessibility.Protected:
- return IsProtectedAccessible(entity.DeclaringTypeDefinition, typeOfReference);
+ return allowProtectedAccess && IsProtectedAccessible(entity.DeclaringTypeDefinition);
case Accessibility.Internal:
return IsInternalAccessible(entity.ProjectContent);
case Accessibility.ProtectedOrInternal:
- return IsProtectedAccessible(entity.DeclaringTypeDefinition, typeOfReference)
+ return (allowProtectedAccess && IsProtectedAccessible(entity.DeclaringTypeDefinition))
|| IsInternalAccessible(entity.ProjectContent);
case Accessibility.ProtectedAndInternal:
- return IsProtectedAccessible(entity.DeclaringTypeDefinition, typeOfReference)
+ return (allowProtectedAccess && IsProtectedAccessible(entity.DeclaringTypeDefinition))
&& IsInternalAccessible(entity.ProjectContent);
default:
throw new Exception("Invalid value for Accessibility");
@@ -82,19 +83,140 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return declaringProject != null && currentProject != null && declaringProject.InternalsVisibleTo(currentProject, context);
}
- bool IsProtectedAccessible(ITypeDefinition declaringType, IType typeOfReference)
+ bool IsProtectedAccessible(ITypeDefinition declaringType)
{
if (declaringType == currentTypeDefinition)
return true;
// PERF: this might hurt performance as this method is called several times (once for each member)
// make sure resolving base types is cheap (caches?) or cache within the MemberLookup instance
- if (currentTypeDefinition == null || !currentTypeDefinition.IsDerivedFrom(declaringType, context))
- return false;
- if (typeOfReference == null)
- return true; // no restriction on the type of reference
- ITypeDefinition referenceDef = typeOfReference.GetDefinition();
- return referenceDef != null && referenceDef.IsDerivedFrom(currentTypeDefinition, context);
+ return currentTypeDefinition != null && currentTypeDefinition.IsDerivedFrom(declaringType, context);
}
#endregion
+
+ ///
+ /// Performs a member lookup.
+ ///
+ public ResolveResult Lookup(IType type, string name, int typeParameterCount, bool isInvocation)
+ {
+ List types = new List();
+ List members = new List();
+ if (!isInvocation) {
+ // Consider nested types only if it's not an invocation. The type parameter count must match in this case.
+ types.AddRange(type.GetNestedTypes(context,
+ d => d.TypeParameterCount == typeParameterCount
+ && d.Name == name && IsAccessible(d, true)));
+ }
+
+ ITypeDefinition typeDef = type.GetDefinition();
+ bool allowProtectedAccess = typeDef != null && typeDef.IsDerivedFrom(currentTypeDefinition, context);
+
+ if (typeParameterCount == 0) {
+ Predicate memberFilter = delegate(IMember member) {
+ return !member.IsOverride && member.Name == name && IsAccessible(member, allowProtectedAccess);
+ };
+ members.AddRange(type.GetMethods(context, memberFilter));
+ members.AddRange(type.GetProperties(context, memberFilter));
+ members.AddRange(type.GetFields(context, memberFilter));
+ members.AddRange(type.GetEvents(context, memberFilter));
+ if (isInvocation)
+ members.RemoveAll(m => IsInvocable(m, context));
+ } else {
+ // No need to check for isInvocation/isInvocable here:
+ // we filter out all non-methods
+ Predicate memberFilter = delegate(IMethod method) {
+ return method.TypeParameters.Count == typeParameterCount
+ && !method.IsOverride && method.Name == name && IsAccessible(method, allowProtectedAccess);
+ };
+ members.AddRange(type.GetMethods(context, memberFilter));
+ }
+
+ // remove types hidden by other types
+ for (int i = types.Count - 1; i >= 0; i--) {
+ ITypeDefinition d = GetDeclaringTypeDef(types[i]);
+ if (d == null)
+ continue;
+ // nested loop depends on the fact that the members of more derived classes appear later in the list
+ for (int j = i + 1; j < types.Count; j++) {
+ if (types[i].TypeParameterCount != types[j].TypeParameterCount)
+ continue;
+ ITypeDefinition s = GetDeclaringTypeDef(types[j]);
+ if (s != null && s != d && s.IsDerivedFrom(d, context)) {
+ // types[j] hides types[i]
+ types.RemoveAt(i);
+ break;
+ }
+ }
+ }
+ // remove members hidden by types
+ for (int i = 0; i < types.Count; i++) {
+ ITypeDefinition d = GetDeclaringTypeDef(types[i]);
+ if (d != null)
+ members.RemoveAll(m => d.IsDerivedFrom(m.DeclaringTypeDefinition, context));
+ }
+ // remove members hidden by other members
+ for (int i = members.Count - 1; i >= 0; i--) {
+ ITypeDefinition d = members[i].DeclaringTypeDefinition;
+ IMethod mi = members[i] as IMethod;
+ // nested loop depends on the fact that the members of more derived classes appear later in the list
+ for (int j = i + 1; j < members.Count; j++) {
+ if (mi != null) {
+ IMethod mj = members[j] as IMethod;
+ if (mj != null && !ParameterListComparer.Instance.Equals(mi, mj))
+ continue;
+ }
+ ITypeDefinition s = members[j].DeclaringTypeDefinition;
+ if (s != null && s != d && s.IsDerivedFrom(d, context)) {
+ // members[j] hides members[i]
+ members.RemoveAt(i);
+ break;
+ }
+ }
+ }
+ // remove interface members hidden by class members
+ if (type is ITypeParameter) {
+ // this can happen only with type parameters
+ for (int i = members.Count - 1; i >= 0; i--) {
+ ITypeDefinition d = members[i].DeclaringTypeDefinition;
+ if (d.ClassType != ClassType.Interface)
+ continue;
+ IMethod mi = members[i] as IMethod;
+ for (int j = 0; j < members.Count; j++) {
+ if (mi != null) {
+ IMethod mj = members[j] as IMethod;
+ if (mj != null && !ParameterListComparer.Instance.Equals(mi, mj))
+ continue;
+ }
+ ITypeDefinition s = members[j].DeclaringTypeDefinition;
+ if (s != null && IsNonInterfaceType(s)) {
+ // members[j] hides members[i]
+ members.RemoveAt(i);
+ break;
+ }
+ }
+ }
+ }
+
+ if (types.Count == 1 && members.Count == 0)
+ return new TypeResolveResult(types[0]);
+ if (types.Count > 0)
+ return new AmbiguousTypeResolveResult(types[0]);
+ IMember firstNonMethod = members.FirstOrDefault(m => !(m is IMethod));
+ if (members.Count == 1 && firstNonMethod != null)
+ return new MemberResolveResult(firstNonMethod, firstNonMethod.ReturnType.Resolve(context));
+ if (firstNonMethod == null)
+ return new MethodGroupResolveResult(members.ConvertAll(m => (IMethod)m));
+ return new AmbiguousMemberResultResult(firstNonMethod, firstNonMethod.ReturnType.Resolve(context));
+ }
+
+ static bool IsNonInterfaceType(ITypeDefinition def)
+ {
+ return def.ClassType != ClassType.Interface && !(def.Name == "Object" && def.Namespace == "System" && def.TypeParameterCount == 0);
+ }
+
+ static ITypeDefinition GetDeclaringTypeDef(IType type)
+ {
+ IType declType = type.DeclaringType;
+ return declType != null ? declType.GetDefinition() : null;
+ }
}
}
diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs
new file mode 100644
index 0000000000..75e47eba4e
--- /dev/null
+++ b/ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs
@@ -0,0 +1,25 @@
+// Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+
+using System;
+using ICSharpCode.NRefactory.TypeSystem;
+
+namespace ICSharpCode.NRefactory.CSharp.Resolver
+{
+ ///
+ /// Represents the result of a member invocation.
+ ///
+ public class MemberResolveResult : ResolveResult
+ {
+ readonly IMember member;
+
+ public MemberResolveResult(IMember member, IType returnType) : base(returnType)
+ {
+ this.member = member;
+ }
+
+ public IMember Member {
+ get { return member; }
+ }
+ }
+}
diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs
new file mode 100644
index 0000000000..a698c8be89
--- /dev/null
+++ b/ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs
@@ -0,0 +1,30 @@
+// Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+using ICSharpCode.NRefactory.TypeSystem;
+
+namespace ICSharpCode.NRefactory.CSharp.Resolver
+{
+ ///
+ /// Represents a group of methods.
+ ///
+ public class MethodGroupResolveResult : ResolveResult
+ {
+ readonly ReadOnlyCollection methods;
+
+ public MethodGroupResolveResult(IList methods) : base(SharedTypes.UnknownType)
+ {
+ if (methods == null)
+ throw new ArgumentNullException("methods");
+ this.methods = new ReadOnlyCollection(methods);
+ }
+
+ public ReadOnlyCollection Methods {
+ get { return methods; }
+ }
+ }
+}
diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs b/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs
index cbd4528469..280ac98994 100644
--- a/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs
+++ b/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs
@@ -9,44 +9,42 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
///
- /// Represents a simple C# name. (a single identifier with an optional list of type arguments)
+ /// Represents a simple C# name. (a single non-qualified identifier with an optional list of type arguments)
///
public sealed class SimpleTypeOrNamespaceReference : ITypeOrNamespaceReference
{
- readonly IMember parentMember;
readonly ITypeDefinition parentTypeDefinition;
readonly UsingScope parentUsingScope;
readonly string identifier;
readonly IList typeArguments;
+ readonly bool isInUsingDeclaration;
- public SimpleTypeOrNamespaceReference(string identifier, IList typeArguments, IMember parentMember, ITypeDefinition parentTypeDefinition, UsingScope parentUsingScope)
+ public SimpleTypeOrNamespaceReference(string identifier, IList typeArguments, ITypeDefinition parentTypeDefinition, UsingScope parentUsingScope, bool isInUsingDeclaration = false)
{
if (identifier == null)
throw new ArgumentNullException("identifier");
this.identifier = identifier;
this.typeArguments = typeArguments ?? EmptyList.Instance;
- this.parentMember = parentMember;
this.parentTypeDefinition = parentTypeDefinition;
this.parentUsingScope = parentUsingScope;
+ this.isInUsingDeclaration = isInUsingDeclaration;
}
ResolveResult DoResolve(ITypeResolveContext context)
{
CSharpResolver r = new CSharpResolver(context);
- r.CurrentMember = parentMember;
r.CurrentTypeDefinition = parentTypeDefinition.GetCompoundClass();
r.UsingScope = parentUsingScope;
IType[] typeArgs = new IType[typeArguments.Count];
for (int i = 0; i < typeArgs.Length; i++) {
typeArgs[i] = typeArguments[i].Resolve(context);
}
- return r.LookupSimpleNamespaceOrTypeName(identifier, typeArgs);
+ return r.LookupSimpleNamespaceOrTypeName(identifier, typeArgs, isInUsingDeclaration);
}
- public string ResolveNamespace(ITypeResolveContext context)
+ public NamespaceResolveResult ResolveNamespace(ITypeResolveContext context)
{
- NamespaceResolveResult nrr = DoResolve(context) as NamespaceResolveResult;
- return nrr != null ? nrr.NamespaceName : null;
+ return DoResolve(context) as NamespaceResolveResult;
}
public IType Resolve(ITypeResolveContext context)
diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
index 53c16e9397..bfa9ecae9e 100644
--- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
+++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
@@ -147,6 +147,8 @@
+
+
@@ -212,6 +214,7 @@
+
diff --git a/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs b/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs
index 8fcbc60b0c..f15f100f5a 100644
--- a/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs
@@ -46,22 +46,55 @@ namespace ICSharpCode.NRefactory.TypeSystem
return a != null && elementType.Equals(a.elementType) && a.dimensions == dimensions;
}
+ static readonly GetClassTypeReference systemArray = new GetClassTypeReference("System.Array", 0);
+ static readonly GetClassTypeReference listInterface = new GetClassTypeReference("System.Collections.Generic.IList", 1);
+
public override IEnumerable GetBaseTypes(ITypeResolveContext context)
{
List baseTypes = new List();
- // PERF: if profiling shows the GetClass(typeof()) here to be a problem, create
- // a static cache for the ITypeDefinitions
- ITypeDefinition t = context.GetClass(typeof(Array));
- if (t != null)
+ IType t = systemArray.Resolve(context);
+ if (t != SharedTypes.UnknownType)
baseTypes.Add(t);
if (dimensions == 1) { // single-dimensional arrays implement IList
- t = context.GetClass(typeof(IList<>));
- if (t != null)
- baseTypes.Add(new ParameterizedType(t, new[] { elementType }));
+ ITypeDefinition def = listInterface.Resolve(context) as ITypeDefinition;
+ if (def != null)
+ baseTypes.Add(new ParameterizedType(def, new[] { elementType }));
}
return baseTypes;
}
+ public override IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null)
+ {
+ return systemArray.Resolve(context).GetMethods(context, filter);
+ }
+
+ public override IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null)
+ {
+ ITypeDefinition arrayDef = systemArray.Resolve(context) as ITypeDefinition;
+ if (arrayDef != null) {
+ foreach (IProperty p in arrayDef.GetProperties(context, filter)) {
+ yield return p;
+ }
+ DefaultProperty indexer = new DefaultProperty(arrayDef, "Items") {
+ ReturnType = elementType,
+ Accessibility = Accessibility.Public,
+ GetterAccessibility = Accessibility.Public,
+ SetterAccessibility = Accessibility.Public,
+ CanGet = true,
+ CanSet = true,
+ IsIndexer = true,
+ IsSynthetic = true
+ };
+ indexer.Freeze();
+ if (filter == null || filter(indexer)) {
+ yield return indexer;
+ }
+ }
+ }
+
+ // Events, Fields: System.Array doesn't have any; so we can use the AbstractType default implementation
+ // that simply returns an empty list
+
public override IType AcceptVisitor(TypeVisitor visitor)
{
return visitor.VisitArrayType(this);
diff --git a/ICSharpCode.NRefactory/TypeSystem/IType.cs b/ICSharpCode.NRefactory/TypeSystem/IType.cs
index 28dc4c569b..d8cec40917 100644
--- a/ICSharpCode.NRefactory/TypeSystem/IType.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/IType.cs
@@ -60,44 +60,34 @@ namespace ICSharpCode.NRefactory.TypeSystem
///
/// Gets inner classes (including inherited inner classes).
///
- ///
- /// If the inner class is generic, this method produces s that
- /// parameterize each nested class with its own type parameters.
- /// TODO: does this make sense? ConstructedType needs it, but maybe it would be better to build
- /// those self-parameterized types only in ConstructedType?
- ///
- IEnumerable GetNestedTypes(ITypeResolveContext context);
-
- // TODO: PERF maybe give GetMethods/GetProperties/etc a filter predicate
- // that allows filtering the members pre-substitution?
- // that could dramatically decrease the number of substitutions we have to perform
+ IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null);
///
/// Gets all methods that can be called on this return type.
///
/// The list does not include constructors.
- IEnumerable GetMethods(ITypeResolveContext context);
+ IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null);
///
/// Gets all instance constructors for this type.
///
/// This list does not include constructors in base classes or static constructors.
- IEnumerable GetConstructors(ITypeResolveContext context);
+ IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null);
///
/// Gets all properties that can be called on this return type.
///
- IEnumerable GetProperties(ITypeResolveContext context);
+ IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null);
///
/// Gets all fields that can be called on this return type.
///
- IEnumerable GetFields(ITypeResolveContext context);
+ IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null);
///
/// Gets all events that can be called on this return type.
///
- IEnumerable GetEvents(ITypeResolveContext context);
+ IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null);
}
[ContractClassFor(typeof(IType))]
@@ -125,42 +115,42 @@ namespace ICSharpCode.NRefactory.TypeSystem
return null;
}
- IEnumerable IType.GetNestedTypes(ITypeResolveContext context)
+ IEnumerable IType.GetNestedTypes(ITypeResolveContext context, Predicate filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result>() != null);
return null;
}
- IEnumerable IType.GetMethods(ITypeResolveContext context)
+ IEnumerable IType.GetMethods(ITypeResolveContext context, Predicate filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result>() != null);
return null;
}
- IEnumerable IType.GetConstructors(ITypeResolveContext context)
+ IEnumerable IType.GetConstructors(ITypeResolveContext context, Predicate filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result>() != null);
return null;
}
- IEnumerable IType.GetProperties(ITypeResolveContext context)
+ IEnumerable IType.GetProperties(ITypeResolveContext context, Predicate filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result>() != null);
return null;
}
- IEnumerable IType.GetFields(ITypeResolveContext context)
+ IEnumerable IType.GetFields(ITypeResolveContext context, Predicate filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result>() != null);
return null;
}
- IEnumerable IType.GetEvents(ITypeResolveContext context)
+ IEnumerable IType.GetEvents(ITypeResolveContext context, Predicate filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result>() != null);
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs
index e074d43b56..b2f981df6a 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs
@@ -61,32 +61,32 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return EmptyList.Instance;
}
- public virtual IEnumerable GetNestedTypes(ITypeResolveContext context)
+ public virtual IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null)
{
return EmptyList.Instance;
}
-
- public virtual IEnumerable GetMethods(ITypeResolveContext context)
+
+ public virtual IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null)
{
return EmptyList.Instance;
}
- public virtual IEnumerable GetConstructors(ITypeResolveContext context)
+ public virtual IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null)
{
return EmptyList.Instance;
}
- public virtual IEnumerable GetProperties(ITypeResolveContext context)
+ public virtual IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null)
{
return EmptyList.Instance;
}
- public virtual IEnumerable GetFields(ITypeResolveContext context)
+ public virtual IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null)
{
return EmptyList.Instance;
}
- public virtual IEnumerable GetEvents(ITypeResolveContext context)
+ public virtual IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null)
{
return EmptyList.Instance;
}
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs
index f4a7e74d33..d70429b3a2 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs
@@ -377,11 +377,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return this;
}
- public virtual IEnumerable GetNestedTypes(ITypeResolveContext context)
+ public virtual IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
- return compound.GetNestedTypes(context);
+ return compound.GetNestedTypes(context, filter);
List nestedTypes = new List();
using (var busyLock = BusyManager.Enter(this)) {
@@ -391,15 +391,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ITypeDefinition baseTypeDef = baseType.GetDefinition();
if (baseTypeDef != null && baseTypeDef.ClassType != ClassType.Interface) {
// get nested types from baseType (not baseTypeDef) so that generics work correctly
- nestedTypes.AddRange(baseType.GetNestedTypes(context));
+ nestedTypes.AddRange(baseType.GetNestedTypes(context, filter));
break; // there is at most 1 non-interface base
}
}
foreach (ITypeDefinition innerClass in this.InnerClasses) {
- if (innerClass.TypeParameterCount > 0) {
- // Parameterize inner classes with their own type parameters, as per on IType.GetNestedTypes.
- nestedTypes.Add(new ParameterizedType(innerClass, innerClass.TypeParameters));
- } else {
+ if (filter == null || filter(innerClass)) {
nestedTypes.Add(innerClass);
}
}
@@ -408,113 +405,151 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return nestedTypes;
}
- public virtual IEnumerable GetMethods(ITypeResolveContext context)
+ public virtual IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
- return compound.GetMethods(context);
+ return compound.GetMethods(context, filter);
List methods = new List();
using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) {
- foreach (var baseTypeRef in this.BaseTypes) {
- IType baseType = baseTypeRef.Resolve(context);
+ int baseCount = 0;
+ foreach (var baseType in GetBaseTypes(context)) {
ITypeDefinition baseTypeDef = baseType.GetDefinition();
if (baseTypeDef != null && (baseTypeDef.ClassType != ClassType.Interface || this.ClassType == ClassType.Interface)) {
- methods.AddRange(baseType.GetMethods(context));
+ methods.AddRange(baseType.GetMethods(context, filter));
+ baseCount++;
}
}
- methods.AddRange(this.Methods.Where(m => !m.IsConstructor));
+ if (baseCount > 1)
+ RemoveDuplicates(methods);
+ AddFilteredRange(methods, this.Methods.Where(m => !m.IsConstructor), filter);
}
}
return methods;
}
- public virtual IEnumerable GetConstructors(ITypeResolveContext context)
+ public virtual IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
- return compound.GetConstructors(context);
+ return compound.GetConstructors(context, filter);
List methods = new List();
- methods.AddRange(this.Methods.Where(m => m.IsConstructor && !m.IsStatic));
+ AddFilteredRange(methods, this.Methods.Where(m => m.IsConstructor && !m.IsStatic), filter);
if (this.AddDefaultConstructorIfRequired) {
if (this.ClassType == ClassType.Class && methods.Count == 0
|| this.ClassType == ClassType.Enum || this.ClassType == ClassType.Struct)
{
- methods.Add(DefaultMethod.CreateDefaultConstructor(this));
+ var m = DefaultMethod.CreateDefaultConstructor(this);
+ if (filter == null || filter(m))
+ methods.Add(m);
}
}
return methods;
}
- public virtual IEnumerable GetProperties(ITypeResolveContext context)
+ public virtual IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
- return compound.GetProperties(context);
+ return compound.GetProperties(context, filter);
List properties = new List();
using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) {
- foreach (var baseTypeRef in this.BaseTypes) {
- IType baseType = baseTypeRef.Resolve(context);
+ int baseCount = 0;
+ foreach (var baseType in GetBaseTypes(context)) {
ITypeDefinition baseTypeDef = baseType.GetDefinition();
if (baseTypeDef != null && (baseTypeDef.ClassType != ClassType.Interface || this.ClassType == ClassType.Interface)) {
- properties.AddRange(baseType.GetProperties(context));
+ properties.AddRange(baseType.GetProperties(context, filter));
+ baseCount++;
}
}
- properties.AddRange(this.Properties);
+ if (baseCount > 1)
+ RemoveDuplicates(properties);
+ AddFilteredRange(properties, this.Properties, filter);
}
}
return properties;
}
- public virtual IEnumerable GetFields(ITypeResolveContext context)
+ public virtual IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
- return compound.GetFields(context);
+ return compound.GetFields(context, filter);
List fields = new List();
using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) {
- foreach (var baseTypeRef in this.BaseTypes) {
- IType baseType = baseTypeRef.Resolve(context);
+ int baseCount = 0;
+ foreach (var baseType in GetBaseTypes(context)) {
ITypeDefinition baseTypeDef = baseType.GetDefinition();
if (baseTypeDef != null && (baseTypeDef.ClassType != ClassType.Interface || this.ClassType == ClassType.Interface)) {
- fields.AddRange(baseType.GetFields(context));
+ fields.AddRange(baseType.GetFields(context, filter));
+ baseCount++;
}
}
- fields.AddRange(this.Fields);
+ if (baseCount > 1)
+ RemoveDuplicates(fields);
+ AddFilteredRange(fields, this.Fields, filter);
}
}
return fields;
}
- public virtual IEnumerable GetEvents(ITypeResolveContext context)
+ public virtual IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
- return compound.GetEvents(context);
+ return compound.GetEvents(context, filter);
List events = new List();
using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) {
- foreach (var baseTypeRef in this.BaseTypes) {
- IType baseType = baseTypeRef.Resolve(context);
+ int baseCount = 0;
+ foreach (var baseType in GetBaseTypes(context)) {
ITypeDefinition baseTypeDef = baseType.GetDefinition();
if (baseTypeDef != null && (baseTypeDef.ClassType != ClassType.Interface || this.ClassType == ClassType.Interface)) {
- events.AddRange(baseType.GetEvents(context));
+ events.AddRange(baseType.GetEvents(context, filter));
+ baseCount++;
}
}
- events.AddRange(this.Events);
+ if (baseCount > 1)
+ RemoveDuplicates(events);
+ AddFilteredRange(events, this.Events, filter);
}
}
return events;
}
+ static void AddFilteredRange(List targetList, IEnumerable sourceList, Predicate filter) where T : class
+ {
+ if (filter == null) {
+ targetList.AddRange(sourceList);
+ } else {
+ foreach (T element in sourceList) {
+ if (filter(element))
+ targetList.Add(element);
+ }
+ }
+ }
+
+ ///
+ /// Removes duplicate members from the list.
+ /// This is necessary when the same member can be inherited twice due to multiple inheritance.
+ ///
+ static void RemoveDuplicates(List list) where T : class
+ {
+ if (list.Count > 1) {
+ HashSet hash = new HashSet();
+ list.RemoveAll(m => !hash.Add(m));
+ }
+ }
+
// we use reference equality
bool IEquatable.Equals(IType other)
{
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs
index 1d137aa494..7964ff0346 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs
@@ -231,22 +231,23 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return c;
}
- public IEnumerable GetConstructors(ITypeResolveContext context)
+ public IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null)
{
if (HasDefaultConstructorConstraint || HasValueTypeConstraint) {
- return new [] { DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter()) };
- } else {
- return EmptyList.Instance;
+ DefaultMethod m = DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter());
+ if (filter(m))
+ return new [] { m };
}
+ return EmptyList.Instance;
}
- public IEnumerable GetMethods(ITypeResolveContext context)
+ public IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null)
{
// TODO: get methods from constraints
IType objectType = context.GetClass("System.Object", 0, StringComparer.Ordinal);
IEnumerable objectMethods;
if (objectType != null)
- objectMethods = objectType.GetMethods(context);
+ objectMethods = objectType.GetMethods(context, filter);
else
objectMethods = EmptyList.Instance;
@@ -254,22 +255,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return objectMethods.Where(m => !m.IsStatic);
}
- public IEnumerable GetProperties(ITypeResolveContext context)
+ public IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null)
{
return EmptyList.Instance;
}
- public IEnumerable GetFields(ITypeResolveContext context)
+ public IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null)
{
return EmptyList.Instance;
}
- public IEnumerable GetEvents(ITypeResolveContext context)
+ public IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null)
{
return EmptyList.Instance;
}
- IEnumerable IType.GetNestedTypes(ITypeResolveContext context)
+ IEnumerable IType.GetNestedTypes(ITypeResolveContext context, Predicate filter = null)
{
return EmptyList.Instance;
}
diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/VoidTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/VoidTypeDefinition.cs
index 6daad440ce..cebee4244c 100644
--- a/ICSharpCode.NRefactory/TypeSystem/Implementation/VoidTypeDefinition.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/VoidTypeDefinition.cs
@@ -17,27 +17,27 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.IsSealed = true;
}
- public override IEnumerable GetConstructors(ITypeResolveContext context)
+ public override IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter)
{
return EmptyList.Instance;
}
- public override IEnumerable GetEvents(ITypeResolveContext context)
+ public override IEnumerable GetEvents(ITypeResolveContext context, Predicate filter)
{
return EmptyList.Instance;
}
- public override IEnumerable GetFields(ITypeResolveContext context)
+ public override IEnumerable GetFields(ITypeResolveContext context, Predicate filter)
{
return EmptyList.Instance;
}
- public override IEnumerable GetMethods(ITypeResolveContext context)
+ public override IEnumerable GetMethods(ITypeResolveContext context, Predicate filter)
{
return EmptyList.Instance;
}
- public override IEnumerable GetProperties(ITypeResolveContext context)
+ public override IEnumerable GetProperties(ITypeResolveContext context, Predicate filter)
{
return EmptyList.Instance;
}
diff --git a/ICSharpCode.NRefactory/TypeSystem/ParameterListComparer.cs b/ICSharpCode.NRefactory/TypeSystem/ParameterListComparer.cs
new file mode 100644
index 0000000000..e488f6def8
--- /dev/null
+++ b/ICSharpCode.NRefactory/TypeSystem/ParameterListComparer.cs
@@ -0,0 +1,38 @@
+// Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+
+using System;
+using System.Collections.Generic;
+
+namespace ICSharpCode.NRefactory.TypeSystem
+{
+ public sealed class ParameterListComparer : IEqualityComparer
+ {
+ public static readonly ParameterListComparer Instance = new ParameterListComparer();
+
+ public bool Equals(IParameterizedMember x, IParameterizedMember y)
+ {
+ var px = x.Parameters;
+ var py = y.Parameters;
+ if (px.Count != py.Count)
+ return false;
+ for (int i = 0; i < px.Count; i++) {
+ if (!px[i].Type.Equals(py[i].Type))
+ return false;
+ }
+ return true;
+ }
+
+ public int GetHashCode(IParameterizedMember obj)
+ {
+ int hashCode = obj.Parameters.Count;
+ unchecked {
+ foreach (IParameter p in obj.Parameters) {
+ hashCode *= 27;
+ hashCode += p.Type.GetHashCode();
+ }
+ }
+ return hashCode;
+ }
+ }
+}
diff --git a/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs b/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs
index f224b601b5..7fb857149c 100644
--- a/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs
+++ b/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs
@@ -158,7 +158,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
return genericType.GetBaseTypes(context).Select(substitution.Apply);
}
- public IEnumerable GetNestedTypes(ITypeResolveContext context)
+ public IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null)
{
/*
class Base {
@@ -172,17 +172,30 @@ namespace ICSharpCode.NRefactory.TypeSystem
Base.GetNestedTypes() = { Base`1+Nested } where T2 = copy of T in Base`1+Nested
*/
Substitution substitution = new Substitution(typeArguments);
- List types = genericType.GetNestedTypes(context).ToList();
+ List types = genericType.GetNestedTypes(context, filter).ToList();
for (int i = 0; i < types.Count; i++) {
- types[i] = types[i].AcceptVisitor(substitution);
+ ITypeDefinition def = types[i] as ITypeDefinition;
+ if (def != null && def.TypeParameterCount > 0) {
+ // (partially) parameterize the nested type definition
+ IType[] newTypeArgs = new IType[def.TypeParameterCount];
+ for (int j = 0; j < newTypeArgs.Length; j++) {
+ if (j < typeArguments.Length)
+ newTypeArgs[j] = typeArguments[i];
+ else
+ newTypeArgs[j] = def.TypeParameters[j];
+ }
+ types[i] = new ParameterizedType(def, newTypeArgs);
+ } else {
+ types[i] = types[i].AcceptVisitor(substitution);
+ }
}
return types;
}
- public IEnumerable GetMethods(ITypeResolveContext context)
+ public IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null)
{
Substitution substitution = new Substitution(typeArguments);
- List methods = genericType.GetMethods(context).ToList();
+ List methods = genericType.GetMethods(context, filter).ToList();
for (int i = 0; i < methods.Count; i++) {
SpecializedMethod m = new SpecializedMethod(methods[i]);
m.SetDeclaringType(this);
@@ -192,10 +205,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
return methods;
}
- public IEnumerable GetConstructors(ITypeResolveContext context)
+ public IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null)
{
Substitution substitution = new Substitution(typeArguments);
- List methods = genericType.GetConstructors(context).ToList();
+ List methods = genericType.GetConstructors(context, filter).ToList();
for (int i = 0; i < methods.Count; i++) {
SpecializedMethod m = new SpecializedMethod(methods[i]);
m.SetDeclaringType(this);
@@ -205,10 +218,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
return methods;
}
- public IEnumerable GetProperties(ITypeResolveContext context)
+ public IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null)
{
Substitution substitution = new Substitution(typeArguments);
- List properties = genericType.GetProperties(context).ToList();
+ List properties = genericType.GetProperties(context, filter).ToList();
for (int i = 0; i < properties.Count; i++) {
SpecializedProperty p = new SpecializedProperty(properties[i]);
p.SetDeclaringType(this);
@@ -218,10 +231,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
return properties;
}
- public IEnumerable GetFields(ITypeResolveContext context)
+ public IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null)
{
Substitution substitution = new Substitution(typeArguments);
- List fields = genericType.GetFields(context).ToList();
+ List fields = genericType.GetFields(context, filter).ToList();
for (int i = 0; i < fields.Count; i++) {
SpecializedField f = new SpecializedField(fields[i]);
f.SetDeclaringType(this);
@@ -231,10 +244,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
return fields;
}
- public IEnumerable GetEvents(ITypeResolveContext context)
+ public IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null)
{
Substitution substitution = new Substitution(typeArguments);
- List events = genericType.GetEvents(context).ToList();
+ List events = genericType.GetEvents(context, filter).ToList();
for (int i = 0; i < events.Count; i++) {
SpecializedEvent e = new SpecializedEvent(events[i]);
e.SetDeclaringType(this);
diff --git a/README b/README
index 73587367d1..af63079446 100644
--- a/README
+++ b/README
@@ -94,6 +94,7 @@ A: This question is a bit difficult to answer.
But of course, this does not mean that everything is thread-safe.
First off, there's no hidden static state, so any two operations working on independent data can be executed concurrently.
+ [Actually, sometimes static state is used for caches, but those uses are thread-safe.]
TODO: what about the C# parser? gmcs is full of static state...
Some instance methods may use hidden instance state, so it is not safe to e.g use an instance of the CSharp.Resolver.Conversions class
@@ -120,7 +121,7 @@ A: This question is a bit difficult to answer.
results (e.g. because another thread updated a class definition).
Also, there's a performance problem: if you have a composite of 15 SimpleProjectContents and the resolve algorithm
requests 100 types, that's 1500 times entering and leaving the read-lock.
- Moreoever, the ITypeResolveContext methods that return collections need to create a copy of the collection.
+ Moreoever, internal caches in the library are not used when passing a mutable ITypeResolveContext.
The solution is to make the read lock more coarse-grained:
using (var syncContext = compositeTypeResolveContext.Synchronize()) {
@@ -128,7 +129,8 @@ A: This question is a bit difficult to answer.
}
On the call to Synchronize(), all 15 SimpleProjectContents are locked for reading.
The return value "syncContext" can then be used to access the type resolve context without further synchronization overhead.
- Once the return value is disposed, the read-locks are released.
+ It is guaranteed not to change (within the using block), so the library may cache some information. (TODO: give example of a cache)
+ Once the return value is disposed, the read-locks are released (and the caches are cleared).
Q: What format do the .ToString() methods use?