// 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); } }