protected override int GetAdjustedContextPoint(int contextPoint, Document document) { // Determine the position in the buffer at which to end the tracking span representing // the part of the imagininary buffer before the text in the view. var tree = document.GetCSharpSyntaxTreeAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); var token = tree.FindTokenOnLeftOfPosition(contextPoint, CancellationToken.None); // Special case to handle class designer because it asks for debugger IntelliSense using // spans between members. if (contextPoint > token.Span.End && token.IsKindOrHasMatchingText(SyntaxKind.CloseBraceToken) && token.Parent.IsKind(SyntaxKind.Block) && token.Parent.Parent is MemberDeclarationSyntax) { return contextPoint; } if (token.IsKindOrHasMatchingText(SyntaxKind.CloseBraceToken) && token.Parent.IsKind(SyntaxKind.Block)) { return token.SpanStart; } return token.FullSpan.End; }
internal static async Task<DebugLocationInfo> GetInfoAsync(Document document, int position, CancellationToken cancellationToken) { string name = null; int lineOffset = 0; // Note that we get the current partial solution here. Technically, this means that we may // not fully understand the signature of the member. But that's ok. We just need this // symbol so we can create a display string to put into the debugger. If we try to // find the document in the "CurrentSolution" then when we try to get the semantic // model below then it might take a *long* time as all dependent compilations are built. var tree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position); SyntaxNode memberDecl = token.GetAncestor<MemberDeclarationSyntax>(); // field or event field declarations may contain multiple variable declarators. Try finding the correct one. // If the position does not point to one, try using the first one. if (memberDecl != null && (memberDecl.Kind() == SyntaxKind.FieldDeclaration || memberDecl.Kind() == SyntaxKind.EventFieldDeclaration)) { SeparatedSyntaxList<VariableDeclaratorSyntax> variableDeclarators = ((BaseFieldDeclarationSyntax)memberDecl).Declaration.Variables; foreach (var declarator in variableDeclarators) { if (declarator.FullSpan.Contains(token.FullSpan)) { memberDecl = declarator; break; } } if (memberDecl == null) { memberDecl = variableDeclarators.Count > 0 ? variableDeclarators[0] : null; } } if (memberDecl != null) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var memberSymbol = semanticModel.GetDeclaredSymbol(memberDecl, cancellationToken); if (memberSymbol != null) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var lineNumber = text.Lines.GetLineFromPosition(position).LineNumber; var accessor = token.GetAncestor<AccessorDeclarationSyntax>(); var memberLine = accessor == null ? text.Lines.GetLineFromPosition(memberDecl.SpanStart).LineNumber : text.Lines.GetLineFromPosition(accessor.SpanStart).LineNumber; name = memberSymbol.ToDisplayString(s_nameFormat); lineOffset = lineNumber - memberLine; return new DebugLocationInfo(name, lineOffset); } } return default(DebugLocationInfo); }
public async Task<IList<string>> GetProximityExpressionsAsync( Document document, int position, CancellationToken cancellationToken) { var tree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); return Do(tree, position, cancellationToken); }
protected override async Task<bool> IsExclusiveAsync(Document document, int caretPosition, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken) { var syntaxTree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var token = syntaxTree.FindTokenOnLeftOfPosition(caretPosition, cancellationToken) .GetPreviousTokenIfTouchingWord(caretPosition); return IsAfterNameColonArgument(token) || IsAfterNameEqualsArgument(token); }
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; }
protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken) { var tree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); // first try to get the #r string literal token. If we couldn't, then we're not in a #r // reference directive and we immediately bail. SyntaxToken stringLiteral; if (!TryGetStringLiteralToken(tree, position, out stringLiteral, cancellationToken)) { return null; } var documentPath = document.Project.IsSubmission ? null : document.FilePath; var textChangeSpan = this.GetTextChangeSpan(stringLiteral, position); var gacHelper = new GlobalAssemblyCacheCompletionHelper(this, textChangeSpan); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var snapshot = text.FindCorrespondingEditorTextSnapshot(); if (snapshot == null) { // Passing null to GetFileSystemDiscoveryService raises an exception. // Instead, return here since there is no longer snapshot for this document. return null; } var assemblyReferenceResolver = document.Project.CompilationOptions.MetadataReferenceResolver as AssemblyReferenceResolver; if (assemblyReferenceResolver == null) { return null; } var metadataFileResolver = assemblyReferenceResolver.PathResolver as MetadataFileReferenceResolver; if (metadataFileResolver == null) { return null; } var fileSystemHelper = new FileSystemCompletionHelper( this, textChangeSpan, GetFileSystemDiscoveryService(snapshot), Glyph.OpenFolder, Glyph.Assembly, searchPaths: metadataFileResolver.SearchPaths, allowableExtensions: new[] { ".dll", ".exe" }, exclude: path => path.Contains(",")); var pathThroughLastSlash = this.GetPathThroughLastSlash(stringLiteral, position); return gacHelper.GetItems(pathThroughLastSlash, documentPath).Concat( fileSystemHelper.GetItems(pathThroughLastSlash, documentPath)); }
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>(); }
protected override int GetContainingClassName(Document document, SnapshotSpan fieldSpan, CancellationToken cancellationToken, ref string value, ref int hasDefaultValue) { // Find the nearest encolsing type declaration and use its name var syntaxTree = document.GetCSharpSyntaxTreeAsync(cancellationToken).WaitAndGetResult(cancellationToken); var type = syntaxTree.FindTokenOnLeftOfPosition(fieldSpan.Start.Position, cancellationToken).GetAncestor<TypeDeclarationSyntax>(); if (type != null) { value = type.Identifier.ToString(); if (!string.IsNullOrWhiteSpace(value)) { hasDefaultValue = 1; } } return VSConstants.S_OK; }
// public async Task<IList<TextChange>> GetFormattingChangesAsync(Document document, char typedChar, int caretPosition, CancellationToken cancellationToken) // { // var formattingRules = this.GetFormattingRules(document, caretPosition); // // // first, find the token user just typed. // SyntaxToken token = await GetTokenBeforeTheCaretAsync(document, caretPosition, cancellationToken).ConfigureAwait(false); // // if (token.IsMissing || // !ValidSingleOrMultiCharactersTokenKind(typedChar, token.Kind()) || // token.IsKind(SyntaxKind.EndOfFileToken, SyntaxKind.None)) // { // return null; // } // // var service = document.GetLanguageService<ISyntaxFactsService>(); // if (service != null && service.IsInNonUserCode(token.SyntaxTree, caretPosition, cancellationToken)) // { // return null; // } // // // Check to see if any of the below. If not, bail. // // case 1: The token is ')' and the parent is an using statement. // // case 2: The token is ':' and the parent is either labelled statement or case switch or default switch // if (TokenShouldNotFormatOnTypeChar(token)) // { // return null; // } // // // if formatting range fails, do format token one at least // var changes = await FormatRangeAsync(document, token, formattingRules, cancellationToken).ConfigureAwait(false); // if (changes.Count > 0) // { // return changes; // } // // // if we can't, do normal smart indentation // return await FormatTokenAsync(document, token, formattingRules, cancellationToken).ConfigureAwait(false); // } public static async Task<SyntaxToken> GetTokenBeforeTheCaretAsync(Document document, int caretPosition, CancellationToken cancellationToken) { var tree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var position = Math.Max(0, caretPosition - 1); var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position, findInsideTrivia: true); return token; }
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; }
internal static async Task<IList<MemberDeclarationSyntax>> GetSelectedMembersAsync( Document document, TextSpan textSpan, CancellationToken cancellationToken) { var tree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); return tree.GetMembersInSpan(textSpan, cancellationToken); }
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); }