未验证 提交 c8d3d3e1 编写于 作者: M msftbot[bot] 提交者: GitHub

Merge pull request #43029 from CyrusNajmabadi/dependentTypeOOP

Initial work to get 'dependent type finding' moved out of process.
......@@ -146,11 +146,13 @@ public ValueTask<ITypeSymbol> DetermineReturnTypeAsync(CancellationToken cancell
var compilation = Document.SemanticModel.Compilation;
var allTypeParameters = availableMethodTypeParameters.Concat(availableTypeParameters);
var availableTypeParameterNames = allTypeParameters.Select(t => t.Name).ToSet();
var typeArgumentToTypeParameterMap = GetTypeArgumentToTypeParameterMap(cancellationToken);
typeSymbol = typeSymbol.RemoveAnonymousTypes(compilation);
typeSymbol = await typeSymbol.ReplaceTypeParametersBasedOnTypeConstraintsAsync(compilation, allTypeParameters, Document.Document.Project.Solution, cancellationToken).ConfigureAwait(false);
typeSymbol = await ReplaceTypeParametersBasedOnTypeConstraintsAsync(
Document.Project, typeSymbol, compilation, availableTypeParameterNames, cancellationToken).ConfigureAwait(false);
return typeSymbol.RemoveUnavailableTypeParameters(compilation, allTypeParameters)
.RemoveUnnamedErrorTypes(compilation)
.SubstituteTypes(typeArgumentToTypeParameterMap, new TypeGenerator());
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember
{
internal partial class AbstractGenerateParameterizedMemberService<TService, TSimpleNameSyntax, TExpressionSyntax, TInvocationExpressionSyntax>
{
private static async ValueTask<ITypeSymbol> ReplaceTypeParametersBasedOnTypeConstraintsAsync(
Project project,
ITypeSymbol type,
Compilation compilation,
ISet<string> availableTypeParameterNames,
CancellationToken cancellationToken)
{
var visitor = new DetermineSubstitutionsVisitor(
compilation, availableTypeParameterNames, project, cancellationToken);
await visitor.Visit(type).ConfigureAwait(false);
return type.SubstituteTypes(visitor.Substitutions, compilation);
}
private sealed class DetermineSubstitutionsVisitor : AsyncSymbolVisitor
{
public readonly Dictionary<ITypeSymbol, ITypeSymbol> Substitutions =
new Dictionary<ITypeSymbol, ITypeSymbol>();
private readonly CancellationToken _cancellationToken;
private readonly Compilation _compilation;
private readonly ISet<string> _availableTypeParameterNames;
private readonly Project _project;
public DetermineSubstitutionsVisitor(
Compilation compilation, ISet<string> availableTypeParameterNames, Project project, CancellationToken cancellationToken)
{
_compilation = compilation;
_availableTypeParameterNames = availableTypeParameterNames;
_project = project;
_cancellationToken = cancellationToken;
}
public override ValueTask VisitDynamicType(IDynamicTypeSymbol symbol)
=> default;
public override ValueTask VisitArrayType(IArrayTypeSymbol symbol)
=> symbol.ElementType.Accept(this);
public override async ValueTask VisitNamedType(INamedTypeSymbol symbol)
{
foreach (var typeArg in symbol.TypeArguments)
await typeArg.Accept(this).ConfigureAwait(false);
}
public override ValueTask VisitPointerType(IPointerTypeSymbol symbol)
=> symbol.PointedAtType.Accept(this);
public override async ValueTask VisitTypeParameter(ITypeParameterSymbol symbol)
{
if (_availableTypeParameterNames.Contains(symbol.Name))
return;
switch (symbol.ConstraintTypes.Length)
{
case 0:
// If there are no constraint then there is no replacement required.
return;
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
if (symbol.ConstraintTypes.ElementAt(0) is INamedTypeSymbol namedType)
Substitutions.Add(symbol, namedType);
return;
}
var commonDerivedType = await DetermineCommonDerivedTypeAsync(symbol).ConfigureAwait(false);
if (commonDerivedType != null)
Substitutions.Add(symbol, commonDerivedType);
}
private async ValueTask<ITypeSymbol> DetermineCommonDerivedTypeAsync(ITypeParameterSymbol symbol)
{
if (!symbol.ConstraintTypes.All(t => t is INamedTypeSymbol))
return null;
var solution = _project.Solution;
var projects = solution.Projects.ToImmutableHashSet();
var commonTypes = await GetDerivedAndImplementedTypesAsync(
(INamedTypeSymbol)symbol.ConstraintTypes[0], projects).ConfigureAwait(false);
for (int i = 1; i < symbol.ConstraintTypes.Length; i++)
{
var currentTypes = await GetDerivedAndImplementedTypesAsync(
(INamedTypeSymbol)symbol.ConstraintTypes[i], projects).ConfigureAwait(false);
commonTypes.IntersectWith(currentTypes);
if (commonTypes.Count == 0)
return null;
}
// If there was any intersecting derived type among the constraint types then pick the first of the lot.
if (commonTypes.Count == 0)
return null;
var commonType = commonTypes.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 substitutedType = await ReplaceTypeParametersBasedOnTypeConstraintsAsync(
_project, commonType, _compilation, _availableTypeParameterNames, _cancellationToken).ConfigureAwait(false);
var similarTypes = SymbolFinder.FindSimilarSymbols(substitutedType, _compilation, _cancellationToken);
if (similarTypes.Any())
return similarTypes.First();
similarTypes = SymbolFinder.FindSimilarSymbols(commonType, _compilation, _cancellationToken);
return similarTypes.FirstOrDefault() ?? 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();
}
}
}
}
......@@ -10,6 +10,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Elfie.Model;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
......@@ -34,7 +35,7 @@ internal sealed partial class GraphBuilder
private readonly Dictionary<GraphNode, Project> _nodeToContextProjectMap = new Dictionary<GraphNode, Project>();
private readonly Dictionary<GraphNode, Document> _nodeToContextDocumentMap = new Dictionary<GraphNode, Document>();
private readonly Dictionary<GraphNode, ISymbol> _nodeToSymbolMap = new Dictionary<GraphNode, ISymbol>();
private readonly Dictionary<GraphNode, SymbolAndProjectId> _nodeToSymbolMap = new Dictionary<GraphNode, SymbolAndProjectId>();
/// <summary>
/// The input solution. Never null.
......@@ -121,7 +122,7 @@ private async Task PopulateMapsForSymbolInputNodeAsync(GraphNode inputNode)
var symbol = symbolId.Value.Resolve(compilation).Symbol;
if (symbol != null)
{
_nodeToSymbolMap.Add(inputNode, symbol);
_nodeToSymbolMap.Add(inputNode, new SymbolAndProjectId(symbol, project.Id));
}
var documentId = (DocumentId)inputNode[RoslynGraphProperties.ContextDocumentId];
......@@ -160,7 +161,7 @@ public Document GetContextDocument(GraphNode node)
}
}
public ISymbol GetSymbol(GraphNode node)
public SymbolAndProjectId GetSymbolAndProjectId(GraphNode node)
{
using (_gate.DisposableWait())
{
......@@ -169,15 +170,17 @@ public ISymbol GetSymbol(GraphNode node)
}
}
public Task<GraphNode> AddNodeForSymbolAsync(ISymbol symbol, GraphNode relatedNode)
public Task<GraphNode> AddNodeAsync(SymbolAndProjectId symbol, GraphNode relatedNode)
{
// The lack of a lock here is acceptable, since each of the functions lock, and GetContextProject/GetContextDocument
// never change for the same input.
return AddNodeForSymbolAsync(symbol, GetContextProject(relatedNode), GetContextDocument(relatedNode));
return AddNodeAsync(symbol, GetContextProject(relatedNode), GetContextDocument(relatedNode));
}
public async Task<GraphNode> AddNodeForSymbolAsync(ISymbol symbol, Project contextProject, Document contextDocument)
public async Task<GraphNode> AddNodeAsync(SymbolAndProjectId symbolAndProjectId, Project contextProject, Document contextDocument)
{
var symbol = symbolAndProjectId.Symbol;
// Figure out what the location for this node should be. We'll arbitrarily pick the
// first one, unless we have a contextDocument to restrict it
var preferredLocation = symbol.Locations.FirstOrDefault(l => l.SourceTree != null);
......@@ -230,7 +233,7 @@ public async Task<GraphNode> AddNodeForSymbolAsync(ISymbol symbol, Project conte
// we won't double-count.
_createdNodes.Add(node);
_nodeToSymbolMap[node] = symbol;
_nodeToSymbolMap[node] = symbolAndProjectId;
_nodeToContextProjectMap[node] = contextProject;
_nodeToContextDocumentMap[node] = contextDocument;
......
......@@ -2,17 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.VisualStudio.GraphModel;
using Microsoft.VisualStudio.GraphModel.CodeSchema;
using Microsoft.VisualStudio.GraphModel.Schemas;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Progression
......@@ -25,14 +21,14 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
foreach (var node in context.InputNodes)
{
var symbol = graphBuilder.GetSymbol(node);
if (symbol != null)
var symbolAndProjectId = graphBuilder.GetSymbolAndProjectId(node);
if (symbolAndProjectId.Symbol != null)
{
foreach (var newSymbol in await GetCalledMethodSymbolsAsync(symbol, solution, cancellationToken).ConfigureAwait(false))
foreach (var newSymbol in await GetCalledMethodSymbolsAsync(symbolAndProjectId, solution, cancellationToken).ConfigureAwait(false))
{
cancellationToken.ThrowIfCancellationRequested();
var newNode = await graphBuilder.AddNodeForSymbolAsync(newSymbol, relatedNode: node).ConfigureAwait(false);
var newNode = await graphBuilder.AddNodeAsync(newSymbol, relatedNode: node).ConfigureAwait(false);
graphBuilder.AddLink(node, CodeLinkCategories.Calls, newNode);
}
}
......@@ -41,11 +37,12 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
return graphBuilder;
}
private static async Task<IEnumerable<ISymbol>> GetCalledMethodSymbolsAsync(ISymbol symbol, Solution solution, CancellationToken cancellationToken)
private static async Task<ImmutableArray<SymbolAndProjectId>> GetCalledMethodSymbolsAsync(
SymbolAndProjectId symbolAndProjectId, Solution solution, CancellationToken cancellationToken)
{
var symbols = new List<ISymbol>();
using var _ = ArrayBuilder<SymbolAndProjectId>.GetInstance(out var symbols);
foreach (var reference in symbol.DeclaringSyntaxReferences)
foreach (var reference in symbolAndProjectId.Symbol.DeclaringSyntaxReferences)
{
var semanticModel = await solution.GetDocument(reference.SyntaxTree).GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
foreach (var syntaxNode in (await reference.GetSyntaxAsync(cancellationToken).ConfigureAwait(false)).DescendantNodes())
......@@ -56,12 +53,12 @@ private static async Task<IEnumerable<ISymbol>> GetCalledMethodSymbolsAsync(ISym
if (newSymbol != null && newSymbol is IMethodSymbol &&
(newSymbol.CanBeReferencedByName || ((IMethodSymbol)newSymbol).MethodKind == MethodKind.Constructor))
{
symbols.Add(newSymbol);
symbols.Add(symbolAndProjectId.WithSymbol(newSymbol));
}
}
}
return symbols;
return symbols.ToImmutable();
}
}
}
......@@ -23,11 +23,11 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
{
if (!cancellationToken.IsCancellationRequested)
{
var symbol = graphBuilder.GetSymbol(node);
var symbolAndProjectId = graphBuilder.GetSymbolAndProjectId(node);
if (symbol != null)
if (symbolAndProjectId.Symbol != null)
{
var containsChildren = SymbolContainment.GetContainedSymbols(symbol).Any();
var containsChildren = SymbolContainment.GetContainedSymbols(symbolAndProjectId).Any();
graphBuilder.AddDeferredPropertySet(node, DgmlNodeProperties.ContainsChildren, containsChildren);
}
else if (node.HasCategory(CodeNodeCategories.File))
......
......@@ -31,15 +31,15 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
{
cancellationToken.ThrowIfCancellationRequested();
var symbol = graphBuilder.GetSymbol(node);
var symbol = graphBuilder.GetSymbolAndProjectId(node);
if (symbol != null)
if (symbol.Symbol != null)
{
foreach (var newSymbol in SymbolContainment.GetContainedSymbols(symbol))
{
cancellationToken.ThrowIfCancellationRequested();
var newNode = await graphBuilder.AddNodeForSymbolAsync(newSymbol, relatedNode: node).ConfigureAwait(false);
var newNode = await graphBuilder.AddNodeAsync(newSymbol, relatedNode: node).ConfigureAwait(false);
graphBuilder.AddLink(node, GraphCommonSchema.Contains, newNode);
}
}
......@@ -53,7 +53,7 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
{
cancellationToken.ThrowIfCancellationRequested();
var newNode = await graphBuilder.AddNodeForSymbolAsync(newSymbol, relatedNode: node).ConfigureAwait(false);
var newNode = await graphBuilder.AddNodeAsync(newSymbol, relatedNode: node).ConfigureAwait(false);
graphBuilder.AddLink(node, GraphCommonSchema.Contains, newNode);
}
}
......
......@@ -22,14 +22,17 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
foreach (var node in context.InputNodes)
{
var symbol = graphBuilder.GetSymbol(node);
if (symbol is INamedTypeSymbol || symbol is IMethodSymbol || symbol is IPropertySymbol || symbol is IEventSymbol)
var symbol = graphBuilder.GetSymbolAndProjectId(node);
if (symbol.Symbol is INamedTypeSymbol ||
symbol.Symbol is IMethodSymbol ||
symbol.Symbol is IPropertySymbol ||
symbol.Symbol is IEventSymbol)
{
var implementations = await SymbolFinder.FindImplementationsAsync(symbol, solution, cancellationToken: cancellationToken).ConfigureAwait(false);
foreach (var implementation in implementations)
{
var symbolNode = await graphBuilder.AddNodeForSymbolAsync(implementation, relatedNode: node).ConfigureAwait(false);
var symbolNode = await graphBuilder.AddNodeAsync(implementation, relatedNode: node).ConfigureAwait(false);
graphBuilder.AddLink(symbolNode, CodeLinkCategories.Implements, node);
}
}
......
......@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
......@@ -23,14 +24,16 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
foreach (var node in context.InputNodes)
{
var symbol = graphBuilder.GetSymbol(node);
if (symbol is INamedTypeSymbol namedType)
var symbol = graphBuilder.GetSymbolAndProjectId(node);
if (symbol.Symbol is INamedTypeSymbol namedType)
{
var implementedSymbols = namedType.AllInterfaces;
var implementedSymbols = namedType.AllInterfaces.SelectAsArray(i => (SymbolAndProjectId)symbol.WithSymbol(i));
await AddImplementedSymbolsAsync(graphBuilder, node, implementedSymbols).ConfigureAwait(false);
}
else if (symbol is IMethodSymbol || symbol is IPropertySymbol || symbol is IEventSymbol)
else if (symbol.Symbol is IMethodSymbol ||
symbol.Symbol is IPropertySymbol ||
symbol.Symbol is IEventSymbol)
{
var implements = await SymbolFinder.FindImplementedInterfaceMembersAsync(symbol, solution, cancellationToken: cancellationToken).ConfigureAwait(false);
await AddImplementedSymbolsAsync(graphBuilder, node, implements).ConfigureAwait(false);
......@@ -41,11 +44,13 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
}
}
private static async Task AddImplementedSymbolsAsync(GraphBuilder graphBuilder, GraphNode node, IEnumerable<ISymbol> implementedSymbols)
private static async Task AddImplementedSymbolsAsync(
GraphBuilder graphBuilder, GraphNode node,
ImmutableArray<SymbolAndProjectId> implementedSymbols)
{
foreach (var interfaceType in implementedSymbols)
{
var interfaceTypeNode = await graphBuilder.AddNodeForSymbolAsync(interfaceType, relatedNode: node).ConfigureAwait(false);
var interfaceTypeNode = await graphBuilder.AddNodeAsync(interfaceType, relatedNode: node).ConfigureAwait(false);
graphBuilder.AddLink(node, CodeLinkCategories.Implements, interfaceTypeNode);
}
}
......
......@@ -19,29 +19,29 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
foreach (var node in context.InputNodes)
{
if (!(graphBuilder.GetSymbol(node) is INamedTypeSymbol namedType))
{
var symbolAndProjectId = graphBuilder.GetSymbolAndProjectId(node);
if (!(symbolAndProjectId.Symbol is INamedTypeSymbol namedType))
continue;
}
if (namedType.TypeKind == TypeKind.Class)
{
var derivedTypes = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(namedType, solution, cancellationToken).ConfigureAwait(false);
var derivedTypes = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(
symbolAndProjectId.WithSymbol(namedType), solution, cancellationToken).ConfigureAwait(false);
foreach (var derivedType in derivedTypes)
{
var symbolNode = await graphBuilder.AddNodeForSymbolAsync(
derivedType.Symbol, relatedNode: node).ConfigureAwait(false);
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);
symbolAndProjectId.WithSymbol(namedType), solution, cancellationToken).ConfigureAwait(false);
foreach (var derivedType in derivedTypes)
{
var symbolNode = await graphBuilder.AddNodeForSymbolAsync(
derivedType.Symbol, relatedNode: node).ConfigureAwait(false);
var symbolNode = await graphBuilder.AddNodeAsync(
derivedType, relatedNode: node).ConfigureAwait(false);
graphBuilder.AddLink(symbolNode, CodeLinkCategories.InheritsFrom, node);
}
}
......
......@@ -31,12 +31,13 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
foreach (var node in nodesToProcess)
{
if (graphBuilder.GetSymbol(node) is INamedTypeSymbol namedType)
var symbolAndProjectId = graphBuilder.GetSymbolAndProjectId(node);
if (symbolAndProjectId.Symbol is INamedTypeSymbol namedType)
{
if (namedType.BaseType != null)
{
var baseTypeNode = await graphBuilder.AddNodeForSymbolAsync(namedType.BaseType, relatedNode: node).ConfigureAwait(false);
var baseTypeNode = await graphBuilder.AddNodeAsync(
symbolAndProjectId.WithSymbol(namedType.BaseType), relatedNode: node).ConfigureAwait(false);
newNodes.Add(baseTypeNode);
graphBuilder.AddLink(node, CodeLinkCategories.InheritsFrom, baseTypeNode);
}
......@@ -44,7 +45,8 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
{
foreach (var baseNode in namedType.OriginalDefinition.AllInterfaces.Distinct())
{
var baseTypeNode = await graphBuilder.AddNodeForSymbolAsync(baseNode, relatedNode: node).ConfigureAwait(false);
var baseTypeNode = await graphBuilder.AddNodeAsync(
symbolAndProjectId.WithSymbol(baseNode), relatedNode: node).ConfigureAwait(false);
newNodes.Add(baseTypeNode);
graphBuilder.AddLink(node, CodeLinkCategories.InheritsFrom, baseTypeNode);
}
......
......@@ -23,14 +23,14 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
foreach (var node in context.InputNodes)
{
var symbol = graphBuilder.GetSymbol(node);
if (symbol != null)
var symbol = graphBuilder.GetSymbolAndProjectId(node);
if (symbol.Symbol != null)
{
var callers = await SymbolFinder.FindCallersAsync(symbol, solution, cancellationToken).ConfigureAwait(false);
foreach (var caller in callers.Where(c => c.IsDirect))
{
var callerNode = await graphBuilder.AddNodeForSymbolAsync(caller.CallingSymbol, relatedNode: node).ConfigureAwait(false);
var callerNode = await graphBuilder.AddNodeAsync(caller.CallingSymbolAndProjectId, relatedNode: node).ConfigureAwait(false);
graphBuilder.AddLink(callerNode, CodeLinkCategories.Calls, node);
}
}
......
......@@ -24,7 +24,7 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
foreach (var node in context.InputNodes)
{
var symbol = graphBuilder.GetSymbol(node);
var symbol = graphBuilder.GetSymbolAndProjectId(node);
var references = await SymbolFinder.FindReferencesAsync(symbol, solution, cancellationToken).ConfigureAwait(false);
foreach (var reference in references)
......
......@@ -19,14 +19,14 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
foreach (var node in context.InputNodes)
{
var symbol = graphBuilder.GetSymbol(node);
if (symbol != null)
var symbol = graphBuilder.GetSymbolAndProjectId(node);
if (symbol.Symbol != null)
{
var overriddenMember = symbol.OverriddenMember();
var overriddenMember = symbol.Symbol.OverriddenMember();
if (overriddenMember != null)
{
var symbolNode = await graphBuilder.AddNodeForSymbolAsync(overriddenMember, relatedNode: node).ConfigureAwait(false);
var symbolNode = await graphBuilder.AddNodeAsync(
symbol.WithSymbol(overriddenMember), relatedNode: node).ConfigureAwait(false);
graphBuilder.AddLink(node, RoslynGraphCategories.Overrides, symbolNode);
}
}
......
......@@ -21,13 +21,15 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
foreach (var node in context.InputNodes)
{
var symbol = graphBuilder.GetSymbol(node);
if (symbol is IMethodSymbol || symbol is IPropertySymbol || symbol is IEventSymbol)
var symbol = graphBuilder.GetSymbolAndProjectId(node);
if (symbol.Symbol is IMethodSymbol ||
symbol.Symbol is IPropertySymbol ||
symbol.Symbol is IEventSymbol)
{
var overrides = await SymbolFinder.FindOverridesAsync(symbol, solution, cancellationToken: cancellationToken).ConfigureAwait(false);
foreach (var o in overrides)
{
var symbolNode = await graphBuilder.AddNodeForSymbolAsync(o, relatedNode: node).ConfigureAwait(false);
var symbolNode = await graphBuilder.AddNodeAsync(o, relatedNode: node).ConfigureAwait(false);
graphBuilder.AddLink(symbolNode, RoslynGraphCategories.Overrides, node);
}
}
......
......@@ -50,9 +50,11 @@ private async Task ProcessProjectAsync(Project project, GraphBuilder graphBuilde
{
cancellationToken.ThrowIfCancellationRequested();
if (symbol is INamedTypeSymbol namedType)
if (symbol.Symbol is INamedTypeSymbol namedType)
{
await AddLinkedNodeForTypeAsync(project, namedType, graphBuilder, symbol.DeclaringSyntaxReferences.Select(d => d.SyntaxTree)).ConfigureAwait(false);
await AddLinkedNodeForTypeAsync(
project, symbol.WithSymbol(namedType), graphBuilder,
symbol.Symbol.DeclaringSyntaxReferences.Select(d => d.SyntaxTree)).ConfigureAwait(false);
}
else
{
......@@ -63,13 +65,15 @@ private async Task ProcessProjectAsync(Project project, GraphBuilder graphBuilde
}
}
private async Task<GraphNode> AddLinkedNodeForTypeAsync(Project project, INamedTypeSymbol namedType, GraphBuilder graphBuilder, IEnumerable<SyntaxTree> syntaxTrees)
private async Task<GraphNode> AddLinkedNodeForTypeAsync(
Project project, SymbolAndProjectId<INamedTypeSymbol> namedTypeAndProjectId, GraphBuilder graphBuilder, IEnumerable<SyntaxTree> syntaxTrees)
{
// If this named type is contained in a parent type, then just link farther up
if (namedType.ContainingType != null)
if (namedTypeAndProjectId.Symbol.ContainingType != null)
{
var parentTypeNode = await AddLinkedNodeForTypeAsync(project, namedType.ContainingType, graphBuilder, syntaxTrees).ConfigureAwait(false);
var typeNode = await graphBuilder.AddNodeForSymbolAsync(namedType, relatedNode: parentTypeNode).ConfigureAwait(false);
var parentTypeNode = await AddLinkedNodeForTypeAsync(
project, namedTypeAndProjectId.WithSymbol(namedTypeAndProjectId.Symbol.ContainingType), graphBuilder, syntaxTrees).ConfigureAwait(false);
var typeNode = await graphBuilder.AddNodeAsync(namedTypeAndProjectId, relatedNode: parentTypeNode).ConfigureAwait(false);
graphBuilder.AddLink(parentTypeNode, GraphCommonSchema.Contains, typeNode);
return typeNode;
......@@ -77,7 +81,7 @@ private async Task<GraphNode> AddLinkedNodeForTypeAsync(Project project, INamedT
else
{
// From here, we can link back up to the containing project item
var typeNode = await graphBuilder.AddNodeForSymbolAsync(namedType, contextProject: project, contextDocument: null).ConfigureAwait(false);
var typeNode = await graphBuilder.AddNodeAsync(namedTypeAndProjectId, contextProject: project, contextDocument: null).ConfigureAwait(false);
foreach (var tree in syntaxTrees)
{
......@@ -92,20 +96,24 @@ private async Task<GraphNode> AddLinkedNodeForTypeAsync(Project project, INamedT
}
}
private async Task<GraphNode> AddLinkedNodeForMemberAsync(Project project, ISymbol member, GraphBuilder graphBuilder)
private async Task<GraphNode> AddLinkedNodeForMemberAsync(
Project project, SymbolAndProjectId symbolAndProjectId, GraphBuilder graphBuilder)
{
var member = symbolAndProjectId.Symbol;
Contract.ThrowIfNull(member.ContainingType);
var trees = member.DeclaringSyntaxReferences.Select(d => d.SyntaxTree);
var parentTypeNode = await AddLinkedNodeForTypeAsync(project, member.ContainingType, graphBuilder, trees).ConfigureAwait(false);
var memberNode = await graphBuilder.AddNodeForSymbolAsync(member, relatedNode: parentTypeNode).ConfigureAwait(false);
var parentTypeNode = await AddLinkedNodeForTypeAsync(
project, symbolAndProjectId.WithSymbol(member.ContainingType), graphBuilder, trees).ConfigureAwait(false);
var memberNode = await graphBuilder.AddNodeAsync(
symbolAndProjectId, relatedNode: parentTypeNode).ConfigureAwait(false);
graphBuilder.AddLink(parentTypeNode, GraphCommonSchema.Contains, memberNode);
return memberNode;
}
internal async Task<ImmutableArray<ISymbol>> FindNavigableSourceSymbolsAsync(
internal async Task<ImmutableArray<SymbolAndProjectId>> FindNavigableSourceSymbolsAsync(
Project project, CancellationToken cancellationToken)
{
ImmutableArray<SymbolAndProjectId> declarations;
......@@ -131,14 +139,14 @@ private async Task<GraphNode> AddLinkedNodeForMemberAsync(Project project, ISymb
throw ExceptionUtilities.Unreachable;
}
var symbols = declarations.SelectAsArray(d => d.Symbol);
using var _ = ArrayBuilder<SymbolAndProjectId>.GetInstance(out var results);
var results = ArrayBuilder<ISymbol>.GetInstance();
foreach (var symbol in symbols)
foreach (var declaration in declarations)
{
cancellationToken.ThrowIfCancellationRequested();
var symbol = declaration.Symbol;
// Ignore constructors and namespaces. We don't want to expose them through this API.
if (symbol.IsConstructor() ||
symbol.IsStaticConstructor() ||
......@@ -153,7 +161,7 @@ private async Task<GraphNode> AddLinkedNodeForMemberAsync(Project project, ISymb
continue;
}
results.Add(symbol);
results.Add(declaration);
// also report matching constructors (using same match result as type)
if (symbol is INamedTypeSymbol namedType)
......@@ -163,7 +171,7 @@ private async Task<GraphNode> AddLinkedNodeForMemberAsync(Project project, ISymb
// only constructors that were explicitly declared
if (!constructor.IsImplicitlyDeclared)
{
results.Add(constructor);
results.Add(declaration.WithSymbol(constructor));
}
}
}
......@@ -171,11 +179,11 @@ private async Task<GraphNode> AddLinkedNodeForMemberAsync(Project project, ISymb
// report both parts of partial methods
if (symbol is IMethodSymbol method && method.PartialImplementationPart != null)
{
results.Add(method);
results.Add(declaration.WithSymbol(method));
}
}
return results.ToImmutableAndFree();
return results.ToImmutable();
}
}
}
......@@ -4,11 +4,14 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
......@@ -30,11 +33,11 @@ public static async Task<IEnumerable<SyntaxNode>> GetContainedSyntaxNodesAsync(D
return progressionLanguageService.GetTopLevelNodesFromDocument(root, cancellationToken);
}
public static async Task<IEnumerable<ISymbol>> GetContainedSymbolsAsync(Document document, CancellationToken cancellationToken)
public static async Task<ImmutableArray<SymbolAndProjectId>> GetContainedSymbolsAsync(Document document, CancellationToken cancellationToken)
{
var syntaxNodes = await GetContainedSyntaxNodesAsync(document, cancellationToken).ConfigureAwait(false);
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var symbols = new List<ISymbol>();
using var _ = ArrayBuilder<SymbolAndProjectId>.GetInstance(out var symbols);
foreach (var syntaxNode in syntaxNodes)
{
......@@ -45,11 +48,11 @@ public static async Task<IEnumerable<ISymbol>> GetContainedSymbolsAsync(Document
!string.IsNullOrEmpty(symbol.Name) &&
IsTopLevelSymbol(symbol))
{
symbols.Add(symbol);
symbols.Add(new SymbolAndProjectId(symbol, document.Project.Id));
}
}
return symbols;
return symbols.ToImmutable();
}
private static bool IsTopLevelSymbol(ISymbol symbol)
......@@ -68,10 +71,9 @@ private static bool IsTopLevelSymbol(ISymbol symbol)
}
}
public static IEnumerable<ISymbol> GetContainedSymbols(ISymbol symbol)
public static IEnumerable<SymbolAndProjectId> GetContainedSymbols(SymbolAndProjectId symbolAndProjectId)
{
if (symbol is INamedTypeSymbol namedType)
if (symbolAndProjectId.Symbol is INamedTypeSymbol namedType)
{
foreach (var member in namedType.GetMembers())
{
......@@ -80,7 +82,6 @@ public static IEnumerable<ISymbol> GetContainedSymbols(ISymbol symbol)
continue;
}
if (member is IMethodSymbol method && method.AssociatedSymbol != null)
{
continue;
......@@ -88,7 +89,7 @@ public static IEnumerable<ISymbol> GetContainedSymbols(ISymbol symbol)
if (!string.IsNullOrEmpty(member.Name))
{
yield return member;
yield return symbolAndProjectId.WithSymbol(member);
}
}
}
......
......@@ -238,7 +238,7 @@ public async Task RemoveDiagnosticForMappedFileToManyDocumentsTestAsync()
Assert.Contains(results[2].Diagnostics, d => d.Code == "doc2Diagnostic");
}
[Fact]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/43046")]
public async Task ClearAllDiagnosticsForMappedFilesTestAsync()
{
using var workspace = CreateTestWorkspace("", out _);
......
......@@ -43,7 +43,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Progression
End If
Dim graphBuilder As New GraphBuilder(_workspace.CurrentSolution, CancellationToken.None)
graphBuilder.AddNodeForSymbolAsync(symbol, document.Project, document).Wait(CancellationToken.None)
graphBuilder.AddNodeAsync(
New SymbolAndProjectId(symbol, document.Project.Id), document.Project, document).Wait(CancellationToken.None)
Return graphBuilder.Graph
End Function
......
......@@ -28,35 +28,6 @@ public static async Task<IEnumerable<SyntaxToken>> GetConstructorInitializerToke
return FindReferenceCache.GetConstructorInitializerTokens(syntaxFacts, model, root, cancellationToken);
}
internal static async Task<ImmutableArray<SyntaxToken>> GetIdentifierOrGlobalNamespaceTokensWithTextAsync(
this Document document, SemanticModel model, string identifier, CancellationToken cancellationToken)
{
// It's very costly to walk an entire tree. So if the tree is simple and doesn't contain
// any unicode escapes in it, then we do simple string matching to find the tokens.
var info = await SyntaxTreeIndex.GetIndexAsync(document, cancellationToken).ConfigureAwait(false);
if (!info.ProbablyContainsIdentifier(identifier))
{
return ImmutableArray<SyntaxToken>.Empty;
}
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
if (syntaxFacts == null)
{
return ImmutableArray<SyntaxToken>.Empty;
}
var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);
var version = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false);
SourceText text = null;
if (!info.ProbablyContainsEscapedIdentifier(identifier))
{
text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
}
return FindReferenceCache.GetIdentifierOrGlobalNamespaceTokensWithText(syntaxFacts, document, version, model, root, text, identifier, cancellationToken);
}
internal static bool TextMatch(this ISyntaxFactsService syntaxFacts, string text1, string text2)
=> syntaxFacts.StringComparer.Equals(text1, text2);
}
......
......@@ -55,8 +55,8 @@ internal static partial class DependentTypeFinder
private static readonly RelatedTypeCache s_typeToTransitivelyImplementingStructuresClassesAndInterfacesMap = new RelatedTypeCache();
private static readonly RelatedTypeCache s_typeToImmediatelyDerivedAndImplementingTypesMap = new RelatedTypeCache();
public static async Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindTypesFromCacheOrComputeAsync(
INamedTypeSymbol type,
private static async Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindTypesFromCacheOrComputeAsync(
SymbolAndProjectId<INamedTypeSymbol> type,
Solution solution,
IImmutableSet<Project> projects,
RelatedTypeCache cache,
......@@ -69,7 +69,7 @@ internal static partial class DependentTypeFinder
// Do a quick lookup first to avoid the allocation. If it fails, go through the
// slower allocating path.
var key = (type.GetSymbolKey(), projects);
var key = (type.Symbol.GetSymbolKey(), projects);
if (!dictionary.TryGetValue(key, out var lazy))
{
lazy = dictionary.GetOrAdd(key,
......@@ -134,15 +134,14 @@ internal static partial class DependentTypeFinder
/// Used for implementing the Inherited-By relation for progression.
/// </summary>
public static Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindImmediatelyDerivedClassesAsync(
INamedTypeSymbol type,
SymbolAndProjectId<INamedTypeSymbol> type,
Solution solution,
CancellationToken cancellationToken)
{
return FindTypesFromCacheOrComputeAsync(
type, solution, projects: null,
cache: s_typeToImmediatelyDerivedClassesMap,
findAsync: c => FindDerivedClassesAsync(
SymbolAndProjectId.Create(type, projectId: null), solution, projects: null,
findAsync: c => FindDerivedClassesAsync(type, solution, projects: null,
transitive: false, cancellationToken: c),
cancellationToken: cancellationToken);
}
......@@ -151,16 +150,14 @@ internal static partial class DependentTypeFinder
/// This is an internal implementation of <see cref="SymbolFinder.FindDerivedClassesAsync(SymbolAndProjectId{INamedTypeSymbol}, Solution, IImmutableSet{Project}, CancellationToken)"/>, which is a publically callable method.
/// </summary>
public static Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindTransitivelyDerivedClassesAsync(
INamedTypeSymbol type,
SymbolAndProjectId<INamedTypeSymbol> type,
Solution solution,
IImmutableSet<Project> projects,
CancellationToken cancellationToken)
{
return FindTypesFromCacheOrComputeAsync(
type, solution, projects, s_typeToTransitivelyDerivedClassesMap,
c => FindDerivedClassesAsync(
SymbolAndProjectId.Create(type, projectId: null), solution, projects,
transitive: true, cancellationToken: c),
c => FindDerivedClassesAsync(type, solution, projects, transitive: true, c),
cancellationToken);
}
......@@ -195,7 +192,7 @@ bool sourceTypeImmediatelyMatches(SymbolAndProjectIdSet set, INamedTypeSymbol me
/// <see cref="INamedTypeSymbol"/>s
/// </summary>
public static async Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindTransitivelyImplementingStructuresAndClassesAsync(
INamedTypeSymbol type,
SymbolAndProjectId<INamedTypeSymbol> type,
Solution solution,
IImmutableSet<Project> projects,
CancellationToken cancellationToken)
......@@ -212,7 +209,7 @@ bool sourceTypeImmediatelyMatches(SymbolAndProjectIdSet set, INamedTypeSymbol me
/// <see cref="INamedTypeSymbol"/>s
/// </summary>
public static Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindTransitivelyImplementingStructuresClassesAndInterfacesAsync(
INamedTypeSymbol type,
SymbolAndProjectId<INamedTypeSymbol> type,
Solution solution,
IImmutableSet<Project> projects,
CancellationToken cancellationToken)
......@@ -224,21 +221,20 @@ bool sourceTypeImmediatelyMatches(SymbolAndProjectIdSet set, INamedTypeSymbol me
}
private static Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindTransitivelyImplementingStructuresClassesAndInterfacesWorkerAsync(
INamedTypeSymbol type,
SymbolAndProjectId<INamedTypeSymbol> type,
Solution solution,
IImmutableSet<Project> projects,
CancellationToken cancellationToken)
{
return FindDerivedAndImplementingTypesAsync(
SymbolAndProjectId.Create(type, projectId: null), solution, projects,
transitive: true, cancellationToken: cancellationToken);
type, solution, projects, transitive: true, cancellationToken);
}
/// <summary>
/// Used for implementing the Inherited-By relation for progression.
/// </summary>
public static Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindImmediatelyDerivedAndImplementingTypesAsync(
INamedTypeSymbol type,
SymbolAndProjectId<INamedTypeSymbol> type,
Solution solution,
CancellationToken cancellationToken)
{
......@@ -246,8 +242,7 @@ bool sourceTypeImmediatelyMatches(SymbolAndProjectIdSet set, INamedTypeSymbol me
type, solution, projects: null,
cache: s_typeToImmediatelyDerivedAndImplementingTypesMap,
findAsync: c => FindDerivedAndImplementingTypesAsync(
SymbolAndProjectId.Create(type, projectId: null), solution, projects: null,
transitive: false, cancellationToken: c),
type, solution, projects: null, transitive: false, c),
cancellationToken: cancellationToken);
}
......
......@@ -62,8 +62,14 @@ public static SymbolInfo GetSymbolInfo(SemanticModel model, SyntaxNode node, Can
}
public static ImmutableArray<SyntaxToken> GetIdentifierOrGlobalNamespaceTokensWithText(
ISyntaxFactsService syntaxFacts, Document document, VersionStamp version, SemanticModel model, SyntaxNode root, SourceText sourceText,
string text, CancellationToken cancellationToken)
ISyntaxFactsService syntaxFacts,
Document document,
VersionStamp version,
SemanticModel model,
SyntaxNode root,
SourceText sourceText,
string text,
CancellationToken cancellationToken)
{
var normalized = syntaxFacts.IsCaseSensitive ? text : text.ToLowerInvariant();
......@@ -82,17 +88,17 @@ public static SymbolInfo GetSymbolInfo(SemanticModel model, SyntaxNode node, Can
ISyntaxFactsService syntaxFacts, Document document, VersionStamp version, SyntaxNode root, SourceText sourceText,
string text, CancellationToken cancellationToken)
{
bool candidate(SyntaxToken t) =>
syntaxFacts.IsGlobalNamespaceKeyword(t) || (syntaxFacts.IsIdentifier(t) && syntaxFacts.TextMatch(t.ValueText, text));
// identifier is not escaped
if (sourceText != null)
{
return GetTokensFromText(syntaxFacts, document, version, root, sourceText, text, candidate, cancellationToken);
return GetTokensFromText(syntaxFacts, document, version, root, sourceText, text, IsCandidate, cancellationToken);
}
// identifier is escaped
return root.DescendantTokens(descendIntoTrivia: true).Where(candidate).ToImmutableArray();
return root.DescendantTokens(descendIntoTrivia: true).Where(IsCandidate).ToImmutableArray();
bool IsCandidate(SyntaxToken t)
=> syntaxFacts.IsGlobalNamespaceKeyword(t) || (syntaxFacts.IsIdentifier(t) && syntaxFacts.TextMatch(t.ValueText, text));
}
private static ImmutableArray<SyntaxToken> GetTokensFromText(
......
......@@ -14,6 +14,7 @@
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols.Finders
......@@ -167,7 +168,7 @@ protected static bool IdentifiersMatch(ISyntaxFactsService syntaxFacts, string n
Func<SyntaxToken, SemanticModel, (bool matched, CandidateReason reason)> symbolsMatch,
CancellationToken cancellationToken)
{
var tokens = await document.GetIdentifierOrGlobalNamespaceTokensWithTextAsync(semanticModel, identifier, cancellationToken).ConfigureAwait(false);
var tokens = await GetIdentifierOrGlobalNamespaceTokensWithTextAsync(document, semanticModel, identifier, cancellationToken).ConfigureAwait(false);
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
......@@ -180,6 +181,29 @@ protected static bool IdentifiersMatch(ISyntaxFactsService syntaxFacts, string n
cancellationToken);
}
protected static async Task<ImmutableArray<SyntaxToken>> GetIdentifierOrGlobalNamespaceTokensWithTextAsync(Document document, SemanticModel semanticModel, string identifier, CancellationToken cancellationToken)
{
// It's very costly to walk an entire tree. So if the tree is simple and doesn't contain
// any unicode escapes in it, then we do simple string matching to find the tokens.
var info = await SyntaxTreeIndex.GetIndexAsync(document, cancellationToken).ConfigureAwait(false);
if (!info.ProbablyContainsIdentifier(identifier))
return ImmutableArray<SyntaxToken>.Empty;
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
if (syntaxFacts == null)
return ImmutableArray<SyntaxToken>.Empty;
var root = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);
var version = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false);
SourceText text = null;
if (!info.ProbablyContainsEscapedIdentifier(identifier))
text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
return FindReferenceCache.GetIdentifierOrGlobalNamespaceTokensWithText(
syntaxFacts, document, version, semanticModel, root, text, identifier, cancellationToken);
}
protected static Func<SyntaxToken, SemanticModel, (bool matched, CandidateReason reason)> GetStandardSymbolsMatchFunction(
ISymbol symbol, Func<SyntaxToken, SyntaxNode> findParentNode, Solution solution, CancellationToken cancellationToken)
{
......
......@@ -62,7 +62,8 @@ protected override bool CanFind(IMethodSymbol symbol)
var tokens = await document.GetConstructorInitializerTokensAsync(semanticModel, cancellationToken).ConfigureAwait(false);
if (semanticModel.Language == LanguageNames.VisualBasic)
{
tokens = tokens.Concat(await document.GetIdentifierOrGlobalNamespaceTokensWithTextAsync(semanticModel, "New", cancellationToken).ConfigureAwait(false)).Distinct();
tokens = tokens.Concat(await GetIdentifierOrGlobalNamespaceTokensWithTextAsync(
document, semanticModel, "New", cancellationToken).ConfigureAwait(false)).Distinct();
}
return FindReferencesInTokens(
......
......@@ -44,11 +44,13 @@ private static string GetNamespaceIdentifierName(INamespaceSymbol symbol)
var identifierName = GetNamespaceIdentifierName(symbol);
var syntaxFactsService = document.GetLanguageService<ISyntaxFactsService>();
var tokens = await GetIdentifierOrGlobalNamespaceTokensWithTextAsync(
document, semanticModel, identifierName, cancellationToken).ConfigureAwait(false);
var nonAliasReferences = FindReferencesInTokens(symbol,
document,
semanticModel,
await document.GetIdentifierOrGlobalNamespaceTokensWithTextAsync(semanticModel, identifierName, cancellationToken).ConfigureAwait(false),
(SyntaxToken t) => syntaxFactsService.TextMatch(t.ValueText, identifierName),
tokens,
t => syntaxFactsService.TextMatch(t.ValueText, identifierName),
cancellationToken);
var aliasReferences = await FindAliasReferencesAsync(nonAliasReferences, symbol, document, semanticModel, cancellationToken).ConfigureAwait(false);
......
......@@ -13,13 +13,13 @@ namespace Microsoft.CodeAnalysis.FindSymbols
{
internal static class ReferenceLocationExtensions
{
public static async Task<Dictionary<ISymbol, List<Location>>> FindReferencingSymbolsAsync(
public static async Task<Dictionary<SymbolAndProjectId, List<Location>>> FindReferencingSymbolsAsync(
this IEnumerable<ReferenceLocation> referenceLocations,
CancellationToken cancellationToken)
{
var documentGroups = referenceLocations.GroupBy(loc => loc.Document);
var projectGroups = documentGroups.GroupBy(g => g.Key.Project);
var result = new Dictionary<ISymbol, List<Location>>();
var result = new Dictionary<SymbolAndProjectId, List<Location>>();
foreach (var projectGroup in projectGroups)
{
......@@ -48,17 +48,18 @@ internal static class ReferenceLocationExtensions
Document document,
SemanticModel semanticModel,
IEnumerable<ReferenceLocation> references,
Dictionary<ISymbol, List<Location>> result)
Dictionary<SymbolAndProjectId, List<Location>> result)
{
foreach (var reference in references)
{
var containingSymbol = GetEnclosingMethodOrPropertyOrField(semanticModel, reference);
if (containingSymbol != null)
{
if (!result.TryGetValue(containingSymbol, out var locations))
var symbolAndProjectId = new SymbolAndProjectId(containingSymbol, document.Project.Id);
if (!result.TryGetValue(symbolAndProjectId, out var locations))
{
locations = new List<Location>();
result.Add(containingSymbol, locations);
result.Add(symbolAndProjectId, locations);
}
locations.Add(reference.Location);
......
......@@ -20,7 +20,9 @@ public struct SymbolCallerInfo
/// <summary>
/// The symbol that is calling the symbol being called.
/// </summary>
public ISymbol CallingSymbol { get; }
public ISymbol CallingSymbol => CallingSymbolAndProjectId.Symbol;
internal SymbolAndProjectId CallingSymbolAndProjectId { get; }
/// <summary>
/// The locations inside the calling symbol where the called symbol is referenced.
......@@ -30,7 +32,9 @@ public struct SymbolCallerInfo
/// <summary>
/// The symbol being called.
/// </summary>
public ISymbol CalledSymbol { get; }
public ISymbol CalledSymbol => CalledSymbolAndProjectId.Symbol;
internal SymbolAndProjectId CalledSymbolAndProjectId { get; }
/// <summary>
/// True if the CallingSymbol is directly calling CalledSymbol. False if it is calling a
......@@ -40,11 +44,14 @@ public struct SymbolCallerInfo
/// </summary>
public bool IsDirect { get; }
internal SymbolCallerInfo(ISymbol callingSymbol, ISymbol calledSymbol, IEnumerable<Location> locations, bool isDirect)
: this()
internal SymbolCallerInfo(
SymbolAndProjectId callingSymbol,
SymbolAndProjectId calledSymbol,
IEnumerable<Location> locations,
bool isDirect)
{
this.CallingSymbol = callingSymbol;
this.CalledSymbol = calledSymbol;
CallingSymbolAndProjectId = callingSymbol;
CalledSymbolAndProjectId = calledSymbol;
this.IsDirect = isDirect;
this.Locations = locations;
}
......
......@@ -19,19 +19,6 @@ namespace Microsoft.CodeAnalysis.FindSymbols
{
public static partial class SymbolFinder
{
/// <summary>
/// Find symbols for members that override the specified member symbol.
/// </summary>
public static async Task<IEnumerable<ISymbol>> FindOverridesAsync(
ISymbol symbol, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default)
{
var result = await FindOverridesAsync(
SymbolAndProjectId.Create(symbol, projectId: null),
solution, projects, cancellationToken).ConfigureAwait(false);
return result.SelectAsArray(s => s.Symbol);
}
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindOverridesAsync(
SymbolAndProjectId symbolAndProjectId, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default)
{
......@@ -79,18 +66,6 @@ public static partial class SymbolFinder
return false;
}
/// <summary>
/// Find symbols for declarations that implement members of the specified interface symbol
/// </summary>
public static async Task<IEnumerable<ISymbol>> FindImplementedInterfaceMembersAsync(
ISymbol symbol, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default)
{
var result = await FindImplementedInterfaceMembersAsync(
SymbolAndProjectId.Create(symbol, projectId: null),
solution, projects, cancellationToken).ConfigureAwait(false);
return result.SelectAsArray(s => s.Symbol);
}
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindImplementedInterfaceMembersAsync(
SymbolAndProjectId symbolAndProjectId, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default)
{
......@@ -180,51 +155,17 @@ public static partial class SymbolFinder
return type.Symbol.AllInterfaces.Select(type.WithSymbol);
}
/// <summary>
/// Finds the derived classes of the given type. Implementations of an interface are not considered "derived", but can be found
/// with <see cref="FindImplementationsAsync(ISymbol, Solution, IImmutableSet{Project}, CancellationToken)"/>.
/// </summary>
/// <param name="type">The symbol to find derived types of.</param>
/// <param name="solution">The solution to search in.</param>
/// <param name="projects">The projects to search. Can be null to search the entire solution.</param>
/// <param name="cancellationToken"></param>
/// <returns>The derived types of the symbol. The symbol passed in is not included in this list.</returns>
public static async Task<IEnumerable<INamedTypeSymbol>> FindDerivedClassesAsync(
INamedTypeSymbol type, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default)
{
var result = await FindDerivedClassesAsync(
SymbolAndProjectId.Create(type, projectId: null),
solution, projects, cancellationToken).ConfigureAwait(false);
return result.SelectAsArray(s => s.Symbol);
}
internal static Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindDerivedClassesAsync(
SymbolAndProjectId<INamedTypeSymbol> typeAndProjectId, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default)
{
var type = typeAndProjectId.Symbol;
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (solution == null)
{
throw new ArgumentNullException(nameof(solution));
}
return DependentTypeFinder.FindTransitivelyDerivedClassesAsync(type, solution, projects, cancellationToken);
}
/// <summary>
/// Finds the symbols that implement an interface or interface member.
/// </summary>
public static async Task<IEnumerable<ISymbol>> FindImplementationsAsync(
ISymbol symbol, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default)
{
var result = await FindImplementationsAsync(
SymbolAndProjectId.Create(symbol, projectId: null),
solution, projects, cancellationToken).ConfigureAwait(false);
return result.SelectAsArray(s => s.Symbol);
return DependentTypeFinder.FindTransitivelyDerivedClassesAsync(typeAndProjectId, solution, projects, cancellationToken);
}
internal static async Task<ImmutableArray<SymbolAndProjectId>> FindImplementationsAsync(
......@@ -235,7 +176,8 @@ public static partial class SymbolFinder
var symbol = symbolAndProjectId.Symbol;
if (symbol is INamedTypeSymbol namedTypeSymbol)
{
var implementingTypes = await DependentTypeFinder.FindTransitivelyImplementingStructuresAndClassesAsync(namedTypeSymbol, solution, projects, cancellationToken).ConfigureAwait(false);
var implementingTypes = await DependentTypeFinder.FindTransitivelyImplementingStructuresAndClassesAsync(
symbolAndProjectId.WithSymbol(namedTypeSymbol), solution, projects, cancellationToken).ConfigureAwait(false);
return implementingTypes.Select(s => (SymbolAndProjectId)s)
.Where(IsAccessible)
.ToImmutableArray();
......@@ -243,7 +185,8 @@ public static partial class SymbolFinder
else if (symbol.IsImplementableMember())
{
var containingType = symbol.ContainingType.OriginalDefinition;
var allTypes = await DependentTypeFinder.FindTransitivelyImplementingStructuresClassesAndInterfacesAsync(containingType, solution, projects, cancellationToken).ConfigureAwait(false);
var allTypes = await DependentTypeFinder.FindTransitivelyImplementingStructuresClassesAndInterfacesAsync(
symbolAndProjectId.WithSymbol(containingType), solution, projects, cancellationToken).ConfigureAwait(false);
ImmutableArray<SymbolAndProjectId>.Builder results = null;
foreach (var t in allTypes.Convert<INamedTypeSymbol, ITypeSymbol>())
......@@ -288,25 +231,26 @@ private static bool IsAccessible(SymbolAndProjectId symbolAndProjectId)
/// <summary>
/// Finds all the callers of a specified symbol.
/// </summary>
public static Task<IEnumerable<SymbolCallerInfo>> FindCallersAsync(
ISymbol symbol, Solution solution, CancellationToken cancellationToken = default)
internal static Task<IEnumerable<SymbolCallerInfo>> FindCallersAsync(
SymbolAndProjectId symbolAndProjectId, Solution solution, CancellationToken cancellationToken = default)
{
return FindCallersAsync(symbol, solution, documents: null, cancellationToken: cancellationToken);
return FindCallersAsync(symbolAndProjectId, solution, documents: null, cancellationToken: cancellationToken);
}
/// <summary>
/// Finds all the callers of a specified symbol.
/// </summary>
public static async Task<IEnumerable<SymbolCallerInfo>> FindCallersAsync(ISymbol symbol, Solution solution, IImmutableSet<Document> documents, CancellationToken cancellationToken = default)
internal static async Task<IEnumerable<SymbolCallerInfo>> FindCallersAsync(
SymbolAndProjectId symbolAndProjectId, Solution solution, IImmutableSet<Document> documents, CancellationToken cancellationToken = default)
{
symbol = symbol.OriginalDefinition;
var foundSymbol = await FindSourceDefinitionAsync(symbol, solution, cancellationToken).ConfigureAwait(false);
symbol = foundSymbol ?? symbol;
symbolAndProjectId = symbolAndProjectId.WithSymbol(symbolAndProjectId.Symbol.OriginalDefinition);
var foundSymbol = await FindSourceDefinitionAsync(symbolAndProjectId, solution, cancellationToken).ConfigureAwait(false);
symbolAndProjectId = foundSymbol.Symbol != null ? foundSymbol : symbolAndProjectId;
var references = await FindCallReferencesAsync(solution, symbol, documents, cancellationToken).ConfigureAwait(false);
var references = await FindCallReferencesAsync(solution, symbolAndProjectId, documents, cancellationToken).ConfigureAwait(false);
var directReference = references.Where(
r => SymbolEquivalenceComparer.Instance.Equals(symbol, r.Definition)).FirstOrDefault();
r => SymbolEquivalenceComparer.Instance.Equals(symbolAndProjectId.Symbol, r.Definition)).FirstOrDefault();
var indirectReferences = references.WhereAsArray(r => r != directReference);
......@@ -329,26 +273,29 @@ async Task AddReferencingSymbols(ReferencedSymbol reference, bool isDirect)
var result = await reference.Locations.FindReferencingSymbolsAsync(cancellationToken).ConfigureAwait(false);
foreach (var (callingSymbol, locations) in result)
{
results.Add(new SymbolCallerInfo(callingSymbol, reference.Definition, locations, isDirect));
results.Add(new SymbolCallerInfo(callingSymbol, reference.DefinitionAndProjectId, locations, isDirect));
}
}
}
private static async Task<ImmutableArray<ReferencedSymbol>> FindCallReferencesAsync(
Solution solution,
ISymbol symbol,
SymbolAndProjectId symbolAndProjectId,
IImmutableSet<Document> documents,
CancellationToken cancellationToken = default)
{
var symbol = symbolAndProjectId.Symbol;
if (symbol != null)
{
if (symbol.Kind == SymbolKind.Event ||
symbol.Kind == SymbolKind.Method ||
symbol.Kind == SymbolKind.Property)
{
var result = await FindReferencesAsync(
symbol, solution, documents, cancellationToken).ConfigureAwait(false);
return result.ToImmutableArray();
var collector = new StreamingProgressCollector();
await FindReferencesAsync(
symbolAndProjectId, solution, collector, documents,
FindReferencesSearchOptions.Default, cancellationToken).ConfigureAwait(false);
return collector.GetReferencedSymbols();
}
}
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.FindSymbols
{
// This file contains the legacy SymbolFinder APIs. The APIs are legacy because they
// do not contain enough information for us to effectively remote them over to the OOP
// process to do the work. Specifically, they lack the "current project context" necessary
// to be able to effectively serialize symbols to/from the remote process.
public static partial class SymbolFinder
{
/// <summary>
/// Find symbols for members that override the specified member symbol.
/// </summary>
public static async Task<IEnumerable<ISymbol>> FindOverridesAsync(
ISymbol symbol, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default)
{
var result = await FindOverridesAsync(
SymbolAndProjectId.Create(symbol, projectId: null),
solution, projects, cancellationToken).ConfigureAwait(false);
return result.SelectAsArray(s => s.Symbol);
}
/// <summary>
/// Find symbols for declarations that implement members of the specified interface symbol
/// </summary>
public static async Task<IEnumerable<ISymbol>> FindImplementedInterfaceMembersAsync(
ISymbol symbol, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default)
{
var result = await FindImplementedInterfaceMembersAsync(
SymbolAndProjectId.Create(symbol, projectId: null),
solution, projects, cancellationToken).ConfigureAwait(false);
return result.SelectAsArray(s => s.Symbol);
}
/// <summary>
/// Finds the derived classes of the given type. Implementations of an interface are not considered "derived", but can be found
/// with <see cref="FindImplementationsAsync(ISymbol, Solution, IImmutableSet{Project}, CancellationToken)"/>.
/// </summary>
/// <param name="type">The symbol to find derived types of.</param>
/// <param name="solution">The solution to search in.</param>
/// <param name="projects">The projects to search. Can be null to search the entire solution.</param>
/// <param name="cancellationToken"></param>
/// <returns>The derived types of the symbol. The symbol passed in is not included in this list.</returns>
public static async Task<IEnumerable<INamedTypeSymbol>> FindDerivedClassesAsync(
INamedTypeSymbol type, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default)
{
var result = await FindDerivedClassesAsync(
SymbolAndProjectId.Create(type, projectId: null),
solution, projects, cancellationToken).ConfigureAwait(false);
return result.SelectAsArray(s => s.Symbol);
}
/// <summary>
/// Finds the symbols that implement an interface or interface member.
/// </summary>
public static async Task<IEnumerable<ISymbol>> FindImplementationsAsync(
ISymbol symbol, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default)
{
var result = await FindImplementationsAsync(
SymbolAndProjectId.Create(symbol, projectId: null),
solution, projects, cancellationToken).ConfigureAwait(false);
return result.SelectAsArray(s => s.Symbol);
}
/// <summary>
/// Finds all the callers of a specified symbol.
/// </summary>
public static Task<IEnumerable<SymbolCallerInfo>> FindCallersAsync(
ISymbol symbol, Solution solution, CancellationToken cancellationToken = default)
{
return FindCallersAsync(
SymbolAndProjectId.Create(symbol, projectId: null),
solution, documents: null, cancellationToken);
}
/// <summary>
/// Finds all the callers of a specified symbol.
/// </summary>
public static Task<IEnumerable<SymbolCallerInfo>> FindCallersAsync(
ISymbol symbol, Solution solution, IImmutableSet<Document> documents, CancellationToken cancellationToken = default)
{
return FindCallersAsync(
SymbolAndProjectId.Create(symbol, projectId: null),
solution, documents, cancellationToken);
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Shared.Extensions
{
internal partial class ITypeSymbolExtensions
{
private class ReplaceTypeParameterBasedOnTypeConstraintVisitor : AsyncSymbolVisitor<ITypeSymbol>
{
private readonly CancellationToken _cancellationToken;
private readonly Compilation _compilation;
private readonly ISet<string> _availableTypeParameterNames;
private readonly Solution _solution;
public ReplaceTypeParameterBasedOnTypeConstraintVisitor(Compilation compilation, ISet<string> availableTypeParameterNames, Solution solution, CancellationToken cancellationToken)
{
_compilation = compilation;
_availableTypeParameterNames = availableTypeParameterNames;
_solution = solution;
_cancellationToken = cancellationToken;
}
protected override ITypeSymbol DefaultResult => throw new NotImplementedException();
public override ValueTask<ITypeSymbol> VisitDynamicType(IDynamicTypeSymbol symbol)
=> new ValueTask<ITypeSymbol>(symbol);
public override async ValueTask<ITypeSymbol> VisitArrayType(IArrayTypeSymbol symbol)
{
var elementType = await symbol.ElementType.Accept(this).ConfigureAwait(false);
if (elementType != null && elementType.Equals(symbol.ElementType))
{
return symbol;
}
return _compilation.CreateArrayTypeSymbol(elementType, symbol.Rank);
}
public override async ValueTask<ITypeSymbol> VisitNamedType(INamedTypeSymbol symbol)
{
var arguments = await SpecializedTasks.WhenAll(symbol.TypeArguments.Select(t => t.Accept(this))).ConfigureAwait(false);
if (arguments.SequenceEqual(symbol.TypeArguments))
{
return symbol;
}
return symbol.ConstructedFrom.Construct(arguments.ToArray());
}
public override async ValueTask<ITypeSymbol> VisitPointerType(IPointerTypeSymbol symbol)
{
var elementType = await symbol.PointedAtType.Accept(this).ConfigureAwait(false);
if (elementType != null && elementType.Equals(symbol.PointedAtType))
{
return symbol;
}
return _compilation.CreatePointerTypeSymbol(elementType);
}
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;
}
}
}
}
}
......@@ -230,20 +230,6 @@ where SymbolEquivalenceComparer.Instance.Equals(explicitInterfaceMethod, constru
return type?.Accept(new AnonymousTypeRemover(compilation));
}
[return: NotNullIfNotNull(parameterName: "type")]
public static ValueTask<ITypeSymbol?> ReplaceTypeParametersBasedOnTypeConstraintsAsync(
this ITypeSymbol? type,
Compilation compilation,
IEnumerable<ITypeParameterSymbol> availableTypeParameters,
Solution solution,
CancellationToken cancellationToken)
{
#pragma warning disable CA2012 // Use ValueTasks correctly (https://github.com/dotnet/roslyn-analyzers/issues/3384)
return type?.Accept(new ReplaceTypeParameterBasedOnTypeConstraintVisitor(compilation, availableTypeParameters.Select(t => t.Name).ToSet(), solution, cancellationToken))
#pragma warning restore CA2012 // Use ValueTasks correctly
?? new ValueTask<ITypeSymbol?>((ITypeSymbol?)null);
}
[return: NotNullIfNotNull(parameterName: "type")]
public static ITypeSymbol? RemoveUnnamedErrorTypes(
this ITypeSymbol? type,
......
......@@ -5,6 +5,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Elfie.Model;
using Microsoft.CodeAnalysis.FindSymbols;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -27,6 +28,8 @@ 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;
......@@ -34,10 +37,10 @@ namespace M
{
public class DerivedClass : BaseClass { }
}
", MscorlibRef, solution.Projects.Single(pid => pid.Name == "PortableProject").Id);
", MscorlibRef, portableProject.Id);
// get symbols for types
var portableCompilation = await solution.Projects.Single(p => p.Name == "PortableProject").GetCompilationAsync();
var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();
var baseClassSymbol = portableCompilation.GetTypeByMetadataName("N.BaseClass");
var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();
......@@ -47,11 +50,17 @@ public class DerivedClass : BaseClass { }
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 derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(
SymbolAndProjectId.Create(baseClassSymbol, portableProject.Id), solution, CancellationToken.None);
var derivedDependentType = derivedFromBase.Single();
Assert.Equal(derivedClassSymbol, derivedDependentType.Symbol);
}
private static Project GetPortableProject(Solution solution)
{
return solution.Projects.Single(p => p.Name == "PortableProject");
}
[Fact]
public async Task ImmediatelyDerivedTypes_CSharp_AliasedNames()
{
......@@ -65,6 +74,8 @@ 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;
......@@ -76,10 +87,10 @@ namespace M
public class DerivedClass : Alias2 { }
}
", MscorlibRef, solution.Projects.Single(pid => pid.Name == "PortableProject").Id);
", MscorlibRef, portableProject.Id);
// get symbols for types
var portableCompilation = await solution.Projects.Single(p => p.Name == "PortableProject").GetCompilationAsync();
var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();
var baseClassSymbol = portableCompilation.GetTypeByMetadataName("N.BaseClass");
var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();
......@@ -89,7 +100,8 @@ public class DerivedClass : Alias2 { }
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 derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(
SymbolAndProjectId.Create(baseClassSymbol, portableProject.Id), solution, CancellationToken.None);
var derivedDependentType = derivedFromBase.Single();
Assert.Equal(derivedClassSymbol, derivedDependentType.Symbol);
}
......@@ -108,6 +120,8 @@ 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;
......@@ -115,10 +129,10 @@ namespace M
{
public class DerivedClass : BaseClass { }
}
", SystemRuntimePP7Ref, solution.Projects.Single(pid => pid.Name == "PortableProject").Id);
", SystemRuntimePP7Ref, portableProject.Id);
// get symbols for types
var portableCompilation = await solution.Projects.Single(p => p.Name == "PortableProject").GetCompilationAsync();
var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();
var baseClassSymbol = portableCompilation.GetTypeByMetadataName("N.BaseClass");
var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();
......@@ -128,7 +142,8 @@ public class DerivedClass : BaseClass { }
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 derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(
SymbolAndProjectId.Create(baseClassSymbol, portableProject.Id), solution, CancellationToken.None);
var derivedDependentType = derivedFromBase.Single();
Assert.Equal(derivedClassSymbol, derivedDependentType.Symbol);
}
......@@ -147,6 +162,8 @@ 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
......@@ -155,10 +172,10 @@ Namespace M
Inherits BaseClass
End Class
End Namespace
", MscorlibRef, solution.Projects.Single(pid => pid.Name == "PortableProject").Id);
", MscorlibRef, portableProject.Id);
// get symbols for types
var portableCompilation = await solution.Projects.Single(p => p.Name == "PortableProject").GetCompilationAsync();
var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();
var baseClassSymbol = portableCompilation.GetTypeByMetadataName("N.BaseClass");
var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();
......@@ -168,7 +185,8 @@ End Namespace
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 derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(
SymbolAndProjectId.Create(baseClassSymbol, portableProject.Id), solution, CancellationToken.None);
var derivedDependentType = derivedFromBase.Single();
Assert.Equal(derivedClassSymbol, derivedDependentType.Symbol);
}
......@@ -187,6 +205,8 @@ 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.VisualBasic, @"
Imports N
......@@ -195,10 +215,10 @@ Namespace M
Inherits BaseClass
End Class
End Namespace
", MscorlibRef, solution.Projects.Single(pid => pid.Name == "PortableProject").Id);
", MscorlibRef, portableProject.Id);
// get symbols for types
var portableCompilation = await solution.Projects.Single(p => p.Name == "PortableProject").GetCompilationAsync();
var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();
var baseClassSymbol = portableCompilation.GetTypeByMetadataName("N.BaseClass");
var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();
......@@ -208,7 +228,8 @@ End Namespace
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 derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(
SymbolAndProjectId.Create(baseClassSymbol, portableProject.Id), solution, CancellationToken.None);
var derivedDependentType = derivedFromBase.Single();
Assert.Equal(derivedClassSymbol, derivedDependentType.Symbol);
}
......@@ -227,6 +248,8 @@ public interface IBaseInterface { }
}
", MscorlibRefPortable);
var portableProject = GetPortableProject(solution);
// create a normal assembly with a type implementing that interface
solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.CSharp, @"
using N;
......@@ -234,10 +257,10 @@ namespace M
{
public class ImplementingClass : IBaseInterface { }
}
", MscorlibRef, solution.Projects.Single(pid => pid.Name == "PortableProject").Id);
", MscorlibRef, portableProject.Id);
// get symbols for types
var portableCompilation = await solution.Projects.Single(p => p.Name == "PortableProject").GetCompilationAsync();
var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();
var baseInterfaceSymbol = portableCompilation.GetTypeByMetadataName("N.IBaseInterface");
var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();
......@@ -248,7 +271,7 @@ public class ImplementingClass : IBaseInterface { }
// verify that the implementing types of `N.IBaseInterface` correctly resolve to `M.ImplementingClass`
var typesThatImplementInterface = await DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync(
baseInterfaceSymbol, solution, CancellationToken.None);
SymbolAndProjectId.Create(baseInterfaceSymbol, portableProject.Id), solution, CancellationToken.None);
Assert.Equal(implementingClassSymbol, typesThatImplementInterface.Single().Symbol);
}
......@@ -266,6 +289,8 @@ 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
......@@ -274,10 +299,10 @@ Namespace M
Implements IBaseInterface
End Class
End Namespace
", MscorlibRef, solution.Projects.Single(pid => pid.Name == "PortableProject").Id);
", MscorlibRef, portableProject.Id);
// get symbols for types
var portableCompilation = await solution.Projects.Single(p => p.Name == "PortableProject").GetCompilationAsync();
var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();
var baseInterfaceSymbol = portableCompilation.GetTypeByMetadataName("N.IBaseInterface");
var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();
......@@ -288,7 +313,7 @@ End Namespace
// verify that the implementing types of `N.IBaseInterface` correctly resolve to `M.ImplementingClass`
var typesThatImplementInterface = await DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync(
baseInterfaceSymbol, solution, CancellationToken.None);
SymbolAndProjectId.Create(baseInterfaceSymbol, portableProject.Id), solution, CancellationToken.None);
Assert.Equal(implementingClassSymbol, typesThatImplementInterface.Single().Symbol);
}
......@@ -306,6 +331,8 @@ End Interface
End Namespace
", MscorlibRefPortable);
var portableProject = GetPortableProject(solution);
// create a normal assembly with a type implementing that interface
solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.CSharp, @"
using N;
......@@ -313,10 +340,10 @@ namespace M
{
public class ImplementingClass : IBaseInterface { }
}
", MscorlibRef, solution.Projects.Single(pid => pid.Name == "PortableProject").Id);
", MscorlibRef, portableProject.Id);
// get symbols for types
var portableCompilation = await solution.Projects.Single(p => p.Name == "PortableProject").GetCompilationAsync();
var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();
var baseInterfaceSymbol = portableCompilation.GetTypeByMetadataName("N.IBaseInterface");
var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();
......@@ -327,7 +354,7 @@ public class ImplementingClass : IBaseInterface { }
// verify that the implementing types of `N.IBaseInterface` correctly resolve to `M.ImplementingClass`
var typesThatImplementInterface = await DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync(
baseInterfaceSymbol, solution, CancellationToken.None);
SymbolAndProjectId.Create(baseInterfaceSymbol, portableProject.Id), solution, CancellationToken.None);
Assert.Equal(implementingClassSymbol, typesThatImplementInterface.Single().Symbol);
}
}
......
......@@ -28,10 +28,10 @@ public static IEnumerable<INamedTypeSymbol> GetBaseTypesAndThis(this INamedTypeS
}
}
public static IEnumerable<ITypeParameterSymbol> GetAllTypeParameters(this INamedTypeSymbol? symbol)
public static ImmutableArray<ITypeParameterSymbol> GetAllTypeParameters(this INamedTypeSymbol? symbol)
{
var stack = GetContainmentStack(symbol);
return stack.SelectMany(n => n.TypeParameters);
return stack.SelectMany(n => n.TypeParameters).ToImmutableArray();
}
public static IEnumerable<ITypeSymbol> GetAllTypeArguments(this INamedTypeSymbol? symbol)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册