public static Task <IEnumerable <INamedTypeSymbol> > FindDerivedClassesAsync(
     this INamedTypeSymbol type,
     Solution solution,
     IImmutableSet <Project> projects,
     CancellationToken cancellationToken)
 {
     return(DependentTypeFinder.FindDerivedClassesAsync(type, solution, projects, cancellationToken));
 }
            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);
                }
            }
 public Task <ImmutableArray <SerializableSymbolAndProjectId> > FindAndCacheImplementingTypesAsync(
     PinnedSolutionInfo solutionInfo,
     SerializableSymbolAndProjectId typeAndProjectId,
     ProjectId[] projectIds,
     bool transitive,
     CancellationToken cancellationToken)
 {
     return(FindAndCacheTypesAsync(
                solutionInfo, typeAndProjectId, projectIds,
                (nt, s, ps) => DependentTypeFinder.FindAndCacheImplementingTypesAsync(nt, s, ps, transitive, cancellationToken),
                cancellationToken));
 }
Exemple #4
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());
            }
Exemple #5
0
        public async Task ImmediatelyDerivedTypes_CSharp_AliasedNames()
        {
            var solution = new AdhocWorkspace().CurrentSolution;

            // create portable assembly with an abstract base class
            solution = AddProjectWithMetadataReferences(solution, "PortableProject", LanguageNames.CSharp, @"
namespace N
{
    public abstract class BaseClass { }
}
", MscorlibRefPortable);

            var portableProject = GetPortableProject(solution);

            // create a normal assembly with a type derived from the portable abstract base
            solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.CSharp, @"
using N;
using Alias1 = N.BaseClass;

namespace M
{
    using Alias2 = Alias1;

    public class DerivedClass : Alias2 { }
}
", MscorlibRef, portableProject.Id);

            // get symbols for types
            var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();

            var baseClassSymbol = portableCompilation.GetTypeByMetadataName("N.BaseClass");

            var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();

            var derivedClassSymbol = normalCompilation.GetTypeByMetadataName("M.DerivedClass");

            // verify that the symbols are different (due to retargeting)
            Assert.NotEqual(baseClassSymbol, derivedClassSymbol.BaseType);

            // verify that the dependent types of `N.BaseClass` correctly resolve to `M.DerivedCLass`
            var derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(
                SymbolAndProjectId.Create(baseClassSymbol, portableProject.Id), solution, CancellationToken.None);

            var derivedDependentType = derivedFromBase.Single();

            Assert.Equal(derivedClassSymbol, derivedDependentType.Symbol);
        }
Exemple #6
0
        public async Task ImmediatelyDerivedTypes_VisualBasic()
        {
            var solution = new AdhocWorkspace().CurrentSolution;

            // create portable assembly with an abstract base class
            solution = AddProjectWithMetadataReferences(solution, "PortableProject", LanguageNames.VisualBasic, @"
Namespace N
    Public MustInherit Class BaseClass
    End Class
End Namespace
", MscorlibRefPortable);

            var portableProject = GetPortableProject(solution);

            // create a normal assembly with a type derived from the portable abstract base
            solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.VisualBasic, @"
Imports N
Namespace M
    Public Class DerivedClass
        Inherits BaseClass
    End Class
End Namespace
", MscorlibRef, portableProject.Id);

            // get symbols for types
            var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();

            var baseClassSymbol = portableCompilation.GetTypeByMetadataName("N.BaseClass");

            var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();

            var derivedClassSymbol = normalCompilation.GetTypeByMetadataName("M.DerivedClass");

            // verify that the symbols are different (due to retargeting)
            Assert.NotEqual(baseClassSymbol, derivedClassSymbol.BaseType);

            // verify that the dependent types of `N.BaseClass` correctly resolve to `M.DerivedCLass`
            var derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(
                baseClassSymbol, solution, CancellationToken.None);

            var derivedDependentType = derivedFromBase.Single();

            Assert.Equal(derivedClassSymbol, derivedDependentType);
        }
Exemple #7
0
        public async Task ImmediatelyDerivedInterfaces_VisualBasic()
        {
            var solution = new AdhocWorkspace().CurrentSolution;

            // create portable assembly with an interface
            solution = AddProjectWithMetadataReferences(solution, "PortableProject", LanguageNames.VisualBasic, @"
Namespace N
    Public Interface IBaseInterface
    End Interface
End Namespace
", MscorlibRefPortable);

            var portableProject = GetPortableProject(solution);

            // create a normal assembly with a type implementing that interface
            solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.VisualBasic, @"
Imports N
Namespace M
    Public Class ImplementingClass
        Implements IBaseInterface
    End Class
End Namespace
", MscorlibRef, portableProject.Id);

            // get symbols for types
            var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();

            var baseInterfaceSymbol = portableCompilation.GetTypeByMetadataName("N.IBaseInterface");

            var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();

            var implementingClassSymbol = normalCompilation.GetTypeByMetadataName("M.ImplementingClass");

            // verify that the symbols are different (due to retargeting)
            Assert.NotEqual(baseInterfaceSymbol, implementingClassSymbol.Interfaces.Single());

            // verify that the implementing types of `N.IBaseInterface` correctly resolve to `M.ImplementingClass`
            var typesThatImplementInterface = await DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync(
                SymbolAndProjectId.Create(baseInterfaceSymbol, portableProject.Id), solution, CancellationToken.None);

            Assert.Equal(implementingClassSymbol, typesThatImplementInterface.Single().Symbol);
        }
        public async Task <GraphBuilder> GetGraphAsync(Solution solution, IGraphContext context, CancellationToken cancellationToken)
        {
            var graphBuilder = await GraphBuilder.CreateForInputNodesAsync(solution, context.InputNodes, cancellationToken).ConfigureAwait(false);

            foreach (var node in context.InputNodes)
            {
                var symbol = graphBuilder.GetSymbol(node);
                if (!(symbol is INamedTypeSymbol namedType))
                {
                    continue;
                }

                if (namedType.TypeKind == TypeKind.Class)
                {
                    var derivedTypes = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(
                        namedType, solution, cancellationToken).ConfigureAwait(false);

                    foreach (var derivedType in derivedTypes)
                    {
                        var symbolNode = await graphBuilder.AddNodeAsync(
                            derivedType, relatedNode : node).ConfigureAwait(false);

                        graphBuilder.AddLink(symbolNode, CodeLinkCategories.InheritsFrom, node);
                    }
                }
                else if (namedType.TypeKind == TypeKind.Interface)
                {
                    var derivedTypes = await DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync(
                        namedType, solution, cancellationToken).ConfigureAwait(false);

                    foreach (var derivedType in derivedTypes)
                    {
                        var symbolNode = await graphBuilder.AddNodeAsync(
                            derivedType, relatedNode : node).ConfigureAwait(false);

                        graphBuilder.AddLink(symbolNode, CodeLinkCategories.InheritsFrom, node);
                    }
                }
            }

            return(graphBuilder);
        }
        public async Task ImmediatelyDerivedInterfaces_CSharp()
        {
            var solution = new AdhocWorkspace().CurrentSolution;

            // create portable assembly with an interface
            solution = AddProjectWithMetadataReferences(solution, "PortableProject", LanguageNames.CSharp, @"
namespace N
{
    public interface IBaseInterface { }
}
", MscorlibRefPortable);

            // create a normal assembly with a type implementing that interface
            solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.CSharp, @"
using N;
namespace M
{
    public class ImplementingClass : IBaseInterface { }
}
", MscorlibRef, solution.Projects.Single(pid => pid.Name == "PortableProject").Id);

            // get symbols for types
            var portableCompilation = await solution.Projects.Single(p => p.Name == "PortableProject").GetCompilationAsync();

            var baseInterfaceSymbol = portableCompilation.GetTypeByMetadataName("N.IBaseInterface");

            var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();

            var implementingClassSymbol = normalCompilation.GetTypeByMetadataName("M.ImplementingClass");

            // verify that the symbols are different (due to retargeting)
            Assert.NotEqual(baseInterfaceSymbol, implementingClassSymbol.Interfaces.Single());

            // verify that the implementing types of `N.IBaseInterface` correctly resolve to `M.ImplementingClass`
            var typesThatImplementInterface = await DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync(
                baseInterfaceSymbol, solution, CancellationToken.None);

            Assert.Equal(implementingClassSymbol, typesThatImplementInterface.Single().Symbol);
        }