Add go-to-definition endpoint logging (#5650)

This commit is contained in:
Allison Chou 2021-10-25 21:28:28 -07:00 коммит произвёл GitHub
Родитель ec5cb4f1ef
Коммит 7d22766f35
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 97 добавлений и 31 удалений

Просмотреть файл

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
@ -17,13 +18,21 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer
{
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly ProjectSnapshotManager _projectSnapshotManager;
private readonly ILogger<DefaultRazorComponentSearchEngine> _logger;
public DefaultRazorComponentSearchEngine(
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
ProjectSnapshotManagerAccessor projectSnapshotManagerAccessor)
ProjectSnapshotManagerAccessor projectSnapshotManagerAccessor,
ILoggerFactory loggerFactory)
{
if (loggerFactory is null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
_projectSnapshotManager = projectSnapshotManagerAccessor?.Instance ?? throw new ArgumentNullException(nameof(projectSnapshotManagerAccessor));
_logger = loggerFactory.CreateLogger<DefaultRazorComponentSearchEngine>();
}
/// <summary>Search for a component in a project based on its tag name and fully qualified name.</summary>
@ -35,14 +44,20 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer
/// </remarks>
/// <param name="tagHelper">A TagHelperDescriptor to find the corresponding Razor component for.</param>
/// <returns>The corresponding DocumentSnapshot if found, null otherwise.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="tagHelper"/> is null.</exception>
public override async Task<DocumentSnapshot> TryLocateComponentAsync(TagHelperDescriptor tagHelper)
{
if (tagHelper is null)
{
throw new ArgumentNullException(nameof(tagHelper));
}
if (!DefaultRazorTagHelperBinderPhase.ComponentDirectiveVisitor.TrySplitNamespaceAndType(tagHelper.Name, out var @namespaceName, out var typeName))
{
_logger.LogWarning($"Could not split namespace and type for name {tagHelper.Name}.");
return null;
}
DefaultRazorTagHelperBinderPhase.ComponentDirectiveVisitor.TrySplitNamespaceAndType(tagHelper.Name, out var @namespaceName, out var typeName);
var lookupSymbolName = RemoveGenericContent(typeName);
var projects = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
@ -73,9 +88,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer
{
continue;
}
return documentSnapshot;
}
}
return null;
}
@ -101,14 +118,20 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer
return new StringSegment(fileName).Equals(path, FilePathComparison.Instance);
}
private static bool ComponentNamespaceMatchesFullyQualifiedName(RazorCodeDocument razorCodeDocument, StringSegment namespaceName)
private bool ComponentNamespaceMatchesFullyQualifiedName(RazorCodeDocument razorCodeDocument, StringSegment namespaceName)
{
var namespaceNode = (NamespaceDeclarationIntermediateNode)razorCodeDocument
.GetDocumentIntermediateNode()
.FindDescendantNodes<IntermediateNode>()
.First(n => n is NamespaceDeclarationIntermediateNode);
return new StringSegment(namespaceNode.Content).Equals(namespaceName, StringComparison.Ordinal);
var namespacesMatch = new StringSegment(namespaceNode.Content).Equals(namespaceName, StringComparison.Ordinal);
if (!namespacesMatch)
{
_logger.LogInformation($"Namespace name {namespaceNode.Content} does not match namespace name {namespaceName}.");
}
return namespacesMatch;
}
}
}

Просмотреть файл

