/// <summary> /// Adds all candidates from the method lists. /// /// This method implements the logic that causes applicable methods in derived types to hide /// all methods in base types. /// </summary> /// <param name="methodLists">The methods, grouped by declaring type. Base types must come first in the list.</param> public void AddMethodLists(IList <MethodListWithDeclaringType> methodLists) { if (methodLists == null) { throw new ArgumentNullException("methodLists"); } // Base types come first, so go through the list backwards (derived types first) bool[] isHiddenByDerivedType; if (methodLists.Count > 1) { isHiddenByDerivedType = new bool[methodLists.Count]; } else { isHiddenByDerivedType = null; } for (int i = methodLists.Count - 1; i >= 0; i--) { if (isHiddenByDerivedType != null && isHiddenByDerivedType[i]) { continue; } MethodListWithDeclaringType methodList = methodLists[i]; bool foundApplicableCandidateInCurrentList = false; for (int j = 0; j < methodList.Count; j++) { IParameterizedMember method = methodList[j]; OverloadResolutionErrors errors = AddCandidate(method); foundApplicableCandidateInCurrentList |= IsApplicable(errors); } if (foundApplicableCandidateInCurrentList && i > 0) { foreach (IType baseType in methodList.DeclaringType.GetAllBaseTypes()) { for (int j = 0; j < i; j++) { if (!isHiddenByDerivedType[j] && baseType.Equals(methodLists[j].DeclaringType)) { isHiddenByDerivedType[j] = true; } } } } } }
/// <summary> /// Looks up the indexers on the target type. /// </summary> public IList <MethodListWithDeclaringType> LookupIndexers(Expression targetExpression) { if (targetExpression == null) { throw new ArgumentNullException("targetExpression"); } IType targetType = targetExpression.Type; bool allowProtectedAccess = IsProtectedAccessAllowed(targetExpression); Predicate <IUnresolvedProperty> filter = p => p.IsIndexer; List <LookupGroup> lookupGroups = new List <LookupGroup>(); foreach (IType type in targetType.GetNonInterfaceBaseTypes()) { List <IParameterizedMember> newMethods = null; IMember newNonMethod = null; IEnumerable <IType> typeBaseTypes = null; var members = type.GetProperties(filter, GetMemberOptions.IgnoreInheritedMembers); AddMembers(type, members, allowProtectedAccess, lookupGroups, true, ref typeBaseTypes, ref newMethods, ref newNonMethod); if (newMethods != null || newNonMethod != null) { lookupGroups.Add(new LookupGroup(type, null, newMethods, newNonMethod)); } } // Remove interface members hidden by class members. if (targetType.Kind == TypeKind.TypeParameter) { // This can happen only with type parameters. RemoveInterfaceMembersHiddenByClassMembers(lookupGroups); } // Remove all hidden groups lookupGroups.RemoveAll(g => g.MethodsAreHidden || g.Methods.Count == 0); 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); }
Expression CreateResult(Expression targetExpression, List <LookupGroup> lookupGroups, string name, IList <IType> typeArguments) { // Remove all hidden groups lookupGroups.RemoveAll(g => g.AllHidden); if (lookupGroups.Count == 0) { // No members found return(new UnknownMemberExpression(targetExpression.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 V# 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 MethodGroupExpression(targetExpression, 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]); // TODO:ERROR AMBIGIOUS return(null); } else { return(new TypeExpression(resultGroup.NestedTypes[0])); } } if (resultGroup.NonMethod.IsStatic && targetExpression is SelfReference) { targetExpression = new TypeExpression(targetExpression.Type); } if (lookupGroups.Count > 1) { throw new ArgumentException(string.Format("Ambigious member {1} found on target {0}", targetExpression.GetSignatureForError(), resultGroup.NonMethod)); } else { if (isInEnumMemberInitializer) { IField field = resultGroup.NonMethod as IField; if (field != null && field.DeclaringTypeDefinition != null && field.DeclaringTypeDefinition.Kind == TypeKind.Enum) { return(new MemberExpressionStatement( targetExpression, field, field.DeclaringTypeDefinition.EnumUnderlyingType, field.IsConst, field.ConstantValue)); } } return(new MemberExpressionStatement(targetExpression, resultGroup.NonMethod)); } }