Browse Source

Started implementation of member lookup.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
a53c6a1934
  1. 1
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  2. 44
      ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs
  3. 11
      ICSharpCode.NRefactory/CSharp/Resolver/AmbiguousResolveResult.cs
  4. 94
      ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
  5. 5
      ICSharpCode.NRefactory/CSharp/Resolver/ITypeOrNamespaceReference.cs
  6. 150
      ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs
  7. 25
      ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs
  8. 30
      ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs
  9. 16
      ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs
  10. 3
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  11. 47
      ICSharpCode.NRefactory/TypeSystem/ArrayType.cs
  12. 34
      ICSharpCode.NRefactory/TypeSystem/IType.cs
  13. 14
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs
  14. 105
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs
  15. 21
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs
  16. 10
      ICSharpCode.NRefactory/TypeSystem/Implementation/VoidTypeDefinition.cs
  17. 38
      ICSharpCode.NRefactory/TypeSystem/ParameterListComparer.cs
  18. 39
      ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs
  19. 6
      README

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

@ -58,6 +58,7 @@ @@ -58,6 +58,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TypeSystem\CecilLoaderTests.cs" />
<Compile Include="TypeSystem\GetAllBaseTypesTest.cs" />
<Compile Include="TypeSystem\GetMembersTests.cs" />
<Compile Include="TypeSystem\ReflectionHelperTests.cs" />
<Compile Include="TypeSystem\TestInterningProvider.cs" />
<Compile Include="TypeSystem\TypeSystemTests.cs" />

44
ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs

@ -0,0 +1,44 @@ @@ -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());
}
}
}

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

@ -19,4 +19,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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; }
}
}
}

94
ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs

@ -1341,20 +1341,28 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1341,20 +1341,28 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region ResolveSimpleName
enum SimpleNameLookupMode
{
Expression,
Type,
TypeInUsingDeclaration
}
public ResolveResult ResolveSimpleName(string identifier, IList<IType> 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<IType> typeArguments)
public ResolveResult LookupSimpleNamespaceOrTypeName(string identifier, IList<IType> typeArguments, bool isUsingDeclaration = false)
{
return LookupSimpleNameOrTypeName(identifier, typeArguments, true);
return LookupSimpleNameOrTypeName(identifier, typeArguments,
isUsingDeclaration ? SimpleNameLookupMode.TypeInUsingDeclaration : SimpleNameLookupMode.Type);
}
ResolveResult LookupSimpleNameOrTypeName(string identifier, IList<IType> typeArguments, bool typeOnly)
ResolveResult LookupSimpleNameOrTypeName(string identifier, IList<IType> 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 @@ -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 @@ -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;
}
/// <summary>
/// Looks up an alias (identifier in front of :: operator)
/// </summary>
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
}
}

5
ICSharpCode.NRefactory/CSharp/Resolver/ITypeOrNamespaceReference.cs

@ -11,6 +11,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -11,6 +11,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary>
public interface ITypeOrNamespaceReference : ITypeReference
{
string ResolveNamespace(ITypeResolveContext context);
/// <summary>
/// Returns the namespace that is referenced; or null if no such namespace is found.
/// </summary>
NamespaceResolveResult ResolveNamespace(ITypeResolveContext context);
}
}

150
ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs

@ -3,6 +3,8 @@ @@ -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 @@ -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 @@ -48,9 +49,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Gets whether <paramref name="entity"/> is accessible in the current class.
/// </summary>
/// <param name="member">The entity to test</param>
/// <param name="typeOfReference">The type used to access the member, or null if no target is used (e.g. static method call)</param>
/// <returns>true if the member is accessible</returns>
public bool IsAccessible(IEntity entity, IType typeOfReference)
/// <param name="allowProtectedAccess">Whether protected access is allowed.
/// True if the type of the reference is derived from the current class.</returns>
public bool IsAccessible(IEntity entity, bool allowProtectedAccess)
{
if (entity == null)
throw new ArgumentNullException("entity");
@ -63,14 +64,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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 @@ -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
/// <summary>
/// Performs a member lookup.
/// </summary>
public ResolveResult Lookup(IType type, string name, int typeParameterCount, bool isInvocation)
{
List<IType> types = new List<IType>();
List<IMember> members = new List<IMember>();
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<IMember> 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<IMethod> 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;
}
}
}

25
ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs

