Move to a single simple type for internal NavTo results#52315
Move to a single simple type for internal NavTo results#52315CyrusNajmabadi merged 15 commits intodotnet:mainfrom
Conversation
| public static Task SearchProjectInCurrentProcessAsync( | ||
| Project project, ImmutableArray<Document> priorityDocuments, string searchPattern, | ||
| IImmutableSet<string> kinds, Func<INavigateToSearchResult, Task> onResultFound, bool isFullyLoaded, CancellationToken cancellationToken) | ||
| IImmutableSet<string> kinds, Func<RoslynNavigateToItem, Task> onResultFound, bool isFullyLoaded, CancellationToken cancellationToken) |
There was a problem hiding this comment.
First change is that internally we use this simple data type RoslynNavigateToItem as the only currency for producing and passing along nav-to results.
| kind, matchKind, | ||
| isCaseSensitive, | ||
| matchedSpans.ToImmutable(), | ||
| ComputSecondarySort(declaredSymbolInfo)); |
There was a problem hiding this comment.
the type only holds onto the basic data that is needed to rehydrate the UI at the end. importantly, it also doesn't need a Document to hold onto. A doc-id is sufficiient. This is important for a followup PR where we allow searchign just by doc-ids.
| ComputSecondarySort(declaredSymbolInfo)); | ||
| } | ||
|
|
||
| private static string ComputSecondarySort(DeclaredSymbolInfo declaredSymbolInfo) |
There was a problem hiding this comment.
these function moved from AbstractNavigateToSearchService.SearchResult.cs, but are otherwise almost hte same.
|
|
||
| await SearchDocumentInCurrentProcessAsync( | ||
| document, searchPattern, kinds, onResultFound, isFullyLoaded, cancellationToken).ConfigureAwait(false); | ||
| document, searchPattern, kinds, onItemFound, isFullyLoaded, cancellationToken).ConfigureAwait(false); |
There was a problem hiding this comment.
both the remote side and the local side only deal with RoslynNavigateToItem internally. Only on the boundary (this method) do we convert it to the INavigateToResult that consumers need.
| public readonly ImmutableArray<TextSpan> NameMatchSpans; | ||
|
|
||
| [DataMember(Order = 15)] | ||
| public readonly string SecondarySort; |
There was a problem hiding this comment.
it's definitely a lot of fields. but all are used.
| var project = solution.GetProject(DocumentId.ProjectId); | ||
| if (project != null) | ||
| document = project.TryGetSourceGeneratedDocumentForAlreadyGeneratedId(DocumentId); | ||
| } |
There was a problem hiding this comment.
@jasonmalinowski is this the right way to map a doc id back to a possibly source-generated document?
There was a problem hiding this comment.
Is it possible to just make this path async? Because then you can just call GetDocumentAsync().
There was a problem hiding this comment.
And the longer answer: that API I really wish I could mark as friend of the other parts of the workspace so it wasn't available but we don't have that in C#. This might work though, but asyncifying is preferrable.
There was a problem hiding this comment.
Is it possible to just make this path async? Because then you can just call GetDocumentAsync().
i don't want this to be async. if it references a source generated document, then we better have that document. i do not want the documents to be generated.
There was a problem hiding this comment.
So two things to be aware of:
- If this type being serialized across a wire, we might have a source generated document generated in-proc but not OOP yet or vice versa if one side is ahead of the other. We do want to get it updated so a generators only run OOP and in-proc will just pull the contents over, but that would have to be behind an async call.
- This method will not return stale results, at all. I don't know what your lifetime model is, but if say project B depends on A, and A is updated, there's no guarantees this will work.
I haven't reviewed the rest of this PR to figure out what's going on and whether this is safe to use. The intent of the API here was only to implement GetDocument() that takes a syntax tree. I've always been switching code over to GetDocumentAsync() in any sort of OOP-rehydration because calling the async method is either:
- fast and cheap if the document does exist
- won't crash if the document doesn't exist
| internal readonly struct RoslynNavigateToItem | ||
| { | ||
| [DataMember(Order = 0)] | ||
| public readonly bool IsStale; |
There was a problem hiding this comment.
stale-ness is a concept that will be in the next pr. currently all results are non-stale. however, in the next PR it will be ok for a stale-result to be returned. the host can then filter it out if that doc doesn't exist in teh current solution. Navigation will also have to be resilient to the span possibly being out of date.
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
this logic moved from teh main searcher. It depends on actual Document/Project info, so we don't want to do it in OOP, where i want NavigateTo to not depend on those. Instead, it does it on the host side before passing back out to vs.
|
|
||
| Glyph INavigableItem.Glyph => GetGlyph(_item.DeclaredSymbolInfoKind, _item.DeclaredSymbolInfoAccessibility); | ||
|
|
||
| private static Glyph GetPublicGlyph(DeclaredSymbolInfoKind kind) |
There was a problem hiding this comment.
moved from NavigableItemFactory.DeclaredSymbolNavigableItem.cs
| { | ||
| internal partial class NavigableItemFactory | ||
| { | ||
| internal class DeclaredSymbolNavigableItem : INavigableItem |
There was a problem hiding this comment.
another pointless intermediary type. removed.
| #region NavigateTo | ||
|
|
||
| [DataContract] | ||
| internal readonly struct SerializableNavigateToSearchResult |
There was a problem hiding this comment.
more remvoed marshalling types.
sharwell
left a comment
There was a problem hiding this comment.
LGTM on condition that you've tried it in experimental instance on Roslyn for each of the various types we support
| Intern(stringTable, name), | ||
| Intern(stringTable, nameSuffix), | ||
| Intern(stringTable, containerDisplayName), | ||
| Intern(stringTable, fullyQualifiedContainerName), |
There was a problem hiding this comment.
❔ Do we not want to move this into the constructor?
There was a problem hiding this comment.
no. i wanted to be able to use thsi as a DataContract. so the pure data part is in the tyep/constructor. but the types that create tehse on the OOP side go through teh factory method to share stirngs there.
|
@jasonmalinowski is this a better way to do things? |
dibarbet
left a comment
There was a problem hiding this comment.
lgtm, but I can't comment on the source generators bit.
| matchedSpans.ToImmutable()); | ||
| } | ||
|
|
||
| private static string ComputeCombinedProjectName(Document document, ImmutableArray<Project> additionalMatchingProjects) |
There was a problem hiding this comment.
this logic is the same. t he method just moved.
This change makes two important changes to how navto internally reports results when searching C# and VB projects.
First, it decouples the result from having an actual Document instance. We want this in the future as we want to be able to search OOP without necessarily hydrating Document values on the remote side (which saves the synchronization cost).
Second, it removes a couple of intermediary conversion steps. THese were left around from multiple rewrites to this area over the years. NOw, we have a simple internal format for a navto result, and we only convert it to the final form we need as the very last step before giving it to the editor.