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); }