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 ;
65using System . Collections . Immutable ;
7- using Roslyn . Utilities ;
86
97namespace Microsoft . CodeAnalysis ;
108
@@ -19,21 +17,16 @@ public sealed override void Create(INamedTypeSymbol symbol, SymbolKeyWriter visi
1917 visitor . WriteSymbolKey ( symbol . ContainingSymbol ) ;
2018 visitor . WriteString ( symbol . Name ) ;
2119 visitor . WriteInteger ( symbol . Arity ) ;
22- visitor . WriteString ( symbol . IsFileLocal
23- ? symbol . DeclaringSyntaxReferences [ 0 ] . SyntaxTree . FilePath
24- : null ) ;
20+ // Include the metadata name for extensions. We need this to uniquely find it when resolving.
21+ visitor . WriteString ( symbol . IsExtension ? symbol . MetadataName : null ) ;
22+ // Include the file path for 'file-local' types. We need this to uniquely find it when resolving.
23+ visitor . WriteString ( symbol . IsFileLocal ? symbol . DeclaringSyntaxReferences [ 0 ] . SyntaxTree . FilePath : null ) ;
2524 visitor . WriteBoolean ( symbol . IsUnboundGenericType ) ;
2625 visitor . WriteBoolean ( symbol . IsNativeIntegerType ) ;
2726 visitor . WriteBoolean ( symbol . SpecialType == SpecialType . System_IntPtr ) ;
2827
29- if ( ! symbol . Equals ( symbol . ConstructedFrom ) && ! symbol . IsUnboundGenericType )
30- {
31- visitor . WriteSymbolKeyArray ( symbol . TypeArguments ) ;
32- }
33- else
34- {
35- visitor . WriteSymbolKeyArray ( ImmutableArray < ITypeSymbol > . Empty ) ;
36- }
28+ visitor . WriteSymbolKeyArray (
29+ symbol . Equals ( symbol . ConstructedFrom ) || symbol . IsUnboundGenericType ? [ ] : symbol. TypeArguments ) ;
3730 }
3831
3932 protected sealed override SymbolKeyResolution Resolve (
@@ -42,6 +35,7 @@ protected sealed override SymbolKeyResolution Resolve(
4235 var containingSymbolResolution = reader . ReadSymbolKey ( contextualSymbol ? . ContainingSymbol , out var containingSymbolFailureReason ) ;
4336 var name = reader . ReadRequiredString ( ) ;
4437 var arity = reader . ReadInteger ( ) ;
38+ var extensionMetadataName = reader . ReadString ( ) ;
4539 var filePath = reader . ReadString ( ) ;
4640 var isUnboundGenericType = reader . ReadBoolean ( ) ;
4741 var isNativeIntegerType = reader . ReadBoolean ( ) ;
@@ -73,7 +67,8 @@ protected sealed override SymbolKeyResolution Resolve(
7367
7468 var normalResolution = ResolveNormalNamedType (
7569 containingSymbolResolution , containingSymbolFailureReason ,
76- name , arity , filePath , isUnboundGenericType , typeArgumentsArray ,
70+ name , extensionMetadataName , arity , filePath ,
71+ isUnboundGenericType , typeArgumentsArray ,
7772 out failureReason ) ;
7873
7974 if ( normalResolution . SymbolCount > 0 )
@@ -140,10 +135,11 @@ private static SymbolKeyResolution ResolveNormalNamedType(
140135 SymbolKeyResolution containingSymbolResolution ,
141136 string ? containingSymbolFailureReason ,
142137 string name ,
138+ string ? extensionMetadataName ,
143139 int arity ,
144140 string ? filePath ,
145141 bool isUnboundGenericType ,
146- ITypeSymbol [ ] typeArgumentsArray ,
142+ ITypeSymbol [ ] typeArguments ,
147143 out string ? failureReason )
148144 {
149145 if ( containingSymbolFailureReason != null )
@@ -154,43 +150,46 @@ private static SymbolKeyResolution ResolveNormalNamedType(
154150
155151 using var result = PooledArrayBuilder < INamedTypeSymbol > . GetInstance ( ) ;
156152 foreach ( var nsOrType in containingSymbolResolution . OfType < INamespaceOrTypeSymbol > ( ) )
157- {
158- Resolve (
159- result , nsOrType , name , arity , filePath ,
160- isUnboundGenericType , typeArgumentsArray ) ;
161- }
153+ Resolve ( nsOrType , result ) ;
162154
163155 return CreateResolution ( result , $ "({ nameof ( NamedTypeSymbolKey ) } failed)", out failureReason ) ;
164- }
165156
166- private static void Resolve (
167- PooledArrayBuilder < INamedTypeSymbol > result ,
168- INamespaceOrTypeSymbol container ,
169- string name ,
170- int arity ,
171- string ? filePath ,
172- bool isUnboundGenericType ,
173- ITypeSymbol [ ] typeArguments )
174- {
175- foreach ( var type in container . GetTypeMembers ( name , arity ) )
157+ void Resolve (
158+ INamespaceOrTypeSymbol container ,
159+ PooledArrayBuilder < INamedTypeSymbol > result )
176160 {
177- // if this is a file-local type, then only resolve to a file-local type from this same file
178- if ( filePath != null )
161+ if ( extensionMetadataName != null )
179162 {
180- if ( ! type . IsFileLocal ||
181- // note: if we found 'IsFile' returned true, we can assume DeclaringSyntaxReferences is non-empty.
182- type . DeclaringSyntaxReferences [ 0 ] . SyntaxTree . FilePath != filePath )
163+ // Unfortunately, no fast index from metadata name to type, so we have to iterate all nested types.
164+ foreach ( var type in container . GetTypeMembers ( ) )
183165 {
184- continue ;
166+ if ( type . MetadataName == extensionMetadataName )
167+ result . AddIfNotNull ( Construct ( type , isUnboundGenericType , typeArguments ) ) ;
185168 }
186169 }
187- else if ( type . IsFileLocal )
170+ else
188171 {
189- // since this key lacks a file path it can't match against a file-local type
190- continue ;
172+ foreach ( var type in container . GetTypeMembers ( name , arity ) )
173+ {
174+ // if this is a file-local type, then only resolve to a file-local type from this same file
175+ if ( filePath != null )
176+ {
177+ if ( ! type . IsFileLocal ||
178+ // note: if we found 'IsFile' returned true, we can assume DeclaringSyntaxReferences is non-empty.
179+ type . DeclaringSyntaxReferences [ 0 ] . SyntaxTree . FilePath != filePath )
180+ {
181+ continue ;
182+ }
183+ }
184+ else if ( type . IsFileLocal )
185+ {
186+ // since this key lacks a file path it can't match against a file-local type
187+ continue ;
188+ }
189+
190+ result . AddIfNotNull ( Construct ( type , isUnboundGenericType , typeArguments ) ) ;
191+ }
191192 }
192-
193- result . AddIfNotNull ( Construct ( type , isUnboundGenericType , typeArguments ) ) ;
194193 }
195194 }
196195
0 commit comments