Skip to content

Commit

Permalink
Wrap completion providers logic in exception filters
Browse files Browse the repository at this point in the history
  • Loading branch information
tmat committed Dec 6, 2017
1 parent 9503de7 commit 1c7d5e0
Show file tree
Hide file tree
Showing 18 changed files with 720 additions and 580 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Microsoft.CodeAnalysis.Completion.Providers;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
Expand All @@ -34,55 +35,62 @@ internal override bool IsInsertionTrigger(SourceText text, int characterPosition

public override async Task ProvideCompletionsAsync(CompletionContext context)
{
var document = context.Document;
var position = context.Position;
var cancellationToken = context.CancellationToken;

var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
if (syntaxTree.IsInNonUserCode(position, cancellationToken))
try
{
return;
}
var document = context.Document;
var position = context.Position;
var cancellationToken = context.CancellationToken;

var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken);
token = token.GetPreviousTokenIfTouchingWord(position);
var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
if (syntaxTree.IsInNonUserCode(position, cancellationToken))
{
return;
}

if (!token.IsKind(SyntaxKind.OpenParenToken, SyntaxKind.CommaToken))
{
return;
}
var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken);
token = token.GetPreviousTokenIfTouchingWord(position);

var attributeArgumentList = token.Parent as AttributeArgumentListSyntax;
var attributeSyntax = token.Parent.Parent as AttributeSyntax;
if (attributeSyntax == null || attributeArgumentList == null)
{
return;
}
if (!token.IsKind(SyntaxKind.OpenParenToken, SyntaxKind.CommaToken))
{
return;
}

if (IsAfterNameColonArgument(token) || IsAfterNameEqualsArgument(token))
{
context.IsExclusive = true;
}
var attributeArgumentList = token.Parent as AttributeArgumentListSyntax;
var attributeSyntax = token.Parent.Parent as AttributeSyntax;
if (attributeSyntax == null || attributeArgumentList == null)
{
return;
}

if (IsAfterNameColonArgument(token) || IsAfterNameEqualsArgument(token))
{
context.IsExclusive = true;
}

// 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 "goo:". And also the named parameters that come from the writable
// fields/properties in the attribute. These will be presented like "bar =".
// 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 "goo:". 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 existingNamedParameters = GetExistingNamedParameters(attributeArgumentList, position);

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

context.AddItems(nameEqualsItems);
context.AddItems(nameEqualsItems);

// If we're after a name= parameter, then we only want to show name= parameters.
// Otherwise, show name: parameters too.
if (!IsAfterNameEqualsArgument(token))
// If we're after a name= parameter, then we only want to show name= parameters.
// Otherwise, show name: parameters too.
if (!IsAfterNameEqualsArgument(token))
{
context.AddItems(nameColonItems);
}
}
catch (Exception e) when (FatalError.ReportWithoutCrashUnlessCanceled(e))
{
context.AddItems(nameColonItems);
// nop
}
}

Expand Down Expand Up @@ -233,7 +241,7 @@ private IEnumerable<ISymbol> GetAttributeNamedParameters(
}