@ -0,0 +1,25 @@ @@ -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
{
/// <summary>
/// Represents the result of a member invocation.
/// </summary>
public class MemberResolveResult : ResolveResult
{
readonly IMember member;
public MemberResolveResult(IMember member, IType returnType) : base(returnType)
{
this.member = member;
}
public IMember Member {
get { return member; }
}
}
}

30
ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs

@ -0,0 +1,30 @@ @@ -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
{
/// <summary>
/// Represents a group of methods.
/// </summary>
public class MethodGroupResolveResult : ResolveResult
{
readonly ReadOnlyCollection<IMethod> methods;
public MethodGroupResolveResult(IList<IMethod> methods) : base(SharedTypes.UnknownType)
{
if (methods == null)
throw new ArgumentNullException("methods");
this.methods = new ReadOnlyCollection<IMethod>(methods);
}
public ReadOnlyCollection<IMethod> Methods {
get { return methods; }
}
}
}

16
ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs

@ -9,44 +9,42 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation; @@ -9,44 +9,42 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// 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)
/// </summary>
public sealed class SimpleTypeOrNamespaceReference : ITypeOrNamespaceReference
{
readonly IMember parentMember;
readonly ITypeDefinition parentTypeDefinition;
readonly UsingScope parentUsingScope;
readonly string identifier;
readonly IList<ITypeReference> typeArguments;
readonly bool isInUsingDeclaration;
public SimpleTypeOrNamespaceReference(string identifier, IList<ITypeReference> typeArguments, IMember parentMember, ITypeDefinition parentTypeDefinition, UsingScope parentUsingScope)
public SimpleTypeOrNamespaceReference(string identifier, IList<ITypeReference> typeArguments, ITypeDefinition parentTypeDefinition, UsingScope parentUsingScope, bool isInUsingDeclaration = false)
{
if (identifier == null)
throw new ArgumentNullException("identifier");
this.identifier = identifier;
this.typeArguments = typeArguments ?? EmptyList<ITypeReference>.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)

3
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -147,6 +147,8 @@ @@ -147,6 +147,8 @@
<Compile Include="CSharp\Resolver\ErrorResolveResult.cs" />
<Compile Include="CSharp\Resolver\ITypeOrNamespaceReference.cs" />
<Compile Include="CSharp\Resolver\MemberLookup.cs" />
<Compile Include="CSharp\Resolver\MemberResolveResult.cs" />
<Compile Include="CSharp\Resolver\MethodGroupResolveResult.cs" />
<Compile Include="CSharp\Resolver\NamespaceResolveResult.cs" />
<Compile Include="CSharp\Resolver\OverloadResolution.cs" />
<Compile Include="CSharp\Resolver\OverloadResolutionErrors.cs" />
@ -212,6 +214,7 @@ @@ -212,6 +214,7 @@
<Compile Include="TypeSystem\ITypeResolveContext.cs" />
<Compile Include="TypeSystem\NullableType.cs" />
<Compile Include="TypeSystem\ParameterizedType.cs" />
<Compile Include="TypeSystem\ParameterListComparer.cs" />
<Compile Include="TypeSystem\ReflectionNameParseException.cs" />
<Compile Include="TypeSystem\TypeVisitor.cs" />
<Compile Include="TypeSystem\IVariable.cs" />

47
ICSharpCode.NRefactory/TypeSystem/ArrayType.cs

@ -46,22 +46,55 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -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<IType> GetBaseTypes(ITypeResolveContext context)
{
List<IType> baseTypes = new List<IType>();
// 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>
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<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter = null)
{
return systemArray.Resolve(context).GetMethods(context, filter);
}
public override IEnumerable<IProperty> GetProperties(ITypeResolveContext context, Predicate<IProperty> 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);

34
ICSharpCode.NRefactory/TypeSystem/IType.cs

@ -60,44 +60,34 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -60,44 +60,34 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// <summary>
/// Gets inner classes (including inherited inner classes).
/// </summary>
/// <remarks>
/// If the inner class is generic, this method produces <see cref="ParameterizedType"/>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?
/// </remarks>
IEnumerable<IType> 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<IType> GetNestedTypes(ITypeResolveContext context, Predicate<ITypeDefinition> filter = null);
/// <summary>
/// Gets all methods that can be called on this return type.
/// </summary>
/// <remarks>The list does not include constructors.</remarks>
IEnumerable<IMethod> GetMethods(ITypeResolveContext context);
IEnumerable<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter = null);
/// <summary>
/// Gets all instance constructors for this type.
/// </summary>
/// <remarks>This list does not include constructors in base classes or static constructors.</remarks>
IEnumerable<IMethod> GetConstructors(ITypeResolveContext context);
IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter = null);
/// <summary>
/// Gets all properties that can be called on this return type.
/// </summary>
IEnumerable<IProperty> GetProperties(ITypeResolveContext context);
IEnumerable<IProperty> GetProperties(ITypeResolveContext context, Predicate<IProperty> filter = null);
/// <summary>
/// Gets all fields that can be called on this return type.
/// </summary>
IEnumerable<IField> GetFields(ITypeResolveContext context);
IEnumerable<IField> GetFields(ITypeResolveContext context, Predicate<IField> filter = null);
/// <summary>
/// Gets all events that can be called on this return type.
/// </summary>
IEnumerable<IEvent> GetEvents(ITypeResolveContext context);
IEnumerable<IEvent> GetEvents(ITypeResolveContext context, Predicate<IEvent> filter = null);
}
[ContractClassFor(typeof(IType))]
@ -125,42 +115,42 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -125,42 +115,42 @@ namespace ICSharpCode.NRefactory.TypeSystem
return null;
}
IEnumerable<IType> IType.GetNestedTypes(ITypeResolveContext context)
IEnumerable<IType> IType.GetNestedTypes(ITypeResolveContext context, Predicate<ITypeDefinition> filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result<IList<IType>>() != null);
return null;
}
IEnumerable<IMethod> IType.GetMethods(ITypeResolveContext context)
IEnumerable<IMethod> IType.GetMethods(ITypeResolveContext context, Predicate<IMethod> filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result<IList<IMethod>>() != null);
return null;
}
IEnumerable<IMethod> IType.GetConstructors(ITypeResolveContext context)
IEnumerable<IMethod> IType.GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result<IList<IMethod>>() != null);
return null;
}
IEnumerable<IProperty> IType.GetProperties(ITypeResolveContext context)
IEnumerable<IProperty> IType.GetProperties(ITypeResolveContext context, Predicate<IProperty> filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result<IList<IProperty>>() != null);
return null;
}
IEnumerable<IField> IType.GetFields(ITypeResolveContext context)
IEnumerable<IField> IType.GetFields(ITypeResolveContext context, Predicate<IField> filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result<IList<IField>>() != null);
return null;
}
IEnumerable<IEvent> IType.GetEvents(ITypeResolveContext context)
IEnumerable<IEvent> IType.GetEvents(ITypeResolveContext context, Predicate<IEvent> filter)
{
Contract.Requires(context != null);
Contract.Ensures(Contract.Result<IList<IEvent>>() != null);

14
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs

@ -61,32 +61,32 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -61,32 +61,32 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return EmptyList<IType>.Instance;
}
public virtual IEnumerable<IType> GetNestedTypes(ITypeResolveContext context)
public virtual IEnumerable<IType> GetNestedTypes(ITypeResolveContext context, Predicate<ITypeDefinition> filter = null)
{
return EmptyList<IType>.Instance;
}
public virtual IEnumerable<IMethod> GetMethods(ITypeResolveContext context)
public virtual IEnumerable<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter = null)
{
return EmptyList<IMethod>.Instance;
}
public virtual IEnumerable<IMethod> GetConstructors(ITypeResolveContext context)
public virtual IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter = null)
{
return EmptyList<IMethod>.Instance;
}
public virtual IEnumerable<IProperty> GetProperties(ITypeResolveContext context)
public virtual IEnumerable<IProperty> GetProperties(ITypeResolveContext context, Predicate<IProperty> filter = null)
{
return EmptyList<IProperty>.Instance;
}
public virtual IEnumerable<IField> GetFields(ITypeResolveContext context)
public virtual IEnumerable<IField> GetFields(ITypeResolveContext context, Predicate<IField> filter = null)
{
return EmptyList<IField>.Instance;
}
public virtual IEnumerable<IEvent> GetEvents(ITypeResolveContext context)
public virtual IEnumerable<IEvent> GetEvents(ITypeResolveContext context, Predicate<IEvent> filter = null)
{
return EmptyList<IEvent>.Instance;
}

