Skip to content
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
40 changes: 40 additions & 0 deletions S1API.Tests/Internal/Utils/ReflectionUtilsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,46 @@ public void DerivedTypeScanFollowsTransitiveAssemblyReferences()
loadedAssemblies));
}

[Fact]
public void DerivedTypeScanDoesNotFollowSameNameAssembliesWithDifferentIdentities()
{
string assemblyName = $"S1API.ReflectionUtilsTests.Duplicate.{Guid.NewGuid():N}";
AssemblyBuilder unrelatedAssembly = CreateDynamicAssembly(assemblyName, new Version(1, 0, 0, 0));
Type unrelatedType = unrelatedAssembly
.DefineDynamicModule(assemblyName)
.DefineType("UnrelatedType", TypeAttributes.Public)
.CreateType()!;

AssemblyBuilder relatedAssembly = CreateDynamicAssembly(assemblyName, new Version(2, 0, 0, 0));
relatedAssembly
.DefineDynamicModule(assemblyName)
.DefineType("RelatedType", TypeAttributes.Public, typeof(ReflectionCandidateBridge))
.CreateType();

AssemblyBuilder candidateAssembly = CreateDynamicAssembly(
$"S1API.ReflectionUtilsTests.Candidate.{Guid.NewGuid():N}",
new Version(1, 0, 0, 0));
ModuleBuilder candidateModule = candidateAssembly.DefineDynamicModule(candidateAssembly.GetName().Name!);
candidateModule
.DefineType("CandidateType", TypeAttributes.Public, unrelatedType)
.CreateType();

Assert.False(ReflectionUtils.CanContainTypesDerivedFrom(
candidateAssembly,
typeof(ReflectionUtils).Assembly,
AppDomain.CurrentDomain.GetAssemblies()));
}

private static AssemblyBuilder CreateDynamicAssembly(string name, Version version)
{
var assemblyName = new AssemblyName(name)
{
Version = version
};

return AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
}

private sealed class MonoShape
{
#pragma warning disable CS0169
Expand Down
15 changes: 13 additions & 2 deletions S1API/Internal/Utils/ReflectionUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ private static bool CanContainTypesDerivedFrom(
AssemblyName baseAssemblyName,
IReadOnlyDictionary<string, Assembly[]> assembliesBySimpleName)
{
if (AssemblyName.ReferenceMatchesDefinition(candidateAssembly.GetName(), baseAssemblyName))
if (AssemblyIdentityMatches(candidateAssembly.GetName(), baseAssemblyName))
return true;

return ReferencesAssemblyTransitively(
Expand Down Expand Up @@ -137,7 +137,7 @@ private static bool ReferencesAssemblyTransitively(

foreach (AssemblyName referencedAssembly in referencedAssemblies)
{
if (AssemblyName.ReferenceMatchesDefinition(referencedAssembly, baseAssemblyName))
if (AssemblyIdentityMatches(referencedAssembly, baseAssemblyName))
return true;

string referencedName = referencedAssembly.Name ?? string.Empty;
Expand All @@ -147,6 +147,9 @@ private static bool ReferencesAssemblyTransitively(

foreach (Assembly loadedReference in loadedReferences)
{
if (!AssemblyIdentityMatches(loadedReference.GetName(), referencedAssembly))
continue;

if (ReferencesAssemblyTransitively(
loadedReference,
baseAssemblyName,
Expand All @@ -161,6 +164,14 @@ private static bool ReferencesAssemblyTransitively(
return false;
}

private static bool AssemblyIdentityMatches(
AssemblyName referenceAssemblyName,
AssemblyName definitionAssemblyName) =>
string.Equals(
referenceAssemblyName.FullName,
definitionAssemblyName.FullName,
StringComparison.OrdinalIgnoreCase);

/// <summary>
/// INTERNAL: Gets all types by their name.
/// </summary>
Expand Down
Loading