File: Symbols\DocumentationCommentIdTests.cs
Web Access
Project: src\src\Compilers\Core\CodeAnalysisTest\Microsoft.CodeAnalysis.UnitTests.csproj (Microsoft.CodeAnalysis.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Sdk;
 
namespace Microsoft.CodeAnalysis.UnitTests.Symbols
{
    public sealed class DocumentationCommentIdTests : CommonTestBase
    {
        private CSharpCompilation CreateCompilation(string code) =>
            CreateCSharpCompilation(
                code, referencedAssemblies: TargetFrameworkUtil.GetReferences(TargetFramework.NetStandard20));
 
        [Fact]
        public void TupleReturnMethod()
        {
            string code = @"
class C
{
    (int i, int) DoStuff() => default;
}";
 
            var comp = CreateCompilation(code);
            comp.VerifyDiagnostics();
 
            var symbol = comp.GetSymbolsWithName("DoStuff").Single();
 
            var actualDocId = DocumentationCommentId.CreateDeclarationId(symbol);
 
            string expectedDocId = "M:C.DoStuff~System.ValueTuple{System.Int32,System.Int32}";
 
            Assert.Equal(expectedDocId, actualDocId);
 
            var foundSymbols = DocumentationCommentId.GetSymbolsForDeclarationId(expectedDocId, comp);
 
            Assert.Equal(new[] { symbol }, foundSymbols);
        }
 
        [Theory]
        [InlineData(
            "void DoStuff((int i, int) tuple) {}",
            "M:C.DoStuff(System.ValueTuple{System.Int32,System.Int32})")]
        [InlineData(
            "void DoStuff((int, int, int, int, int, int, int, int, int) tuple) { }",
            "M:C.DoStuff(System.ValueTuple{System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.ValueTuple{System.Int32,System.Int32}})")]
        public void TupleParameterMethod(string methodCode, string expectedDocId)
        {
            string code = $@"
class C
{{
    {methodCode}
}}";
 
            var comp = CreateCompilation(code);
            comp.VerifyDiagnostics();
 
            var symbol = comp.GetSymbolsWithName("DoStuff").Single();
            var actualDocId = DocumentationCommentId.CreateDeclarationId(symbol);
            Assert.Equal(expectedDocId, actualDocId);
            var foundSymbols = DocumentationCommentId.GetSymbolsForDeclarationId(expectedDocId, comp);
 
            Assert.Equal(new[] { symbol }, foundSymbols);
        }
 
        [Fact]
        public void DynamicParameterMethod()
        {
            string code = @"
class C
{
    int DoStuff(dynamic dynamic) => 0;
}";
 
            var comp = CreateCSharpCompilation(code);
 
            var symbol = comp.GetSymbolsWithName("DoStuff").Single();
 
            var actualDocId = DocumentationCommentId.CreateDeclarationId(symbol);
 
            var expectedDocId = "M:C.DoStuff(System.Object)~System.Int32";
 
            Assert.Equal(expectedDocId, actualDocId);
 
            var foundSymbols = DocumentationCommentId.GetSymbolsForDeclarationId(expectedDocId, comp);
 
            Assert.Equal(new[] { symbol }, foundSymbols);
        }
 
        [Fact]
        public void NintParameterMethod()
        {
            string code = @"
class C
{
    void DoStuff(nint nint) {}
}";
 
            var comp = CreateCSharpCompilation(code);
 
            var symbol = comp.GetSymbolsWithName("DoStuff").Single();
 
            var actualDocId = DocumentationCommentId.CreateDeclarationId(symbol);
 
            var expectedDocId = "M:C.DoStuff(System.IntPtr)";
 
            Assert.Equal(expectedDocId, actualDocId);
 
            var foundSymbols = DocumentationCommentId.GetSymbolsForDeclarationId(expectedDocId, comp);
 
            Assert.Equal(new[] { symbol }, foundSymbols);
        }
 
        [Fact, WorkItem(65396, "https://github.com/dotnet/roslyn/issues/65396")]
        public void InvalidTypeParameterIndex_CSharp()
        {
            var comp = CreateCSharpCompilation("""
                namespace N;
                class C
                {
                    static void Main() { }
                    public void M<T>(T[] ts) { }
                }
                """).VerifyDiagnostics();
            Assert.NotNull(DocumentationCommentId.GetFirstSymbolForDeclarationId("M:N.C.M``1(``0[])", comp));
            Assert.Null(DocumentationCommentId.GetFirstSymbolForDeclarationId("M:N.C.M``1(`0[])", comp));
            Assert.Null(DocumentationCommentId.GetFirstSymbolForDeclarationId("M:N.C.M``1(``1[])", comp));
        }
 
        [Fact, WorkItem(65396, "https://github.com/dotnet/roslyn/issues/65396")]
        public void InvalidTypeParameterIndex_VisualBasic()
        {
            var comp = CreateVisualBasicCompilation("""
                Namespace N
                    Class C
                        Shared Sub Main()
                        End Sub
 
                        Public Sub M(Of T)(ByVal ts As T())
                        End Sub
                    End Class
                End Namespace
                """).VerifyDiagnostics();
            Assert.NotNull(DocumentationCommentId.GetFirstSymbolForDeclarationId("M:N.C.M``1(``0[])", comp));
            Assert.Null(DocumentationCommentId.GetFirstSymbolForDeclarationId("M:N.C.M``1(`0[])", comp));
            Assert.Null(DocumentationCommentId.GetFirstSymbolForDeclarationId("M:N.C.M``1(``1[])", comp));
        }
 
        [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/70159")]
        public async Task TestReturnValueOnInvalidSymbol1(
            [CombinatorialValues("int*", "dynamic")] string type)
        {
            var text = $$"""
                class C
                {
                    unsafe void M({{type}} i)
                    {
                        var x = i + 1;
                    }
                }
                """;
 
            var comp = CreateCSharpCompilation(text, compilationOptions: TestOptions.UnsafeDebugDll).VerifyDiagnostics();
            var tree = comp.SyntaxTrees.Single();
            var semanticModel = comp.GetSemanticModel(tree);
            var root = await tree.GetRootAsync();
 
            var token = root.FindToken(text.IndexOf('+'));
            var node = token.Parent;
            Assert.NotNull(node);
            var symbol = semanticModel.GetSymbolInfo(node!).Symbol;
            Assert.NotNull(symbol);
 
            var id = DocumentationCommentId.CreateDeclarationId(symbol!);
            Assert.Null(id);
        }
 
        internal override string VisualizeRealIL(
            IModuleSymbol peModule, CompilationTestData.MethodData methodData, IReadOnlyDictionary<int, string> markers, bool areLocalsZeroed)
            => throw new NotImplementedException();
    }
}