5
// Mansheng Yang <lightyang0@gmail.com>
7
// Copyright (c) 2012 Mansheng Yang
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
using System.Collections.Generic;
29
using MonoDevelop.Projects;
30
using MonoDevelop.Ide.TypeSystem;
31
using ICSharpCode.NRefactory.TypeSystem;
33
namespace MonoDevelop.Ide.FindInFiles
35
public static class MemberCollector
38
static bool MatchParameters (IMember a, IMember b)
40
return MatchParameters (a as IParameterizedMember, b as IParameterizedMember);
43
static bool MatchParameters (IParameterizedMember a, IParameterizedMember b)
45
if (a == null && b == null) return true;
46
if (a == null || b == null) return false;
47
return ParameterListComparer.Instance.Equals (a.Parameters, b.Parameters);
51
/// find all base types(types that are not derived from other types) in the specified types
53
/// <param name="types"></param>
54
/// <returns></returns>
55
public static IEnumerable<ITypeDefinition> GetBaseTypes (IEnumerable<ITypeDefinition> types)
59
types = types.ToList ();
63
var baseType = types.FirstOrDefault ();
64
var otherTypes = new List<ITypeDefinition> ();
66
foreach (var type in types.Skip (1)) {
67
if (baseType.IsDerivedFrom (type)) {
69
} else if (!type.IsDerivedFrom (baseType)) {
70
// this type is not directly related to baseType
71
otherTypes.Add (type);
74
yield return baseType;
75
foreach (var type in GetBaseTypes (otherTypes))
79
static IEnumerable<IMember> GetMembers (ITypeDefinition type, string name, bool ignoreInherited,
80
Func<IMember, bool> filter)
82
var options = ignoreInherited ? GetMemberOptions.IgnoreInheritedMembers : GetMemberOptions.None;
83
var members = type.GetMembers (m => m.Name == name, options);
85
members = members.Where (filter);
89
static IEnumerable<ITypeDefinition> Import (ICompilation compilation, IEnumerable<ITypeDefinition> types)
91
return types.Select (t => compilation.Import (t));
95
/// collect members with the same signature/name(if overloads are included) as the specified member
96
/// in the inheritance tree
98
public static IEnumerable<IMember> CollectMembers (Solution solution, IMember member, ReferenceFinder.RefactoryScope scope,
99
bool includeOverloads = true, bool matchDeclaringType = false)
101
if (solution == null || member.EntityType == EntityType.Destructor || member.EntityType == EntityType.Operator)
102
return new [] { member };
104
if (member.EntityType == EntityType.Constructor) {
105
if (includeOverloads)
106
return member.DeclaringType.GetConstructors ();
107
return new [] { member };
110
Func<IMember, bool> memberFilter = null;
111
if (member is IParameterizedMember && !includeOverloads)
112
memberFilter = m => MatchParameters (m, member);
114
var declaringType = member.DeclaringTypeDefinition;
115
// only collect members in declaringType
116
if (matchDeclaringType)
117
return GetMembers (declaringType, member.Name, true, memberFilter);
119
if (declaringType.Kind != TypeKind.Class && declaringType.Kind != TypeKind.Interface)
120
return GetMembers (declaringType, member.Name, false, memberFilter);
122
var searchTypes = new List<ITypeDefinition> ();
123
var interfaces = from t in declaringType.GetAllBaseTypeDefinitions ()
124
where t.Kind == TypeKind.Interface && GetMembers (t, member.Name, true, memberFilter).Any ()
126
searchTypes.AddRange (GetBaseTypes (interfaces));
128
if (member.DeclaringType.Kind == TypeKind.Class) {
129
var members = GetMembers (declaringType, member.Name, false, memberFilter).ToList ();
130
if (members.Any (m => m.IsOverridable))
131
searchTypes.AddRange (GetBaseTypes (members.Select (m => m.DeclaringTypeDefinition)));
132
else if (searchTypes.Count == 0)
136
IList<ICompilation> compilations;
137
if (scope == ReferenceFinder.RefactoryScope.Solution || scope == ReferenceFinder.RefactoryScope.Unknown) {
138
var projects = SearchCollector.CollectProjects (solution, searchTypes);
139
compilations = projects.Select (TypeSystemService.GetCompilation).ToList ();
141
compilations = new [] { member.Compilation };
144
var result = new List<IMember> ();
145
var mainAssemblies = new HashSet<string> (compilations.Select (c => c.MainAssembly.AssemblyName));
146
var searchedAssemblies = new HashSet<string> ();
147
var searchedTypes = new HashSet<string> ();
149
foreach (var compilation in compilations) {
150
var baseTypeImports = Import(compilation, searchTypes).Where (t => t != null).ToList ();
151
if (!baseTypeImports.Any ()) continue;
153
foreach (var assembly in compilation.Assemblies) {
154
// search main assemblies in their projects' own compilation, to avoid possible resolving problems
155
if ((mainAssemblies.Contains(assembly.AssemblyName) && assembly != compilation.MainAssembly) ||
156
!searchedAssemblies.Add (assembly.AssemblyName))
159
foreach (var type in assembly.GetAllTypeDefinitions ()) {
160
// members in base types will also be added
161
// because IsDerivedFrom return true for a type itself
162
if (!searchedTypes.Add (type.ReflectionName) || !baseTypeImports.Any (baseType => type.IsDerivedFrom (baseType)))
164
result.AddRange (GetMembers (type, member.Name, true, memberFilter));
5
// Mansheng Yang <lightyang0@gmail.com>
7
// Copyright (c) 2012 Mansheng Yang
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
using System.Collections.Generic;
29
using MonoDevelop.Projects;
30
using MonoDevelop.Ide.TypeSystem;
31
using ICSharpCode.NRefactory.TypeSystem;
33
namespace MonoDevelop.Ide.FindInFiles
35
public static class MemberCollector
38
static bool MatchParameters (IMember a, IMember b)
40
return MatchParameters (a as IParameterizedMember, b as IParameterizedMember);
43
static bool MatchParameters (IParameterizedMember a, IParameterizedMember b)
45
if (a == null && b == null) return true;
46
if (a == null || b == null) return false;
47
return ParameterListComparer.Instance.Equals (a.Parameters, b.Parameters);
51
/// find all base types(types that are not derived from other types) in the specified types
53
/// <param name="types"></param>
54
/// <returns></returns>
55
public static IEnumerable<ITypeDefinition> GetBaseTypes (IEnumerable<ITypeDefinition> types)
59
types = types.ToList ();
63
var baseType = types.FirstOrDefault ();
64
var otherTypes = new List<ITypeDefinition> ();
66
foreach (var type in types.Skip (1)) {
67
if (baseType.IsDerivedFrom (type)) {
69
} else if (!type.IsDerivedFrom (baseType)) {
70
// this type is not directly related to baseType
71
otherTypes.Add (type);
74
yield return baseType;
75
foreach (var type in GetBaseTypes (otherTypes))
79
static IEnumerable<IMember> GetMembers (ITypeDefinition type, IMember member, bool ignoreInherited,
80
Func<IMember, bool> filter)
82
var options = ignoreInherited ? GetMemberOptions.IgnoreInheritedMembers : GetMemberOptions.None;
83
var members = type.GetMembers (m => m.Name == member.Name, options);
85
/* // Filter out shadowed members.
86
// class A { public string Foo { get; set; } } class B : A { public string Foo { get; set; } }
87
if (member.EntityType == EntityType.Property || !(member is IParameterizedMember)) {
88
members = members.Where (m => m == member || m.DeclaringType.Kind == TypeKind.Interface);
92
members = members.Where (filter);
96
static IEnumerable<ITypeDefinition> Import (ICompilation compilation, IEnumerable<ITypeDefinition> types)
98
return types.Select (t => compilation.Import (t));
102
/// collect members with the same signature/name(if overloads are included) as the specified member
103
/// in the inheritance tree
105
public static IEnumerable<IMember> CollectMembers (Solution solution, IMember member, ReferenceFinder.RefactoryScope scope,
106
bool includeOverloads = true, bool matchDeclaringType = false)
108
if (solution == null || member.EntityType == EntityType.Destructor || member.EntityType == EntityType.Operator)
109
return new [] { member };
111
if (member.EntityType == EntityType.Constructor) {
112
if (includeOverloads)
113
return member.DeclaringType.GetMembers (m => m.EntityType == EntityType.Constructor, GetMemberOptions.IgnoreInheritedMembers);
114
return new [] { member };
117
Func<IMember, bool> memberFilter = null;
118
if (member is IParameterizedMember && !includeOverloads)
119
memberFilter = m => MatchParameters (m, member);
121
var declaringType = member.DeclaringTypeDefinition;
122
if (declaringType == null)
123
return new [] { member };
124
// only collect members in declaringType
125
if (matchDeclaringType)
126
return GetMembers (declaringType, member, true, memberFilter);
128
if (declaringType.Kind != TypeKind.Class && declaringType.Kind != TypeKind.Interface)
129
return GetMembers (declaringType, member, false, memberFilter);
131
var searchTypes = new List<ITypeDefinition> ();
132
var interfaces = from t in declaringType.GetAllBaseTypeDefinitions ()
133
where t.Kind == TypeKind.Interface && GetMembers (t, member, true, memberFilter).Any ()
135
searchTypes.AddRange (GetBaseTypes (interfaces));
137
if (member.DeclaringType.Kind == TypeKind.Class) {
138
var members = GetMembers (declaringType, member, false, memberFilter).ToList ();
139
if (members.Any (m => m.IsOverridable))
140
searchTypes.AddRange (GetBaseTypes (members.Select (m => m.DeclaringTypeDefinition)));
141
else if (searchTypes.Count == 0)
145
IList<ICompilation> compilations;
146
if (scope == ReferenceFinder.RefactoryScope.Solution || scope == ReferenceFinder.RefactoryScope.Unknown) {
147
var projects = SearchCollector.CollectProjects (solution, searchTypes);
148
compilations = projects.Select (TypeSystemService.GetCompilation).ToList ();
150
compilations = new [] { member.Compilation };
153
var result = new List<IMember> ();
154
var mainAssemblies = new HashSet<string> (compilations.Select (c => c.MainAssembly.AssemblyName));
155
var searchedAssemblies = new HashSet<string> ();
156
var searchedTypes = new HashSet<string> ();
158
foreach (var compilation in compilations) {
159
var baseTypeImports = Import(compilation, searchTypes).Where (t => t != null).ToList ();
160
if (!baseTypeImports.Any ()) continue;
162
foreach (var assembly in compilation.Assemblies) {
163
// search main assemblies in their projects' own compilation, to avoid possible resolving problems
164
if ((mainAssemblies.Contains(assembly.AssemblyName) && assembly != compilation.MainAssembly) ||
165
!searchedAssemblies.Add (assembly.AssemblyName))
168
foreach (var type in assembly.GetAllTypeDefinitions ()) {
169
// members in base types will also be added
170
// because IsDerivedFrom return true for a type itself
171
if (!searchedTypes.Add (type.ReflectionName) || !baseTypeImports.Any (type.IsDerivedFrom))
173
result.AddRange (GetMembers (type, member, true, memberFilter));