Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/aspnetcore.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Newton-King <james@newtonking.com>2022-09-28 05:37:35 +0300
committerJames Newton-King <james@newtonking.com>2022-09-28 05:37:35 +0300
commit99f475daea151302e18d13f0732fb19e36d5357e (patch)
tree5c2cd37e57808ec3481ea6f4c708c852f720f3a7
parent9da05de7b25398e6dcf770f8f6a3b1202f52c67a (diff)
Remove framework parameters completion providerjamesnk/route-syntax-net8-squash
-rw-r--r--src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteEmbeddedLanguage/FrameworkParametersCompletionProvider.cs582
-rw-r--r--src/Framework/AspNetCoreAnalyzers/test/RouteEmbeddedLanguage/FrameworkParametersCompletionProviderTests.cs857
-rw-r--r--src/Framework/AspNetCoreAnalyzers/test/RouteEmbeddedLanguage/RoutePatternParserTests.cs2
3 files changed, 1 insertions, 1440 deletions
diff --git a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteEmbeddedLanguage/FrameworkParametersCompletionProvider.cs b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteEmbeddedLanguage/FrameworkParametersCompletionProvider.cs
deleted file mode 100644
index 01d3932c10..0000000000
--- a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteEmbeddedLanguage/FrameworkParametersCompletionProvider.cs
+++ /dev/null
@@ -1,582 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Composition;
-using System.Diagnostics;
-using System.Globalization;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage.Infrastructure;
-using Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage.Infrastructure.VirtualChars;
-using Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage.RoutePattern;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.Completion;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Options;
-using Microsoft.CodeAnalysis.Tags;
-using Microsoft.CodeAnalysis.Text;
-using Document = Microsoft.CodeAnalysis.Document;
-using RoutePatternToken = Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage.Infrastructure.EmbeddedSyntax.EmbeddedSyntaxToken<Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage.RoutePattern.RoutePatternKind>;
-
-namespace Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage;
-
-[ExportCompletionProvider(nameof(RoutePatternCompletionProvider), LanguageNames.CSharp)]
-[Shared]
-public class FrameworkParametersCompletionProvider : CompletionProvider
-{
- private const string StartKey = nameof(StartKey);
- private const string LengthKey = nameof(LengthKey);
- private const string NewTextKey = nameof(NewTextKey);
- private const string NewPositionKey = nameof(NewPositionKey);
- private const string DescriptionKey = nameof(DescriptionKey);
-
- // Always soft-select these completion items. Also, never filter down.
- private static readonly CompletionItemRules s_rules = CompletionItemRules.Create(
- selectionBehavior: CompletionItemSelectionBehavior.SoftSelection,
- filterCharacterRules: ImmutableArray.Create(CharacterSetModificationRule.Create(CharacterSetModificationKind.Replace, Array.Empty<char>())));
-
- // The space between type and parameter name.
- // void TestMethod(int // <- space after type name
- public ImmutableHashSet<char> TriggerCharacters { get; } = ImmutableHashSet.Create(' ');
-
- public override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, OptionSet options)
- {
- if (trigger.Kind is CompletionTriggerKind.Invoke or CompletionTriggerKind.InvokeAndCommitIfUnique)
- {
- return true;
- }
-
- if (trigger.Kind == CompletionTriggerKind.Insertion)
- {
- return TriggerCharacters.Contains(trigger.Character);
- }
-
- return false;
- }
-
- public override Task<CompletionDescription> GetDescriptionAsync(Document document, CompletionItem item, CancellationToken cancellationToken)
- {
- if (!item.Properties.TryGetValue(DescriptionKey, out var description))
- {
- return Task.FromResult<CompletionDescription>(null);
- }
-
- return Task.FromResult(CompletionDescription.Create(
- ImmutableArray.Create(new TaggedText(TextTags.Text, description))));
- }
-
- public override Task<CompletionChange> GetChangeAsync(Document document, CompletionItem item, char? commitKey, CancellationToken cancellationToken)
- {
- // These values have always been added by us.
- var startString = item.Properties[StartKey];
- var lengthString = item.Properties[LengthKey];
- var newText = item.Properties[NewTextKey];
-
- // This value is optionally added in some cases and may not always be there.
- item.Properties.TryGetValue(NewPositionKey, out var newPositionString);
-
- return Task.FromResult(CompletionChange.Create(
- new TextChange(new TextSpan(int.Parse(startString, CultureInfo.InvariantCulture), int.Parse(lengthString, CultureInfo.InvariantCulture)), newText),
- newPositionString == null ? null : int.Parse(newPositionString, CultureInfo.InvariantCulture)));
- }
-
- public override async Task ProvideCompletionsAsync(CompletionContext context)
- {
- var position = context.Position;
-
- var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
- if (root == null)
- {
- return;
- }
-
- SyntaxToken? parentOpt = null;
-
- var token = root.FindTokenOnLeftOfPosition(position);
-
- // If space is after ? or > then it's likely a nullable or generic type. Move to previous type token.
- if (token.IsKind(SyntaxKind.QuestionToken) || token.IsKind(SyntaxKind.GreaterThanToken))
- {
- token = token.GetPreviousToken();
- }
-
- // Whitespace should follow the identifier token of the parameter.
- if (!IsArgumentTypeToken(token))
- {
- return;
- }
-
- var container = TryFindMinimalApiArgument(token.Parent) ?? TryFindMvcActionParameter(token.Parent);
- if (container == null)
- {
- return;
- }
-
- var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);
- if (semanticModel == null)
- {
- return;
- }
-
- if (!WellKnownTypes.TryGetOrCreate(semanticModel.Compilation, out var wellKnownTypes))
- {
- return;
- }
-
- // Don't offer route parameter names when the parameter type can't be bound to route parameters. e.g. HttpContext.
- var isCurrentParameterSpecialType = IsCurrentParameterNotBindable(token, semanticModel, wellKnownTypes, context.CancellationToken);
- if (isCurrentParameterSpecialType)
- {
- return;
- }
-
- // Don't offer route parameter names when the parameter has an attribute that can't be bound to route parameters.
- // e.g [AsParameters] or [IFromBodyMetadata].
- var hasNonRouteAttribute = HasNonRouteAttribute(token, semanticModel, wellKnownTypes, context.CancellationToken);
- if (hasNonRouteAttribute)
- {
- return;
- }
-
- SyntaxToken routeStringToken;
- SyntaxNode methodNode;
-
- if (container.Parent.IsKind(SyntaxKind.Argument))
- {
- // Minimal API
- var mapMethodParts = RoutePatternUsageDetector.FindMapMethodParts(semanticModel, wellKnownTypes, container, context.CancellationToken);
- if (mapMethodParts == null)
- {
- return;
- }
- var (_, routeStringExpression, delegateExpression) = mapMethodParts.Value;
-
- routeStringToken = routeStringExpression.Token;
- methodNode = delegateExpression;
-
- // Incomplete inline delegate syntax is very messy and arguments are mixed together.
- // Examine tokens to figure out wether the current token is the argument name.
- var previous = token.GetPreviousToken();
- if (previous.IsKind(SyntaxKind.CommaToken) ||
- previous.IsKind(SyntaxKind.OpenParenToken) ||
- previous.IsKind(SyntaxKind.OutKeyword) ||
- previous.IsKind(SyntaxKind.InKeyword) ||
- previous.IsKind(SyntaxKind.RefKeyword) ||
- previous.IsKind(SyntaxKind.ParamsKeyword) ||
- (previous.IsKind(SyntaxKind.CloseBracketToken) && previous.GetRequiredParent().FirstAncestorOrSelf<AttributeListSyntax>() != null) ||
- (previous.IsKind(SyntaxKind.LessThanToken) && previous.GetRequiredParent().FirstAncestorOrSelf<GenericNameSyntax>() != null))
- {
- // Positioned after type token. Don't replace current.
- }
- else
- {
- // Space after argument name. Don't show completion options.
- if (context.Trigger.Kind == CompletionTriggerKind.Insertion)
- {
- return;
- }
-
- parentOpt = token;
- }
- }
- else if (container.IsKind(SyntaxKind.Parameter))
- {
- // MVC
- var methodSyntax = container.FirstAncestorOrSelf<MethodDeclarationSyntax>();
- var methodSymbol = semanticModel.GetDeclaredSymbol(methodSyntax, context.CancellationToken);
-
- // Check method is a valid MVC action.
- if (methodSymbol?.ContainingType is not INamedTypeSymbol typeSymbol ||
- !MvcDetector.IsController(typeSymbol, wellKnownTypes) ||
- !MvcDetector.IsAction(methodSymbol, wellKnownTypes))
- {
- return;
- }
-
- var routeToken = TryGetMvcActionRouteToken(context, semanticModel, methodSyntax);
- if (routeToken == null)
- {
- return;
- }
-
- routeStringToken = routeToken.Value;
- methodNode = methodSyntax;
-
- if (((ParameterSyntax)container).Identifier == token)
- {
- // Space after argument name. Don't show completion options.
- if (context.Trigger.Kind == CompletionTriggerKind.Insertion)
- {
- return;
- }
-
- parentOpt = token;
- }
- }
- else
- {
- return;
- }
-
- var virtualChars = CSharpVirtualCharService.Instance.TryConvertToVirtualChars(routeStringToken);
- var tree = RoutePatternParser.TryParse(virtualChars, supportTokenReplacement: false);
- if (tree == null)
- {
- return;
- }
-
- var routePatternCompletionContext = new EmbeddedCompletionContext(context, tree, wellKnownTypes);
-
- var existingParameterNames = GetExistingParameterNames(methodNode);
- foreach (var parameterName in existingParameterNames)
- {
- routePatternCompletionContext.AddUsedParameterName(parameterName);
- }
-
- ProvideCompletions(routePatternCompletionContext, parentOpt);
-
- if (routePatternCompletionContext.Items == null || routePatternCompletionContext.Items.Count == 0)
- {
- return;
- }
-
- foreach (var embeddedItem in routePatternCompletionContext.Items)
- {
- var change = embeddedItem.Change;
- var textChange = change.TextChange;
-
- var properties = ImmutableDictionary.CreateBuilder<string, string>();
- properties.Add(StartKey, textChange.Span.Start.ToString(CultureInfo.InvariantCulture));
- properties.Add(LengthKey, textChange.Span.Length.ToString(CultureInfo.InvariantCulture));
- properties.Add(NewTextKey, textChange.NewText);
- properties.Add(DescriptionKey, embeddedItem.FullDescription);
-
- if (change.NewPosition != null)
- {
- properties.Add(NewPositionKey, change.NewPosition.ToString());
- }
-
- // Keep everything sorted in the order we just produced the items in.
- var sortText = routePatternCompletionContext.Items.Count.ToString("0000", CultureInfo.InvariantCulture);
- context.AddItem(CompletionItem.Create(
- displayText: embeddedItem.DisplayText,
- inlineDescription: "",
- sortText: sortText,
- properties: properties.ToImmutable(),
- rules: s_rules,
- tags: ImmutableArray.Create(embeddedItem.Glyph)));
- }
-
- context.SuggestionModeItem = CompletionItem.Create(
- displayText: "<Name>",
- inlineDescription: "",
- rules: CompletionItemRules.Default);
-
- context.IsExclusive = true;
- }
-
- private static bool IsArgumentTypeToken(SyntaxToken token)
- {
- return SyntaxFacts.IsPredefinedType(token.Kind()) || token.IsKind(SyntaxKind.IdentifierToken);
- }
-
- private static SyntaxToken? TryGetMvcActionRouteToken(CompletionContext context, SemanticModel? semanticModel, MethodDeclarationSyntax? method)
- {
- foreach (var attributeList in method.AttributeLists)
- {
- foreach (var attribute in attributeList.Attributes)
- {
- foreach (var attributeArgument in attribute.ArgumentList.Arguments)
- {
- if (RouteStringSyntaxDetector.IsArgumentToAttributeParameterWithMatchingStringSyntaxAttribute(
- semanticModel,
- attributeArgument,
- context.CancellationToken,
- out var identifer) &&
- identifer == "Route" &&
- attributeArgument.Expression is LiteralExpressionSyntax literalExpression)
- {
- return literalExpression.Token;
- }
- }
- }
- }
-
- return null;
- }
-
- private static SyntaxNode? TryFindMvcActionParameter(SyntaxNode node)
- {
- var current = node;
- while (current != null)
- {
- if (current.IsKind(SyntaxKind.Parameter))
- {
- return current;
- }
-
- current = current.Parent;
- }
-
- return null;
- }
-
- private static SyntaxNode? TryFindMinimalApiArgument(SyntaxNode node)
- {
- var current = node;
- while (current != null)
- {
- if (current.Parent?.IsKind(SyntaxKind.Argument) ?? false)
- {
- if (current.Parent?.Parent?.IsKind(SyntaxKind.ArgumentList) ?? false)
- {
- return current;
- }
- }
-
- current = current.Parent;
- }
-
- return null;
- }
-
- private static bool HasNonRouteAttribute(SyntaxToken token, SemanticModel semanticModel, WellKnownTypes wellKnownTypes, CancellationToken cancellationToken)
- {
- if (token.Parent?.Parent is ParameterSyntax parameter)
- {
- foreach (var attributeList in parameter.AttributeLists.OfType<AttributeListSyntax>())
- {
- foreach (var attribute in attributeList.Attributes)
- {
- var attributeTypeSymbol = semanticModel.GetSymbolInfo(attribute, cancellationToken).GetAnySymbol();
-
- if (attributeTypeSymbol != null)
- {
- foreach (var nonRouteMetadataType in wellKnownTypes.NonRouteMetadataTypes)
- {
- if (attributeTypeSymbol.ContainingSymbol is ITypeSymbol typeSymbol &&
- typeSymbol.Implements(nonRouteMetadataType))
- {
- return true;
- }
- }
- if (SymbolEqualityComparer.Default.Equals(attributeTypeSymbol.ContainingSymbol, wellKnownTypes.AsParametersAttribute))
- {
- return true;
- }
- }
- }
- }
- }
-
- return false;
- }
-
- private static bool IsCurrentParameterNotBindable(SyntaxToken token, SemanticModel semanticModel, WellKnownTypes wellKnownTypes, CancellationToken cancellationToken)
- {
- if (token.Parent.IsKind(SyntaxKind.PredefinedType))
- {
- return false;
- }
-
- var parameterTypeSymbol = semanticModel.GetSymbolInfo(token.Parent, cancellationToken).GetAnySymbol();
- if (parameterTypeSymbol is INamedTypeSymbol typeSymbol)
- {
- // Check if the parameter type is a minimal API special type. e.g. HttpContext.
- foreach (var specialType in wellKnownTypes.ParameterSpecialTypes)
- {
- if (typeSymbol.IsType(specialType))
- {
- return true;
- }
- }
- }
- else if (parameterTypeSymbol is IMethodSymbol)
- {
- // If the parameter type is a method then the method is bound to the minimal API.
- return true;
- }
-
- return false;
- }
-
- private static ImmutableArray<string> GetExistingParameterNames(SyntaxNode node)
- {
- var builder = ImmutableArray.CreateBuilder<string>();
-
- if (node is TupleExpressionSyntax tupleExpression)
- {
- foreach (var argument in tupleExpression.Arguments)
- {
- if (argument.Expression is DeclarationExpressionSyntax declarationExpression &&
- declarationExpression.Designation is SingleVariableDesignationSyntax variableDesignationSyntax &&
- variableDesignationSyntax.Identifier is { } identifer &&
- !identifer.IsMissing)
- {
- builder.Add(identifer.ValueText);
- }
- }
- }
- else
- {
- var parameterList = node switch
- {
- ParenthesizedLambdaExpressionSyntax parenthesizedLambdaExpression => parenthesizedLambdaExpression.ParameterList,
- MethodDeclarationSyntax methodDeclaration => methodDeclaration.ParameterList,
- _ => null
- };
-
- if (parameterList != null)
- {
- foreach (var p in parameterList.Parameters)
- {
- if (p is ParameterSyntax parameter &&
- parameter.Identifier is { } identifer && !identifer.IsMissing)
- {
- builder.Add(identifer.ValueText);
- }
- }
- }
- }
-
- return builder.ToImmutable();
- }
-
- private static void ProvideCompletions(EmbeddedCompletionContext context, SyntaxToken? parentOpt)
- {
- foreach (var parameterSymbol in context.Tree.RouteParameters)
- {
- context.AddIfMissing(parameterSymbol.Key, suffix: null, description: "(Route parameter)", WellKnownTags.Parameter, parentOpt);
- }
- }
-
- private (RoutePatternNode parent, RoutePatternToken Token)? FindToken(RoutePatternNode parent, VirtualChar ch)
- {
- foreach (var child in parent)
- {
- if (child.IsNode)
- {
- var result = FindToken(child.Node, ch);
- if (result != null)
- {
- return result;
- }
- }
- else
- {
- if (child.Token.VirtualChars.Contains(ch))
- {
- return (parent, child.Token);
- }
- }
- }
-
- return null;
- }
-
- private readonly struct RoutePatternItem
- {
- public readonly string DisplayText;
- public readonly string InlineDescription;
- public readonly string FullDescription;
- public readonly string Glyph;
- public readonly CompletionChange Change;
-
- public RoutePatternItem(
- string displayText, string inlineDescription, string fullDescription, string glyph, CompletionChange change)
- {
- DisplayText = displayText;
- InlineDescription = inlineDescription;
- FullDescription = fullDescription;
- Glyph = glyph;
- Change = change;
- }
- }
-
- private readonly struct EmbeddedCompletionContext
- {
- private readonly CompletionContext _context;
- private readonly HashSet<string> _names = new(StringComparer.OrdinalIgnoreCase);
-
- public readonly RoutePatternTree Tree;
- public readonly WellKnownTypes WellKnownTypes;
- public readonly CancellationToken CancellationToken;
- public readonly int Position;
- public readonly CompletionTrigger Trigger;
- public readonly List<RoutePatternItem> Items = new();
- public readonly CompletionListSpanContainer CompletionListSpan = new();
-
- internal class CompletionListSpanContainer
- {
- public TextSpan? Value { get; set; }
- }
-
- public EmbeddedCompletionContext(
- CompletionContext context,
- RoutePatternTree tree,
- WellKnownTypes wellKnownTypes)
- {
- _context = context;
- Tree = tree;
- WellKnownTypes = wellKnownTypes;
- Position = _context.Position;
- Trigger = _context.Trigger;
- CancellationToken = _context.CancellationToken;
- }
-
- public void AddUsedParameterName(string name)
- {
- _names.Add(name);
- }
-
- public void AddIfMissing(
- string displayText, string suffix, string description, string glyph,
- SyntaxToken? parentOpt, int? positionOffset = null, string insertionText = null)
- {
- var replacementStart = parentOpt != null
- ? parentOpt.Value.GetLocation().SourceSpan.Start
- : Position;
- var replacementEnd = parentOpt != null
- ? parentOpt.Value.GetLocation().SourceSpan.End
- : Position;
-
- var replacementSpan = TextSpan.FromBounds(replacementStart, replacementEnd);
- var newPosition = replacementStart + positionOffset;
-
- insertionText ??= displayText;
-
- AddIfMissing(new RoutePatternItem(
- displayText, suffix, description, glyph,
- CompletionChange.Create(
- new TextChange(replacementSpan, insertionText),
- newPosition)));
- }
-
- public void AddIfMissing(RoutePatternItem item)
- {
- if (_names.Add(item.DisplayText))
- {
- Items.Add(item);
- }
- }
-
- public static string EscapeText(string text, SyntaxToken token)
- {
- // This function is called when Completion needs to escape something its going to
- // insert into the user's string token. This means that we only have to escape
- // things that completion could insert. In this case, the only regex character
- // that is relevant is the \ character, and it's only relevant if we insert into
- // a normal string and not a verbatim string. There are no other regex characters
- // that completion will produce that need any escaping.
- Debug.Assert(token.IsKind(SyntaxKind.StringLiteralToken));
- return token.IsVerbatimStringLiteral()
- ? text
- : text.Replace(@"\", @"\\");
- }
- }
-}
diff --git a/src/Framework/AspNetCoreAnalyzers/test/RouteEmbeddedLanguage/FrameworkParametersCompletionProviderTests.cs b/src/Framework/AspNetCoreAnalyzers/test/RouteEmbeddedLanguage/FrameworkParametersCompletionProviderTests.cs
deleted file mode 100644
index 3812915e67..0000000000
--- a/src/Framework/AspNetCoreAnalyzers/test/RouteEmbeddedLanguage/FrameworkParametersCompletionProviderTests.cs
+++ /dev/null
@@ -1,857 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.IO.Pipelines;
-using System.Security.Claims;
-using Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage.Infrastructure;
-using Microsoft.AspNetCore.Http;
-using Microsoft.CodeAnalysis.Completion;
-
-namespace Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage;
-
-public partial class FrameworkParametersCompletionProviderTests
-{
- private TestDiagnosticAnalyzerRunner Runner { get; } = new(new RoutePatternAnalyzer());
-
- [Fact]
- public async Task Insertion_Space_Int_EndpointMapGet_HasDelegate_ReturnRouteParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (int $$
- }
-}
-");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
-
- var change = await result.Service.GetChangeAsync(result.Document, result.Completions.ItemsList[0]);
- Assert.Equal("id", change.TextChange.NewText);
- Assert.Equal(result.CompletionListSpan, change.TextChange.Span);
- }
-
- [Fact]
- public async Task Insertion_Space_DateTime_EndpointMapGet_HasDelegate_ReturnRouteParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (DateTime $$
- }
-}
-");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
-
- var change = await result.Service.GetChangeAsync(result.Document, result.Completions.ItemsList[0]);
- Assert.Equal("id", change.TextChange.NewText);
- Assert.Equal(result.CompletionListSpan, change.TextChange.Span);
- }
-
- [Fact]
- public async Task Insertion_Space_NullableInt_CloseParen_EndpointMapGet_HasDelegate_ReturnRouteParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (int? $$)
- }
-}
-");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
-
- var change = await result.Service.GetChangeAsync(result.Document, result.Completions.ItemsList[0]);
- Assert.Equal("id", change.TextChange.NewText);
- Assert.Equal(result.CompletionListSpan, change.TextChange.Span);
- }
-
- [Fact]
- public async Task Insertion_Space_NullableInt_EndpointMapGet_HasDelegate_ReturnRouteParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (int? $$
- }
-}
-");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
-
- var change = await result.Service.GetChangeAsync(result.Document, result.Completions.ItemsList[0]);
- Assert.Equal("id", change.TextChange.NewText);
- Assert.Equal(result.CompletionListSpan, change.TextChange.Span);
- }
-
- [Fact]
- public async Task Insertion_Space_OutInt_EndpointMapGet_HasDelegate_ReturnRouteParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (out int $$
- }
-}
-");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
-
- var change = await result.Service.GetChangeAsync(result.Document, result.Completions.ItemsList[0]);
- Assert.Equal("id", change.TextChange.NewText);
- Assert.Equal(result.CompletionListSpan, change.TextChange.Span);
- }
-
- [Fact]
- public async Task Insertion_Space_Generic_EndpointMapGet_HasDelegate_ReturnRouteParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (Nullable<int> $$
- }
-}
-");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
-
- var change = await result.Service.GetChangeAsync(result.Document, result.Completions.ItemsList[0]);
- Assert.Equal("id", change.TextChange.NewText);
- Assert.Equal(result.CompletionListSpan, change.TextChange.Span);
- }
-
- [Fact]
- public async Task Invoke_Space_Generic_EndpointMapGet_HasDelegate_HasText_ReturnRouteParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (int [|i|]$$
- }
-}
-", CompletionTrigger.Invoke);
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
-
- var change = await result.Service.GetChangeAsync(result.Document, result.Completions.ItemsList[0]);
- Assert.Equal("id", change.TextChange.NewText);
- Assert.Equal(result.CompletionListSpan, change.TextChange.Span);
- }
-
- [Fact]
- public async Task Invoke_Space_Generic_EndpointMapGet_HasDelegate_InText_ReturnRouteParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (int [|i$$d|]
- }
-}
-", CompletionTrigger.Invoke);
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
-
- var change = await result.Service.GetChangeAsync(result.Document, result.Completions.ItemsList[0]);
- Assert.Equal("id", change.TextChange.NewText);
- Assert.Equal(result.CompletionListSpan, change.TextChange.Span);
- }
-
- [Fact]
- public async Task Invoke_Space_Generic_EndpointMapGet_HasCompleteDelegate_InText_ReturnRouteParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{ids}"", (int [|i$$d|]) => {});
- }
-}
-", CompletionTrigger.Invoke);
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("ids", i.DisplayText));
-
- var change = await result.Service.GetChangeAsync(result.Document, result.Completions.ItemsList[0]);
- Assert.Equal("ids", change.TextChange.NewText);
- Assert.Equal(result.CompletionListSpan, change.TextChange.Span);
- }
-
- [Fact]
- public async Task Insertion_FirstArgument_SpaceAfterIdentifer_EndpointMapGet_HasDelegate_NoItems()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (int i $$
- }
-}
-");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- [Fact]
- public async Task Insertion_SecondArgument_SpaceAfterIdentifer_EndpointMapGet_HasDelegate_NoItems()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (int o, string i $$
- }
-}
-");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- [Fact]
- public async Task Insertion_Space_MultipleArgs_EndpointMapGet_HasDelegate_ReturnRouteParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-using System.IO.Pipelines;
-using System.Security.Claims;
-using System.Threading;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (HttpContext context, int $$
- }
-}
-");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
- }
-
- [Fact]
- public async Task Insertion_Space_MultipleArgs_ParameterAlreadyUsed_EndpointMapGet_HasDelegate_NoItems()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-using System.IO.Pipelines;
-using System.Security.Claims;
-using System.Threading;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (string id, int $$
- }
-}
-");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- [Fact]
- public async Task Insertion_Space_MultipleArgs_ParameterAlreadyUsed_EndpointMapGet_HasCompleteDelegate_NoItems()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-using System.IO.Pipelines;
-using System.Security.Claims;
-using System.Threading;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (string id, int $$) => { });
- }
-}
-");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- [Fact]
- public async Task Insertion_Space_MultipleArgs_ParameterAlreadyUsed_DifferentCase_EndpointMapGet_HasCompleteDelegate_NoItems()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-using System.IO.Pipelines;
-using System.Security.Claims;
-using System.Threading;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{ID}"", (string id, int $$) => { });
- }
-}
-");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- [Theory]
- [InlineData("HttpContext")]
- [InlineData("CancellationToken")]
- [InlineData("HttpRequest")]
- [InlineData("HttpResponse")]
- [InlineData("ClaimsPrincipal")]
- [InlineData("IFormFileCollection")]
- [InlineData("IFormFile")]
- [InlineData("Stream")]
- [InlineData("PipeReader")]
- public async Task Insertion_Space_SpecialType_EndpointMapGet_HasDelegate_NoItems(string parameterType)
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-using System.IO.Pipelines;
-using System.Security.Claims;
-using System.Threading;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", (" + parameterType + @" $$
- }
-}
-");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- [Fact]
- public async Task Insertion_Space_EndpointMapGet_HasMethod_NoItems()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", ExecuteGet $$);
- }
-
- static string ExecuteGet(string id)
- {
- return """";
- }
-}
-");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- [Fact]
- public async Task Insertion_Space_EndpointMapGet_HasMethod_NamedParameters_ReturnDelegateParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(pattern: @""{id}"", endpoints: null, handler: (string blah, int $$)
- }
-}
-");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
- }
-
- [Theory]
- [InlineData("AsParameters")]
- [InlineData("FromQuery")]
- [InlineData("FromForm")]
- [InlineData("FromHeader")]
- [InlineData("FromServices")]
- public async Task Insertion_Space_EndpointMapGet_AsParameters_NoItem(string attributeName)
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", ([" + attributeName + @"] int $$) => {});
- }
-}
-");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- [Fact]
- public async Task Insertion_Space_EndpointMapGet_UnknownAttribute_ReturnItems()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", ([PurpleMonkeyDishwasher] int $$) => {});
- }
-}
-");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
- }
-
- [Fact]
- public async Task Insertion_Space_EndpointMapGet_NullDelegate_NoResults()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", null $$
- }
-}
-");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- [Fact]
- public async Task Insertion_Space_EndpointMapGet_Incomplete_NoResults()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-
-class Program
-{
- static void Main()
- {
- EndpointRouteBuilderExtensions.MapGet(null, @""{id}"", $$
- }
-}
-");
-
- // Assert
- var item = result.Completions.ItemsList.FirstOrDefault(i => i.DisplayText == "id");
- Assert.Null(item);
- }
-
- [Fact]
- public async Task Insertion_Space_CustomMapGet_ReturnDelegateParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Routing;
-
-class Program
-{
- static void Main()
- {
- MapCustomThing(null, @""{id}"", (string $$) => "");
- }
-
- static void MapCustomThing(IEndpointRouteBuilder endpoints, [StringSyntax(""Route"")] string pattern, Delegate delegate)
- {
- }
-}
-");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
- }
-
- [Fact]
- public async Task Insertion_Space_CustomMapGet_NoRouteSyntax_NoItems()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Routing;
-
-class Program
-{
- static void Main()
- {
- MapCustomThing(null, @""{id}"", (string $$) => "");
- }
-
- static void MapCustomThing(IEndpointRouteBuilder endpoints, string pattern, Delegate delegate)
- {
- }
-}
-");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- [Fact]
- public async Task Insertion_Space_ControllerAction_HasParameter_ReturnActionParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
- using System;
- using System.Diagnostics.CodeAnalysis;
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Mvc;
-
- class Program
- {
- static void Main()
- {
- }
- }
-
- public class TestController
- {
- [HttpGet(@""{id}"")]
- public object TestAction(int $$)
- {
- return null;
- }
- }
- ");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
- }
-
- [Fact]
- public async Task Insertion_Space_ControllerAction_HasParameter_Incomplete_ReturnActionParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
- using System;
- using System.Diagnostics.CodeAnalysis;
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Mvc;
-
- class Program
- {
- static void Main()
- {
- }
- }
-
- public class TestController
- {
- [HttpGet(@""{id}"")]
- public object TestAction(int $$
- }
- ");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
- }
-
- [Fact]
- public async Task Invoke_ControllerAction_HasParameter_Incomplete_ReturnActionParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
- using System;
- using System.Diagnostics.CodeAnalysis;
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Mvc;
-
- class Program
- {
- static void Main()
- {
- }
- }
-
- public class TestController
- {
- [HttpGet(@""{id}"")]
- public object TestAction(int [|i|]$$
- }
- ", CompletionTrigger.Invoke);
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
-
- var change = await result.Service.GetChangeAsync(result.Document, result.Completions.ItemsList[0]);
- Assert.Equal("id", change.TextChange.NewText);
- Assert.Equal(result.CompletionListSpan, change.TextChange.Span);
- }
-
- [Fact]
- public async Task Insertion_ControllerAction_HasParameter_Incomplete_NoItems()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
- using System;
- using System.Diagnostics.CodeAnalysis;
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Mvc;
-
- class Program
- {
- static void Main()
- {
- }
- }
-
- public class TestController
- {
- [HttpGet(@""{id}"")]
- public object TestAction(int i $$
- }
- ");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- [Fact]
- public async Task Insertion_Space_ControllerAction_HasParameter_BeforeComma_ReturnActionParameterItem()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
- using System;
- using System.Diagnostics.CodeAnalysis;
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Mvc;
-
- class Program
- {
- static void Main()
- {
- }
- }
-
- public class TestController
- {
- [HttpGet(@""{id}"")]
- public object TestAction(int $$, string blah)
- {
- return null;
- }
- }
- ");
-
- // Assert
- Assert.Collection(
- result.Completions.ItemsList,
- i => Assert.Equal("id", i.DisplayText));
- }
-
- [Fact]
- public async Task Insertion_Space_NonControllerAction_HasParameter_NoItems()
- {
- // Arrange & Act
- var result = await GetCompletionsAndServiceAsync(@"
- using System;
- using System.Diagnostics.CodeAnalysis;
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Mvc;
-
- class Program
- {
- static void Main()
- {
- }
- }
-
- public class TestController
- {
- [HttpGet(@""{id}"")]
- internal object TestAction(int $$)
- {
- return null;
- }
- }
- ");
-
- // Assert
- Assert.Empty(result.Completions.ItemsList);
- }
-
- private Task<CompletionResult> GetCompletionsAndServiceAsync(string source, CompletionTrigger? completionTrigger = null)
- {
- return CompletionTestHelpers.GetCompletionsAndServiceAsync(Runner, source, completionTrigger);
- }
-}
diff --git a/src/Framework/AspNetCoreAnalyzers/test/RouteEmbeddedLanguage/RoutePatternParserTests.cs b/src/Framework/AspNetCoreAnalyzers/test/RouteEmbeddedLanguage/RoutePatternParserTests.cs
index 3bbd8a8a8d..db5fe029e8 100644
--- a/src/Framework/AspNetCoreAnalyzers/test/RouteEmbeddedLanguage/RoutePatternParserTests.cs
+++ b/src/Framework/AspNetCoreAnalyzers/test/RouteEmbeddedLanguage/RoutePatternParserTests.cs
@@ -80,7 +80,7 @@ public partial class RoutePatternParserTests
_outputHelper.WriteLine(actual);
if (expected != null)
{
- Assert.Equal(expected.Replace("\"", DoubleQuoteEscaping), actual);
+ Assert.Equal(expected.Replace("\"", DoubleQuoteEscaping), actual, ignoreLineEndingDifferences: true);
}
return tree;