/// <summary>
        /// Returns a context value containing StringElements constructed from the TElement types
        /// that get found, plus a SmartPointerElement if the corresponding SmartPointerType is
        /// present, and the Natvis tokens to resolve in expressions involving those.
        /// </summary>
        FormatStringContext BuildFormatStringContext <TElement>(
            IVariableInformation variable, Func <TElement, IStringElement> stringElementConstructor)
            where TElement : class
        {
            VisualizerInfo visualizer = _visualizerScanner.FindType(variable);

            if (visualizer?.Visualizer.Items == null)
            {
                return(new FormatStringContext());
            }

            object[] items = visualizer.Visualizer.Items;
            IEnumerable <IStringElement> stringElements =
                items.OfType <TElement>().Select(e => stringElementConstructor((TElement)e));

            // Fall back to the smart pointee.
            stringElements = stringElements.Concat(
                items.OfType <SmartPointerType>()
                .Take(1)
                .Where(e => !string.IsNullOrWhiteSpace(e.Value))
                .Select(e => new SmartPointerStringElement(e)));

            return(new FormatStringContext {
                StringElements = stringElements,
                NatvisScope = visualizer.NatvisScope
            });
        }
        VisualizerInfo Scan(string varTypeName, TypeName typeNameToFind)
        {
            // Iterate list in reverse order, so that files loaded later take precedence.
            // In particular, CustomVisualizers can be overridden by user files.
            // TODO: Ordering is a bit brittle, consider using another way to make
            // CustomVisualizers overridable, e.g. priority, a custom built-in flag or storing
            // built-in Natvis in a file that can be changed by users.
            _visualizerCache[varTypeName] = null;
            for (int index = _typeVisualizers.Count - 1; index >= 0; --index)
            {
                FileInfo fileInfo = _typeVisualizers[index];

                // TODO: match on View, version, etc
                TypeInfo visualizer =
                    fileInfo.Visualizers.Find(v => v.ParsedName.Match(typeNameToFind));

                if (visualizer != null)
                {
                    _visualizerCache[varTypeName] =
                        new VisualizerInfo(visualizer.Visualizer, typeNameToFind);

                    break;
                }
            }

            return(_visualizerCache[varTypeName]);
        }
Example #3
0
        internal bool MightHaveChildren(IVariableInformation variable)
        {
            VisualizerInfo visualizer = VisualizerScanner.FindType(variable);
            ExpandType     expandType = visualizer?.GetExpandType();

            if (expandType != null)
            {
                if (expandType.Items != null && expandType.Items.Length > 0)
                {
                    return(true);
                }

                return(!expandType.HideRawView && variable.MightHaveChildren());
            }

            SmartPointerType smartPointerType = visualizer?.GetSmartPointerType();

            return(smartPointerType != null || variable.MightHaveChildren());
        }
Example #4
0
        IChildAdapter CreateNatvisChildAdapter(VisualizerInfo visualizer,
                                               IVariableInformation variable)
        {
            ExpandType expandType = visualizer.GetExpandType();

            if (expandType != null)
            {
                return(_natvisCollectionFactory.Create(variable, expandType,
                                                       visualizer.NatvisScope));
            }

            SmartPointerType smartPointerType = visualizer.GetSmartPointerType();

            if (smartPointerType != null)
            {
                return(_smartPointerFactory.Create(
                           variable, smartPointerType, visualizer.NatvisScope, variable.GetChildAdapter()));
            }

            return(variable.GetChildAdapter());
        }
Example #5
0
        internal IChildAdapter GetChildAdapter(IVariableInformation variable)
        {
            VisualizerInfo visualizer = VisualizerScanner.FindType(variable);

            if (visualizer?.Visualizer.Items == null)
            {
                return(variable.GetChildAdapter());
            }

            IChildAdapter childAdapter = CreateNatvisChildAdapter(visualizer, variable);

            // Special case for SSE registers. VS calls VariableInformationEnum.Count, even if
            // the SSE registers are not visible. Without this, we would have to expand all
            // children just to get the count, which slows down the register window a lot.
            if (variable.CustomVisualizer == CustomVisualizer.SSE ||
                variable.CustomVisualizer == CustomVisualizer.SSE2)
            {
                return(new SseAdapter(visualizer.GetExpandType().Items.Length, childAdapter));
            }

            return(childAdapter);
        }
        /// <summary>
        /// Find Natvis visualizer by variable.
        /// </summary>
        public VisualizerInfo FindType(IVariableInformation variable)
        {
            // Check for custom visualizers first.
            if (variable.CustomVisualizer != CustomVisualizer.None)
            {
                // Custom visualizers are keyed by pseudo-types "$" + CustomVisualizer enum name.
                string pseudoTypeName = "$" + variable.CustomVisualizer;

                VisualizerInfo visualizer;
                if (_visualizerCache.TryGetValue(pseudoTypeName, out visualizer))
                {
                    _logger.Verbose(() => $"Selected cached custom Natvis Visualizer " +
                                    $"'{visualizer?.Visualizer.Name ?? "null"} '" +
                                    $"for custom visualizer '{variable.CustomVisualizer}'");

                    return(visualizer);
                }

                visualizer = Scan(pseudoTypeName, TypeName.Parse(pseudoTypeName));
                if (visualizer != null)
                {
                    _logger.Verbose(() => $"Selected Natvis Visualizer " +
                                    $"'{visualizer.Visualizer.Name}'" +
                                    $" for custom visualizer '{variable.CustomVisualizer}'");

                    return(visualizer);
                }
            }

            string initialTypeName = variable.TypeName;

            _logger.Verbose($"Finding Natvis Visualizer for type '{initialTypeName}'");
            if (_visualizerCache.ContainsKey(initialTypeName))
            {
                VisualizerInfo visualizer = _visualizerCache[variable.TypeName];
                _logger.Verbose(() => $"Selected cached Natvis Visualizer " +
                                $"'{visualizer?.Visualizer.Name ?? "null"}' for type " +
                                $"'{initialTypeName}'");

                return(visualizer);
            }

            uint count = 0;

            foreach (string typeName in variable.GetAllInheritedTypes())
            {
                var parsedName = TypeName.Parse(typeName);
                if (parsedName == null)
                {
                    break;
                }

                _logger.Verbose(
                    () => $"Scanning for Natvis Visualizer for type '{parsedName.BaseName}' for " +
                    $"variable of type '{initialTypeName}'");

                VisualizerInfo visualizer = Scan(initialTypeName, parsedName);

                if (visualizer != null)
                {
                    _logger.Verbose(
                        () => $"Selected Natvis Visualizer '{visualizer.Visualizer.Name}'" +
                        $" for type '{initialTypeName}'");

                    return(visualizer);
                }

                ++count;

                // Safety check to make sure we don't get in to an expensive loop.
                if (count > _maxInheritedTypes)
                {
                    _logger.Warning($"The '{initialTypeName}' type exceeds the" +
                                    $" maximum number ({_maxInheritedTypes}) of searchable base " +
                                    $"classes.");

                    break;
                }
            }

            _logger.Verbose($"No Natvis Visualizer found for type '{initialTypeName}'");
            return(null);
        }