Improve searching for symbols when a name is known ahead of time. (Including Compilation.GetEntryPoint())#26325
Conversation
|
Tagging @jcouv @dotnet/roslyn-compiler . #Resolved |
9bb9106 to
941b6ce
Compare
| /// <summary> | ||
| /// Return source declaration symbols whose name matches the provided name | ||
| /// </summary> | ||
| internal abstract IEnumerable<ISymbol> GetSymbolsWithName(string name, SymbolFilter filter = SymbolFilter.TypeAndMember, CancellationToken cancellationToken = default(CancellationToken)); |
There was a problem hiding this comment.
i woudl like to make this public. This would also be a valuable member for the FindReferencesEngine to have. Currently we have to call into the member above this which is quite expensive.
There was a problem hiding this comment.
I will do that in another PR though.
| } | ||
|
|
||
| private class SymbolSearcher | ||
| private abstract class AbstractSymbolSearcher |
There was a problem hiding this comment.
note: i would like to move these to sibling files. However, i didn't want to interfere with teh diff, so i kept them in this file for now. I'll move if that's what people would like, once this is reviewed. #Resolved
There was a problem hiding this comment.
I recommend doing the move in a separate iteration of this PR.
In reply to: 183247833 [](ancestors = 183247833)
There was a problem hiding this comment.
Sounds good. #Resolved
| { | ||
| continue; | ||
| } | ||
| } |
There was a problem hiding this comment.
this moved into MethodSymbol.IsEntryPointCandidate #Resolved
| Dim method = DirectCast(member, MethodSymbol) | ||
| ' check if this is an entry point | ||
| If Not method.IsSubmissionConstructor AndAlso _entryPointCandidates IsNot Nothing AndAlso Not method.IsImplicitlyDeclared AndAlso method.IsEntryPointCandidate Then | ||
| If _entryPointCandidates IsNot Nothing AndAlso method.IsEntryPointCandidate Then |
There was a problem hiding this comment.
the other checks moved into IsEntryPointCandidate. #Resolved
| Return True | ||
| End If | ||
| Next | ||
| Next |
There was a problem hiding this comment.
note: it's a pity we can't just do typeDecl.MemberNames.Contains(_name) However, MemberNames is just an array, and not a set with an appropriate comparer.
This means hte algorithm is O(n) with the number of member names to check. If we can actually use a set here, then we are only O(n) with the number of types to check. There are vastly less types than members, so that would be a substantive improvement.
There was a problem hiding this comment.
We could potentially replace that array with a SmallDictionary.Keys, but that could potentially have larger remifications. Personally, i don't htink it would be an issue, as this would be just one small change per TypeDeclaration, but it seemed out of scope of this PR. @VSadov for his thoughts here.
There was a problem hiding this comment.
Note: i was the original person who added MemberNames to the decl table. It was always intended, from the beginning, to be a fast way to check for existence of a member and/or to get that member quickly. I believe i started things out with a set, but it's so lost in the annals of time for me that i'm not sure. However, it does feel like this would be an easy tweak to make, with minimal issues, for the beneficial goal of speeding up these queries. Being able to just do simple O(1) lookup per type, instead of N checks would be very nice.
|
Very nice. LGTM #Resolved |
@gafter Unfortunately yes. It's used when the user supplies a class name, and is what finds the right method inside that class. That said, that's soooo narrow at this point, that it could be removed with the client just enumerating the methods of the class for an appropriate candidate. If you'd like, i can do that. Let me know. #Resolved |
|
@jcouv Can you take a look? #Resolved |
|
@gafter i removed the types as they served practically no purpose anymore. #Resolved |
|
@jcouv Thoughts? #Resolved |
|
Looking now #Resolved |
|
|
||
| protected override bool ShouldCheckTypeForMembers(MergedTypeDeclaration current) | ||
| { | ||
| foreach (var typeDecl in current.Declarations) |
There was a problem hiding this comment.
Could you type this var. Thanks #Closed
There was a problem hiding this comment.
Sure! #resolved #Resolved
| } | ||
| get | ||
| { | ||
| if (this.IsPartialDefinition() && |
There was a problem hiding this comment.
Is this already covered by test? #Closed
There was a problem hiding this comment.
Yes: ERR_NoEntryPoint_PartialClass (and siblings). #resolved #Resolved
| Assert.Throws<ArgumentException>(() => | ||
| { | ||
| var compilation = GetTestCompilation(); | ||
| compilation.GetSymbolsWithName("", SymbolFilter.None); |
There was a problem hiding this comment.
GetSymbolsWithName [](start = 28, length = 18)
I expect a similar case for ContainsSymbolsWithName (passing in a name, but SymbolFilter.None) #Closed
There was a problem hiding this comment.
will do. #Closed
There was a problem hiding this comment.
Done. #resolved #Closed
| private static void Test(CSharpCompilation compilation, string name, bool includeNamespace, bool includeType, bool includeMember, int count) | ||
| { | ||
| var filter = SymbolFilter.None; | ||
| filter = includeNamespace ? filter | SymbolFilter.Namespace : filter; |
There was a problem hiding this comment.
Consider parens for readability #Closed
There was a problem hiding this comment.
Done. #resolved.
| End Function | ||
|
|
||
| ''' <summary> | ||
| ''' Return true if there Is a source declaration symbol name that matches the provided name. |
There was a problem hiding this comment.
Is [](start = 33, length = 2)
Typo: Is from copy&paste (in a couple of places) #Closed
There was a problem hiding this comment.
#fixed. thanks! #Resolved
| ''' <returns>True if the method can be used as an entry point.</returns> | ||
| Friend ReadOnly Property IsEntryPointCandidate As Boolean | ||
| Get | ||
| If Me.ContainingType.IsEmbedded Then |
There was a problem hiding this comment.
Were those bugs? Do we have tests to cover? #Closed
There was a problem hiding this comment.
This was just code that was in the EntryPointWalker. I just moved it into this method so that the logic for entrypoitn consideration was localized into one single location. #Closed
|
|
||
| Assert.Throws(Of ArgumentException)(Sub() | ||
| Dim compilation = GetTestCompilation() | ||
| compilation.GetSymbolsWithName("", SymbolFilter.None) |
There was a problem hiding this comment.
Same here (test ContainsSymbolsWithName with None) #Closed
There was a problem hiding this comment.
sure #Closed
jcouv
left a comment
There was a problem hiding this comment.
Done with review pass (iteration 22).
Feels like some tests may be missing relative to change in entry point detection logic.
|
@jaredpar for approval to merge for 15.8. Thanks |
|
retest ubuntu_16_debug_prtest please |
|
approved |
…names searches. (#26331) Followup to #26325 and #26330. This PR updates the IDE to forward certain helpers to these more efficient implementations. This helps things out by more quickly being able to determine if a type even contains a member with name, and thus whether or not it should even be hydrated into a symbol and have its members created. Previous we would have to do a linear scan on all the members in a type to determine this. Now this data is in a set which can be queried much more efficiently.
Found as part of this review: #26316
@jcouv Would like to call compilation.GetEntryPoint inside an analyzer. However, this is currently very expensive as it will realize all namespace, type and member symbols in a compilation. We can improve things greatly here through use of the decl table. We only need to analyze types that actually contain a 'Main' member in them, vastly decreasing the amount of work and garbage that is necessary.
I've also decreased the cost of decl table searches. Avoiding linq, and other unnecessary allocations when we hit each decl.