Skip to content

Commit 9bf4fe6

Browse files
authored
Merge pull request #649 from drewnoakes/fix-VSMEF003
Fix exception in VSMEF003 relating to unbound generic interfaces
2 parents 4e2c4f8 + cde0f3f commit 9bf4fe6

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

src/Microsoft.VisualStudio.Composition.Analyzers/VSMEF003ExportTypeMismatchAnalyzer.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,26 @@ private static bool IsTypeCompatible(INamedTypeSymbol implementingType, INamedTy
155155
// Check if implementing type implements exported interface
156156
if (exportedType.TypeKind == TypeKind.Interface)
157157
{
158-
return implementingType.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(exportedType.IsUnboundGenericType ? i.ConstructUnboundGenericType() : i, exportedType));
158+
foreach (INamedTypeSymbol iface in implementingType.AllInterfaces)
159+
{
160+
if (exportedType.IsUnboundGenericType)
161+
{
162+
if (iface is INamedTypeSymbol { IsGenericType: true } namedInterface)
163+
{
164+
if (SymbolEqualityComparer.Default.Equals(namedInterface.ConstructUnboundGenericType(), exportedType))
165+
{
166+
return true;
167+
}
168+
}
169+
}
170+
else
171+
{
172+
if (SymbolEqualityComparer.Default.Equals(iface, exportedType))
173+
{
174+
return true;
175+
}
176+
}
177+
}
159178
}
160179

161180
return false;

test/Microsoft.VisualStudio.Composition.Analyzers.Tests/VSMEF003ExportTypeMismatchAnalyzerTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,4 +421,34 @@ class TestClass
421421

422422
await VerifyCS.VerifyAnalyzerAsync(test);
423423
}
424+
425+
[Fact]
426+
public async Task ExportingWrongUnboundGenericWithNonGenericInterfaces_ForcesEvaluationOfAllInterfaces()
427+
{
428+
// Reproduces a bug seen related to unbound generic types.
429+
string test = """
430+
using System;
431+
using System.Composition;
432+
433+
interface IValue<T>
434+
{
435+
}
436+
437+
interface IOther<T>
438+
{
439+
}
440+
441+
interface IFirstInterface
442+
{
443+
}
444+
445+
[Export(typeof(IOther<>))]
446+
class [|Test|]<T> : IValue<T>, IFirstInterface, IDisposable
447+
{
448+
public void Dispose() => throw new NotImplementedException();
449+
}
450+
""";
451+
452+
await VerifyCS.VerifyAnalyzerAsync(test);
453+
}
424454
}

0 commit comments

Comments
 (0)