105
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs

@ -377,11 +377,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -377,11 +377,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return this;
}
public virtual IEnumerable<IType> GetNestedTypes(ITypeResolveContext context)
public virtual IEnumerable<IType> GetNestedTypes(ITypeResolveContext context, Predicate<ITypeDefinition> filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
return compound.GetNestedTypes(context);
return compound.GetNestedTypes(context, filter);
List<IType> nestedTypes = new List<IType>();
using (var busyLock = BusyManager.Enter(this)) {
@ -391,15 +391,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -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 <remarks> 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 @@ -408,113 +405,151 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return nestedTypes;
}
public virtual IEnumerable<IMethod> GetMethods(ITypeResolveContext context)
public virtual IEnumerable<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
return compound.GetMethods(context);
return compound.GetMethods(context, filter);
List<IMethod> methods = new List<IMethod>();
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<IMethod> GetConstructors(ITypeResolveContext context)
public virtual IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
return compound.GetConstructors(context);
return compound.GetConstructors(context, filter);
List<IMethod> methods = new List<IMethod>();
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<IProperty> GetProperties(ITypeResolveContext context)
public virtual IEnumerable<IProperty> GetProperties(ITypeResolveContext context, Predicate<IProperty> filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
return compound.GetProperties(context);
return compound.GetProperties(context, filter);
List<IProperty> properties = new List<IProperty>();
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<IField> GetFields(ITypeResolveContext context)
public virtual IEnumerable<IField> GetFields(ITypeResolveContext context, Predicate<IField> filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
return compound.GetFields(context);
return compound.GetFields(context, filter);
List<IField> fields = new List<IField>();
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<IEvent> GetEvents(ITypeResolveContext context)
public virtual IEnumerable<IEvent> GetEvents(ITypeResolveContext context, Predicate<IEvent> filter = null)
{
ITypeDefinition compound = GetCompoundClass();
if (compound != this)
return compound.GetEvents(context);
return compound.GetEvents(context, filter);
List<IEvent> events = new List<IEvent>();
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<T>(List<T> targetList, IEnumerable<T> sourceList, Predicate<T> filter) where T : class
{
if (filter == null) {
targetList.AddRange(sourceList);
} else {
foreach (T element in sourceList) {
if (filter(element))
targetList.Add(element);
}
}
}
/// <summary>
/// Removes duplicate members from the list.
/// This is necessary when the same member can be inherited twice due to multiple inheritance.
/// </summary>
static void RemoveDuplicates<T>(List<T> list) where T : class
{
if (list.Count > 1) {
HashSet<T> hash = new HashSet<T>();
list.RemoveAll(m => !hash.Add(m));
}
}
// we use reference equality
bool IEquatable<IType>.Equals(IType other)
{

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

@ -231,22 +231,23 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -231,22 +231,23 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return c;
}
public IEnumerable<IMethod> GetConstructors(ITypeResolveContext context)
public IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter = null)
{
if (HasDefaultConstructorConstraint || HasValueTypeConstraint) {
return new [] { DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter()) };
} else {
return EmptyList<IMethod>.Instance;
DefaultMethod m = DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter());
if (filter(m))
return new [] { m };
}
return EmptyList<IMethod>.Instance;
}
public IEnumerable<IMethod> GetMethods(ITypeResolveContext context)
public IEnumerable<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter = null)
{
// TODO: get methods from constraints
IType objectType = context.GetClass("System.Object", 0, StringComparer.Ordinal);
IEnumerable<IMethod> objectMethods;
if (objectType != null)
objectMethods = objectType.GetMethods(context);
objectMethods = objectType.GetMethods(context, filter);
else
objectMethods = EmptyList<IMethod>.Instance;
@ -254,22 +255,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -254,22 +255,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return objectMethods.Where(m => !m.IsStatic);
}
public IEnumerable<IProperty> GetProperties(ITypeResolveContext context)
public IEnumerable<IProperty> GetProperties(ITypeResolveContext context, Predicate<IProperty> filter = null)
{
return EmptyList<IProperty>.Instance;
}
public IEnumerable<IField> GetFields(ITypeResolveContext context)
public IEnumerable<IField> GetFields(ITypeResolveContext context, Predicate<IField> filter = null)
{
return EmptyList<IField>.Instance;
}
public IEnumerable<IEvent> GetEvents(ITypeResolveContext context)
public IEnumerable<IEvent> GetEvents(ITypeResolveContext context, Predicate<IEvent> filter = null)
{
return EmptyList<IEvent>.Instance;
}
IEnumerable<IType> IType.GetNestedTypes(ITypeResolveContext context)
IEnumerable<IType> IType.GetNestedTypes(ITypeResolveContext context, Predicate<ITypeDefinition> filter = null)
{
return EmptyList<IType>.Instance;
}

