diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs b/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs
index f652ef4c1e..c490f9b72b 100644
--- a/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs
+++ b/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs
@@ -17,7 +17,6 @@
// DEALINGS IN THE SOFTWARE.
using System;
-using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -141,6 +140,87 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
#endregion
+ #region GetAccessibleMembers
+ ///
+ /// Retrieves all members that are accessible and not hidden (by being overridden or shadowed).
+ /// Returns both members and nested type definitions. Does not include extension methods.
+ ///
+ public IEnumerable GetAccessibleMembers(ResolveResult targetResolveResult)
+ {
+ if (targetResolveResult == null)
+ throw new ArgumentNullException("targetResolveResult");
+
+ bool targetIsTypeParameter = targetResolveResult.Type.Kind == TypeKind.TypeParameter;
+ bool allowProtectedAccess = (targetResolveResult is ThisResolveResult || IsProtectedAccessAllowed(targetResolveResult.Type));
+
+ // maps the member name to the list of lookup groups
+ var lookupGroupDict = new Dictionary>();
+
+ // This loop will handle base types before derived types.
+ // The loop performs three jobs:
+ // 1) It marks entries in lookup groups from base classes as removed when those members
+ // are hidden by a derived class.
+ // 2) It adds a new lookup group with the members from a declaring type.
+ // 3) It replaces virtual members with the overridden version, placing the override in the
+ // lookup group belonging to the base class.
+ foreach (IType type in targetResolveResult.Type.GetNonInterfaceBaseTypes()) {
+
+ List entities = new List();
+ entities.AddRange(type.GetMembers(options: GetMemberOptions.IgnoreInheritedMembers));
+ if (!targetIsTypeParameter)
+ entities.AddRange(type.GetNestedTypes(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions).Select(t => t.GetDefinition()));
+
+ foreach (var entityGroup in entities.GroupBy(e => e.Name)) {
+
+ List lookupGroups = new List();
+ if (!lookupGroupDict.TryGetValue(entityGroup.Key, out lookupGroups))
+ lookupGroupDict.Add(entityGroup.Key, lookupGroups = new List());
+
+ List newNestedTypes = null;
+ List newMethods = null;
+ IMember newNonMethod = null;
+
+ IEnumerable typeBaseTypes = null;
+
+ if (!targetIsTypeParameter) {
+ AddNestedTypes(type, entityGroup.OfType(), 0, lookupGroups, ref typeBaseTypes, ref newNestedTypes);
+ }
+ AddMembers(type, entityGroup.OfType(), allowProtectedAccess, lookupGroups, false, ref typeBaseTypes, ref newMethods, ref newNonMethod);
+
+ if (newNestedTypes != null || newMethods != null || newNonMethod != null)
+ lookupGroups.Add(new LookupGroup(type, newNestedTypes, newMethods, newNonMethod));
+ }
+ }
+
+ foreach (List lookupGroups in lookupGroupDict.Values) {
+ // Remove interface members hidden by class members.
+ if (targetIsTypeParameter) {
+ // This can happen only with type parameters.
+ RemoveInterfaceMembersHiddenByClassMembers(lookupGroups);
+ }
+
+ // Now report the results:
+ foreach (LookupGroup lookupGroup in lookupGroups) {
+ if (!lookupGroup.MethodsAreHidden) {
+ foreach (IMethod method in lookupGroup.Methods) {
+ yield return method;
+ }
+ }
+ if (!lookupGroup.NonMethodIsHidden) {
+ yield return lookupGroup.NonMethod;
+ }
+ if (lookupGroup.NestedTypes != null) {
+ foreach (IType type in lookupGroup.NestedTypes) {
+ ITypeDefinition typeDef = type.GetDefinition();
+ if (typeDef != null)
+ yield return typeDef;
+ }
+ }
+ }
+ }
+ }
+ #endregion
+
#region class LookupGroup
sealed class LookupGroup
{