|
// 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.Threading;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.UnitTests;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SymbolId;
public class SymbolKeyErrorTypeTests : SymbolKeyTestBase
{
[Fact]
public void GenericType_NotMissingWithMissingTypeArgument()
{
var source = """
namespace N
{
public class C
{
public void M(D<string> x)
{
}
}
public class D<T>
{
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.M"));
}
[Fact]
public void GenericType_MissingWithNonMissingTypeArgument()
{
var source = """
using System.Collections.Generic;
namespace N
{
public class C
{
public void M(List<D> x)
{
}
}
public class D
{
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.M"));
}
[Fact]
public void GenericType_MissingWithMissingTypeArgument()
{
var source = """
using System.Collections.Generic;
namespace N
{
public class C
{
public void M(List<string> x)
{
}
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.M"));
}
[Fact]
public void Tuple_MissingTypes()
{
var source = """
namespace N
{
public class C
{
public void M((string, int) x)
{
}
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.M"));
}
[Fact]
public void Tuple_NonMissingTypes()
{
var source = """
namespace N
{
public class C
{
public void M((C, D) x)
{
}
}
public class D
{
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.M"));
}
[Fact]
public void Array_MissingElementType()
{
var source = """
namespace N
{
public class C
{
public void M(string[] x)
{
}
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.M"));
}
[Fact]
public void Array_NonMissingElementType()
{
var source = """
namespace N
{
public class C
{
public void M(D[] x)
{
}
}
public class D
{
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.M"));
}
[Fact]
public void Pointer_MissingType()
{
var source = """
namespace N
{
public class C
{
public unsafe void M(int *x)
{
}
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.M"));
}
[Fact]
public void Pointer_NonMissingType()
{
var source = """
namespace N
{
public class C
{
public unsafe void M(S *x)
{
}
}
public struct S
{
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.M"));
}
[Fact]
public void NestedType_MissingInGenericContainer()
{
var source = """
using System.Collections.Generic;
namespace N
{
public class C
{
public void M(List<int>.Enumerator x)
{
}
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.M"));
}
[Fact]
public void NestedType_MissingInNonGenericContainer()
{
var source = """
using System.Diagnostics;
namespace N
{
public class C
{
public void M(DebuggableAttribute.DebuggingModes x)
{
}
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.M"));
}
[Fact]
public void Method_MissingReturnType()
{
var source = """
namespace N
{
public class C
{
public string Create()
{
return new string('c', 1);
}
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.Create"));
}
[Fact]
public void Method_MissingParameterType()
{
var source = """
namespace N
{
public class C
{
public C Create(string x)
{
return new C();
}
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.Create"));
}
[Fact]
public void Constructor_MissingParameterType()
{
var source = """
public class C
{
public C(string x)
{
}
}
""";
VerifyResolution(source, c => c.GetMember("C..ctor"));
}
[Fact]
public void Indexer_MissingParameterType()
{
var source = """
namespace N
{
public class C
{
public C this[string x]
{
get { return null; }
set { }
}
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.this[]"));
}
[Fact]
public void Indexer_MissingReturnType()
{
var source = """
namespace N
{
public class C
{
public string this[C x]
{
get { return null; }
set { }
}
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.this[]"));
}
[Fact]
public void Property_MissingReturnType()
{
var source = """
namespace N
{
public class C
{
public string P
{
get { return null; }
set { }
}
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.P"));
}
[Fact]
public void EventField_MissingReturnType()
{
var source = """
namespace N
{
public class C
{
public event System.EventHandler E;
}
}
""";
VerifyResolution(source, c => c.GetMember("N.C.E"));
}
private static void VerifyResolution(string source, Func<Compilation, ISymbol> symbolToResolve)
{
var sourceCompilation = (Compilation)CreateCompilation(source, options: new(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true));
var symbol = symbolToResolve(sourceCompilation);
Assert.NotNull(symbol);
var symbolKey = SymbolKey.CreateString(symbol);
// Create a compilation that references our library, but doesn't reference types needed by the library.
// This emulates the experience in Go To Definition when navigating to metadata from the .NET runtime when
// implementations are split over multiple assemblies with various type forwards in play.
// For example:
// System.Uri exists in System.Private.Uri.dll, but System.String exists in System.Private.CoreLib.dll
// and we want to allow a symbol for System.Uri.Create(System.String) to resolve correctly even when the
// System.Private.CoreLib reference is missing.
var emptyCompilation = CSharpCompilation.Create("empty", options: new(OutputKind.DynamicallyLinkedLibrary, concurrentBuild: false))
.AddReferences(sourceCompilation.EmitToImageReference());
var resolution = SymbolKey.ResolveString(symbolKey, emptyCompilation, ignoreAssemblyKey: true, out var failureReason, CancellationToken.None);
Assert.Null(failureReason);
Assert.NotNull(resolution.Symbol);
// Since we expect some types to be error types, we just use display string to make sure we found the right
// symbol.
Assert.Equal(symbol.ToDisplayString(), resolution.Symbol!.ToDisplayString());
}
}
|