in src/Microsoft.VisualStudio.Composition/CompositionConfiguration.cs [322:384]
private static IEnumerable<ComposedPartDiagnostic> FindLoops(IEnumerable<ComposedPart> parts)
{
Requires.NotNull(parts, nameof(parts));
var partByPartDefinition = parts.ToDictionary(p => p.Definition);
var partByPartType = parts.ToDictionary(p => p.Definition.TypeRef);
var partsAndDirectImports = new Dictionary<ComposedPart, IReadOnlyList<KeyValuePair<ImportDefinitionBinding, ComposedPart>>>();
foreach (var part in parts)
{
var directlyImportedParts = (from importAndExports in part.SatisfyingExports
from export in importAndExports.Value
let exportingPart = partByPartDefinition[export.PartDefinition]
select new KeyValuePair<ImportDefinitionBinding, ComposedPart>(importAndExports.Key, exportingPart)).ToList();
partsAndDirectImports.Add(part, directlyImportedParts);
}
Func<Func<KeyValuePair<ImportDefinitionBinding, ComposedPart>, bool>, Func<ComposedPart, IEnumerable<ComposedPart>>> getDirectLinksWithFilter =
filter => (part => partsAndDirectImports[part].Where(filter).Select(ip => ip.Value));
var visited = new HashSet<ComposedPart>();
// Find any loops of exclusively non-shared parts.
var nonSharedPartsInLoops = new HashSet<ComposedPart>();
foreach (var part in partsAndDirectImports.Keys)
{
if (nonSharedPartsInLoops.Contains(part))
{
// Don't check and report parts already detected to be involved in a loop.
continue;
}
visited.Clear();
var path = PathExistsBetween(part, part, getDirectLinksWithFilter(ip => !ip.Key.IsExportFactory && (!ip.Value.Definition.IsShared || PartCreationPolicyConstraint.IsNonSharedInstanceRequired(ip.Key.ImportDefinition))), visited);
if (!path.IsEmpty)
{
path = path.Push(part);
nonSharedPartsInLoops.UnionWith(path);
yield return new ComposedPartDiagnostic(path, Strings.LoopBetweenNonSharedParts);
}
}
// Find loops even with shared parts where an importing constructor is involved.
Func<KeyValuePair<ImportDefinitionBinding, ComposedPart>, bool> importingConstructorFilter = ip => !ip.Key.IsExportFactory && !ip.Key.IsLazy;
foreach (var partAndImports in partsAndDirectImports)
{
var importingPart = partAndImports.Key;
foreach (var import in partAndImports.Value)
{
var importDefinitionBinding = import.Key;
var satisfyingPart = import.Value;
if (importDefinitionBinding.ImportingParameterRef != null && importingConstructorFilter(import))
{
visited.Clear();
var path = PathExistsBetween(satisfyingPart, importingPart, getDirectLinksWithFilter(importingConstructorFilter), visited);
if (!path.IsEmpty)
{
path = path.Push(satisfyingPart).Push(partByPartType[importDefinitionBinding.ComposablePartTypeRef]);
yield return new ComposedPartDiagnostic(path, Strings.LoopInvolvingImportingCtorArgumentAndAllNonLazyImports);
}
}
}
}
}