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