-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Find dependent types more efficiently by storing inheritance info directly in our indices. #11313
Changes from 65 commits
cdd6ae2
05edce6
7b3f3fc
2b53f67
34cfbc8
3231d5c
1bc2a33
895aae8
db529bb
a0b4ae8
0f10675
e530f35
5899191
b7cbe4b
9dc1d81
2a64e25
e22be5c
00aab8f
38fc108
7d9d0aa
c000f95
079b33e
c7d1078
e43b127
a52813b
907cdfe
7e69ca2
3e7ebcf
96810ec
dba9b28
deb4fe3
f70f829
bb4137c
4bf06cc
bdf09da
091d664
386df78
6692376
0f13e98
b366740
445e325
2f73524
6dc136f
a16a09c
ed984a5
fed0a33
78131a7
0f087bf
05f17f2
ca411a8
37b9999
419e2d9
993c2d5
2f3e1ab
302c924
3e6558e
653d1bd
8f704c1
4e96456
5632828
b19cb19
942c751
0aef7d4
d377f78
33be43f
253eb57
01a74a2
a6e2bea
e1be5c9
77c293e
31acc1f
28f6f3e
0662815
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,49 +759,56 @@ public bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo dec | |
GetFullyQualifiedContainerName(node.Parent), | ||
DeclaredSymbolInfoKind.Constructor, | ||
ctorDecl.Identifier.Span, | ||
ImmutableArray<string>.Empty, | ||
parameterCount: (ushort)(ctorDecl.ParameterList?.Parameters.Count ?? 0)); | ||
return true; | ||
case SyntaxKind.DelegateDeclaration: | ||
var delegateDecl = (DelegateDeclarationSyntax)node; | ||
declaredSymbolInfo = new DeclaredSymbolInfo(delegateDecl.Identifier.ValueText, | ||
GetContainerDisplayName(node.Parent), | ||
GetFullyQualifiedContainerName(node.Parent), | ||
DeclaredSymbolInfoKind.Delegate, delegateDecl.Identifier.Span); | ||
DeclaredSymbolInfoKind.Delegate, delegateDecl.Identifier.Span, | ||
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, | ||
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, | ||
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, | ||
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, | ||
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, | ||
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, | ||
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, | ||
ImmutableArray<string>.Empty); | ||
return true; | ||
} | ||
|
||
|
@@ -853,6 +867,126 @@ 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); | ||
|
||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you document what the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure! |
||
{ | ||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "namespace" |
||
// 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) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
named arguments (for this and rest of file)