提交 a6a51c25 编写于 作者: C CyrusNajmabadi

Merge pull request #11237 from CyrusNajmabadi/betterGenerateMethodInference

Do a better job inferring where type parameters will be used when generating methods.

Fixes #11141
......@@ -867,8 +867,25 @@ public async Task TestUnmentionableTypeParameter6()
public async Task TestUnmentionableTypeParameter7()
{
await TestAsync(
@"class H < T > { void A ( T t1 ) { t1 = [|Foo < T >|] ( t1 ) ; } } ",
@"using System; class H < T > { void A ( T t1 ) { t1 = Foo < T > ( t1 ) ; } private T Foo < T1 > ( T t1 ) { throw new NotImplementedException ( ) ; } } ");
@"class H < T >
{
void A ( T t1 )
{
t1 = [|Foo < T >|] ( t1 ) ;
}
} ",
@"using System;
class H < T >
{
void A ( T t1 )
{
t1 = Foo < T > ( t1 ) ;
}
private T1 Foo < T1 > ( T1 t1 )
{
throw new NotImplementedException ( ) ;
}
} ");
}
[WorkItem(539593, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539593")]
......@@ -1006,8 +1023,19 @@ public async Task TestInTopLevelMethod()
public async Task TestLambdaReturnType()
{
await TestAsync(
@"using System ; class C < T , R > { private static Func < T , R > g = null ; private static Func < T , R > f = ( T ) => { return [|Foo < T , R >|] ( g ) ; } ; } ",
@"using System ; class C < T , R > { private static Func < T , R > g = null ; private static Func < T , R > f = ( T ) => { return Foo < T , R > ( g ) ; } ; private static R Foo < T1 , T2 > ( Func < T , R > g ) { throw new NotImplementedException ( ) ; } } ");
@"using System ;
class C < T , R >
{
private static Func < T , R > g = null ;
private static Func < T , R > f = ( T ) => { return [|Foo < T , R >|] ( g ) ; } ;
} ",
@"using System ;
class C < T , R >
{
private static Func < T , R > g = null ;
private static Func < T , R > f = ( T ) => { return Foo < T , R > ( g ) ; } ;
private static T2 Foo < T1 , T2 > ( Func < T1 , T2 > g ) { throw new NotImplementedException ( ) ; }
} ");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
......@@ -2919,6 +2947,38 @@ public static class Ex
");
}
[WorkItem(11141, "https://github.com/dotnet/roslyn/issues/11141")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
public async Task InferTypeParameters1()
{
await TestAsync(
@"using System;
class C
{
void M()
{
List<int> list = null;
int i = [|First<int>(list)|];
}
}",
@"using System;
class C
{
void M()
{
List<int> list = null;
int i = First<int>(list);
}
private T First<T>(List<T> list)
{
throw new NotImplementedException();
}
}");
}
public class GenerateConversionTest : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override Tuple<DiagnosticAnalyzer, CodeFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
......
......@@ -1337,7 +1337,7 @@ Class M1
sub1(Of Integer, String)(New Integer() {1, 2, 3}, New String() {"a", "b"})
End Sub
Private Sub sub1(Of T1, T2)(v1() As Integer, v2() As String)
Private Sub sub1(Of T1, T2)(v1() As T1, v2() As T2)
Throw New NotImplementedException()
End Sub
End Class
......
......@@ -169,6 +169,22 @@ protected override bool IsImplicitReferenceConversion(Compilation compilation, I
var conversion = compilation.ClassifyConversion(sourceType, targetType);
return conversion.IsImplicit && conversion.IsReference;
}
protected override IList<ITypeSymbol> DetermineTypeArguments(CancellationToken cancellationToken)
{
var result = new List<ITypeSymbol>();
if (State.SimpleNameOpt is GenericNameSyntax)
{
foreach (var typeArgument in ((GenericNameSyntax)State.SimpleNameOpt).TypeArgumentList.Arguments)
{
var type = this.Document.SemanticModel.GetTypeInfo(typeArgument, cancellationToken).Type;
result.Add(type);
}
}
return result;
}
}
}
}
......@@ -24,14 +24,14 @@ protected AbstractInvocationInfo(SemanticDocument document, State state)
{
}
public override IList<ITypeParameterSymbol> DetermineTypeParameters(
protected override IList<ITypeParameterSymbol> DetermineTypeParametersWorker(
CancellationToken cancellationToken)
{
var typeParameters = DetermineTypeParametersWorker(cancellationToken);
var typeParameters = ComputeTypeParameters(cancellationToken);
return typeParameters.Select(tp => MassageTypeParameter(tp, cancellationToken)).ToList();
}
private IList<ITypeParameterSymbol> DetermineTypeParametersWorker(
private IList<ITypeParameterSymbol> ComputeTypeParameters(
CancellationToken cancellationToken)
{
if (IsIdentifierName())
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember
{
......@@ -32,7 +34,7 @@ protected override ITypeSymbol DetermineReturnTypeWorker(CancellationToken cance
return _methodSymbol.ReturnType;
}
public override IList<ITypeParameterSymbol> DetermineTypeParameters(CancellationToken cancellationToken)
protected override IList<ITypeParameterSymbol> DetermineTypeParametersWorker(CancellationToken cancellationToken)
{
return _methodSymbol.TypeParameters;
}
......@@ -56,6 +58,11 @@ protected override IList<string> DetermineParameterNames(CancellationToken cance
{
return _methodSymbol.Parameters.Select(p => p.Name).ToList();
}
protected override IList<ITypeSymbol> DetermineTypeArguments(CancellationToken cancellationToken)
{
return SpecializedCollections.EmptyList<ITypeSymbol>();
}
}
}
}
......@@ -21,6 +21,8 @@ internal abstract class SignatureInfo
{
protected readonly SemanticDocument Document;
protected readonly State State;
private IList<ITypeParameterSymbol> _typeParameters;
private IDictionary<ITypeSymbol, ITypeParameterSymbol> _typeArgumentToTypeParameterMap;
public SignatureInfo(
SemanticDocument document,
......@@ -30,12 +32,19 @@ internal abstract class SignatureInfo
this.State = state;
}
public abstract IList<ITypeParameterSymbol> DetermineTypeParameters(CancellationToken cancellationToken);
public IList<ITypeParameterSymbol> DetermineTypeParameters(CancellationToken cancellationToken)
{
return _typeParameters ?? (_typeParameters = DetermineTypeParametersWorker(cancellationToken));
}
protected abstract IList<ITypeParameterSymbol> DetermineTypeParametersWorker(CancellationToken cancellationToken);
public ITypeSymbol DetermineReturnType(CancellationToken cancellationToken)
{
return FixType(DetermineReturnTypeWorker(cancellationToken), cancellationToken);
}
protected abstract IList<ITypeSymbol> DetermineTypeArguments(CancellationToken cancellationToken);
protected abstract ITypeSymbol DetermineReturnTypeWorker(CancellationToken cancellationToken);
protected abstract IList<RefKind> DetermineParameterModifiers(CancellationToken cancellationToken);
protected abstract IList<ITypeSymbol> DetermineParameterTypes(CancellationToken cancellationToken);
......@@ -115,10 +124,38 @@ public ITypeSymbol DetermineReturnType(CancellationToken cancellationToken)
var compilation = this.Document.SemanticModel.Compilation;
var allTypeParameters = availableMethodTypeParameters.Concat(availableTypeParameters);
var typeArgumentToTypeParameterMap = this.GetTypeArgumentToTypeParameterMap(cancellationToken);
return typeSymbol.RemoveAnonymousTypes(compilation)
.ReplaceTypeParametersBasedOnTypeConstraints(compilation, allTypeParameters, this.Document.Document.Project.Solution, cancellationToken)
.RemoveUnavailableTypeParameters(compilation, allTypeParameters)
.RemoveUnnamedErrorTypes(compilation);
.RemoveUnnamedErrorTypes(compilation)
.SubstituteTypes(typeArgumentToTypeParameterMap, new TypeGenerator());
}
private IDictionary<ITypeSymbol, ITypeParameterSymbol> GetTypeArgumentToTypeParameterMap(
CancellationToken cancellationToken)
{
return _typeArgumentToTypeParameterMap ?? (_typeArgumentToTypeParameterMap = CreateTypeArgumentToTypeParameterMap(cancellationToken));
}
private IDictionary<ITypeSymbol, ITypeParameterSymbol> CreateTypeArgumentToTypeParameterMap(
CancellationToken cancellationToken)
{
var typeArguments = this.DetermineTypeArguments(cancellationToken);
var typeParameters = this.DetermineTypeParameters(cancellationToken);
var result = new Dictionary<ITypeSymbol, ITypeParameterSymbol>();
for(var i = 0; i < typeArguments.Count; i++)
{
if (typeArguments[i] != null)
{
result[typeArguments[i]] = typeParameters[i];
}
}
return result;
}
private IList<SyntaxNode> GenerateStatements(
......
......@@ -157,6 +157,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateMethod
Dim conversion = compilation.ClassifyConversion(sourceType, targetType)
Return conversion.IsWidening AndAlso conversion.IsReference
End Function
Protected Overrides Function DetermineTypeArguments(cancellationToken As CancellationToken) As IList(Of ITypeSymbol)
Dim Result = New List(Of ITypeSymbol)()
If TypeOf State.SimpleNameOpt Is GenericNameSyntax Then
For Each typeArgument In DirectCast(State.SimpleNameOpt, GenericNameSyntax).TypeArgumentList.Arguments
Dim Type = Me.Document.SemanticModel.GetTypeInfo(typeArgument, cancellationToken).Type
Result.Add(Type)
Next
End If
Return Result
End Function
End Class
End Class
End Namespace
......@@ -45,7 +45,7 @@ private ITypeSymbol VisitType(ITypeSymbol symbol)
public override ITypeSymbol VisitDynamicType(IDynamicTypeSymbol symbol)
{
return symbol;
return VisitType(symbol);
}
public override ITypeSymbol VisitTypeParameter(ITypeParameterSymbol symbol)
......@@ -55,6 +55,12 @@ public override ITypeSymbol VisitTypeParameter(ITypeParameterSymbol symbol)
public override ITypeSymbol VisitNamedType(INamedTypeSymbol symbol)
{
var mapped = VisitType(symbol);
if (mapped != symbol)
{
return mapped;
}
if (symbol.IsAnonymousType)
{
return symbol;
......@@ -89,6 +95,12 @@ public override ITypeSymbol VisitNamedType(INamedTypeSymbol symbol)
public override ITypeSymbol VisitArrayType(IArrayTypeSymbol symbol)
{
var mapped = VisitType(symbol);
if (mapped != symbol)
{
return mapped;
}
var elementType = symbol.ElementType.Accept(this);
if (elementType != null && elementType.Equals(symbol.ElementType))
{
......@@ -100,6 +112,12 @@ public override ITypeSymbol VisitArrayType(IArrayTypeSymbol symbol)
public override ITypeSymbol VisitPointerType(IPointerTypeSymbol symbol)
{
var mapped = VisitType(symbol);
if (mapped != symbol)
{
return mapped;
}
var pointedAtType = symbol.PointedAtType.Accept(this);
if (pointedAtType != null && pointedAtType.Equals(symbol.PointedAtType))
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册