File: src\Workspaces\SharedUtilitiesAndExtensions\Workspace\Core\Simplification\Simplifiers\AbstractMemberAccessExpressionSimplifier.cs
Web Access
Project: src\src\CodeStyle\Core\CodeFixes\Microsoft.CodeAnalysis.CodeStyle.Fixes.csproj (Microsoft.CodeAnalysis.CodeStyle.Fixes)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
 
namespace Microsoft.CodeAnalysis.Simplification.Simplifiers;
 
internal abstract class AbstractMemberAccessExpressionSimplifier<
    TExpressionSyntax,
    TMemberAccessExpressionSyntax,
    TThisExpressionSyntax>
    where TExpressionSyntax : SyntaxNode
    where TMemberAccessExpressionSyntax : TExpressionSyntax
    where TThisExpressionSyntax : TExpressionSyntax
{
    protected abstract ISyntaxFacts SyntaxFacts { get; }
    protected abstract ISpeculationAnalyzer GetSpeculationAnalyzer(
        SemanticModel semanticModel, TMemberAccessExpressionSyntax memberAccessExpression, CancellationToken cancellationToken);
 
    protected abstract bool MayCauseParseDifference(TMemberAccessExpressionSyntax memberAccessExpression);
 
    /// <summary>
    /// Checks a member access expression <c>expr.Name</c> and, if it is of the form <c>this.Name</c> or
    /// <c>Me.Name</c> determines if it is safe to replace with just <c>Name</c> alone.
    /// </summary>
    public bool ShouldSimplifyThisMemberAccessExpression(
        TMemberAccessExpressionSyntax? memberAccessExpression,
        SemanticModel semanticModel,
        SimplifierOptions simplifierOptions,
        [NotNullWhen(true)] out TThisExpressionSyntax? thisExpression,
        out NotificationOption2 notificationOption,
        CancellationToken cancellationToken)
    {
        notificationOption = NotificationOption2.Silent;
        thisExpression = null;
 
        if (memberAccessExpression is null)
            return false;
 
        var syntaxFacts = this.SyntaxFacts;
        if (!syntaxFacts.IsSimpleMemberAccessExpression(memberAccessExpression))
            return false;
 
        thisExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(memberAccessExpression) as TThisExpressionSyntax;
        if (!syntaxFacts.IsThisExpression(thisExpression))
            return false;
 
        var symbolInfo = semanticModel.GetSymbolInfo(memberAccessExpression, cancellationToken);
        if (symbolInfo.Symbol == null)
            return false;
 
        if (!simplifierOptions.TryGetQualifyMemberAccessOption(symbolInfo.Symbol.Kind, out var optionValue))
            return false;
 
        // We always simplify a static accesses off of this/me.  Otherwise, we fall back to whatever the user's option is.
        if (!symbolInfo.Symbol.IsStatic && optionValue.Value)
            return false;
 
        var speculationAnalyzer = GetSpeculationAnalyzer(semanticModel, memberAccessExpression, cancellationToken);
        var newSymbolInfo = speculationAnalyzer.SpeculativeSemanticModel.GetSymbolInfo(speculationAnalyzer.ReplacedExpression, cancellationToken);
        if (!symbolInfo.Symbol.Equals(newSymbolInfo.Symbol, SymbolEqualityComparer.IncludeNullability))
            return false;
 
        notificationOption = optionValue.Notification;
        return !semanticModel.SyntaxTree.OverlapsHiddenPosition(memberAccessExpression.Span, cancellationToken) &&
               !MayCauseParseDifference(memberAccessExpression);
    }
}