public override async ValueTask <ITypeSymbol> VisitTypeParameter(ITypeParameterSymbol symbol) { if (_availableTypeParameterNames.Contains(symbol.Name)) { return(symbol); } switch (symbol.ConstraintTypes.Length) { case 0: // If there are no constraint then there is no replacement required // Just return the symbol return(symbol); case 1: // If there is one constraint which is a INamedTypeSymbol then return the INamedTypeSymbol // because the TypeParameter is expected to be of that type // else return the original symbol return(symbol.ConstraintTypes.ElementAt(0) as INamedTypeSymbol ?? (ITypeSymbol)symbol); // More than one default: if (symbol.ConstraintTypes.All(t => t is INamedTypeSymbol)) { var immutableProjects = _solution.Projects.ToImmutableHashSet(); var derivedImplementedTypesOfEachConstraintType = await Task.WhenAll(symbol.ConstraintTypes.Select(async ct => { var derivedAndImplementedTypes = new List <INamedTypeSymbol>(); var derivedClasses = await SymbolFinder.FindDerivedClassesAsync((INamedTypeSymbol)ct, _solution, immutableProjects, _cancellationToken).ConfigureAwait(false); var implementedTypes = await DependentTypeFinder.FindTransitivelyImplementingStructuresAndClassesAsync((INamedTypeSymbol)ct, _solution, immutableProjects, _cancellationToken).ConfigureAwait(false); return(derivedClasses.Concat(implementedTypes.Select(s => s.Symbol)).ToList()); })).ConfigureAwait(false); var intersectingTypes = derivedImplementedTypesOfEachConstraintType.Aggregate((x, y) => x.Intersect(y).ToList()); // If there was any intersecting derived type among the constraint types then pick the first of the lot. if (intersectingTypes.Any()) { var resultantIntersectingType = intersectingTypes.First(); // If the resultant intersecting type contains any Type arguments that could be replaced // using the type constraints then recursively update the type until all constraints are appropriately handled var typeConstraintConvertedType = await resultantIntersectingType.Accept(this).ConfigureAwait(false); var knownSimilarTypesInCompilation = SymbolFinder.FindSimilarSymbols(typeConstraintConvertedType, _compilation, _cancellationToken); if (knownSimilarTypesInCompilation.Any()) { return(knownSimilarTypesInCompilation.First()); } var resultantSimilarKnownTypes = SymbolFinder.FindSimilarSymbols(resultantIntersectingType, _compilation, _cancellationToken); return(resultantSimilarKnownTypes.FirstOrDefault() ?? (ITypeSymbol)symbol); } } return(symbol); } }
private async Task <ISet <INamedTypeSymbol> > GetDerivedAndImplementedTypesAsync( INamedTypeSymbol constraintType, IImmutableSet <Project> projects) { var solution = _project.Solution; var symbolAndProjectId = SymbolAndProjectId.Create(constraintType, _project.Id); var derivedClasses = await SymbolFinder.FindDerivedClassesAsync( symbolAndProjectId, solution, projects, _cancellationToken).ConfigureAwait(false); var implementedTypes = await DependentTypeFinder.FindTransitivelyImplementingStructuresAndClassesAsync( symbolAndProjectId, solution, projects, _cancellationToken).ConfigureAwait(false); return(derivedClasses.Concat(implementedTypes).Select(t => t.Symbol).ToSet()); }