22// The .NET Foundation licenses this file to you under the MIT license.
33// See the LICENSE file in the project root for more information.
44
5- using System . Collections . Generic ;
6- using System . Collections . Immutable ;
7- using System . Linq ;
8- using System . Runtime . ExceptionServices ;
95using System . Threading ;
106using System . Threading . Tasks ;
117using Microsoft . CodeAnalysis ;
128using Microsoft . CodeAnalysis . Editor . Shared . Utilities ;
13- using Microsoft . CodeAnalysis . FindSymbols ;
149using Microsoft . CodeAnalysis . NavigateTo ;
15- using Microsoft . CodeAnalysis . PooledObjects ;
16- using Microsoft . CodeAnalysis . Shared . Extensions ;
1710using Microsoft . CodeAnalysis . Shared . TestHooks ;
1811using Microsoft . VisualStudio . GraphModel ;
19- using Roslyn . Utilities ;
2012
2113namespace Microsoft . VisualStudio . LanguageServices . Implementation . Progression
2214{
@@ -36,16 +28,7 @@ public SearchGraphQuery(
3628 _searchPattern = searchPattern ;
3729 }
3830
39- public Task < GraphBuilder > GetGraphAsync ( Solution solution , IGraphContext context , CancellationToken cancellationToken )
40- {
41- var forceLegacySearch = solution . Options . GetOption ( ProgressionOptions . LegacySearchFeatureFlag ) ;
42- var option = solution . Options . GetOption ( ProgressionOptions . SearchUsingNavigateToEngine ) ;
43- return ! forceLegacySearch && option
44- ? SearchUsingNavigateToEngineAsync ( solution , context , cancellationToken )
45- : SearchUsingSymbolsAsync ( solution , context , cancellationToken ) ;
46- }
47-
48- private async Task < GraphBuilder > SearchUsingNavigateToEngineAsync ( Solution solution , IGraphContext context , CancellationToken cancellationToken )
31+ public async Task < GraphBuilder > GetGraphAsync ( Solution solution , IGraphContext context , CancellationToken cancellationToken )
4932 {
5033 var graphBuilder = await GraphBuilder . CreateForInputNodesAsync ( solution , context . InputNodes , cancellationToken ) . ConfigureAwait ( false ) ;
5134 var callback = new ProgressionNavigateToSearchCallback ( context , graphBuilder ) ;
@@ -62,171 +45,5 @@ private async Task<GraphBuilder> SearchUsingNavigateToEngineAsync(Solution solut
6245
6346 return graphBuilder ;
6447 }
65-
66- private async Task < GraphBuilder > SearchUsingSymbolsAsync ( Solution solution , IGraphContext context , CancellationToken cancellationToken )
67- {
68- var graphBuilder = await GraphBuilder . CreateForInputNodesAsync ( solution , context . InputNodes , cancellationToken ) . ConfigureAwait ( false ) ;
69-
70- var searchTasks = solution . Projects
71- . Where ( p => p . FilePath != null )
72- . Select ( p => ProcessProjectAsync ( p , graphBuilder , cancellationToken ) )
73- . ToArray ( ) ;
74- await Task . WhenAll ( searchTasks ) . ConfigureAwait ( false ) ;
75-
76- return graphBuilder ;
77- }
78-
79- private async Task ProcessProjectAsync ( Project project , GraphBuilder graphBuilder , CancellationToken cancellationToken )
80- {
81- var cacheService = project . Solution . Services . CacheService ;
82- if ( cacheService != null )
83- {
84- using ( cacheService . EnableCaching ( project . Id ) )
85- {
86- var results = await FindNavigableSourceSymbolsAsync ( project , cancellationToken ) . ConfigureAwait ( false ) ;
87-
88- foreach ( var symbol in results )
89- {
90- cancellationToken . ThrowIfCancellationRequested ( ) ;
91-
92- if ( symbol is INamedTypeSymbol namedType )
93- {
94- await AddLinkedNodeForTypeAsync (
95- project , namedType , graphBuilder ,
96- symbol . DeclaringSyntaxReferences . Select ( d => d . SyntaxTree ) ,
97- cancellationToken ) . ConfigureAwait ( false ) ;
98- }
99- else
100- {
101- await AddLinkedNodeForMemberAsync (
102- project , symbol , graphBuilder , cancellationToken ) . ConfigureAwait ( false ) ;
103- }
104- }
105- }
106- }
107- }
108-
109- private async Task < GraphNode > AddLinkedNodeForTypeAsync (
110- Project project , INamedTypeSymbol namedType , GraphBuilder graphBuilder ,
111- IEnumerable < SyntaxTree > syntaxTrees , CancellationToken cancellationToken )
112- {
113- // If this named type is contained in a parent type, then just link farther up
114- if ( namedType . ContainingType != null )
115- {
116- var parentTypeNode = await AddLinkedNodeForTypeAsync (
117- project , namedType . ContainingType , graphBuilder , syntaxTrees , cancellationToken ) . ConfigureAwait ( false ) ;
118- var typeNode = await graphBuilder . AddNodeAsync ( namedType , relatedNode : parentTypeNode , cancellationToken ) . ConfigureAwait ( false ) ;
119- graphBuilder . AddLink ( parentTypeNode , GraphCommonSchema . Contains , typeNode , cancellationToken ) ;
120-
121- return typeNode ;
122- }
123- else
124- {
125- // From here, we can link back up to the containing project item
126- var typeNode = await graphBuilder . AddNodeAsync (
127- namedType , contextProject : project , contextDocument : null , cancellationToken ) . ConfigureAwait ( false ) ;
128-
129- foreach ( var tree in syntaxTrees )
130- {
131- var document = project . Solution . GetDocument ( tree ) ;
132- Contract . ThrowIfNull ( document ) ;
133-
134- var documentNode = graphBuilder . AddNodeForDocument ( document , cancellationToken ) ;
135- graphBuilder . AddLink ( documentNode , GraphCommonSchema . Contains , typeNode , cancellationToken ) ;
136- }
137-
138- return typeNode ;
139- }
140- }
141-
142- private async Task < GraphNode > AddLinkedNodeForMemberAsync (
143- Project project , ISymbol symbol , GraphBuilder graphBuilder , CancellationToken cancellationToken )
144- {
145- var member = symbol ;
146- Contract . ThrowIfNull ( member . ContainingType ) ;
147-
148- var trees = member . DeclaringSyntaxReferences . Select ( d => d . SyntaxTree ) ;
149-
150- var parentTypeNode = await AddLinkedNodeForTypeAsync (
151- project , member . ContainingType , graphBuilder , trees , cancellationToken ) . ConfigureAwait ( false ) ;
152- var memberNode = await graphBuilder . AddNodeAsync (
153- symbol , relatedNode : parentTypeNode , cancellationToken ) . ConfigureAwait ( false ) ;
154- graphBuilder . AddLink ( parentTypeNode , GraphCommonSchema . Contains , memberNode , cancellationToken ) ;
155-
156- return memberNode ;
157- }
158-
159- internal async Task < ImmutableArray < ISymbol > > FindNavigableSourceSymbolsAsync (
160- Project project , CancellationToken cancellationToken )
161- {
162- ImmutableArray < ISymbol > declarations ;
163-
164- // FindSourceDeclarationsWithPatternAsync calls into OOP to do the search; if something goes badly it
165- // throws a SoftCrashException which inherits from OperationCanceledException. This is unfortunate, because
166- // it means that other bits of code see this as a cancellation and then may crash because they expect that if this
167- // method is raising cancellation, it's because cancellationToken requested the cancellation. The intent behind
168- // SoftCrashException was since it inherited from OperationCancelled it would make things safer, but in this case
169- // it's violating other invariants in the process which creates other problems.
170- //
171- // https://github.com/dotnet/roslyn/issues/40476 tracks removing SoftCrashException. When it is removed, the
172- // catch here can be removed and simply let the exception propagate; our Progression code is hardened to
173- // handle exceptions and report them gracefully.
174- try
175- {
176- declarations = await DeclarationFinder . FindSourceDeclarationsWithPatternAsync (
177- project , _searchPattern , SymbolFilter . TypeAndMember , cancellationToken ) . ConfigureAwait ( false ) ;
178- }
179- catch ( SoftCrashException ex ) when ( ex . InnerException != null )
180- {
181- ExceptionDispatchInfo . Capture ( ex . InnerException ) . Throw ( ) ;
182- throw ExceptionUtilities . Unreachable ;
183- }
184-
185- using var _ = ArrayBuilder < ISymbol > . GetInstance ( out var results ) ;
186-
187- foreach ( var declaration in declarations )
188- {
189- cancellationToken . ThrowIfCancellationRequested ( ) ;
190-
191- var symbol = declaration ;
192-
193- // Ignore constructors and namespaces. We don't want to expose them through this API.
194- if ( symbol . IsConstructor ( ) ||
195- symbol . IsStaticConstructor ( ) ||
196- symbol is INamespaceSymbol )
197- {
198- continue ;
199- }
200-
201- // Ignore symbols that have no source location. We don't want to expose them through this API.
202- if ( ! symbol . Locations . Any ( loc => loc . IsInSource ) )
203- {
204- continue ;
205- }
206-
207- results . Add ( declaration ) ;
208-
209- // also report matching constructors (using same match result as type)
210- if ( symbol is INamedTypeSymbol namedType )
211- {
212- foreach ( var constructor in namedType . Constructors )
213- {
214- // only constructors that were explicitly declared
215- if ( ! constructor . IsImplicitlyDeclared )
216- {
217- results . Add ( constructor ) ;
218- }
219- }
220- }
221-
222- // report both parts of partial methods
223- if ( symbol is IMethodSymbol method && method . PartialImplementationPart != null )
224- {
225- results . Add ( method ) ;
226- }
227- }
228-
229- return results . ToImmutable ( ) ;
230- }
23148 }
23249}
0 commit comments