static async Task UpdateDocument(ConcurrentDictionary <DocumentId, Dictionary <DeclaredSymbolInfoKind, List <DeclaredSymbolInfoWrapper> > > result, Microsoft.CodeAnalysis.Document document, CancellationToken cancellationToken)
            {
                var syntaxFactsService        = document.GetLanguageService <ISyntaxFactsService> ();
                var declaredSymbolInfoService = document.GetLanguageService <IDeclaredSymbolInfoFactoryService> ();
                var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                var infos       = new Dictionary <DeclaredSymbolInfoKind, List <DeclaredSymbolInfoWrapper> > ();
                var stringTable = Roslyn.Utilities.StringTable.GetInstance();                  // TODO: fix this

                foreach (var kind in AllKinds)
                {
                    infos [kind] = new List <DeclaredSymbolInfoWrapper> ();
                }
                foreach (var current in root.DescendantNodesAndSelf(n => !(n is BlockSyntax)))
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    var kind = current.Kind();
                    if (kind == SyntaxKind.ConstructorDeclaration ||
                        kind == SyntaxKind.IndexerDeclaration)
                    {
                        continue;
                    }
                    if (declaredSymbolInfoService.TryGetDeclaredSymbolInfo(stringTable, current, out DeclaredSymbolInfo info))
                    {
                        var declaredSymbolInfo = new DeclaredSymbolInfoWrapper(current, document.Id, info);
                        infos[info.Kind].Add(declaredSymbolInfo);
                    }
                }
                RemoveDocument(result, document.Id);
                result.TryAdd(document.Id, infos);
            }
        protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            InvocationExpressionSyntax invocationExpression;
            if (!TryGetInvocationExpression(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out invocationExpression))
            {
                return null;
            }

            var semanticModel = await document.GetSemanticModelForNodeAsync(invocationExpression, cancellationToken).ConfigureAwait(false);
            var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken);
            if (within == null)
            {
                return null;
            }

            var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>();
            var methodGroup = semanticModel.GetMemberGroup(invocationExpression.Expression, cancellationToken)
                                           .OfType<IMethodSymbol>()
                                           .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation)
                                           .Sort(symbolDisplayService, semanticModel, invocationExpression.SpanStart);

            var expressionType = semanticModel.GetTypeInfo(invocationExpression.Expression, cancellationToken).Type as INamedTypeSymbol;

            var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>();
            var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>();

            var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(invocationExpression.ArgumentList);
            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();

            if (methodGroup.Any())
            {
                return CreateSignatureHelpItems(
                    GetMethodGroupItems(invocationExpression, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, within, methodGroup, cancellationToken),
                    textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken));
            }
            else if (expressionType != null && expressionType.TypeKind == TypeKind.Delegate)
            {
                return CreateSignatureHelpItems(
                    GetDelegateInvokeItems(invocationExpression, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, within, expressionType, cancellationToken),
                    textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken));
            }
            else
            {
                return null;
            }
        }
        protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            if (!TryGetInvocationExpression(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out var invocationExpression))
            {
                return null;
            }

            var semanticModel = await document.GetSemanticModelForNodeAsync(invocationExpression, cancellationToken).ConfigureAwait(false);
            var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken);
            if (within == null)
            {
                return null;
            }

            // get the regular signature help items
            var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>();
            var methodGroup = semanticModel.GetMemberGroup(invocationExpression.Expression, cancellationToken)
                                           .OfType<IMethodSymbol>()
                                           .ToImmutableArray()
                                           .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation);

            // try to bind to the actual method
            var symbolInfo = semanticModel.GetSymbolInfo(invocationExpression, cancellationToken);
            var matchedMethodSymbol = symbolInfo.Symbol as IMethodSymbol;

            // if the symbol could be bound, replace that item in the symbol list
            if (matchedMethodSymbol != null && matchedMethodSymbol.IsGenericMethod)
            {
                methodGroup = methodGroup.SelectAsArray(m => matchedMethodSymbol.OriginalDefinition == m ? matchedMethodSymbol : m);
            }

            methodGroup = methodGroup.Sort(
                symbolDisplayService, semanticModel, invocationExpression.SpanStart);

            var expressionType = semanticModel.GetTypeInfo(invocationExpression.Expression, cancellationToken).Type as INamedTypeSymbol;

            var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>();
            var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>();

            var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(invocationExpression.ArgumentList);
            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();

            if (methodGroup.Any())
            {
                return CreateSignatureHelpItems(
                    GetMethodGroupItems(invocationExpression, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, within, methodGroup, cancellationToken),
                    textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken));
            }
            else if (expressionType != null && expressionType.TypeKind == TypeKind.Delegate)
            {
                return CreateSignatureHelpItems(
                    GetDelegateInvokeItems(invocationExpression, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, within, expressionType, cancellationToken),
                    textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken));
            }
            else
            {
                return null;
            }
        }
        public async Task<Document> AddSourceToAsync(Document document, ISymbol symbol, CancellationToken cancellationToken)
        {
            if (document == null)
            {
                throw new ArgumentNullException(nameof(document));
            }

            var newSemanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
            var rootNamespace = newSemanticModel.GetEnclosingNamespace(0, cancellationToken);

            // Add the interface of the symbol to the top of the root namespace
            document = await CodeGenerator.AddNamespaceOrTypeDeclarationAsync(
                document.Project.Solution,
                rootNamespace,
                CreateCodeGenerationSymbol(document, symbol),
                CreateCodeGenerationOptions(newSemanticModel.SyntaxTree.GetLocation(new TextSpan()), symbol),
                cancellationToken).ConfigureAwait(false);

            var docCommentFormattingService = document.GetLanguageService<IDocumentationCommentFormattingService>();
            var docWithDocComments = await ConvertDocCommentsToRegularComments(document, docCommentFormattingService, cancellationToken).ConfigureAwait(false);

            var docWithAssemblyInfo = await AddAssemblyInfoRegionAsync(docWithDocComments, symbol.GetOriginalUnreducedDefinition(), cancellationToken).ConfigureAwait(false);
            var node = await docWithAssemblyInfo.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var formattedDoc = await Formatter.FormatAsync(
                docWithAssemblyInfo, SpecializedCollections.SingletonEnumerable(node.FullSpan), options: null, rules: GetFormattingRules(docWithAssemblyInfo), cancellationToken: cancellationToken).ConfigureAwait(false);

            var reducers = this.GetReducers();
            return await Simplifier.ReduceAsync(formattedDoc, reducers, null, cancellationToken).ConfigureAwait(false);
        }
        private static INamespaceOrTypeSymbol CreateCodeGenerationSymbol(Document document, ISymbol symbol)
        {
            symbol = symbol.GetOriginalUnreducedDefinition();
            var topLevelNamespaceSymbol = symbol.ContainingNamespace;
            var topLevelNamedType = MetadataAsSourceHelpers.GetTopLevelContainingNamedType(symbol);

            var canImplementImplicitly = document.GetLanguageService<ISemanticFactsService>().SupportsImplicitInterfaceImplementation;
            var docCommentFormattingService = document.GetLanguageService<IDocumentationCommentFormattingService>();

            INamespaceOrTypeSymbol wrappedType = new WrappedNamedTypeSymbol(topLevelNamedType, canImplementImplicitly, docCommentFormattingService);

            return topLevelNamespaceSymbol.IsGlobalNamespace
                ? wrappedType
                : CodeGenerationSymbolFactory.CreateNamespaceSymbol(
                    topLevelNamespaceSymbol.ToDisplayString(SymbolDisplayFormats.NameFormat),
                    null,
                    new[] { wrappedType });
        }
        public override async Task<string> GetHelpTermAsync(Document document, TextSpan span, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();

            // For now, find the token under the start of the selection.
            var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
            var token = syntaxTree.GetTouchingToken(span.Start, cancellationToken, findInsideTrivia: true);

            if (IsValid(token, span))
            {
                var semanticModel = await document.GetSemanticModelForSpanAsync(span, cancellationToken).ConfigureAwait(false);

                var result = TryGetText(token, semanticModel, document, cancellationToken, syntaxFacts);
                if (string.IsNullOrEmpty(result))
                {
                    var previousToken = token.GetPreviousToken();
                    if (IsValid(previousToken, span))
                    {
                        result = TryGetText(previousToken, semanticModel, document, cancellationToken, syntaxFacts);
                    }
                }

                return result;
            }

            var trivia = root.FindTrivia(span.Start, findInsideTrivia: true);
            if (trivia.Span.IntersectsWith(span) && trivia.Kind() == SyntaxKind.PreprocessingMessageTrivia &&
                trivia.Token.GetAncestor<RegionDirectiveTriviaSyntax>() != null)
            {
                return "#region";
            }

            if (trivia.IsRegularOrDocComment())
            {
                // just find the first "word" that intersects with our position
                var text = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false);
                int start = span.Start;
                int end = span.Start;

                while (start > 0 && syntaxFacts.IsIdentifierPartCharacter(text[start - 1]))
                {
                    start--;
                }

                while (end < text.Length - 1 && syntaxFacts.IsIdentifierPartCharacter(text[end]))
                {
                    end++;
                }

                return text.GetSubText(TextSpan.FromBounds(start, end)).ToString();
            }

            return string.Empty;
        }
        protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            ConstructorInitializerSyntax constructorInitializer;
            if (!TryGetConstructorInitializer(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out constructorInitializer))
            {
                return null;
            }

            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
            var within = semanticModel.GetEnclosingNamedType(position, cancellationToken);
            if (within == null)
            {
                return null;
            }

            if (within.TypeKind != TypeKind.Struct && within.TypeKind != TypeKind.Class)
            {
                return null;
            }

            var type = constructorInitializer.Kind() == SyntaxKind.BaseConstructorInitializer
                ? within.BaseType
                : within;

            if (type == null)
            {
                return null;
            }

            var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>();
            var accessibleConstructors = type.InstanceConstructors
                                             .Where(c => c.IsAccessibleWithin(within))
                                             .Where(c => c.IsEditorBrowsable(document.ShouldHideAdvancedMembers(), semanticModel.Compilation))
                                             .Sort(symbolDisplayService, semanticModel, constructorInitializer.SpanStart);

            if (!accessibleConstructors.Any())
            {
                return null;
            }

            var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>();
            var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>();
            var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(constructorInitializer.ArgumentList);
            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();

            return CreateSignatureHelpItems(accessibleConstructors.Select(c =>
                Convert(c, constructorInitializer.ArgumentList.OpenParenToken, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, cancellationToken)),
                textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken));
        }
