From 2ff8f45193a893c518a4fe9648de97555b3c7603 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 15 Nov 2019 14:41:33 -0800 Subject: [PATCH] Optimize namespace comparisons (#17119) Fixes: #16922 Improves the performance significantly by avoiding allocations for the purpose of comparing the namespace. --- .../ComponentInternalUsageDiagnosticAnalzyer.cs | 17 ++++++++++++++--- .../Analyzers/src/InternalUsageAnalyzer.cs | 1 + ...onentInternalUsageDiagnosticsAnalyzerTest.cs | 15 +++++++++++++++ .../UsersRendererTypesInMethodBody.cs | 4 +++- .../UsesRendererTypesInDeclarations.cs | 2 +- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/Components/Analyzers/src/ComponentInternalUsageDiagnosticAnalzyer.cs b/src/Components/Analyzers/src/ComponentInternalUsageDiagnosticAnalzyer.cs index 8f6272c326..b1b5724cb3 100644 --- a/src/Components/Analyzers/src/ComponentInternalUsageDiagnosticAnalzyer.cs +++ b/src/Components/Analyzers/src/ComponentInternalUsageDiagnosticAnalzyer.cs @@ -1,6 +1,7 @@ // 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.Collections.Immutable; using Microsoft.AspNetCore.Components.Analyzers; using Microsoft.CodeAnalysis; @@ -15,6 +16,8 @@ namespace Microsoft.Extensions.Internal [DiagnosticAnalyzer(LanguageNames.CSharp)] public class ComponentInternalUsageDiagnosticAnalyzer : DiagnosticAnalyzer { + private static readonly string[] NamespaceParts = new[] { "RenderTree", "Components", "AspNetCore", "Microsoft", }; + private readonly InternalUsageAnalyzer _inner; public ComponentInternalUsageDiagnosticAnalyzer() @@ -27,17 +30,25 @@ namespace Microsoft.Extensions.Internal public override void Initialize(AnalysisContext context) { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); + _inner.Register(context); } private static bool IsInInternalNamespace(ISymbol symbol) { - if (symbol?.ContainingNamespace?.ToDisplayString() is string ns) + var @namespace = symbol?.ContainingNamespace; + for (var i = 0; i < NamespaceParts.Length; i++) { - return string.Equals(ns, "Microsoft.AspNetCore.Components.RenderTree"); + if (@namespace == null || !string.Equals(NamespaceParts[i], @namespace.Name, StringComparison.Ordinal)) + { + return false; + } + + @namespace = @namespace.ContainingNamespace; } - return false; + return @namespace.IsGlobalNamespace; } } } diff --git a/src/Components/Analyzers/src/InternalUsageAnalyzer.cs b/src/Components/Analyzers/src/InternalUsageAnalyzer.cs index 2d76122377..495e4c90fa 100644 --- a/src/Components/Analyzers/src/InternalUsageAnalyzer.cs +++ b/src/Components/Analyzers/src/InternalUsageAnalyzer.cs @@ -40,6 +40,7 @@ namespace Microsoft.Extensions.Internal context.RegisterOperationAction( AnalyzeOperation, OperationKind.ObjectCreation, + OperationKind.Invocation, OperationKind.FieldReference, OperationKind.MethodReference, OperationKind.PropertyReference, diff --git a/src/Components/Analyzers/test/ComponentInternalUsageDiagnosticsAnalyzerTest.cs b/src/Components/Analyzers/test/ComponentInternalUsageDiagnosticsAnalyzerTest.cs index 3c5b11b577..c7a01a5c63 100644 --- a/src/Components/Analyzers/test/ComponentInternalUsageDiagnosticsAnalyzerTest.cs +++ b/src/Components/Analyzers/test/ComponentInternalUsageDiagnosticsAnalyzerTest.cs @@ -42,6 +42,11 @@ namespace Microsoft.AspNetCore.Components.Analyzers AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MMField"], diagnostic.Location); }, diagnostic => + { + Assert.Same(DiagnosticDescriptors.DoNotUseRenderTreeTypes, diagnostic.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MMInvocation"], diagnostic.Location); + }, + diagnostic => { Assert.Same(DiagnosticDescriptors.DoNotUseRenderTreeTypes, diagnostic.Descriptor); AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MMProperty"], diagnostic.Location); @@ -84,6 +89,16 @@ namespace Microsoft.AspNetCore.Components.Analyzers { Assert.Same(DiagnosticDescriptors.DoNotUseRenderTreeTypes, diagnostic.Descriptor); AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MMProperty"], diagnostic.Location); + }, + diagnostic => + { + Assert.Same(DiagnosticDescriptors.DoNotUseRenderTreeTypes, diagnostic.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MMNewObject2"], diagnostic.Location); + }, + diagnostic => + { + Assert.Same(DiagnosticDescriptors.DoNotUseRenderTreeTypes, diagnostic.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MMInvocation"], diagnostic.Location); }); } } diff --git a/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnosticsAnalyzerTest/UsersRendererTypesInMethodBody.cs b/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnosticsAnalyzerTest/UsersRendererTypesInMethodBody.cs index c6495e084e..9bd27fb960 100644 --- a/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnosticsAnalyzerTest/UsersRendererTypesInMethodBody.cs +++ b/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnosticsAnalyzerTest/UsersRendererTypesInMethodBody.cs @@ -12,7 +12,9 @@ namespace Microsoft.AspNetCore.Components.Analyzers.Tests.TestFiles.ComponentInt var frame = /*MMNewObject*/new RenderTreeFrame(); GC.KeepAlive(/*MMProperty*/frame.Component); - } + var range = /*MMNewObject2*/new ArrayRange(null, 0); + /*MMInvocation*/range.Clone(); + } } } diff --git a/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnosticsAnalyzerTest/UsesRendererTypesInDeclarations.cs b/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnosticsAnalyzerTest/UsesRendererTypesInDeclarations.cs index ad0e10bbc5..e2877b0df5 100644 --- a/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnosticsAnalyzerTest/UsesRendererTypesInDeclarations.cs +++ b/src/Components/Analyzers/test/TestFiles/ComponentInternalUsageDiagnosticsAnalyzerTest/UsesRendererTypesInDeclarations.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Components.Analyzers.Tests.TestFiles.ComponentInt private Renderer /*MMField*/_field = null; public UsesRendererTypesInDeclarations() - : base(null, null) + /*MMInvocation*/: base(null, null) { }