diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs index f2e60c705dba4..9cc3503e60bc2 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs @@ -327,14 +327,15 @@ private ImmutableArray BindConversionOperatorMemberCref(ConversionOperat private ImmutableArray ComputeSortedCrefMembers(CSharpSyntaxNode syntax, NamespaceOrTypeSymbol? containerOpt, string memberName, int arity, bool hasParameterList, BindingDiagnosticBag diagnostics) { CompoundUseSiteInfo 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 ComputeSortedCrefMembers(NamespaceOrTypeSymbol? containerOpt, string memberName, int arity, bool hasParameterList, ref CompoundUseSiteInfo useSiteInfo) + private ImmutableArray ComputeSortedCrefMembers(NamespaceOrTypeSymbol? containerOpt, string memberName, int arity, bool hasParameterList, + CSharpSyntaxNode syntax, BindingDiagnosticBag diagnostics, ref CompoundUseSiteInfo 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 builder; { @@ -349,8 +350,19 @@ private ImmutableArray 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.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. diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs index 0d3a25ea598aa..0f1da0c51cbfd 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs @@ -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 . +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(); + var cref = docComments.First().DescendantNodes().OfType().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 . +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(); + var cref = docComments.First().DescendantNodes().OfType().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, diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs index 316ec24ddb116..2006d03878f21 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs @@ -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 . +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(); + var cref = docComments.First().DescendantNodes().OfType().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 . +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(); + var cref = docComments.First().DescendantNodes().OfType().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 . +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(); + var cref = docComments.First().DescendantNodes().OfType().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 . +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(); + var cref = docComments.First().DescendantNodes().OfType().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 . + 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 . + 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(); + var cref = docComments.First().DescendantNodes().OfType().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); + } } }