Speed up progression searches by using the navigate-to index#54382
Speed up progression searches by using the navigate-to index#54382CyrusNajmabadi merged 12 commits intodotnet:mainfrom
Conversation
| // to. | ||
| spanStart = sourceText.Length; | ||
| } | ||
| var span = NavigateToUtilities.GetBoundedSpan(_searchResult.NavigableItem, sourceText); |
There was a problem hiding this comment.
extracted the above into a helper to use in progression as well.
| return result; | ||
| } | ||
| } | ||
| => NavigateToUtilities.GetKindsProvided(_workspace.CurrentSolution); |
There was a problem hiding this comment.
similar. this moved to a common locatino so Progressin could use it.
src/VisualStudio/Core/Def/Implementation/Progression/ProgressionOptions.cs
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/Progression/ProgressionOptions.cs
Show resolved
Hide resolved
| private static string GetIconString(Glyph glyph) | ||
| { | ||
| return glyph switch | ||
| { | ||
| Glyph.ClassPublic or Glyph.ClassProtected or Glyph.ClassPrivate or Glyph.ClassInternal => IconHelper.GetIconName("Class", GetAccessibility(glyph, Glyph.ClassPublic)), | ||
| Glyph.ConstantPublic or Glyph.ConstantProtected or Glyph.ConstantPrivate or Glyph.ConstantInternal => IconHelper.GetIconName("Field", GetAccessibility(glyph, Glyph.ConstantPublic)), | ||
| Glyph.DelegatePublic or Glyph.DelegateProtected or Glyph.DelegatePrivate or Glyph.DelegateInternal => IconHelper.GetIconName("Delegate", GetAccessibility(glyph, Glyph.DelegatePublic)), | ||
| Glyph.EnumPublic or Glyph.EnumProtected or Glyph.EnumPrivate or Glyph.EnumInternal => IconHelper.GetIconName("Enum", GetAccessibility(glyph, Glyph.EnumPublic)), | ||
| Glyph.EnumMemberPublic or Glyph.EnumMemberProtected or Glyph.EnumMemberPrivate or Glyph.EnumMemberInternal => IconHelper.GetIconName("EnumMember", GetAccessibility(glyph, Glyph.EnumMemberPublic)), | ||
| Glyph.ExtensionMethodPublic or Glyph.ExtensionMethodProtected or Glyph.ExtensionMethodPrivate or Glyph.ExtensionMethodInternal => IconHelper.GetIconName("Method", GetAccessibility(glyph, Glyph.ExtensionMethodPublic)), | ||
| Glyph.EventPublic or Glyph.EventProtected or Glyph.EventPrivate or Glyph.EventInternal => IconHelper.GetIconName("Event", GetAccessibility(glyph, Glyph.EventPublic)), | ||
| Glyph.FieldPublic or Glyph.FieldProtected or Glyph.FieldPrivate or Glyph.FieldInternal => IconHelper.GetIconName("Field", GetAccessibility(glyph, Glyph.FieldPublic)), | ||
| Glyph.InterfacePublic or Glyph.InterfaceProtected or Glyph.InterfacePrivate or Glyph.InterfaceInternal => IconHelper.GetIconName("Interface", GetAccessibility(glyph, Glyph.InterfacePublic)), | ||
| Glyph.MethodPublic or Glyph.MethodProtected or Glyph.MethodPrivate or Glyph.MethodInternal => IconHelper.GetIconName("Method", GetAccessibility(glyph, Glyph.MethodPublic)), | ||
| Glyph.ModulePublic or Glyph.ModuleProtected or Glyph.ModulePrivate or Glyph.ModuleInternal => IconHelper.GetIconName("Module", GetAccessibility(glyph, Glyph.ModulePublic)), | ||
| Glyph.PropertyPublic or Glyph.PropertyProtected or Glyph.PropertyPrivate or Glyph.PropertyInternal => IconHelper.GetIconName("Property", GetAccessibility(glyph, Glyph.PropertyPublic)), | ||
| Glyph.StructurePublic or Glyph.StructureProtected or Glyph.StructurePrivate or Glyph.StructureInternal => IconHelper.GetIconName("Structure", GetAccessibility(glyph, Glyph.StructurePublic)), | ||
| _ => null, | ||
| }; |
There was a problem hiding this comment.
Anyway to instead reuse GetTags?
and also:
There was a problem hiding this comment.
yup. THat seems nice. Thanks!
| } | ||
|
|
||
| private static Accessibility GetAccessibility(ImmutableArray<string> tags) | ||
| public static Accessibility GetAccessibility(ImmutableArray<string> tags) |
There was a problem hiding this comment.
| public static Accessibility GetAccessibility(ImmutableArray<string> tags) | |
| public static Accessibility GetAccessibility(this ImmutableArray<string> tags) |
very nit here, but I would expect this to be an extension like the others in the file.
There was a problem hiding this comment.
nooooooooooooooooooooooooooooooooooooo do not make highly specific extension methods on widely used types like this.
There was a problem hiding this comment.
i'm not a fan of extending random collections. For example, you could have an ImmutableArray in many different contexts. Having this .GetAccessibility extension show up for all of those seems wonky to me :)
There was a problem hiding this comment.
almost all static types called XXXExtensions though are extension methods. Should it move instead?
| NavigateToItemKind.Constant or | ||
| NavigateToItemKind.EnumItem or | ||
| NavigateToItemKind.Field => CodeNodeCategories.Field, |
There was a problem hiding this comment.
| NavigateToItemKind.Constant or | |
| NavigateToItemKind.EnumItem or | |
| NavigateToItemKind.Field => CodeNodeCategories.Field, | |
| NavigateToItemKind.Constant or | |
| NavigateToItemKind.EnumItem or | |
| NavigateToItemKind.Field => CodeNodeCategories.Field, |
This is definitely a style preference, but I find it hard to know that items are linked to a single thing in switch expressions without the indentation.
| var groupName = glyph switch | ||
| { | ||
| Glyph.ClassPublic or Glyph.ClassProtected or Glyph.ClassPrivate or Glyph.ClassInternal => "Class", | ||
| Glyph.ConstantPublic or Glyph.ConstantProtected or Glyph.ConstantPrivate or Glyph.ConstantInternal => "Field", |
There was a problem hiding this comment.
Do we use the same glyph for constants and fields?
There was a problem hiding this comment.
Yup! As per GetOrCreateNodeForFieldAsync it looks like we only distinguish fields and enum-members in progression.
The current progression search system works by literally walking the entire solution, producing compilations for all projects and symbols for every symbol therein. This is pretty terrible as it's enormously costly and uses a ton of ram. On my machine it takes a full 2 minutes to search Roslyn.sln and uses at least a GB of ram.
This PR introduces a new implementation of progression search that sits on top of the NavigateTo search index instead. This brings search time down <4 seconds, and uses around 900mb less memory. This also benefits from:
However, this change is not a pure win. The way progression search works today is that all entries are backed by real symbols. This means that the presented nodes can expose commands (like 'find all callers'). These continue to work for normal progression items. However, this is not supported for tehse new search results (as they're not backed by a real symbol anymore).
The progression team is going to investigate though how often (if ever) these advanced commands are used on search results. We hypothesize that very few people will be affected by this, but we would like data to be sure. So, in the meantime, this will be off by default.