Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Text;
using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Components;
using Microsoft.AspNetCore.Razor.Language.Syntax;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Features;
Expand Down Expand Up @@ -214,12 +215,7 @@ public void Generate()
var node = root.FindInnermostNode(originalSpan.AbsoluteIndex);
if (node is CSharpExpressionLiteralSyntax)
{
// Rather than bother to store more data about the formatted file, since we don't actually know where
// these will end up in that file once it's all said and done, we are just going to use a simple comment
// format that we can easily parse.
additionalLinesBuilder.AppendLine(GetAdditionalLineComment(originalSpan));
additionalLinesBuilder.AppendLine(_sourceText.GetSubTextString(originalSpan.ToTextSpan()));
additionalLinesBuilder.AppendLine(";");
AddAdditionalLineFormattingContent(additionalLinesBuilder, node, originalSpan);
}

iMapping++;
Expand Down Expand Up @@ -254,6 +250,34 @@ public void Generate()
_builder.AppendLine(additionalLinesBuilder.ToString());
}

private void AddAdditionalLineFormattingContent(StringBuilder additionalLinesBuilder, RazorSyntaxNode node, SourceSpan originalSpan)
{
// Rather than bother to store more data about the formatted file, since we don't actually know where
// these will end up in that file once it's all said and done, we are just going to use a simple comment
// format that we can easily parse.

// Special case, for attributes that represent generic type parameters, we want to output something such
// that Roslyn knows to format it as a type. For example, the meaning and spacing around "?"s should be
// what the user expects.
if (node is { Parent.Parent: MarkupTagHelperAttributeSyntax attribute } &&
attribute is { Parent.Parent: MarkupTagHelperElementSyntax element } &&
element.TagHelperInfo.BindingResult.Descriptors is [{ } descriptor] &&
descriptor.IsGenericTypedComponent() &&
descriptor.BoundAttributes.FirstOrDefault(d => d.Name == attribute.TagHelperAttributeInfo.Name) is { } boundAttribute &&
boundAttribute.IsTypeParameterProperty())
{
additionalLinesBuilder.AppendLine("F<");
additionalLinesBuilder.AppendLine(GetAdditionalLineComment(originalSpan));
additionalLinesBuilder.AppendLine(_sourceText.GetSubTextString(originalSpan.ToTextSpan()));
additionalLinesBuilder.AppendLine("> x;");
return;
}

additionalLinesBuilder.AppendLine(GetAdditionalLineComment(originalSpan));
additionalLinesBuilder.AppendLine(_sourceText.GetSubTextString(originalSpan.ToTextSpan()));
additionalLinesBuilder.AppendLine(";");
}

public override LineInfo Visit(RazorSyntaxNode? node)
{
// Sometimes we are in a block where we want to do no formatting at all
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7303,4 +7303,21 @@ public Task NestedExplicitExpression4()
</span>
}
""");

[FormattingTestFact]
[WorkItem("https://github.com/dotnet/razor/issues/12445")]
public Task TypeParameterAttribute()
=> RunFormattingTestAsync(
input: """
<div>
<InputSelect TValue="Guid?">
</InputSelect>
</div>
""",
expected: """
<div>
<InputSelect TValue="Guid?">
</InputSelect>
</div>
""");
}
Loading