Example #1
0
        internal static void AppendTypeMembers(
            this Type type,
            ArrayBuilder <MemberAndDeclarationInfo> includedMembers,
            Predicate <MemberInfo> predicate,
            Type declaredType,
            DkmClrAppDomain appDomain,
            bool includeInherited,
            bool hideNonPublic)
        {
            Debug.Assert(!type.IsInterface);

            var memberLocation         = DeclarationInfo.FromSubTypeOfDeclaredType;
            var previousDeclarationMap = includeInherited ? new Dictionary <string, DeclarationInfo>() : null;

            int inheritanceLevel = 0;

            while (!type.IsObject())
            {
                if (type.Equals(declaredType))
                {
                    Debug.Assert(memberLocation == DeclarationInfo.FromSubTypeOfDeclaredType);
                    memberLocation = DeclarationInfo.FromDeclaredTypeOrBase;
                }

                // Get the state from DebuggerBrowsableAttributes for the members of the current type.
                var browsableState = DkmClrType.Create(appDomain, type).GetDebuggerBrowsableAttributeState();

                // Hide non-public members if hideNonPublic is specified (intended to reflect the
                // DkmInspectionContext's DkmEvaluationFlags), and the type is from an assembly
                // with no symbols.
                var hideNonPublicBehavior = DeclarationInfo.None;
                if (hideNonPublic)
                {
                    var moduleInstance = appDomain.FindClrModuleInstance(type.Module.ModuleVersionId);
                    if (moduleInstance == null || moduleInstance.Module == null)
                    {
                        // Synthetic module or no symbols loaded.
                        hideNonPublicBehavior = DeclarationInfo.HideNonPublic;
                    }
                }

                foreach (var member in type.GetMembers(MemberBindingFlags))
                {
                    if (!predicate(member))
                    {
                        continue;
                    }

                    var memberName = member.Name;
                    // This represents information about the immediately preceding (more derived)
                    // declaration with the same name as the current member.
                    var previousDeclaration   = DeclarationInfo.None;
                    var memberNameAlreadySeen = false;
                    if (includeInherited)
                    {
                        memberNameAlreadySeen = previousDeclarationMap.TryGetValue(memberName, out previousDeclaration);
                        if (memberNameAlreadySeen)
                        {
                            // There was a name conflict, so we'll need to include the declaring
                            // type of the member to disambiguate.
                            previousDeclaration |= DeclarationInfo.IncludeTypeInMemberName;
                        }

                        // Update previous member with name hiding (casting) and declared location information for next time.
                        previousDeclarationMap[memberName] =
                            (previousDeclaration & ~(DeclarationInfo.RequiresExplicitCast |
                                                     DeclarationInfo.FromSubTypeOfDeclaredType)) |
                            member.AccessingBaseMemberWithSameNameRequiresExplicitCast() |
                            memberLocation;
                    }

                    Debug.Assert(memberNameAlreadySeen != (previousDeclaration == DeclarationInfo.None));

                    // Decide whether to include this member in the list of members to display.
                    if (!memberNameAlreadySeen || previousDeclaration.IsSet(DeclarationInfo.RequiresExplicitCast))
                    {
                        DkmClrDebuggerBrowsableAttributeState?browsableStateValue = null;
                        if (browsableState != null)
                        {
                            DkmClrDebuggerBrowsableAttributeState value;
                            if (browsableState.TryGetValue(memberName, out value))
                            {
                                browsableStateValue = value;
                            }
                        }

                        if (memberLocation.IsSet(DeclarationInfo.FromSubTypeOfDeclaredType))
                        {
                            // If the current type is a sub-type of the declared type, then
                            // we always need to insert a cast to access the member
                            previousDeclaration |= DeclarationInfo.RequiresExplicitCast;
                        }
                        else if (previousDeclaration.IsSet(DeclarationInfo.FromSubTypeOfDeclaredType))
                        {
                            // If the immediately preceding member (less derived) was
                            // declared on a sub-type of the declared type, then we'll
                            // ignore the casting bit.  Accessing a member through the
                            // declared type is the same as casting to that type, so
                            // the cast would be redundant.
                            previousDeclaration &= ~DeclarationInfo.RequiresExplicitCast;
                        }

                        previousDeclaration |= hideNonPublicBehavior;

                        includedMembers.Add(new MemberAndDeclarationInfo(member, browsableStateValue, previousDeclaration, inheritanceLevel));
                    }
                }

                if (!includeInherited)
                {
                    break;
                }

                type = type.BaseType;
                inheritanceLevel++;
            }

            includedMembers.Sort(MemberAndDeclarationInfo.Comparer);
        }