c#
Determining if the current span is an attribute deleration using Roslyn APIs
I'm building a visual studio extension for coloring various language constructs using Roslyn APIs, I want to change the color of attribute declarations, like Asp.Net MVC [Require] attribute for example. I have access to SyntaxNode and ISymbol, my current check to find out if the current node is an attribute declaration is: public static bool IsCSharpAttributeSyntaxKind(this SyntaxNode node) { return node.Kind() == SyntaxKind.Attribute; } And use it like: if (node.IsCSharpAttributeSyntaxKind()) { classificationTypeDictionary.TryGetValue(ColorCoderClassificationName.Attribute, out IClassificationType classificationValue); return new TagSpan<IClassificationTag>(new SnapshotSpan(snapshot, span.TextSpan.Start, span.TextSpan.Length), new ClassificationTag(classificationValue)); } I get the Roslyn info by: public IEnumerable<ITagSpan<IClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans) { if (spans.Count == 0) { return Enumerable.Empty<ITagSpan<IClassificationTag>>(); } var cacheStatus = _colorCoderTaggerServices.ManageCache(ref _cache, spans, _buffer); if (cacheStatus == CacheState.NotResolved) { return Enumerable.Empty<ITagSpan<IClassificationTag>>(); } return _colorCoderTaggerServices.GetClassificationTags(_cache, spans, classificationTypeDictionary); } Also the method for retrieving the identifiers: internal IEnumerable<ClassifiedSpan> GetIdentifiersInSpans(Workspace workspace, SemanticModel model, NormalizedSnapshotSpanCollection spans) { var comparer = StringComparer.InvariantCultureIgnoreCase; var classifiedSpans = spans.SelectMany(span => { var textSpan = TextSpan.FromBounds(span.Start, span.End); return Classifier.GetClassifiedSpans(model, textSpan, workspace); }); return classifiedSpans.Where(c => comparer.Compare(c.ClassificationType, "identifier") == 0); } I don't know if the attribute declaration is part of the identifiers that I return form GetIdentifiersInSpans, but I did it without the Where with no success. And for my caching mechanism I use: public class ProviderCache { public Workspace Workspace { get; private set; } public Document Document { get; private set; } public SemanticModel SemanticModel { get; private set; } public SyntaxNode SyntaxRoot { get; private set; } public ITextSnapshot Snapshot { get; private set; } public static async Task<ProviderCache> Resolve(ITextBuffer buffer, ITextSnapshot snapshot) { var workspace = buffer.GetWorkspace(); var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) { return null; } var semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(false); var syntaxRoot = await document.GetSyntaxRootAsync().ConfigureAwait(false); return new ProviderCache { Workspace = workspace, Document = document, SemanticModel = semanticModel, SyntaxRoot = syntaxRoot, Snapshot = snapshot }; } } I've tried various other things but none of them worked, I believe I miss something else here. I understand that my question is not good enough, I'm sorry for that, that's because I lack the terminology to ask a good question, and visual studio's extensibility frameworks are usually under-documented, if you need any more detail please let me know.
You don't mention how you are getting the roslyn info in your extension, but because you mention SyntaxNode Workspace and SemanticModel in your code samples, I assume you can get the current Document. The approach I would take is to get the root node for the document you are attempting to classify. A good starting place would be somthing like the code below and this VSSDK sample. public static async Task<IEnumerable<ClassificationSpan>> ClassifyAttributes(Document currentDocument, CancellationToken token) { // Get all attribute nodes in the current document var rootNode = await currentDocument.GetSyntaxRootAsync(token).ConfigureAwait(false); var attributesInDocument = from descendantNode in rootNode.DescendantNodesAndSelf() where descendantNode.IsKind(SyntaxKind.Attribute) select (AttributeSyntax)descendantNode; // Check to see if the attribute binds to a type (I assume you do not want to classify attributes with errors) var model = await currentDocument.GetSemanticModelAsync(token).ConfigureAwait(false); var attributeSpans = from attributeNode in attributesInDocument let typeInfo = model.GetTypeInfo(attributeNode, token) where typeInfo.Type.Kind != SymbolKind.ErrorType select new ClassificationSpan(attributeNode.Span, _classificationType); // returns a set of ClassifiedSpans that your extensions classifer will colorize return attributeSpans; }
Related Links
XSD cant create class from XML based on inherited classes
My stored procedure returns something, but sqlDataAdapter.Fill leaves datatable empty
Is it OK to remove .property statements from ILAsm files for production use?
Printing bitmaps in C# - hasmorepages issue
NHibernate 3.1 Query equals
How to do XSLT 2.0 transformation with C# [duplicate]
Cannot return proper model into view when doing a join linq query
Generate random bytes for TripleDES key C#
Question regarding common class
C# Assign Name for Try-Catch Error
How to compare two objects excluding a single object property?
Setting to DataContext not reflecting in Listbox
TFS 2010, cannot get files to workspace, The server returned content type text/html, which is not supported
Can't get ValueInjecter to map COM objects
WPF: Naming controls generated during binding for UI Automation Tests
NetDataContractSerializer and assembly versions mismatch