Browse Source

Add support for partial methods.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
3fbcf2f7d0
  1. 6
      ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs
  2. 20
      ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs
  3. 17
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs
  4. 10
      ICSharpCode.NRefactory/TypeSystem/IMethod.cs
  5. 2
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractUnresolvedEntity.cs
  6. 15
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs
  7. 74
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs
  8. 16
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedMethod.cs
  9. 4
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs

6
ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs

@ -437,6 +437,12 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
m.IsExtensionMethod = true; m.IsExtensionMethod = true;
currentTypeDefinition.HasExtensionMethods = true; currentTypeDefinition.HasExtensionMethods = true;
} }
if (methodDeclaration.HasModifier(Modifiers.Partial)) {
if (methodDeclaration.Body.IsNull)
m.IsPartialMethodDeclaration = true;
else
m.IsPartialMethodImplementation = true;
}
ConvertParameters(m.Parameters, methodDeclaration.Parameters); ConvertParameters(m.Parameters, methodDeclaration.Parameters);
if (!methodDeclaration.PrivateImplementationType.IsNull) { if (!methodDeclaration.PrivateImplementationType.IsNull) {

20
ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs

@ -106,6 +106,26 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
Assert.AreEqual(genericParamType.ReflectionName, interfaceGenericParamType.ReflectionName); Assert.AreEqual(genericParamType.ReflectionName, interfaceGenericParamType.ReflectionName);
} }
} }
[Test]
public void PartialMethodWithImplementation()
{
var t = compilation.FindType(typeof(PartialClass));
var methods = t.GetMethods(m => m.Name == "PartialMethodWithImplementation").ToList();
Assert.AreEqual(2, methods.Count);
var method1 = methods.Single(m => m.Parameters[0].Type.FullName == "System.Int32");
var method2 = methods.Single(m => m.Parameters[0].Type.FullName == "System.String");
Assert.AreEqual(2, method1.Parts.Count);
Assert.AreEqual(2, method2.Parts.Count);
}
[Test]
public void PartialMethodWithoutImplementation()
{
var t = compilation.FindType(typeof(PartialClass));
var method = t.GetMethods(m => m.Name == "PartialMethodWithoutImplementation").Single();
Assert.AreEqual(1, method.Parts.Count);
}
} }
[TestFixture] [TestFixture]

17
ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs

@ -203,4 +203,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase
void IGenericInterfaceWithUnifiableMethods<T, S>.Test(T a) {} void IGenericInterfaceWithUnifiableMethods<T, S>.Test(T a) {}
void IGenericInterfaceWithUnifiableMethods<T, S>.Test(S a) {} void IGenericInterfaceWithUnifiableMethods<T, S>.Test(S a) {}
} }
public partial class PartialClass
{
partial void PartialMethodWithImplementation(int a);
partial void PartialMethodWithImplementation(System.Int32 a)
{
}
partial void PartialMethodWithImplementation(string a);
partial void PartialMethodWithImplementation(System.String a)
{
}
partial void PartialMethodWithoutImplementation();
}
} }

10
ICSharpCode.NRefactory/TypeSystem/IMethod.cs

