private static IReadOnlyList <T> GetPossibleTs <T>( SourceSymbolContext context, QualifiedName name, ImmutableArray <IType> typeArguments, TryGetT <T> tryGetT, GetLocalTs <T> getLocalTs, GetFullyQualifiedName <T> getFullyQualifiedName, GetTypeParameters <T> getTypeParameters) where T : class { List <T> possibleTs; if (name.Parent is null) { // local ts have priority over top level ts, // and an inner local t hides an outer local t // local ts can only have simple names, so we can skip this check if the name is not simple var scope = context.Scope; while (scope != null) { possibleTs = getLocalTs(scope) .Where( x => getFullyQualifiedName(x) == name && getTypeParameters(x).Length == typeArguments.Length) .ToList(); if (possibleTs.Count > 0) { return(possibleTs); } scope = scope.DeclaringMethod; } } var assemblies = context.Assembly.ReferencedAssembliesAndSelf; // types in the innermost namespace have priority over types in its parent namespace, // which have priority over types in its parent etc. var @namespace = context.NameSpace; while (@namespace != null) { var possibleName = name.Prepend(@namespace); possibleTs = LookupPossibleName(possibleName).ToList(); if (possibleTs.Count > 0) { return(possibleTs); } @namespace = @namespace?.Parent; } // Types in the global namespace have priority over types defined in imports possibleTs = LookupPossibleName(name).ToList(); if (possibleTs.Count > 0) { return(possibleTs); } // look for types in imports if (name.Parent is null) { // imports only bring the top level types into scope, so they are only relevant if the name is simple; var possibleNames = context.Imports.Select(x => x.Append(name)).ToList(); return (possibleNames .SelectMany(LookupPossibleName) .ToList()); } return(Array.Empty <T>()); IEnumerable <T> LookupPossibleName(QualifiedName possibleName) { return(assemblies.Select(x => { tryGetT(x, possibleName, out var t); return t; }).Where(x => x != null && getTypeParameters(x).Length == typeArguments.Length) !); } }