@@ -34,13 +34,13 @@ protected override void ExecuteCore(RazorCodeDocument codeDocument)
34
34
35
35
document . Options = codeDocument . GetCodeGenerationOptions ( ) ?? _optionsFeature . GetOptions ( ) ;
36
36
37
- var namespaces = new Dictionary < string , SourceSpan ? > ( StringComparer . Ordinal ) ;
37
+ IReadOnlyList < UsingReference > importedUsings = Array . Empty < UsingReference > ( ) ;
38
38
39
39
// The import documents should be inserted logically before the main document.
40
40
var imports = codeDocument . GetImportSyntaxTrees ( ) ;
41
41
if ( imports != null )
42
42
{
43
- var importsVisitor = new ImportsVisitor ( document , builder , namespaces , syntaxTree . Options . FeatureFlags ) ;
43
+ var importsVisitor = new ImportsVisitor ( document , builder , syntaxTree . Options . FeatureFlags ) ;
44
44
45
45
for ( var j = 0 ; j < imports . Count ; j ++ )
46
46
{
@@ -49,26 +49,40 @@ protected override void ExecuteCore(RazorCodeDocument codeDocument)
49
49
importsVisitor . FilePath = import . Source . FilePath ;
50
50
importsVisitor . VisitBlock ( import . Root ) ;
51
51
}
52
+
53
+ importedUsings = importsVisitor . Usings ;
52
54
}
53
55
54
56
var tagHelperPrefix = tagHelperContext ? . Prefix ;
55
- var visitor = new MainSourceVisitor ( document , builder , namespaces , tagHelperPrefix , syntaxTree . Options . FeatureFlags )
57
+ var visitor = new MainSourceVisitor ( document , builder , tagHelperPrefix , syntaxTree . Options . FeatureFlags )
56
58
{
57
59
FilePath = syntaxTree . Source . FilePath ,
58
60
} ;
59
61
60
62
visitor . VisitBlock ( syntaxTree . Root ) ;
61
63
64
+ // 1. Prioritize non-imported usings over imported ones.
65
+ // 2. Don't import usings that already exist in primary document.
66
+ // 3. Allow duplicate usings in primary document (C# warning).
67
+ var usingReferences = new List < UsingReference > ( visitor . Usings ) ;
68
+ for ( var j = importedUsings . Count - 1 ; j >= 0 ; j -- )
69
+ {
70
+ if ( ! usingReferences . Contains ( importedUsings [ j ] ) )
71
+ {
72
+ usingReferences . Insert ( 0 , importedUsings [ j ] ) ;
73
+ }
74
+ }
75
+
62
76
// In each lowering piece above, namespaces were tracked. We render them here to ensure every
63
77
// lowering action has a chance to add a source location to a namespace. Ultimately, closest wins.
64
78
65
79
var i = 0 ;
66
- foreach ( var @namespace in namespaces )
80
+ foreach ( var reference in usingReferences )
67
81
{
68
82
var @using = new UsingDirectiveIntermediateNode ( )
69
83
{
70
- Content = @namespace . Key ,
71
- Source = @namespace . Value ,
84
+ Content = reference . Namespace ,
85
+ Source = reference . Source ,
72
86
} ;
73
87
74
88
builder . Insert ( i ++ , @using ) ;
@@ -147,21 +161,51 @@ private void ImportDirectives(DocumentIntermediateNode document)
147
161
}
148
162
}
149
163
164
+ private struct UsingReference : IEquatable < UsingReference >
165
+ {
166
+ public UsingReference ( string @namespace , SourceSpan ? source )
167
+ {
168
+ Namespace = @namespace ;
169
+ Source = source ;
170
+ }
171
+ public string Namespace { get ; }
172
+
173
+ public SourceSpan ? Source { get ; }
174
+
175
+ public override bool Equals ( object other )
176
+ {
177
+ if ( other is UsingReference reference )
178
+ {
179
+ return Equals ( reference ) ;
180
+ }
181
+
182
+ return false ;
183
+ }
184
+ public bool Equals ( UsingReference other )
185
+ {
186
+ return string . Equals ( Namespace , other . Namespace , StringComparison . Ordinal ) ;
187
+ }
188
+
189
+ public override int GetHashCode ( ) => Namespace . GetHashCode ( ) ;
190
+ }
191
+
150
192
private class LoweringVisitor : ParserVisitor
151
193
{
152
194
protected readonly IntermediateNodeBuilder _builder ;
153
195
protected readonly DocumentIntermediateNode _document ;
154
- protected readonly Dictionary < string , SourceSpan ? > _namespaces ;
196
+ protected readonly List < UsingReference > _usings ;
155
197
protected readonly RazorParserFeatureFlags _featureFlags ;
156
198
157
- public LoweringVisitor ( DocumentIntermediateNode document , IntermediateNodeBuilder builder , Dictionary < string , SourceSpan ? > namespaces , RazorParserFeatureFlags featureFlags )
199
+ public LoweringVisitor ( DocumentIntermediateNode document , IntermediateNodeBuilder builder , RazorParserFeatureFlags featureFlags )
158
200
{
159
201
_document = document ;
160
202
_builder = builder ;
161
- _namespaces = namespaces ;
203
+ _usings = new List < UsingReference > ( ) ;
162
204
_featureFlags = featureFlags ;
163
205
}
164
206
207
+ public IReadOnlyList < UsingReference > Usings => _usings ;
208
+
165
209
public string FilePath { get ; set ; }
166
210
167
211
public override void VisitDirectiveToken ( DirectiveTokenChunkGenerator chunkGenerator , Span span )
@@ -212,7 +256,7 @@ public override void VisitImportSpan(AddImportChunkGenerator chunkGenerator, Spa
212
256
{
213
257
var namespaceImport = chunkGenerator . Namespace . Trim ( ) ;
214
258
var namespaceSpan = BuildSourceSpanFromNode ( span ) ;
215
- _namespaces [ namespaceImport ] = namespaceSpan ;
259
+ _usings . Add ( new UsingReference ( namespaceImport , namespaceSpan ) ) ;
216
260
}
217
261
218
262
public override void VisitAddTagHelperSpan ( AddTagHelperChunkGenerator chunkGenerator , Span span )
@@ -353,8 +397,8 @@ private class MainSourceVisitor : LoweringVisitor
353
397
{
354
398
private readonly string _tagHelperPrefix ;
355
399
356
- public MainSourceVisitor ( DocumentIntermediateNode document , IntermediateNodeBuilder builder , Dictionary < string , SourceSpan ? > namespaces , string tagHelperPrefix , RazorParserFeatureFlags featureFlags )
357
- : base ( document , builder , namespaces , featureFlags )
400
+ public MainSourceVisitor ( DocumentIntermediateNode document , IntermediateNodeBuilder builder , string tagHelperPrefix , RazorParserFeatureFlags featureFlags )
401
+ : base ( document , builder , featureFlags )
358
402
{
359
403
_tagHelperPrefix = tagHelperPrefix ;
360
404
}
@@ -731,8 +775,8 @@ private void AddTagHelperAttributes(IList<TagHelperAttributeNode> attributes, Ta
731
775
732
776
private class ImportsVisitor : LoweringVisitor
733
777
{
734
- public ImportsVisitor ( DocumentIntermediateNode document , IntermediateNodeBuilder builder , Dictionary < string , SourceSpan ? > namespaces , RazorParserFeatureFlags featureFlags )
735
- : base ( document , new ImportBuilder ( builder ) , namespaces , featureFlags )
778
+ public ImportsVisitor ( DocumentIntermediateNode document , IntermediateNodeBuilder builder , RazorParserFeatureFlags featureFlags )
779
+ : base ( document , new ImportBuilder ( builder ) , featureFlags )
736
780
{
737
781
}
738
782
0 commit comments