/// <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); }
IList <Expression> GetArgumentsWithConversions(Expression targetExpression, IParameterizedMember bestCandidateForNamedArguments) { var conversions = this.ArgumentConversions; Expression[] args = new Expression[arguments.Length]; for (int i = 0; i < args.Length; i++) { var argument = arguments[i]; if (this.IsExtensionMethodInvocation && i == 0 && targetExpression != null) { argument = targetExpression; } int parameterIndex = bestCandidate.ArgumentToParameterMap[i]; if (parameterIndex >= 0 && conversions[i] != Conversion.IdentityConversion) { // Wrap argument in ConversionResolveResult IType parameterType = bestCandidate.ParameterTypes[parameterIndex]; if (parameterType.Kind != TypeKind.Unknown) { if (arguments[i].IsCompileTimeConstant && conversions[i].IsValid && !conversions[i].IsUserDefined) { argument = new CastExpression(parameterType, argument).DoResolve(new ResolveContext(compilation).WithCheckForOverflow(CheckForOverflow)); } else { argument = new AST.CastExpression(parameterType, argument, conversions[i], CheckForOverflow); } } } if (bestCandidateForNamedArguments != null && argumentNames[i] != null) { // Wrap argument in NamedArgumentResolveResult if (parameterIndex >= 0) { argument = new NamedArgumentExpression(bestCandidateForNamedArguments.Parameters[parameterIndex], argument, bestCandidateForNamedArguments); } else { argument = new NamedArgumentExpression(argumentNames[i], argument); } } args[i] = argument; } return(args); }
/// <summary> /// Creates a ResolveResult representing the result of overload resolution. /// </summary> /// <param name="targetExpression"> /// The target expression of the call. May be <c>null</c> for static methods/constructors. /// </param> /// <param name="initializerStatements"> /// Statements for Objects/Collections initializer. /// <see cref="InvocationExpression.InitializerStatements"/> /// <param name="returnTypeOverride"> /// If not null, use this instead of the ReturnType of the member as the type of the created resolve result. /// </param> public Invocation CreateInvocation(Expression targetExpression, IList <Expression> initializerStatements = null, IType returnTypeOverride = null) { IParameterizedMember member = GetBestCandidateWithSubstitutedTypeArguments(); if (member == null) { throw new InvalidOperationException(); } return(new Invocation(targetExpression, member, GetArgumentsWithConversions(targetExpression, member), this.BestCandidateErrors, this.IsExtensionMethodInvocation, this.BestCandidateIsExpandedForm, isDelegateInvocation: false, argumentToParameterMap: this.GetArgumentToParameterMap(), initializerStatements: initializerStatements, returnTypeOverride: returnTypeOverride)); }
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)); } }
/// <summary> /// 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. /// </summary> public IEnumerable <IEntity> GetAccessibleMembers(Expression targetExpression) { if (targetExpression == null) { throw new ArgumentNullException("targetExpression"); } bool targetIsTypeParameter = targetExpression.Type.Kind == TypeKind.TypeParameter; bool allowProtectedAccess = IsProtectedAccessAllowed(targetExpression); // maps the member name to the list of lookup groups var lookupGroupDict = new Dictionary <string, 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 targetExpression.Type.GetNonInterfaceBaseTypes()) { List <IEntity> entities = new List <IEntity>(); entities.AddRange(type.GetMembers(options: GetMemberOptions.IgnoreInheritedMembers)); if (!targetIsTypeParameter) { var nestedTypes = type.GetNestedTypes(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions); // GetDefinition() might return null if some IType has a strange implementation of GetNestedTypes. entities.AddRange(nestedTypes.Select(t => t.GetDefinition()).Where(td => td != null)); } foreach (var entityGroup in entities.GroupBy(e => e.Name)) { List <LookupGroup> lookupGroups = new List <LookupGroup>(); if (!lookupGroupDict.TryGetValue(entityGroup.Key, out lookupGroups)) { lookupGroupDict.Add(entityGroup.Key, lookupGroups = new List <LookupGroup>()); } List <IType> newNestedTypes = null; List <IParameterizedMember> newMethods = null; IMember newNonMethod = null; IEnumerable <IType> typeBaseTypes = null; if (!targetIsTypeParameter) { AddNestedTypes(type, entityGroup.OfType <IType>(), 0, lookupGroups, ref typeBaseTypes, ref newNestedTypes); } AddMembers(type, entityGroup.OfType <IMember>(), 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 <LookupGroup> 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); } } } } } }