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
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand Down Expand Up @@ -37,17 +37,23 @@ public void Execute(TagHelperDescriptorProviderContext context)

var types = new List<INamedTypeSymbol>();
var visitor = new ViewComponentTypeVisitor(vcAttribute, nonVCAttribute, types);
var discoveryMode = context.Items.GetTagHelperDiscoveryFilter();

// We always visit the global namespace.
visitor.Visit(compilation.Assembly.GlobalNamespace);
if ((discoveryMode & TagHelperDiscoveryFilter.CurrentCompilation) == TagHelperDiscoveryFilter.CurrentCompilation)
{
visitor.Visit(compilation.Assembly.GlobalNamespace);
}

foreach (var reference in compilation.References)
if ((discoveryMode & TagHelperDiscoveryFilter.ReferenceAssemblies) == TagHelperDiscoveryFilter.ReferenceAssemblies)
{
if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly)
foreach (var reference in compilation.References)
{
if (IsTagHelperAssembly(assembly))
if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly)
{
visitor.Visit(assembly.GlobalNamespace);
if (IsTagHelperAssembly(assembly))
{
visitor.Visit(assembly.GlobalNamespace);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.AspNetCore.Razor.Language;
Expand Down Expand Up @@ -65,5 +65,63 @@ public class StringParameterViewComponent
// Assert
Assert.Single(context.Results, d => TagHelperDescriptorComparer.Default.Equals(d, expectedDescriptor));
}

[Fact]
public void DescriptorProvider_WithCurrentCompilationFilter_FindsDescriptorFromCurrentCompilation()
{
// Arrange
var code = @"
public class StringParameterViewComponent
{
public string Invoke(string foo, string bar) => null;
}
";

var compilation = MvcShim.BaseCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(code));

var context = TagHelperDescriptorProviderContext.Create();
context.SetCompilation(compilation);
context.Items.SetTagHelperDiscoveryFilter(TagHelperDiscoveryFilter.CurrentCompilation);

var provider = new ViewComponentTagHelperDescriptorProvider()
{
Engine = RazorProjectEngine.CreateEmpty().Engine,
};

// Act
provider.Execute(context);

// Assert
Assert.Single(context.Results);
}

[Fact]
public void DescriptorProvider_WithReferenceAssembliesFilter_DoesNotFindDescriptorFromCurrentCompilation()
{
// Arrange
var code = @"
public class StringParameterViewComponent
{
public string Invoke(string foo, string bar) => null;
}
";

var compilation = MvcShim.BaseCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(code));

var context = TagHelperDescriptorProviderContext.Create();
context.SetCompilation(compilation);
context.Items.SetTagHelperDiscoveryFilter(TagHelperDiscoveryFilter.ReferenceAssemblies);

var provider = new ViewComponentTagHelperDescriptorProvider()
{
Engine = RazorProjectEngine.CreateEmpty().Engine,
};

// Act
provider.Execute(context);

// Assert
Assert.Empty(context.Results);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,24 @@ public void Execute(TagHelperDescriptorProviderContext context)
var types = new List<INamedTypeSymbol>();
var visitor = new ComponentTypeVisitor(symbols, types);

// Visit the primary output of this compilation, as well as all references.
visitor.Visit(compilation.Assembly);
foreach (var reference in compilation.References)
var discoveryMode = context.Items.GetTagHelperDiscoveryFilter();

if ((discoveryMode & TagHelperDiscoveryFilter.CurrentCompilation) == TagHelperDiscoveryFilter.CurrentCompilation)
{
// Visit the primary output of this compilation
visitor.Visit(compilation.Assembly);
}

