// 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.Collections.Immutable;
using Microsoft.CodeAnalysis;
namespace CommunityToolkit.Mvvm.SourceGenerators.Extensions;
///
/// Extension methods for the type.
///
internal static class ISymbolExtensions
{
///
/// Gets the fully qualified name for a given symbol.
///
/// The input instance.
/// The fully qualified name for .
public static string GetFullyQualifiedName(this ISymbol symbol)
{
return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
}
///
/// Gets the fully qualified name for a given symbol, including nullability annotations
///
/// The input instance.
/// The fully qualified name for .
public static string GetFullyQualifiedNameWithNullabilityAnnotations(this ISymbol symbol)
{
return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.AddMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier));
}
///
/// Checks whether or not a given type symbol has a specified full name.
///
/// The input instance to check.
/// The full name to check.
/// Whether has a full name equals to .
public static bool HasFullyQualifiedName(this ISymbol symbol, string name)
{
return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == name;
}
///
/// Checks whether or not a given symbol has an attribute with the specified full name.
///
/// The input instance to check.
/// The attribute name to look for.
/// Whether or not has an attribute with the specified name.
public static bool HasAttributeWithFullyQualifiedName(this ISymbol symbol, string name)
{
ImmutableArray attributes = symbol.GetAttributes();
foreach (AttributeData attribute in attributes)
{
if (attribute.AttributeClass?.HasFullyQualifiedName(name) == true)
{
return true;
}
}
return false;
}
///
/// Calculates the effective accessibility for a given symbol.
///
/// The instance to check.
/// The effective accessibility for .
public static Accessibility GetEffectiveAccessibility(this ISymbol symbol)
{
// Start by assuming it's visible
Accessibility visibility = Accessibility.Public;
// Handle special cases
switch (symbol.Kind)
{
case SymbolKind.Alias: return Accessibility.Private;
case SymbolKind.Parameter: return GetEffectiveAccessibility(symbol.ContainingSymbol);
case SymbolKind.TypeParameter: return Accessibility.Private;
}
// Traverse the symbol hierarchy to determine the effective accessibility
while (symbol is not null && symbol.Kind != SymbolKind.Namespace)
{
switch (symbol.DeclaredAccessibility)
{
case Accessibility.NotApplicable:
case Accessibility.Private:
return Accessibility.Private;
case Accessibility.Internal:
case Accessibility.ProtectedAndInternal:
visibility = Accessibility.Internal;
break;
}
symbol = symbol.ContainingSymbol;
}
return visibility;
}
///
/// Checks whether or not a given symbol can be accessed from a specified assembly.
///
/// The input instance to check.
/// The assembly to check the accessibility of for.
/// Whether can access .
public static bool CanBeAccessedFrom(this ISymbol symbol, IAssemblySymbol assembly)
{
Accessibility accessibility = symbol.GetEffectiveAccessibility();
return
accessibility == Accessibility.Public ||
accessibility == Accessibility.Internal && symbol.ContainingAssembly.GivesAccessTo(assembly);
}
}