Пример #8
0
 private static IEnumerable<CompletionListProvider> GetCompletionListProviders(Document document)
 {
     var languageService = document.GetLanguageService<ICompletionService>();
     IEnumerable<CompletionListProvider> providers = null;
     if (languageService != null)
     {
         providers = InnerCompletionService.GetDefaultCompletionListProviders(document);
         if (_additionalProviders != null)
         {
             providers = providers.Concat(_additionalProviders);
         }
     }
     return providers;
 }
        protected override async Task<CompletionItem> GetBuilderAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (triggerInfo.TriggerReason == CompletionTriggerReason.TypeCharCommand)
            {
                var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                if (triggerInfo.IsDebugger)
                {
                    // Aggressive Intellisense in the debugger: always show the builder 
                    return CreateEmptyBuilder(text, position);
                }

                var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
                var token = tree
                    .FindTokenOnLeftOfPosition(position, cancellationToken)
                    .GetPreviousTokenIfTouchingWord(position);

                if (token.Kind() == SyntaxKind.None)
                {
                    return null;
                }

                var semanticModel = await document.GetSemanticModelForNodeAsync(token.Parent, cancellationToken).ConfigureAwait(false);
                var typeInferrer = document.GetLanguageService<ITypeInferenceService>();

                if (IsLambdaExpression(semanticModel, position, token, typeInferrer, cancellationToken))
                {
                    return CreateBuilder(text, position, CSharpFeaturesResources.LambdaExpression, CSharpFeaturesResources.AutoselectDisabledDueToPotentialLambdaDeclaration);
                }
                else if (IsAnonymousObjectCreation(token))
                {
                    return CreateBuilder(text, position, CSharpFeaturesResources.MemberName, CSharpFeaturesResources.AutoselectDisabledDueToPossibleExplicitlyNamesAnonTypeMemCreation);
                }
                else if (token.IsPreProcessorExpressionContext())
                {
                    return CreateEmptyBuilder(text, position);
                }
                else if (IsImplicitArrayCreation(semanticModel, token, position, typeInferrer, cancellationToken))
                {
                    return CreateBuilder(text, position, CSharpFeaturesResources.ImplicitArrayCreation, CSharpFeaturesResources.AutoselectDisabledDueToPotentialImplicitArray);
                }
                else if (token.IsKindOrHasMatchingText(SyntaxKind.FromKeyword) || token.IsKindOrHasMatchingText(SyntaxKind.JoinKeyword))
                {
                    return CreateBuilder(text, position, CSharpFeaturesResources.RangeVariable, CSharpFeaturesResources.AutoselectDisabledDueToPotentialRangeVariableDecl);
                }
            }

            return null;
        }
        protected override async Task<CompletionItem> GetSuggestionModeItemAsync(Document document, int position, TextSpan itemSpan, CompletionTrigger trigger, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (trigger.Kind == CompletionTriggerKind.Insertion)
            {
                var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
                var token = tree
                    .FindTokenOnLeftOfPosition(position, cancellationToken)
                    .GetPreviousTokenIfTouchingWord(position);

                if (token.Kind() == SyntaxKind.None)
                {
                    return null;
                }

                var semanticModel = await document.GetSemanticModelForNodeAsync(token.Parent, cancellationToken).ConfigureAwait(false);
                var typeInferrer = document.GetLanguageService<ITypeInferenceService>();

                if (IsLambdaExpression(semanticModel, position, token, typeInferrer, cancellationToken))
                {
                    return CreateSuggestionModeItem(CSharpFeaturesResources.LambdaExpression, itemSpan, CSharpFeaturesResources.AutoselectDisabledDueToPotentialLambdaDeclaration);
                }
                else if (IsAnonymousObjectCreation(token) || IsPossibleTupleExpression(token))
                {
                    return CreateSuggestionModeItem(CSharpFeaturesResources.MemberName, itemSpan, CSharpFeaturesResources.AutoselectDisabledDueToPossibleExplicitlyNamesAnonTypeMemCreation);
                }
                else if (token.IsPreProcessorExpressionContext())
                {
                    return CreateEmptySuggestionModeItem(itemSpan);
                }
                else if (IsImplicitArrayCreation(semanticModel, token, position, typeInferrer, cancellationToken))
                {
                    return CreateSuggestionModeItem(CSharpFeaturesResources.ImplicitArrayCreation, itemSpan, CSharpFeaturesResources.AutoselectDisabledDueToPotentialImplicitArray);
                }
                else if (token.IsKindOrHasMatchingText(SyntaxKind.FromKeyword) || token.IsKindOrHasMatchingText(SyntaxKind.JoinKeyword))
                {
                    return CreateSuggestionModeItem(CSharpFeaturesResources.RangeVariable, itemSpan, CSharpFeaturesResources.AutoselectDisabledDueToPotentialRangeVariableDecl);
                }
                else if (tree.IsNamespaceDeclarationNameContext(position, cancellationToken))
                {
                    return CreateSuggestionModeItem(CSharpFeaturesResources.NamespaceName, itemSpan, CSharpFeaturesResources.AutoselectDisabledDueToNamespaceDeclaration);
                }
            }

            return null;
        }
        internal override Task<Document> GetUpdatedDocumentAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, string diagnosticId, CancellationToken cancellationToken)
        {            
            //// We are going to add a call Dispose on fields:
            ////
            ////        public void Dispose()
            ////        {
            ////            A.Dispose();
            ////            ...
            ////        }

            var syntaxNode = nodeToFix as VariableDeclaratorSyntax;
            if (syntaxNode == null)
            {
                return Task.FromResult(document);
            }

            // find a Dispose method
            var member = syntaxNode.FirstAncestorOrSelf<ClassDeclarationSyntax>()
                .DescendantNodes().OfType<MethodDeclarationSyntax>()
                .Where(n => n.Identifier.ValueText == CA2213DiagnosticAnalyzer.Dispose).FirstOrDefault();
            if (member == null)
            {
                return Task.FromResult(document);
            }

            var factory = document.GetLanguageService<SyntaxGenerator>();
            var symbol = model.GetDeclaredSymbol(syntaxNode);

            // handle a case where a local in the Dipose method with the same name by generating this (or ClassName) and simplifying it
            var path = symbol.IsStatic
                            ? factory.IdentifierName(symbol.ContainingType.MetadataName)
                            : factory.ThisExpression();

            var statement =
                factory.ExpressionStatement(
                    factory.InvocationExpression(
                        factory.MemberAccessExpression(
                            factory.MemberAccessExpression(path, factory.IdentifierName(symbol.Name)).WithAdditionalAnnotations(Simplification.Simplifier.Annotation),
                                factory.IdentifierName(CA2213DiagnosticAnalyzer.Dispose))));

            var newMember = member.AddBodyStatements((StatementSyntax)statement).WithAdditionalAnnotations(Formatter.Annotation);
            return Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode(member, newMember)));
        }
        protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            AttributeSyntax attribute;
            if (!TryGetAttributeExpression(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out attribute))
            {
                return null;
            }

            var semanticModel = await document.GetSemanticModelForNodeAsync(attribute, cancellationToken).ConfigureAwait(false);
            var attributeType = semanticModel.GetTypeInfo(attribute, cancellationToken).Type as INamedTypeSymbol;
            if (attributeType == null)
            {
                return null;
            }

            var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken);
            if (within == null)
            {
                return null;
            }

            var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>();
            var accessibleConstructors = attributeType.InstanceConstructors
                                                      .WhereAsArray(c => c.IsAccessibleWithin(within))
                                                      .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation)
                                                      .Sort(symbolDisplayService, semanticModel, attribute.SpanStart);

            if (!accessibleConstructors.Any())
            {
                return null;
            }

            var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>();
            var documentationCommentFormatter = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>();
            var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(attribute.ArgumentList);

            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
            return CreateSignatureHelpItems(accessibleConstructors.Select(c =>
                Convert(c, within, attribute, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormatter, cancellationToken)).ToList(),
                textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken));
        }
        public IndentationResult? GetDesiredIndentation(Document document, int lineNumber, CancellationToken cancellationToken)
        {
            var root = document.GetSyntaxRootSynchronously(cancellationToken);
            var sourceText = root.SyntaxTree.GetText(cancellationToken);
            var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken);

            var lineToBeIndented = sourceText.Lines[lineNumber];

            var formattingRules = GetFormattingRules(document, lineToBeIndented.Start);

            // enter on a token case.
            if (ShouldUseSmartTokenFormatterInsteadOfIndenter(formattingRules, root, lineToBeIndented, documentOptions, cancellationToken))
            {
                return null;
            }

            var indenter = GetIndenter(
                document.GetLanguageService<ISyntaxFactsService>(),
                root.SyntaxTree, lineToBeIndented, formattingRules,
                documentOptions, cancellationToken);

            return indenter.GetDesiredIndentation();
        }
        protected override async Task<CodeIssue> GetIssueAsync(
            Document document,
            SyntaxNode node,
            CancellationToken cancellationToken)
        {
            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return null;
            }

            var service = document.GetLanguageService<IImplementAbstractClassService>();
            var result = await service.ImplementAbstractClassAsync(document, node, cancellationToken).ConfigureAwait(false);

            var changes = await result.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false);
            if (!changes.Any())
            {
                return null;
            }

            return new CodeIssue(
                CodeIssueKind.Error,
                node.Span,
                SpecializedCollections.SingletonEnumerable(new CodeAction(result)));
        }
        protected override async Task<CompletionItem> GetSuggestionModeItemAsync(
            Document document, int position, TextSpan itemSpan, CompletionTrigger trigger, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (trigger.Kind == CompletionTriggerKind.Insertion)
            {
                var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
                var token = tree
                    .FindTokenOnLeftOfPosition(position, cancellationToken)
                    .GetPreviousTokenIfTouchingWord(position);

                if (token.Kind() == SyntaxKind.None)
                {
                    return null;
                }

                var semanticModel = await document.GetSemanticModelForNodeAsync(token.Parent, cancellationToken).ConfigureAwait(false);
                var typeInferrer = document.GetLanguageService<ITypeInferenceService>();
                if (IsLambdaExpression(semanticModel, position, token, typeInferrer, cancellationToken))
                {
                    return CreateSuggestionModeItem(CSharpFeaturesResources.lambda_expression, CSharpFeaturesResources.Autoselect_disabled_due_to_potential_lambda_declaration);
                }
                else if (IsAnonymousObjectCreation(token))
                {
                    return CreateSuggestionModeItem(CSharpFeaturesResources.member_name, CSharpFeaturesResources.Autoselect_disabled_due_to_possible_explicitly_named_anonymous_type_member_creation);
                }
                else if (token.IsPreProcessorExpressionContext())
                {
                    return CreateEmptySuggestionModeItem();
                }
                else if (IsImplicitArrayCreation(semanticModel, token, position, typeInferrer, cancellationToken))
                {
                    return CreateSuggestionModeItem(CSharpFeaturesResources.implicit_array_creation, CSharpFeaturesResources.Autoselect_disabled_due_to_potential_implicit_array_creation);
                }
                else if (token.IsKindOrHasMatchingText(SyntaxKind.FromKeyword) || token.IsKindOrHasMatchingText(SyntaxKind.JoinKeyword))
                {
                    return CreateSuggestionModeItem(CSharpFeaturesResources.range_variable, CSharpFeaturesResources.Autoselect_disabled_due_to_potential_range_variable_declaration);
                }
                else if (tree.IsNamespaceDeclarationNameContext(position, cancellationToken))
                {
                    return CreateSuggestionModeItem(CSharpFeaturesResources.namespace_name, CSharpFeaturesResources.Autoselect_disabled_due_to_namespace_declaration);
                }
                else if (tree.IsPartialTypeDeclarationNameContext(position, cancellationToken, out var typeDeclaration))
                {
                    switch (typeDeclaration.Keyword.Kind())
                    {
                        case SyntaxKind.ClassKeyword:
                            return CreateSuggestionModeItem(CSharpFeaturesResources.class_name, CSharpFeaturesResources.Autoselect_disabled_due_to_type_declaration);

                        case SyntaxKind.StructKeyword:
                            return CreateSuggestionModeItem(CSharpFeaturesResources.struct_name, CSharpFeaturesResources.Autoselect_disabled_due_to_type_declaration);

                        case SyntaxKind.InterfaceKeyword:
                            return CreateSuggestionModeItem(CSharpFeaturesResources.interface_name, CSharpFeaturesResources.Autoselect_disabled_due_to_type_declaration);
                    }
                }
                else if (tree.IsPossibleDeconstructionDesignation(position, cancellationToken))
                {
                    return CreateSuggestionModeItem(CSharpFeaturesResources.designation_name,
                        CSharpFeaturesResources.Autoselect_disabled_due_to_possible_deconstruction_declaration);
                }
            }

            return null;
        }
		protected IPropertySymbol GenerateProperty(string propertyName, string fieldName, Accessibility accessibility, IFieldSymbol field, INamedTypeSymbol containingSymbol, SyntaxAnnotation annotation, Document document, CancellationToken cancellationToken)
		{
			var factory = document.GetLanguageService<SyntaxGenerator>();

			var propertySymbol = annotation.AddAnnotationToSymbol(CodeGenerationSymbolFactory.CreatePropertySymbol(containingType: containingSymbol,
			                                                                                                       attributes: SpecializedCollections.EmptyList<AttributeData>(),
			                                                                                                       accessibility: ComputeAccessibility(accessibility, field.Type),
			                                                                                                       modifiers: new DeclarationModifiers().WithIsStatic (field.IsStatic).WithIsReadOnly (field.IsReadOnly).WithIsUnsafe (field.IsUnsafe()),
			                                                                                                       type: field.Type,
			                                                                                                       explicitInterfaceSymbol: null,
			                                                                                                       name: propertyName,
			                                                                                                       parameters: SpecializedCollections.EmptyList<IParameterSymbol>(),
			                                                                                                       getMethod: CreateGet(fieldName, field, factory),
			                                                                                                       setMethod: field.IsReadOnly || field.IsConst ? null : CreateSet(fieldName, field, factory)));

			return Simplifier.Annotation.AddAnnotationToSymbol(
				Formatter.Annotation.AddAnnotationToSymbol(propertySymbol));
		}
        protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var root = await document.GetCSharpSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            ExpressionSyntax expression;
            SyntaxToken openBrace;
            if (!TryGetElementAccessExpression(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out expression, out openBrace))
            {
                return null;
            }

            var semanticModel = await document.GetCSharpSemanticModelAsync(cancellationToken).ConfigureAwait(false);
            var expressionSymbol = semanticModel.GetSymbolInfo(expression, cancellationToken).GetAnySymbol();
            if (expressionSymbol is INamedTypeSymbol)
            {
                // foo?[$$]
                var namedType = (INamedTypeSymbol)expressionSymbol;
                if (namedType.ConstructedFrom.SpecialType == SpecialType.System_Nullable_T &&
                    expression.IsKind(SyntaxKind.NullableType) &&
                    expression.IsChildNode<ArrayTypeSyntax>(a => a.ElementType))
                {
                    // Speculatively bind the type part of the nullable as an expression
                    var nullableTypeSyntax = (NullableTypeSyntax)expression;
                    var speculativeBinding = semanticModel.GetSpeculativeSymbolInfo(position, nullableTypeSyntax.ElementType, SpeculativeBindingOption.BindAsExpression);
                    expressionSymbol = speculativeBinding.GetAnySymbol();
                    expression = nullableTypeSyntax.ElementType;
                }
            }

            if (expressionSymbol != null && expressionSymbol is INamedTypeSymbol)
            {
                return null;
            }

            IEnumerable<IPropertySymbol> indexers;
            ITypeSymbol expressionType;

            if (!TryGetIndexers(position, semanticModel, expression, cancellationToken, out indexers, out expressionType) &&
                !TryGetComIndexers(semanticModel, expression, cancellationToken, out indexers, out expressionType))
            {
                return null;
            }

            var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken);
            if (within == null)
            {
                return null;
            }

            var accessibleIndexers = indexers.Where(m => m.IsAccessibleWithin(within, throughTypeOpt: expressionType));
            if (!accessibleIndexers.Any())
            {
                return null;
            }

            var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>();
            accessibleIndexers = accessibleIndexers.FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation)
                                                   .Sort(symbolDisplayService, semanticModel, expression.SpanStart);

            var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>();
            var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>();
            var textSpan = GetTextSpan(expression, openBrace);
            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();

            return CreateSignatureHelpItems(accessibleIndexers.Select(p =>
                Convert(p, openBrace, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, cancellationToken)),
                textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken));
        }
        protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxToken genericIdentifier, lessThanToken;
            if (!TryGetGenericIdentifier(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken,
                    out genericIdentifier, out lessThanToken))
            {
                return null;
            }

            var simpleName = genericIdentifier.Parent as SimpleNameSyntax;
            if (simpleName == null)
            {
                return null;
            }

            var beforeDotExpression = simpleName.IsRightSideOfDot() ? simpleName.GetLeftSideOfDot() : null;

            var semanticModel = await document.GetSemanticModelForNodeAsync(simpleName, cancellationToken).ConfigureAwait(false);

            var leftSymbol = beforeDotExpression == null
                ? null
                : semanticModel.GetSymbolInfo(beforeDotExpression, cancellationToken).GetAnySymbol() as INamespaceOrTypeSymbol;
            var leftType = beforeDotExpression == null
                ? null
                : semanticModel.GetTypeInfo(beforeDotExpression, cancellationToken).Type as INamespaceOrTypeSymbol;

            var leftContainer = leftSymbol ?? leftType;

            var isBaseAccess = beforeDotExpression is BaseExpressionSyntax;
            var namespacesOrTypesOnly = SyntaxFacts.IsInNamespaceOrTypeContext(simpleName);
            var includeExtensions = leftSymbol == null && leftType != null;
            var name = genericIdentifier.ValueText;
            var symbols = isBaseAccess
                ? semanticModel.LookupBaseMembers(position, name)
                : namespacesOrTypesOnly
                    ? semanticModel.LookupNamespacesAndTypes(position, leftContainer, name)
                    : semanticModel.LookupSymbols(position, leftContainer, name, includeExtensions);

            var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken);
            if (within == null)
            {
                return null;
            }

            var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>();
            var accessibleSymbols =
                symbols.Where(s => s.GetArity() > 0)
                       .Where(s => s is INamedTypeSymbol || s is IMethodSymbol)
                       .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation)
                       .Sort(symbolDisplayService, semanticModel, genericIdentifier.SpanStart);

            if (!accessibleSymbols.Any())
            {
                return null;
            }

            var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>();
            var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>();
            var textSpan = GetTextSpan(genericIdentifier, lessThanToken);
            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();

            return CreateSignatureHelpItems(accessibleSymbols.Select(s =>
                Convert(s, lessThanToken, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, cancellationToken)).ToList(),
                textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken));
        }
        protected static async Task<ImmutableArray<ReferenceLocation>> FindReferencesInDocumentUsingIdentifierAsync(
            string identifier,
            Document document,
            Func<SyntaxToken, SemanticModel, ValueTuple<bool, CandidateReason>> symbolsMatch,
            CancellationToken cancellationToken)
        {
            var tokens = await document.GetIdentifierOrGlobalNamespaceTokensWithTextAsync(identifier, cancellationToken).ConfigureAwait(false);

            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
            Func<SyntaxToken, bool> tokensMatch = t => IdentifiersMatch(syntaxFacts, identifier, t);

            return await FindReferencesInTokensAsync(
                document,
                tokens,
                tokensMatch,
                symbolsMatch,
                cancellationToken).ConfigureAwait(false);
        }
