File: CSharpQualifyMemberAccessDiagnosticAnalyzer.cs
Web Access
Project: ..\..\..\src\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj (Microsoft.CodeAnalysis.CSharp.Features)
// 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.Linq;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Simplification;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.QualifyMemberAccess;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
 
namespace Microsoft.CodeAnalysis.CSharp.QualifyMemberAccess
{
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    internal sealed class CSharpQualifyMemberAccessDiagnosticAnalyzer
        : AbstractQualifyMemberAccessDiagnosticAnalyzer<SyntaxKind, ExpressionSyntax, SimpleNameSyntax>
    {
        protected override ISimplification Simplification
            => CSharpSimplification.Instance;
 
        protected override bool IsAlreadyQualifiedMemberAccess(ExpressionSyntax node)
            => node.IsKind(SyntaxKind.ThisExpression);
 
        // If the member is already qualified with `base.`,
        // or member is in object initialization context,
        // or member in property or field initialization,
        // or member in constructor initializer, it cannot be qualified.
        protected override bool CanMemberAccessBeQualified(ISymbol containingSymbol, SyntaxNode node)
        {
            if (node.GetAncestorOrThis<AttributeSyntax>() != null)
            {
                return false;
            }
 
            if (node.GetAncestorOrThis<ConstructorInitializerSyntax>() != null)
            {
                return false;
            }
 
            return !(node.IsKind(SyntaxKind.BaseExpression) ||
                     node.GetRequiredParent().GetRequiredParent().IsKind(SyntaxKind.ObjectInitializerExpression) ||
                     IsInPropertyOrFieldInitialization(containingSymbol, node));
        }
 
        private static bool IsInPropertyOrFieldInitialization(ISymbol containingSymbol, SyntaxNode node)
        {
            return (containingSymbol.Kind == SymbolKind.Field || containingSymbol.Kind == SymbolKind.Property) &&
                containingSymbol.DeclaringSyntaxReferences
                    .Select(declaringSyntaxReferences => declaringSyntaxReferences.GetSyntax())
                    .Any(declaringSyntax => IsInPropertyInitialization(declaringSyntax, node) || IsInFieldInitialization(declaringSyntax, node));
        }
 
        private static bool IsInPropertyInitialization(SyntaxNode declarationSyntax, SyntaxNode node)
            => declarationSyntax.IsKind(SyntaxKind.PropertyDeclaration) && declarationSyntax.Contains(node);
 
        private static bool IsInFieldInitialization(SyntaxNode declarationSyntax, SyntaxNode node)
            => declarationSyntax.GetAncestorsOrThis(n => n.IsKind(SyntaxKind.FieldDeclaration) && n.Contains(node)).Any();
 
        protected override Location GetLocation(IOperation operation) => operation.Syntax.GetLocation();
    }
}