Skip to content

Commit

Permalink
Bind native integers in cref
Browse files Browse the repository at this point in the history
  • Loading branch information
jcouv committed May 20, 2022
1 parent 18da795 commit 4985e9d
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 4 deletions.
20 changes: 16 additions & 4 deletions src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -327,14 +327,15 @@ private ImmutableArray<Symbol> BindConversionOperatorMemberCref(ConversionOperat
private ImmutableArray<Symbol> ComputeSortedCrefMembers(CSharpSyntaxNode syntax, NamespaceOrTypeSymbol? containerOpt, string memberName, 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, 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, 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 @@ -349,8 +350,19 @@ private ImmutableArray<Symbol> ComputeSortedCrefMembers(NamespaceOrTypeSymbol? c
diagnose: false,
useSiteInfo: ref useSiteInfo);

if (memberName is "nint" or "nuint"
&& containerOpt is null
&& arity == 0
&& !hasParameterList
&& !IsViableType(result))
{
result.Free(); // Won't be using this.
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());
}
// CONSIDER: Dev11 also checks for a constructor in the event of an ambiguous result.
if (result.IsMultiViable)
else if (result.IsMultiViable)
{
// Dev11 doesn't consider members from System.Object when the container is an interface.
// Lookup should already have dropped such members.
Expand Down
48 changes: 48 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,54 @@ 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());
}

private void VerifyNoNativeIntegerAttributeEmitted(CSharpCompilation comp)
{
// PEVerify is skipped because it reports "Type load failed" because of the above corlib,
Expand Down
123 changes: 123 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14813,5 +14813,128 @@ public static void M10(IntPtr{{s1Nullable}} x) { }

CompileAndVerify(comp, expectedOutput: "M1 M2 M3 M4 M5 M6 M7 M8 M9 M10");
}

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

var comp = CreateCompilation(src, 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_IntPtr()
{
var src = """
/// <summary>Summary <see cref="System.IntPtr"/>.</summary>
class C { }
""";

var comp = CreateCompilation(src, 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("System.IntPtr", cref.ToString());

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

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

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

var comp = CreateCompilation(src, 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());
}

[Fact]
public void XmlDoc_Cref_NamedType()
{
var src = """
interface @nint { }

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

var comp = CreateCompilation(src, 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("nint", symbol.ToTestDisplayString());
Assert.Equal(TypeKind.Interface, symbol.TypeKind);
}

[Fact]
public void XmlDoc_Cref_TypeParameter()
{
var src = """
struct Outer<@nint>
{
/// <summary>Summary <see cref="nint"/>.</summary>
class C { }
}
""";

var comp = CreateCompilation(src, parseOptions: TestOptions.RegularWithDocumentationComments);
comp.VerifyDiagnostics(
// (3,37): warning CS1723: XML comment has cref attribute 'nint' that refers to a type parameter
// /// <summary>Summary <see cref="nint"/>.</summary>
Diagnostic(ErrorCode.WRN_BadXMLRefTypeVar, "nint").WithArguments("nint").WithLocation(3, 37)
);

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 = (ITypeSymbol)model.GetSymbolInfo(cref).Symbol;
Assert.False(symbol.IsNativeIntegerType);
Assert.Equal("nint", symbol.ToTestDisplayString());
Assert.Equal(TypeKind.TypeParameter, symbol.TypeKind);
}
}
}

0 comments on commit 4985e9d

Please sign in to comment.