Skip to content

Commit 3d9a8ac

Browse files
committed
File types emit
1 parent 01e5dc6 commit 3d9a8ac

File tree

24 files changed

+627
-69
lines changed

24 files changed

+627
-69
lines changed

src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2493,7 +2493,8 @@ protected AssemblySymbol GetForwardedToAssembly(string name, int arity, ref Name
24932493

24942494
// NOTE: This won't work if the type isn't using CLS-style generic naming (i.e. `arity), but this code is
24952495
// only intended to improve diagnostic messages, so false negatives in corner cases aren't a big deal.
2496-
var metadataName = MetadataHelpers.ComposeAritySuffixedMetadataName(name, arity);
2496+
// File types can't be forwarded, so we won't attempt to determine a file identifier to attach to the metadata name.
2497+
var metadataName = MetadataHelpers.ComposeAritySuffixedMetadataName(name, arity, associatedFileIdentifier: null);
24972498
var fullMetadataName = MetadataHelpers.BuildQualifiedName(qualifierOpt?.ToDisplayString(SymbolDisplayFormat.QualifiedNameOnlyFormat), metadataName);
24982499
var result = GetForwardedToAssembly(fullMetadataName, diagnostics, location);
24992500
if ((object)result != null)

src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeReference.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ bool Cci.INamedTypeReference.MangleName
4040
}
4141
}
4242

43+
#nullable enable
44+
string? Cci.INamedTypeReference.AssociatedFileIdentifier
45+
{
46+
get
47+
{
48+
return UnderlyingNamedType.AssociatedFileIdentifier();
49+
}
50+
}
51+
#nullable disable
52+
4353
string Cci.INamedEntity.Name
4454
{
4555
get

src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,16 @@ bool Cci.INamedTypeReference.MangleName
756756
}
757757
}
758758

759+
#nullable enable
760+
string? Cci.INamedTypeReference.AssociatedFileIdentifier
761+
{
762+
get
763+
{
764+
return AdaptedNamedTypeSymbol.AssociatedFileIdentifier();
765+
}
766+
}
767+
#nullable disable
768+
759769
string Cci.INamedEntity.Name
760770
{
761771
get

src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,11 @@ public override void VisitNamedType(INamedTypeSymbol symbol)
182182
AddNullableAnnotations(symbol);
183183

184184
if ((format.CompilerInternalOptions & SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes) != 0
185-
// PROTOTYPE(ft): public API?
186-
&& symbol.GetSymbol() is SourceMemberContainerTypeSymbol { IsFile: true } fileType)
185+
&& symbol.GetSymbol() is SourceMemberContainerTypeSymbol { AssociatedSyntaxTree: SyntaxTree tree } internalSymbol)
187186
{
188-
var tree = symbol.DeclaringSyntaxReferences[0].SyntaxTree;
189-
var fileDescription = tree.FilePath is { Length: not 0 } path
190-
? Path.GetFileNameWithoutExtension(path)
191-
: $"<tree {fileType.DeclaringCompilation.SyntaxTrees.IndexOf(tree)}>";
187+
var fileDescription = tree.GetDisplayFileName() is { Length: not 0 } path
188+
? path
189+
: $"<tree {internalSymbol.DeclaringCompilation.SyntaxTrees.IndexOf(tree)}>";
192190

193191
builder.Add(CreatePart(SymbolDisplayPartKind.Punctuation, symbol, "@"));
194192
builder.Add(CreatePart(SymbolDisplayPartKind.ModuleName, symbol, fileDescription));

src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,14 +478,15 @@ public virtual bool IsImplicitClass
478478
/// </summary>
479479
public abstract override string Name { get; }
480480

481+
#nullable enable
481482
/// <summary>
482483
/// Return the name including the metadata arity suffix.
483484
/// </summary>
484485
public override string MetadataName
485486
{
486487
get
487488
{
488-
return MangleName ? MetadataHelpers.ComposeAritySuffixedMetadataName(Name, Arity) : Name;
489+
return MangleName ? MetadataHelpers.ComposeAritySuffixedMetadataName(Name, Arity, this.AssociatedFileIdentifier()) : Name;
489490
}
490491
}
491492

@@ -498,6 +499,7 @@ internal abstract bool MangleName
498499
// Intentionally no default implementation to force consideration of appropriate implementation for each new subclass
499500
get;
500501
}
502+
#nullable disable
501503

