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 @@ -437,6 +437,12 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
m.IsExtensionMethod = 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);
if (!methodDeclaration.PrivateImplementationType.IsNull) {

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

@ -106,6 +106,26 @@ namespace ICSharpCode.NRefactory.CSharp.Parser @@ -106,6 +106,26 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
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]

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

@ -203,4 +203,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase @@ -203,4 +203,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase
void IGenericInterfaceWithUnifiableMethods<T, S>.Test(T 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 @@ -35,6 +35,9 @@ namespace ICSharpCode.NRefactory.TypeSystem
bool IsConstructor { get; }
bool IsDestructor { get; }
bool IsOperator { get; }
bool IsPartialMethodDeclaration { get; }
bool IsPartialMethodImplementation { get; }
}
/// <summary>
@ -42,6 +45,13 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -42,6 +45,13 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary>
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>
/// Gets the attributes associated with the return type. (e.g. [return: MarshalAs(...)])
/// </summary>

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

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

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

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

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

@ -150,11 +150,19 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -150,11 +150,19 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
internal readonly IUnresolvedMember[] unresolvedMembers;
internal readonly IMember[] resolvedMembers;
public MemberList(ITypeResolveContext[] contextPerMember, IUnresolvedMember[] unresolvedMembers)
public MemberList(ITypeResolveContext[] contextPerMember, IUnresolvedMember[] unresolvedMembers, List<PartialMethodInfo> partialMethodInfos)
{
this.contextPerMember = contextPerMember;
this.unresolvedMembers = unresolvedMembers;
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] {
@ -236,6 +244,44 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -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 GetMemberList()
@ -247,11 +293,34 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -247,11 +293,34 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
List<IUnresolvedMember> unresolvedMembers = new List<IUnresolvedMember>();
List<ITypeResolveContext> contextPerMember = new List<ITypeResolveContext>();
List<PartialMethodInfo> partialMethodInfos = null;
bool addDefaultConstructorIfRequired = false;
foreach (IUnresolvedTypeDefinition part in parts) {
ITypeResolveContext parentContextForPart = part.CreateResolveContext(parentContext);
ITypeResolveContext contextForPart = parentContextForPart.WithCurrentTypeDefinition(this);
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);
contextPerMember.Add(contextForPart);
}
@ -270,7 +339,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -270,7 +339,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
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 {

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

@ -100,6 +100,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -100,6 +100,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
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 {
get {
if (parameters == null)

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

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

Loading…
Cancel
Save