Browse Source

Implemented first version of the symbol collector.

pull/45/merge
Mike Krüger 12 years ago
parent
commit
5b9e640160
  1. 162
      ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs
  2. 4
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs
  3. 104
      ICSharpCode.NRefactory/Analysis/SymbolCollector.cs

162
ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs

@ -29,6 +29,10 @@ using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework; using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.CodeCompletion; using ICSharpCode.NRefactory.CSharp.CodeCompletion;
using System.Text;
using System.Collections.Generic;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.CSharp.Resolver;
namespace ICSharpCode.NRefactory.Analysis namespace ICSharpCode.NRefactory.Analysis
{ {
@ -36,6 +40,164 @@ namespace ICSharpCode.NRefactory.Analysis
public class SymbolCollectorTests public class SymbolCollectorTests
{ {
void CollectMembers(string code, string memberName, bool includeOverloads = true)
{
StringBuilder sb = new StringBuilder();
List<int> offsets = new List<int>();
foreach (var ch in code) {
if (ch == '$') {
offsets.Add(sb.Length);
continue;
}
sb.Append(ch);
}
var syntaxTree = SyntaxTree.Parse(sb.ToString (), "test.cs");
var unresolvedFile = syntaxTree.ToTypeSystem();
var compilation = TypeSystemHelper.CreateCompilation(unresolvedFile);
var symbol = FindReferencesTest.GetSymbol(compilation, memberName);
var result = SymbolCollector.GetRelatedSymbols (new TypeGraph (compilation.Assemblies),
symbol, includeOverloads);
if (offsets.Count != result.Count()) {
foreach (var a in result)
Console.WriteLine(a);
}
Assert.AreEqual(offsets.Count, result.Count());
var doc = new ReadOnlyDocument(sb.ToString ());
result
.Select(r => doc.GetOffset ((r as IEntity).Region.Begin))
.SequenceEqual(offsets);
}
[Test]
public void TestSingleInterfaceImpl ()
{
var code = @"
interface IA
{
void $Method();
}
class A : IA
{
public virtual void $Method() { };
}
class B : A
{
public override void Method() { };
}
class C : IA
{
public void $Method() { };
}";
CollectMembers(code, "IA.Method");
}
[Test]
public void TestMultiInterfacesImpl1 ()
{
var code = @"
interface IA
{
void $Method();
}
interface IB
{
void $Method();
}
class A : IA, IB
{
public void $Method() { }
}
class B : IA
{
public void $Method() { }
}
class C : IB
{
public void $Method() { }
}";
CollectMembers(code, "A.Method");
}
[Test]
public void TestOverloads ()
{
var code = @"
class A
{
public void $Method () { }
public void $Method (int i) { }
public void $Method (string i) { }
}
";
CollectMembers(code, "A.Method");
}
[Test]
public void TestConstructor ()
{
var code = @"
class $A
{
public $A() { }
public $A(int i) { }
}
";
CollectMembers(code, "A");
}
[Test]
public void TestDestructor ()
{
var code = @"
class $A
{
$~A() { }
}
";
CollectMembers(code, "A");
}
[Test]
public void TestStaticConstructor ()
{
var code = @"
class $A
{
static $A() { }
public $A(int i) { }
}
";
CollectMembers(code, "A");
}
[Test]
public void TestShadowedMember ()
{
var code = @"
class A
{
public int $Prop
{ get; set; }
}
class B : A
{
public int Prop
{ get; set; }
}
";
CollectMembers(code, "A.Prop");
}
} }
} }

4
ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs

