|
// 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.
#nullable disable
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
internal sealed class NamingStyleRules(ImmutableArray<NamingRule> namingRules)
{
public ImmutableArray<NamingRule> NamingRules { get; } = namingRules;
private readonly ImmutableArray<SymbolKind> _symbolKindsThatCanBeOverridden =
[SymbolKind.Method, SymbolKind.Property, SymbolKind.Event];
internal bool TryGetApplicableRule(ISymbol symbol, out NamingRule applicableRule)
{
if (NamingRules != null &&
IsSymbolNameAnalyzable(symbol))
{
foreach (var namingRule in NamingRules)
{
if (namingRule.SymbolSpecification.AppliesTo(symbol))
{
applicableRule = namingRule;
return true;
}
}
}
applicableRule = default;
return false;
}
private bool IsSymbolNameAnalyzable(ISymbol symbol)
{
if (_symbolKindsThatCanBeOverridden.Contains(symbol.Kind) && DoesSymbolImplementAnotherSymbol(symbol))
{
return false;
}
if (symbol is IMethodSymbol method)
{
return method.MethodKind is MethodKind.Ordinary or
MethodKind.LocalFunction;
}
if (symbol is IPropertySymbol property)
{
return !property.IsIndexer;
}
return true;
}
private static bool DoesSymbolImplementAnotherSymbol(ISymbol symbol)
{
if (symbol.IsStatic)
{
return false;
}
var containingType = symbol.ContainingType;
if (containingType.TypeKind is not TypeKind.Class and not TypeKind.Struct)
{
return false;
}
return symbol.IsOverride ||
symbol.ExplicitInterfaceImplementations().Any() ||
IsInterfaceImplementation(symbol);
}
/// <summary>
/// This does not handle the case where a method in a base type implicitly implements an
/// interface method on behalf of one of its derived types.
/// </summary>
private static bool IsInterfaceImplementation(ISymbol symbol)
{
if (symbol.DeclaredAccessibility != Accessibility.Public)
{
return false;
}
var containingType = symbol.ContainingType;
var implementedInterfaces = containingType.AllInterfaces;
foreach (var implementedInterface in implementedInterfaces)
{
var implementedInterfaceMembersWithSameName = implementedInterface.GetMembers(symbol.Name);
foreach (var implementedInterfaceMember in implementedInterfaceMembersWithSameName)
{
if (symbol.Equals(containingType.FindImplementationForInterfaceMember(implementedInterfaceMember)))
{
return true;
}
}
}
return false;
}
}
|