diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs index 365b4f2624..516b4d7a8b 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs @@ -4574,7 +4574,7 @@ namespace Test { public class MyComponent : ComponentBase { - [Parameter] public string Message { get; private set; } + [Parameter] public string Message { get; set; } } } ")); @@ -4603,7 +4603,7 @@ namespace Test { public class MyComponent : ComponentBase { - [Parameter] public string Message { get; private set; } + [Parameter] public string Message { get; set; } } } ")); @@ -4634,7 +4634,7 @@ namespace Test { public class MyComponent : ComponentBase { - [Parameter] public string Message { get; private set; } + [Parameter] public string Message { get; set; } } } ")); @@ -4664,9 +4664,9 @@ namespace Test { public class MyComponent : ComponentBase { - [Parameter] public string Message { get; private set; } - [Parameter] public EventCallback MessageChanged { get; private set; } - [Parameter] public Expression> MessageExpression { get; private set; } + [Parameter] public string Message { get; set; } + [Parameter] public EventCallback MessageChanged { get; set; } + [Parameter] public Expression> MessageExpression { get; set; } } } ")); @@ -4699,9 +4699,9 @@ namespace Test { public class MyComponent : ComponentBase { - [Parameter] public string Message { get; private set; } - [Parameter] public EventCallback MessageChanged { get; private set; } - [Parameter] public Expression> MessageExpression { get; private set; } + [Parameter] public string Message { get; set; } + [Parameter] public EventCallback MessageChanged { get; set; } + [Parameter] public Expression> MessageExpression { get; set; } } } ")); @@ -4734,9 +4734,9 @@ namespace Test { public class MyComponent : ComponentBase { - [Parameter] public string Message { get; private set; } - [Parameter] public EventCallback MessageChanged { get; private set; } - [Parameter] public Expression> MessageExpression { get; private set; } + [Parameter] public string Message { get; set; } + [Parameter] public EventCallback MessageChanged { get; set; } + [Parameter] public Expression> MessageExpression { get; set; } } } ")); diff --git a/src/Razor/Microsoft.CodeAnalysis.Razor/src/ComponentTagHelperDescriptorProvider.cs b/src/Razor/Microsoft.CodeAnalysis.Razor/src/ComponentTagHelperDescriptorProvider.cs index 30b8983983..29aa54ced0 100644 --- a/src/Razor/Microsoft.CodeAnalysis.Razor/src/ComponentTagHelperDescriptorProvider.cs +++ b/src/Razor/Microsoft.CodeAnalysis.Razor/src/ComponentTagHelperDescriptorProvider.cs @@ -4,10 +4,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; -using Microsoft.CodeAnalysis.CSharp; namespace Microsoft.CodeAnalysis.Razor { @@ -18,10 +16,6 @@ namespace Microsoft.CodeAnalysis.Razor .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted) .WithMiscellaneousOptions(SymbolDisplayFormat.FullyQualifiedFormat.MiscellaneousOptions & (~SymbolDisplayMiscellaneousOptions.UseSpecialTypes)); - private static MethodInfo WithMetadataImportOptionsMethodInfo = - typeof(CSharpCompilationOptions) - .GetMethod("WithMetadataImportOptions", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - public bool IncludeDocumentation { get; set; } public int Order { get; set; } @@ -40,9 +34,6 @@ namespace Microsoft.CodeAnalysis.Razor return; } - // We need to see private members too - compilation = WithMetadataImportOptionsAll(compilation); - var symbols = ComponentSymbols.Create(compilation); var types = new List(); @@ -81,13 +72,6 @@ namespace Microsoft.CodeAnalysis.Razor } } - private Compilation WithMetadataImportOptionsAll(Compilation compilation) - { - var newCompilationOptions = (CSharpCompilationOptions)WithMetadataImportOptionsMethodInfo - .Invoke(compilation.Options, new object[] { /* All */ (byte)2 }); - return compilation.WithOptions(newCompilationOptions); - } - private TagHelperDescriptor CreateShortNameMatchingDescriptor(ComponentSymbols symbols, INamedTypeSymbol type) { var builder = CreateDescriptorBuilder(symbols, type); @@ -216,9 +200,9 @@ namespace Microsoft.CodeAnalysis.Razor } // We need to check for cases like: - // [Parameter] List MyProperty { get; set; } + // [Parameter] public List MyProperty { get; set; } // AND - // [Parameter] List MyProperty { get; set; } + // [Parameter] public List MyProperty { get; set; } // // We need to inspect the type arguments to tell the difference between a property that // uses the containing class' type parameter(s) and a vanilla usage of generic types like @@ -333,6 +317,7 @@ namespace Microsoft.CodeAnalysis.Razor // a dictionary keyed on property name. // // We consider parameters to be defined by properties satisfying all of the following: + // - are public // - are visible (not shadowed) // - have the [Parameter] attribute // - have a setter, even if private @@ -367,6 +352,12 @@ namespace Microsoft.CodeAnalysis.Razor } var kind = PropertyKind.Default; + if (property.DeclaredAccessibility != Accessibility.Public) + { + // Not public + kind = PropertyKind.Ignored; + } + if (property.Parameters.Length != 0) { // Indexer @@ -378,6 +369,11 @@ namespace Microsoft.CodeAnalysis.Razor // No setter kind = PropertyKind.Ignored; } + else if (property.SetMethod.DeclaredAccessibility != Accessibility.Public) + { + // No public setter + kind = PropertyKind.Ignored; + } if (property.IsStatic) { diff --git a/src/Razor/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs b/src/Razor/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs index 329a8606b5..42461de24c 100644 --- a/src/Razor/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs +++ b/src/Razor/Microsoft.CodeAnalysis.Razor/test/ComponentTagHelperDescriptorProviderTest.cs @@ -246,6 +246,86 @@ namespace Test Assert.Equal("System.String", attribute.TypeName); } + [Fact] + public void Execute_IgnoresPrivateParameters_CreatesDescriptor() + { + // Arrange + + var compilation = BaseCompilation.AddSyntaxTrees(Parse(@" +using Microsoft.AspNetCore.Components; + +namespace Test +{ + public class MyComponent : ComponentBase + { + [Parameter] + private string MyProperty { get; set; } + } +} + +")); + + Assert.Empty(compilation.GetDiagnostics()); + + var context = TagHelperDescriptorProviderContext.Create(); + context.SetCompilation(compilation); + + var provider = new ComponentTagHelperDescriptorProvider(); + + // Act + provider.Execute(context); + + // Assert + var components = ExcludeBuiltInComponents(context); + components = AssertAndExcludeFullyQualifiedNameMatchComponents(components, expectedCount: 1); + var component = Assert.Single(components); + + Assert.Equal("TestAssembly", component.AssemblyName); + Assert.Equal("Test.MyComponent", component.Name); + + Assert.Empty(component.BoundAttributes); + } + + [Fact] + public void Execute_IgnoresParametersWithPrivateSetters_CreatesDescriptor() + { + // Arrange + + var compilation = BaseCompilation.AddSyntaxTrees(Parse(@" +using Microsoft.AspNetCore.Components; + +namespace Test +{ + public class MyComponent : ComponentBase + { + [Parameter] + public string MyProperty { get; private set; } + } +} + +")); + + Assert.Empty(compilation.GetDiagnostics()); + + var context = TagHelperDescriptorProviderContext.Create(); + context.SetCompilation(compilation); + + var provider = new ComponentTagHelperDescriptorProvider(); + + // Act + provider.Execute(context); + + // Assert + var components = ExcludeBuiltInComponents(context); + components = AssertAndExcludeFullyQualifiedNameMatchComponents(components, expectedCount: 1); + var component = Assert.Single(components); + + Assert.Equal("TestAssembly", component.AssemblyName); + Assert.Equal("Test.MyComponent", component.Name); + + Assert.Empty(component.BoundAttributes); + } + [Fact] // bool properties support minimized attributes public void Execute_BoolProperty_CreatesDescriptor() {