Skip to content

Commit

Permalink
Remove more LocateOwner usage (#9132)
Browse files Browse the repository at this point in the history
Update code actions and completion
Update diagnostics to get off LocateOwner
  • Loading branch information
ryzngard authored Aug 30, 2023
1 parent e065ded commit 598c7d5
Show file tree
Hide file tree
Showing 8 changed files with 387 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public DefaultCSharpCodeActionProvider(LanguageServerFeatureOptions languageServ
}

var tree = context.CodeDocument.GetSyntaxTree();
var node = tree.GetOwner(context.Location.AbsoluteIndex);
var node = tree.Root.FindInnermostNode(context.Location.AbsoluteIndex);
var isInImplicitExpression = node?.AncestorsAndSelf().Any(n => n is CSharpImplicitExpressionSyntax) ?? false;

var allowList = isInImplicitExpression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public override async Task<VSInternalCompletionList> RewriteAsync(
}

var syntaxTree = await hostDocumentContext.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var owner = syntaxTree.GetOwner(hostDocumentIndex);
var owner = syntaxTree.Root.FindInnermostNode(hostDocumentIndex);
if (owner is null)
{
Debug.Fail("Owner should never be null.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Microsoft.AspNetCore.Razor.LanguageServer.Extensions;
using Microsoft.AspNetCore.Razor.LanguageServer.Protocol;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions;
using Microsoft.Extensions.Logging;
using Diagnostic = Microsoft.VisualStudio.LanguageServer.Protocol.Diagnostic;
using DiagnosticSeverity = Microsoft.VisualStudio.LanguageServer.Protocol.DiagnosticSeverity;
Expand Down Expand Up @@ -120,7 +121,7 @@ private static Diagnostic[] FilterHTMLDiagnostics(

var filteredDiagnostics = unmappedDiagnostics
.Where(d =>
!InCSharpLiteral(d, sourceText, syntaxTree, logger) &&
!InCSharpLiteral(d, sourceText, syntaxTree) &&
!InAttributeContainingCSharp(d, sourceText, syntaxTree, processedAttributes, logger) &&
!AppliesToTagHelperTagName(d, sourceText, syntaxTree, logger) &&
!ShouldFilterHtmlDiagnosticBasedOnErrorCode(d, sourceText, syntaxTree, logger))
Expand Down Expand Up @@ -162,23 +163,34 @@ private Diagnostic[] MapDiagnostics(
private static bool InCSharpLiteral(
Diagnostic d,
SourceText sourceText,
RazorSyntaxTree syntaxTree,
ILogger logger)
RazorSyntaxTree syntaxTree)
{
if (d.Range is null)
{
return false;
}

var owner = syntaxTree.GetOwner(sourceText, d.Range.End, logger);
if (owner is null)

var owner = syntaxTree.Root.FindNode(d.Range.AsRazorTextSpan(sourceText), getInnermostNodeForTie: true);
if (IsCsharpKind(owner))
{
return false;
return true;
}

var isCSharp = owner.Kind is SyntaxKind.CSharpExpressionLiteral or SyntaxKind.CSharpStatementLiteral or SyntaxKind.CSharpEphemeralTextLiteral;
if (owner is CSharpImplicitExpressionSyntax implicitExpressionSyntax &&
implicitExpressionSyntax.Body is CSharpImplicitExpressionBodySyntax bodySyntax &&
bodySyntax.CSharpCode is CSharpCodeBlockSyntax codeBlock)
{
return codeBlock.Children.Count == 1
&& IsCsharpKind(codeBlock.Children[0]);
}

return false;

return isCSharp;
static bool IsCsharpKind([NotNullWhen(true)] SyntaxNode? node)
=> node?.Kind is SyntaxKind.CSharpExpressionLiteral
or SyntaxKind.CSharpStatementLiteral
or SyntaxKind.CSharpEphemeralTextLiteral;
}

private static bool AppliesToTagHelperTagName(
Expand All @@ -201,7 +213,7 @@ private static bool AppliesToTagHelperTagName(
return false;
}

var owner = syntaxTree.GetOwner(sourceText, diagnostic.Range.End, logger);
var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.End, logger);

var startOrEndTag = owner?.FirstAncestorOrSelf<RazorSyntaxNode>(n => n is MarkupTagHelperStartTagSyntax || n is MarkupTagHelperEndTagSyntax);
if (startOrEndTag is null)
Expand Down Expand Up @@ -246,7 +258,7 @@ private static bool ShouldFilterHtmlDiagnosticBasedOnErrorCode(Diagnostic diagno
static bool IsCSharpInStyleBlock(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger)
{
// C# in a style block causes diagnostics because the HTML background document replaces C# with "~"
var owner = syntaxTree.GetOwner(sourceText, diagnostic.Range.Start, logger);
var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start, logger);
if (owner is null)
{
return false;
Expand All @@ -262,7 +274,7 @@ static bool IsCSharpInStyleBlock(Diagnostic diagnostic, SourceText sourceText, R
// but we don't currently have a system to accomplish that
static bool IsAnyFilteredTooFewElementsError(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger)
{
var owner = syntaxTree.GetOwner(sourceText, diagnostic.Range.Start, logger);
var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start, logger);
if (owner is null)
{
return false;
Expand Down Expand Up @@ -291,7 +303,7 @@ static bool IsAnyFilteredTooFewElementsError(Diagnostic diagnostic, SourceText s
// but we don't currently have a system to accomplish that
static bool IsHtmlWithBangAndMatchingTags(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger)
{
var owner = syntaxTree.GetOwner(sourceText, diagnostic.Range.Start, logger);
var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start, logger);
if (owner is null)
{
return false;
Expand Down Expand Up @@ -319,7 +331,7 @@ static bool IsAnyFilteredInvalidNestingError(Diagnostic diagnostic, SourceText s

static bool IsInvalidNestingWarningWithinComponent(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger)
{
var owner = syntaxTree.GetOwner(sourceText, diagnostic.Range.Start, logger);
var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start, logger);
if (owner is null)
{
return false;
Expand All @@ -334,7 +346,7 @@ static bool IsInvalidNestingWarningWithinComponent(Diagnostic diagnostic, Source
// but we don't currently have a system to accomplish that
static bool IsInvalidNestingFromBody(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger)
{
var owner = syntaxTree.GetOwner(sourceText, diagnostic.Range.Start, logger);
var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start, logger);
if (owner is null)
{
return false;
Expand Down Expand Up @@ -371,7 +383,7 @@ private static bool InAttributeContainingCSharp(
return false;
}

var owner = syntaxTree.GetOwner(sourceText, diagnostic.Range.End, logger);
var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.End, logger);
if (owner is null)
{
return false;
Expand Down Expand Up @@ -497,7 +509,8 @@ private bool TryRemapRudeEditRange(Range diagnosticRange, RazorCodeDocument code
// semi-intelligent way.

var syntaxTree = codeDocument.GetSyntaxTree();
var owner = syntaxTree.GetOwner(sourceText, diagnosticRange, logger: _logger);
var span = diagnosticRange.AsRazorTextSpan(codeDocument.GetSourceText());
var owner = syntaxTree.Root.FindNode(span, getInnermostNodeForTie: true);

switch (owner?.Kind)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.Language.Syntax;
using Microsoft.AspNetCore.Razor.LanguageServer.Formatting;
using Microsoft.CodeAnalysis.Text;
Expand Down Expand Up @@ -59,23 +58,12 @@ public static IReadOnlyList<CSharpStatementSyntax> GetCSharpStatements(this Razo
return statements;
}

public static SyntaxNode? GetOwner(this RazorSyntaxTree syntaxTree, int absoluteIndex)
{
if (syntaxTree is null)
{
throw new ArgumentNullException(nameof(syntaxTree));
}

var change = new SourceChange(absoluteIndex, 0, string.Empty);
var owner = syntaxTree.Root.LocateOwner(change);
return owner;
}

public static SyntaxNode? GetOwner(
public static SyntaxNode? FindInnermostNode(
this RazorSyntaxTree syntaxTree,
SourceText sourceText,
Position position,
ILogger logger)
ILogger logger,
bool includeWhitespace = false)
{
if (syntaxTree is null)
{
Expand All @@ -102,40 +90,6 @@ public static IReadOnlyList<CSharpStatementSyntax> GetCSharpStatements(this Razo
return default;
}

return GetOwner(syntaxTree, absoluteIndex);
}

public static SyntaxNode? GetOwner(
this RazorSyntaxTree syntaxTree,
SourceText sourceText,
Range range,
ILogger logger)
{
if (syntaxTree is null)
{
throw new ArgumentNullException(nameof(syntaxTree));
}

if (sourceText is null)
{
throw new ArgumentNullException(nameof(sourceText));
}

if (range is null)
{
throw new ArgumentNullException(nameof(range));
}

var startInSync = range.Start.TryGetAbsoluteIndex(sourceText, logger, out var absoluteStartIndex);
var endInSync = range.End.TryGetAbsoluteIndex(sourceText, logger, out var absoluteEndIndex);
if (startInSync is false || endInSync is false)
{
return default;
}

var length = absoluteEndIndex - absoluteStartIndex;
var change = new SourceChange(absoluteStartIndex, length, string.Empty);
var owner = syntaxTree.Root.LocateOwner(change);
return owner;
return syntaxTree.Root.FindInnermostNode(absoluteIndex, includeWhitespace);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Syntax;
using Microsoft.AspNetCore.Razor.LanguageServer.Formatting;
Expand Down Expand Up @@ -328,5 +329,60 @@ public static int GetTrailingWhitespaceLength(this SyntaxNode node, FormattingCo
}

public static SyntaxNode? FindInnermostNode(this SyntaxNode node, int index, bool includeWhitespace = false)
=> node.FindToken(index, includeWhitespace)?.Parent;
{
var token = node.FindToken(index, includeWhitespace);

// If the index is EOF but the node has index-1,
// then try to get a token to the left of the index.
// patterns like
// <button></button>$$
// should get the button node instead of the razor document (which is the parent
// of the EOF token)
if (token.Kind == SyntaxKind.EndOfFile && node.Span.Contains(index - 1))
{
token = node.FindToken(index - 1, includeWhitespace);
}

return token.Parent;
}

public static SyntaxNode? FindNode(this SyntaxNode @this, Language.Syntax.TextSpan span, bool includeWhitespace = false, bool getInnermostNodeForTie = false)
{
if (!@this.FullSpan.Contains(span))
{
throw new ArgumentOutOfRangeException(nameof(span));
}

var node = @this.FindToken(span.Start, includeWhitespace)
.Parent
!.FirstAncestorOrSelf<SyntaxNode>(a => a.FullSpan.Contains(span));

node.AssumeNotNull();

// Tie-breaking.
if (!getInnermostNodeForTie)
{
var cuRoot = node.Ancestors().Last();

while (true)
{
var parent = node.Parent;
// NOTE: We care about FullSpan equality, but FullWidth is cheaper and equivalent.
if (parent == null || parent.FullWidth != node.FullWidth)
{
break;
}

// prefer child over compilation unit
if (parent == cuRoot)
{
break;
}

node = parent;
}
}

return node;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static bool TryGetAttributeNameAbsoluteIndex(RazorCodeDocument codeDocume
attributeNameAbsoluteIndex = 0;

var tree = codeDocument.GetSyntaxTree();
var owner = tree.GetOwner(absoluteIndex);
var owner = tree.Root.FindInnermostNode(absoluteIndex);

var attributeName = owner?.Parent switch
{
Expand Down Expand Up @@ -72,7 +72,7 @@ public static bool TryGetAttributeNameAbsoluteIndex(RazorCodeDocument codeDocume
public static bool TryGetFullAttributeNameSpan(RazorCodeDocument codeDocument, int absoluteIndex, out TextSpan attributeNameSpan)
{
var tree = codeDocument.GetSyntaxTree();
var owner = tree.GetOwner(absoluteIndex);
var owner = tree.Root.FindInnermostNode(absoluteIndex);

attributeNameSpan = GetFullAttributeNameSpan(owner?.Parent);

Expand Down
Loading

0 comments on commit 598c7d5

Please sign in to comment.