Browse Source

[CodeIssues] Improve ParameterCouldBeDemotedIssue.

newNRvisualizers
Simon Lindgren 13 years ago
parent
commit
be0d89c486
  1. 65
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeDemotedIssue.cs
  2. 116
      ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeDemotedTests.cs

65
ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeDemotedIssue.cs

@ -68,8 +68,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
continue; continue;
var currentType = localResolveResult.Type; var currentType = localResolveResult.Type;
var candidateTypes = localResolveResult.Type.GetAllBaseTypes().ToList(); var candidateTypes = localResolveResult.Type.GetAllBaseTypes().ToList();
candidateTypes.Add(localResolveResult.Type); var possibleTypes = GetPossibleTypes(candidateTypes, invocations);
var possibleTypes = GetLeastDerivedImplementors(candidateTypes, invocations);
var suggestedTypes = possibleTypes.Where(t => t != currentType); var suggestedTypes = possibleTypes.Where(t => t != currentType);
if (suggestedTypes.Any()) if (suggestedTypes.Any())
AddIssue(parameter, context.TranslateString("Parameter can be demoted to base class"), AddIssue(parameter, context.TranslateString("Parameter can be demoted to base class"),
@ -89,45 +88,45 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} }
} }
static IEnumerable<IMember> GetDeclaredMembers(IMember member)
{
var implementedInterfaceMembers = member.ImplementedInterfaceMembers;
if (implementedInterfaceMembers.Count == 0) {
yield return member;
}
else {
foreach (var interfaceMember in implementedInterfaceMembers) {
yield return interfaceMember;
}
}
}
HashSet<IMember> GetNeededMembers(IEnumerable<InvocationResolveResult> invocations) HashSet<IMember> GetNeededMembers(IEnumerable<InvocationResolveResult> invocations)
{ {
var members = new HashSet<IMember>(); var members = new HashSet<IMember>();
foreach (var invocation in invocations) { foreach (var invocation in invocations) {
foreach (var member in GetDeclaredMembers(invocation.Member)) { members.Add(invocation.Member);
members.Add(member);
}
} }
return members; return members;
} }
bool SatisfiesMemberRequests(IType type, HashSet<IMember> members) static bool HasCommonMemberDeclaration(IEnumerable<IMember> acceptableMembers, IMember member)
{
var implementedInterfaceMembers = member.MemberDefinition.ImplementedInterfaceMembers;
if (implementedInterfaceMembers.Any()) {
return acceptableMembers.ContainsAny(implementedInterfaceMembers);
}
else {
return acceptableMembers.Contains(member.MemberDefinition);
}
}
bool SatisfiesMemberRequests(IType candidateType, HashSet<IMember> wantedMembers)
{ {
var unsatisfiedMembers = new HashSet<IMember>(members); var allMembers = candidateType.GetMembers();
foreach (var member in type.GetMembers()) { foreach (var wantedMember in wantedMembers) {
var interfaceMembers = member.ImplementedInterfaceMembers; IEnumerable<IMember> acceptableMembers;
if (interfaceMembers.Count > 0) { if (wantedMember.ImplementedInterfaceMembers.Any()) {
unsatisfiedMembers.RemoveWhere(m => interfaceMembers.Contains(m)); acceptableMembers = wantedMember.ImplementedInterfaceMembers.ToList();
} else { } else {
unsatisfiedMembers.RemoveWhere(m => m == member); acceptableMembers = new List<IMember>() { wantedMember.MemberDefinition };
} }
var hasMember = allMembers.Any(m => HasCommonMemberDeclaration(acceptableMembers, m));
if (!hasMember)
return false;
} }
return unsatisfiedMembers.Count == 0; return true;
} }
IEnumerable<IType> GetLeastDerivedImplementors(IEnumerable<IType> types, IEnumerable<InvocationResolveResult> invocations) IEnumerable<IType> GetPossibleTypes(IEnumerable<IType> types, IEnumerable<InvocationResolveResult> invocations)
{ {
var members = GetNeededMembers(invocations); var members = GetNeededMembers(invocations);
return from type in types return from type in types
@ -176,5 +175,17 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} }
} }
} }
static class IEnumerableExtensions
{
public static bool ContainsAny<T>(this IEnumerable<T> collection, IEnumerable<T> items)
{
foreach (var item in items) {
if (collection.Contains(item))
return true;
}
return false;
}
}
} }

