コード例 #1
0
		private async Task<IEnumerable<CompletionData>> GetSpeculativeTCompletions(CompletionEngine engine, Document document, int position, CancellationToken cancellationToken)
		{
			var syntaxTree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
			if (syntaxTree.IsInNonUserCode(position, cancellationToken) ||
				syntaxTree.IsPreProcessorDirectiveContext(position, cancellationToken))
			{
				return Enumerable.Empty<CompletionData>();
			}

			// If we're in a generic type argument context, use the start of the generic type name
			// as the position for the rest of the context checks.
			int testPosition = position;
			var leftToken = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken);

			var semanticModel = await document.GetCSharpSemanticModelForNodeAsync(leftToken.Parent, cancellationToken).ConfigureAwait(false);
			if (syntaxTree.IsGenericTypeArgumentContext(position, leftToken, cancellationToken, semanticModel))
			{
				// Walk out until we find the start of the partial written generic
				SyntaxToken nameToken;
				while (syntaxTree.IsInPartiallyWrittenGeneric(testPosition, cancellationToken, out nameToken))
				{
					testPosition = nameToken.SpanStart;
				}

				// If the user types Foo<T, automatic brace completion will insert the close brace
				// and the generic won't be "partially written".
				if (testPosition == position)
				{
					var typeArgumentList = leftToken.GetAncestor<TypeArgumentListSyntax>();
					if (typeArgumentList != null)
					{
						if (typeArgumentList.LessThanToken != default(SyntaxToken) && typeArgumentList.GreaterThanToken != default(SyntaxToken))
						{
							testPosition = typeArgumentList.LessThanToken.SpanStart;
						}
					}
				}
			}

			if ((!leftToken.GetPreviousTokenIfTouchingWord(position).IsKindOrHasMatchingText(SyntaxKind.AsyncKeyword) &&
				syntaxTree.IsMemberDeclarationContext(testPosition, contextOpt: null, validModifiers: SyntaxKindSet.AllMemberModifiers, validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructTypeDeclarations, canBePartial: false, cancellationToken: cancellationToken)) ||
				syntaxTree.IsGlobalMemberDeclarationContext(testPosition, SyntaxKindSet.AllGlobalMemberModifiers, cancellationToken) ||
				syntaxTree.IsGlobalStatementContext(testPosition, cancellationToken) ||
				syntaxTree.IsDelegateReturnTypeContext(testPosition, syntaxTree.FindTokenOnLeftOfPosition(testPosition, cancellationToken), cancellationToken))
			{
				const string T = "T";
				return new [] { engine.Factory.CreateGenericData (this, T, GenericDataType.Undefined) };
			}
			return Enumerable.Empty<CompletionData>();
		}
		public override async Task<bool> IsExclusiveAsync (Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
		{
			// We're exclusive if this context could only be an object initializer and not also a
			// collection initializer. If we're initializing something that could be initialized as
			// an object or as a collection, say we're not exclusive. That way the rest of
			// intellisense can be used in the collection intitializer.
			// 
			// Consider this case:

			// class c : IEnumerable<int> 
			// { 
			// public void Add(int addend) { }
			// public int foo; 
			// }

			// void foo()
			// {
			//    var b = new c {|
			// }

			// There we could initialize b using either an object initializer or a collection
			// initializer. Since we don't know which the user will use, we'll be non-exclusive, so
			// the other providers can help the user write the collection initializer, if they want
			// to.
			var tree = await document.GetCSharpSyntaxTreeAsync (cancellationToken).ConfigureAwait (false);

			if (tree.IsInNonUserCode (position, cancellationToken)) {
				return false;
			}

			var token = tree.FindTokenOnLeftOfPosition (position, cancellationToken);
			token = token.GetPreviousTokenIfTouchingWord (position);

			if (token.Parent == null) {
				return false;
			}

			var expression = token.Parent.Parent as ExpressionSyntax;
			if (expression == null) {
				return false;
			}

			var semanticModel = await document.GetCSharpSemanticModelForNodeAsync (expression, cancellationToken).ConfigureAwait (false);
			var initializedType = semanticModel.GetTypeInfo (expression, cancellationToken).Type;
			if (initializedType == null) {
				return false;
			}

			// Non-exclusive if initializedType can be initialized as a collection.
			if (initializedType.CanSupportCollectionInitializer ()) {
				return false;
			}

			// By default, only our member names will show up.
			return true;
		}
コード例 #3
0
        private 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 && triggerInfo.IsImmediateWindow)
                {
                    // Aggressive Intellisense in the debugger: always show the builder 
                    return new CompletionItem(this, "", CompletionUtilities.GetTextChangeSpan(text, position), isBuilder: true);
                }

                var tree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
                var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken);
                token = token.GetPreviousTokenIfTouchingWord(position);
                if (token.Kind() == SyntaxKind.None)
                {
                    return null;
                }

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

                if (IsLambdaExpression(semanticModel, position, token, typeInferrer, cancellationToken))
                {
                    return new CompletionItem(this, CSharpFeaturesResources.LambdaExpression,
                        CompletionUtilities.GetTextChangeSpan(text, position),
                        CSharpFeaturesResources.AutoselectDisabledDueToPotentialLambdaDeclaration.ToSymbolDisplayParts(),
                        isBuilder: true);
                }
                else if (IsAnonymousObjectCreation(token))
                {
                    return new CompletionItem(this, CSharpFeaturesResources.MemberName,
                        CompletionUtilities.GetTextChangeSpan(text, position),
                        CSharpFeaturesResources.AutoselectDisabledDueToPossibleExplicitlyNamesAnonTypeMemCreation.ToSymbolDisplayParts(),
                        isBuilder: true);
                }
                else if (token.IsPreProcessorExpressionContext())
                {
                    return new CompletionItem(this, "", CompletionUtilities.GetTextChangeSpan(text, position), isBuilder: true);
                }
                else if (IsImplicitArrayCreation(semanticModel, token, position, typeInferrer, cancellationToken))
                {
                    return new CompletionItem(this, CSharpFeaturesResources.ImplicitArrayCreation,
                        CompletionUtilities.GetTextChangeSpan(text, position),
                        CSharpFeaturesResources.AutoselectDisabledDueToPotentialImplicitArray.ToSymbolDisplayParts(),
                        isBuilder: true);
                }
                else
                {
                    return token.IsKindOrHasMatchingText(SyntaxKind.FromKeyword) || token.IsKindOrHasMatchingText(SyntaxKind.JoinKeyword)
                        ? new CompletionItem(this, CSharpFeaturesResources.RangeVariable,
                            CompletionUtilities.GetTextChangeSpan(text, position),
                            CSharpFeaturesResources.AutoselectDisabledDueToPotentialRangeVariableDecl.ToSymbolDisplayParts(),
                        isBuilder: true)
                        : null;
                }
            }

            return null;
        }
        protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(
            Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var syntaxTree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
            if (syntaxTree.IsInNonUserCode(position, cancellationToken))
            {
                return null;
            }

            var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken);
            token = token.GetPreviousTokenIfTouchingWord(position);

            if (token.Kind() != SyntaxKind.OpenParenToken && token.Kind() != SyntaxKind.CommaToken)
            {
                return null;
            }

            var attributeArgumentList = token.Parent as AttributeArgumentListSyntax;
            var attributeSyntax = token.Parent.Parent as AttributeSyntax;
            if (attributeSyntax == null || attributeArgumentList == null)
            {
                return null;
            }

            // We actually want to collect two sets of named parameters to present the user.  The
            // normal named parameters that come from the attribute constructors.  These will be
            // presented like "foo:".  And also the named parameters that come from the writable
            // fields/properties in the attribute.  These will be presented like "bar =".  

            var existingNamedParameters = GetExistingNamedParameters(attributeArgumentList, position);

            var workspace = document.Project.Solution.Workspace;
            var semanticModel = await document.GetCSharpSemanticModelForNodeAsync(attributeSyntax, cancellationToken).ConfigureAwait(false);
            var nameColonItems = await GetNameColonItemsAsync(workspace, semanticModel, position, token, attributeSyntax, existingNamedParameters, cancellationToken).ConfigureAwait(false);
            var nameEqualsItems = await GetNameEqualsItemsAsync(workspace, semanticModel, position, token, attributeSyntax, existingNamedParameters, cancellationToken).ConfigureAwait(false);

            // If we're after a name= parameter, then we only want to show name= parameters.
            if (IsAfterNameEqualsArgument(token))
            {
                return nameEqualsItems;
            }

            return nameColonItems.Concat(nameEqualsItems);
        }