|
// 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.
#nullable disable
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.VisualBasic;
using Microsoft.CodeAnalysis.VisualBasic.UnitTests;
using Roslyn.Test.Utilities;
using Xunit;
using System.Collections.Generic;
using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics
{
public class SuppressMessageTargetSymbolResolverTests
{
[Fact]
public void TestResolveGlobalNamespace1()
{
VerifyNamespaceResolution("namespace $$N {}", LanguageNames.CSharp, false, "N");
}
[Fact]
public void TestResolveGlobalNamespace2()
{
VerifyNamespaceResolution(@"
Namespace $$N
End Namespace",
LanguageNames.VisualBasic, false, "N");
}
[Fact]
public void TestResolveNestedNamespace1()
{
VerifyNamespaceResolution(@"
namespace A
{
namespace B.$$C
{
}
}
",
LanguageNames.CSharp, false, "A.B.C");
}
[Fact]
public void TestResolveNestedNamespace2()
{
VerifyNamespaceResolution(@"
Namespace A
Namespace B.$$C
End Namespace
End Namespace
",
LanguageNames.VisualBasic, false, "A.B.C");
}
[Fact]
public void TestResolveNamespaceWithSameNameAsGenericInterface1()
{
VerifyNamespaceResolution(@"
namespace $$IGoo
{
}
interface IGoo<T>
{
}
",
LanguageNames.CSharp, false, "IGoo");
}
[Fact]
public void TestResolveNamespaceWithSameNameAsGenericInterface2()
{
VerifyNamespaceResolution(@"
Namespace $$IGoo
End Namespace
Interface IGoo(Of T)
End Interface
",
LanguageNames.VisualBasic, false, "IGoo");
}
[Fact]
public void TestDontPartiallyResolveNamespace1()
{
VerifyNoNamespaceResolution(@"
namespace A
{
namespace B
{
}
}
",
LanguageNames.CSharp, false, "A+B", "A#B");
}
[Fact]
public void TestDontPartiallyResolveNamespace2()
{
VerifyNoNamespaceResolution(@"
Namespace A
Namespace B
End Namespace
End Namespace
",
LanguageNames.VisualBasic, false, "A+B", "A#B");
}
[Fact]
public void TestResolveGlobalType1()
{
VerifyTypeResolution("class $$C {}", LanguageNames.CSharp, false, "C");
}
[Fact]
public void TestResolveGlobalType2()
{
VerifyTypeResolution(@"
Class $$C
End Class",
LanguageNames.VisualBasic, false, "C");
}
[Fact]
public void TestResolveModule()
{
VerifyTypeResolution(@"
Module $$C
End Module",
LanguageNames.VisualBasic, false, "C");
}
[Fact]
public void TestResolveTypeInModule()
{
VerifyTypeResolution(@"
Module M
Class $$C
End Class
End Module",
LanguageNames.VisualBasic, false, "M+C");
}
[Fact]
public void TestDontPartiallyResolveTypeInModule()
{
VerifyNoTypeResolution(@"
Module M
Class C
End Class
End Module",
LanguageNames.VisualBasic, false, "M.C");
}
[Fact]
public void TestNestedTypesInModule()
{
VerifyTypeResolution(@"
Module M
Class C
Structure $$D
End Structure
End Class
End Module",
LanguageNames.VisualBasic, false, "M+C+D");
}
[Fact]
public void TestResolveTypeInNamespace1()
{
VerifyTypeResolution(@"
namespace N1.N2
{
class $$C
{
}
}
",
LanguageNames.CSharp, false, "N1.N2.C");
}
[Fact]
public void TestResolveTypeInNamespace2()
{
VerifyTypeResolution(@"
Namespace N1.N2
Class $$C
End Class
End Namespace
",
LanguageNames.VisualBasic, false, "N1.N2.C");
}
[Fact]
public void TestResolveTypeNestedInGlobalType1()
{
VerifyTypeResolution(@"
class C
{
interface $$D
{
}
}
",
LanguageNames.CSharp, false, "C+D");
}
[Fact]
public void TestResolveTypeNestedInGlobalType2()
{
VerifyTypeResolution(@"
Class C
Public Delegate Sub $$D()
End Class
",
LanguageNames.VisualBasic, false, "C+D");
}
[Fact]
public void TestResolveNestedType1()
{
VerifyTypeResolution(@"
namespace N
{
class C
{
class D
{
class $$E
{ }
}
}
}
",
LanguageNames.CSharp, false, "N.C+D+E");
}
[Fact]
public void TestResolveNestedType2()
{
VerifyTypeResolution(@"
Namespace N
Class C
Class D
Class $$E
End Class
End Class
End Class
End Namespace
",
LanguageNames.VisualBasic, false, "N.C+D+E");
}
[Fact]
public void TestResolveGenericType1()
{
VerifyTypeResolution(@"
class D<T>
{
}
class $$D<T1, T2, T3>
{
}
",
LanguageNames.CSharp, false, "D`3");
}
[Fact]
public void TestResolveGenericType2()
{
VerifyTypeResolution(@"
Class D(Of T)
End Class
Class $$D(Of T1, T2, T3)
End Class
",
LanguageNames.VisualBasic, false, "D`3");
}
[Fact]
public void TestDontResolveGenericType1()
{
VerifyNoTypeResolution(@"
class D<T1, T2, T3>
{
}
",
LanguageNames.CSharp, false, "D");
}
[Fact]
public void TestDontResolveGenericType2()
{
VerifyNoTypeResolution(@"
Class D(Of T1, T2, T3)
End Class
",
LanguageNames.VisualBasic, false, "D");
}
[Fact]
public void TestResolveRootNamespace()
{
VerifyTypeResolution(@"
Module M
Class $$C
End Class
End Module
",
LanguageNames.VisualBasic, true, "RootNamespace.M+C");
}
[Fact]
public void TestDontPartiallyResolveType1()
{
VerifyNoTypeResolution(@"
class A
{
class B
{
}
}
",
LanguageNames.CSharp, false, "A.B");
}
[Fact]
public void TestDontPartiallyResolveType2()
{
VerifyNoTypeResolution(@"
Class A
Class B
End Class
End Class
",
LanguageNames.VisualBasic, false, "A.B");
}
[Fact]
public void TestResolveField1()
{
VerifyMemberResolution(@"
class C
{
string $$s;
}
",
LanguageNames.CSharp, false,
"C.#s",
"C.s");
}
[Fact]
public void TestResolveField2()
{
VerifyMemberResolution(@"
Class C
Dim $$s As String
End Class
",
LanguageNames.VisualBasic, false,
"C.#s",
"C.s");
}
[Fact, WorkItem(1141257, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1141257")]
public void TestResolveEnumFieldWithoutName()
{
var source = @"
enum E
{
$$,
}
";
var syntaxTree = CreateSyntaxTree(source, LanguageNames.CSharp);
var compilation = CreateCompilation(syntaxTree, LanguageNames.CSharp, "");
_ = SuppressMessageAttributeState.ResolveTargetSymbols(compilation, "E.", SuppressMessageAttributeState.TargetScope.Member);
}
[Fact]
public void TestResolveProperty1()
{
VerifyMemberResolution(@"
class C
{
public string $$StringProperty { get; set; }
}
",
LanguageNames.CSharp, false,
"C.#StringProperty",
"C.StringProperty");
}
[Fact]
public void TestResolveProperty2()
{
VerifyMemberResolution(@"
Class C
Public Property $$StringProperty
Get
End Get
Set
End Set
End Property
End Class
",
LanguageNames.VisualBasic, false,
"C.#StringProperty",
"C.StringProperty");
}
[Fact]
public void TestResolveEvent1()
{
VerifyMemberResolution(@"
class C
{
public event System.EventHandler<int> $$E;
}
",
LanguageNames.CSharp, false,
"e:C.#E",
"C.E");
}
[Fact]
public void TestResolveEvent2()
{
VerifyMemberResolution(@"
Class C
Public Event $$E As System.EventHandler(Of Integer)
End Class
",
LanguageNames.VisualBasic, false,
"e:C.#E",
"C.E");
}
[Fact]
public void TestDontResolveNonEvent1()
{
VerifyNoMemberResolution(@"
public class C
{
public int E;
}
",
LanguageNames.CSharp, false, "e:C.E");
}
[Fact]
public void TestDontResolveNonEvent2()
{
VerifyNoMemberResolution(@"
Public Class C
Public Dim E As Integer
End Class
",
LanguageNames.VisualBasic, false, "e:C.E");
}
[Fact]
public void TestResolvePropertySetMethod1()
{
VerifyMemberResolution(@"
class C
{
public string StringProperty { get; $$set; }
}
",
LanguageNames.CSharp, false,
"C.#set_StringProperty(System.String)",
"C.set_StringProperty(System.String):System.Void");
}
[Fact]
public void TestResolvePropertySetMethod2()
{
VerifyMemberResolution(@"
Class C
Public Property StringProperty As String
Get
End Get
$$Set
End Set
End Property
End Class
",
LanguageNames.VisualBasic, false,
"C.#set_StringProperty(System.String)",
"C.set_StringProperty(System.String):System.Void");
}
[Fact]
public void TestResolveEventAddMethod()
{
VerifyMemberResolution(@"
class C
{
public delegate void Del(int x);
public event Del E
{
$$add { }
remove { }
}
}
",
LanguageNames.CSharp, false,
"C.#add_E(C.Del)",
"C.add_E(C.Del):System.Void");
}
[Fact]
public void TestResolveEventRemoveMethod()
{
VerifyMemberResolution(@"
class C
{
public delegate void Del(int x);
public event Del E
{
add { }
$$remove { }
}
}
",
LanguageNames.CSharp, false,
"C.#remove_E(C.Del)",
"C.remove_E(C.Del):System.Void");
}
[Fact]
public void TestResolveVoidMethod1()
{
VerifyMemberResolution(@"
class C
{
void Goo() {}
void $$Goo(int x) {}
void Goo(string x) {}
}
",
LanguageNames.CSharp, false,
"C.#Goo(System.Int32)",
"C.Goo(System.Int32):System.Void");
}
[Fact]
public void TestResolveVoidMethod2()
{
VerifyMemberResolution(@"
Class C
Sub Goo()
End Sub
Sub $$Goo(ByVal x as Integer)
End Sub
Sub Goo(ByVal x as String)
End Sub
End Class
",
LanguageNames.VisualBasic, false,
"C.#Goo(System.Int32)",
"C.Goo(System.Int32):System.Void");
}
[Fact]
public void TestResolveMethod1()
{
VerifyMemberResolution(@"
class C
{
void Goo() {}
string Goo(int x) {}
string $$Goo(string x) {}
}
",
LanguageNames.CSharp, false,
"C.#Goo(System.String)",
"C.Goo(System.String):System.String");
}
[Fact]
public void TestResolveMethod2()
{
VerifyMemberResolution(@"
Class C
Sub Goo()
End Sub
Function Goo(ByVal x As Integer) As String
End Function
Function $$Goo(ByVal x As String) As String
End Function
End Class
",
LanguageNames.VisualBasic, false,
"C.#Goo(System.String)",
"C.Goo(System.String):System.String");
}
[Fact]
public void TestResolveOverloadedGenericMethod1()
{
VerifyMemberResolution(@"
class C
{
int Goo<T>(T x) {}
int $$Goo<T>(T x, params T[] y) {}
}
",
LanguageNames.CSharp, false,
"C.#Goo`1(!!0,!!0[])",
"C.Goo(T,T[]):System.Int32");
VerifyMemberResolution(@"
class C
{
int [|Goo|]<T>(T x) {}
int [|Goo|]<T>(T x, T y) {}
}
",
LanguageNames.CSharp, false, "C.Goo():System.Int32");
}
[Fact]
public void TestResolveOverloadedGenericMethod2()
{
VerifyMemberResolution(@"
Class C
Function Goo(Of T)(ByVal x As T) As Integer
End Function
Function $$Goo(Of T)(ByVal x As T, ByVal y as T()) As Integer
End Function
End Class
",
LanguageNames.VisualBasic, false,
"C.#Goo`1(!!0,!!0[])",
"C.Goo(T,T[]):System.Int32");
VerifyMemberResolution(@"
Class C
Function [|Goo|](Of T)(ByVal x As T) As Integer
End Function
Function [|Goo|](Of T)(ByVal x As T, ByVal y As T) As Integer
End Function
End Class
",
LanguageNames.VisualBasic, false, "C.Goo():System.Int32");
}
[Fact]
public void TestResolveMethodOverloadedOnArity1()
{
VerifyMemberResolution(@"
interface I
{
void M<T>();
void $$M<T1, T2>();
}
",
LanguageNames.CSharp, false, "I.#M`2()");
VerifyMemberResolution(@"
interface I
{
void [|M|]<T>();
void [|M|]<T1, T2>();
}
",
LanguageNames.CSharp, false, "I.M():System.Void");
}
[Fact]
public void TestResolveMethodOverloadedOnArity2()
{
VerifyMemberResolution(@"
Interface I
Sub M(Of T)
Sub $$M(Of T1, T2)
End Interface
",
LanguageNames.VisualBasic, false, "I.#M`2()");
VerifyMemberResolution(@"
Interface I
Sub [|M|](Of T)
Sub [|M|](Of T1, T2)
End Interface
",
LanguageNames.VisualBasic, false, "I.M():System.Void");
}
[Fact]
public void TestResolveConstructor1()
{
VerifyMemberResolution(@"
class C
{
$$C() {}
}
",
LanguageNames.CSharp, false,
"C.#.ctor()",
"C..ctor()");
}
[Fact]
public void TestResolveConstructor2()
{
VerifyMemberResolution(@"
Class C
Sub $$New()
End Sub
End Class
",
LanguageNames.VisualBasic, false,
"C.#.ctor()",
"C..ctor()");
}
[Fact]
public void TestResolveStaticConstructor1()
{
VerifyMemberResolution(@"
class C
{
static $$C() {}
}
",
LanguageNames.CSharp, false,
"C.#.cctor()",
"C..cctor()");
}
[Fact]
public void TestResolveStaticConstructor2()
{
VerifyMemberResolution(@"
Class C
Shared Sub $$New()
End Sub
End Class
",
LanguageNames.VisualBasic, false,
"C.#.cctor()",
"C..cctor()");
}
[Fact]
public void TestResolveSimpleOperator1()
{
VerifyMemberResolution(@"
class C
{
public static bool operator $$==(C a, C b)
{
return true;
}
}
",
LanguageNames.CSharp, false,
"C.#op_Equality(C,C)",
"C.op_Equality(C,C):System.Boolean");
}
[Fact]
public void TestResolveSimpleOperator2()
{
VerifyMemberResolution(@"
Class C
Public Shared Operator $$+(a as C, b as C) As Boolean
return true
End Operator
End Class
",
LanguageNames.VisualBasic, false,
"C.#op_Addition(C,C)",
"C.op_Addition(C,C):System.Boolean");
}
[Fact]
public void TestResolveIndexer1()
{
VerifyMemberResolution(@"
class C
{
public C $$this[int i, string j]
{
get { return this; }
}
public C this[string i]
{
get { return this; }
}
}
",
LanguageNames.CSharp, false,
"C.#Item[System.Int32,System.String]",
"C.Item[System.Int32,System.String]");
}
[Fact]
public void TestResolveIndexer2()
{
VerifyMemberResolution(@"
Class C
Public Default ReadOnly Property $$Item(i As Integer, j As String) As C
Get
Return Me
End Get
End Property
Public Default ReadOnly Property Item(i As String) As C
Get
Return Me
End Get
End Property
End Class
",
LanguageNames.VisualBasic, false,
"C.#Item[System.Int32,System.String]",
"C.Item[System.Int32,System.String]");
}
[Fact]
public void TestResolveIndexerAccessorMethod()
{
VerifyMemberResolution(@"
class C
{
public C this[int i]
{
get { return this; }
}
public C this[string i]
{
$$get { return this; }
}
}
",
LanguageNames.CSharp, false,
"C.#get_Item(System.String)",
"C.get_Item(System.String):C");
}
[Fact]
public void TestResolveExplicitOperator()
{
VerifyMemberResolution(@"
class C
{
public static explicit operator $$bool(C c)
{
return C == null;
}
public static explicit operator string(C c)
{
return string.Empty;
}
}
",
LanguageNames.CSharp, false,
"C.#op_Explicit(C):System.Boolean",
"C.op_Explicit(C):System.Boolean");
}
[Fact]
public void TestResolveMethodWithComplexParameterTypes1()
{
VerifyMemberResolution(@"
class C
{
public unsafe static bool $$IsComplex<T0, T1>(int* a, ref int b, ref T0 c, T1[] d)
{
return true;
}
}
",
LanguageNames.CSharp, false,
"C.#IsComplex`2(System.Int32*,System.Int32&,!!0&,!!1[])",
"C.IsComplex(System.Int32*,System.Int32&,T0&,T1[]):System.Boolean");
}
[Fact]
public void TestResolveMethodWithComplexParameterTypes2()
{
VerifyMemberResolution(@"
Class C
Public Shared Function $$IsComplex(Of T0, T1)(a As Integer, ByRef b As Integer, ByRef c As T0, d As T1()) As Boolean
Return True
End Function
End Class",
LanguageNames.VisualBasic, false,
"C.#IsComplex`2(System.Int32,System.Int32&,!!0&,!!1[])",
"C.IsComplex(System.Int32,System.Int32&,T0&,T1[]):System.Boolean");
}
[Fact]
public void TestFinalize1()
{
VerifyMemberResolution(@"
class A
{
~$$A()
{
}
}
",
LanguageNames.CSharp, false,
"A.#Finalize()",
"A.Finalize():System.Void");
}
[Fact]
public void TestFinalize2()
{
VerifyMemberResolution(@"
Class A
Protected Overrides Sub $$Finalize()
Try
Finally
MyBase.Finalize()
End Try
End Sub
End Class
",
LanguageNames.VisualBasic, false,
"A.#Finalize()",
"A.Finalize():System.Void");
}
[Fact]
public void TestResolveMethodWithComplexReturnType1()
{
VerifyMemberResolution(@"
class C
{
public static T[][][,,][,] $$GetComplex<T>()
{
return null;
}
}
",
LanguageNames.CSharp, false,
"C.#GetComplex`1()",
"C.GetComplex():T[,][,,][][]");
}
[Fact]
public void TestResolveMethodWithComplexReturnType2()
{
VerifyMemberResolution(@"
Class C
Public Shared Function $$GetComplex(Of T)() As T()()(,,)(,)
Return Nothing
End Function
End Class
",
LanguageNames.VisualBasic, false,
"C.#GetComplex`1()",
"C.GetComplex():T[,][,,][][]");
}
[Fact]
public void TestResolveMethodWithGenericParametersAndReturnTypeFromContainingClass1()
{
VerifyMemberResolution(@"
public class C<T0>
{
public class D<T1>
{
public T3 $$M<T2, T3>(T0 a, T1 b, T2 c)
{
return default(T3);
}
}
}
",
LanguageNames.CSharp, false,
"C`1+D`1.#M`2(!0,!1,!!0)",
"C`1+D`1.M(T0,T1,T2):T3");
}
[Fact]
public void TestResolveMethodWithGenericParametersAndReturnTypeFromContainingClass2()
{
VerifyMemberResolution(@"
Public Class C(Of T0)
Public Class D(Of T1)
Public Function $$M(Of T2, T3)(a As T0, b As T1, c As T2) As T3
Return Nothing
End Function
End Class
End Class
",
LanguageNames.VisualBasic, false,
"C`1+D`1.#M`2(!0,!1,!!0)",
"C`1+D`1.M(T0,T1,T2):T3");
}
[Fact]
public void TestResolveIndexerWithGenericParametersTypeFromContainingClass1()
{
VerifyMemberResolution(@"
public class C<T0>
{
public class D<T1>
{
public T0 $$this[T1 a]
{
get { return default(T0); }
}
}
}
",
LanguageNames.CSharp, false,
"C`1+D`1.#Item[!1]",
"C`1+D`1.Item[!1]:!0");
}
[Fact]
public void TestResolveIndexerWithGenericParametersTypeFromContainingClass2()
{
VerifyMemberResolution(@"
Public Class C(Of T0)
Public Class D(Of T1)
Public Default ReadOnly Property $$Item(a As T1) As T0
Get
Return Nothing
End Get
End Property
End Class
End Class
",
LanguageNames.VisualBasic, false,
"C`1+D`1.#Item[!1]",
"C`1+D`1.Item[!1]:!0");
}
[Fact]
public void TestResolveMethodOnOutParameter1()
{
VerifyMemberResolution(@"
class C
{
void M0(int x)
{
}
void $$M1(out int x)
{
x = 1;
}
}
",
LanguageNames.CSharp, false,
"C.#M1(System.Int32&)",
"C.M1(System.Int32&):System.Void");
}
[Fact]
public void TestResolveMethodOnOutParameter2()
{
VerifyMemberResolution(@"
Class C
Private Sub M0(x As Integer)
End Sub
Private Sub $$M1(ByRef x As Integer)
x = 1
End Sub
End Class
",
LanguageNames.VisualBasic, false,
"C.#M1(System.Int32&)",
"C.M1(System.Int32&):System.Void");
}
[Fact]
public void TestResolveMethodWithInstantiatedGenericParameterAndReturnType1()
{
VerifyMemberResolution(@"
class G<T0,T1>
{
}
class C<T3>
{
G<int,int> $$M<T4>(G<double, double> g, G<T3, T4[]> h)
{
}
}
",
LanguageNames.CSharp, false,
"C.#M`1(G`2<System.Double,System.Double>,G`2<!0,!!0[]>)",
"C.M(G`2<System.Double,System.Double>,G`2<T3,T4[]>):G`2<System.Int32,System.Int32>");
}
[Fact]
public void TestResolveMethodWithInstantiatedGenericParameterAndReturnType2()
{
VerifyMemberResolution(@"
Class G(Of T0, T1)
End Class
Class C(Of T3)
Private Function $$M(Of T4)(g As G(Of Double, Double), h As G(Of T3, T4())) As G(Of Integer, Integer)
End Function
End Class
",
LanguageNames.VisualBasic, false,
"C.#M`1(G`2<System.Double,System.Double>,G`2<!0,!!0[]>)",
"C.M(G`2<System.Double,System.Double>,G`2<T3,T4[]>):G`2<System.Int32,System.Int32>");
}
[Fact]
public void TestResolveEscapedName1()
{
VerifyMemberResolution(@"
namespace @namespace
{
class @class
{
int $$@if;
}
}
",
LanguageNames.CSharp, false,
"namespace.class.if");
}
[Fact]
public void TestResolveEscapedName2()
{
VerifyMemberResolution(@"
Namespace [Namespace]
Class [Class]
Private $$[If] As Integer
End Class
End Namespace
",
LanguageNames.VisualBasic, false,
"Namespace.Class.If");
}
[Fact]
public void TestResolveMethodIgnoresConvention1()
{
VerifyMemberResolution(@"
class C
{
string $$Goo(string x) {}
}
",
LanguageNames.CSharp, false,
"C.#[vararg]Goo(System.String)",
"C.#[cdecl]Goo(System.String)",
"C.#[fastcall]Goo(System.String)",
"C.#[stdcall]Goo(System.String)",
"C.#[thiscall]Goo(System.String)");
}
[Fact]
public void TestResolveMethodIgnoresConvention2()
{
VerifyMemberResolution(@"
Class C
Private Function $$Goo(x As String) As String
End Function
End Class
",
LanguageNames.VisualBasic, false,
"C.#[vararg]Goo(System.String)",
"C.#[cdecl]Goo(System.String)",
"C.#[fastcall]Goo(System.String)",
"C.#[stdcall]Goo(System.String)",
"C.#[thiscall]Goo(System.String)");
}
[Fact]
public void TestNoResolutionForMalformedNames1()
{
VerifyNoMemberResolution(@"
public class C<T0>
{
public class D<T4>
{
int @namespace;
public T3 M<T2, T3>(T0 a, T4 b, T2 c)
{
return null;
}
}
}
",
LanguageNames.CSharp, false,
"C`1+D`1.#M`2(!0,!1,!!0", // Missing close paren
"C`1+D`1.M`2(T0,T4,T2):", // Missing return type
"C`1+D`1.M`2(T0,T4,T2", // Missing close paren
"C`1+D`1+M`2(T0,T4,T2)", // '+' instead of '.' delimiter
"C`1.D`1.M`2(T0,T4,T2)", // '.' instead of '+' delimiter
"C`1+D`1.@namespace", // Escaped name
"C`1+D`1.#[blah]M`2(!0,!1,!!0)"); // Invalid calling convention
}
[Fact]
public void TestNoResolutionForMalformedNames2()
{
VerifyNoMemberResolution(@"
Public Class C(Of T0)
Public Class D(Of T1)
Private [Namespace] As Integer
Public Function M(Of T2, T3)(a As T0, b As T1, c As T2) As T3
Return Nothing
End Function
End Class
End Class
",
LanguageNames.VisualBasic, false,
"C`1+D`1.#M`2(!0,!1,!!0", // Missing close paren
"C`1+D`1.M`2(T0,T1,T2):", // Missing return type
"C`1+D`1.M`2(T0,T1,T2", // Missing close paren
"C`1+D`1+M`2(T0,T1,T2)", // '+' instead of '.' delimiter
"C`1.D`1.M`2(T0,T1,T2)", // '.' instead of '+' delimiter
"C`1+D`1.[Namespace]", // Escaped name
"C`1+D`1.#[blah]M`2(!0,!1,!!0)"); // Invalid calling convention
}
[Fact, WorkItem(65396, "https://github.com/dotnet/roslyn/issues/65396")]
public void TestNoResolutionForMalformedNames3()
{
var names = new[]
{
"C.#M`1(G`2<!1,!!0[]>)", // Wrong class type index
"C.#M`1(G`2<!0,!!1[]>)", // Wrong method type index
};
VerifyNoMemberResolution("""
class G<T0,T1> { }
class C<T3>
{
G<int,int> M<T4>(G<T3, T4[]> g) { }
}
""",
LanguageNames.CSharp, false, names);
VerifyNoMemberResolution("""
Class G(Of T0, T1)
End Class
Class C(Of T3)
Private Function M(Of T4)(g As G(Of T3, T4())) As G(Of Integer, Integer)
End Function
End Class
""",
LanguageNames.VisualBasic, false, names);
}
private static void VerifyNamespaceResolution(string markup, string language, bool rootNamespace, params string[] fxCopFullyQualifiedNames)
{
string rootNamespaceName = "";
if (rootNamespace)
{
rootNamespaceName = "RootNamespace";
}
VerifyResolution(markup, fxCopFullyQualifiedNames, SuppressMessageAttributeState.TargetScope.Namespace, language, rootNamespaceName);
}
private static void VerifyNoNamespaceResolution(string markup, string language, bool rootNamespace, params string[] fxCopFullyQualifiedNames)
{
string rootNamespaceName = "";
if (rootNamespace)
{
rootNamespaceName = "RootNamespace";
}
VerifyNoResolution(markup, fxCopFullyQualifiedNames, SuppressMessageAttributeState.TargetScope.Namespace, language, rootNamespaceName);
}
private static void VerifyTypeResolution(string markup, string language, bool rootNamespace, params string[] fxCopFullyQualifiedNames)
{
string rootNamespaceName = "";
if (rootNamespace)
{
rootNamespaceName = "RootNamespace";
}
VerifyResolution(markup, fxCopFullyQualifiedNames, SuppressMessageAttributeState.TargetScope.Type, language, rootNamespaceName);
}
private static void VerifyNoTypeResolution(string markup, string language, bool rootNamespace, params string[] fxCopFullyQualifiedNames)
{
string rootNamespaceName = "";
if (rootNamespace)
{
rootNamespaceName = "RootNamespace";
}
VerifyNoResolution(markup, fxCopFullyQualifiedNames, SuppressMessageAttributeState.TargetScope.Type, language, rootNamespaceName);
}
private static void VerifyMemberResolution(string markup, string language, bool rootNamespace, params string[] fxCopFullyQualifiedNames)
{
string rootNamespaceName = "";
if (rootNamespace)
{
rootNamespaceName = "RootNamespace";
}
VerifyResolution(markup, fxCopFullyQualifiedNames, SuppressMessageAttributeState.TargetScope.Member, language, rootNamespaceName);
}
private static void VerifyNoMemberResolution(string markup, string language, bool rootNamespace, params string[] fxCopFullyQualifiedNames)
{
string rootNamespaceName = "";
if (rootNamespace)
{
rootNamespaceName = "RootNamespace";
}
VerifyNoResolution(markup, fxCopFullyQualifiedNames, SuppressMessageAttributeState.TargetScope.Member, language, rootNamespaceName);
}
private static void VerifyResolution(string markup, string[] fxCopFullyQualifiedNames, SuppressMessageAttributeState.TargetScope scope, string language, string rootNamespace)
{
// Parse out the span containing the declaration of the expected symbol
MarkupTestFile.GetPositionAndSpans(markup,
out var source, out var pos, out IDictionary<string, ImmutableArray<TextSpan>> spans);
Assert.True(pos != null || spans.Count > 0, "Must specify a position or spans marking expected symbols for resolution");
// Get the expected symbol from the given position
var syntaxTree = CreateSyntaxTree(source, language);
var compilation = CreateCompilation(syntaxTree, language, rootNamespace);
var model = compilation.GetSemanticModel(syntaxTree);
var expectedSymbols = new List<ISymbol>();
bool shouldResolveSingleSymbol = pos != null;
if (shouldResolveSingleSymbol)
{
expectedSymbols.Add(GetSymbolAtPosition(model, pos.Value));
}
else
{
foreach (var span in spans.Values.First())
{
expectedSymbols.Add(GetSymbolAtPosition(model, span.Start));
}
}
// Resolve the symbol based on each given FxCop fully-qualified name
foreach (var fxCopName in fxCopFullyQualifiedNames)
{
var symbols = SuppressMessageAttributeState.ResolveTargetSymbols(compilation, fxCopName, scope);
if (shouldResolveSingleSymbol)
{
var expectedSymbol = expectedSymbols.Single();
if (symbols.Count() > 1)
{
Assert.True(false,
string.Format("Expected to resolve FxCop fully-qualified name '{0}' to '{1}': got multiple symbols:\r\n{2}",
fxCopName, expectedSymbol, string.Join("\r\n", symbols)));
}
var symbol = symbols.SingleOrDefault();
Assert.True(expectedSymbol == symbol,
string.Format("Failed to resolve FxCop fully-qualified name '{0}' to symbol '{1}': got '{2}'",
fxCopName, expectedSymbol, symbol));
}
else
{
foreach (var symbol in symbols)
{
Assert.True(expectedSymbols.Contains(symbol),
string.Format("Failed to resolve FxCop fully-qualified name '{0}' to symbols:\r\n{1}\r\nResolved to unexpected symbol '{2}'",
fxCopName, string.Join("\r\n", expectedSymbols), symbol));
}
}
}
}
private static ISymbol GetSymbolAtPosition(SemanticModel model, int pos)
{
var token = model.SyntaxTree.GetRoot().FindToken(pos);
Assert.NotNull(token.Parent);
var location = token.GetLocation();
var q = from node in token.Parent.AncestorsAndSelf()
let candidate = model.GetDeclaredSymbol(node)
where candidate != null && candidate.Locations.Contains(location)
select candidate;
var symbol = q.FirstOrDefault();
Assert.NotNull(symbol);
return symbol;
}
private static void VerifyNoResolution(string source, string[] fxCopFullyQualifiedNames, SuppressMessageAttributeState.TargetScope scope, string language, string rootNamespace)
{
var compilation = CreateCompilation(source, language, rootNamespace);
foreach (var fxCopName in fxCopFullyQualifiedNames)
{
var symbols = SuppressMessageAttributeState.ResolveTargetSymbols(compilation, fxCopName, scope);
Assert.True(symbols.FirstOrDefault() == null,
string.Format("Did not expect FxCop fully-qualified name '{0}' to resolve to any symbol: resolved to:\r\n{1}",
fxCopName, string.Join("\r\n", symbols)));
}
}
private static Compilation CreateCompilation(SyntaxTree syntaxTree, string language, string rootNamespace)
{
string projectName = "TestProject";
if (language == LanguageNames.CSharp)
{
return CSharpCompilation.Create(
projectName,
syntaxTrees: new[] { syntaxTree },
references: new[] { TestBase.MscorlibRef });
}
else
{
return VisualBasicCompilation.Create(
projectName,
options: new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, rootNamespace: rootNamespace),
syntaxTrees: new[] { syntaxTree },
references: new[] { TestBase.MscorlibRef });
}
}
private static Compilation CreateCompilation(string source, string language, string rootNamespace)
{
return CreateCompilation(CreateSyntaxTree(source, language), language, rootNamespace);
}
private static SyntaxTree CreateSyntaxTree(string source, string language)
{
string fileName = language == LanguageNames.CSharp ? "Test.cs" : "Test.vb";
return language == LanguageNames.CSharp ?
CSharpTestSource.Parse(source, path: fileName) :
BasicTestSource.Parse(source, path: fileName);
}
}
}
|