116
ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeDemotedTests.cs

@ -27,18 +27,17 @@ using System;
using NUnit.Framework; using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.CodeActions; using ICSharpCode.NRefactory.CSharp.CodeActions;
using ICSharpCode.NRefactory.CSharp.Refactoring; using ICSharpCode.NRefactory.CSharp.Refactoring;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.CodeIssues namespace ICSharpCode.NRefactory.CSharp.CodeIssues
{ {
[TestFixture] [TestFixture]
public class ParameterCanBeDemotedTests : InspectionActionTestBase public class ParameterCanBeDemotedTests : InspectionActionTestBase
{ {
[Test] [Test]
public void BasicTest() public void BasicTest()
{ {
var input = @" var input = @"
class A class A
{ {
public virtual void Foo() {} public virtual void Foo() {}
@ -54,11 +53,13 @@ class C
b.Foo(); b.Foo();
} }
}"; }";
TestRefactoringContext context; TestRefactoringContext context;
var issues = GetIssues(new ParameterCanBeDemotedIssue(), input, out context); var issues = GetIssues(new ParameterCanBeDemotedIssue(), input, out context);
Assert.AreEqual(1, issues.Count); Assert.AreEqual(1, issues.Count);
var issue = issues [0];
Assert.AreEqual(1, issue.Actions.Count);
CheckFix(context, issues [0], @" CheckFix(context, issues [0], @"
class A class A
{ {
public virtual void Foo() {} public virtual void Foo() {}
@ -74,13 +75,13 @@ class C
b.Foo(); b.Foo();
} }
}" }"
); );
} }
[Test] [Test]
public void InterfaceTest() public void InterfaceTest()
{ {
var input = @" var input = @"
interface IA interface IA
{ {
void Foo(); void Foo();
@ -97,11 +98,13 @@ class C
b.Foo(); b.Foo();
} }
}"; }";
TestRefactoringContext context; TestRefactoringContext context;
var issues = GetIssues(new ParameterCanBeDemotedIssue(), input, out context); var issues = GetIssues(new ParameterCanBeDemotedIssue(), input, out context);
Assert.AreEqual(1, issues.Count); Assert.AreEqual(1, issues.Count);
var issue = issues [0];
Assert.AreEqual(1, issue.Actions.Count);
CheckFix(context, issues [0], @" CheckFix(context, issues [0], @"
interface IA interface IA
{ {
void Foo(); void Foo();
@ -118,8 +121,66 @@ class C
b.Foo(); b.Foo();
} }
}" }"
); );
} }
[Test]
public void MultipleInterfaceTest()
{
var input = @"
interface IA1
{
void Foo();
}
interface IA2
{
void Bar();
}
class B : IA1, IA2
{
public virtual void Foo() {}
public virtual void Bar() {}
}
class C : B {}
class Test
{
void F(C c)
{
c.Foo();
c.Bar();
}
}";
TestRefactoringContext context;
var issues = GetIssues(new ParameterCanBeDemotedIssue(), input, out context);
Assert.AreEqual(1, issues.Count);
var issue = issues [0];
Assert.AreEqual(1, issue.Actions.Count);
CheckFix(context, issues [0], @"
interface IA1
{
void Foo();
}
interface IA2
{
void Bar();
}
class B : IA1, IA2
{
public virtual void Foo() {}
public virtual void Bar() {}
}
class C : B {}
class Test
{
void F(B c)
{
c.Foo();
c.Bar();
}
}"
);
}
string baseInput = @" string baseInput = @"
interface IA interface IA
@ -160,7 +221,9 @@ class Test
TestRefactoringContext context; TestRefactoringContext context;
var issues = GetIssues(new ParameterCanBeDemotedIssue(), input, out context); var issues = GetIssues(new ParameterCanBeDemotedIssue(), input, out context);
Assert.AreEqual(1, issues.Count); Assert.AreEqual(1, issues.Count);
var fixes = issues [0].Actions; var issue = issues [0];
Assert.AreEqual(4, issue.Actions.Count);
CheckFix(context, issues [0], baseInput + @" CheckFix(context, issues [0], baseInput + @"
class Test class Test
{ {
@ -168,7 +231,8 @@ class Test
{ {
d.Foo(); d.Foo();
} }
}"); }"
);
} }
} }
} }

Loading…
Cancel
Save