public void Execute(TagHelperDescriptorProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        var compilation = context.GetCompilation();

        if (compilation == null)
        {
            // No compilation, nothing to do.
            return;
        }

        var vcAttribute    = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute);
        var nonVCAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.NonViewComponentAttribute);

        if (vcAttribute == null || vcAttribute.TypeKind == TypeKind.Error)
        {
            // Could not find attributes we care about in the compilation. Nothing to do.
            return;
        }

        var types   = new List <INamedTypeSymbol>();
        var visitor = new ViewComponentTypeVisitor(vcAttribute, nonVCAttribute, types);

        var targetAssembly = context.Items.GetTargetAssembly();

        if (targetAssembly is not null)
        {
            visitor.Visit(targetAssembly.GlobalNamespace);
        }
        else
        {
            visitor.Visit(compilation.Assembly.GlobalNamespace);
            foreach (var reference in compilation.References)
            {
                if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly)
                {
                    if (IsTagHelperAssembly(assembly))
                    {
                        visitor.Visit(assembly.GlobalNamespace);
                    }
                }
            }
        }

        var factory = new ViewComponentTagHelperDescriptorFactory(compilation);

        for (var i = 0; i < types.Count; i++)
        {
            var descriptor = factory.CreateDescriptor(types[i]);

            if (descriptor != null)
            {
                context.Results.Add(descriptor);
            }
        }
    }
    public void CreateDescriptor_ForViewComponentWithInvokeAsync_UnderstandsNonGenericTask()
    {
        // Arrange
        var testCompilation = TestCompilation.Create(_assembly);
        var factory         = new ViewComponentTagHelperDescriptorFactory(testCompilation);

        var viewComponent = testCompilation.GetTypeByMetadataName(typeof(AsyncViewComponentWithNonGenericTask).FullName);

        // Act
        var descriptor = factory.CreateDescriptor(viewComponent);

        // Assert
        Assert.Empty(descriptor.GetAllDiagnostics());
    }
    public void CreateDescriptor_ForViewComponentWithInvoke_DoesNotUnderstandGenericTask()
    {
        // Arrange
        var testCompilation = TestCompilation.Create(_assembly);
        var factory         = new ViewComponentTagHelperDescriptorFactory(testCompilation);

        var viewComponent = testCompilation.GetTypeByMetadataName(typeof(SyncViewComponentWithGenericTask).FullName);

        // Act
        var descriptor = factory.CreateDescriptor(viewComponent);

        // Assert
        var diagnostic = Assert.Single(descriptor.GetAllDiagnostics());

        Assert.Equal(RazorExtensionsDiagnosticFactory.ViewComponent_SyncMethod_CannotReturnTask.Id, diagnostic.Id);
    }
    public void CreateDescriptor_AddsDiagnostic_ForViewComponentWithNoInvokeMethod()
    {
        // Arrange
        var testCompilation = TestCompilation.Create(_assembly);
        var factory         = new ViewComponentTagHelperDescriptorFactory(testCompilation);

        var viewComponent = testCompilation.GetTypeByMetadataName(typeof(ViewComponentWithoutInvokeMethod).FullName);

        // Act
        var descriptor = factory.CreateDescriptor(viewComponent);

        // Assert
        var diagnostic = Assert.Single(descriptor.GetAllDiagnostics());

        Assert.Equal(RazorExtensionsDiagnosticFactory.ViewComponent_CannotFindMethod.Id, diagnostic.Id);
    }
    public void CreateDescriptor_ForViewComponent_WithAmbiguousMethods()
    {
        // Arrange
        var testCompilation = TestCompilation.Create(_assembly);
        var factory         = new ViewComponentTagHelperDescriptorFactory(testCompilation);

        var viewComponent = testCompilation.GetTypeByMetadataName(typeof(DerivedViewComponentWithAmbiguity).FullName);

        // Act
        var descriptor = factory.CreateDescriptor(viewComponent);

        // Assert
        var diagnostic = Assert.Single(descriptor.GetAllDiagnostics());

        Assert.Equal(RazorExtensionsDiagnosticFactory.ViewComponent_AmbiguousMethods.Id, diagnostic.Id);
    }
    public void CreateDescriptor_UnderstandsVariousParameterTypes()
    {
        // Arrange
        var testCompilation = TestCompilation.Create(_assembly);
        var viewComponent   = testCompilation.GetTypeByMetadataName(typeof(VariousParameterViewComponent).FullName);
        var factory         = new ViewComponentTagHelperDescriptorFactory(testCompilation);

        var expectedDescriptor = TagHelperDescriptorBuilder.Create(
            ViewComponentTagHelperConventions.Kind,
            "__Generated__VariousParameterViewComponentTagHelper",
            typeof(VariousParameterViewComponent).GetTypeInfo().Assembly.GetName().Name)
                                 .TypeName("__Generated__VariousParameterViewComponentTagHelper")
                                 .DisplayName("VariousParameterViewComponentTagHelper")
                                 .TagMatchingRuleDescriptor(rule =>
                                                            rule
                                                            .RequireTagName("vc:various-parameter")
                                                            .RequireAttributeDescriptor(attribute => attribute.Name("test-enum"))
                                                            .RequireAttributeDescriptor(attribute => attribute.Name("test-string"))
                                                            .RequireAttributeDescriptor(attribute => attribute.Name("baz")))
                                 .BoundAttributeDescriptor(attribute =>
                                                           attribute
                                                           .Name("test-enum")
                                                           .PropertyName("testEnum")
                                                           .TypeName(typeof(VariousParameterViewComponent).FullName + "." + nameof(VariousParameterViewComponent.TestEnum))
                                                           .AsEnum()
                                                           .DisplayName(typeof(VariousParameterViewComponent).FullName + "." + nameof(VariousParameterViewComponent.TestEnum) + " VariousParameterViewComponentTagHelper.testEnum"))
                                 .BoundAttributeDescriptor(attribute =>
                                                           attribute
                                                           .Name("test-string")
                                                           .PropertyName("testString")
                                                           .TypeName(typeof(string).FullName)
                                                           .DisplayName("string VariousParameterViewComponentTagHelper.testString"))
                                 .BoundAttributeDescriptor(attribute =>
                                                           attribute
                                                           .Name("baz")
                                                           .PropertyName("baz")
                                                           .TypeName(typeof(int).FullName)
                                                           .DisplayName("int VariousParameterViewComponentTagHelper.baz"))
                                 .AddMetadata(ViewComponentTagHelperMetadata.Name, "VariousParameter")
                                 .Build();

        // Act
        var descriptor = factory.CreateDescriptor(viewComponent);

        // Assert
        Assert.Equal(expectedDescriptor, descriptor, TagHelperDescriptorComparer.Default);
    }
    public void CreateDescriptor_ForSyncViewComponentWithInvokeInBaseType_Works()
    {
        // Arrange
        var testCompilation = TestCompilation.Create(_assembly);
        var factory         = new ViewComponentTagHelperDescriptorFactory(testCompilation);

        var expectedDescriptor = TagHelperDescriptorBuilder.Create(
            ViewComponentTagHelperConventions.Kind,
            "__Generated__SyncDerivedViewComponentTagHelper",
            typeof(SyncDerivedViewComponent).GetTypeInfo().Assembly.GetName().Name)
                                 .TypeName("__Generated__SyncDerivedViewComponentTagHelper")
                                 .DisplayName("SyncDerivedViewComponentTagHelper")
                                 .TagMatchingRuleDescriptor(rule =>
                                                            rule
                                                            .RequireTagName("vc:sync-derived")
                                                            .RequireAttributeDescriptor(attribute => attribute.Name("foo"))
                                                            .RequireAttributeDescriptor(attribute => attribute.Name("bar")))
                                 .BoundAttributeDescriptor(attribute =>
                                                           attribute
                                                           .Name("foo")
                                                           .PropertyName("foo")
                                                           .TypeName(typeof(string).FullName)
                                                           .DisplayName("string SyncDerivedViewComponentTagHelper.foo"))
                                 .BoundAttributeDescriptor(attribute =>
                                                           attribute
                                                           .Name("bar")
                                                           .PropertyName("bar")
                                                           .TypeName(typeof(string).FullName)
                                                           .DisplayName("string SyncDerivedViewComponentTagHelper.bar"))
                                 .AddMetadata(ViewComponentTagHelperMetadata.Name, "SyncDerived")
                                 .Build();

        var viewComponent = testCompilation.GetTypeByMetadataName(typeof(SyncDerivedViewComponent).FullName);

        // Act
        var descriptor = factory.CreateDescriptor(viewComponent);

        // Assert
        Assert.Equal(expectedDescriptor, descriptor, TagHelperDescriptorComparer.Default);
    }
    public void CreateDescriptor_UnderstandsGenericParameters()
    {
        // Arrange
        var testCompilation = TestCompilation.Create(_assembly);
        var viewComponent   = testCompilation.GetTypeByMetadataName(typeof(GenericParameterViewComponent).FullName);
        var factory         = new ViewComponentTagHelperDescriptorFactory(testCompilation);

        var expectedDescriptor = TagHelperDescriptorBuilder.Create(
            ViewComponentTagHelperConventions.Kind,
            "__Generated__GenericParameterViewComponentTagHelper",
            typeof(GenericParameterViewComponent).GetTypeInfo().Assembly.GetName().Name)
                                 .TypeName("__Generated__GenericParameterViewComponentTagHelper")
                                 .DisplayName("GenericParameterViewComponentTagHelper")
                                 .TagMatchingRuleDescriptor(rule =>
                                                            rule
                                                            .RequireTagName("vc:generic-parameter")
                                                            .RequireAttributeDescriptor(attribute => attribute.Name("foo")))
                                 .BoundAttributeDescriptor(attribute =>
                                                           attribute
                                                           .Name("foo")
                                                           .PropertyName("Foo")
                                                           .TypeName("System.Collections.Generic.List<System.String>")
                                                           .DisplayName("System.Collections.Generic.List<System.String> GenericParameterViewComponentTagHelper.Foo"))
                                 .BoundAttributeDescriptor(attribute =>
                                                           attribute
                                                           .Name("bar")
                                                           .PropertyName("Bar")
                                                           .TypeName("System.Collections.Generic.Dictionary<System.String, System.Int32>")
                                                           .AsDictionaryAttribute("bar-", typeof(int).FullName)
                                                           .DisplayName("System.Collections.Generic.Dictionary<System.String, System.Int32> GenericParameterViewComponentTagHelper.Bar"))
                                 .AddMetadata(ViewComponentTagHelperMetadata.Name, "GenericParameter")
                                 .Build();

        // Act
        var descriptor = factory.CreateDescriptor(viewComponent);

        // Assert
        Assert.Equal(expectedDescriptor, descriptor, TagHelperDescriptorComparer.Default);
    }