2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
// See the LICENSE file in the project root for more information.
4
4
5
+ using System ;
5
6
using System . Collections . Generic ;
6
7
using System . Text ;
8
+ using CommunityToolkit . Mvvm . SourceGenerators . Helpers ;
7
9
using Microsoft . CodeAnalysis ;
8
10
9
11
namespace CommunityToolkit . Mvvm . SourceGenerators . Extensions ;
@@ -20,27 +22,46 @@ internal static class INamedTypeSymbolExtensions
20
22
/// <returns>The full metadata name for <paramref name="symbol"/> that is also a valid filename.</returns>
21
23
public static string GetFullMetadataNameForFileName ( this INamedTypeSymbol symbol )
22
24
{
23
- static StringBuilder BuildFrom ( ISymbol ? symbol , StringBuilder builder )
25
+ using ImmutableArrayBuilder < char > builder = ImmutableArrayBuilder < char > . Rent ( ) ;
26
+
27
+ static void BuildFrom ( ISymbol ? symbol , in ImmutableArrayBuilder < char > builder )
24
28
{
25
- return symbol switch
29
+ switch ( symbol )
26
30
{
27
- INamespaceSymbol ns when ns . IsGlobalNamespace => builder ,
28
- INamespaceSymbol ns when ns . ContainingNamespace is { IsGlobalNamespace : false }
29
- => BuildFrom ( ns . ContainingNamespace , builder . Insert ( 0 , $ ".{ ns . MetadataName } ") ) ,
30
- ITypeSymbol ts when ts . ContainingType is ISymbol pt
31
- => BuildFrom ( pt , builder . Insert ( 0 , $ "+{ ts . MetadataName } ") ) ,
32
- ITypeSymbol ts when ts . ContainingNamespace is ISymbol pn and not INamespaceSymbol { IsGlobalNamespace : true }
33
- => BuildFrom ( pn , builder . Insert ( 0 , $ ".{ ts . MetadataName } ") ) ,
34
- ISymbol => BuildFrom ( symbol . ContainingSymbol , builder . Insert ( 0 , symbol . MetadataName ) ) ,
35
- _ => builder
36
- } ;
31
+ // Namespaces that are nested also append a leading '.'
32
+ case INamespaceSymbol { ContainingNamespace . IsGlobalNamespace : false } :
33
+ BuildFrom ( symbol . ContainingNamespace , in builder ) ;
34
+ builder . Add ( '.' ) ;
35
+ builder . AddRange ( symbol . MetadataName . AsSpan ( ) ) ;
36
+ break ;
37
+ // Other namespaces (ie. the one right before global) skip the leading '.'
38
+ case INamespaceSymbol { IsGlobalNamespace : false } :
39
+ builder . AddRange ( symbol . MetadataName . AsSpan ( ) ) ;
40
+ break ;
41
+ // Types with no namespace just have their metadata name directly written
42
+ case ITypeSymbol { ContainingSymbol : INamespaceSymbol { IsGlobalNamespace : true } } :
43
+ builder . AddRange ( symbol . MetadataName . AsSpan ( ) ) ;
44
+ break ;
45
+ // Types with a containing non-global namespace also append a leading '.'
46
+ case ITypeSymbol { ContainingSymbol : INamespaceSymbol namespaceSymbol } :
47
+ BuildFrom ( namespaceSymbol , in builder ) ;
48
+ builder . Add ( '.' ) ;
49
+ builder . AddRange ( symbol . MetadataName . AsSpan ( ) ) ;
50
+ break ;
51
+ // Nested types append a leading '+'
52
+ case ITypeSymbol { ContainingSymbol : ITypeSymbol typeSymbol } :
53
+ BuildFrom ( typeSymbol , in builder ) ;
54
+ builder . Add ( '+' ) ;
55
+ builder . AddRange ( symbol . MetadataName . AsSpan ( ) ) ;
56
+ break ;
57
+ default :
58
+ break ;
59
+ }
37
60
}
38
61
39
- // Build the full metadata name by concatenating the metadata names of all symbols from the input
40
- // one to the outermost namespace, if any. Additionally, the ` and + symbols need to be replaced
41
- // to avoid errors when generating code. This is a known issue with source generators not accepting
42
- // those characters at the moment, see: https://github.com/dotnet/roslyn/issues/58476.
43
- return BuildFrom ( symbol , new StringBuilder ( 256 ) ) . Replace ( '`' , '-' ) . Replace ( '+' , '.' ) . ToString ( ) ;
62
+ BuildFrom ( symbol , in builder ) ;
63
+
64
+ return builder . ToString ( ) ;
44
65
}
45
66
46
67
/// <summary>
0 commit comments