提交 a247cea1 编写于 作者: C CyrusNajmabadi

Merge pull request #11313 from CyrusNajmabadi/findRefsOneProject

Find dependent types more efficiently by storing inheritance info directly in our indices.

Fixes #11255
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
......@@ -11,7 +12,7 @@ namespace Roslyn.Utilities
/// A concurrent, simplified HashSet.
/// </summary>
[DebuggerDisplay("Count = {Count}")]
internal sealed class ConcurrentSet<T> : IEnumerable<T>
internal sealed class ConcurrentSet<T> : ICollection<T>
{
/// <summary>
/// The default concurrency level is 2. That means the collection can cope with up to two
......@@ -65,6 +66,8 @@ public bool IsEmpty
get { return _dictionary.IsEmpty; }
}
public bool IsReadOnly => false;
/// <summary>
/// Determine whether the given value is in the set.
/// </summary>
......@@ -85,6 +88,17 @@ public bool Add(T value)
return _dictionary.TryAdd(value, 0);
}
public void AddRange(IEnumerable<T> values)
{
if (values != null)
{
foreach (var v in values)
{
Add(v);
}
}
}
/// <summary>
/// Attempts to remove a value from the set.
/// </summary>
......@@ -161,5 +175,15 @@ IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumeratorImpl();
}
void ICollection<T>.Add(T item)
{
Add(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
throw new NotImplementedException();
}
}
}
......@@ -63,9 +63,7 @@ private ISymbol FindSymbol()
// CancellationToken.None.
var semanticModel = Document.GetPartialSemanticModelAsync(CancellationToken.None).GetAwaiter().GetResult();
var root = semanticModel.SyntaxTree.GetRoot(CancellationToken.None);
var node = root.FindNode(_declaredSymbolInfo.Span);
return semanticModel.GetDeclaredSymbol(node, CancellationToken.None);
return _declaredSymbolInfo.Resolve(semanticModel, CancellationToken.None);
}
}
}
......
......@@ -22,7 +22,6 @@ public static INavigableItem GetItemFromDeclaredSymbolInfo(DeclaredSymbolInfo de
return new DeclaredSymbolNavigableItem(document, declaredSymbolInfo);
}
public static IEnumerable<INavigableItem> GetItemsFromPreferredSourceLocations(Solution solution, ISymbol symbol, string displayString = null)
{
var locations = GetPreferredSourceLocations(solution, symbol);
......
......@@ -22,8 +22,9 @@ internal static class NavigateToSymbolFinder
foreach (var document in project.Documents)
{
cancellationToken.ThrowIfCancellationRequested();
var declaredSymbolInfos = await document.GetDeclaredSymbolInfosAsync(cancellationToken).ConfigureAwait(false);
foreach (var declaredSymbolInfo in declaredSymbolInfos)
var declarationInfo = await document.GetDeclarationInfoAsync(cancellationToken).ConfigureAwait(false);
foreach (var declaredSymbolInfo in declarationInfo.DeclaredSymbolInfos)
{
cancellationToken.ThrowIfCancellationRequested();
var patternMatches = patternMatcher.GetMatches(
......
......@@ -25,7 +25,7 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
if (namedType.TypeKind == TypeKind.Class)
{
var derivedTypes = await DependentTypeFinder.GetTypesImmediatelyDerivedFromClassesAsync(namedType, solution, cancellationToken).ConfigureAwait(false);
var derivedTypes = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(namedType, solution, cancellationToken).ConfigureAwait(false);
foreach (var derivedType in derivedTypes)
{
var symbolNode = await graphBuilder.AddNodeForSymbolAsync(derivedType, relatedNode: node).ConfigureAwait(false);
......@@ -34,7 +34,8 @@ public async Task<GraphBuilder> GetGraphAsync(Solution solution, IGraphContext c
}
else if (namedType.TypeKind == TypeKind.Interface)
{
var derivedTypes = await DependentTypeFinder.GetTypesImmediatelyDerivedFromInterfacesAsync(namedType, solution, cancellationToken).ConfigureAwait(false);
var derivedTypes = await DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync(
namedType, solution, cancellationToken).ConfigureAwait(false);
foreach (var derivedType in derivedTypes)
{
var symbolNode = await graphBuilder.AddNodeForSymbolAsync(derivedType, relatedNode: node).ConfigureAwait(false);
......
......@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Linq;
......@@ -20,7 +21,7 @@
namespace Microsoft.CodeAnalysis.CSharp
{
[ExportLanguageService(typeof(ISyntaxFactsService), LanguageNames.CSharp), Shared]
internal class CSharpSyntaxFactsService : ISyntaxFactsService
internal class CSharpSyntaxFactsService : AbstractSyntaxFactsService, ISyntaxFactsService
{
public bool IsAwaitKeyword(SyntaxToken token)
{
......@@ -747,7 +748,8 @@ public bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo dec
declaredSymbolInfo = new DeclaredSymbolInfo(classDecl.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Class, classDecl.Identifier.Span);
DeclaredSymbolInfoKind.Class, classDecl.Identifier.Span,
GetInheritanceNames(classDecl.BaseList));
return true;
case SyntaxKind.ConstructorDeclaration:
var ctorDecl = (ConstructorDeclarationSyntax)node;
......@@ -757,6 +759,7 @@ public bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo dec
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Constructor,
ctorDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty,
parameterCount: (ushort)(ctorDecl.ParameterList?.Parameters.Count ?? 0));
return true;
case SyntaxKind.DelegateDeclaration:
......@@ -764,42 +767,48 @@ public bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo dec
declaredSymbolInfo = new DeclaredSymbolInfo(delegateDecl.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Delegate, delegateDecl.Identifier.Span);
DeclaredSymbolInfoKind.Delegate, delegateDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.EnumDeclaration:
var enumDecl = (EnumDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(enumDecl.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Enum, enumDecl.Identifier.Span);
DeclaredSymbolInfoKind.Enum, enumDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.EnumMemberDeclaration:
var enumMember = (EnumMemberDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(enumMember.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.EnumMember, enumMember.Identifier.Span);
DeclaredSymbolInfoKind.EnumMember, enumMember.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.EventDeclaration:
var eventDecl = (EventDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(ExpandExplicitInterfaceName(eventDecl.Identifier.ValueText, eventDecl.ExplicitInterfaceSpecifier),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Event, eventDecl.Identifier.Span);
DeclaredSymbolInfoKind.Event, eventDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.IndexerDeclaration:
var indexerDecl = (IndexerDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(WellKnownMemberNames.Indexer,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Indexer, indexerDecl.ThisKeyword.Span);
DeclaredSymbolInfoKind.Indexer, indexerDecl.ThisKeyword.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.InterfaceDeclaration:
var interfaceDecl = (InterfaceDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(interfaceDecl.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Interface, interfaceDecl.Identifier.Span);
DeclaredSymbolInfoKind.Interface, interfaceDecl.Identifier.Span,
GetInheritanceNames(interfaceDecl.BaseList));
return true;
case SyntaxKind.MethodDeclaration:
var method = (MethodDeclarationSyntax)node;
......@@ -809,6 +818,7 @@ public bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo dec
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Method,
method.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty,
parameterCount: (ushort)(method.ParameterList?.Parameters.Count ?? 0),
typeParameterCount: (ushort)(method.TypeParameterList?.Parameters.Count ?? 0));
return true;
......@@ -817,14 +827,16 @@ public bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo dec
declaredSymbolInfo = new DeclaredSymbolInfo(ExpandExplicitInterfaceName(property.Identifier.ValueText, property.ExplicitInterfaceSpecifier),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Property, property.Identifier.Span);
DeclaredSymbolInfoKind.Property, property.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.StructDeclaration:
var structDecl = (StructDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(structDecl.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Struct, structDecl.Identifier.Span);
DeclaredSymbolInfoKind.Struct, structDecl.Identifier.Span,
GetInheritanceNames(structDecl.BaseList));
return true;
case SyntaxKind.VariableDeclarator:
// could either be part of a field declaration or an event field declaration
......@@ -839,10 +851,12 @@ public bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo dec
? DeclaredSymbolInfoKind.Constant
: DeclaredSymbolInfoKind.Field;
declaredSymbolInfo = new DeclaredSymbolInfo(variableDeclarator.Identifier.ValueText,
GetContainerDisplayName(fieldDeclaration.Parent),
GetFullyQualifiedContainerName(fieldDeclaration.Parent),
kind, variableDeclarator.Identifier.Span);
declaredSymbolInfo = new DeclaredSymbolInfo(
variableDeclarator.Identifier.ValueText,
GetContainerDisplayName(fieldDeclaration.Parent),
GetFullyQualifiedContainerName(fieldDeclaration.Parent),
kind, variableDeclarator.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
}
......@@ -853,6 +867,144 @@ public bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo dec
return false;
}
private ImmutableArray<string> GetInheritanceNames(BaseListSyntax baseList)
{
if (baseList == null)
{
return ImmutableArray<string>.Empty;
}
var builder = ImmutableArray.CreateBuilder<string>(baseList.Types.Count);
// It's not sufficient to just store the textual names we see in the inheritance list
// of a type. For example if we have:
//
// using Y = X;
// ...
// using Z = Y;
// ...
// class C : Z
//
// It's insufficient to just state that 'C' derives from 'Z'. If we search for derived
// types from 'B' we won't examine 'C'. To solve this, we keep track of the aliasing
// that occurs in containing scopes. Then, when we're adding an inheritance name we
// walk the alias maps and we also add any names that these names alias to. In the
// above example we'd put Z, Y, and X in the inheritance names list for 'C'.
// Each dictionary in this list is a mapping from alias name to the name of the thing
// it aliases. Then, each scope with alias mapping gets its own entry in this list.
// For the above example, we would produce: [{Z => Y}, {Y => X}]
var aliasMaps = AllocateAliasMapList();
try
{
AddAliasMaps(baseList, aliasMaps);
foreach (var baseType in baseList.Types)
{
AddInheritanceName(builder, baseType.Type, aliasMaps);
}
return builder.ToImmutable();
}
finally
{
FreeAliasMapList(aliasMaps);
}
}
private void AddAliasMaps(SyntaxNode node, List<Dictionary<string, string>> aliasMaps)
{
for (var current = node; current != null; current = current.Parent)
{
if (current.IsKind(SyntaxKind.NamespaceDeclaration))
{
ProcessUsings(aliasMaps, ((NamespaceDeclarationSyntax)current).Usings);
}
else if (current.IsKind(SyntaxKind.CompilationUnit))
{
ProcessUsings(aliasMaps, ((CompilationUnitSyntax)current).Usings);
}
}
}
private void ProcessUsings(List<Dictionary<string, string>> aliasMaps, SyntaxList<UsingDirectiveSyntax> usings)
{
Dictionary<string, string> aliasMap = null;
foreach (var usingDecl in usings)
{
if (usingDecl.Alias != null)
{
var mappedName = GetTypeName(usingDecl.Name);
if (mappedName != null)
{
aliasMap = aliasMap ?? AllocateAliasMap();
// If we have: using X = Foo, then we store a mapping from X -> Foo
// here. That way if we see a class that inherits from X we also state
// that it inherits from Foo as well.
aliasMap[usingDecl.Alias.Name.Identifier.ValueText] = mappedName;
}
}
}
if (aliasMap != null)
{
aliasMaps.Add(aliasMap);
}
}
private void AddInheritanceName(
ImmutableArray<string>.Builder builder, TypeSyntax type,
List<Dictionary<string, string>> aliasMaps)
{
var name = GetTypeName(type);
if (name != null)
{
// First, add the name that the typename that the type directly says it inherits from.
builder.Add(name);
// Now, walk the alias chain and add any names this alias may eventually map to.
var currentName = name;
foreach (var aliasMap in aliasMaps)
{
string mappedName;
if (aliasMap.TryGetValue(currentName, out mappedName))
{
// Looks like this could be an alias. Also include the name the alias points to
builder.Add(mappedName);
// Keep on searching. An alias in an inner namespcae can refer to an
// alias in an outer namespace.
currentName = mappedName;
}
}
}
}
private string GetTypeName(TypeSyntax type)
{
if (type is SimpleNameSyntax)
{
return GetSimpleTypeName((SimpleNameSyntax)type);
}
else if (type is QualifiedNameSyntax)
{
return GetSimpleTypeName(((QualifiedNameSyntax)type).Right);
}
else if (type is AliasQualifiedNameSyntax)
{
return GetSimpleTypeName(((AliasQualifiedNameSyntax)type).Name);
}
return null;
}
private static string GetSimpleTypeName(SimpleNameSyntax name)
{
return name.Identifier.ValueText;
}
private static string ExpandExplicitInterfaceName(string identifier, ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifier)
{
if (explicitInterfaceSpecifier == null)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Text;
......@@ -35,7 +38,19 @@ internal struct DeclaredSymbolInfo
public ushort ParameterCount { get; }
public ushort TypeParameterCount { get; }
public DeclaredSymbolInfo(string name, string containerDisplayName, string fullyQualifiedContainerName, DeclaredSymbolInfoKind kind, TextSpan span, ushort parameterCount = 0, ushort typeParameterCount = 0)
/// <summary>
/// The names directly referenced in source that this type inherits from.
/// </summary>
public ImmutableArray<string> InheritanceNames { get; }
public DeclaredSymbolInfo(
string name,
string containerDisplayName,
string fullyQualifiedContainerName,
DeclaredSymbolInfoKind kind,
TextSpan span,
ImmutableArray<string> inheritanceNames,
ushort parameterCount = 0, ushort typeParameterCount = 0)
: this()
{
Name = name;
......@@ -45,6 +60,7 @@ public DeclaredSymbolInfo(string name, string containerDisplayName, string fully
Span = span;
ParameterCount = parameterCount;
TypeParameterCount = typeParameterCount;
InheritanceNames = inheritanceNames;
}
internal void WriteTo(ObjectWriter writer)
......@@ -57,6 +73,12 @@ internal void WriteTo(ObjectWriter writer)
writer.WriteInt32(Span.Length);
writer.WriteUInt16(ParameterCount);
writer.WriteUInt16(TypeParameterCount);
writer.WriteInt32(InheritanceNames.Length);
foreach (var name in InheritanceNames)
{
writer.WriteString(name);
}
}
internal static DeclaredSymbolInfo ReadFrom(ObjectReader reader)
......@@ -72,12 +94,35 @@ internal static DeclaredSymbolInfo ReadFrom(ObjectReader reader)
var parameterCount = reader.ReadUInt16();
var typeParameterCount = reader.ReadUInt16();
return new DeclaredSymbolInfo(name, immediateContainer, entireContainer, kind, new TextSpan(spanStart, spanLength), parameterCount, typeParameterCount);
var inheritanceNamesLength = reader.ReadInt32();
var builder = ImmutableArray.CreateBuilder<string>(inheritanceNamesLength);
for (var i = 0; i < inheritanceNamesLength; i++)
{
builder.Add(reader.ReadString());
}
return new DeclaredSymbolInfo(
name, immediateContainer, entireContainer, kind, new TextSpan(spanStart, spanLength),
builder.MoveToImmutable(),
parameterCount, typeParameterCount);
}
catch
{
return default(DeclaredSymbolInfo);
}
}
public async Task<ISymbol> ResolveAsync(Document document, CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
return Resolve(semanticModel, cancellationToken);
}
public ISymbol Resolve(SemanticModel semanticModel, CancellationToken cancellationToken)
{
var root = semanticModel.SyntaxTree.GetRoot(cancellationToken);
var node = root.FindNode(this.Span);
return semanticModel.GetDeclaredSymbol(node, cancellationToken);
}
}
}
......@@ -225,11 +225,11 @@ protected static bool IdentifiersMatch(ISyntaxFactsService syntaxFacts, string n
var symbolToMatch = symbolInfoToMatch.Symbol;
var symbolToMatchCompilation = model.Compilation;
if (DependentTypeFinder.OriginalSymbolsMatch(searchSymbol, symbolInfoToMatch.Symbol, solution, null, symbolToMatchCompilation, cancellationToken))
if (SymbolFinder.OriginalSymbolsMatch(searchSymbol, symbolInfoToMatch.Symbol, solution, null, symbolToMatchCompilation, cancellationToken))
{
return ValueTuple.Create(true, CandidateReason.None);
}
else if (symbolInfoToMatch.CandidateSymbols.Any(s => DependentTypeFinder.OriginalSymbolsMatch(searchSymbol, s, solution, null, symbolToMatchCompilation, cancellationToken)))
else if (symbolInfoToMatch.CandidateSymbols.Any(s => SymbolFinder.OriginalSymbolsMatch(searchSymbol, s, solution, null, symbolToMatchCompilation, cancellationToken)))
{
return ValueTuple.Create(true, symbolInfoToMatch.CandidateReason);
}
......
......@@ -43,7 +43,7 @@ public static partial class SymbolFinder
if (member != null &&
member.IsOverride &&
member.OverriddenMember() != null &&
DependentTypeFinder.OriginalSymbolsMatch(member.OverriddenMember().OriginalDefinition, symbol.OriginalDefinition, solution, cancellationToken))
OriginalSymbolsMatch(member.OverriddenMember().OriginalDefinition, symbol.OriginalDefinition, solution, cancellationToken))
{
results = results ?? new List<ISymbol>();
results.Add(member);
......@@ -152,7 +152,7 @@ public static partial class SymbolFinder
throw new ArgumentNullException(nameof(solution));
}
return DependentTypeFinder.FindDerivedClassesAsync(type, solution, projects, cancellationToken);
return DependentTypeFinder.FindTransitivelyDerivedClassesAsync(type, solution, projects, cancellationToken);
}
/// <summary>
......@@ -166,13 +166,13 @@ public static partial class SymbolFinder
if (symbol is INamedTypeSymbol)
{
var namedTypeSymbol = (INamedTypeSymbol)symbol;
var implementingTypes = await DependentTypeFinder.FindImplementingTypesAsync(namedTypeSymbol, solution, projects, cancellationToken).ConfigureAwait(false);
var implementingTypes = await DependentTypeFinder.FindTransitivelyImplementingTypesAsync(namedTypeSymbol, solution, projects, cancellationToken).ConfigureAwait(false);
return implementingTypes.Where(IsAccessible);
}
else if (symbol.IsImplementableMember())
{
var containingType = symbol.ContainingType.OriginalDefinition;
var allTypes = await DependentTypeFinder.FindImplementingTypesAsync(containingType, solution, projects, cancellationToken).ConfigureAwait(false);
var allTypes = await DependentTypeFinder.FindTransitivelyImplementingTypesAsync(containingType, solution, projects, cancellationToken).ConfigureAwait(false);
List<ISymbol> results = null;
foreach (var t in allTypes)
......@@ -275,5 +275,257 @@ public static async Task<IEnumerable<SymbolCallerInfo>> FindCallersAsync(ISymbol
return SpecializedTasks.EmptyEnumerable<ReferencedSymbol>();
}
private static bool OriginalSymbolsMatch(
ISymbol searchSymbol,
ISymbol symbolToMatch,
Solution solution,
CancellationToken cancellationToken)
{
if (ReferenceEquals(searchSymbol, symbolToMatch))
{
return true;
}
if (searchSymbol == null || symbolToMatch == null)
{
return false;
}
Compilation symbolToMatchCompilation = null;
if (!TryGetCompilation(symbolToMatch, solution, out symbolToMatchCompilation, cancellationToken))
{
return false;
}
return OriginalSymbolsMatch(searchSymbol, symbolToMatch, solution, null, symbolToMatchCompilation, cancellationToken);
}
internal static bool OriginalSymbolsMatch(
ISymbol searchSymbol,
ISymbol symbolToMatch,
Solution solution,
Compilation searchSymbolCompilation,
Compilation symbolToMatchCompilation,
CancellationToken cancellationToken)
{
if (symbolToMatch == null)
{
return false;
}
if (OriginalSymbolsMatchCore(searchSymbol, symbolToMatch, solution, searchSymbolCompilation, symbolToMatchCompilation, cancellationToken))
{
return true;
}
if (searchSymbol.Kind == SymbolKind.Namespace && symbolToMatch.Kind == SymbolKind.Namespace)
{
// if one of them is a merged namespace symbol and other one is its constituent namespace symbol, they are equivalent.
var namespace1 = (INamespaceSymbol)searchSymbol;
var namespace2 = (INamespaceSymbol)symbolToMatch;
var namespace1Count = namespace1.ConstituentNamespaces.Length;
var namespace2Count = namespace2.ConstituentNamespaces.Length;
if (namespace1Count != namespace2Count)
{
if ((namespace1Count > 1 &&
namespace1.ConstituentNamespaces.Any(n => NamespaceSymbolsMatch(n, namespace2, solution, cancellationToken))) ||
(namespace2Count > 1 &&
namespace2.ConstituentNamespaces.Any(n2 => NamespaceSymbolsMatch(namespace1, n2, solution, cancellationToken))))
{
return true;
}
}
}
if (searchSymbol.Kind == SymbolKind.NamedType && symbolToMatch.IsConstructor())
{
return OriginalSymbolsMatch(searchSymbol, symbolToMatch.ContainingType, solution, searchSymbolCompilation, symbolToMatchCompilation, cancellationToken);
}
return false;
}
private static bool OriginalSymbolsMatchCore(
ISymbol searchSymbol,
ISymbol symbolToMatch,
Solution solution,
Compilation searchSymbolCompilation,
Compilation symbolToMatchCompilation,
CancellationToken cancellationToken)
{
if (searchSymbol == null || symbolToMatch == null)
{
return false;
}
searchSymbol = searchSymbol.GetOriginalUnreducedDefinition();
symbolToMatch = symbolToMatch.GetOriginalUnreducedDefinition();
// We compare the given searchSymbol and symbolToMatch for equivalence using SymbolEquivalenceComparer
// as follows:
// 1) We compare the given symbols using the SymbolEquivalenceComparer.IgnoreAssembliesInstance,
// which ignores the containing assemblies for named types equivalence checks. This is required
// to handle equivalent named types which are forwarded to completely different assemblies.
// 2) If the symbols are NOT equivalent ignoring assemblies, then they cannot be equivalent.
// 3) Otherwise, if the symbols ARE equivalent ignoring assemblies, they may or may not be equivalent
// if containing assemblies are NOT ignored. We need to perform additional checks to ensure they
// are indeed equivalent:
//
// (a) If IgnoreAssembliesInstance.Equals equivalence visitor encountered any pair of non-nested
// named types which were equivalent in all aspects, except that they resided in different
// assemblies, we need to ensure that all such pairs are indeed equivalent types. Such a pair
// of named types is equivalent if and only if one of them is a type defined in either
// searchSymbolCompilation(C1) or symbolToMatchCompilation(C2), say defined in reference assembly
// A (version v1) in compilation C1, and the other type is a forwarded type, such that it is
// forwarded from reference assembly A (version v2) to assembly B in compilation C2.
// (b) Otherwise, if no such named type pairs were encountered, symbols ARE equivalent.
using (var equivalentTypesWithDifferingAssemblies = SharedPools.Default<Dictionary<INamedTypeSymbol, INamedTypeSymbol>>().GetPooledObject())
{
// 1) Compare searchSymbol and symbolToMatch using SymbolEquivalenceComparer.IgnoreAssembliesInstance
if (!SymbolEquivalenceComparer.IgnoreAssembliesInstance.Equals(searchSymbol, symbolToMatch, equivalentTypesWithDifferingAssemblies.Object))
{
// 2) If the symbols are NOT equivalent ignoring assemblies, then they cannot be equivalent.
return false;
}
// 3) If the symbols ARE equivalent ignoring assemblies, they may or may not be equivalent if containing assemblies are NOT ignored.
if (equivalentTypesWithDifferingAssemblies.Object.Count > 0)
{
// Step 3a) Ensure that all pairs of named types in equivalentTypesWithDifferingAssemblies are indeed equivalent types.
return VerifyForwardedTypes(equivalentTypesWithDifferingAssemblies.Object, searchSymbol, symbolToMatch,
solution, searchSymbolCompilation, symbolToMatchCompilation, cancellationToken);
}
// 3b) If no such named type pairs were encountered, symbols ARE equivalent.
return true;
}
}
private static bool NamespaceSymbolsMatch(
INamespaceSymbol namespace1,
INamespaceSymbol namespace2,
Solution solution,
CancellationToken cancellationToken)
{
return OriginalSymbolsMatch(namespace1, namespace2, solution, cancellationToken);
}
// Verifies that all pairs of named types in equivalentTypesWithDifferingAssemblies are equivalent forwarded types.
private static bool VerifyForwardedTypes(
Dictionary<INamedTypeSymbol, INamedTypeSymbol> equivalentTypesWithDifferingAssemblies,
ISymbol searchSymbol,
ISymbol symbolToMatch,
Solution solution,
Compilation searchSymbolCompilation,
Compilation symbolToMatchCompilation,
CancellationToken cancellationToken)
{
var verifiedKeys = new HashSet<INamedTypeSymbol>();
var count = equivalentTypesWithDifferingAssemblies.Count;
int verifiedCount = 0;
// First check forwarded types in searchSymbolCompilation.
if (searchSymbolCompilation != null || TryGetCompilation(searchSymbol, solution, out searchSymbolCompilation, cancellationToken))
{
verifiedCount = VerifyForwardedTypes(equivalentTypesWithDifferingAssemblies, searchSymbolCompilation, verifiedKeys, isSearchSymbolCompilation: true);
if (verifiedCount == count)
{
// All equivalent types verified.
return true;
}
}
// Now check forwarded types in symbolToMatchCompilation.
verifiedCount += VerifyForwardedTypes(equivalentTypesWithDifferingAssemblies, symbolToMatchCompilation, verifiedKeys, isSearchSymbolCompilation: false);
return verifiedCount == count;
}
private static int VerifyForwardedTypes(
Dictionary<INamedTypeSymbol, INamedTypeSymbol> equivalentTypesWithDifferingAssemblies,
Compilation compilation,
HashSet<INamedTypeSymbol> verifiedKeys,
bool isSearchSymbolCompilation)
{
Contract.ThrowIfNull(compilation);
Contract.ThrowIfNull(equivalentTypesWithDifferingAssemblies);
Contract.ThrowIfTrue(!equivalentTypesWithDifferingAssemblies.Any());
// Must contain equivalents named types residing in different assemblies.
Contract.ThrowIfFalse(equivalentTypesWithDifferingAssemblies.All(kvp => !SymbolEquivalenceComparer.Instance.Equals(kvp.Key.ContainingAssembly, kvp.Value.ContainingAssembly)));
// Must contain non-nested named types.
Contract.ThrowIfFalse(equivalentTypesWithDifferingAssemblies.All(kvp => kvp.Key.ContainingType == null));
Contract.ThrowIfFalse(equivalentTypesWithDifferingAssemblies.All(kvp => kvp.Value.ContainingType == null));
var referencedAssemblies = new MultiDictionary<string, IAssemblySymbol>();
foreach (var assembly in compilation.GetReferencedAssemblySymbols())
{
referencedAssemblies.Add(assembly.Name, assembly);
}
int verifiedCount = 0;
foreach (var kvp in equivalentTypesWithDifferingAssemblies)
{
if (!verifiedKeys.Contains(kvp.Key))
{
INamedTypeSymbol originalType, expectedForwardedType;
if (isSearchSymbolCompilation)
{
originalType = kvp.Value.OriginalDefinition;
expectedForwardedType = kvp.Key.OriginalDefinition;
}
else
{
originalType = kvp.Key.OriginalDefinition;
expectedForwardedType = kvp.Value.OriginalDefinition;
}
foreach (var referencedAssembly in referencedAssemblies[originalType.ContainingAssembly.Name])
{
var fullyQualifiedTypeName = originalType.MetadataName;
if (originalType.ContainingNamespace != null)
{
fullyQualifiedTypeName = originalType.ContainingNamespace.ToDisplayString(SymbolDisplayFormats.SignatureFormat) +
"." + fullyQualifiedTypeName;
}
// Resolve forwarded type and verify that the types from different assembly are indeed equivalent.
var forwardedType = referencedAssembly.ResolveForwardedType(fullyQualifiedTypeName);
if (forwardedType == expectedForwardedType)
{
verifiedKeys.Add(kvp.Key);
verifiedCount++;
}
}
}
}
return verifiedCount;
}
private static bool TryGetCompilation(
ISymbol symbol,
Solution solution,
out Compilation definingCompilation,
CancellationToken cancellationToken)
{
var definitionProject = solution.GetProject(symbol.ContainingAssembly, cancellationToken);
if (definitionProject == null)
{
definingCompilation = null;
return false;
}
// compilation from definition project must already exist.
if (!definitionProject.TryGetCompilation(out definingCompilation))
{
Contract.Requires(false, "How can compilation not exist?");
return false;
}
return true;
}
}
}
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.FindSymbols
{
/// <summary>
/// Information about all the declarations defined within a document. Each declaration in the
/// document get a single item in <see cref="IDeclarationInfo.DeclaredSymbolInfos"/>.
/// </summary>
internal interface IDeclarationInfo
{
IReadOnlyList<DeclaredSymbolInfo> DeclaredSymbolInfos { get; }
}
}
\ No newline at end of file
......@@ -10,10 +10,10 @@
namespace Microsoft.CodeAnalysis.FindSymbols
{
internal class SyntaxTreeDeclarationInfo : AbstractSyntaxTreeInfo
internal class SyntaxTreeDeclarationInfo : AbstractSyntaxTreeInfo, IDeclarationInfo
{
private const string PersistenceName = "<SyntaxTreeInfoDeclarationPersistence>";
private const string SerializationFormat = "2";
private const string SerializationFormat = "3";
/// <summary>
/// in memory cache will hold onto any info related to opened documents in primary branch or all documents in forked branch
......@@ -23,9 +23,9 @@ internal class SyntaxTreeDeclarationInfo : AbstractSyntaxTreeInfo
private static readonly ConditionalWeakTable<BranchId, ConditionalWeakTable<DocumentId, AbstractSyntaxTreeInfo>> s_cache =
new ConditionalWeakTable<BranchId, ConditionalWeakTable<DocumentId, AbstractSyntaxTreeInfo>>();
public IEnumerable<DeclaredSymbolInfo> DeclaredSymbolInfos { get; }
public IReadOnlyList<DeclaredSymbolInfo> DeclaredSymbolInfos { get; }
public SyntaxTreeDeclarationInfo(VersionStamp version, IEnumerable<DeclaredSymbolInfo> declaredSymbolInfos)
public SyntaxTreeDeclarationInfo(VersionStamp version, IReadOnlyList<DeclaredSymbolInfo> declaredSymbolInfos)
: base(version)
{
DeclaredSymbolInfos = declaredSymbolInfos;
......@@ -33,7 +33,7 @@ public SyntaxTreeDeclarationInfo(VersionStamp version, IEnumerable<DeclaredSymbo
public override void WriteTo(ObjectWriter writer)
{
writer.WriteInt32(DeclaredSymbolInfos.Count());
writer.WriteInt32(DeclaredSymbolInfos.Count);
foreach (var declaredSymbolInfo in DeclaredSymbolInfos)
{
declaredSymbolInfo.WriteTo(writer);
......
......@@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols
internal partial class SyntaxTreeIdentifierInfo : AbstractSyntaxTreeInfo
{
private const string PersistenceName = "<SyntaxTreeInfoIdentifierPersistence>";
private const string SerializationFormat = "1";
private const string SerializationFormat = "2";
/// <summary>
/// in memory cache will hold onto any info related to opened documents in primary branch or all documents in forked branch
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.LanguageServices
{
internal abstract class AbstractSyntaxFactsService
{
private readonly static ObjectPool<List<Dictionary<string, string>>> s_aliasMapListPool =
new ObjectPool<List<Dictionary<string, string>>>(() => new List<Dictionary<string, string>>());
// Note: these names are stored case insensitively. That way the alias mapping works
// properly for VB. It will mean that our inheritance maps may store more links in them
// for C#. However, that's ok. It will be rare in practice, and all it means is that
// we'll end up examining slightly more types (likely 0) when doing operations like
// Find all references.
private readonly static ObjectPool<Dictionary<string, string>> s_aliasMapPool =
new ObjectPool<Dictionary<string, string>>(() => new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase));
protected static List<Dictionary<string, string>> AllocateAliasMapList()
{
return s_aliasMapListPool.Allocate();
}
protected static void FreeAliasMapList(List<Dictionary<string, string>> list)
{
if (list != null)
{
foreach (var aliasMap in list)
{
FreeAliasMap(aliasMap);
}
s_aliasMapListPool.ClearAndFree(list);
}
}
protected static void FreeAliasMap(Dictionary<string, string> aliasMap)
{
if (aliasMap != null)
{
s_aliasMapPool.ClearAndFree(aliasMap);
}
}
protected static Dictionary<string, string> AllocateAliasMap()
{
return s_aliasMapPool.Allocate();
}
}
}
......@@ -158,10 +158,9 @@ public static async Task<bool> IsForkedDocumentWithSyntaxChangesAsync(this Docum
}
}
public static async Task<IEnumerable<DeclaredSymbolInfo>> GetDeclaredSymbolInfosAsync(this Document document, CancellationToken cancellationToken)
public static async Task<IDeclarationInfo> GetDeclarationInfoAsync(this Document document, CancellationToken cancellationToken)
{
var declarationInfo = await SyntaxTreeInfo.GetDeclarationInfoAsync(document, cancellationToken).ConfigureAwait(false);
return declarationInfo.DeclaredSymbolInfos;
return await SyntaxTreeInfo.GetDeclarationInfoAsync(document, cancellationToken).ConfigureAwait(false);
}
/// <summary>
......
......@@ -101,10 +101,10 @@ public override ITypeSymbol VisitTypeParameter(ITypeParameterSymbol symbol)
var derivedImplementedTypesOfEachConstraintType = symbol.ConstraintTypes.Select(ct =>
{
var derivedAndImplementedTypes = new List<INamedTypeSymbol>();
return SymbolFinder.FindDerivedClassesAsync((INamedTypeSymbol)ct, _solution, immutableProjects, _cancellationToken).WaitAndGetResult(_cancellationToken)
.Concat(DependentTypeFinder.FindImplementingTypesAsync((INamedTypeSymbol)ct, _solution, immutableProjects, _cancellationToken).WaitAndGetResult(_cancellationToken))
.ToList();
});
var derivedClasses = SymbolFinder.FindDerivedClassesAsync((INamedTypeSymbol)ct, _solution, immutableProjects, _cancellationToken).WaitAndGetResult(_cancellationToken);
var implementedTypes = DependentTypeFinder.FindTransitivelyImplementingTypesAsync((INamedTypeSymbol)ct, _solution, immutableProjects, _cancellationToken).WaitAndGetResult(_cancellationToken);
return derivedClasses.Concat(implementedTypes).ToList();
}).ToList();
var intersectingTypes = derivedImplementedTypesOfEachConstraintType.Aggregate((x, y) => x.Intersect(y).ToList());
......
......@@ -71,6 +71,11 @@ public static bool IsDelegateType(this ITypeSymbol symbol)
return symbol?.TypeKind == TypeKind.Delegate;
}
public static bool IsStructType(this ITypeSymbol symbol)
{
return symbol?.TypeKind == TypeKind.Struct;
}
public static bool IsAnonymousType(this INamedTypeSymbol symbol)
{
return symbol?.IsAnonymousType == true;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Host
{
/// <summary>
......@@ -10,4 +8,4 @@ namespace Microsoft.CodeAnalysis.Host
public interface ILanguageService
{
}
}
}
\ No newline at end of file
......@@ -346,6 +346,8 @@
<Compile Include="Diagnostics\Extensions.cs" />
<Compile Include="Diagnostics\InternalDiagnosticsOptions.cs" />
<Compile Include="Diagnostics\InternalRuntimeDiagnosticOptions.cs" />
<Compile Include="FindSymbols\SyntaxTree\IDeclarationInfo.cs" />
<Compile Include="LanguageServices\SyntaxFactsService\AbstractSyntaxFactsService.cs" />
<Compile Include="SolutionCrawler\ExportIncrementalAnalyzerProviderAttribute.cs" />
<Compile Include="SolutionCrawler\IIncrementalAnalyzer.cs" />
<Compile Include="SolutionCrawler\IIncrementalAnalyzerProvider.cs" />
......
......@@ -45,7 +45,49 @@ 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.GetTypesImmediatelyDerivedFromClassesAsync(baseClassSymbol, solution, CancellationToken.None);
var derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(baseClassSymbol, solution, CancellationToken.None);
var derivedDependentType = derivedFromBase.Single();
Assert.Equal(derivedClassSymbol, derivedDependentType);
}
[Fact]
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);
// 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, solution.Projects.Single(pid => pid.Name == "PortableProject").Id);
// get symbols for types
var portableCompilation = await solution.Projects.Single(p => p.Name == "PortableProject").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);
}
......@@ -84,7 +126,7 @@ 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.GetTypesImmediatelyDerivedFromClassesAsync(baseClassSymbol, solution, CancellationToken.None);
var derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(baseClassSymbol, solution, CancellationToken.None);
var derivedDependentType = derivedFromBase.Single();
Assert.Equal(derivedClassSymbol, derivedDependentType);
}
......@@ -124,7 +166,7 @@ End Namespace
Assert.NotEqual(baseClassSymbol, derivedClassSymbol.BaseType);
// verify that the dependent types of `N.BaseClass` correctly resolve to `M.DerivedCLass`
var derivedFromBase = await DependentTypeFinder.GetTypesImmediatelyDerivedFromClassesAsync(baseClassSymbol, solution, CancellationToken.None);
var derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(baseClassSymbol, solution, CancellationToken.None);
var derivedDependentType = derivedFromBase.Single();
Assert.Equal(derivedClassSymbol, derivedDependentType);
}
......@@ -164,7 +206,7 @@ End Namespace
Assert.NotEqual(baseClassSymbol, derivedClassSymbol.BaseType);
// verify that the dependent types of `N.BaseClass` correctly resolve to `M.DerivedCLass`
var derivedFromBase = await DependentTypeFinder.GetTypesImmediatelyDerivedFromClassesAsync(baseClassSymbol, solution, CancellationToken.None);
var derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(baseClassSymbol, solution, CancellationToken.None);
var derivedDependentType = derivedFromBase.Single();
Assert.Equal(derivedClassSymbol, derivedDependentType);
}
......@@ -203,7 +245,8 @@ public class ImplementingClass : IBaseInterface { }
Assert.NotEqual(baseInterfaceSymbol, implementingClassSymbol.Interfaces.Single());
// verify that the implementing types of `N.IBaseInterface` correctly resolve to `M.ImplementingClass`
var typesThatImplementInterface = await DependentTypeFinder.GetTypesImmediatelyDerivedFromInterfacesAsync(baseInterfaceSymbol, solution, CancellationToken.None);
var typesThatImplementInterface = await DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync(
baseInterfaceSymbol, solution, CancellationToken.None);
Assert.Equal(implementingClassSymbol, typesThatImplementInterface.Single());
}
......@@ -242,7 +285,8 @@ End Namespace
Assert.NotEqual(baseInterfaceSymbol, implementingClassSymbol.Interfaces.Single());
// verify that the implementing types of `N.IBaseInterface` correctly resolve to `M.ImplementingClass`
var typesThatImplementInterface = await DependentTypeFinder.GetTypesImmediatelyDerivedFromInterfacesAsync(baseInterfaceSymbol, solution, CancellationToken.None);
var typesThatImplementInterface = await DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync(
baseInterfaceSymbol, solution, CancellationToken.None);
Assert.Equal(implementingClassSymbol, typesThatImplementInterface.Single());
}
......@@ -280,7 +324,8 @@ public class ImplementingClass : IBaseInterface { }
Assert.NotEqual(baseInterfaceSymbol, implementingClassSymbol.Interfaces.Single());
// verify that the implementing types of `N.IBaseInterface` correctly resolve to `M.ImplementingClass`
var typesThatImplementInterface = await DependentTypeFinder.GetTypesImmediatelyDerivedFromInterfacesAsync(baseInterfaceSymbol, solution, CancellationToken.None);
var typesThatImplementInterface = await DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync(
baseInterfaceSymbol, solution, CancellationToken.None);
Assert.Equal(implementingClassSymbol, typesThatImplementInterface.Single());
}
}
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Collections.Immutable
Imports System.Composition
Imports System.Text
Imports System.Threading
......@@ -15,6 +16,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.SyntaxFacts
Namespace Microsoft.CodeAnalysis.VisualBasic
<ExportLanguageService(GetType(ISyntaxFactsService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicSyntaxFactsService
Inherits AbstractSyntaxFactsService
Implements ISyntaxFactsService
Public Function IsAwaitKeyword(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsAwaitKeyword
......@@ -761,10 +763,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Select Case node.Kind()
Case SyntaxKind.ClassBlock
Dim classDecl = CType(node, ClassBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(classDecl.ClassStatement.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Class, classDecl.ClassStatement.Identifier.Span)
declaredSymbolInfo = New DeclaredSymbolInfo(
classDecl.ClassStatement.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Class, classDecl.ClassStatement.Identifier.Span,
GetInheritanceNames(classDecl))
Return True
Case SyntaxKind.ConstructorBlock
Dim constructor = CType(node, ConstructorBlockSyntax)
......@@ -776,38 +780,47 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Constructor,
constructor.SubNewStatement.NewKeyword.Span,
ImmutableArray(Of String).Empty,
parameterCount:=CType(If(constructor.SubNewStatement.ParameterList?.Parameters.Count, 0), UShort))
Return True
End If
Case SyntaxKind.DelegateFunctionStatement, SyntaxKind.DelegateSubStatement
Dim delegateDecl = CType(node, DelegateStatementSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(delegateDecl.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Delegate, delegateDecl.Identifier.Span)
declaredSymbolInfo = New DeclaredSymbolInfo(
delegateDecl.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Delegate, delegateDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.EnumBlock
Dim enumDecl = CType(node, EnumBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(enumDecl.EnumStatement.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Enum, enumDecl.EnumStatement.Identifier.Span)
declaredSymbolInfo = New DeclaredSymbolInfo(
enumDecl.EnumStatement.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Enum, enumDecl.EnumStatement.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.EnumMemberDeclaration
Dim enumMember = CType(node, EnumMemberDeclarationSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(enumMember.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.EnumMember, enumMember.Identifier.Span)
declaredSymbolInfo = New DeclaredSymbolInfo(
enumMember.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.EnumMember, enumMember.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.EventStatement
Dim eventDecl = CType(node, EventStatementSyntax)
Dim eventParent = If(TypeOf node.Parent Is EventBlockSyntax, node.Parent.Parent, node.Parent)
declaredSymbolInfo = New DeclaredSymbolInfo(eventDecl.Identifier.ValueText,
GetContainerDisplayName(eventParent),
GetFullyQualifiedContainerName(eventParent),
DeclaredSymbolInfoKind.Event, eventDecl.Identifier.Span)
declaredSymbolInfo = New DeclaredSymbolInfo(
eventDecl.Identifier.ValueText,
GetContainerDisplayName(eventParent),
GetFullyQualifiedContainerName(eventParent),
DeclaredSymbolInfoKind.Event, eventDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.FunctionBlock, SyntaxKind.SubBlock
Dim funcDecl = CType(node, MethodBlockSyntax)
......@@ -817,15 +830,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Method,
funcDecl.SubOrFunctionStatement.Identifier.Span,
ImmutableArray(Of String).Empty,
parameterCount:=CType(If(funcDecl.SubOrFunctionStatement.ParameterList?.Parameters.Count, 0), UShort),
typeParameterCount:=CType(If(funcDecl.SubOrFunctionStatement.TypeParameterList?.Parameters.Count, 0), UShort))
Return True
Case SyntaxKind.InterfaceBlock
Dim interfaceDecl = CType(node, InterfaceBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(interfaceDecl.InterfaceStatement.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Interface, interfaceDecl.InterfaceStatement.Identifier.Span)
declaredSymbolInfo = New DeclaredSymbolInfo(
interfaceDecl.InterfaceStatement.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Interface, interfaceDecl.InterfaceStatement.Identifier.Span,
GetInheritanceNames(interfaceDecl))
Return True
Case SyntaxKind.ModifiedIdentifier
Dim modifiedIdentifier = CType(node, ModifiedIdentifierSyntax)
......@@ -835,33 +851,41 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim kind = If(fieldDecl.Modifiers.Any(Function(m) m.Kind() = SyntaxKind.ConstKeyword),
DeclaredSymbolInfoKind.Constant,
DeclaredSymbolInfoKind.Field)
declaredSymbolInfo = New DeclaredSymbolInfo(modifiedIdentifier.Identifier.ValueText,
GetContainerDisplayName(fieldDecl.Parent),
GetFullyQualifiedContainerName(fieldDecl.Parent),
kind, modifiedIdentifier.Identifier.Span)
declaredSymbolInfo = New DeclaredSymbolInfo(
modifiedIdentifier.Identifier.ValueText,
GetContainerDisplayName(fieldDecl.Parent),
GetFullyQualifiedContainerName(fieldDecl.Parent),
kind, modifiedIdentifier.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
End If
Case SyntaxKind.ModuleBlock
Dim moduleDecl = CType(node, ModuleBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(moduleDecl.ModuleStatement.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Module, moduleDecl.ModuleStatement.Identifier.Span)
declaredSymbolInfo = New DeclaredSymbolInfo(
moduleDecl.ModuleStatement.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Module, moduleDecl.ModuleStatement.Identifier.Span,
GetInheritanceNames(moduleDecl))
Return True
Case SyntaxKind.PropertyStatement
Dim propertyDecl = CType(node, PropertyStatementSyntax)
Dim propertyParent = If(TypeOf node.Parent Is PropertyBlockSyntax, node.Parent.Parent, node.Parent)
declaredSymbolInfo = New DeclaredSymbolInfo(propertyDecl.Identifier.ValueText,
GetContainerDisplayName(propertyParent),
GetFullyQualifiedContainerName(propertyParent),
DeclaredSymbolInfoKind.Property, propertyDecl.Identifier.Span)
declaredSymbolInfo = New DeclaredSymbolInfo(
propertyDecl.Identifier.ValueText,
GetContainerDisplayName(propertyParent),
GetFullyQualifiedContainerName(propertyParent),
DeclaredSymbolInfoKind.Property, propertyDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.StructureBlock
Dim structDecl = CType(node, StructureBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(structDecl.StructureStatement.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Struct, structDecl.StructureStatement.Identifier.Span)
declaredSymbolInfo = New DeclaredSymbolInfo(
structDecl.StructureStatement.Identifier.ValueText,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Struct, structDecl.StructureStatement.Identifier.Span,
GetInheritanceNames(structDecl))
Return True
End Select
......@@ -869,6 +893,87 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return False
End Function
Private Function GetInheritanceNames(typeBlock As TypeBlockSyntax) As ImmutableArray(Of String)
Dim builder = ImmutableArray.CreateBuilder(Of String)
Dim aliasMap = GetAliasMap(typeBlock)
Try
For Each inheritsStatement In typeBlock.Inherits
AddInheritanceNames(builder, inheritsStatement.Types, aliasMap)
Next
For Each implementsStatement In typeBlock.Implements
AddInheritanceNames(builder, implementsStatement.Types, aliasMap)
Next
Return builder.ToImmutable()
Finally
FreeAliasMap(aliasMap)
End Try
End Function
Private Function GetAliasMap(typeBlock As TypeBlockSyntax) As Dictionary(Of String, String)
Dim compilationUnit = typeBlock.SyntaxTree.GetCompilationUnitRoot()
Dim aliasMap As Dictionary(Of String, String) = Nothing
For Each import In compilationUnit.Imports
For Each clause In import.ImportsClauses
If clause.IsKind(SyntaxKind.SimpleImportsClause) Then
Dim simpleImport = DirectCast(clause, SimpleImportsClauseSyntax)
If simpleImport.Alias IsNot Nothing Then
Dim mappedName = GetTypeName(simpleImport.Name)
If mappedName IsNot Nothing Then
aliasMap = If(aliasMap, AllocateAliasMap())
aliasMap(simpleImport.Alias.Identifier.ValueText) = mappedName
End If
End If
End If
Next
Next
Return aliasMap
End Function
Private Sub AddInheritanceNames(
builder As ImmutableArray(Of String).Builder,
types As SeparatedSyntaxList(Of TypeSyntax),
aliasMap As Dictionary(Of String, String))
For Each typeSyntax In types
AddInheritanceName(builder, typeSyntax, aliasMap)
Next
End Sub
Private Sub AddInheritanceName(
builder As ImmutableArray(Of String).Builder,
typeSyntax As TypeSyntax,
aliasMap As Dictionary(Of String, String))
Dim name = GetTypeName(typeSyntax)
If name IsNot Nothing Then
builder.Add(name)
Dim mappedName As String = Nothing
If aliasMap?.TryGetValue(name, mappedName) = True Then
' Looks Like this could be an alias. Also include the name the alias points to
builder.Add(mappedName)
End If
End If
End Sub
Private Function GetTypeName(typeSyntax As TypeSyntax) As String
If TypeOf typeSyntax Is SimpleNameSyntax Then
Return GetSimpleName(DirectCast(typeSyntax, SimpleNameSyntax))
ElseIf TypeOf typeSyntax Is QualifiedNameSyntax Then
Return GetSimpleName(DirectCast(typeSyntax, QualifiedNameSyntax).Right)
End If
Return Nothing
End Function
Private Function GetSimpleName(simpleName As SimpleNameSyntax) As String
Return simpleName.Identifier.ValueText
End Function
Private Function GetContainerDisplayName(node As SyntaxNode) As String
Return GetDisplayName(node, DisplayNameOptions.IncludeTypeParameters)
End Function
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册