Skip to content

Commit

Permalink
Merge pull request #563 from Sergio0694/dev/simplify-type-access-checks
Browse files Browse the repository at this point in the history
Simplify HasAccessibleTypeWithMetadataName
  • Loading branch information
Sergio0694 authored Sep 27, 2023
2 parents 9311348 + eb3c695 commit f2188b5
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 82 deletions.
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));
}
}

0 comments on commit f2188b5

Please sign in to comment.