/// <summary> /// Gets whether access to protected instance members of the target expression is possible. /// </summary> public bool IsProtectedAccessAllowed(AST.Expression targetResolveResult) { return(targetResolveResult is SelfReference || IsProtectedAccessAllowed(targetResolveResult.Type)); }
/// <summary> /// Performs a member lookup. /// </summary> public AST.Expression Lookup(AST.Expression targetResolveResult, string name, IList <IType> typeArguments, bool isInvocation) { if (targetResolveResult == null) { throw new ArgumentNullException("targetResolveResult"); } if (name == null) { throw new ArgumentNullException("name"); } if (typeArguments == null) { throw new ArgumentNullException("typeArguments"); } bool targetIsTypeParameter = targetResolveResult.Type.Kind == TypeKind.TypeParameter; bool allowProtectedAccess = IsProtectedAccessAllowed(targetResolveResult); Predicate <ITypeDefinition> nestedTypeFilter = delegate(ITypeDefinition entity) { return(entity.Name == name && IsAccessible(entity, allowProtectedAccess)); }; Predicate <IUnresolvedMember> memberFilter = delegate(IUnresolvedMember entity) { // NOTE: Atm destructors can be looked up with 'Finalize' return(entity.SymbolKind != SymbolKind.Indexer && entity.SymbolKind != SymbolKind.Operator && entity.Name == name); }; 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()) { 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, nestedTypeFilter, 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(memberFilter, GetMemberOptions.IgnoreInheritedMembers); if (isInvocation) { members = members.Where(m => IsInvocable(m)); } } else { // No need to check for isInvocation/isInvocable here: // we only fetch methods members = type.GetMethods(typeArguments, memberFilter, GetMemberOptions.IgnoreInheritedMembers); } AddMembers(type, members, allowProtectedAccess, lookupGroups, false, ref typeBaseTypes, ref newMethods, ref newNonMethod); if (newNestedTypes != null || newMethods != null || newNonMethod != null) { lookupGroups.Add(new LookupGroup(type, newNestedTypes, newMethods, newNonMethod)); } } // Remove interface members hidden by class members. if (targetIsTypeParameter) { // This can happen only with type parameters. RemoveInterfaceMembersHiddenByClassMembers(lookupGroups); } return(CreateResult(targetResolveResult, lookupGroups, name, typeArguments)); }