// Copyright (c) 2013 AlphaSierraPapa for the SharpDevelop Team // // 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 // without restriction, including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons // to whom the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; using ICSharpCode.NRefactory.TypeSystem; using System.Linq; namespace ICSharpCode.NRefactory.Analysis { /// /// 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. /// public class SymbolCollector { /// /// Gets or sets a value indicating whether this should include overloads. /// /// true if overloads should be included; otherwise, false. public bool IncludeOverloads { get; set; } public bool GroupForRenaming { get; set; } static IEnumerable 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 CollectOverloads (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 MakeUnique (List symbols) { HashSet taken = new HashSet (); foreach (var sym in symbols) { if (taken.Contains (sym)) continue; taken.Add (sym); yield return sym; } } /// /// Gets the related symbols. /// /// The related symbols. /// The type graph. /// The symbol to search public IEnumerable GetRelatedSymbols(Lazy g, ISymbol 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: if (GroupForRenaming) return GetRelatedSymbols (g, ((IMethod)m).DeclaringTypeDefinition); List constructorSymbols = new List (); if (IncludeOverloads) { foreach (var m3 in CollectOverloads ((IMethod)m)) { constructorSymbols.Add (m3); } } return constructorSymbols; case SymbolKind.Destructor: if (GroupForRenaming) return GetRelatedSymbols (g, ((IMethod)m).DeclaringTypeDefinition); return new ISymbol[] { m }; case SymbolKind.Indexer: case SymbolKind.Event: case SymbolKind.Property: case SymbolKind.Method: { var member = (IMember)m; List symbols = new List (); if (!member.IsExplicitInterfaceImplementation) symbols.Add (member); if (GroupForRenaming) { foreach (var m2 in member.ImplementedInterfaceMembers) { symbols.AddRange (GetRelatedSymbols (g, m2)); } } else { symbols.AddRange(member.ImplementedInterfaceMembers); } if (member.DeclaringType.Kind == TypeKind.Interface) { var declaringTypeNode = g.Value.GetNode(member.DeclaringTypeDefinition); if (declaringTypeNode != null) { foreach (var derivedType in declaringTypeNode.DerivedTypes) { var mem = SearchMember (derivedType.TypeDefinition, member); if (mem != null) symbols.Add (mem); } } } if (IncludeOverloads) { IncludeOverloads = false; if (member is IMethod) { foreach (var m3 in CollectOverloads ((IMethod)member)) { symbols.AddRange (GetRelatedSymbols (g, m3)); } } else if (member.SymbolKind == SymbolKind.Indexer) { symbols.AddRange (member.DeclaringTypeDefinition.GetProperties (p => p.IsIndexer)); } } return MakeUnique (symbols); } case SymbolKind.Namespace: // TODO? return new ISymbol[] { m }; default: throw new ArgumentOutOfRangeException ("symbol:"+m.SymbolKind); } } } }