Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
a7294b31
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,发现更多精彩内容 >>
未验证
提交
a7294b31
编写于
10月 12, 2018
作者:
S
Sam Harwell
提交者:
GitHub
10月 12, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #30470 from Neme12/useLocalFunctionSemantics
Fix for UseLocalFunction breaking semantics
上级
2f18894d
34921ac1
变更
3
显示空白变更内容
内联
并排
Showing
3 changed file
with
245 addition
and
27 deletion
+245
-27
src/EditorFeatures/CSharpTest/UseLocalFunction/UseLocalFunctionTests.cs
...ures/CSharpTest/UseLocalFunction/UseLocalFunctionTests.cs
+207
-0
src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs
...UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs
+26
-19
src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionDiagnosticAnalyzer.cs
...LocalFunction/CSharpUseLocalFunctionDiagnosticAnalyzer.cs
+12
-8
未找到文件。
src/EditorFeatures/CSharpTest/UseLocalFunction/UseLocalFunctionTests.cs
浏览文件 @
a7294b31
...
...
@@ -3100,6 +3100,213 @@ public void Caller()
U local(U x) => x;
Callee(local);
}
}"
);
}
[
WorkItem
(
26526
,
"https://github.com/dotnet/roslyn/issues/26526"
)]
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseLocalFunction
)]
public
async
Task
TestAvailableWithCastIntroducedIfAssignedToVar
()
{
await
TestInRegularAndScript1Async
(
@"using System;
class C
{
void M()
{
Func<string> [||]f = () => null;
var f2 = f;
}
}"
,
@"using System;
class C
{
void M()
{
string f() => null;
var f2 = (Func<string>)f;
}
}"
);
}
[
WorkItem
(
26526
,
"https://github.com/dotnet/roslyn/issues/26526"
)]
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseLocalFunction
)]
public
async
Task
TestAvailableWithCastIntroducedForGenericTypeInference1
()
{
await
TestInRegularAndScript1Async
(
@"using System;
class C
{
void M()
{
Func<int, string> [||]f = _ => null;
Method(f);
}
void Method<T>(Func<T, string> o)
{
}
}"
,
@"using System;
class C
{
void M()
{
string f(int _) => null;
Method((Func<int, string>)f);
}
void Method<T>(Func<T, string> o)
{
}
}"
);
}
[
WorkItem
(
26526
,
"https://github.com/dotnet/roslyn/issues/26526"
)]
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseLocalFunction
)]
public
async
Task
TestAvailableWithCastIntroducedForGenericTypeInference2
()
{
await
TestInRegularAndScript1Async
(
@"using System;
class C
{
void M()
{
Func<int, string> [||]f = _ => null;
Method(f);
}
void Method<T>(Func<T, string> o)
{
}
void Method(string o)
{
}
}"
,
@"using System;
class C
{
void M()
{
string f(int _) => null;
Method((Func<int, string>)f);
}
void Method<T>(Func<T, string> o)
{
}
void Method(string o)
{
}
}"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseLocalFunction
)]
public
async
Task
TestAvailableWithCastIntroducedForOverloadResolution
()
{
await
TestInRegularAndScript1Async
(
@"using System;
delegate string CustomDelegate();
class C
{
void M()
{
Func<string> [||]f = () => null;
Method(f);
}
void Method(Func<string> o)
{
}
void Method(CustomDelegate o)
{
}
}"
,
@"using System;
delegate string CustomDelegate();
class C
{
void M()
{
string f() => null;
Method((Func<string>)f);
}
void Method(Func<string> o)
{
}
void Method(CustomDelegate o)
{
}
}"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseLocalFunction
)]
public
async
Task
TestAvailableWithoutCastIfUnnecessaryForOverloadResolution
()
{
await
TestInRegularAndScript1Async
(
@"using System;
delegate string CustomDelegate(object arg);
class C
{
void M()
{
Func<string> [||]f = () => null;
Method(f);
}
void Method(Func<string> o)
{
}
void Method(CustomDelegate o)
{
}
}"
,
@"using System;
delegate string CustomDelegate(object arg);
class C
{
void M()
{
string f() => null;
Method(f);
}
void Method(Func<string> o)
{
}
void Method(CustomDelegate o)
{
}
}"
);
}
}
...
...
src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs
浏览文件 @
a7294b31
...
...
@@ -49,7 +49,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
var
nodesFromDiagnostics
=
new
List
<(
LocalDeclarationStatementSyntax
declaration
,
AnonymousFunctionExpressionSyntax
function
,
List
<
InvocationExpressionSyntax
>
invocation
s
)>(
diagnostics
.
Length
);
List
<
ExpressionSyntax
>
reference
s
)>(
diagnostics
.
Length
);
var
nodesToTrack
=
new
HashSet
<
SyntaxNode
>();
...
...
@@ -58,18 +58,18 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
var
localDeclaration
=
(
LocalDeclarationStatementSyntax
)
diagnostic
.
AdditionalLocations
[
0
].
FindNode
(
cancellationToken
);
var
anonymousFunction
=
(
AnonymousFunctionExpressionSyntax
)
diagnostic
.
AdditionalLocations
[
1
].
FindNode
(
cancellationToken
);
var
invocations
=
new
List
<
Invocation
ExpressionSyntax
>(
diagnostic
.
AdditionalLocations
.
Count
-
2
);
var
references
=
new
List
<
ExpressionSyntax
>(
diagnostic
.
AdditionalLocations
.
Count
-
2
);
for
(
var
i
=
2
;
i
<
diagnostic
.
AdditionalLocations
.
Count
;
i
++)
{
invocations
.
Add
((
Invocation
ExpressionSyntax
)
diagnostic
.
AdditionalLocations
[
i
].
FindNode
(
getInnermostNodeForTie
:
true
,
cancellationToken
));
references
.
Add
((
ExpressionSyntax
)
diagnostic
.
AdditionalLocations
[
i
].
FindNode
(
getInnermostNodeForTie
:
true
,
cancellationToken
));
}
nodesFromDiagnostics
.
Add
((
localDeclaration
,
anonymousFunction
,
invocation
s
));
nodesFromDiagnostics
.
Add
((
localDeclaration
,
anonymousFunction
,
reference
s
));
nodesToTrack
.
Add
(
localDeclaration
);
nodesToTrack
.
Add
(
anonymousFunction
);
nodesToTrack
.
AddRange
(
invocation
s
);
nodesToTrack
.
AddRange
(
reference
s
);
}
var
root
=
editor
.
OriginalRoot
;
...
...
@@ -77,7 +77,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
// Process declarations in reverse order so that we see the effects of nested
// declarations befor processing the outer decls.
foreach
(
var
(
localDeclaration
,
anonymousFunction
,
invocation
s
)
in
nodesFromDiagnostics
.
OrderByDescending
(
nodes
=>
nodes
.
function
.
SpanStart
))
foreach
(
var
(
localDeclaration
,
anonymousFunction
,
reference
s
)
in
nodesFromDiagnostics
.
OrderByDescending
(
nodes
=>
nodes
.
function
.
SpanStart
))
{
var
delegateType
=
(
INamedTypeSymbol
)
semanticModel
.
GetTypeInfo
(
anonymousFunction
,
cancellationToken
).
ConvertedType
;
var
parameterList
=
GenerateParameterList
(
anonymousFunction
,
delegateType
.
DelegateInvokeMethod
);
...
...
@@ -91,10 +91,10 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
delegateType
.
DelegateInvokeMethod
,
parameterList
);
// these invocations might actually be inside the local function! so we have to do this separately
currentRoot
=
Replace
Invocation
s
(
document
.
Project
.
Solution
.
Workspace
,
currentRoot
,
delegateType
.
DelegateInvokeMethod
,
parameterList
,
invocation
s
.
Select
(
node
=>
currentRoot
.
GetCurrentNode
(
node
)).
ToImmutableArray
());
currentRoot
=
Replace
Reference
s
(
document
,
currentRoot
,
delegateType
,
parameterList
,
reference
s
.
Select
(
node
=>
currentRoot
.
GetCurrentNode
(
node
)).
ToImmutableArray
());
}
editor
.
ReplaceNode
(
root
,
currentRoot
);
...
...
@@ -123,18 +123,25 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
return
editor
.
GetChangedRoot
();
}
private
static
SyntaxNode
ReplaceInvocations
(
Workspace
workspace
,
SyntaxNode
currentRoot
,
IMethodSymbol
delegateMethod
,
ParameterListSyntax
parameterList
,
ImmutableArray
<
InvocationExpressionSyntax
>
invocations
)
private
static
SyntaxNode
ReplaceReferences
(
Document
document
,
SyntaxNode
currentRoot
,
INamedTypeSymbol
delegateType
,
ParameterListSyntax
parameterList
,
ImmutableArray
<
ExpressionSyntax
>
references
)
{
return
currentRoot
.
ReplaceNodes
(
references
,
(
_
/* nested invocations! */
,
reference
)
=>
{
return
currentRoot
.
ReplaceNodes
(
invocations
,
(
_
/* nested invocations! */
,
invocation
)
=>
if
(
reference
is
InvocationExpressionSyntax
invocation
)
{
var
directInvocation
=
invocation
.
Expression
is
MemberAccessExpressionSyntax
memberAccessExpression
// it's a .Invoke call
?
invocation
.
WithExpression
(
memberAccessExpression
.
Expression
).
WithTriviaFrom
(
invocation
)
// remove it
var
directInvocation
=
invocation
.
Expression
is
MemberAccessExpressionSyntax
memberAccess
// it's a .Invoke call
?
invocation
.
WithExpression
(
memberAccess
.
Expression
).
WithTriviaFrom
(
invocation
)
// remove it
:
invocation
;
return
WithNewParameterNames
(
directInvocation
,
delegateMethod
,
parameterList
);
return
WithNewParameterNames
(
directInvocation
,
delegateType
.
DelegateInvokeMethod
,
parameterList
);
}
// It's not an invocation. Wrap the identifier in a cast (which will be remove by the simplifier if unnecessary)
// to ensure we preserve semantics in cases like overload resolution or generic type inference.
return
SyntaxGenerator
.
GetGenerator
(
document
).
CastExpression
(
delegateType
,
reference
);
});
}
...
...
src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionDiagnosticAnalyzer.cs
浏览文件 @
a7294b31
...
...
@@ -120,7 +120,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp
return
;
}
if
(!
CanReplaceAnonymousWithLocalFunction
(
semanticModel
,
expressionTypeOpt
,
local
,
block
,
anonymousFunction
,
out
var
invocation
Locations
,
cancellationToken
))
if
(!
CanReplaceAnonymousWithLocalFunction
(
semanticModel
,
expressionTypeOpt
,
local
,
block
,
anonymousFunction
,
out
var
reference
Locations
,
cancellationToken
))
{
return
;
}
...
...
@@ -130,7 +130,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp
localDeclaration
.
GetLocation
(),
anonymousFunction
.
GetLocation
());
additionalLocations
=
additionalLocations
.
AddRange
(
invocation
Locations
);
additionalLocations
=
additionalLocations
.
AddRange
(
reference
Locations
);
if
(
severity
.
WithDefaultSeverity
(
DiagnosticSeverity
.
Hidden
)
<
ReportDiagnostic
.
Hidden
)
{
...
...
@@ -209,12 +209,12 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp
private
bool
CanReplaceAnonymousWithLocalFunction
(
SemanticModel
semanticModel
,
INamedTypeSymbol
expressionTypeOpt
,
ISymbol
local
,
BlockSyntax
block
,
AnonymousFunctionExpressionSyntax
anonymousFunction
,
out
ImmutableArray
<
Location
>
invocation
Locations
,
CancellationToken
cancellationToken
)
AnonymousFunctionExpressionSyntax
anonymousFunction
,
out
ImmutableArray
<
Location
>
reference
Locations
,
CancellationToken
cancellationToken
)
{
// Check all the references to the anonymous function and disallow the conversion if
// they're used in certain ways.
var
invocation
s
=
ArrayBuilder
<
Location
>.
GetInstance
();
invocation
Locations
=
ImmutableArray
<
Location
>.
Empty
;
var
reference
s
=
ArrayBuilder
<
Location
>.
GetInstance
();
reference
Locations
=
ImmutableArray
<
Location
>.
Empty
;
var
anonymousFunctionStart
=
anonymousFunction
.
SpanStart
;
foreach
(
var
descendentNode
in
block
.
DescendantNodes
())
{
...
...
@@ -248,14 +248,14 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp
if
(
nodeToCheck
.
Parent
is
InvocationExpressionSyntax
invocationExpression
)
{
invocation
s
.
Add
(
invocationExpression
.
GetLocation
());
reference
s
.
Add
(
invocationExpression
.
GetLocation
());
}
else
if
(
nodeToCheck
.
Parent
is
MemberAccessExpressionSyntax
memberAccessExpression
)
{
if
(
memberAccessExpression
.
Parent
is
InvocationExpressionSyntax
explicitInvocationExpression
&&
memberAccessExpression
.
Name
.
Identifier
.
ValueText
==
WellKnownMemberNames
.
DelegateInvokeName
)
{
invocation
s
.
Add
(
explicitInvocationExpression
.
GetLocation
());
reference
s
.
Add
(
explicitInvocationExpression
.
GetLocation
());
}
else
{
...
...
@@ -264,6 +264,10 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp
return
false
;
}
}
else
{
references
.
Add
(
nodeToCheck
.
GetLocation
());
}
var
convertedType
=
semanticModel
.
GetTypeInfo
(
nodeToCheck
,
cancellationToken
).
ConvertedType
;
if
(!
convertedType
.
IsDelegateType
())
...
...
@@ -284,7 +288,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp
}
}
invocationLocations
=
invocation
s
.
ToImmutableAndFree
();
referenceLocations
=
reference
s
.
ToImmutableAndFree
();
return
true
;
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录