Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bind native integers in cref #61431

Merged
merged 5 commits into from
May 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,13 @@ private ImmutableArray<Symbol> BindNameMemberCref(NameMemberCrefSyntax syntax, N

int arity;
string memberName;
string memberNameText;

if (nameSyntax != null)
{
arity = nameSyntax.Arity;
memberName = nameSyntax.Identifier.ValueText;
memberNameText = nameSyntax.Identifier.Text;
}
else
{
Expand All @@ -161,7 +163,7 @@ private ImmutableArray<Symbol> BindNameMemberCref(NameMemberCrefSyntax syntax, N
containerOpt = BindNamespaceOrTypeSymbolInCref(syntax.Name);

arity = 0;
memberName = WellKnownMemberNames.InstanceConstructorName;
memberName = memberNameText = WellKnownMemberNames.InstanceConstructorName;
}

if (string.IsNullOrEmpty(memberName))
Expand All @@ -170,7 +172,7 @@ private ImmutableArray<Symbol> BindNameMemberCref(NameMemberCrefSyntax syntax, N
return ImmutableArray<Symbol>.Empty;
}

ImmutableArray<Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, arity, syntax.Parameters != null, diagnostics);
ImmutableArray<Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, memberNameText, arity, syntax.Parameters != null, diagnostics);

if (sortedSymbols.IsEmpty)
{
Expand All @@ -192,7 +194,7 @@ private ImmutableArray<Symbol> BindIndexerMemberCref(IndexerMemberCrefSyntax syn
{
const int arity = 0;

ImmutableArray<Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, WellKnownMemberNames.Indexer, arity, syntax.Parameters != null, diagnostics);
ImmutableArray<Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, WellKnownMemberNames.Indexer, memberNameText: WellKnownMemberNames.Indexer, arity, syntax.Parameters != null, diagnostics);

if (sortedSymbols.IsEmpty)
{
Expand Down Expand Up @@ -240,7 +242,7 @@ private ImmutableArray<Symbol> BindOperatorMemberCref(OperatorMemberCrefSyntax s
return ImmutableArray<Symbol>.Empty;
}

ImmutableArray<Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, arity, syntax.Parameters != null, diagnostics);
ImmutableArray<Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, memberNameText: memberName, arity, syntax.Parameters != null, diagnostics);

if (sortedSymbols.IsEmpty)
{
Expand Down Expand Up @@ -286,7 +288,7 @@ private ImmutableArray<Symbol> BindConversionOperatorMemberCref(ConversionOperat
memberName = WellKnownMemberNames.ExplicitConversionName;
}

ImmutableArray<Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, arity, syntax.Parameters != null, diagnostics);
ImmutableArray<Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, memberNameText: memberName, arity, syntax.Parameters != null, diagnostics);