10
ICSharpCode.NRefactory/TypeSystem/Implementation/VoidTypeDefinition.cs

@ -17,27 +17,27 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -17,27 +17,27 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.IsSealed = true;
}
public override IEnumerable<IMethod> GetConstructors(ITypeResolveContext context)
public override IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter)
{
return EmptyList<IMethod>.Instance;
}
public override IEnumerable<IEvent> GetEvents(ITypeResolveContext context)
public override IEnumerable<IEvent> GetEvents(ITypeResolveContext context, Predicate<IEvent> filter)
{
return EmptyList<IEvent>.Instance;
}
public override IEnumerable<IField> GetFields(ITypeResolveContext context)
public override IEnumerable<IField> GetFields(ITypeResolveContext context, Predicate<IField> filter)
{
return EmptyList<IField>.Instance;
}
public override IEnumerable<IMethod> GetMethods(ITypeResolveContext context)
public override IEnumerable<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter)
{
return EmptyList<IMethod>.Instance;
}
public override IEnumerable<IProperty> GetProperties(ITypeResolveContext context)
public override IEnumerable<IProperty> GetProperties(ITypeResolveContext context, Predicate<IProperty> filter)
{
return EmptyList<IProperty>.Instance;
}

38
ICSharpCode.NRefactory/TypeSystem/ParameterListComparer.cs

