예제 #1
0
        public void Validate(Stream stream)
        {
            var doc              = new XPathDocument(stream);
            var navigator        = doc.CreateNavigator();
            var namespaceUri     = @"http://schemas.microsoft.com/vstudio/debugger/natvis/2010";
            var namespaceManager = new XmlNamespaceManager(navigator.NameTable);

            namespaceManager.AddNamespace("vs", namespaceUri);
            var validatorBuilder = new ValidatorBuilder(namespaceManager);

            List <Validator> validators = new List <Validator>();

            validators.Add(validatorBuilder.Build(@"count(//vs:Synthetic[@Expression])",
                                                  "The 'Expression' attribute is not supported on the <Synthetic> tag."));
            validators.Add(validatorBuilder.Build(@"count(//@*[name()='ModuleName'])",
                                                  "The 'ModuleName' attribute is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//@*[name()='ModuleVersionMin'])",
                                                  "The 'ModuleVersionMin' attribute is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//@*[name()='ModuleVersionMax'])",
                                                  "The 'ModuleVersionMax' attribute is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//vs:DisplayString[@Export])",
                                                  "The 'Export' attribute is not supported on the <DisplayString> tag."));
            validators.Add(validatorBuilder.Build(@"count(//vs:DisplayString[@Encoding])",
                                                  "The 'Encoding' attribute is not supported on the <DisplayString> tag."));
            validators.Add(validatorBuilder.Build(@"count(//vs:DisplayString[@LegacyAddin])",
                                                  "The 'LegacyAddin' attribute is not supported on the <DisplayString> tag."));
            validators.Add(validatorBuilder.Build(@"count(//vs:UIVisualizer)",
                                                  "The <UIVisualizer> tag is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//vs:CustomVisualizer)",
                                                  "The <CustomVisualizer> tag is not supported."));
            validators.Add(
                validatorBuilder.Build(@"count(//vs:LinkedListItems/vs:ValueNode[@Name])",
                                       "The 'Name' attribute is not supported on the <LinkedListItems>/<ValueNode> tag."));
            validators.Add(validatorBuilder.Build(@"count(//vs:ArrayItems/vs:Direction)",
                                                  "The <ArrayItems>/<Direction> tag is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//vs:ArrayItems/vs:Rank)",
                                                  "The <ArrayItems>/<Rank> tag is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//vs:ArrayItems/vs:LowerBound)",
                                                  "The <ArrayItems>/<LowerBound> tag is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//vs:Type/vs:MostDerivedType)",
                                                  "The <Type>/<MostDerivedType> tag is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//vs:Type/vs:Version)",
                                                  "The <Type>/<Version> tag is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//vs:Type[@Priority])",
                                                  "The 'Priority' attribute is not supported on the <Type> tag."));
            validators.Add(validatorBuilder.Build(@"count(//vs:Type[@Inheritable])",
                                                  "The 'Inheritable' attribute is not supported on the <Type> tag."));
            validators.Add(validatorBuilder.Build(@"count(//vs:AlternativeType[@Priority])",
                                                  "The 'Priority' attribute is not supported on the <AlternativeType> tag."));
            validators.Add(validatorBuilder.Build(@"count(//vs:AlternativeType[@Inheritable])",
                                                  "The 'Inheritable' attribute is not supported on the <AlternativeType> tag."));
            validators.Add(validatorBuilder.Build(@"count(//vs:Intrinsic)",
                                                  "The <Intrinsic> tag is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//vs:HResult)",
                                                  "The <HResult> tag is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//vs:LocalizedStrings)",
                                                  "The <LocalizedStrings> tag is not supported."));
            validators.Add(validatorBuilder.Build(@"count(//vs:Version)",
                                                  "The <Version> tag is not supported."));

            foreach (var validator in validators)
            {
                var xPathResult = navigator.Evaluate(validator.XPathExpression);
                if (xPathResult is double)
                {
                    if ((double)xPathResult > 0)
                    {
                        logger.Warning(() => $"{validator.WarningMessage} It was found " +
                                       $"{xPathResult} time(s).");
                    }
                }
                else
                {
                    Trace.WriteLine($"ERROR: Unexpected XPath result type=" +
                                    $"{xPathResult?.GetType()} for expression={validator.XPathExpression}.");
                }
            }
        }
        /// <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);
        }