// 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 Microsoft.CodeAnalysis; namespace CommunityToolkit.Mvvm.SourceGenerators.Extensions; /// /// Extension methods for the type. /// internal static class CompilationExtensions { /// /// /// Checks whether or not a type with a specified metadata name is accessible from a given instance. /// /// /// This method enumerates candidate type symbols to find a match in the following order: /// /// /// If only one type with the given name is found within the compilation and its referenced assemblies, check its accessibility. /// /// /// If the current defines the symbol, check its accessibility. /// /// /// Otherwise, check whether the type exists and is accessible from any of the referenced assemblies. /// /// /// /// /// The to consider for analysis. /// The fully-qualified metadata type name to find. /// Whether a type with the specified metadata name can be accessed from the given compilation. public static bool HasAccessibleTypeWithMetadataName(this Compilation compilation, string fullyQualifiedMetadataName) { // Try to get the unique type with this name INamedTypeSymbol? type = compilation.GetTypeByMetadataName(fullyQualifiedMetadataName); // If there is only a single matching symbol, check its accessibility if (type is not null) { return type.CanBeAccessedFrom(compilation.Assembly); } // Otherwise, try to get the unique type with this name originally defined in 'compilation' type ??= compilation.Assembly.GetTypeByMetadataName(fullyQualifiedMetadataName); if (type is not null) { return type.CanBeAccessedFrom(compilation.Assembly); } // Otherwise, check whether the type is defined and accessible from any of the referenced assemblies foreach (IModuleSymbol module in compilation.Assembly.Modules) { foreach (IAssemblySymbol referencedAssembly in module.ReferencedAssemblySymbols) { if (referencedAssembly.GetTypeByMetadataName(fullyQualifiedMetadataName) is not INamedTypeSymbol currentType) { continue; } switch (currentType.GetEffectiveAccessibility()) { case Accessibility.Public: case Accessibility.Internal when referencedAssembly.GivesAccessTo(compilation.Assembly): return true; default: continue; } } } return false; } }