Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify HasAccessibleTypeWithMetadataName #563

Merged
merged 1 commit into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,41 +69,18 @@ public static bool TryBuildNamedTypeSymbolSet(
/// <returns>Whether a type with the specified metadata name can be accessed from the given compilation.</returns>
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)
if (compilation.GetTypeByMetadataName(fullyQualifiedMetadataName) is INamedTypeSymbol typeSymbol)
{
return type.CanBeAccessedFrom(compilation.Assembly);
return compilation.IsSymbolAccessibleWithin(typeSymbol, compilation.Assembly);
}

// Otherwise, check whether the type is defined and accessible from any of the referenced assemblies
foreach (IModuleSymbol module in compilation.Assembly.Modules)
// Otherwise, check all available types
foreach (INamedTypeSymbol currentTypeSymbol in compilation.GetTypesByMetadataName(fullyQualifiedMetadataName))
{
foreach (IAssemblySymbol referencedAssembly in module.ReferencedAssemblySymbols)
if (compilation.IsSymbolAccessibleWithin(currentTypeSymbol, compilation.Assembly))
{
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 true;
}
}

Expand Down
53 changes: 0 additions & 53 deletions src/ComputeSharp.SourceGeneration/Extensions/ISymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,57 +75,4 @@ public static bool TryGetAttributeWithFullyQualifiedMetadataName(this ISymbol sy

return false;
}

/// <summary>
/// Calculates the effective accessibility for a given symbol.
/// </summary>
/// <param name="symbol">The <see cref="ISymbol"/> instance to check.</param>
/// <returns>The effective accessibility for <paramref name="symbol"/>.</returns>
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;
}

/// <summary>
/// Checks whether or not a given symbol can be accessed from a specified assembly.
/// </summary>
/// <param name="symbol">The input <see cref="ISymbol"/> instance to check.</param>
/// <param name="assembly">The assembly to check the accessibility of <paramref name="symbol"/> for.</param>
/// <returns>Whether <paramref name="assembly"/> can access <paramref name="symbol"/>.</returns>
public static bool CanBeAccessedFrom(this ISymbol symbol, IAssemblySymbol assembly)
{
Accessibility accessibility = symbol.GetEffectiveAccessibility();

return
accessibility == Accessibility.Public ||
(accessibility == Accessibility.Internal && symbol.ContainingAssembly.GivesAccessTo(assembly));
}
}