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 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TypeSystem\CecilLoaderTests.cs" /> <Compile Include="TypeSystem\CecilLoaderTests.cs" />
<Compile Include="TypeSystem\GetAllBaseTypesTest.cs" /> <Compile Include="TypeSystem\GetAllBaseTypesTest.cs" />
<Compile Include="TypeSystem\GetMembersTests.cs" />
<Compile Include="TypeSystem\ReflectionHelperTests.cs" /> <Compile Include="TypeSystem\ReflectionHelperTests.cs" />
<Compile Include="TypeSystem\TestInterningProvider.cs" /> <Compile Include="TypeSystem\TestInterningProvider.cs" />
<Compile Include="TypeSystem\TypeSystemTests.cs" /> <Compile Include="TypeSystem\TypeSystemTests.cs" />

44
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());
}
}
}

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

@ -19,4 +19,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
get { return true; } 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
#endregion #endregion
#region ResolveSimpleName #region ResolveSimpleName
enum SimpleNameLookupMode
{
Expression,
Type,
TypeInUsingDeclaration
}
public ResolveResult ResolveSimpleName(string identifier, IList<IType> typeArguments) public ResolveResult ResolveSimpleName(string identifier, IList<IType> typeArguments)
{ {
// C# 4.0 spec: §7.6.2 Simple Names // C# 4.0 spec: §7.6.2 Simple Names
// TODO: lookup in local variables, in parameters, etc. // 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 // 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) { if (lookupMode == SimpleNameLookupMode.Expression) {
// TODO: perform member lookup within the type t, restricted to finding types // TODO: perform member lookup within the type t
} else { } 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 // look in current namespace definitions
@ -1415,41 +1424,66 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (k == 0) { if (k == 0) {
if (n.ExternAliases.Contains(identifier)) { if (n.ExternAliases.Contains(identifier)) {
// TODO: implement extern alias support // TODO: implement extern alias support
throw new NotImplementedException(); return new NamespaceResolveResult(string.Empty);
} }
foreach (var pair in n.UsingAliases) { if (lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration || n != this.UsingScope) {
if (pair.Key == identifier) { foreach (var pair in n.UsingAliases) {
string ns = pair.Value.ResolveNamespace(context); if (pair.Key == identifier) {
if (ns != null) NamespaceResolveResult ns = pair.Value.ResolveNamespace(context);
return new NamespaceResolveResult(ns); if (ns != null)
else return ns;
return new TypeResolveResult(pair.Value.Resolve(context)); else
return new TypeResolveResult(pair.Value.Resolve(context));
}
} }
} }
} }
// finally, look in the imported namespaces: // finally, look in the imported namespaces:
IType firstResult = null; if (lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration || n != this.UsingScope) {
foreach (var u in n.Usings) { IType firstResult = null;
string ns = u.ResolveNamespace(context); foreach (var u in n.Usings) {
if (ns != null) { NamespaceResolveResult ns = u.ResolveNamespace(context);
fullName = NamespaceDeclaration.BuildQualifiedName(ns, identifier); if (ns != null) {
def = context.GetClass(ns, k, StringComparer.Ordinal); fullName = NamespaceDeclaration.BuildQualifiedName(ns.NamespaceName, identifier);
if (firstResult == null) { def = context.GetClass(fullName, k, StringComparer.Ordinal);
if (k == 0) if (firstResult == null) {
firstResult = def; if (k == 0)
else firstResult = def;
firstResult = new ParameterizedType(def, typeArguments); else
} else { firstResult = new ParameterizedType(def, typeArguments);
return new AmbiguousTypeResolveResult(firstResult); } 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 // if we didn't find anything: repeat lookup with parent namespace
} }
return ErrorResult; 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 #endregion
} }
} }

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

@ -11,6 +11,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
public interface ITypeOrNamespaceReference : ITypeReference 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 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
@ -27,7 +29,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return true; return true;
return member.ReturnType.Resolve(context).IsDelegate(); return member.ReturnType.Resolve(context).IsDelegate();
} }
#endregion #endregion
ITypeResolveContext context; ITypeResolveContext context;
@ -48,9 +49,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Gets whether <paramref name="entity"/> is accessible in the current class. /// Gets whether <paramref name="entity"/> is accessible in the current class.
/// </summary> /// </summary>
/// <param name="member">The entity to test</param> /// <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> /// <param name="allowProtectedAccess">Whether protected access is allowed.
/// <returns>true if the member is accessible</returns> /// True if the type of the reference is derived from the current class.</returns>
public bool IsAccessible(IEntity entity, IType typeOfReference) public bool IsAccessible(IEntity entity, bool allowProtectedAccess)
{ {
if (entity == null) if (entity == null)
throw new ArgumentNullException("entity"); throw new ArgumentNullException("entity");
@ -63,14 +64,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
case Accessibility.Public: case Accessibility.Public:
return true; return true;
case Accessibility.Protected: case Accessibility.Protected:
return IsProtectedAccessible(entity.DeclaringTypeDefinition, typeOfReference); return allowProtectedAccess && IsProtectedAccessible(entity.DeclaringTypeDefinition);
case Accessibility.Internal: case Accessibility.Internal:
return IsInternalAccessible(entity.ProjectContent); return IsInternalAccessible(entity.ProjectContent);
case Accessibility.ProtectedOrInternal: case Accessibility.ProtectedOrInternal:
return IsProtectedAccessible(entity.DeclaringTypeDefinition, typeOfReference) return (allowProtectedAccess && IsProtectedAccessible(entity.DeclaringTypeDefinition))
|| IsInternalAccessible(entity.ProjectContent); || IsInternalAccessible(entity.ProjectContent);
case Accessibility.ProtectedAndInternal: case Accessibility.ProtectedAndInternal:
return IsProtectedAccessible(entity.DeclaringTypeDefinition, typeOfReference) return (allowProtectedAccess && IsProtectedAccessible(entity.DeclaringTypeDefinition))
&& IsInternalAccessible(entity.ProjectContent); && IsInternalAccessible(entity.ProjectContent);
default: default:
throw new Exception("Invalid value for Accessibility"); 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); return declaringProject != null && currentProject != null && declaringProject.InternalsVisibleTo(currentProject, context);
} }
bool IsProtectedAccessible(ITypeDefinition declaringType, IType typeOfReference) bool IsProtectedAccessible(ITypeDefinition declaringType)
{ {
if (declaringType == currentTypeDefinition) if (declaringType == currentTypeDefinition)
return true; return true;
// PERF: this might hurt performance as this method is called several times (once for each member) // 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 // make sure resolving base types is cheap (caches?) or cache within the MemberLookup instance
if (currentTypeDefinition == null || !currentTypeDefinition.IsDerivedFrom(declaringType, context)) return 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);
} }
#endregion #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 @@
// 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 @@
// 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;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
/// <summary> /// <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> /// </summary>
public sealed class SimpleTypeOrNamespaceReference : ITypeOrNamespaceReference public sealed class SimpleTypeOrNamespaceReference : ITypeOrNamespaceReference
{ {
readonly IMember parentMember;
readonly ITypeDefinition parentTypeDefinition; readonly ITypeDefinition parentTypeDefinition;
readonly UsingScope parentUsingScope; readonly UsingScope parentUsingScope;
readonly string identifier; readonly string identifier;
readonly IList<ITypeReference> typeArguments; 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) if (identifier == null)
throw new ArgumentNullException("identifier"); throw new ArgumentNullException("identifier");
this.identifier = identifier; this.identifier = identifier;
this.typeArguments = typeArguments ?? EmptyList<ITypeReference>.Instance; this.typeArguments = typeArguments ?? EmptyList<ITypeReference>.Instance;
this.parentMember = parentMember;
this.parentTypeDefinition = parentTypeDefinition; this.parentTypeDefinition = parentTypeDefinition;
this.parentUsingScope = parentUsingScope; this.parentUsingScope = parentUsingScope;
this.isInUsingDeclaration = isInUsingDeclaration;
} }
ResolveResult DoResolve(ITypeResolveContext context) ResolveResult DoResolve(ITypeResolveContext context)
{ {
CSharpResolver r = new CSharpResolver(context); CSharpResolver r = new CSharpResolver(context);
r.CurrentMember = parentMember;
r.CurrentTypeDefinition = parentTypeDefinition.GetCompoundClass(); r.CurrentTypeDefinition = parentTypeDefinition.GetCompoundClass();
r.UsingScope = parentUsingScope; r.UsingScope = parentUsingScope;
IType[] typeArgs = new IType[typeArguments.Count]; IType[] typeArgs = new IType[typeArguments.Count];
for (int i = 0; i < typeArgs.Length; i++) { for (int i = 0; i < typeArgs.Length; i++) {
typeArgs[i] = typeArguments[i].Resolve(context); 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 DoResolve(context) as NamespaceResolveResult;
return nrr != null ? nrr.NamespaceName : null;
} }
public IType Resolve(ITypeResolveContext context) public IType Resolve(ITypeResolveContext context)

3
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

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

47
ICSharpCode.NRefactory/TypeSystem/ArrayType.cs

@ -46,22 +46,55 @@ namespace ICSharpCode.NRefactory.TypeSystem
return a != null && elementType.Equals(a.elementType) && a.dimensions == dimensions; 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) public override IEnumerable<IType> GetBaseTypes(ITypeResolveContext context)
{ {
List<IType> baseTypes = new List<IType>(); List<IType> baseTypes = new List<IType>();
// PERF: if profiling shows the GetClass(typeof()) here to be a problem, create IType t = systemArray.Resolve(context);
// a static cache for the ITypeDefinitions if (t != SharedTypes.UnknownType)
ITypeDefinition t = context.GetClass(typeof(Array));
if (t != null)
baseTypes.Add(t); baseTypes.Add(t);
if (dimensions == 1) { // single-dimensional arrays implement IList<T> if (dimensions == 1) { // single-dimensional arrays implement IList<T>
t = context.GetClass(typeof(IList<>)); ITypeDefinition def = listInterface.Resolve(context) as ITypeDefinition;
if (t != null) if (def != null)
baseTypes.Add(new ParameterizedType(t, new[] { elementType })); baseTypes.Add(new ParameterizedType(def, new[] { elementType }));
} }
return baseTypes; 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) public override IType AcceptVisitor(TypeVisitor visitor)
{ {
return visitor.VisitArrayType(this); return visitor.VisitArrayType(this);

34
ICSharpCode.NRefactory/TypeSystem/IType.cs

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

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

@ -61,32 +61,32 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return EmptyList<IType>.Instance; 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; 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; 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; 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; 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; 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; return EmptyList<IEvent>.Instance;
} }

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

@ -377,11 +377,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return this; return this;
} }
public virtual IEnumerable<IType> GetNestedTypes(ITypeResolveContext context) public virtual IEnumerable<IType> GetNestedTypes(ITypeResolveContext context, Predicate<ITypeDefinition> filter = null)
{ {
ITypeDefinition compound = GetCompoundClass(); ITypeDefinition compound = GetCompoundClass();
if (compound != this) if (compound != this)
return compound.GetNestedTypes(context); return compound.GetNestedTypes(context, filter);
List<IType> nestedTypes = new List<IType>(); List<IType> nestedTypes = new List<IType>();
using (var busyLock = BusyManager.Enter(this)) { using (var busyLock = BusyManager.Enter(this)) {
@ -391,15 +391,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ITypeDefinition baseTypeDef = baseType.GetDefinition(); ITypeDefinition baseTypeDef = baseType.GetDefinition();
if (baseTypeDef != null && baseTypeDef.ClassType != ClassType.Interface) { if (baseTypeDef != null && baseTypeDef.ClassType != ClassType.Interface) {
// get nested types from baseType (not baseTypeDef) so that generics work correctly // 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 break; // there is at most 1 non-interface base
} }
} }
foreach (ITypeDefinition innerClass in this.InnerClasses) { foreach (ITypeDefinition innerClass in this.InnerClasses) {
if (innerClass.TypeParameterCount > 0) { if (filter == null || filter(innerClass)) {
// Parameterize inner classes with their own type parameters, as per <remarks> on IType.GetNestedTypes.
nestedTypes.Add(new ParameterizedType(innerClass, innerClass.TypeParameters));
} else {
nestedTypes.Add(innerClass); nestedTypes.Add(innerClass);
} }
} }
@ -408,113 +405,151 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return nestedTypes; return nestedTypes;
} }
public virtual IEnumerable<IMethod> GetMethods(ITypeResolveContext context) public virtual IEnumerable<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter = null)
{ {
ITypeDefinition compound = GetCompoundClass(); ITypeDefinition compound = GetCompoundClass();
if (compound != this) if (compound != this)
return compound.GetMethods(context); return compound.GetMethods(context, filter);
List<IMethod> methods = new List<IMethod>(); List<IMethod> methods = new List<IMethod>();
using (var busyLock = BusyManager.Enter(this)) { using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) { if (busyLock.Success) {
foreach (var baseTypeRef in this.BaseTypes) { int baseCount = 0;
IType baseType = baseTypeRef.Resolve(context); foreach (var baseType in GetBaseTypes(context)) {
ITypeDefinition baseTypeDef = baseType.GetDefinition(); ITypeDefinition baseTypeDef = baseType.GetDefinition();
if (baseTypeDef != null && (baseTypeDef.ClassType != ClassType.Interface || this.ClassType == ClassType.Interface)) { 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; return methods;
} }
public virtual IEnumerable<IMethod> GetConstructors(ITypeResolveContext context) public virtual IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter = null)
{ {
ITypeDefinition compound = GetCompoundClass(); ITypeDefinition compound = GetCompoundClass();
if (compound != this) if (compound != this)
return compound.GetConstructors(context); return compound.GetConstructors(context, filter);
List<IMethod> methods = new List<IMethod>(); 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.AddDefaultConstructorIfRequired) {
if (this.ClassType == ClassType.Class && methods.Count == 0 if (this.ClassType == ClassType.Class && methods.Count == 0
|| this.ClassType == ClassType.Enum || this.ClassType == ClassType.Struct) || 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; return methods;
} }
public virtual IEnumerable<IProperty> GetProperties(ITypeResolveContext context) public virtual IEnumerable<IProperty> GetProperties(ITypeResolveContext context, Predicate<IProperty> filter = null)
{ {
ITypeDefinition compound = GetCompoundClass(); ITypeDefinition compound = GetCompoundClass();
if (compound != this) if (compound != this)
return compound.GetProperties(context); return compound.GetProperties(context, filter);
List<IProperty> properties = new List<IProperty>(); List<IProperty> properties = new List<IProperty>();
using (var busyLock = BusyManager.Enter(this)) { using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) { if (busyLock.Success) {
foreach (var baseTypeRef in this.BaseTypes) { int baseCount = 0;
IType baseType = baseTypeRef.Resolve(context); foreach (var baseType in GetBaseTypes(context)) {
ITypeDefinition baseTypeDef = baseType.GetDefinition(); ITypeDefinition baseTypeDef = baseType.GetDefinition();
if (baseTypeDef != null && (baseTypeDef.ClassType != ClassType.Interface || this.ClassType == ClassType.Interface)) { 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; return properties;
} }
public virtual IEnumerable<IField> GetFields(ITypeResolveContext context) public virtual IEnumerable<IField> GetFields(ITypeResolveContext context, Predicate<IField> filter = null)
{ {
ITypeDefinition compound = GetCompoundClass(); ITypeDefinition compound = GetCompoundClass();
if (compound != this) if (compound != this)
return compound.GetFields(context); return compound.GetFields(context, filter);
List<IField> fields = new List<IField>(); List<IField> fields = new List<IField>();
using (var busyLock = BusyManager.Enter(this)) { using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) { if (busyLock.Success) {
foreach (var baseTypeRef in this.BaseTypes) { int baseCount = 0;
IType baseType = baseTypeRef.Resolve(context); foreach (var baseType in GetBaseTypes(context)) {
ITypeDefinition baseTypeDef = baseType.GetDefinition(); ITypeDefinition baseTypeDef = baseType.GetDefinition();
if (baseTypeDef != null && (baseTypeDef.ClassType != ClassType.Interface || this.ClassType == ClassType.Interface)) { 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; return fields;
} }
public virtual IEnumerable<IEvent> GetEvents(ITypeResolveContext context) public virtual IEnumerable<IEvent> GetEvents(ITypeResolveContext context, Predicate<IEvent> filter = null)
{ {
ITypeDefinition compound = GetCompoundClass(); ITypeDefinition compound = GetCompoundClass();
if (compound != this) if (compound != this)
return compound.GetEvents(context); return compound.GetEvents(context, filter);
List<IEvent> events = new List<IEvent>(); List<IEvent> events = new List<IEvent>();
using (var busyLock = BusyManager.Enter(this)) { using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) { if (busyLock.Success) {
foreach (var baseTypeRef in this.BaseTypes) { int baseCount = 0;
IType baseType = baseTypeRef.Resolve(context); foreach (var baseType in GetBaseTypes(context)) {
ITypeDefinition baseTypeDef = baseType.GetDefinition(); ITypeDefinition baseTypeDef = baseType.GetDefinition();
if (baseTypeDef != null && (baseTypeDef.ClassType != ClassType.Interface || this.ClassType == ClassType.Interface)) { 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; 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 // we use reference equality
bool IEquatable<IType>.Equals(IType other) bool IEquatable<IType>.Equals(IType other)
{ {

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

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

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

@ -17,27 +17,27 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.IsSealed = true; this.IsSealed = true;
} }
public override IEnumerable<IMethod> GetConstructors(ITypeResolveContext context) public override IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter)
{ {
return EmptyList<IMethod>.Instance; 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; 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; 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; 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; return EmptyList<IProperty>.Instance;
} }

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

6
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. 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. 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... 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 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). 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 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. 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: The solution is to make the read lock more coarse-grained:
using (var syncContext = compositeTypeResolveContext.Synchronize()) { 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. 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. 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? Q: What format do the .ToString() methods use?

Loading…
Cancel
Save