if (sortedSymbols.IsEmpty)
{
Expand Down Expand Up @@ -324,17 +326,18 @@ private ImmutableArray<Symbol> BindConversionOperatorMemberCref(ConversionOperat
/// <remarks>
/// Never returns null.
/// </remarks>
private ImmutableArray<Symbol> ComputeSortedCrefMembers(CSharpSyntaxNode syntax, NamespaceOrTypeSymbol? containerOpt, string memberName, int arity, bool hasParameterList, BindingDiagnosticBag diagnostics)
private ImmutableArray<Symbol> ComputeSortedCrefMembers(CSharpSyntaxNode syntax, NamespaceOrTypeSymbol? containerOpt, string memberName, string memberNameText, int arity, bool hasParameterList, BindingDiagnosticBag diagnostics)
{
CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics);
var result = ComputeSortedCrefMembers(containerOpt, memberName, arity, hasParameterList, ref useSiteInfo);
var result = ComputeSortedCrefMembers(containerOpt, memberName, memberNameText, arity, hasParameterList, syntax, diagnostics, ref useSiteInfo);
diagnostics.Add(syntax, useSiteInfo);
return result;
}

private ImmutableArray<Symbol> ComputeSortedCrefMembers(NamespaceOrTypeSymbol? containerOpt, string memberName, int arity, bool hasParameterList, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
private ImmutableArray<Symbol> ComputeSortedCrefMembers(NamespaceOrTypeSymbol? containerOpt, string memberName, string memberNameText, int arity, bool hasParameterList, CSharpSyntaxNode syntax,
BindingDiagnosticBag diagnostics, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
// Since we may find symbols without going through the lookup API,
// Since we may find symbols without going through the lookup API,
// expose the symbols via an ArrayBuilder.
ArrayBuilder<Symbol> builder;
{
Expand All @@ -358,6 +361,17 @@ private ImmutableArray<Symbol> ComputeSortedCrefMembers(NamespaceOrTypeSymbol? c
builder.AddRange(result.Symbols);
result.Free();
}
else if (memberNameText is "nint" or "nuint"
&& containerOpt is null
&& arity == 0
&& !hasParameterList)
{
result.Free(); // Won't be using this.
Debug.Assert(memberName == memberNameText);
CheckFeatureAvailability(syntax, MessageID.IDS_FeatureNativeInt, diagnostics);
builder = ArrayBuilder<Symbol>.GetInstance();
builder.Add(this.GetSpecialType(memberName == "nint" ? SpecialType.System_IntPtr : SpecialType.System_UIntPtr, diagnostics, syntax).AsNativeInteger());
}
else
{
result.Free(); // Won't be using this.
Expand Down
145 changes: 145 additions & 0 deletions src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10305,6 +10305,151 @@ public class C
comp.VerifyDiagnostics();
}

[Theory]
[InlineData("nint")]
[InlineData("nuint")]
[InlineData("System.IntPtr")]
[InlineData("System.UIntPtr")]
public void XmlDoc_Cref(string type)
{
var src = $$"""
/// <summary>Summary <see cref="{{type}}"/>.</summary>
class C { }
""";
var comp = CreateNumericIntPtrCompilation(src, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.RegularWithDocumentationComments);
comp.VerifyDiagnostics();

var tree = comp.SyntaxTrees.Single();
var docComments = tree.GetCompilationUnitRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType<DocumentationCommentTriviaSyntax>();
var cref = docComments.First().DescendantNodes().OfType<XmlCrefAttributeSyntax>().First().Cref;
Assert.Equal(type, cref.ToString());

var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
var nintSymbol = (INamedTypeSymbol)model.GetSymbolInfo(cref).Symbol;
Assert.True(nintSymbol.IsNativeIntegerType);
}

[Fact]
public void XmlDoc_Cref_Alias()
{
var src = """
using @nint = System.String;

/// <summary>Summary <see cref="nint"/>.</summary>
class C { }
""";

var comp = CreateNumericIntPtrCompilation(src, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.RegularWithDocumentationComments);
comp.VerifyDiagnostics();

var tree = comp.SyntaxTrees.Single();
var docComments = tree.GetCompilationUnitRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType<DocumentationCommentTriviaSyntax>();
var cref = docComments.First().DescendantNodes().OfType<XmlCrefAttributeSyntax>().First().Cref;
Assert.Equal("nint", cref.ToString());

var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
var symbol = (INamedTypeSymbol)model.GetSymbolInfo(cref).Symbol;
Assert.False(symbol.IsNativeIntegerType);
Assert.Equal("System.String", symbol.ToTestDisplayString());
}

[Theory]
[InlineData("nint")]
[InlineData("nuint")]
public void XmlDoc_Cref_Member(string fieldName)
{
var src = $$"""
/// <summary>Summary <see cref="{{fieldName}}"/>.</summary>
public class C
{
/// <summary></summary>
public int {{fieldName}};
}
""";

var comp = CreateNumericIntPtrCompilation(src, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.RegularWithDocumentationComments);
comp.VerifyDiagnostics();

var tree = comp.SyntaxTrees.Single();
var docComments = tree.GetCompilationUnitRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType<DocumentationCommentTriviaSyntax>();
var cref = docComments.First().DescendantNodes().OfType<XmlCrefAttributeSyntax>().First().Cref;
Assert.Equal(fieldName, cref.ToString());

var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
var symbol = (IFieldSymbol)model.GetSymbolInfo(cref).Symbol;
Assert.Equal($"System.Int32 C.{fieldName}", symbol.ToTestDisplayString());
}

[Fact]
public void XmlDoc_Cref_Member_Escaped()
Copy link
Contributor

@Neme12 Neme12 May 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be a good idea to make this a Theory and test nuint as well and verify that it does indeed correspond to
IntPtr vs UIntPtr. Right now it seems like this won't work because of an omission in the code. #Resolved

{
var src = """
/// <summary>Summary <see cref="@nint"/>.</summary>
public class C
{
/// <summary></summary>
public int nint;
}
""";

var comp = CreateNumericIntPtrCompilation(src, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.RegularWithDocumentationComments);
comp.VerifyDiagnostics();

var tree = comp.SyntaxTrees.Single();
var docComments = tree.GetCompilationUnitRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType<DocumentationCommentTriviaSyntax>();
var cref = docComments.First().DescendantNodes().OfType<XmlCrefAttributeSyntax>().First().Cref;
Assert.Equal("@nint", cref.ToString());

var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
var symbol = (IFieldSymbol)model.GetSymbolInfo(cref).Symbol;
Assert.Equal("System.Int32 C.nint", symbol.ToTestDisplayString());
}

[Theory]
[InlineData("@nint")]
[InlineData("@nuint")]
public void XmlDoc_Cref_Escaped(string type)
{
var src = $$"""
/// <summary>Summary <see cref="{{type}}"/>.</summary>
public class C
{
}
""";

var comp = CreateNumericIntPtrCompilation(src, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.RegularWithDocumentationComments);
comp.VerifyDiagnostics(
// (1,33): warning CS1574: XML comment has cref attribute 'type' that could not be resolved
// /// <summary>Summary <see cref="type"/>.</summary>
Diagnostic(ErrorCode.WRN_BadXMLRef, type).WithArguments(type).WithLocation(1, 33)
);
}

[Fact]
public void XmlDoc_Cref_Member_NintZero()
{
var src = """
/// <summary>Summary <see cref="nint.Zero"/>.</summary>
public class C
{
/// <summary></summary>
public int nint;
}
""";

var comp = CreateNumericIntPtrCompilation(src, references: new[] { MscorlibRefWithoutSharingCachedSymbols }, parseOptions: TestOptions.RegularWithDocumentationComments);
comp.VerifyDiagnostics();

var tree = comp.SyntaxTrees.Single();
var docComments = tree.GetCompilationUnitRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType<DocumentationCommentTriviaSyntax>();
var cref = docComments.First().DescendantNodes().OfType<XmlCrefAttributeSyntax>().First().Cref;
Assert.Equal("nint.Zero", cref.ToString());

var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
var symbol = (IFieldSymbol)model.GetSymbolInfo(cref).Symbol;
Assert.Equal("nint nint.Zero", symbol.ToTestDisplayString());
}

private void VerifyNoNativeIntegerAttributeEmitted(CSharpCompilation comp)
{
// PEVerify is skipped because it reports "Type load failed" because of the above corlib,
Expand Down
Loading