From 15e4b605eb59e3ebc5eadfc9b8ed7000bf50ea2b Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Tue, 6 Aug 2019 22:41:02 -0700 Subject: [PATCH] Blazor API Review: RenderTree types (#12869) * Add analzyer for pubternal This is based on some existing code from EF. I'm having a discussion with them right now on the best way to share this logic. I also added support for parameters here which was missing. We might want to make this code converge with `BannedApiAnalyzer` which is much more thorough than this. This is using our existing package for testing analyzers thats the *official* way to do it in our repo. Filed #12868 to track that. * Add S C A R Y warnings to render tree types * PR feedback --- ...omponentInternalUsageDiagnosticAnalzyer.cs | 39 ++++++ .../Analyzers/src/DiagnosticDescriptors.cs | 9 ++ .../Analyzers/src/InternalUsageAnalyzer.cs | 126 ++++++++++++++++++ src/Components/Analyzers/src/Resources.resx | 63 +++++---- .../Analyzers/test/AnalyzerTestBase.cs | 68 ++++++++++ ...mponentAnalyzerDiagnosticAnalyzerRunner.cs | 31 +++++ ...nentInternalUsageDiagnoticsAnalyzerTest.cs | 60 +++++++++ ...pNetCore.Components.Analyzers.Tests.csproj | 18 ++- .../UsesRenderTreeFrameAsParameter.cs | 11 ++ .../UsesRenderTreeFrameTypeAsLocal.cs | 15 +++ .../src/RenderTree/ArrayBuilderSegment.cs | 5 +- .../Components/src/RenderTree/ArrayRange.cs | 7 +- .../src/RenderTree/RenderTreeDiff.cs | 7 +- .../src/RenderTree/RenderTreeEdit.cs | 5 +- .../src/RenderTree/RenderTreeEditType.cs | 5 +- .../src/RenderTree/RenderTreeFrame.cs | 5 +- .../src/RenderTree/RenderTreeFrameType.cs | 5 +- 17 files changed, 437 insertions(+), 42 deletions(-) create mode 100644 src/Components/Analyzers/src/ComponentInternalUsageDiagnosticAnalzyer.cs create mode 100644 src/Components/Analyzers/src/InternalUsageAnalyzer.cs create mode 100644 src/Components/Analyzers/test/AnalyzerTestBase.cs create mode 100644 src/Components/Analyzers/test/ComponentAnalyzerDiagnosticAnalyzerRunner.cs create mode 100644 src/Components/Analyzers/test/ComponentInternalUsageDiagnoticsAnalyzerTest.cs create mode 100644 src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameAsParameter.cs create mode 100644 src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameTypeAsLocal.cs diff --git a/src/Components/Analyzers/src/ComponentInternalUsageDiagnosticAnalzyer.cs b/src/Components/Analyzers/src/ComponentInternalUsageDiagnosticAnalzyer.cs new file mode 100644 index 0000000000..3f0c765614 --- /dev/null +++ b/src/Components/Analyzers/src/ComponentInternalUsageDiagnosticAnalzyer.cs @@ -0,0 +1,39 @@ +// 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.Collections.Immutable; +using Microsoft.AspNetCore.Components.Analyzers; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.Extensions.Internal +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class ComponentInternalUsageDiagnosticAnalyzer : DiagnosticAnalyzer + { + private readonly InternalUsageAnalyzer _inner; + + public ComponentInternalUsageDiagnosticAnalyzer() + { + // We don't have in *internal* attribute in Blazor. + _inner = new InternalUsageAnalyzer(IsInInternalNamespace, hasInternalAttribute: null, DiagnosticDescriptors.DoNotUseRenderTreeTypes); + } + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseRenderTreeTypes); + + public override void Initialize(AnalysisContext context) + { + _inner.Register(context); + } + + private static bool IsInInternalNamespace(ISymbol symbol) + { + if (symbol?.ContainingNamespace?.ToDisplayString() is string ns) + { + return string.Equals(ns, "Microsoft.AspNetCore.Components.RenderTree"); + } + + return false; + } + } +} diff --git a/src/Components/Analyzers/src/DiagnosticDescriptors.cs b/src/Components/Analyzers/src/DiagnosticDescriptors.cs index e0ecbce055..8eb86b3212 100644 --- a/src/Components/Analyzers/src/DiagnosticDescriptors.cs +++ b/src/Components/Analyzers/src/DiagnosticDescriptors.cs @@ -55,5 +55,14 @@ namespace Microsoft.AspNetCore.Components.Analyzers DiagnosticSeverity.Warning, isEnabledByDefault: true, description: new LocalizableResourceString(nameof(Resources.ComponentParameterShouldNotBeSetOutsideOfTheirDeclaredComponent_Description), Resources.ResourceManager, typeof(Resources))); + + public static readonly DiagnosticDescriptor DoNotUseRenderTreeTypes = new DiagnosticDescriptor( + "BL0006", + new LocalizableResourceString(nameof(Resources.DoNotUseRenderTreeTypes_Title), Resources.ResourceManager, typeof(Resources)), + new LocalizableResourceString(nameof(Resources.DoNotUseRenderTreeTypes_Description), Resources.ResourceManager, typeof(Resources)), + "Usage", + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: new LocalizableResourceString(nameof(Resources.DoNotUseRenderTreeTypes_Description), Resources.ResourceManager, typeof(Resources))); } } diff --git a/src/Components/Analyzers/src/InternalUsageAnalyzer.cs b/src/Components/Analyzers/src/InternalUsageAnalyzer.cs new file mode 100644 index 0000000000..92b07a7ab2 --- /dev/null +++ b/src/Components/Analyzers/src/InternalUsageAnalyzer.cs @@ -0,0 +1,126 @@ +// 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; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.Extensions.Internal +{ + internal class InternalUsageAnalyzer + { + private readonly Func _isInternalNamespace; + private readonly Func _hasInternalAttribute; + private readonly DiagnosticDescriptor _descriptor; + + /// + /// Creates a new instance of . The creator should provide delegates to help determine whether + /// a given symbol is internal or not, and a to create errors. + /// + /// The delegate used to check if a symbol belongs to an internal namespace. + /// The delegate used to check if a symbol has an internal attribute. + /// + /// The used to create errors. The error message should expect a single parameter + /// used for the display name of the member. + /// + public InternalUsageAnalyzer(Func isInInternalNamespace, Func hasInternalAttribute, DiagnosticDescriptor descriptor) + { + _isInternalNamespace = isInInternalNamespace ?? new Func((_) => false); + _hasInternalAttribute = hasInternalAttribute ?? new Func((_) => false); + _descriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor)); + } + + public void Register(AnalysisContext context) + { + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeNode, + SyntaxKind.SimpleMemberAccessExpression, + SyntaxKind.ObjectCreationExpression, + SyntaxKind.ClassDeclaration, + SyntaxKind.Parameter); + } + + private void AnalyzeNode(SyntaxNodeAnalysisContext context) + { + switch (context.Node) + { + case MemberAccessExpressionSyntax memberAccessSyntax: + { + if (context.SemanticModel.GetSymbolInfo(context.Node, context.CancellationToken).Symbol is ISymbol symbol && + symbol.ContainingAssembly != context.Compilation.Assembly) + { + var containingType = symbol.ContainingType; + + if (HasInternalAttribute(symbol)) + { + context.ReportDiagnostic(Diagnostic.Create(_descriptor, memberAccessSyntax.Name.GetLocation(), $"{containingType}.{symbol.Name}")); + return; + } + + if (IsInInternalNamespace(containingType) || HasInternalAttribute(containingType)) + { + context.ReportDiagnostic(Diagnostic.Create(_descriptor, memberAccessSyntax.Name.GetLocation(), containingType)); + return; + } + } + return; + } + + case ObjectCreationExpressionSyntax creationSyntax: + { + if (context.SemanticModel.GetSymbolInfo(context.Node, context.CancellationToken).Symbol is ISymbol symbol && + symbol.ContainingAssembly != context.Compilation.Assembly) + { + var containingType = symbol.ContainingType; + + if (HasInternalAttribute(symbol)) + { + context.ReportDiagnostic(Diagnostic.Create(_descriptor, creationSyntax.GetLocation(), containingType)); + return; + } + + if (IsInInternalNamespace(containingType) || HasInternalAttribute(containingType)) + { + context.ReportDiagnostic(Diagnostic.Create(_descriptor, creationSyntax.Type.GetLocation(), containingType)); + return; + } + } + + return; + } + + case ClassDeclarationSyntax declarationSyntax: + { + if (context.SemanticModel.GetDeclaredSymbol(declarationSyntax)?.BaseType is ISymbol symbol && + symbol.ContainingAssembly != context.Compilation.Assembly && + (IsInInternalNamespace(symbol) || HasInternalAttribute(symbol)) && + declarationSyntax.BaseList?.Types.Count > 0) + { + context.ReportDiagnostic(Diagnostic.Create(_descriptor, declarationSyntax.BaseList.Types[0].GetLocation(), symbol)); + } + + return; + } + + case ParameterSyntax parameterSyntax: + { + if (context.SemanticModel.GetDeclaredSymbol(parameterSyntax)?.Type is ISymbol symbol && + symbol.ContainingAssembly != context.Compilation.Assembly && + (IsInInternalNamespace(symbol) || HasInternalAttribute(symbol))) + { + + context.ReportDiagnostic(Diagnostic.Create(_descriptor, parameterSyntax.GetLocation(), symbol)); + } + + return; + } + } + } + + private bool HasInternalAttribute(ISymbol symbol) => _hasInternalAttribute(symbol); + + private bool IsInInternalNamespace(ISymbol symbol) => _isInternalNamespace(symbol); + } +} diff --git a/src/Components/Analyzers/src/Resources.resx b/src/Components/Analyzers/src/Resources.resx index 648adb2c3b..ed4f36c531 100644 --- a/src/Components/Analyzers/src/Resources.resx +++ b/src/Components/Analyzers/src/Resources.resx @@ -1,17 +1,17 @@ - @@ -165,4 +165,13 @@ Component parameter should not be set outside of its component. + + The types in 'Microsoft.AspNetCore.Components.RenderTree' are not recommended for use outside of the Blazor framework. These type definitions will change in future releases. + + + The type or member {0} is is not recommended for use outside of the Blazor frameworks. Types defined in 'Microsoft.AspNetCore.Components.RenderTree' will change in future releases. + + + Do not use RenderTree types + \ No newline at end of file diff --git a/src/Components/Analyzers/test/AnalyzerTestBase.cs b/src/Components/Analyzers/test/AnalyzerTestBase.cs new file mode 100644 index 0000000000..e174b4f667 --- /dev/null +++ b/src/Components/Analyzers/test/AnalyzerTestBase.cs @@ -0,0 +1,68 @@ +// 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; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Analyzer.Testing; +using Microsoft.AspNetCore.Testing; +using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.CodeAnalysis; + +namespace Microsoft.AspNetCore.Components.Analyzers +{ + public abstract class AnalyzerTestBase + { + private static readonly string ProjectDirectory = GetProjectDirectory(); + + public TestSource Read(string source) + { + if (!source.EndsWith(".cs")) + { + source = source + ".cs"; + } + + var filePath = Path.Combine(ProjectDirectory, "TestFiles", GetType().Name, source); + if (!File.Exists(filePath)) + { + throw new FileNotFoundException($"TestFile {source} could not be found at {filePath}.", filePath); + } + + var fileContent = File.ReadAllText(filePath); + return TestSource.Read(fileContent); + } + + public Project CreateProject(string source) + { + if (!source.EndsWith(".cs")) + { + source = source + ".cs"; + } + + var read = Read(source); + return DiagnosticProject.Create(GetType().Assembly, new[] { read.Source, }); + } + + public Task CreateCompilationAsync(string source) + { + return CreateProject(source).GetCompilationAsync(); + } + + private static string GetProjectDirectory() + { + // On helix we use the published test files + if (SkipOnHelixAttribute.OnHelix()) + { + return AppContext.BaseDirectory; + } + + // This test code needs to be updated to support distributed testing. + // See https://github.com/aspnet/AspNetCore/issues/10422 +#pragma warning disable 0618 + var solutionDirectory = TestPathUtilities.GetSolutionRootDirectory("Components"); +#pragma warning restore 0618 + var projectDirectory = Path.Combine(solutionDirectory, "Analyzers", "test"); + return projectDirectory; + } + } +} diff --git a/src/Components/Analyzers/test/ComponentAnalyzerDiagnosticAnalyzerRunner.cs b/src/Components/Analyzers/test/ComponentAnalyzerDiagnosticAnalyzerRunner.cs new file mode 100644 index 0000000000..727f060bd4 --- /dev/null +++ b/src/Components/Analyzers/test/ComponentAnalyzerDiagnosticAnalyzerRunner.cs @@ -0,0 +1,31 @@ +// 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; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Analyzer.Testing; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.AspNetCore.Components.Analyzers +{ + internal class ComponentAnalyzerDiagnosticAnalyzerRunner : DiagnosticAnalyzerRunner + { + public ComponentAnalyzerDiagnosticAnalyzerRunner(DiagnosticAnalyzer analyzer) + { + Analyzer = analyzer; + } + + public DiagnosticAnalyzer Analyzer { get; } + + public Task GetDiagnosticsAsync(string source) + { + return GetDiagnosticsAsync(sources: new[] { source }, Analyzer, Array.Empty()); + } + + public Task GetDiagnosticsAsync(Project project) + { + return GetDiagnosticsAsync(new[] { project }, Analyzer, Array.Empty()); + } + } +} diff --git a/src/Components/Analyzers/test/ComponentInternalUsageDiagnoticsAnalyzerTest.cs b/src/Components/Analyzers/test/ComponentInternalUsageDiagnoticsAnalyzerTest.cs new file mode 100644 index 0000000000..92e2252304 --- /dev/null +++ b/src/Components/Analyzers/test/ComponentInternalUsageDiagnoticsAnalyzerTest.cs @@ -0,0 +1,60 @@ +// 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.Threading.Tasks; +using Microsoft.AspNetCore.Analyzer.Testing; +using Microsoft.Extensions.Internal; +using Xunit; + +namespace Microsoft.AspNetCore.Components.Analyzers +{ + public class ComponentInternalUsageDiagnoticsAnalyzerTest : AnalyzerTestBase + { + public ComponentInternalUsageDiagnoticsAnalyzerTest() + { + Analyzer = new ComponentInternalUsageDiagnosticAnalyzer(); + Runner = new ComponentAnalyzerDiagnosticAnalyzerRunner(Analyzer); + } + + private ComponentInternalUsageDiagnosticAnalyzer Analyzer { get; } + private ComponentAnalyzerDiagnosticAnalyzerRunner Runner { get; } + + [Fact] + public async Task InternalUsage_FindsUseOfRenderTreeFrameAsParameter() + { + // Arrange + var source = Read("UsesRenderTreeFrameAsParameter"); + + // Act + var diagnostics = await Runner.GetDiagnosticsAsync(source.Source); + + // Assert + Assert.Collection( + diagnostics, + diagnostic => + { + Assert.Same(DiagnosticDescriptors.DoNotUseRenderTreeTypes, diagnostic.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location); + }); + } + + [Fact] + public async Task InternalUsage_FindsUseOfRenderTreeType() + { + // Arrange + var source = Read("UsesRenderTreeFrameTypeAsLocal"); + + // Act + var diagnostics = await Runner.GetDiagnosticsAsync(source.Source); + + // Assert + Assert.Collection( + diagnostics, + diagnostic => + { + Assert.Same(DiagnosticDescriptors.DoNotUseRenderTreeTypes, diagnostic.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location); + }); + } + } +} diff --git a/src/Components/Analyzers/test/Microsoft.AspNetCore.Components.Analyzers.Tests.csproj b/src/Components/Analyzers/test/Microsoft.AspNetCore.Components.Analyzers.Tests.csproj index a31c1a8f0e..45b379c65c 100644 --- a/src/Components/Analyzers/test/Microsoft.AspNetCore.Components.Analyzers.Tests.csproj +++ b/src/Components/Analyzers/test/Microsoft.AspNetCore.Components.Analyzers.Tests.csproj @@ -2,16 +2,24 @@ netcoreapp3.0 - - - - - + + + false + + + + + + + + + + diff --git a/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameAsParameter.cs b/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameAsParameter.cs new file mode 100644 index 0000000000..415030a011 --- /dev/null +++ b/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameAsParameter.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Components.RenderTree; + +namespace Microsoft.AspNetCore.Components.Analyzers.Tests.TestFiles.ComponentInternalUsageDiagnoticsAnalyzerTest +{ + class UsesRenderTreeFrameAsParameter + { + private void Test(/*MM*/RenderTreeFrame frame) + { + } + } +} diff --git a/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameTypeAsLocal.cs b/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameTypeAsLocal.cs new file mode 100644 index 0000000000..bdd40c2df1 --- /dev/null +++ b/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnoticsAnalyzerTest/UsesRenderTreeFrameTypeAsLocal.cs @@ -0,0 +1,15 @@ +using System; +using Microsoft.AspNetCore.Components.RenderTree; + +namespace Microsoft.AspNetCore.Components.Analyzers.Tests.TestFiles.ComponentInternalUsageDiagnoticsAnalyzerTest +{ + class UsesRenderTreeFrameTypeAsLocal + { + private void Test() + { + var test = RenderTreeFrameType./*MM*/Attribute; + GC.KeepAlive(test); + } + + } +} diff --git a/src/Components/Components/src/RenderTree/ArrayBuilderSegment.cs b/src/Components/Components/src/RenderTree/ArrayBuilderSegment.cs index 18317ece48..3377e18163 100644 --- a/src/Components/Components/src/RenderTree/ArrayBuilderSegment.cs +++ b/src/Components/Components/src/RenderTree/ArrayBuilderSegment.cs @@ -8,9 +8,12 @@ using System.Collections.Generic; namespace Microsoft.AspNetCore.Components.RenderTree { /// - /// Represents a range of elements within an instance of . + /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside + /// of the Blazor framework. These types will change in future release. /// /// The type of the elements in the array + // + // Represents a range of elements within an instance of . public readonly struct ArrayBuilderSegment : IEnumerable { // The following fields are memory mapped to the WASM client. Do not re-order or use auto-properties. diff --git a/src/Components/Components/src/RenderTree/ArrayRange.cs b/src/Components/Components/src/RenderTree/ArrayRange.cs index ec113dbdb8..b27a8d5310 100644 --- a/src/Components/Components/src/RenderTree/ArrayRange.cs +++ b/src/Components/Components/src/RenderTree/ArrayRange.cs @@ -4,9 +4,12 @@ namespace Microsoft.AspNetCore.Components.RenderTree { /// - /// Represents a range of elements in an array that are in use. + /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside + /// of the Blazor framework. These types will change in future release. /// - /// The array item type. + /// + // + // Represents a range of elements in an array that are in use. public readonly struct ArrayRange { /// diff --git a/src/Components/Components/src/RenderTree/RenderTreeDiff.cs b/src/Components/Components/src/RenderTree/RenderTreeDiff.cs index 9ad92ec31b..da5b3ed3f7 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeDiff.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeDiff.cs @@ -1,13 +1,14 @@ // 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; - namespace Microsoft.AspNetCore.Components.RenderTree { /// - /// Describes changes to a component's render tree between successive renders. + /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside + /// of the Blazor framework. These types will change in future release. /// + // + // Describes changes to a component's render tree between successive renders. public readonly struct RenderTreeDiff { /// diff --git a/src/Components/Components/src/RenderTree/RenderTreeEdit.cs b/src/Components/Components/src/RenderTree/RenderTreeEdit.cs index 96f661924b..68437a7471 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeEdit.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeEdit.cs @@ -6,8 +6,11 @@ using System.Runtime.InteropServices; namespace Microsoft.AspNetCore.Components.RenderTree { /// - /// Represents a single edit operation on a component's render tree. + /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside + /// of the Blazor framework. These types will change in future release. /// + // + // Represents a single edit operation on a component's render tree. [StructLayout(LayoutKind.Explicit)] public readonly struct RenderTreeEdit { diff --git a/src/Components/Components/src/RenderTree/RenderTreeEditType.cs b/src/Components/Components/src/RenderTree/RenderTreeEditType.cs index c2f3e4aba6..f508760135 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeEditType.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeEditType.cs @@ -4,8 +4,11 @@ namespace Microsoft.AspNetCore.Components.RenderTree { /// - /// Describes the type of a render tree edit operation. + /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside + /// of the Blazor framework. These types will change in future release. /// + // + //Describes the type of a render tree edit operation. public enum RenderTreeEditType: int { /// diff --git a/src/Components/Components/src/RenderTree/RenderTreeFrame.cs b/src/Components/Components/src/RenderTree/RenderTreeFrame.cs index f3e003080b..39dd7de74a 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeFrame.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeFrame.cs @@ -8,8 +8,11 @@ using Microsoft.AspNetCore.Components.Rendering; namespace Microsoft.AspNetCore.Components.RenderTree { /// - /// Represents an entry in a tree of user interface (UI) items. + /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside + /// of the Blazor framework. These types will change in future release. /// + // + // Represents an entry in a tree of user interface (UI) items. [StructLayout(LayoutKind.Explicit, Pack = 4)] public readonly struct RenderTreeFrame { diff --git a/src/Components/Components/src/RenderTree/RenderTreeFrameType.cs b/src/Components/Components/src/RenderTree/RenderTreeFrameType.cs index 61d2558305..339a7b6795 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeFrameType.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeFrameType.cs @@ -4,8 +4,11 @@ namespace Microsoft.AspNetCore.Components.RenderTree { /// - /// Describes the type of a . + /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside + /// of the Blazor framework. These types will change in future release. /// + // + // Describes the type of a . public enum RenderTreeFrameType: short { ///