diff --git a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs index 7a57c996c6d67bbea73b43191431449f024cdfa2..88ce12d18130ea1d674992340acf69979a966ded 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs @@ -1987,29 +1987,29 @@ public override ITypeParameterSymbol GetDeclaredSymbol(TypeParameterSyntax typeP throw new ArgumentException("typeParameter not within tree"); } - var typeParamList = typeParameter.Parent as TypeParameterListSyntax; - if (typeParamList != null) + if (typeParameter.Parent is TypeParameterListSyntax typeParamList) { - var memberDecl = typeParamList.Parent as MemberDeclarationSyntax; - if (memberDecl != null) + ISymbol parameterizedSymbol = null; + switch (typeParamList.Parent) { - var symbol = GetDeclaredSymbol(memberDecl, cancellationToken); - if ((object)symbol != null) - { - var typeSymbol = symbol as NamedTypeSymbol; - if ((object)typeSymbol != null) - { - return this.GetTypeParameterSymbol(typeSymbol.TypeParameters, typeParameter); - } + case MemberDeclarationSyntax memberDecl: + parameterizedSymbol = GetDeclaredSymbol(memberDecl, cancellationToken); + break; + case LocalFunctionStatementSyntax localDecl: + parameterizedSymbol = GetDeclaredSymbol(localDecl, cancellationToken); + break; + } - var methodSymbol = symbol as MethodSymbol; - if ((object)methodSymbol != null) - { - return - this.GetTypeParameterSymbol(methodSymbol.TypeParameters, typeParameter) ?? - ((object)methodSymbol.PartialDefinitionPart == null ? null : this.GetTypeParameterSymbol(methodSymbol.PartialDefinitionPart.TypeParameters, typeParameter)); - } - } + switch (parameterizedSymbol) + { + case NamedTypeSymbol typeSymbol: + return this.GetTypeParameterSymbol(typeSymbol.TypeParameters, typeParameter); + + case MethodSymbol methodSymbol: + return this.GetTypeParameterSymbol(methodSymbol.TypeParameters, typeParameter) ?? + ((object)methodSymbol.PartialDefinitionPart == null + ? null + : this.GetTypeParameterSymbol(methodSymbol.PartialDefinitionPart.TypeParameters, typeParameter)); } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index e0c3a7cae97ca622684d31fa1f61222913d61b7b..5e436764f8cd6f3a2ada554109d7c3c4eb4b8d3d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -3331,5 +3331,43 @@ static void M() Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L5(1, 3, val)").WithArguments("L5").WithLocation(26, 9) ); } + + [Fact] + [WorkItem(23699, "https://github.com/dotnet/roslyn/issues/23699")] + public void GetDeclaredSymbolOnTypeParameter() + { + var src = @" +class C +{ + void M() + { + void LocalFunction(T p1, U p2, V p3) + { + } + } +} +"; + var comp = CreateStandardCompilation(src); + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var localDecl = (LocalFunctionStatementSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.LocalFunctionStatement).AsNode(); + + var typeParameters = localDecl.TypeParameterList.Parameters; + var parameters = localDecl.ParameterList.Parameters; + verifyTypeParameterAndParameter(typeParameters[0], parameters[0], "T"); + verifyTypeParameterAndParameter(typeParameters[1], parameters[1], "U"); + verifyTypeParameterAndParameter(typeParameters[2], parameters[2], "V"); + + void verifyTypeParameterAndParameter(TypeParameterSyntax typeParameter, ParameterSyntax parameter, string expected) + { + var symbol = model.GetDeclaredSymbol(typeParameter); + Assert.Equal(expected, symbol.ToTestDisplayString()); + + var parameterSymbol = model.GetDeclaredSymbol(parameter); + Assert.Equal(expected, parameterSymbol.Type.ToTestDisplayString()); + Assert.True(symbol == parameterSymbol.Type); + } + } } } diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.TypeParameterTypeSymbol.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.TypeParameterTypeSymbol.vb index 57cbb7b7b1491bcadb78b482b4f6bc723b6b0f49..8e00376c7488e515669698f4b811d6ab97bf8b7a 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.TypeParameterTypeSymbol.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.TypeParameterTypeSymbol.vb @@ -25,6 +25,94 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences Await TestAPIAndFeature(input) End Function + + + Public Async Function TestCSharp_LocalFunctionTypeParameter() As Task + Dim input = + + + ([|TParam|] parameter) + { + } + } +} + ]]> + + + Await TestAPIAndFeature(input) + End Function + + + + Public Async Function TestCSharp_LocalFunctionTypeParameter2() As Task + Dim input = + + + ([|TPa$$ram|] parameter) + { + } + } +} + ]]> + + + Await TestAPIAndFeature(input) + End Function + + + + Public Async Function TestCSharp_LocalFunctionTypeParameter3() As Task + Dim input = + + + () + { + void local([|TPa$$ram|] parameter) + { + } + } +} + ]]> + + + Await TestAPIAndFeature(input) + End Function + + + + Public Async Function TestCSharp_LocalFunctionTypeParameter4() As Task + Dim input = + + + () + { + void local([|TParam|] parameter) + { + } + } +} + ]]> + + + Await TestAPIAndFeature(input) + End Function + Public Async Function TestTypeParameter2() As Task Dim input =