Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
1b61db95
R
roslyn
项目概览
lwm1986
/
roslyn
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
roslyn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
1b61db95
编写于
3月 08, 2020
作者:
C
Cyrus Najmabadi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Do not convert to 'var' if it would change tuple names
上级
153fec7d
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
157 addition
and
62 deletion
+157
-62
src/Analyzers/CSharp/Tests/UseImplicitOrExplicitType/UseImplicitTypeTests.cs
...p/Tests/UseImplicitOrExplicitType/UseImplicitTypeTests.cs
+66
-0
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs
...CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs
+46
-16
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs
...Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs
+2
-1
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs
...ions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs
+43
-45
未找到文件。
src/Analyzers/CSharp/Tests/UseImplicitOrExplicitType/UseImplicitTypeTests.cs
浏览文件 @
1b61db95
...
...
@@ -2664,5 +2664,71 @@ void M()
}
}"
,
options
:
ImplicitTypeEverywhere
());
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseExplicitType
)]
[
WorkItem
(
32088
,
"https://github.com/dotnet/roslyn/issues/32088"
)]
public
async
Task
DoNotSuggestVarOnDeclarationExpressionWithInferredTupleNames
()
{
await
TestMissingAsync
(
@"
using System.Collections.Generic;
using System.Linq;
static class Program
{
static void Main(string[] args)
{
if (!_data.TryGetValue(0, [|out List<(int X, int Y)>|] value))
return;
var x = value.FirstOrDefault().X;
}
private static Dictionary<int, List<(int, int)>> _data =
new Dictionary<int, List<(int, int)>>();
}"
,
parameters
:
new
TestParameters
(
options
:
ImplicitTypeEverywhere
()));
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseExplicitType
)]
[
WorkItem
(
32088
,
"https://github.com/dotnet/roslyn/issues/32088"
)]
public
async
Task
DoSuggestVarOnDeclarationExpressionWithMatchingTupleNames
()
{
await
TestInRegularAndScriptAsync
(
@"
using System.Collections.Generic;
using System.Linq;
static class Program
{
static void Main(string[] args)
{
if (!_data.TryGetValue(0, [|out List<(int X, int Y)>|] value))
return;
var x = value.FirstOrDefault().X;
}
private static Dictionary<int, List<(int X, int Y)>> _data =
new Dictionary<int, List<(int, int)>>();
}"
,
@"
using System.Collections.Generic;
using System.Linq;
static class Program
{
static void Main(string[] args)
{
if (!_data.TryGetValue(0, out var value))
return;
var x = value.FirstOrDefault().X;
}
private static Dictionary<int, List<(int X, int Y)>> _data =
new Dictionary<int, List<(int, int)>>();
}"
,
options
:
ImplicitTypeEverywhere
());
}
}
}
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs
浏览文件 @
1b61db95
...
...
@@ -11,6 +11,9 @@
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.CodeAnalysis.Shared.Utilities
;
using
Microsoft.CodeAnalysis.Simplification
;
using
System
;
using
Microsoft.CodeAnalysis.Operations
;
using
Roslyn.Utilities
;
#if CODE_STYLE
using
OptionSet
=
Microsoft
.
CodeAnalysis
.
Diagnostics
.
AnalyzerConfigOptions
;
...
...
@@ -160,7 +163,7 @@ protected override bool IsStylePreferred(in State state)
}
}
else
if
(
typeName
.
Parent
is
DeclarationExpressionSyntax
declarationExpression
&&
TryAnalyzeDeclarationExpression
(
declarationExpression
,
semanticModel
,
optionSet
,
cancellationToken
))
TryAnalyzeDeclarationExpression
(
declarationExpression
,
semanticModel
,
cancellationToken
))
{
return
true
;
}
...
...
@@ -171,7 +174,6 @@ protected override bool IsStylePreferred(in State state)
private
bool
TryAnalyzeDeclarationExpression
(
DeclarationExpressionSyntax
declarationExpression
,
SemanticModel
semanticModel
,
OptionSet
optionSet
,
CancellationToken
cancellationToken
)
{
// It's not always safe to convert a decl expression like "Method(out int i)" to
...
...
@@ -180,21 +182,9 @@ protected override bool IsStylePreferred(in State state)
// Note: this is fairly expensive, so we try to avoid this if we can by seeing if
// there are multiple candidates with the original call. If not, then we don't
// have to do anything.
if
(
declarationExpression
.
Parent
is
ArgumentSyntax
argument
&&
argument
.
Parent
is
ArgumentListSyntax
argumentList
&&
argumentList
.
Parent
is
InvocationExpressionSyntax
invocationExpression
)
if
(
IsMatchingArgToSimpleMethod
(
declarationExpression
,
semanticModel
,
cancellationToken
))
{
// If there was only one member in the group, and it was non-generic itself,
// then this change is safe to make without doing any complex analysis.
// Multiple methods mean that switching to 'var' might remove information
// that affects overload resolution. And if the method is generic, then
// switching to 'var' may mean that inference might not work properly.
var
memberGroup
=
semanticModel
.
GetMemberGroup
(
invocationExpression
.
Expression
,
cancellationToken
);
if
(
memberGroup
.
Length
==
1
&&
memberGroup
[
0
].
GetTypeParameters
().
IsEmpty
)
{
return
true
;
}
return
true
;
}
if
(!
semanticModel
.
SyntaxTree
.
HasCompilationUnitRoot
)
...
...
@@ -228,6 +218,46 @@ protected override bool IsStylePreferred(in State state)
return
SymbolEquivalenceComparer
.
Instance
.
Equals
(
declarationType
,
newDeclarationType
);
}
private
bool
IsMatchingArgToSimpleMethod
(
DeclarationExpressionSyntax
declarationExpression
,
SemanticModel
semanticModel
,
CancellationToken
cancellationToken
)
{
if
(!(
declarationExpression
.
Parent
is
ArgumentSyntax
argument
)
||
!(
argument
.
Parent
is
ArgumentListSyntax
argumentList
)
||
!(
argumentList
.
Parent
is
InvocationExpressionSyntax
invocationExpression
))
return
false
;
// If there was only one member in the group, and it was non-generic itself,
// then this change is safe to make without doing any complex analysis.
// Multiple methods mean that switching to 'var' might remove information
// that affects overload resolution. And if the method is generic, then
// switching to 'var' may mean that inference might not work properly.
var
memberGroup
=
semanticModel
.
GetMemberGroup
(
invocationExpression
.
Expression
,
cancellationToken
);
if
(
memberGroup
.
Length
!=
1
)
return
false
;
var
method
=
memberGroup
[
0
]
as
IMethodSymbol
;
if
(
method
==
null
)
return
false
;
if
(!
method
.
GetTypeParameters
().
IsEmpty
)
return
false
;
var
invocationOp
=
semanticModel
.
GetOperation
(
invocationExpression
)
as
IInvocationOperation
;
if
(
invocationOp
==
null
)
return
false
;
var
argumentOp
=
invocationOp
.
Arguments
.
FirstOrDefault
(
a
=>
a
.
Syntax
==
argument
);
if
(
argumentOp
==
null
)
return
false
;
if
(
argumentOp
.
Value
?.
Type
==
null
)
return
false
;
if
(
argumentOp
.
Parameter
?.
Type
==
null
)
return
false
;
return
argumentOp
.
Value
.
Type
.
Equals
(
argumentOp
.
Parameter
.
Type
);
}
/// <summary>
/// Analyzes the assignment expression and rejects a given declaration if it is unsuitable for implicit typing.
/// </summary>
...
...
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs
浏览文件 @
1b61db95
...
...
@@ -24,7 +24,8 @@ private class EquivalenceVisitor
public
EquivalenceVisitor
(
SymbolEquivalenceComparer
symbolEquivalenceComparer
,
bool
compareMethodTypeParametersByIndex
,
bool
objectAndDynamicCompareEqually
)
bool
objectAndDynamicCompareEqually
,
bool
tupleNamesMustMatch
)
{
_symbolEquivalenceComparer
=
symbolEquivalenceComparer
;
_compareMethodTypeParametersByIndex
=
compareMethodTypeParametersByIndex
;
...
...
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs
浏览文件 @
1b61db95
...
...
@@ -39,39 +39,48 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities
internal
partial
class
SymbolEquivalenceComparer
:
IEqualityComparer
<
ISymbol
>
{
private
readonly
ImmutableArray
<
EquivalenceVisitor
>
_equivalenceVisitors
;
private
readonly
ImmutableArray
<
GetHashCodeVisitor
>
_getHashCodeVisitors
;
private
readonly
EquivalenceVisitor
[]
_equivalenceVisitors
;
private
readonly
GetHashCodeVisitor
[]
_getHashCodeVisitors
;
public
static
readonly
SymbolEquivalenceComparer
Instance
=
new
SymbolEquivalenceComparer
(
SimpleNameAssemblyComparer
.
Instance
,
distinguishRefFromOut
:
false
);
public
static
readonly
SymbolEquivalenceComparer
IgnoreAssembliesInstance
=
new
SymbolEquivalenceComparer
(
assemblyComparerOpt
:
null
,
distinguishRefFromOut
:
false
);
public
static
readonly
SymbolEquivalenceComparer
Instance
=
new
SymbolEquivalenceComparer
(
SimpleNameAssemblyComparer
.
Instance
,
distinguishRefFromOut
:
false
,
tupleNamesMustMatch
:
false
);
public
static
readonly
SymbolEquivalenceComparer
TupleNamesMustMatchInstance
=
new
SymbolEquivalenceComparer
(
SimpleNameAssemblyComparer
.
Instance
,
distinguishRefFromOut
:
false
,
tupleNamesMustMatch
:
true
);
public
static
readonly
SymbolEquivalenceComparer
IgnoreAssembliesInstance
=
new
SymbolEquivalenceComparer
(
assemblyComparerOpt
:
null
,
distinguishRefFromOut
:
false
,
tupleNamesMustMatch
:
false
);
private
readonly
IEqualityComparer
<
IAssemblySymbol
>
_assemblyComparerOpt
;
public
ParameterSymbolEqualityComparer
ParameterEquivalenceComparer
{
get
;
}
public
SignatureTypeSymbolEquivalenceComparer
SignatureTypeEquivalenceComparer
{
get
;
}
internal
SymbolEquivalenceComparer
(
IEqualityComparer
<
IAssemblySymbol
>
assemblyComparerOpt
,
bool
distinguishRefFromOut
)
internal
SymbolEquivalenceComparer
(
IEqualityComparer
<
IAssemblySymbol
>
assemblyComparerOpt
,
bool
distinguishRefFromOut
,
bool
tupleNamesMustMatch
)
{
_assemblyComparerOpt
=
assemblyComparerOpt
;
_tupleNamesMustMatch
=
this
.
ParameterEquivalenceComparer
=
new
ParameterSymbolEqualityComparer
(
this
,
distinguishRefFromOut
);
this
.
SignatureTypeEquivalenceComparer
=
new
SignatureTypeSymbolEquivalenceComparer
(
this
);
// There are only so many EquivalenceVisitors and GetHashCodeVisitors we can have.
// Create them all up front.
var
equivalenceVisitorsBuilder
=
ImmutableArray
.
CreateBuilder
<
EquivalenceVisitor
>();
equivalenceVisitorsBuilder
.
Add
(
new
EquivalenceVisitor
(
this
,
compareMethodTypeParametersByIndex
:
true
,
objectAndDynamicCompareEqually
:
true
));
equivalenceVisitorsBuilder
.
Add
(
new
EquivalenceVisitor
(
this
,
compareMethodTypeParametersByIndex
:
true
,
objectAndDynamicCompareEqually
:
false
));
equivalenceVisitorsBuilder
.
Add
(
new
EquivalenceVisitor
(
this
,
compareMethodTypeParametersByIndex
:
false
,
objectAndDynamicCompareEqually
:
true
));
equivalenceVisitorsBuilder
.
Add
(
new
EquivalenceVisitor
(
this
,
compareMethodTypeParametersByIndex
:
false
,
objectAndDynamicCompareEqually
:
false
));
_equivalenceVisitors
=
equivalenceVisitorsBuilder
.
ToImmutable
();
var
getHashCodeVisitorsBuilder
=
ImmutableArray
.
CreateBuilder
<
GetHashCodeVisitor
>();
getHashCodeVisitorsBuilder
.
Add
(
new
GetHashCodeVisitor
(
this
,
compareMethodTypeParametersByIndex
:
true
,
objectAndDynamicCompareEqually
:
true
));
getHashCodeVisitorsBuilder
.
Add
(
new
GetHashCodeVisitor
(
this
,
compareMethodTypeParametersByIndex
:
true
,
objectAndDynamicCompareEqually
:
false
));
getHashCodeVisitorsBuilder
.
Add
(
new
GetHashCodeVisitor
(
this
,
compareMethodTypeParametersByIndex
:
false
,
objectAndDynamicCompareEqually
:
true
));
getHashCodeVisitorsBuilder
.
Add
(
new
GetHashCodeVisitor
(
this
,
compareMethodTypeParametersByIndex
:
false
,
objectAndDynamicCompareEqually
:
false
));
_getHashCodeVisitors
=
getHashCodeVisitorsBuilder
.
ToImmutable
();
GetEquivalenceVisitor
(
false
,
false
,
false
);
GetEquivalenceVisitor
(
false
,
false
,
true
);
GetEquivalenceVisitor
(
false
,
true
,
false
);
GetEquivalenceVisitor
(
false
,
true
,
true
);
GetEquivalenceVisitor
(
true
,
false
,
false
);
GetEquivalenceVisitor
(
true
,
false
,
true
);
GetEquivalenceVisitor
(
true
,
true
,
false
);
GetEquivalenceVisitor
(
true
,
true
,
true
);
GetGetHashCodeVisitor
(
false
,
false
,
false
);
GetGetHashCodeVisitor
(
false
,
false
,
true
);
GetGetHashCodeVisitor
(
false
,
true
,
false
);
GetGetHashCodeVisitor
(
false
,
true
,
true
);
GetGetHashCodeVisitor
(
true
,
false
,
false
);
GetGetHashCodeVisitor
(
true
,
false
,
true
);
GetGetHashCodeVisitor
(
true
,
true
,
false
);
GetGetHashCodeVisitor
(
true
,
true
,
true
);
}
// Very subtle logic here. When checking if two parameters are the same, we can end up with
...
...
@@ -82,44 +91,33 @@ internal SymbolEquivalenceComparer(IEqualityComparer<IAssemblySymbol> assemblyCo
// here. So, instead, when asking if parameters are equal, we pass an appropriate flag so
// that method type parameters are just compared by index and nothing else.
private
EquivalenceVisitor
GetEquivalenceVisitor
(
bool
compareMethodTypeParametersByIndex
=
false
,
bool
objectAndDynamicCompareEqually
=
false
)
bool
compareMethodTypeParametersByIndex
=
false
,
bool
objectAndDynamicCompareEqually
=
false
,
bool
tupleNamesMustMatch
=
false
)
{
var
visitorIndex
=
GetVisitorIndex
(
compareMethodTypeParametersByIndex
,
objectAndDynamicCompareEqually
);
var
visitorIndex
=
GetVisitorIndex
(
compareMethodTypeParametersByIndex
,
objectAndDynamicCompareEqually
,
tupleNamesMustMatch
);
return
_equivalenceVisitors
[
visitorIndex
];
}
private
GetHashCodeVisitor
GetGetHashCodeVisitor
(
bool
compareMethodTypeParametersByIndex
,
bool
objectAndDynamicCompareEqually
)
bool
compareMethodTypeParametersByIndex
=
false
,
bool
objectAndDynamicCompareEqually
=
false
,
bool
tupleNamesMustMatch
=
false
)
{
var
visitorIndex
=
GetVisitorIndex
(
compareMethodTypeParametersByIndex
,
objectAndDynamicCompareEqually
);
var
visitorIndex
=
GetVisitorIndex
(
compareMethodTypeParametersByIndex
,
objectAndDynamicCompareEqually
,
tupleNamesMustMatch
);
return
_getHashCodeVisitors
[
visitorIndex
];
}
private
static
int
GetVisitorIndex
(
bool
compareMethodTypeParametersByIndex
,
bool
objectAndDynamicCompareEqually
)
bool
compareMethodTypeParametersByIndex
,
bool
objectAndDynamicCompareEqually
,
bool
tupleNamesMustMatch
)
{
if
(
compareMethodTypeParametersByIndex
)
{
if
(
objectAndDynamicCompareEqually
)
{
return
0
;
}
else
{
return
1
;
}
}
else
{
if
(
objectAndDynamicCompareEqually
)
{
return
2
;
}
else
{
return
3
;
}
}
return
((
compareMethodTypeParametersByIndex
?
1
:
0
)
<<
2
)
|
((
objectAndDynamicCompareEqually
?
1
:
0
)
<<
1
)
|
((
tupleNamesMustMatch
?
1
:
0
)
<<
0
);
}
public
bool
ReturnTypeEquals
(
IMethodSymbol
x
,
IMethodSymbol
y
,
Dictionary
<
INamedTypeSymbol
,
INamedTypeSymbol
>
equivalentTypesWithDifferingAssemblies
=
null
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录