ObjectCreationCompletionProvider.cs 5.3 KB
Newer Older
1 2 3
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System.Collections.Generic;
M
Matt Warren 已提交
4
using System.Collections.Immutable;
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Completion.Providers;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers
{
21
    internal partial class ObjectCreationCompletionProvider : AbstractObjectCreationCompletionProvider
22
    {
M
Matt Warren 已提交
23
        internal override bool IsInsertionTrigger(SourceText text, int characterPosition, OptionSet options)
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
        {
            return CompletionUtilities.IsTriggerAfterSpaceOrStartOfWordCharacter(text, characterPosition, options);
        }

        protected override SyntaxNode GetObjectCreationNewExpression(SyntaxTree tree, int position, CancellationToken cancellationToken)
        {
            if (tree != null)
            {
                if (!tree.IsInNonUserCode(position, cancellationToken))
                {
                    var tokenOnLeftOfPosition = tree.FindTokenOnLeftOfPosition(position, cancellationToken);
                    var newToken = tokenOnLeftOfPosition.GetPreviousTokenIfTouchingWord(position);

                    // Only after 'new'.
                    if (newToken.Kind() == SyntaxKind.NewKeyword)
                    {
                        // Only if the 'new' belongs to an object creation expression (and isn't a 'new'
                        // modifier on a member).
                        if (tree.IsObjectCreationTypeContext(position, tokenOnLeftOfPosition, cancellationToken))
                        {
                            return newToken.Parent as ExpressionSyntax;
                        }
                    }
                }
            }

            return null;
        }

C
CyrusNajmabadi 已提交
53
        protected override async Task<SyntaxContext> CreateContext(Document document, int position, CancellationToken cancellationToken)
54
        {
D
Dustin Campbell 已提交
55
            var semanticModel = await document.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken).ConfigureAwait(false);
56 57 58
            return CSharpSyntaxContext.CreateContext(document.Project.Solution.Workspace, semanticModel, position, cancellationToken);
        }

C
CyrusNajmabadi 已提交
59
        protected override async Task<IEnumerable<ISymbol>> GetPreselectedSymbolsWorker(SyntaxContext context, int position, OptionSet options, CancellationToken cancellationToken)
60 61 62 63 64 65 66 67 68 69 70
        {
            var result = await base.GetPreselectedSymbolsWorker(context, position, options, cancellationToken).ConfigureAwait(false);
            if (result.Any())
            {
                var type = (ITypeSymbol)result.Single();
                var alias = await type.FindApplicableAlias(position, context.SemanticModel, cancellationToken).ConfigureAwait(false);
                if (alias != null)
                {
                    return SpecializedCollections.SingletonEnumerable(alias);
                }
            }
71

72 73 74
            return result;
        }

C
CyrusNajmabadi 已提交
75
        protected override ValueTuple<string, string> GetDisplayAndInsertionText(ISymbol symbol, SyntaxContext context)
76 77 78 79 80 81 82 83
        {
            if (symbol is IAliasSymbol)
            {
                return ValueTuple.Create(symbol.Name, symbol.Name);
            }

            return base.GetDisplayAndInsertionText(symbol, context);
        }
84

85
        private static readonly CompletionItemRules s_objectRules =
86 87
            CompletionItemRules.Create(
                commitCharacterRules: ImmutableArray.Create(CharacterSetModificationRule.Create(CharacterSetModificationKind.Replace, ' ', '(', '[')),
88
                matchPriority: MatchPriority.Preselect,
89
                selectionBehavior: CompletionItemSelectionBehavior.HardSelection);
M
Matt Warren 已提交
90

91
        private static readonly CompletionItemRules s_defaultRules =
92 93
            CompletionItemRules.Create(
                commitCharacterRules: ImmutableArray.Create(CharacterSetModificationRule.Create(CharacterSetModificationKind.Replace, ' ', '(', '[', '{')),
94
                matchPriority: MatchPriority.Preselect,
95
                selectionBehavior: CompletionItemSelectionBehavior.HardSelection);
M
Matt Warren 已提交
96

C
CyrusNajmabadi 已提交
97
        protected override CompletionItemRules GetCompletionItemRules(IReadOnlyList<ISymbol> symbols, SyntaxContext context)
98
        {
M
Matt Warren 已提交
99 100 101 102 103 104 105 106 107 108 109
            // SPECIAL: If the preselected symbol is System.Object, don't commit on '{'.
            // Otherwise, it is cumbersome to type an anonymous object when the target type is object.
            // The user would get 'new object {' rather than 'new {'. Since object doesn't have any
            // properties, the user never really wants to commit 'new object {' anyway.
            var namedTypeSymbol = symbols.Count > 0 ? symbols[0] as INamedTypeSymbol : null;
            if (namedTypeSymbol?.SpecialType == SpecialType.System_Object)
            {
                return s_objectRules;
            }

            return s_defaultRules;
110
        }
111
    }
112
}