1 | // Copyright (c) 2013 AlphaSierraPapa for the SharpDevelop Team |
---|
2 | // |
---|
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this |
---|
4 | // software and associated documentation files (the "Software"), to deal in the Software |
---|
5 | // without restriction, including without limitation the rights to use, copy, modify, merge, |
---|
6 | // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
---|
7 | // to whom the Software is furnished to do so, subject to the following conditions: |
---|
8 | // |
---|
9 | // The above copyright notice and this permission notice shall be included in all copies or |
---|
10 | // substantial portions of the Software. |
---|
11 | // |
---|
12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
---|
13 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
---|
14 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
---|
15 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
---|
16 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
---|
17 | // DEALINGS IN THE SOFTWARE. |
---|
18 | |
---|
19 | using System; |
---|
20 | using System.Collections.Generic; |
---|
21 | using ICSharpCode.NRefactory.TypeSystem; |
---|
22 | using System.Linq; |
---|
23 | |
---|
24 | namespace ICSharpCode.NRefactory.Analysis |
---|
25 | { |
---|
26 | /// <summary> |
---|
27 | /// The symbol collector collects related symbols that form a group of symbols that should be renamed |
---|
28 | /// when a name of one symbol changes. For example if a type definition name should be changed |
---|
29 | /// the constructors and destructor names should change as well. |
---|
30 | /// </summary> |
---|
31 | public class SymbolCollector |
---|
32 | { |
---|
33 | /// <summary> |
---|
34 | /// Gets or sets a value indicating whether this <see cref="ICSharpCode.NRefactory.Analysis.SymbolCollector"/> should include overloads. |
---|
35 | /// </summary> |
---|
36 | /// <value><c>true</c> if overloads should be included; otherwise, <c>false</c>.</value> |
---|
37 | public bool IncludeOverloads { |
---|
38 | get; |
---|
39 | set; |
---|
40 | } |
---|
41 | |
---|
42 | public bool GroupForRenaming { |
---|
43 | get; |
---|
44 | set; |
---|
45 | } |
---|
46 | |
---|
47 | static IEnumerable<ISymbol> CollectTypeRelatedMembers (ITypeDefinition type) |
---|
48 | { |
---|
49 | yield return type; |
---|
50 | foreach (var c in type.GetDefinition ().GetMembers (m => !m.IsSynthetic && (m.SymbolKind == SymbolKind.Constructor || m.SymbolKind == SymbolKind.Destructor), GetMemberOptions.IgnoreInheritedMembers)) { |
---|
51 | yield return c; |
---|
52 | } |
---|
53 | } |
---|
54 | |
---|
55 | static IEnumerable<ISymbol> CollectOverloads (IMethod method) |
---|
56 | { |
---|
57 | return method.DeclaringType |
---|
58 | .GetMethods (m => m.Name == method.Name) |
---|
59 | .Where (m => m != method); |
---|
60 | } |
---|
61 | |
---|
62 | static IMember SearchMember (ITypeDefinition derivedType, IMember method) |
---|
63 | { |
---|
64 | foreach (var m in derivedType.Members) { |
---|
65 | if (m.ImplementedInterfaceMembers.Contains (method)) |
---|
66 | return m; |
---|
67 | } |
---|
68 | return null; |
---|
69 | } |
---|
70 | |
---|
71 | static IEnumerable<ISymbol> MakeUnique (List<ISymbol> symbols) |
---|
72 | { |
---|
73 | HashSet<ISymbol> taken = new HashSet<ISymbol> (); |
---|
74 | foreach (var sym in symbols) { |
---|
75 | if (taken.Contains (sym)) |
---|
76 | continue; |
---|
77 | taken.Add (sym); |
---|
78 | yield return sym; |
---|
79 | } |
---|
80 | } |
---|
81 | |
---|
82 | /// <summary> |
---|
83 | /// Gets the related symbols. |
---|
84 | /// </summary> |
---|
85 | /// <returns>The related symbols.</returns> |
---|
86 | /// <param name="g">The type graph.</param> |
---|
87 | /// <param name="m">The symbol to search</param> |
---|
88 | public IEnumerable<ISymbol> GetRelatedSymbols(Lazy<TypeGraph> g, ISymbol m) |
---|
89 | { |
---|
90 | switch (m.SymbolKind) { |
---|
91 | case SymbolKind.TypeDefinition: |
---|
92 | return CollectTypeRelatedMembers ((ITypeDefinition)m); |
---|
93 | |
---|
94 | case SymbolKind.Field: |
---|
95 | case SymbolKind.Operator: |
---|
96 | case SymbolKind.Variable: |
---|
97 | case SymbolKind.Parameter: |
---|
98 | case SymbolKind.TypeParameter: |
---|
99 | return new ISymbol[] { m }; |
---|
100 | |
---|
101 | case SymbolKind.Constructor: |
---|
102 | if (GroupForRenaming) |
---|
103 | return GetRelatedSymbols (g, ((IMethod)m).DeclaringTypeDefinition); |
---|
104 | List<ISymbol> constructorSymbols = new List<ISymbol> (); |
---|
105 | if (IncludeOverloads) { |
---|
106 | foreach (var m3 in CollectOverloads ((IMethod)m)) { |
---|
107 | constructorSymbols.Add (m3); |
---|
108 | } |
---|
109 | } |
---|
110 | return constructorSymbols; |
---|
111 | |
---|
112 | case SymbolKind.Destructor: |
---|
113 | if (GroupForRenaming) |
---|
114 | return GetRelatedSymbols (g, ((IMethod)m).DeclaringTypeDefinition); |
---|
115 | return new ISymbol[] { m }; |
---|
116 | |
---|
117 | case SymbolKind.Indexer: |
---|
118 | case SymbolKind.Event: |
---|
119 | case SymbolKind.Property: |
---|
120 | case SymbolKind.Method: { |
---|
121 | var member = (IMember)m; |
---|
122 | List<ISymbol> symbols = new List<ISymbol> (); |
---|
123 | if (!member.IsExplicitInterfaceImplementation) |
---|
124 | symbols.Add (member); |
---|
125 | if (GroupForRenaming) { |
---|
126 | foreach (var m2 in member.ImplementedInterfaceMembers) { |
---|
127 | symbols.AddRange (GetRelatedSymbols (g, m2)); |
---|
128 | } |
---|
129 | } else { |
---|
130 | symbols.AddRange(member.ImplementedInterfaceMembers); |
---|
131 | } |
---|
132 | |
---|
133 | if (member.DeclaringType.Kind == TypeKind.Interface) { |
---|
134 | var declaringTypeNode = g.Value.GetNode(member.DeclaringTypeDefinition); |
---|
135 | if (declaringTypeNode != null) { |
---|
136 | foreach (var derivedType in declaringTypeNode.DerivedTypes) { |
---|
137 | var mem = SearchMember (derivedType.TypeDefinition, member); |
---|
138 | if (mem != null) |
---|
139 | symbols.Add (mem); |
---|
140 | } |
---|
141 | } |
---|
142 | } |
---|
143 | |
---|
144 | |
---|
145 | if (IncludeOverloads) { |
---|
146 | IncludeOverloads = false; |
---|
147 | if (member is IMethod) { |
---|
148 | foreach (var m3 in CollectOverloads ((IMethod)member)) { |
---|
149 | symbols.AddRange (GetRelatedSymbols (g, m3)); |
---|
150 | } |
---|
151 | } else if (member.SymbolKind == SymbolKind.Indexer) { |
---|
152 | symbols.AddRange (member.DeclaringTypeDefinition.GetProperties (p => p.IsIndexer)); |
---|
153 | } |
---|
154 | } |
---|
155 | return MakeUnique (symbols); |
---|
156 | } |
---|
157 | case SymbolKind.Namespace: |
---|
158 | // TODO? |
---|
159 | return new ISymbol[] { m }; |
---|
160 | default: |
---|
161 | throw new ArgumentOutOfRangeException ("symbol:"+m.SymbolKind); |
---|
162 | } |
---|
163 | } |
---|
164 | } |
---|
165 | } |
---|