if ((discoveryMode & TagHelperDiscoveryFilter.ReferenceAssemblies) == TagHelperDiscoveryFilter.ReferenceAssemblies)
{
// We ignore .netmodules here - there really isn't a case where they are used by user code
// even though the Roslyn APIs all support them.
if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly)
foreach (var reference in compilation.References)
{
visitor.Visit(assembly);
// We ignore .netmodules here - there really isn't a case where they are used by user code
// even though the Roslyn APIs all support them.
if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly)
{
visitor.Visit(assembly);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand Down Expand Up @@ -34,17 +34,23 @@ public void Execute(TagHelperDescriptorProviderContext context)

var types = new List<INamedTypeSymbol>();
var visitor = new TagHelperTypeVisitor(iTagHelper, types);
var discoveryMode = context.Items.GetTagHelperDiscoveryFilter();

// We always visit the global namespace.
visitor.Visit(compilation.Assembly.GlobalNamespace);
if ((discoveryMode & TagHelperDiscoveryFilter.CurrentCompilation) == TagHelperDiscoveryFilter.CurrentCompilation)
{
visitor.Visit(compilation.Assembly.GlobalNamespace);
}

foreach (var reference in compilation.References)
if ((discoveryMode & TagHelperDiscoveryFilter.ReferenceAssemblies) == TagHelperDiscoveryFilter.ReferenceAssemblies)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we encapsulate these types of checks into two static methods: ShouldDiscoverFromReferenceAssemblies and ShouldDiscoverFromAppAssembly or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I were to create a method, it's tempting to also put the lookup inside the code which now results in an extra dictionary lookup per call. In the absence of it, it's a simple enum check, which seems like an overkill to have a method for.

{
if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly)
foreach (var reference in compilation.References)
{
if (IsTagHelperAssembly(assembly))
if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly)
{
visitor.Visit(assembly.GlobalNamespace);
if (IsTagHelperAssembly(assembly))
{
visitor.Visit(assembly.GlobalNamespace);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,43 +28,41 @@ public void Execute(TagHelperDescriptorProviderContext context)
return;
}

var bindMethods = compilation.GetTypeByMetadataName(ComponentsApi.IComponent.FullTypeName);
if (bindMethods == null)
if (compilation.GetTypeByMetadataName(ComponentsApi.EventHandlerAttribute.FullTypeName) is not INamedTypeSymbol eventHandlerAttribute)
{
// If we can't find IComponent, then just bail. We won't be able to compile the
// generated code anyway.
// If we can't find EventHandlerAttribute, then just bail. We won't discover anything.
return;
}

var eventHandlerData = GetEventHandlerData(compilation);
var eventHandlerData = GetEventHandlerData(context, compilation, eventHandlerAttribute);

foreach (var tagHelper in CreateEventHandlerTagHelpers(eventHandlerData))
{
context.Results.Add(tagHelper);
}
}

private List<EventHandlerData> GetEventHandlerData(Compilation compilation)
private List<EventHandlerData> GetEventHandlerData(TagHelperDescriptorProviderContext context, Compilation compilation, INamedTypeSymbol eventHandlerAttribute)
{
var eventHandlerAttribute = compilation.GetTypeByMetadataName(ComponentsApi.EventHandlerAttribute.FullTypeName);
if (eventHandlerAttribute == null)
{
// This won't likely happen, but just in case.
return new List<EventHandlerData>();
}

var types = new List<INamedTypeSymbol>();
var visitor = new EventHandlerDataVisitor(types);

// Visit the primary output of this compilation, as well as all references.
visitor.Visit(compilation.Assembly);
foreach (var reference in compilation.References)
var discoveryMode = context.Items.GetTagHelperDiscoveryFilter();
if ((discoveryMode & TagHelperDiscoveryFilter.CurrentCompilation) == TagHelperDiscoveryFilter.CurrentCompilation)
{
visitor.Visit(compilation.Assembly);
}

if ((discoveryMode & TagHelperDiscoveryFilter.ReferenceAssemblies) == TagHelperDiscoveryFilter.ReferenceAssemblies)
{
// We ignore .netmodules here - there really isn't a case where they are used by user code
// even though the Roslyn APIs all support them.
if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly)
foreach (var reference in compilation.References)
{
visitor.Visit(assembly);
// We ignore .netmodules here - there really isn't a case where they are used by user code
// even though the Roslyn APIs all support them.
if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly)
{
visitor.Visit(assembly);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.LanguageServer, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("rzc, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Test.Common, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.LanguageServer.Common, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

#nullable enable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nullable everything!


using System;

namespace Microsoft.CodeAnalysis.Razor
{
[Flags]
internal enum TagHelperDiscoveryFilter
{
CurrentCompilation = 1,
ReferenceAssemblies = 2,
Default = CurrentCompilation | ReferenceAssemblies,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

#nullable enable

using Microsoft.AspNetCore.Razor.Language;

namespace Microsoft.CodeAnalysis.Razor
{
internal static class TagHelperDiscoveryFilterExtensions
{
private static readonly object TagHelperDiscoveryModeKey = new object();

public static TagHelperDiscoveryFilter GetTagHelperDiscoveryFilter(this ItemCollection items)
{
if (items.Count == 0 || items[TagHelperDiscoveryModeKey] is not TagHelperDiscoveryFilter filter)
{
return TagHelperDiscoveryFilter.Default;
}

return filter;
}

public static void SetTagHelperDiscoveryFilter(this ItemCollection items, TagHelperDiscoveryFilter filter)
{
items[TagHelperDiscoveryModeKey] = filter;
}
}
}
Loading