@ -0,0 +1,38 @@ @@ -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<IParameterizedMember>
{
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;
}
}
}

39
ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs

@ -158,7 +158,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -158,7 +158,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
return genericType.GetBaseTypes(context).Select(substitution.Apply);
}
public IEnumerable<IType> GetNestedTypes(ITypeResolveContext context)
public IEnumerable<IType> GetNestedTypes(ITypeResolveContext context, Predicate<ITypeDefinition> filter = null)
{
/*
class Base<T> {
@ -172,17 +172,30 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -172,17 +172,30 @@ namespace ICSharpCode.NRefactory.TypeSystem
Base.GetNestedTypes() = { Base`1+Nested<T2> } where T2 = copy of T in Base`1+Nested
*/
Substitution substitution = new Substitution(typeArguments);
List<IType> types = genericType.GetNestedTypes(context).ToList();
List<IType> 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<IMethod> GetMethods(ITypeResolveContext context)
public IEnumerable<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter = null)
{
Substitution substitution = new Substitution(typeArguments);
List<IMethod> methods = genericType.GetMethods(context).ToList();
List<IMethod> 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 @@ -192,10 +205,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
return methods;
}
public IEnumerable<IMethod> GetConstructors(ITypeResolveContext context)
public IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter = null)
{
Substitution substitution = new Substitution(typeArguments);
List<IMethod> methods = genericType.GetConstructors(context).ToList();
List<IMethod> 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 @@ -205,10 +218,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
return methods;
}
public IEnumerable<IProperty> GetProperties(ITypeResolveContext context)
public IEnumerable<IProperty> GetProperties(ITypeResolveContext context, Predicate<IProperty> filter = null)
{
Substitution substitution = new Substitution(typeArguments);
List<IProperty> properties = genericType.GetProperties(context).ToList();
List<IProperty> 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 @@ -218,10 +231,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
return properties;
}
public IEnumerable<IField> GetFields(ITypeResolveContext context)
public IEnumerable<IField> GetFields(ITypeResolveContext context, Predicate<IField> filter = null)
{
Substitution substitution = new Substitution(typeArguments);
List<IField> fields = genericType.GetFields(context).ToList();
List<IField> 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 @@ -231,10 +244,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
return fields;
}
public IEnumerable<IEvent> GetEvents(ITypeResolveContext context)
public IEnumerable<IEvent> GetEvents(ITypeResolveContext context, Predicate<IEvent> filter = null)
{
Substitution substitution = new Substitution(typeArguments);
List<IEvent> events = genericType.GetEvents(context).ToList();
List<IEvent> events = genericType.GetEvents(context, filter).ToList();
for (int i = 0; i < events.Count; i++) {
SpecializedEvent e = new SpecializedEvent(events[i]);
e.SetDeclaringType(this);

6
README

@ -94,6 +94,7 @@ A: This question is a bit difficult to answer. @@ -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. @@ -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. @@ -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?

Loading…
Cancel
Save