private TextChange? GetTextChange(CompletionItem selectedItem, char? ch)
{
{
var displayText = selectedItem.DisplayText;

if (ch != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Completion.Providers;
using System;
using Microsoft.CodeAnalysis.ErrorReporting;

namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers
{
Expand Down Expand Up @@ -69,29 +70,36 @@ internal override bool IsInsertionTrigger(SourceText text, int characterPosition

public override async Task ProvideCompletionsAsync(CompletionContext context)
{
var document = context.Document;
var position = context.Position;
var options = context.Options;
var cancellationToken = context.CancellationToken;
try
{
var document = context.Document;
var position = context.Position;
var options = context.Options;
var cancellationToken = context.CancellationToken;

var (token, semanticModel, symbols) = await GetSymbolsAsync(document, position, options, cancellationToken).ConfigureAwait(false);
var (token, semanticModel, symbols) = await GetSymbolsAsync(document, position, options, cancellationToken).ConfigureAwait(false);

if (symbols.Length == 0)
{
return;
}
if (symbols.Length == 0)
{
return;
}

context.IsExclusive = true;
context.IsExclusive = true;

var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var span = GetCompletionItemSpan(text, position);
var hideAdvancedMembers = options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language);
var serializedOptions = ImmutableDictionary<string, string>.Empty.Add(HideAdvancedMembers, hideAdvancedMembers.ToString());
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var span = GetCompletionItemSpan(text, position);
var hideAdvancedMembers = options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language);
var serializedOptions = ImmutableDictionary<string, string>.Empty.Add(HideAdvancedMembers, hideAdvancedMembers.ToString());

var items = CreateCompletionItems(document.Project.Solution.Workspace,
semanticModel, symbols, token, span, position, serializedOptions);
var items = CreateCompletionItems(document.Project.Solution.Workspace,
semanticModel, symbols, token, span, position, serializedOptions);

context.AddItems(items);
context.AddItems(items);
}
catch (Exception e) when (FatalError.ReportWithoutCrashUnlessCanceled(e))
{
// nop
}
}

protected override async Task<(SyntaxToken, SemanticModel, ImmutableArray<ISymbol>)> GetSymbolsAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
Expand All @@ -27,39 +28,46 @@ internal override bool IsInsertionTrigger(SourceText text, int insertedCharacter

public override async Task ProvideCompletionsAsync(CompletionContext completionContext)
{
var position = completionContext.Position;
var document = completionContext.Document;
var cancellationToken = completionContext.CancellationToken;
var semanticModel = await document.GetSemanticModelForSpanAsync(new Text.TextSpan(position, 0), cancellationToken).ConfigureAwait(false);

if (!completionContext.Options.GetOption(CompletionOptions.ShowNameSuggestions, LanguageNames.CSharp))
try
{
return;
}
var position = completionContext.Position;
var document = completionContext.Document;
var cancellationToken = completionContext.CancellationToken;
var semanticModel = await document.GetSemanticModelForSpanAsync(new Text.TextSpan(position, 0), cancellationToken).ConfigureAwait(false);

var context = CSharpSyntaxContext.CreateContext(document.Project.Solution.Workspace, semanticModel, position, cancellationToken);
if (context.IsInNonUserCode)
{
return;
}
if (!completionContext.Options.GetOption(CompletionOptions.ShowNameSuggestions, LanguageNames.CSharp))
{
return;
}

var nameInfo = await NameDeclarationInfo.GetDeclarationInfo(document, position, cancellationToken).ConfigureAwait(false);
var baseNames = GetBaseNames(semanticModel, nameInfo);
if (baseNames == default)
{
return;
}
var context = CSharpSyntaxContext.CreateContext(document.Project.Solution.Workspace, semanticModel, position, cancellationToken);
if (context.IsInNonUserCode)
{
return;
}

var recommendedNames = await GetRecommendedNamesAsync(baseNames, nameInfo, context, document, cancellationToken).ConfigureAwait(false);
int sortValue = 0;
foreach (var (name, kind) in recommendedNames)
var nameInfo = await NameDeclarationInfo.GetDeclarationInfo(document, position, cancellationToken).ConfigureAwait(false);
var baseNames = GetBaseNames(semanticModel, nameInfo);
if (baseNames == default)
{
return;
}

var recommendedNames = await GetRecommendedNamesAsync(baseNames, nameInfo, context, document, cancellationToken).ConfigureAwait(false);
int sortValue = 0;
foreach (var (name, kind) in recommendedNames)
{
// We've produced items in the desired order, add a sort text to each item to prevent alphabetization
completionContext.AddItem(CreateCompletionItem(name, GetGlyph(kind, nameInfo.DeclaredAccessibility), sortValue.ToString("D8")));
sortValue++;
}

completionContext.SuggestionModeItem = CommonCompletionItem.Create(CSharpFeaturesResources.Name, CompletionItemRules.Default);
}
catch (Exception e) when (FatalError.ReportWithoutCrashUnlessCanceled(e))
{
// We've produced items in the desired order, add a sort text to each item to prevent alphabetization
completionContext.AddItem(CreateCompletionItem(name, GetGlyph(kind, nameInfo.DeclaredAccessibility), sortValue.ToString("D8")));
sortValue++;
// nop
}

completionContext.SuggestionModeItem = CommonCompletionItem.Create(CSharpFeaturesResources.Name, CompletionItemRules.Default);
}

private ImmutableArray<ImmutableArray<string>> GetBaseNames(SemanticModel semanticModel, NameDeclarationInfo nameInfo)
Expand Down
Loading

0 comments on commit 1c7d5e0

Please sign in to comment.