@ -35,6 +35,9 @@ namespace ICSharpCode.NRefactory.TypeSystem
bool IsConstructor { get; } bool IsConstructor { get; }
bool IsDestructor { get; } bool IsDestructor { get; }
bool IsOperator { get; } bool IsOperator { get; }
bool IsPartialMethodDeclaration { get; }
bool IsPartialMethodImplementation { get; }
} }
/// <summary> /// <summary>
@ -42,6 +45,13 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
public interface IMethod : IParameterizedMember public interface IMethod : IParameterizedMember
{ {
/// <summary>
/// Gets the unresolved method parts.
/// For partial methods, this returns all parts.
/// Otherwise, this returns an array with a single element (new[] { UnresolvedMember }).
/// </summary>
IList<IUnresolvedMethod> Parts { get; }
/// <summary> /// <summary>
/// Gets the attributes associated with the return type. (e.g. [return: MarshalAs(...)]) /// Gets the attributes associated with the return type. (e.g. [return: MarshalAs(...)])
/// </summary> /// </summary>

2
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractUnresolvedEntity.cs

@ -63,6 +63,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
internal const ushort FlagFieldIsVolatile = 0x2000; internal const ushort FlagFieldIsVolatile = 0x2000;
// flags for DefaultMethod: // flags for DefaultMethod:
internal const ushort FlagExtensionMethod = 0x1000; internal const ushort FlagExtensionMethod = 0x1000;
internal const ushort FlagPartialMethodDeclaration = 0x2000;
internal const ushort FlagPartialMethodImplemenation = 0x4000;
public bool IsFrozen { public bool IsFrozen {
get { return flags[FlagFrozen]; } get { return flags[FlagFrozen]; }

15
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs

@ -28,6 +28,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// </summary> /// </summary>
public class DefaultResolvedMethod : AbstractResolvedMember, IMethod public class DefaultResolvedMethod : AbstractResolvedMember, IMethod
{ {
IUnresolvedMethod[] parts;
public DefaultResolvedMethod(DefaultUnresolvedMethod unresolved, ITypeResolveContext parentContext) public DefaultResolvedMethod(DefaultUnresolvedMethod unresolved, ITypeResolveContext parentContext)
: this(unresolved, parentContext, unresolved.IsExtensionMethod) : this(unresolved, parentContext, unresolved.IsExtensionMethod)
{ {
@ -42,12 +44,25 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.IsExtensionMethod = isExtensionMethod; this.IsExtensionMethod = isExtensionMethod;
} }
public static DefaultResolvedMethod CreateFromMultipleParts(IUnresolvedMethod[] parts, ITypeResolveContext firstPartParentContext, bool isExtensionMethod)
{
DefaultResolvedMethod method = new DefaultResolvedMethod(parts[0], firstPartParentContext, isExtensionMethod);
method.parts = parts;
return method;
}
public IList<IParameter> Parameters { get; private set; } public IList<IParameter> Parameters { get; private set; }
public IList<IAttribute> ReturnTypeAttributes { get; private set; } public IList<IAttribute> ReturnTypeAttributes { get; private set; }
public IList<ITypeParameter> TypeParameters { get; private set; } public IList<ITypeParameter> TypeParameters { get; private set; }
public bool IsExtensionMethod { get; private set; } public bool IsExtensionMethod { get; private set; }
public IList<IUnresolvedMethod> Parts {
get {
return parts ?? new IUnresolvedMethod[] { (IUnresolvedMethod)unresolved };
}
}
public bool IsConstructor { public bool IsConstructor {
get { return ((IUnresolvedMethod)unresolved).IsConstructor; } get { return ((IUnresolvedMethod)unresolved).IsConstructor; }
} }

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

@ -150,11 +150,19 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
internal readonly IUnresolvedMember[] unresolvedMembers; internal readonly IUnresolvedMember[] unresolvedMembers;
internal readonly IMember[] resolvedMembers; internal readonly IMember[] resolvedMembers;
public MemberList(ITypeResolveContext[] contextPerMember, IUnresolvedMember[] unresolvedMembers) public MemberList(ITypeResolveContext[] contextPerMember, IUnresolvedMember[] unresolvedMembers, List<PartialMethodInfo> partialMethodInfos)
{ {
this.contextPerMember = contextPerMember; this.contextPerMember = contextPerMember;
this.unresolvedMembers = unresolvedMembers; this.unresolvedMembers = unresolvedMembers;
this.resolvedMembers = new IMember[unresolvedMembers.Length]; this.resolvedMembers = new IMember[unresolvedMembers.Length];
if (partialMethodInfos != null) {
foreach (var info in partialMethodInfos) {
unresolvedMembers[info.MemberIndex] = info.Parts[0];
contextPerMember[info.MemberIndex] = info.PrimaryContext;
resolvedMembers[info.MemberIndex] = DefaultResolvedMethod.CreateFromMultipleParts(
info.Parts.ToArray(), info.PrimaryContext, false);
}
}
} }
public IMember this[int index] { public IMember this[int index] {
@ -236,6 +244,44 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
} }
sealed class PartialMethodInfo
{
public readonly string Name;
public readonly int TypeParameterCount;
public readonly IList<IParameter> Parameters;
public readonly int MemberIndex;
public readonly List<IUnresolvedMethod> Parts = new List<IUnresolvedMethod>();
public ITypeResolveContext PrimaryContext;
public PartialMethodInfo(IUnresolvedMethod method, ITypeResolveContext context, int memberIndex)
{
this.Name = method.Name;
this.TypeParameterCount = method.TypeParameters.Count;
this.Parameters = method.Parameters.CreateResolvedParameters(context);
this.MemberIndex = memberIndex;
this.Parts.Add(method);
this.PrimaryContext = context;
}
public void AddPart(IUnresolvedMethod method, ITypeResolveContext context)
{
if (method.IsPartialMethodImplementation) {
// make the implementation the primary part
this.Parts.Insert(0, method);
this.PrimaryContext = context;
} else {
this.Parts.Add(method);
}
}
public bool IsSameSignature(PartialMethodInfo other, StringComparer nameComparer)
{
return nameComparer.Equals(this.Name, other.Name)
&& this.TypeParameterCount == other.TypeParameterCount
&& ParameterListComparer.Instance.Equals(this.Parameters, other.Parameters);
}
}
MemberList memberList; MemberList memberList;
MemberList GetMemberList() MemberList GetMemberList()
@ -247,11 +293,34 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
List<IUnresolvedMember> unresolvedMembers = new List<IUnresolvedMember>(); List<IUnresolvedMember> unresolvedMembers = new List<IUnresolvedMember>();
List<ITypeResolveContext> contextPerMember = new List<ITypeResolveContext>(); List<ITypeResolveContext> contextPerMember = new List<ITypeResolveContext>();
List<PartialMethodInfo> partialMethodInfos = null;
bool addDefaultConstructorIfRequired = false; bool addDefaultConstructorIfRequired = false;
foreach (IUnresolvedTypeDefinition part in parts) { foreach (IUnresolvedTypeDefinition part in parts) {
ITypeResolveContext parentContextForPart = part.CreateResolveContext(parentContext); ITypeResolveContext parentContextForPart = part.CreateResolveContext(parentContext);
ITypeResolveContext contextForPart = parentContextForPart.WithCurrentTypeDefinition(this); ITypeResolveContext contextForPart = parentContextForPart.WithCurrentTypeDefinition(this);
foreach (var member in part.Members) { foreach (var member in part.Members) {
IUnresolvedMethod method = member as IUnresolvedMethod;
if (method != null && (method.IsPartialMethodDeclaration || method.IsPartialMethodImplementation)) {
// Merge partial method declaration and implementation
if (partialMethodInfos == null)
partialMethodInfos = new List<PartialMethodInfo>();
PartialMethodInfo newInfo = new PartialMethodInfo(method, contextForPart, unresolvedMembers.Count);
PartialMethodInfo existingInfo = null;
foreach (var info in partialMethodInfos) {
if (newInfo.IsSameSignature(info, Compilation.NameComparer)) {
existingInfo = info;
break;
}
}
if (existingInfo != null) {
// Add the unresolved method to the PartialMethodInfo:
existingInfo.AddPart(method, contextForPart);
// We handled this unresolved method; do not add it to unresolvedMembers.
continue;
} else {
partialMethodInfos.Add(newInfo);
}
}
unresolvedMembers.Add(member); unresolvedMembers.Add(member);
contextPerMember.Add(contextForPart); contextPerMember.Add(contextForPart);
} }
@ -270,7 +339,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
unresolvedMembers.Add(DefaultUnresolvedMethod.CreateDefaultConstructor(parts[0])); unresolvedMembers.Add(DefaultUnresolvedMethod.CreateDefaultConstructor(parts[0]));
} }
} }
return LazyInit.GetOrSet(ref this.memberList, new MemberList(contextPerMember.ToArray(), unresolvedMembers.ToArray())); result = new MemberList(contextPerMember.ToArray(), unresolvedMembers.ToArray(), partialMethodInfos);
return LazyInit.GetOrSet(ref this.memberList, result);
} }
public IList<IMember> Members { public IList<IMember> Members {

16
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedMethod.cs

@ -100,6 +100,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return this.EntityType == EntityType.Operator; } get { return this.EntityType == EntityType.Operator; }
} }
public bool IsPartialMethodDeclaration {
get { return flags[FlagPartialMethodDeclaration]; }
set {
ThrowIfFrozen();
flags[FlagPartialMethodDeclaration] = value;
}
}
public bool IsPartialMethodImplementation {
get { return flags[FlagPartialMethodImplemenation]; }
set {
ThrowIfFrozen();
flags[FlagPartialMethodImplemenation] = value;
}
}
public IList<IUnresolvedParameter> Parameters { public IList<IUnresolvedParameter> Parameters {
get { get {
if (parameters == null) if (parameters == null)

4
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs

@ -144,6 +144,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return true; return true;
} }
public IList<IUnresolvedMethod> Parts {
get { return methodDefinition.Parts; }
}
public IList<IAttribute> ReturnTypeAttributes { public IList<IAttribute> ReturnTypeAttributes {
get { return methodDefinition.ReturnTypeAttributes; } get { return methodDefinition.ReturnTypeAttributes; }
} }

Loading…
Cancel
Save