@ -1,6 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Linq;
using System.Threading;
@ -14,6 +16,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Extensions.Logging;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
@ -25,15 +28,23 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly DocumentResolver _documentResolver;
private readonly RazorComponentSearchEngine _componentSearchEngine;
private readonly ILogger<RazorDefinitionEndpoint> _logger;
public RazorDefinitionEndpoint(
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
DocumentResolver documentResolver,
RazorComponentSearchEngine componentSearchEngine)
RazorComponentSearchEngine componentSearchEngine,
ILoggerFactory loggerFactory)
{
if (loggerFactory is null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
_documentResolver = documentResolver ?? throw new ArgumentNullException(nameof(documentResolver));
_componentSearchEngine = componentSearchEngine ?? throw new ArgumentNullException(nameof(componentSearchEngine));
_logger = loggerFactory.CreateLogger<RazorDefinitionEndpoint>();
}
public DefinitionRegistrationOptions GetRegistrationOptions(DefinitionCapability capability, ClientCapabilities clientCapabilities)
@ -44,10 +55,17 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
};
}
public async Task<LocationOrLocationLinks> Handle(DefinitionParams request, CancellationToken cancellationToken)
#pragma warning disable CS8613 // Nullability of reference types in return type doesn't match implicitly implemented member.
// The return type of the handler should be nullable. O# tracking issue:
// https://github.com/OmniSharp/csharp-language-server-protocol/issues/644
public async Task<LocationOrLocationLinks?> Handle(DefinitionParams request, CancellationToken cancellationToken)
#pragma warning restore CS8613 // Nullability of reference types in return type doesn't match implicitly implemented member.
{
_logger.LogInformation("Starting go-to-def endpoint request.");
if (request is null)
{
_logger.LogWarning("Request is null.");
throw new ArgumentNullException(nameof(request));
}
@ -60,38 +78,46 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
if (documentSnapshot is null)
{
_logger.LogWarning("Document snapshot is null for document.");
return null;
}
if (!FileKinds.IsComponent(documentSnapshot.FileKind))
{
_logger.LogInformation($"FileKind '{documentSnapshot.FileKind}' is not a component type.");
return null;
}
var codeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false);
if (codeDocument.IsUnsupported())
{
_logger.LogInformation("Generated document is unsupported.");
return null;
}
var originTagHelperBinding = await GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, request.Position).ConfigureAwait(false);
var originTagHelperBinding = await GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, request.Position, _logger).ConfigureAwait(false);
if (originTagHelperBinding is null)
{
_logger.LogInformation("Origin TagHelper binding is null.");
return null;
}
var originTagDescriptor = originTagHelperBinding.Descriptors.FirstOrDefault(d => !d.IsAttributeDescriptor());
if (originTagDescriptor is null)
{
_logger.LogInformation("Origin TagHelper descriptor is null.");
return null;
}
var originComponentDocumentSnapshot = await _componentSearchEngine.TryLocateComponentAsync(originTagDescriptor).ConfigureAwait(false);
if (originComponentDocumentSnapshot is null)
{
_logger.LogInformation("Origin TagHelper document snapshot is null.");
return null;
}
_logger.LogInformation($"Definition found at file path: {originComponentDocumentSnapshot.FilePath}");
var originComponentUri = new UriBuilder
{
Path = originComponentDocumentSnapshot.FilePath,
@ -109,10 +135,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
});
}
internal static async Task<TagHelperBinding> GetOriginTagHelperBindingAsync(
internal static async Task<TagHelperBinding?> GetOriginTagHelperBindingAsync(
DocumentSnapshot documentSnapshot,
RazorCodeDocument codeDocument,
Position position)
Position position,
ILogger logger)
{
var sourceText = await documentSnapshot.GetTextAsync().ConfigureAwait(false);
var linePosition = new LinePosition(position.Line, position.Character);
@ -123,12 +150,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var syntaxTree = codeDocument.GetSyntaxTree();
if (syntaxTree?.Root is null)
{
logger.LogInformation("Could not retrieve syntax tree.");
return null;
}
var owner = syntaxTree.Root.LocateOwner(change);
if (owner is null)
{
logger.LogInformation("Could not locate owner.");
return null;
}
@ -137,29 +166,33 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
n.Kind == SyntaxKind.MarkupTagHelperEndTag);
if (node is null)
{
logger.LogInformation("Could not locate ancestor of type MarkupTagHelperStartTag or MarkupTagHelperEndTag.");
return null;
}
var name = GetStartOrEndTagName(node);
if (name is null)
{
logger.LogInformation("Could not retrieve name of start or end tag.");
return null;
}
if (!name.Span.Contains(location.AbsoluteIndex))
{
logger.LogInformation($"Tag name's span does not contain location's absolute index ({location.AbsoluteIndex}).");
return null;
}
if (!(node.Parent is MarkupTagHelperElementSyntax tagHelperElement))
if (node.Parent is not MarkupTagHelperElementSyntax tagHelperElement)
{
logger.LogInformation("Parent of start or end tag is not a MarkupTagHelperElement.");
return null;
}
return tagHelperElement.TagHelperInfo.BindingResult;
}
private static SyntaxNode GetStartOrEndTagName(SyntaxNode node)
private static SyntaxNode? GetStartOrEndTagName(SyntaxNode node)
{
return node switch
{

Просмотреть файл

@ -12,7 +12,6 @@ using Microsoft.VisualStudio.LanguageServer.ContainedLanguage;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.LanguageServerClient.Razor.Extensions;
using Microsoft.VisualStudio.LanguageServerClient.Razor.Logging;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Threading;

Просмотреть файл

@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Test
// Arrange
var tagHelperDescriptor1 = CreateRazorComponentTagHelperDescriptor("First", "First.Components", "Component1", typeName: "Component1<TItem>");
var tagHelperDescriptor2 = CreateRazorComponentTagHelperDescriptor("Second", "Second.Components", "Component3", typeName: "Component3<TItem>");
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager);
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager, LoggerFactory);
// Act
var documentSnapshot1 = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor1).ConfigureAwait(false);
@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Test
// Arrange
var tagHelperDescriptor1 = CreateRazorComponentTagHelperDescriptor("First", "First.Components", "Component1");
var tagHelperDescriptor2 = CreateRazorComponentTagHelperDescriptor("Second", "Second.Components", "Component3");
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager);
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager, LoggerFactory);
// Act
var documentSnapshot1 = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor1).ConfigureAwait(false);
@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Test
{
// Arrange
var tagHelperDescriptor = CreateRazorComponentTagHelperDescriptor("First", "Test", "Component2");
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager);
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager, LoggerFactory);
// Act
var documentSnapshot = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor).ConfigureAwait(false);
@ -72,7 +72,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Test
{
// Arrange
var tagHelperDescriptor = CreateRazorComponentTagHelperDescriptor("Third", "First.Components", "Component3");
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager);
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager, LoggerFactory);
// Act
var documentSnapshot = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor).ConfigureAwait(false);
@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Test
{
// Arrange
var tagHelperDescriptor = CreateRazorComponentTagHelperDescriptor("First", "First.Components", "Component2");
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager);
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager, LoggerFactory);
// Act
var documentSnapshot = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor).ConfigureAwait(false);
@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Test
{
// Arrange
var tagHelperDescriptor = CreateRazorComponentTagHelperDescriptor("First", "First.Components", "Component3");
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager);
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager, LoggerFactory);
// Act
var documentSnapshot = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor).ConfigureAwait(false);
@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Test
{
// Arrange
var tagHelperDescriptor = CreateRazorComponentTagHelperDescriptor("AssemblyName", "Test", "Component2");
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager);
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, s_projectSnapshotManager, LoggerFactory);
// Act
var documentSnapshot = await searchEngine.TryLocateComponentAsync(tagHelperDescriptor).ConfigureAwait(false);

