Skip to content

Optimize InternalUsageDiagnosticAnalyzer: replace ToDisplayString with symbol equality - #38726

Merged
AndriySvyryd merged 2 commits into
mainfrom
copilot/optimize-todisplaystring-check
Jul 31, 2026
Merged

Optimize InternalUsageDiagnosticAnalyzer: replace ToDisplayString with symbol equality#38726
AndriySvyryd merged 2 commits into
mainfrom
copilot/optimize-todisplaystring-check

Conversation

Copilot AI commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

HasInternalAttribute was calling ToDisplayString() on every attribute class for every analyzed symbol to match against EntityFrameworkInternalAttribute by name — allocating a new string each time. This was measured at ~36% of inclusive time in a perf trace, contributing ~2 MB of extra string allocations per build.

Changes

  • Cache attribute symbol at compilation start: Register actions via RegisterCompilationStartAction and resolve the INamedTypeSymbol for EntityFrameworkInternalAttribute once per compilation using GetTypeByMetadataName.
  • Replace string comparison with symbol equality: HasInternalAttribute now uses SymbolEqualityComparer.Default.Equals(a.AttributeClass, internalAttributeSymbol) — no allocation.
  • Thread cached symbol through call chain: All private methods that previously called HasInternalAttribute() now accept and forward INamedTypeSymbol? internalAttributeSymbol. If EFCore isn't referenced (null), the attribute check is skipped entirely.
// Before: allocates a string on every attribute of every symbol
private static bool HasInternalAttribute(ISymbol symbol)
    => symbol.GetAttributes().Any(a =>
        a.AttributeClass!.ToDisplayString()
        == "Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkInternalAttribute");

// After: resolved once per compilation, compared by reference
private static bool HasInternalAttribute(ISymbol symbol, INamedTypeSymbol? internalAttributeSymbol)
    => internalAttributeSymbol is not null
        && symbol.GetAttributes().Any(a =>
            SymbolEqualityComparer.Default.Equals(a.AttributeClass, internalAttributeSymbol));

…ocations

Instead of calling ToDisplayString() on every attribute class to compare against
the EntityFrameworkInternalAttribute name (which allocates a new string each time),
look up the INamedTypeSymbol for that attribute once per compilation in
CompilationStart and use SymbolEqualityComparer.Default.Equals() for comparisons.

Fixes #38723

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Copilot AI changed the title [WIP] Optimize ToDisplayString check in InternalUsageDiagnosticAnalyzer Optimize InternalUsageDiagnosticAnalyzer: replace ToDisplayString with symbol equality Jul 30, 2026
Copilot AI requested a review from AndriySvyryd July 30, 2026 23:27
@AndriySvyryd
AndriySvyryd requested a review from Copilot July 30, 2026 23:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR optimizes InternalUsageDiagnosticAnalyzer by removing repeated ToDisplayString() allocations during attribute checks and replacing them with cached symbol equality comparisons, addressing perf findings from #38723.

Changes:

  • Resolves EntityFrameworkInternalAttribute once per compilation via RegisterCompilationStartAction + GetTypeByMetadataName.
  • Replaces per-attribute string formatting/comparison with SymbolEqualityComparer.Default.Equals(...) against the cached symbol.
  • Threads the cached INamedTypeSymbol? through the analyzer’s private call chain so the attribute check becomes a fast no-op when the symbol can’t be resolved.

@AndriySvyryd
AndriySvyryd marked this pull request as ready for review July 31, 2026 00:48
@AndriySvyryd
AndriySvyryd requested a review from a team as a code owner July 31, 2026 00:48
@AndriySvyryd
AndriySvyryd merged commit b9678d4 into main Jul 31, 2026
18 checks passed
@AndriySvyryd
AndriySvyryd deleted the copilot/optimize-todisplaystring-check branch July 31, 2026 00:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

InternalUsageDiagnosticAnalyzer uses non-optimal ToDisplayString check to find matching attribute

4 participants