diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs index d050067f58..5342de7b4d 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs @@ -89,6 +89,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring return; if (typeResolveResult.Type.Equals(member.DeclaringType)) return; + // check whether member.DeclaringType contains the original type + // (curiously recurring template pattern) + var v = new ContainsTypeVisitor(typeResolveResult.Type.GetDefinition()); + member.DeclaringType.AcceptVisitor(v); + if (v.IsContained) + return; AddIssue(issueAnchor, context.TranslateString("Static method invoked via derived type"), GetActions(context, targetExpression, member)); } @@ -96,14 +102,31 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring IEnumerable GetActions(BaseRefactoringContext context, Expression targetExpression, IMember member) { - var csResolver = context.Resolver.GetResolverStateBefore(targetExpression); - var builder = new TypeSystemAstBuilder(csResolver); + var builder = context.CreateTypeSytemAstBuilder(targetExpression); var newType = builder.ConvertType(member.DeclaringType); string description = string.Format("{0} '{1}'", context.TranslateString("Use base class"), newType.GetText()); yield return new CodeAction(description, script => { script.Replace(targetExpression, newType); }); } + + sealed class ContainsTypeVisitor : TypeVisitor + { + readonly ITypeDefinition searchedType; + internal bool IsContained; + + public ContainsTypeVisitor(ITypeDefinition searchedType) + { + this.searchedType = searchedType; + } + + public override IType VisitTypeDefinition(ITypeDefinition type) + { + if (type.Equals(searchedType)) + IsContained = true; + return base.VisitTypeDefinition(type); + } + } } #endregion } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ReferenceToStaticMemberViaDerivedTypeTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ReferenceToStaticMemberViaDerivedTypeTests.cs index c46e2b872e..f357818b34 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ReferenceToStaticMemberViaDerivedTypeTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ReferenceToStaticMemberViaDerivedTypeTests.cs @@ -299,6 +299,28 @@ class B : A var issues = GetIssues(new ReferenceToStaticMemberViaDerivedTypeIssue(), input, out context); Assert.AreEqual(0, issues.Count); } + + [Test] + public void IgnoresCuriouslyRecurringTemplatePattern() + { + var input = @" +class Base +{ + public static void F() { } +} +class Derived : Base {} +class Test +{ + void Main() + { + Derived.F(); + } +}"; + // do not suggest replacing 'Derived.F()' with 'Base.F()' + TestRefactoringContext context; + var issues = GetIssues(new ReferenceToStaticMemberViaDerivedTypeIssue(), input, out context); + Assert.AreEqual(0, issues.Count); + } } }