Просмотреть файл

@ -32,7 +32,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var position = new Position(1, 2);
// Act
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, position).ConfigureAwait(false);
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(
documentSnapshot, codeDocument, position, LoggerFactory.CreateLogger("RazorDefinitionEndpoint")).ConfigureAwait(false);
// Assert
Assert.Equal("test1", binding.TagName);
@ -48,7 +49,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var position = new Position(1, 2);
// Act
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, position).ConfigureAwait(false);
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(
documentSnapshot, codeDocument, position, LoggerFactory.CreateLogger("RazorDefinitionEndpoint")).ConfigureAwait(false);
// Assert
Assert.Equal("Component1", binding.TagName);
@ -65,7 +67,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var position = new Position(1, 35);
// Act
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, position).ConfigureAwait(false);
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(
documentSnapshot, codeDocument, position, LoggerFactory.CreateLogger("RazorDefinitionEndpoint")).ConfigureAwait(false);
// Assert
Assert.Equal("Component1", binding.TagName);
@ -82,7 +85,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var position = new Position(1, 14);
// Act
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, position).ConfigureAwait(false);
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(
documentSnapshot, codeDocument, position, LoggerFactory.CreateLogger("RazorDefinitionEndpoint")).ConfigureAwait(false);
// Assert
Assert.Null(binding);
@ -96,7 +100,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var position = new Position(1, 24);
// Act
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, position).ConfigureAwait(false);
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(
documentSnapshot, codeDocument, position, LoggerFactory.CreateLogger("RazorDefinitionEndpoint")).ConfigureAwait(false);
// Assert
Assert.Null(binding);
@ -110,7 +115,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var position = new Position(1, 18);
// Act
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, position).ConfigureAwait(false);
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(
documentSnapshot, codeDocument, position, LoggerFactory.CreateLogger("RazorDefinitionEndpoint")).ConfigureAwait(false);
// Assert
Assert.Null(binding);
@ -124,7 +130,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var position = new Position(1, 29);
// Act
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, position).ConfigureAwait(false);
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(
documentSnapshot, codeDocument, position, LoggerFactory.CreateLogger("RazorDefinitionEndpoint")).ConfigureAwait(false);
// Assert
Assert.Null(binding);
@ -145,7 +152,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var position = new Position(1, 2);
// Act
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, position).ConfigureAwait(false);
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(
documentSnapshot, codeDocument, position, LoggerFactory.CreateLogger("RazorDefinitionEndpoint")).ConfigureAwait(false);
// Assert
Assert.Equal("Component1", binding.TagName);
@ -170,7 +178,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var position = new Position(1, 2);
// Act
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, position).ConfigureAwait(false);
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(
documentSnapshot, codeDocument, position, LoggerFactory.CreateLogger("RazorDefinitionEndpoint")).ConfigureAwait(false);
// Assert
Assert.Equal("Component1", binding.TagName);
@ -194,7 +203,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var position = new Position(1, 2);
// Act
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, position).ConfigureAwait(false);
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(
documentSnapshot, codeDocument, position, LoggerFactory.CreateLogger("RazorDefinitionEndpoint")).ConfigureAwait(false);
// Assert
Assert.Equal("Component1", binding.TagName);
@ -212,7 +222,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition
var position = new Position(1, 6);
// Act
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(documentSnapshot, codeDocument, position).ConfigureAwait(false);
var binding = await RazorDefinitionEndpoint.GetOriginTagHelperBindingAsync(
documentSnapshot, codeDocument, position, LoggerFactory.CreateLogger("RazorDefinitionEndpoint")).ConfigureAwait(false);
// Assert
Assert.Null(binding);

Просмотреть файл

@ -488,7 +488,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring.Test
d.TryResolveDocument(itemDirectory1.FilePath, out directory1Component) == true &&
d.TryResolveDocument(itemDirectory2.FilePath, out directory2Component) == true, MockBehavior.Strict);
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, projectSnapshotManagerAccessor);
var searchEngine = new DefaultRazorComponentSearchEngine(Dispatcher, projectSnapshotManagerAccessor, LoggerFactory);
languageServerFeatureOptions ??= Mock.Of<LanguageServerFeatureOptions>(options => options.SupportsFileManipulation == true, MockBehavior.Strict);
var endpoint = new RazorComponentRenameEndpoint(Dispatcher, documentResolver, searchEngine, projectSnapshotManagerAccessor, languageServerFeatureOptions);
return endpoint;