Make more dependent-type-finder operations public through SymbolFinder.#43622
Make more dependent-type-finder operations public through SymbolFinder.#43622CyrusNajmabadi merged 56 commits intodotnet:masterfrom
Conversation
| Solution solution, | ||
| IImmutableSet<Project> projects, | ||
| bool transitive, | ||
| CancellationToken cancellationToken) |
There was a problem hiding this comment.
renamed these to 'Descend' or 'Add' to better help explain what they're doing. 'Find' was fairly generic.
| Solution solution, | ||
| IImmutableSet<Project> projects, | ||
| bool transitive, | ||
| CancellationToken cancellationToken) |
There was a problem hiding this comment.
renamed this for clarity. 'Find' was a little vague. i think 'DescendInheritanceTree' gives more of an intuition about what is going on here.
| // Only classes/struct implement interface types. Derived interfaces can be found with | ||
| // FindDerivedInterfacesAsync. | ||
| return allTypes.WhereAsArray(t => t.TypeKind == TypeKind.Class || t.TypeKind == TypeKind.Struct); |
There was a problem hiding this comment.
Enums or delegates don't count? C# interactive says:
> enum E { A, B, C }
> E.A is IComparable
true
Although I could imagine there's some complicated conversion going on and it strictly not an implementation.
There was a problem hiding this comment.
Very interesting case! It will come down to: does the compiler model this in the .Interfaces list of the enum. if so, then i should find these. if not, then i think it's fine not to.
src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs
Show resolved
Hide resolved
src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs
Show resolved
Hide resolved
src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs
Show resolved
Hide resolved
| if (!(reference is PortableExecutableReference peReference)) | ||
| continue; |
There was a problem hiding this comment.
Why? I see AddMatchingMetadataTypesInMetadataReferenceAsync is requiring a PortableExecutableReference for the index, but if there's other types of references do we still need to process those without the index?
There was a problem hiding this comment.
Good question. The short answer is: no, there are no other types of refernces we need to process.
The long answer is:
There are effectively two types of references we ever care about "CompilationReference" and "PEReference". The latter is what we traditionally consider as a DLL, whereas the former is for a P2P reference. For the former, we're already processing the other projects higher up directly as we walk that project, so we don't want to walk again through the compilation reference.
| @@ -631,61 +521,37 @@ private static async Task FindImmediateMatchingMetadataTypesInMetadataReferenceA | |||
| // our criteria. | |||
There was a problem hiding this comment.
So it seems a bit funky to me that it seems like we lost the information in the index about how it was related and now we're trying to recover that information again. Was there a specific reason for that?
There was a problem hiding this comment.
great question! first, know that this is an index over metadata, and that index is built independent of that DLL's context in some containing project. THe way the index is built is to actually crack it open directly, read the tables and build information out of that. So the index doesn't store "this ISymbol derives from this other ISymbol", instead it stores "I remember that a type called 'FileStream' derived from a type called 'Stream'".
The goal of hte index was to be fast and lightweight and unencumbered from concerns like retargetting. Instead, it just stores basic data pulled out of the metadata tables in a lightweight fashion.
It's actually just like how the source-index works, just a little faster and more accurate because we can look at real md tokens.
| Solution solution, | ||
| IImmutableSet<Project> projects, | ||
| bool transitive, | ||
| CancellationToken cancellationToken) |
src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs
Show resolved
Hide resolved
| return ImmutableArray<ISymbol>.Empty; | ||
| var types = await DependentTypeFinder.FindAndCacheDerivedClassesAsync( | ||
| type, solution, projects, transitive, cancellationToken).ConfigureAwait(false); | ||
| return types.WhereAsArray(t => IsAccessible(t)); |
There was a problem hiding this comment.
Why is the accessibility check out here rather than inside the DependentTypeFinder code?
There was a problem hiding this comment.
that's a good question.... let me noodle on it. This maintains the semantics from before, but i think we could potentially safely move this down.
| /// Special comparer we need for our cache keys. Necessary because <see cref="IImmutableSet{T}"/> uses | ||
| /// reference equality and not value-equality semantics. |
There was a problem hiding this comment.
@CyrusNajmabadi ImmutableHashSet<T> uses EqualityComparer<T>.Default unless some other comparer has been specified.
There was a problem hiding this comment.
Can you point me to where you see that being done for testing if two sets are .equals? Note that this is not about the elements of the set themselves but about checking if the two entire sets are. Equals when used as part of a tuple.
|
@CyrusNajmabadi @jinujoseph Can we port this one to 16.7 Preview 1? Otherwise it will be a dogfood blocker for me and I'll be stuck on 16.6 until 16.7 Preview 2 is released. |
|
Sure, I can do that if @jinujoseph is ok with it |
|
@CyrusNajmabadi @sharwell Do you anticipate any risk with this change? |
|
Yes. There's definitely some risk here. This changes a bunch of core algorithms that many other features layer on top of. We have lots of testing, but risk is always there |
|
@CyrusNajmabadi let's keep in master then. |
Followup to #43593. That PR should go in first before this is reviewed.This is a precursor to moving these operations OOP.
This shoudl be reviewed one commit at a time.