1
1
// Copyright (c) .NET Foundation. All rights reserved.
2
- // Licensed under the MIT license. See License.txt in the project root for license information.
2
+ // Licensed under the MIT license. See License.txt in the project divNode for license information.
3
3
4
4
using System ;
5
5
using System . Collections . Generic ;
17
17
using Microsoft . AspNetCore . Razor . Language . Syntax ;
18
18
using Microsoft . AspNetCore . Razor . LanguageServer . CodeActions . Models ;
19
19
using Microsoft . AspNetCore . Razor . Threading ;
20
+ using Microsoft . CodeAnalysis . CSharp . Syntax ;
20
21
using Microsoft . CodeAnalysis . Razor . Logging ;
21
22
using Microsoft . CodeAnalysis . Razor . Workspaces ;
22
23
using Microsoft . CodeAnalysis . Text ;
@@ -58,25 +59,30 @@ public Task<ImmutableArray<RazorVSInternalCodeAction>> ProvideAsync(RazorCodeAct
58
59
return SpecializedTasks . EmptyImmutableArray < RazorVSInternalCodeAction > ( ) ;
59
60
}
60
61
62
+ if ( endElementNode is null )
63
+ {
64
+ endElementNode = startElementNode ;
65
+ }
66
+
61
67
if ( ! TryGetNamespace ( context . CodeDocument , out var @namespace ) )
62
68
{
63
69
return SpecializedTasks . EmptyImmutableArray < RazorVSInternalCodeAction > ( ) ;
64
70
}
65
71
66
- var actionParams = CreateInitialActionParams ( context , startElementNode , @namespace ) ;
67
-
68
- var dependencyScanRoot = FindNearestCommonAncestor ( startElementNode , endElementNode ) ;
69
-
70
- AddComponentDependenciesInRange ( dependencyScanRoot ,
71
- actionParams . ExtractStart ,
72
- actionParams . ExtractEnd ,
73
- actionParams ) ;
72
+ var actionParams = CreateInitialActionParams ( context , startElementNode , @namespace ) ;
74
73
75
74
if ( IsMultiPointSelection ( context . Request . Range ) )
76
75
{
77
76
ProcessMultiPointSelection ( startElementNode , endElementNode , actionParams ) ;
78
77
}
79
78
79
+ var utilityScanRoot = FindNearestCommonAncestor ( startElementNode , endElementNode ) ?? startElementNode ;
80
+ AddComponentDependenciesInRange ( utilityScanRoot ,
81
+ actionParams . ExtractStart ,
82
+ actionParams . ExtractEnd ,
83
+ actionParams ) ;
84
+ GetUsedIdentifiers ( utilityScanRoot , syntaxTree . Root , actionParams ) ;
85
+
80
86
var resolutionParams = new RazorCodeActionResolutionParams ( )
81
87
{
82
88
Action = LanguageServerConstants . CodeActions . ExtractToNewComponentAction ,
@@ -105,8 +111,6 @@ private static (MarkupElementSyntax? Start, MarkupElementSyntax? End) GetStartAn
105
111
106
112
var endElementNode = GetEndElementNode ( context , syntaxTree , logger ) ;
107
113
108
- endElementNode ??= startElementNode ;
109
-
110
114
return ( startElementNode , endElementNode ) ;
111
115
}
112
116
@@ -144,7 +148,7 @@ private static bool IsInsideProperHtmlContent(RazorCodeActionContext context, Ma
144
148
return null ;
145
149
}
146
150
147
- // Correct selection to include the current node if the selection ends immediately after a closing tag.
151
+ // Correct selection to include the current node if the selection ends at the "edge" (i.e. immediately after the ">") of a tag.
148
152
if ( string . IsNullOrWhiteSpace ( endOwner . ToFullString ( ) ) && endOwner . TryGetPreviousSibling ( out var previousSibling ) )
149
153
{
150
154
endOwner = previousSibling ;
@@ -161,7 +165,9 @@ private static ExtractToNewComponentCodeActionParams CreateInitialActionParams(R
161
165
ExtractStart = startElementNode . Span . Start ,
162
166
ExtractEnd = startElementNode . Span . End ,
163
167
Namespace = @namespace ,
164
- Dependencies = [ ]
168
+ Dependencies = [ ] ,
169
+ UsedIdentifiers = [ ] ,
170
+ UsedMembers = [ ] ,
165
171
} ;
166
172
}
167
173
@@ -236,7 +242,7 @@ private static (SyntaxNode? Start, SyntaxNode? End) FindContainingSiblingPair(Sy
236
242
{
237
243
// Find the lowest common ancestor of both nodes
238
244
var nearestCommonAncestor = FindNearestCommonAncestor ( startNode , endNode ) ;
239
- if ( nearestCommonAncestor == null )
245
+ if ( nearestCommonAncestor is null )
240
246
{
241
247
return ( null , null ) ;
242
248
}
@@ -248,11 +254,11 @@ private static (SyntaxNode? Start, SyntaxNode? End) FindContainingSiblingPair(Sy
248
254
var startSpan = startNode . Span ;
249
255
var endSpan = endNode . Span ;
250
256
251
- foreach ( var child in nearestCommonAncestor . ChildNodes ( ) . Where ( node => node . Kind == SyntaxKind . MarkupElement ) )
257
+ foreach ( var child in nearestCommonAncestor . ChildNodes ( ) . Where ( node => node is MarkupElementSyntax ) )
252
258
{
253
259
var childSpan = child . Span ;
254
260
255
- if ( startContainingNode == null && childSpan . Contains ( startSpan ) )
261
+ if ( startContainingNode is null && childSpan . Contains ( startSpan ) )
256
262
{
257
263
startContainingNode = child ;
258
264
if ( endContainingNode is not null )
@@ -274,7 +280,7 @@ private static (SyntaxNode? Start, SyntaxNode? End) FindContainingSiblingPair(Sy
274
280
{
275
281
var current = node1 ;
276
282
277
- while ( current . Kind == SyntaxKind . MarkupElement && current is not null )
283
+ while ( current is MarkupElementSyntax && current is not null )
278
284
{
279
285
if ( current . Span . Contains ( node2 . Span ) )
280
286
{
@@ -297,7 +303,7 @@ private static void AddComponentDependenciesInRange(SyntaxNode root, int extract
297
303
if ( IsMarkupTagHelperElement ( node , extractSpan ) )
298
304
{
299
305
var tagHelperInfo = GetTagHelperInfo ( node ) ;
300
- if ( tagHelperInfo != null )
306
+ if ( tagHelperInfo is not null )
301
307
{
302
308
AddDependenciesFromTagHelperInfo ( tagHelperInfo , components , actionParams ) ;
303
309
}
@@ -325,7 +331,7 @@ private static void AddDependenciesFromTagHelperInfo(TagHelperInfo tagHelperInfo
325
331
{
326
332
foreach ( var descriptor in tagHelperInfo . BindingResult . Descriptors )
327
333
{
328
- if ( descriptor != null )
334
+ if ( descriptor is not null )
329
335
{
330
336
foreach ( var metadata in descriptor . Metadata )
331
337
{
@@ -340,4 +346,27 @@ metadata.Value is not null &&
340
346
}
341
347
}
342
348
}
349
+
350
+ private static void GetUsedIdentifiers ( SyntaxNode divNode , SyntaxNode documentRoot , ExtractToNewComponentCodeActionParams actionParams )
351
+ {
352
+ HashSet < string > identifiersInScope = [ ] ;
353
+ HashSet < string > identifiersInBlock = [ ] ;
354
+
355
+
356
+ foreach ( var node in divNode . DescendantNodes ( ) . Where ( static node => node . Kind is SyntaxKind . Identifier ) )
357
+ {
358
+ identifiersInScope . Add ( node . GetContent ( ) ) ;
359
+ }
360
+
361
+ foreach ( var codeBlock in documentRoot . DescendantNodes ( ) . Where ( static node => node . Kind is SyntaxKind . RazorDirective ) )
362
+ {
363
+ foreach ( var node in codeBlock . DescendantNodes ( ) . Where ( static node => node . Kind is SyntaxKind . Identifier ) )
364
+ {
365
+ identifiersInBlock . Add ( node . GetContent ( ) ) ;
366
+ }
367
+ }
368
+
369
+ identifiersInBlock . IntersectWith ( identifiersInScope ) ;
370
+ actionParams . UsedIdentifiers = identifiersInBlock ;
371
+ }
343
372
}
0 commit comments