@ -19,6 +19,7 @@
@@ -19,6 +19,7 @@
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Linq ;
using ICSharpCode.NRefactory.TypeSystem ;
@ -43,7 +44,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -43,7 +44,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
IType returnType = member . ReturnType . Resolve ( context ) ;
if ( returnType = = SharedTypes . Dynamic )
return true ;
return returnType . IsDelegate ( ) ;
return returnType . Kind = = TypeKind . Delegate ;
}
#endregion
@ -122,166 +123,419 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
@@ -122,166 +123,419 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
#endregion
#region class LookupGroup
sealed class LookupGroup
{
public readonly IType DeclaringType ;
// When a nested type is hidden, it is simply removed from the list.
public List < IType > NestedTypes ;
// When members are hidden, they are merely marked as hidden.
// We still need to store the hidden methods so that the 'override' processing can
// find them, so that it won't introduce the override as a new method.
public readonly List < IParameterizedMember > Methods ;
public bool MethodsAreHidden ;
public IMember NonMethod ;
public bool NonMethodIsHidden ;
public LookupGroup ( IType declaringType , List < IType > nestedTypes , List < IParameterizedMember > methods , IMember nonMethod )
{
this . DeclaringType = declaringType ;
this . NestedTypes = nestedTypes ;
this . Methods = methods ;
this . NonMethod = nonMethod ;
this . MethodsAreHidden = ( methods = = null | | methods . Count = = 0 ) ;
this . NonMethodIsHidden = ( nonMethod = = null ) ;
}
public bool AllHidden {
get {
if ( NestedTypes ! = null & & NestedTypes . Count > 0 )
return false ;
return NonMethodIsHidden & & MethodsAreHidden ;
}
}
}
#endregion
#region LookupType
public ResolveResult LookupType ( IType declaringType , string name , IList < IType > typeArguments , bool parameterizeResultType = true )
{
int typeArgumentCount = typeArguments . Count ;
Predicate < ITypeDefinition > typeFilter = delegate ( ITypeDefinition d ) {
// inner types contain the type parameters of outer types. therefore this count has to been adjusted.
int correctedCount = d . TypeParameterCount - ( d . DeclaringType ! = null ? d . DeclaringType . TypeParameterCount : 0 ) ;
return correctedCount = = typeArgumentCount & & d . Name = = name & & IsAccessible ( d , true ) ;
Predicate < ITypeDefinition > filter = delegate ( ITypeDefinition d ) {
return InnerTypeParameterCount ( d ) = = typeArgumentCount & & d . Name = = name & & IsAccessible ( d , true ) ;
} ;
List < IType > types ;
if ( parameterizeResultType )
types = declaringType . GetNestedTypes ( typeArguments , context , typeFilter ) . ToList ( ) ;
else
types = declaringType . GetNestedTypes ( context , typeFilter ) . ToList ( ) ;
RemoveTypesHiddenByOtherTypes ( types ) ;
if ( types . Count = = 1 )
return new TypeResolveResult ( types [ 0 ] ) ;
else if ( types . Count > 1 )
return new AmbiguousTypeResolveResult ( types [ 0 ] ) ;
else
List < LookupGroup > lookupGroups = new List < LookupGroup > ( ) ;
if ( declaringType . Kind ! = TypeKind . TypeParameter ) {
foreach ( IType type in declaringType . GetNonInterfaceBaseTypes ( context ) ) {
List < IType > newNestedTypes = null ;
IEnumerable < IType > typeBaseTypes = null ;
IEnumerable < IType > nestedTypes ;
if ( parameterizeResultType ) {
nestedTypes = type . GetNestedTypes ( typeArguments , context , filter , GetMemberOptions . IgnoreInheritedMembers ) ;
} else {
nestedTypes = type . GetNestedTypes ( context , filter , GetMemberOptions . IgnoreInheritedMembers | GetMemberOptions . ReturnMemberDefinitions ) ;
}
AddNestedTypes ( type , nestedTypes , typeArgumentCount , lookupGroups , ref typeBaseTypes , ref newNestedTypes ) ;
if ( newNestedTypes ! = null )
lookupGroups . Add ( new LookupGroup ( type , newNestedTypes , null , null ) ) ;
}
}
lookupGroups . RemoveAll ( g = > g . AllHidden ) ;
Debug . Assert ( lookupGroups . All ( g = > g . NestedTypes ! = null & & g . NestedTypes . Count > 0 ) ) ;
if ( lookupGroups . Count = = 0 ) {
return new UnknownMemberResolveResult ( declaringType , name , typeArguments ) ;
}
LookupGroup resultGroup = lookupGroups [ lookupGroups . Count - 1 ] ;
if ( resultGroup . NestedTypes . Count > 1 | | lookupGroups . Count > 1 )
return new AmbiguousTypeResolveResult ( resultGroup . NestedTypes [ 0 ] ) ;
else
return new TypeResolveResult ( resultGroup . NestedTypes [ 0 ] ) ;
}
void RemoveTypesHiddenByOtherTypes ( List < IType > types )
static int InnerTypeParameterCount ( IType type )
{
for ( int i = types . Count - 1 ; i > = 0 ; i - - ) {
ITypeDefinition d = GetDeclaringTypeDef ( types [ i ] ) ;
if ( d = = null )
continue ;
// nested loop depends on the fact that the members of more derived classes appear later in the list
for ( int j = i + 1 ; j < types . Count ; j + + ) {
if ( types [ i ] . TypeParameterCount ! = types [ j ] . TypeParameterCount )
continue ;
ITypeDefinition s = GetDeclaringTypeDef ( types [ j ] ) ;
if ( s ! = null & & s ! = d & & s . IsDerivedFrom ( d , context ) ) {
// types[j] hides types[i]
types . RemoveAt ( i ) ;
break ;
}
}
}
// inner types contain the type parameters of outer types. therefore this count has to been adjusted.
return type . TypeParameterCount - ( type . DeclaringType ! = null ? type . DeclaringType . TypeParameterCount : 0 ) ;
}
#endregion
#region Lookup
/// <summary>
/// Performs a member lookup.
/// </summary>
public ResolveResult Lookup ( ResolveResult targetResolveResult , string name , IList < IType > typeArguments , bool isInvocation )
{
IType type = targetResolveResult . Type ;
int typeArgumentCount = typeArguments . Count ;
bool targetIsTypeParameter = targetResolveResult . Type . Kind = = TypeKind . TypeParameter ;
List < IType > types = new List < IType > ( ) ;
List < IMember > members = new List < IMember > ( ) ;
if ( ! isInvocation ) {
// Consider nested types only if it's not an invocation.
// type.GetNestedTypes() is checking the type parameter count for an exact match.
Predicate < ITypeDefinition > typeFilter = delegate ( ITypeDefinition d ) {
return d . Name = = name & & IsAccessible ( d , true ) ;
} ;
types . AddRange ( type . GetNestedTypes ( typeArguments , context , typeFilter ) ) ;
bool allowProtectedAccess = IsProtectedAccessAllowed ( targetResolveResult . Type ) ;
Predicate < IEntity > filter = delegate ( IEntity entity ) {
return entity . Name = = name & & IsAccessible ( entity , allowProtectedAccess ) ;
} ;
List < LookupGroup > lookupGroups = new List < LookupGroup > ( ) ;
// 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 ( context ) ) {
List < IType > newNestedTypes = null ;
List < IParameterizedMember > newMethods = null ;
IMember newNonMethod = null ;
IEnumerable < IType > typeBaseTypes = null ;
if ( ! isInvocation & & ! targetIsTypeParameter ) {
// Consider nested types only if it's not an invocation.
// type.GetNestedTypes() is checking the type parameter count for an exact match,
// so we don't need to do that in our filter.
var nestedTypes = type . GetNestedTypes ( typeArguments , context , filter , GetMemberOptions . IgnoreInheritedMembers ) ;
AddNestedTypes ( type , nestedTypes , typeArguments . Count , lookupGroups , ref typeBaseTypes , ref newNestedTypes ) ;
}
IEnumerable < IMember > members ;
if ( typeArguments . Count = = 0 ) {
// Note: IsInvocable-checking cannot be done as part of the filter;
// because it must be done after type substitution.
members = type . GetMembers ( context , filter , GetMemberOptions . IgnoreInheritedMembers ) ;
if ( isInvocation )
members = members . Where ( m = > IsInvocable ( m , context ) ) ;
} else {
// No need to check for isInvocation/isInvocable here:
// we only fetch methods
members = type . GetMethods ( typeArguments , context , filter , GetMemberOptions . IgnoreInheritedMembers ) ;
}
AddMembers ( type , members , lookupGroups , false , ref typeBaseTypes , ref newMethods , ref newNonMethod ) ;
if ( newNestedTypes ! = null | | newMethods ! = null | | newNonMethod ! = null )
lookupGroups . Add ( new LookupGroup ( type , newNestedTypes , newMethods , newNonMethod ) ) ;
}
bool allowProtectedAccess = IsProtectedAccessAllowed ( type ) ;
// Remove interface members hidden by class members.
if ( targetIsTypeParameter ) {
// This can happen only with type parameters.
RemoveInterfaceMembersHiddenByClassMembers ( lookupGroups ) ;
}
Predicate < IMember > memberFilter = delegate ( IMember member ) {
return ! member . IsOverride & & member . Name = = name & & IsAccessible ( member , allowProtectedAccess ) ;
return CreateResult ( targetResolveResult , lookupGroups , name , typeArguments ) ;
}
#endregion
#region Lookup Indexer
/// <summary>
/// Looks up the indexers on the target type.
/// </summary>
public IList < MethodListWithDeclaringType > LookupIndexers ( IType targetType )
{
bool allowProtectedAccess = IsProtectedAccessAllowed ( targetType ) ;
Predicate < IProperty > filter = delegate ( IProperty property ) {
return property . IsIndexer & & IsAccessible ( property , allowProtectedAccess ) ;
} ;
if ( typeArgumentCount = = 0 ) {
members . AddRange ( type . GetMembers ( context , memberFilter ) ) ;
// Note: IsInvocable-checking cannot be done as part of the memberFilter;
// because it must be done after type substitution.
if ( isInvocation )
members . RemoveAll ( m = > ! IsInvocable ( m , context ) ) ;
} else {
// No need to check for isInvocation/isInvocable here:
// we filter out all non-methods
members . AddRange ( type . GetMethods ( typeArguments , context , memberFilter ) ) ;
}
// TODO: can't members also hide types?
List < LookupGroup > lookupGroups = new List < LookupGroup > ( ) ;
foreach ( IType type in targetType . GetNonInterfaceBaseTypes ( context ) ) {
List < IParameterizedMember > newMethods = null ;
IMember newNonMethod = null ;
IEnumerable < IType > typeBaseTypes = null ;
var members = type . GetProperties ( context , filter , GetMemberOptions . IgnoreInheritedMembers ) ;
AddMembers ( type , members , lookupGroups , true , ref typeBaseTypes , ref newMethods , ref newNonMethod ) ;
if ( newMethods ! = null | | newNonMethod ! = null )
lookupGroups . Add ( new LookupGroup ( type , null , newMethods , newNonMethod ) ) ;
}
RemoveTypesHiddenByOtherTypes ( types ) ;
// remove members hidden by types
for ( int i = 0 ; i < types . Count ; i + + ) {
ITypeDefinition d = GetDeclaringTypeDef ( types [ i ] ) ;
if ( d ! = null )
members . RemoveAll ( m = > d . IsDerivedFrom ( m . DeclaringTypeDefinition , context ) ) ;
// Remove interface members hidden by class members.
if ( targetType . Kind = = TypeKind . TypeParameter ) {
// This can happen only with type parameters.
RemoveInterfaceMembersHiddenByClassMembers ( lookupGroups ) ;
}
ParameterListComparer parameterListComparer = new ParameterListComparer ( context ) ;
// Remove all hidden groups
lookupGroups . RemoveAll ( g = > g . MethodsAreHidden | | g . Methods . Count = = 0 ) ;
// remove members hidden by other members
for ( int i = members . Count - 1 ; i > = 0 ; i - - ) {
ITypeDefinition d = members [ i ] . DeclaringTypeDefinition ;
IMethod mi = members [ i ] as IMethod ;
// nested loop depends on the fact that the members of more derived classes appear later in the list
for ( int j = i + 1 ; j < members . Count ; j + + ) {
if ( mi ! = null ) {
IMethod mj = members [ j ] as IMethod ;
if ( mj ! = null & & ! parameterListComparer . Equals ( mi , mj ) )
continue ;
}
ITypeDefinition s = members [ j ] . DeclaringTypeDefinition ;
if ( s ! = null & & s ! = d & & s . IsDerivedFrom ( d , context ) ) {
// members[j] hides members[i]
members . RemoveAt ( i ) ;
break ;
MethodListWithDeclaringType [ ] methodLists = new MethodListWithDeclaringType [ lookupGroups . Count ] ;
for ( int i = 0 ; i < methodLists . Length ; i + + ) {
methodLists [ i ] = new MethodListWithDeclaringType ( lookupGroups [ i ] . DeclaringType , lookupGroups [ i ] . Methods ) ;
}
return methodLists ;
}
#endregion
#region AddNestedTypes
/// <summary>
/// Adds the nested types to 'newNestedTypes' and removes any hidden members from the existing lookup groups.
/// </summary>
/// <param name="type">Declaring type of the nested types</param>
/// <param name="nestedTypes">List of nested types to add.</param>
/// <param name="typeArgumentCount">The number of type arguments - used for hiding types from the base class</param>
/// <param name="lookupGroups">List of existing lookup groups</param>
/// <param name="typeBaseTypes">The base types of 'type' (initialized on demand)</param>
/// <param name="newNestedTypes">The target list (created on demand).</param>
void AddNestedTypes ( IType type , IEnumerable < IType > nestedTypes , int typeArgumentCount ,
List < LookupGroup > lookupGroups ,
ref IEnumerable < IType > typeBaseTypes ,
ref List < IType > newNestedTypes )
{
foreach ( IType nestedType in nestedTypes ) {
// Remove all non-types declared in a base type of 'type',
// and all types with same number of type parameters declared in a base type of 'type'.
foreach ( var lookupGroup in lookupGroups ) {
if ( lookupGroup . AllHidden )
continue ; // everything is already hidden
if ( typeBaseTypes = = null )
typeBaseTypes = type . GetNonInterfaceBaseTypes ( context ) ;
if ( typeBaseTypes . Contains ( lookupGroup . DeclaringType ) ) {
lookupGroup . MethodsAreHidden = true ;
lookupGroup . NonMethodIsHidden = true ;
if ( lookupGroup . NestedTypes ! = null )
lookupGroup . NestedTypes . RemoveAll ( t = > InnerTypeParameterCount ( t ) = = typeArgumentCount ) ;
}
}
// Add the new nested type.
if ( newNestedTypes = = null )
newNestedTypes = new List < IType > ( ) ;
newNestedTypes . Add ( nestedType ) ;
}
// remove interface members hidden by class members
if ( type is ITypeParameter ) {
// this can happen only with type parameters
for ( int i = members . Count - 1 ; i > = 0 ; i - - ) {
if ( members [ i ] . DeclaringTypeDefinition . Kind ! = TypeKind . Interface )
continue ;
IMethod mi = members [ i ] as IMethod ;
for ( int j = 0 ; j < members . Count ; j + + ) {
if ( mi ! = null ) {
IMethod mj = members [ j ] as IMethod ;
if ( mj ! = null & & ! parameterListComparer . Equals ( mi , mj ) )
continue ;
}
#endregion
#region AddMembers
/// <summary>
/// Adds members to 'newMethods'/'newNonMethod'.
/// Removes any members in the existing lookup groups that were hidden by added members.
/// Substitutes 'virtual' members in the existing lookup groups for added 'override' members.
/// </summary>
/// <param name="type">Declaring type of the members</param>
/// <param name="members">List of members to add.</param>
/// <param name="lookupGroups">List of existing lookup groups</param>
/// <param name="treatAllParameterizedMembersAsMethods">Whether to treat properties as methods</param>
/// <param name="typeBaseTypes">The base types of 'type' (initialized on demand)</param>
/// <param name="newMethods">The target list for methods (created on demand).</param>
/// <param name="newNonMethod">The target variable for non-method members.</param>
void AddMembers ( IType type , IEnumerable < IMember > members , List < LookupGroup > lookupGroups ,
bool treatAllParameterizedMembersAsMethods ,
ref IEnumerable < IType > typeBaseTypes , ref List < IParameterizedMember > newMethods , ref IMember newNonMethod )
{
foreach ( IMember member in members ) {
IParameterizedMember method ;
if ( treatAllParameterizedMembersAsMethods )
method = member as IParameterizedMember ;
else
method = member as IMethod ;
bool replacedVirtualMemberWithOverride = false ;
if ( member . IsOverride ) {
// Replacing virtual member with override:
// Go backwards so that we find the corresponding virtual member
// in the most-derived type
for ( int i = lookupGroups . Count - 1 ; i > = 0 & & ! replacedVirtualMemberWithOverride ; i - - ) {
if ( typeBaseTypes = = null )
typeBaseTypes = type . GetNonInterfaceBaseTypes ( context ) ;
var lookupGroup = lookupGroups [ i ] ;
if ( typeBaseTypes . Contains ( lookupGroup . DeclaringType ) ) {
if ( method ! = null ) {
// Find the matching method, and replace it with the override
for ( int j = 0 ; j < lookupGroup . Methods . Count ; j + + ) {
if ( ParameterListComparer . Compare ( context , method , lookupGroup . Methods [ j ] ) ) {
lookupGroup . Methods [ j ] = method ;
replacedVirtualMemberWithOverride = true ;
break ;
}
}
} else {
// If the member type matches, replace it with the override
if ( lookupGroup . NonMethod ! = null & & lookupGroup . NonMethod . EntityType = = member . EntityType ) {
lookupGroup . NonMethod = member ;
replacedVirtualMemberWithOverride = true ;
break ;
}
}
}
ITypeDefinition s = members [ j ] . DeclaringTypeDefinition ;
if ( s ! = null & & IsNonInterfaceType ( s ) ) {
// members[j] hides members[i]
members . RemoveAt ( i ) ;
break ;
}
}
// If the member wasn't an override, or if we didn't find any matching virtual method,
// proceed to add the member.
if ( ! replacedVirtualMemberWithOverride ) {
// Make the member hide other members:
foreach ( var lookupGroup in lookupGroups ) {
if ( lookupGroup . AllHidden )
continue ; // everything is already hidden
if ( typeBaseTypes = = null )
typeBaseTypes = type . GetNonInterfaceBaseTypes ( context ) ;
if ( typeBaseTypes . Contains ( lookupGroup . DeclaringType ) ) {
// Methods hide all non-methods; Non-methods hide everything
lookupGroup . NestedTypes = null ;
lookupGroup . NonMethodIsHidden = true ;
if ( method = = null ) { // !(member is IMethod)
lookupGroup . MethodsAreHidden = true ;
}
}
}
// Add the new member
if ( method ! = null ) {
if ( newMethods = = null )
newMethods = new List < IParameterizedMember > ( ) ;
newMethods . Add ( method ) ;
} else {
newNonMethod = member ;
}
}
}
if ( types . Count > 0 ) {
bool isAmbiguous = ! ( types . Count = = 1 & & members . Count = = 0 ) ;
if ( isAmbiguous )
return new AmbiguousTypeResolveResult ( types [ 0 ] ) ;
else
return new TypeResolveResult ( types [ 0 ] ) ;
}
#endregion
#region RemoveInterfaceMembersHiddenByClassMembers
void RemoveInterfaceMembersHiddenByClassMembers ( List < LookupGroup > lookupGroups )
{
foreach ( var classLookupGroup in lookupGroups ) {
if ( IsInterfaceOrSystemObject ( classLookupGroup . DeclaringType ) )
continue ;
// The current lookup groups contains class members that might hide interface members
bool hasNestedTypes = classLookupGroup . NestedTypes ! = null & & classLookupGroup . NestedTypes . Count > 0 ;
if ( hasNestedTypes | | ! classLookupGroup . NonMethodIsHidden ) {
// Hide all members from interface types
foreach ( var interfaceLookupGroup in lookupGroups ) {
if ( IsInterfaceOrSystemObject ( interfaceLookupGroup . DeclaringType ) ) {
interfaceLookupGroup . NestedTypes = null ;
interfaceLookupGroup . NonMethodIsHidden = true ;
interfaceLookupGroup . MethodsAreHidden = true ;
}
}
} else if ( ! classLookupGroup . MethodsAreHidden ) {
foreach ( IMethod classMethod in classLookupGroup . Methods ) {
// Hide all non-methods from interface types, and all methods with the same signature
// as a method in this class type.
foreach ( var interfaceLookupGroup in lookupGroups ) {
if ( IsInterfaceOrSystemObject ( interfaceLookupGroup . DeclaringType ) ) {
interfaceLookupGroup . NestedTypes = null ;
interfaceLookupGroup . NonMethodIsHidden = true ;
if ( interfaceLookupGroup . Methods ! = null & & ! interfaceLookupGroup . MethodsAreHidden ) {
// The mapping of virtual to overridden methods is already done,
// so we can simply remove the methods from the collection
interfaceLookupGroup . Methods . RemoveAll (
m = > ParameterListComparer . Compare ( context , classMethod , m ) ) ;
}
}
}
}
}
}
if ( members . Count = = 0 )
return new UnknownMemberResolveResult ( type , name , typeArguments ) ;
IMember firstNonMethod = members . FirstOrDefault ( m = > ! ( m is IMethod ) ) ;
if ( members . Count = = 1 & & firstNonMethod ! = null )
return new MemberResolveResult ( targetResolveResult , firstNonMethod , context ) ;
if ( firstNonMethod = = null )
return new MethodGroupResolveResult ( targetResolveResult , name , members . ConvertAll ( m = > ( IMethod ) m ) , typeArguments ) ;
return new AmbiguousMemberResolveResult ( targetResolveResult , firstNonMethod , firstNonMethod . ReturnType . Resolve ( context ) ) ;
}
static bool IsNonInterfaceType ( ITypeDefinition def )
static bool IsInterfaceOrSystemObject ( IType type )
{
// return type if def is neither an interface nor System.Object
return def . Kind ! = TypeKind . Interface & & ! ( def . Name = = "Object" & & def . Namespace = = "System" & & def . TypeParameterCount = = 0 ) ;
// return if type is an interface or System.Object
return type . Kind = = TypeKind . Interface
| | ( type . Name = = "Object" & & type . Namespace = = "System" & & type . TypeParameterCount = = 0 ) ;
}
#endregion
static ITypeDefinition GetDeclaringTypeDef ( IType type )
#region CreateResult
ResolveResult CreateResult ( ResolveResult targetResolveResult , List < LookupGroup > lookupGroups , string name , IList < IType > typeArguments )
{
IType declType = type . DeclaringType ;
return declType ! = null ? declType . GetDefinition ( ) : null ;
// Remove all hidden groups
lookupGroups . RemoveAll ( g = > g . AllHidden ) ;
if ( lookupGroups . Count = = 0 ) {
// No members found
return new UnknownMemberResolveResult ( targetResolveResult . Type , name , typeArguments ) ;
}
if ( lookupGroups . Any ( g = > ! g . MethodsAreHidden & & g . Methods . Count > 0 ) ) {
// If there are methods, make a MethodGroupResolveResult.
// Note that a conflict between a member and a method (possible with multiple interface inheritance)
// is only a warning, not an error, and the C# compiler will prefer the method group.
List < MethodListWithDeclaringType > methodLists = new List < MethodListWithDeclaringType > ( ) ;
foreach ( var lookupGroup in lookupGroups ) {
if ( ! lookupGroup . MethodsAreHidden & & lookupGroup . Methods . Count > 0 ) {
var methodListWithDeclType = new MethodListWithDeclaringType ( lookupGroup . DeclaringType ) ;
foreach ( var method in lookupGroup . Methods ) {
methodListWithDeclType . Add ( ( IMethod ) method ) ;
}
methodLists . Add ( methodListWithDeclType ) ;
}
}
return new MethodGroupResolveResult ( targetResolveResult , name , methodLists , typeArguments ) ;
}
// If there are ambiguities, report the most-derived result (last group)
LookupGroup resultGroup = lookupGroups [ lookupGroups . Count - 1 ] ;
if ( resultGroup . NestedTypes ! = null & & resultGroup . NestedTypes . Count > 0 ) {
if ( resultGroup . NestedTypes . Count > 1 | | ! resultGroup . NonMethodIsHidden | | lookupGroups . Count > 1 )
return new AmbiguousTypeResolveResult ( resultGroup . NestedTypes [ 0 ] ) ;
else
return new TypeResolveResult ( resultGroup . NestedTypes [ 0 ] ) ;
}
if ( lookupGroups . Count > 1 ) {
return new AmbiguousMemberResolveResult ( targetResolveResult , resultGroup . NonMethod ,
resultGroup . NonMethod . ReturnType . Resolve ( context ) ) ;
} else {
return new MemberResolveResult ( targetResolveResult , resultGroup . NonMethod , context ) ;
}
}
#endregion
}
}