502504
/// <summary>
503505
/// Collection of names of members declared within this type. May return duplicates.

src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ internal override bool MangleName
932932
{
933933
get
934934
{
935-
return Arity > 0;
935+
return Arity > 0 || IsFile;
936936
}
937937
}
938938

src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ internal enum GeneratedNameKind
3030
ReusableHoistedLocalField = '7',
3131
LambdaCacheField = '9',
3232
FixedBufferField = 'e',
33+
FileType = 'F',
3334
AnonymousType = 'f',
3435
TransparentIdentifier = 'h',
3536
AnonymousTypeField = 'i',

src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Collections.Immutable;
88
using System.Diagnostics;
99
using System.Diagnostics.CodeAnalysis;
10+
using System.Text;
1011
using Microsoft.CodeAnalysis.PooledObjects;
1112
using Roslyn.Utilities;
1213

@@ -1361,6 +1362,64 @@ public static bool IsFileTypeOrUsesFileTypes(this TypeSymbol type)
13611362
return foundType is not null;
13621363
}
13631364

1365+
internal static string? AssociatedFileIdentifier(this NamedTypeSymbol type)
1366+
{
1367+
if (type is not SourceMemberContainerTypeSymbol { AssociatedSyntaxTree: SyntaxTree tree })
1368+
{
1369+
return null;
1370+
}
1371+
var ordinal = type.DeclaringCompilation.GetSyntaxTreeOrdinal(tree);
1372+
1373+
var pooledBuilder = PooledStringBuilder.GetInstance();
1374+
var sb = pooledBuilder.Builder;
1375+
sb.Append('<');
1376+
AppendFileName(tree, sb);
1377+
sb.Append('>');
1378+
sb.Append((char)GeneratedNameKind.FileType);
1379+
sb.Append(ordinal);
1380+
sb.Append("__");
1381+
return pooledBuilder.ToStringAndFree();
1382+
}
1383+
1384+
internal static string GetDisplayFileName(this SyntaxTree tree)
1385+
{
1386+
var pooledBuilder = PooledStringBuilder.GetInstance();
1387+
var sb = pooledBuilder.Builder;
1388+
AppendFileName(tree, sb);
1389+
return pooledBuilder.ToStringAndFree();
1390+
}
1391+
1392+
private static void AppendFileName(SyntaxTree tree, StringBuilder sb)
1393+
{
1394+
// note: a "file path" for a syntax tree can be basically any string.
1395+
// since methods like Path.GetFileNameWithoutExtension throw when invalid path characters are found,
1396+
// we implement more of a heuristic here.
1397+
var originalFilePath = tree.FilePath;
1398+
var fileNameStartIndex = Math.Max(originalFilePath.LastIndexOf('/'), originalFilePath.LastIndexOf('\\')) + 1;
1399+
var fileNameEndIndex = originalFilePath.LastIndexOf('.');
1400+
if (fileNameEndIndex < fileNameStartIndex)
1401+
{
1402+
fileNameEndIndex = originalFilePath.Length;
1403+
}
1404+
1405+
for (int i = fileNameStartIndex; i < fileNameEndIndex; i++)
1406+
{
1407+
var ch = originalFilePath[i];
1408+
switch (ch)
1409+
{
1410+
case '_':
1411+
case >= 'a' and <= 'z':
1412+
case >= 'A' and <= 'Z':
1413+
case >= '0' and <= '9':
1414+
sb.Append(ch);
1415+
break;
1416+
default:
1417+
sb.Append('_');
1418+
break;
1419+
}
1420+
}
1421+
}
1422+
13641423
public static bool IsPointerType(this TypeSymbol type)
13651424
{
13661425
return type is PointerTypeSymbol;

0 commit comments

Comments
 (0)