@ -389,7 +389,7 @@ namespace Foo
#region Rename #region Rename
ISymbol GetSymbol (string reflectionName) internal static ISymbol GetSymbol (ICompilation compilation, string reflectionName)
{ {
Stack<ITypeDefinition> typeStack = new Stack<ITypeDefinition>(compilation.MainAssembly.TopLevelTypeDefinitions); Stack<ITypeDefinition> typeStack = new Stack<ITypeDefinition>(compilation.MainAssembly.TopLevelTypeDefinitions);
while (typeStack.Count > 0) { while (typeStack.Count > 0) {
@ -408,7 +408,7 @@ namespace Foo
IList<AstNode> Rename(string fullyQualifiedName, string newName, bool includeOverloads) IList<AstNode> Rename(string fullyQualifiedName, string newName, bool includeOverloads)
{ {
var sym = GetSymbol(fullyQualifiedName); var sym = GetSymbol(compilation, fullyQualifiedName);
Assert.NotNull(sym); Assert.NotNull(sym);
var graph = new TypeGraph(compilation.Assemblies); var graph = new TypeGraph(compilation.Assemblies);

104
ICSharpCode.NRefactory/Analysis/SymbolCollector.cs

@ -1,4 +1,4 @@
// Copyright (c) 2013 AlphaSierraPapa for the SharpDevelop Team // Copyright (c) 2013 AlphaSierraPapa for the SharpDevelop Team
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software // software and associated documentation files (the "Software"), to deal in the Software
@ -19,14 +19,114 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using System.Linq;
namespace ICSharpCode.NRefactory.Analysis namespace ICSharpCode.NRefactory.Analysis
{ {
/// <summary>
/// The symbol collector collects related symbols that form a group of symbols that should be renamed
/// when a name of one symbol changes. For example if a type definition name should be changed
/// the constructors and destructor names should change as well.
/// </summary>
public class SymbolCollector public class SymbolCollector
{ {
static IEnumerable<ISymbol> CollectTypeRelatedMembers (ITypeDefinition type)
{
yield return type;
foreach (var c in type.GetDefinition ().GetMembers (m => !m.IsSynthetic && (m.SymbolKind == SymbolKind.Constructor || m.SymbolKind == SymbolKind.Destructor), GetMemberOptions.IgnoreInheritedMembers)) {
yield return c;
}
}
static IEnumerable<ISymbol> CollectOverloads (TypeGraph g, IMethod method)
{
return method.DeclaringType
.GetMethods (m => m.Name == method.Name)
.Where (m => m != method);
}
static IMember SearchMember (ITypeDefinition derivedType, IMember method)
{
foreach (var m in derivedType.Members) {
if (m.ImplementedInterfaceMembers.Contains (method))
return m;
}
return null;
}
static IEnumerable<ISymbol> MakeUnique (List<ISymbol> symbols)
{
HashSet<ISymbol> taken = new HashSet<ISymbol> ();
foreach (var sym in symbols) {
if (taken.Contains (sym))
continue;
taken.Add (sym);
yield return sym;
}
}
/// <summary>
/// Gets the related symbols.
/// </summary>
/// <returns>The related symbols.</returns>
/// <param name="g">The type graph.</param>
/// <param name="m">The symbol to search</param>
/// <param name="includeOverloads">If set to <c>true</c> overloads are included in the rename.</param>
public static IEnumerable<ISymbol> GetRelatedSymbols(TypeGraph g, ISymbol m, bool includeOverloads) public static IEnumerable<ISymbol> GetRelatedSymbols(TypeGraph g, ISymbol m, bool includeOverloads)
{ {
yield return m; switch (m.SymbolKind) {
case SymbolKind.TypeDefinition:
return CollectTypeRelatedMembers ((ITypeDefinition)m);
case SymbolKind.Field:
case SymbolKind.Operator:
case SymbolKind.Variable:
case SymbolKind.Parameter:
case SymbolKind.TypeParameter:
return new ISymbol[] { m };
case SymbolKind.Constructor:
case SymbolKind.Destructor:
return GetRelatedSymbols (g, ((IMethod)m).DeclaringTypeDefinition, includeOverloads);
case SymbolKind.Indexer:
case SymbolKind.Event:
case SymbolKind.Property:
return new ISymbol[] { m };
case SymbolKind.Method:
var method = (IMethod)m;
List<ISymbol> symbols = new List<ISymbol> ();
if (method.ImplementedInterfaceMembers.Count > 0) {
foreach (var m2 in method.ImplementedInterfaceMembers) {
symbols.AddRange (GetRelatedSymbols (g, m2, includeOverloads));
}
} else {
symbols.Add (method);
}
if (method.DeclaringType.Kind == TypeKind.Interface) {
foreach (var derivedType in g.GetNode (method.DeclaringTypeDefinition).DerivedTypes) {
var member = SearchMember (derivedType.TypeDefinition, method);
if (member != null)
symbols.Add (member);
}
}
if (includeOverloads) {
foreach (var m3 in CollectOverloads (g, method)) {
symbols.AddRange (GetRelatedSymbols (g, m3, false));
}
}
return MakeUnique (symbols);
case SymbolKind.Namespace:
// TODO?
return new ISymbol[] { m };
default:
throw new ArgumentOutOfRangeException ("symbol:"+m.SymbolKind);
}
} }
} }
} }

Loading…
Cancel
Save