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; }
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); }