internal List <ClassificationSpan> GetClassificationSpans(
            Workspace workspace, SemanticModel semanticModel, SnapshotSpan span)
        {
            var spans = new List <ClassificationSpan>();

            var root     = semanticModel.SyntaxTree.GetCompilationUnitRoot();
            var textSpan = new TextSpan(span.Start.Position, span.Length);

            foreach (var item in Classifier.GetClassifiedSpans(semanticModel, textSpan, workspace))
            {
                if (!ClassificationHelper.IsSupportedClassification(item.ClassificationType))
                {
                    continue;
                }

                if (item.ClassificationType == ClassificationTypeNames.Keyword)
                {
                    var keywordToken = root.FindToken(item.TextSpan.Start, true);
                    switch (keywordToken.ValueText)
                    {
                    case "GoTo":
                    case "Else":
                    case "ElseIf":
                    case "Then":
                    case "Throw":
                    case "Do":
                    case "Loop":
                    case "While":
                    case "Until":
                    case "Continue":
                    case "For":
                    case "Next":
                    case "Each":
                    case "Yield":
                    case "Return":
                    case "Select":
                    case "Case":
                    case "Exit":
                    case "Try":
                    case "Catch":
                    case "Finally":
                    case "Function" when keywordToken.IsExitStatementKeyword():
                    case "Sub" when keywordToken.IsExitStatementKeyword():
                    case "Property" when keywordToken.IsExitStatementKeyword():
                    case "End" when keywordToken.IsEndStatementKeyword():
                    case "If" when keywordToken.IsIfStatementKeyword() || keywordToken.IsEndStatementKeyword():
                        AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _controlFlowType);

                        break;
                    }
                    continue;
                }

                var node = root.FindNode(item.TextSpan, true).HandleNode();
                if (!semanticModel.TryGetSymbolInfo(node, out var symbol, out var reason))
                {
                    // NOTE: handle alias in imports directive
                    if (node is ImportAliasClauseSyntax && node.Parent is SimpleImportsClauseSyntax importSyntax)
                    {
                        var aliasNameSymbol           = semanticModel.GetSymbolInfo(importSyntax.Name).Symbol;
                        IClassificationType aliasType = null;
                        if (!(aliasNameSymbol is null))
                        {
                            aliasType =
                                aliasNameSymbol.Kind == SymbolKind.Namespace ? _aliasNamespaceType :
                                aliasNameSymbol.Kind == SymbolKind.NamedType ? GetTypeClassification(aliasNameSymbol as INamedTypeSymbol) :
                                null;
                        }

                        if (!(aliasType is null))
                        {
                            AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, aliasType);
                            continue;
                        }
                    }

                    Log.Debug("Nothing is found. Span start at {0} and end at {1}", item.TextSpan.Start, item.TextSpan.End);
                    Log.Debug("Candidate Reason is {0}", reason);
                    Log.Debug("Node is {0}", node);
                    continue;
                }

                // TODO: add posibility to turn off classification a type characters as part of identifiers
                switch (symbol.Kind)
                {
                case SymbolKind.Field:
                    var fieldSymbol = symbol as IFieldSymbol;
                    var fieldType   =
                        fieldSymbol.Type.TypeKind == TypeKind.Enum ? _enumFieldType :
                        fieldSymbol.IsConst ? _constantFieldType :
                        _fieldType;
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, fieldType, node);
                    break;

                case SymbolKind.RangeVariable:
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _rangeVariableType);
                    break;

                case SymbolKind.Local:
                    var localSymbol = symbol as ILocalSymbol;
                    var localType   =
                        localSymbol.IsStatic ? _staticLocalVariableType :
                        localSymbol.IsFunctionValue ? _functionVariableType :
                        _localVariableType;
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, localType);
                    break;

                case SymbolKind.Method:
                    var methodSymbol = symbol as IMethodSymbol;
                    var methodType   =
                        methodSymbol.IsExtensionMethod ? _extensionMethodType :
                        methodSymbol.IsShared() || methodSymbol.ContainingType?.TypeKind == TypeKind.Module ? _sharedMethodType :
                        methodSymbol.ReturnType.SpecialType == SpecialType.System_Void ? _subType :
                        _functionType;
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, methodType, node);
                    break;

                case SymbolKind.Parameter:
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _parameterType, node);
                    break;

                case SymbolKind.Property:
                    var propertySymbol = symbol as IPropertySymbol;
                    var propertyType   = propertySymbol.IsWithEvents ? _withEventsPropertyType : _propertyType;
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, propertyType, node);
                    break;

                case SymbolKind.Namespace:
                    var namespaceType = node.IsAliasNamespace(symbol, semanticModel) ? _aliasNamespaceType : _namespaceType;
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, namespaceType, node);
                    break;

                case SymbolKind.Event:
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _eventType, node);
                    break;

                case SymbolKind.TypeParameter:
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _typeParameterType, node);
                    break;

                case SymbolKind.NamedType:
                    var type = GetTypeClassification(symbol as INamedTypeSymbol);
                    if (!(type is null))
                    {
                        AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, type, node);
                    }
                    break;

                default:
                    Log.Debug("Symbol kind={0} was on position [{1}..{2}]", symbol.Kind, item.TextSpan.Start, item.TextSpan.End);
                    Log.Debug("Node is: {0}", node);
                    break;
                }
            }

            return(spans);
        }