Пример #20
0
        internal override Document AddImports(
            Document document, int position, XElement snippetNode,
            bool placeSystemNamespaceFirst, CancellationToken cancellationToken)
        {
            var importsNode = snippetNode.Element(XName.Get("Imports", snippetNode.Name.NamespaceName));
            if (importsNode == null ||
                !importsNode.HasElements)
            {
                return document;
            }

            var root = document.GetSyntaxRootSynchronously(cancellationToken);
            var contextLocation = root.FindToken(position).Parent;

            var newUsingDirectives = GetUsingDirectivesToAdd(contextLocation, snippetNode, importsNode, cancellationToken);
            if (!newUsingDirectives.Any())
            {
                return document;
            }

            // In Venus/Razor, inserting imports statements into the subject buffer does not work.
            // Instead, we add the imports through the contained language host.
            if (TryAddImportsToContainedDocument(document, newUsingDirectives.Where(u => u.Alias == null).Select(u => u.Name.ToString())))
            {
                return document;
            }

            var addImportService = document.GetLanguageService<IAddImportsService>();
            var compilation = document.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var newRoot = addImportService.AddImports(compilation, root, contextLocation, newUsingDirectives, placeSystemNamespaceFirst);

            var newDocument = document.WithSyntaxRoot(newRoot);

            var formattedDocument = Formatter.FormatAsync(newDocument, Formatter.Annotation, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);
            document.Project.Solution.Workspace.ApplyDocumentChanges(formattedDocument, cancellationToken);

            return formattedDocument;
        }
        private static async Task<ImmutableArray<ReferenceLocation>> FindReferencesThroughAliasSymbolsAsync(
            ISymbol symbol,
            Document document,
            ImmutableArray<IAliasSymbol> aliasSymbols,
            Func<SyntaxToken, SemanticModel, ValueTuple<bool, CandidateReason>> symbolsMatch,
            CancellationToken cancellationToken)
        {
            var syntaxFactsService = document.GetLanguageService<ISyntaxFactsService>();
            var allAliasReferences = ArrayBuilder<ReferenceLocation>.GetInstance();
            foreach (var aliasSymbol in aliasSymbols)
            {
                var aliasReferences = await FindReferencesInDocumentUsingIdentifierAsync(aliasSymbol.Name, document, symbolsMatch, cancellationToken).ConfigureAwait(false);
                allAliasReferences.AddRange(aliasReferences);

                // the alias may reference an attribute and the alias name may end with an "Attribute" suffix. In this case search for the
                // shortened name as well (e.g. using FooAttribute = MyNamespace.FooAttribute; [Foo] class C1 {})
                string simpleName;
                if (TryGetNameWithoutAttributeSuffix(aliasSymbol.Name, syntaxFactsService, out simpleName))
                {
                    aliasReferences = await FindReferencesInDocumentUsingIdentifierAsync(simpleName, document, symbolsMatch, cancellationToken).ConfigureAwait(false);
                    allAliasReferences.AddRange(aliasReferences);
                }
            }

            return allAliasReferences.ToImmutableAndFree();
        }
        private static Dictionary<string, List<int>> CreateIdentifierLocations(Document document, SyntaxNode root, CancellationToken cancellationToken)
        {
            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();

            var identifierMap = SharedPools.StringIgnoreCaseDictionary<List<int>>().AllocateAndClear();
            foreach (var token in root.DescendantTokens(descendIntoTrivia: true))
            {
                if (token.IsMissing || token.Span.Length == 0)
                {
                    continue;
                }

                if (syntaxFacts.IsIdentifier(token) || syntaxFacts.IsGlobalNamespaceKeyword(token))
                {
                    var valueText = token.ValueText;
                    identifierMap.GetOrAdd(valueText, _ => SharedPools.BigDefault<List<int>>().AllocateAndClear()).Add(token.Span.Start);
                }
            }

            return identifierMap;
        }
            private async Task<ClassifiedSpansAndHighlightSpan> GetTaggedTextForReferenceAsync(
                Document document, TextSpan referenceSpan, TextSpan widenedSpan)
            {
                var classificationService = document.GetLanguageService<IEditorClassificationService>();
                if (classificationService == null)
                {
                    return new ClassifiedSpansAndHighlightSpan(ImmutableArray<ClassifiedSpan>.Empty, new TextSpan());
                }

                // Call out to the individual language to classify the chunk of text around the
                // reference. We'll get both the syntactic and semantic spans for this region.
                // Because the semantic tags may override the semantic ones (for example, 
                // "DateTime" might be syntactically an identifier, but semantically a struct
                // name), we'll do a later merging step to get the final correct list of 
                // classifications.  For tagging, normally the editor handles this.  But as
                // we're producing the list of Inlines ourselves, we have to handles this here.
                var syntaxSpans = new List<ClassifiedSpan>();
                var semanticSpans = new List<ClassifiedSpan>();

                var sourceText = await document.GetTextAsync(CancellationToken).ConfigureAwait(false);

                await classificationService.AddSyntacticClassificationsAsync(
                    document, widenedSpan, syntaxSpans, CancellationToken).ConfigureAwait(false);
                await classificationService.AddSemanticClassificationsAsync(
                    document, widenedSpan, semanticSpans, CancellationToken).ConfigureAwait(false);

                var classifiedSpans = MergeClassifiedSpans(
                    syntaxSpans, semanticSpans, widenedSpan, sourceText);

                var highlightSpan = new TextSpan(
                    start: referenceSpan.Start - widenedSpan.Start,
                    length: referenceSpan.Length);

                return new ClassifiedSpansAndHighlightSpan(classifiedSpans, highlightSpan);
            }
