/// <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(IReadOnlyList <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]) { Log.WriteLine(" Skipping methods in {0} because they are hidden by an applicable method in a derived type", methodLists[i].DeclaringType); continue; } MethodListWithDeclaringType methodList = methodLists[i]; bool foundApplicableCandidateInCurrentList = false; for (int j = 0; j < methodList.Count; j++) { IParameterizedMember method = methodList[j]; Log.Indent(); OverloadResolutionErrors errors = AddCandidate(method); Log.Unindent(); LogCandidateAddingResult(" Candidate", method, errors); 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 IReadOnlyList <MethodListWithDeclaringType> LookupIndexers(ResolveResult targetResolveResult) { if (targetResolveResult == null) { throw new ArgumentNullException("targetResolveResult"); } IType targetType = targetResolveResult.Type; bool allowProtectedAccess = IsProtectedAccessAllowed(targetResolveResult); Predicate <IProperty> filter = p => p.IsIndexer && !p.IsExplicitInterfaceImplementation; 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); }
ResolveResult CreateResult(ResolveResult targetResolveResult, List <LookupGroup> lookupGroups, string name, IReadOnlyList <IType> typeArguments) { // 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 (resultGroup.NonMethod.IsStatic && targetResolveResult is ThisResolveResult) { targetResolveResult = new TypeResolveResult(targetResolveResult.Type); } if (lookupGroups.Count > 1) { return(new AmbiguousMemberResolveResult(targetResolveResult, resultGroup.NonMethod)); } else { if (isInEnumMemberInitializer) { IField field = resultGroup.NonMethod as IField; if (field != null && field.DeclaringTypeDefinition != null && field.DeclaringTypeDefinition.Kind == TypeKind.Enum) { return(new MemberResolveResult( targetResolveResult, field, field.DeclaringTypeDefinition.EnumUnderlyingType, field.IsConst, field.GetConstantValue())); } } return(new MemberResolveResult(targetResolveResult, resultGroup.NonMethod)); } }