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);
                }
            }
Exemplo n.º 2
0
            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());
            }