Пример #24
0
        private bool TryGetTextForOperator(SyntaxToken token, Document document, out string text)
        {
            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
            if (syntaxFacts.IsOperator(token) || syntaxFacts.IsPredefinedOperator(token) || SyntaxFacts.IsAssignmentExpressionOperatorToken(token.Kind()))
            {
                text = Keyword(syntaxFacts.GetText(token.RawKind));
                return true;
            }

            if (token.IsKind(SyntaxKind.ColonColonToken))
            {
                text = "::_CSharpKeyword";
                return true;
            }

            if (token.Kind() == SyntaxKind.ColonToken && token.Parent is NameColonSyntax)
            {
                text = "cs_namedParameter";
                return true;
            }

            if (token.IsKind(SyntaxKind.QuestionToken) && token.Parent is ConditionalExpressionSyntax)
            {
                text = "?_CSharpKeyword";
                return true;
            }

            if (token.IsKind(SyntaxKind.EqualsGreaterThanToken))
            {
                text = "=>_CSharpKeyword";
                return true;
            }

            if (token.IsKind(SyntaxKind.PlusEqualsToken))
            {
                text = "+=_CSharpKeyword";
                return true;
            }

            if (token.IsKind(SyntaxKind.MinusEqualsToken))
            {
                text = "-=_CSharpKeyword";
                return true;
            }

            text = null;
            return false;
        }