Exemplo n.º 2
0
        internal List <ClassificationSpan> GetClassificationSpans(
            Workspace workspace, SemanticModel semanticModel, SnapshotSpan span)
        {
            var spans = new List <ClassificationSpan>();

            var root     = semanticModel.SyntaxTree.GetCompilationUnitRoot();
            var textSpan = new TextSpan(span.Start.Position, span.Length);

            foreach (var item in Classifier.GetClassifiedSpans(semanticModel, textSpan, workspace))
            {
                if (!ClassificationHelper.IsSupportedClassification(item.ClassificationType))
                {
                    continue;
                }

                if (item.ClassificationType == ClassificationTypeNames.Keyword)
                {
                    var keywordToken = root.FindToken(item.TextSpan.Start, true);
                    switch (keywordToken.ValueText)
                    {
                    case "if":
                    case "else":
                    case "while":
                    case "do":
                    case "for":
                    case "foreach":
                    case "switch":
                    case "case":
                    case "goto":
                    case "return":
                    case "break":
                    case "continue":
                    case "throw":
                    case "yield":
                    case "try":
                    case "catch":
                    case "finally":
                    case "default" when keywordToken.Parent is DefaultSwitchLabelSyntax:
                        AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _controlFlowType);
                        break;
                    }
                    continue;
                }

                var node = root.FindNode(item.TextSpan, true).HandleNode();
                if (!semanticModel.TryGetSymbolInfo(node, out var symbol, out var reason))
                {
                    // NOTE: handle alias in using directive
                    if ((node.Parent as NameEqualsSyntax)?.Parent is UsingDirectiveSyntax usingSyntax)
                    {
                        var aliasNameSymbol           = semanticModel.GetSymbolInfo(usingSyntax.Name).Symbol;
                        IClassificationType aliasType = null;
                        if (!(aliasNameSymbol is null))
                        {
                            aliasType =
                                aliasNameSymbol.Kind == SymbolKind.Namespace ? _aliasNamespaceType :
                                aliasNameSymbol.Kind == SymbolKind.NamedType ? GetTypeClassification(aliasNameSymbol as INamedTypeSymbol) :
                                null;
                        }

                        if (!(aliasType is null))
                        {
                            AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, aliasType);
                            continue;
                        }
                    }

                    Log.Debug("Nothing is found. Span start at {0} and end at {1}", item.TextSpan.Start, item.TextSpan.End);
                    Log.Debug("Candidate Reason is {0}", reason);
                    Log.Debug("Node is {0}", node);
                    continue;
                }

                switch (symbol.Kind)
                {
                case SymbolKind.Label:
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _labelType);
                    break;

                case SymbolKind.RangeVariable:
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _rangeVariableType);
                    break;

                case SymbolKind.Field:
                    var fieldSymbol = symbol as IFieldSymbol;
                    var fieldType   =
                        fieldSymbol.Type.TypeKind == TypeKind.Enum ? _enumFieldType :
                        fieldSymbol.IsConst ? _constantFieldType :
                        _fieldType;
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, fieldType, node);
                    break;

                case SymbolKind.Property:
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _propertyType, node);
                    break;

                case SymbolKind.Event:
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _eventType, node);
                    break;

                case SymbolKind.Local:
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _localVariableType);
                    break;

                case SymbolKind.Namespace:
                    var namesapceType = node.IsAliasNamespace(symbol, semanticModel) ? _aliasNamespaceType : _namespaceType;
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, namesapceType, node);
                    break;

                case SymbolKind.Parameter:
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _parameterType, node);
                    break;

                case SymbolKind.Method:
                    var methodSymbol = symbol as IMethodSymbol;
                    var methodType   =
                        methodSymbol.MethodKind == MethodKind.Constructor ? _constructorType :
                        methodSymbol.MethodKind == MethodKind.Destructor ? _destructorType :
                        methodSymbol.MethodKind == MethodKind.LocalFunction ? _localMethodType :
                        methodSymbol.IsExtensionMethod ? _extensionMethodType :
                        methodSymbol.IsStatic ? _staticMethodType :
                        _methodType;
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, methodType, node);
                    break;

                case SymbolKind.TypeParameter:
                    AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, _typeParameterType, node);
                    break;

                case SymbolKind.NamedType:
                    var typeSymbol = symbol as INamedTypeSymbol;
                    var type       = GetTypeClassification(typeSymbol);
                    if (!(type is null))
                    {
                        AppendClassificationSpan(spans, span.Snapshot, item.TextSpan, type, node);
                    }
                    break;

                default:
                    Log.Debug("Symbol kind={0} was on position [{1}..{2}]", symbol.Kind, item.TextSpan.Start, item.TextSpan.End);
                    Log.Debug("Node is: {0}", node);
                    break;
                }
            }

            return(spans);
        }
Exemplo n.º 3
0
 private bool IsSupportedClassification(string classification) =>
 ClassificationHelper.IsSupportedClassification(classification) || classification == ClassificationTypeNames.Keyword;