Пример #25
0
        private bool TryGetTextForSymbol(SyntaxToken token, SemanticModel semanticModel, Document document, CancellationToken cancellationToken, out string text)
        {
            ISymbol symbol;
            if (token.Parent is TypeArgumentListSyntax)
            {
                var genericName = token.GetAncestor<GenericNameSyntax>();
                symbol = semanticModel.GetSymbolInfo(genericName, cancellationToken).Symbol ?? semanticModel.GetTypeInfo(genericName, cancellationToken).Type;
            }
            else if (token.Parent is NullableTypeSyntax && token.IsKind(SyntaxKind.QuestionToken))
            {
                text = "System.Nullable`1";
                return true;
            }
            else
            {
                var symbols = semanticModel.GetSymbols(token, document.Project.Solution.Workspace, bindLiteralsToUnderlyingType: true, cancellationToken: cancellationToken);
                symbol = symbols.FirstOrDefault();

                if (symbol == null)
                {
                    var bindableParent = document.GetLanguageService<ISyntaxFactsService>().GetBindableParent(token);
                    var overloads = semanticModel.GetMemberGroup(bindableParent);
                    symbol = overloads.FirstOrDefault();
                }
            }

            // Local: return the name if it's the declaration, otherwise the type
            if (symbol is ILocalSymbol && !symbol.DeclaringSyntaxReferences.Any(d => d.GetSyntax().DescendantTokens().Contains(token)))
            {
                symbol = ((ILocalSymbol)symbol).Type;
            }

            // Range variable: use the type
            if (symbol is IRangeVariableSymbol)
            {
                var info = semanticModel.GetTypeInfo(token.Parent, cancellationToken);
                symbol = info.Type;
            }

            // Just use syntaxfacts for operators
            if (symbol is IMethodSymbol && ((IMethodSymbol)symbol).MethodKind == MethodKind.BuiltinOperator)
            {
                text = null;
                return false;
            }

            text = symbol != null ? Format(symbol) : null;
            return symbol != null;
        }
        private async Task<ValueTuple<SemanticModel, IList<ISymbol>>> BindTokenAsync(
            Document document,
            SyntaxToken token,
            CancellationToken cancellationToken)
        {
            var semanticModel = await document.GetSemanticModelForNodeAsync(token.Parent, cancellationToken).ConfigureAwait(false);
            var enclosingType = semanticModel.GetEnclosingNamedType(token.SpanStart, cancellationToken);

            var symbols = semanticModel.GetSymbols(token, document.Project.Solution.Workspace, bindLiteralsToUnderlyingType: true, cancellationToken: cancellationToken);

            var bindableParent = document.GetLanguageService<ISyntaxFactsService>().GetBindableParent(token);
            var overloads = semanticModel.GetMemberGroup(bindableParent, cancellationToken);

            symbols = symbols.Where(IsOk)
                             .Where(s => IsAccessible(s, enclosingType))
                             .Concat(overloads)
                             .Distinct(SymbolEquivalenceComparer.Instance);

            if (symbols.Any())
            {
                var typeParameter = symbols.First() as ITypeParameterSymbol;
                return new ValueTuple<SemanticModel, IList<ISymbol>>(
                    semanticModel,
                    typeParameter != null && typeParameter.TypeParameterKind == TypeParameterKind.Cref
                        ? SpecializedCollections.EmptyList<ISymbol>()
                        : symbols.ToList());
            }

            // Couldn't bind the token to specific symbols.  If it's an operator, see if we can at
            // least bind it to a type.
            var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>();
            if (syntaxFacts.IsOperator(token))
            {
                var typeInfo = semanticModel.GetTypeInfo(token.Parent, cancellationToken);
                if (IsOk(typeInfo.Type))
                {
                    return new ValueTuple<SemanticModel, IList<ISymbol>>(semanticModel, new List<ISymbol>(1) { typeInfo.Type });
                }
            }

            return ValueTuple.Create(semanticModel, SpecializedCollections.EmptyList<ISymbol>());
        }
        /// <summary>
        /// Ensure that an event handler exists for a given event.
        /// </summary>
        /// <param name="thisDocument">The document corresponding to this operation.</param>
        /// <param name="targetDocument">The document to generate the event handler in if it doesn't
        /// exist.</param>
        /// <param name="className">The name of the type to generate the event handler in.</param>
        /// <param name="objectName">The name of the event member (if <paramref
        /// name="useHandlesClause"/> is true)</param>
        /// <param name="objectTypeName">The name of the type containing the event.</param>
        /// <param name="nameOfEvent">The name of the event member in <paramref
        /// name="objectTypeName"/></param>
        /// <param name="eventHandlerName">The name of the method to be hooked up to the
        /// event.</param>
        /// <param name="itemidInsertionPoint">The VS itemid of the file to generate the event
        /// handler in.</param>
        /// <param name="useHandlesClause">If true, a vb "Handles" clause will be generated for the
        /// handler.</param>
        /// <param name="additionalFormattingRule">An additional formatting rule that can be used to
        /// format the newly inserted method</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <returns>Either the unique id of the method if it already exists, or the unique id of
        /// the to be generated method, the text of the to be generated method, and the position in
        /// <paramref name="itemidInsertionPoint"/> where the text should be inserted.</returns>
        public static Tuple<string, string, VsTextSpan> EnsureEventHandler(
            Document thisDocument,
            Document targetDocument,
            string className,
            string objectName,
            string objectTypeName,
            string nameOfEvent,
            string eventHandlerName,
            uint itemidInsertionPoint,
            bool useHandlesClause,
            IFormattingRule additionalFormattingRule,
            CancellationToken cancellationToken)
        {
            var thisCompilation = thisDocument.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var type = thisCompilation.GetTypeByMetadataName(className);

            var existingEventHandlers = GetCompatibleEventHandlers(targetDocument, className, objectTypeName, nameOfEvent, cancellationToken);
            var existingHandler = existingEventHandlers.SingleOrDefault(e => e.Item1 == eventHandlerName);
            if (existingHandler != null)
            {
                return Tuple.Create(existingHandler.Item2, (string)null, default(VsTextSpan));
            }

            // Okay, it doesn't exist yet.  Let's create it.
            var codeGenerationService = targetDocument.GetLanguageService<ICodeGenerationService>();
            var syntaxFactory = targetDocument.GetLanguageService<SyntaxGenerator>();
            var eventMember = GetEventSymbol(thisDocument, objectTypeName, nameOfEvent, type, cancellationToken);
            if (eventMember == null)
            {
                throw new InvalidOperationException();
            }

            var eventType = ((IEventSymbol)eventMember).Type;
            if (eventType.Kind != SymbolKind.NamedType || ((INamedTypeSymbol)eventType).DelegateInvokeMethod == null)
            {
                throw new InvalidOperationException(ServicesVSResources.EventTypeIsInvalid);
            }

            var handlesExpressions = useHandlesClause ?
                new[]
                {
                    syntaxFactory.MemberAccessExpression(
                        objectName != null ? syntaxFactory.IdentifierName(objectName) : syntaxFactory.ThisExpression(),
                        syntaxFactory.IdentifierName(nameOfEvent))
                }
            : null;

            var invokeMethod = ((INamedTypeSymbol)eventType).DelegateInvokeMethod;
            var newMethod = CodeGenerationSymbolFactory.CreateMethodSymbol(
                attributes: null,
                accessibility: Accessibility.Protected,
                modifiers: new DeclarationModifiers(),
                returnType: targetDocument.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken).GetSpecialType(SpecialType.System_Void),
                explicitInterfaceSymbol: null,
                name: eventHandlerName,
                typeParameters: null,
                parameters: invokeMethod.Parameters.ToArray(),
                statements: null,
                handlesExpressions: handlesExpressions);

            var annotation = new SyntaxAnnotation();
            newMethod = annotation.AddAnnotationToSymbol(newMethod);
            var codeModel = targetDocument.Project.LanguageServices.GetService<ICodeModelNavigationPointService>();
            var syntaxFacts = targetDocument.Project.LanguageServices.GetService<ISyntaxFactsService>();

            var targetSyntaxTree = targetDocument.GetSyntaxTreeAsync(cancellationToken).WaitAndGetResult(cancellationToken);

            var position = type.Locations.First(loc => loc.SourceTree == targetSyntaxTree).SourceSpan.Start;
            var destinationType = syntaxFacts.GetContainingTypeDeclaration(targetSyntaxTree.GetRoot(cancellationToken), position);
            var insertionPoint = codeModel.GetEndPoint(destinationType, EnvDTE.vsCMPart.vsCMPartBody);

            if (insertionPoint == null)
            {
                throw new InvalidOperationException(ServicesVSResources.MemberInsertionFailed);
            }

            var newType = codeGenerationService.AddMethod(destinationType, newMethod, new CodeGenerationOptions(autoInsertionLocation: false), cancellationToken);
            var newRoot = targetSyntaxTree.GetRoot(cancellationToken).ReplaceNode(destinationType, newType);

            newRoot = Simplifier.ReduceAsync(targetDocument.WithSyntaxRoot(newRoot), Simplifier.Annotation, null, cancellationToken).WaitAndGetResult(cancellationToken).GetSyntaxRootAsync(cancellationToken).WaitAndGetResult(cancellationToken);

            var formattingRules = additionalFormattingRule.Concat(Formatter.GetDefaultFormattingRules(targetDocument));

            var workspace = targetDocument.Project.Solution.Workspace;
            newRoot = Formatter.Format(newRoot, Formatter.Annotation, workspace, workspace.Options, formattingRules, cancellationToken);

            var newMember = newRoot.GetAnnotatedNodesAndTokens(annotation).Single();
            var newMemberText = newMember.ToFullString();

            // In VB, the final newline is likely a statement terminator in the parent - just add
            // one on so that things don't get messed.
            if (!newMemberText.EndsWith(Environment.NewLine, StringComparison.Ordinal))
            {
                newMemberText += Environment.NewLine;
            }

            return Tuple.Create(ConstructMemberId(newMethod), newMemberText, insertionPoint.Value.ToVsTextSpan());
        }