Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
17a30872
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,发现更多精彩内容 >>
提交
17a30872
编写于
6月 28, 2019
作者:
P
Petr Houška
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
LambdaSimplifier moved to helper + improved unwrapper.
上级
6419779b
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
88 addition
and
20 deletion
+88
-20
src/EditorFeatures/CSharpTest/CodeActions/LambdaSimplifier/LambdaSimplifierTests.cs
...est/CodeActions/LambdaSimplifier/LambdaSimplifierTests.cs
+45
-0
src/Features/CSharp/Portable/CodeRefactorings/LambdaSimplifier/LambdaSimplifierCodeRefactoringProvider.cs
...mbdaSimplifier/LambdaSimplifierCodeRefactoringProvider.cs
+4
-3
src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs
...ble/CodeRefactorings/AbstractRefactoringHelpersService.cs
+27
-17
src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
...arp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
+2
-0
src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs
...anguageServices/SyntaxFactsService/ISyntaxFactsService.cs
+1
-0
src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
...ortable/LanguageServices/VisualBasicSyntaxFactsService.vb
+9
-0
未找到文件。
src/EditorFeatures/CSharpTest/CodeActions/LambdaSimplifier/LambdaSimplifierTests.cs
浏览文件 @
17a30872
...
...
@@ -557,6 +557,51 @@ static void Main()
}"
,
@"using System;
class Program
{
static void Main()
{
Action a = Console.WriteLine;
}
}"
);
}
[
WorkItem
(
35180
,
"https://github.com/dotnet/roslyn/issues/35180"
)]
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsLambdaSimplifier
)]
public
async
Task
TestMissingCaretPositionInside
()
{
await
TestMissingInRegularAndScriptAsync
(
@"using System;
class Program
{
static void Main()
{
Action a = () => {
Console.[||]WriteLine();
};
}
}"
);
}
[
WorkItem
(
35180
,
"https://github.com/dotnet/roslyn/issues/35180"
)]
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsLambdaSimplifier
)]
public
async
Task
TestCaretPosition
()
{
await
TestInRegularAndScriptAsync
(
@"using System;
class Program
{
static void Main()
{
[|Action a = () => {
Console.WriteLine();
};|]
}
}"
,
@"using System;
class Program
{
static void Main()
...
...
src/Features/CSharp/Portable/CodeRefactorings/LambdaSimplifier/LambdaSimplifierCodeRefactoringProvider.cs
浏览文件 @
17a30872
...
...
@@ -14,6 +14,7 @@
namespace
Microsoft.CodeAnalysis.CSharp.CodeRefactorings.LambdaSimplifier
{
// Disabled due to: https://github.com/dotnet/roslyn/issues/5835 & https://github.com/dotnet/roslyn/pull/6642
// [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.SimplifyLambda)]
internal
partial
class
LambdaSimplifierCodeRefactoringProvider
:
CodeRefactoringProvider
{
...
...
@@ -35,9 +36,9 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
var
semanticDocument
=
await
SemanticDocument
.
CreateAsync
(
document
,
cancellationToken
).
ConfigureAwait
(
false
);
var
lambda
=
semanticDocument
.
Root
.
FindToken
(
textSpan
.
Start
).
GetAncestor
(
n
=>
n
is
SimpleLambdaExpressionSyntax
||
n
is
ParenthesizedLambdaExpressionSyntax
);
if
(
lambda
==
null
||
!
lambda
.
Span
.
IntersectsWith
(
textSpan
.
Start
)
)
var
refactoringHelperService
=
document
.
GetLanguageService
<
IRefactoringHelpersService
>();
var
lambda
=
await
refactoringHelperService
.
TryGetSelectedNodeAsync
<
LambdaExpressionSyntax
>(
document
,
context
.
Span
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
lambda
==
null
)
{
return
;
}
...
...
src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs
浏览文件 @
17a30872
...
...
@@ -30,7 +30,7 @@ internal abstract class AbstractRefactoringHelpersService : IRefactoringHelpersS
/// - Whole node passing <paramref name="predicate"/> is selected.
/// </para>
/// <para>
/// Attempts extracting (and testing with <paramref name="predicate"/> a Node for each Node it consider
e
s (see above).
/// Attempts extracting (and testing with <paramref name="predicate"/> a Node for each Node it considers (see above).
/// By default extracts initializer expressions from declarations and assignments.
/// </para>
/// <para>
...
...
@@ -56,7 +56,7 @@ protected Task<SyntaxNode> TryGetSelectedNodeAsync(Document document, TextSpan s
/// </para>
/// <para>
/// The <paramref name="extractNode"/> enables testing with <paramref name="predicate"/> and potentially returning Nodes
/// that are under those that might be selected / considered (as described above). It is a <see cref="Func{SyntaxNode, SyntaxNode}"/> that
/// that are under
/above
those that might be selected / considered (as described above). It is a <see cref="Func{SyntaxNode, SyntaxNode}"/> that
/// should always return either given Node or a Node somewhere below it that should be tested with <paramref name="predicate"/> and
/// potentially returned instead of current Node.
/// </para>
...
...
@@ -68,8 +68,8 @@ protected Task<SyntaxNode> TryGetSelectedNodeAsync(Document document, TextSpan s
/// </summary>
protected
async
Task
<
SyntaxNode
>
TryGetSelectedNodeAsync
(
Document
document
,
TextSpan
selection
,
Predicate
<
SyntaxNode
>
predicate
,
Func
<
SyntaxNode
,
ISyntaxFactsService
,
SyntaxNode
>
extractNode
,
CancellationToken
cancellationToken
)
{
// Given selection is trimmed first to enable overselection that spans multiple lines. Since trailing whitespace ends
// at newline boundary overselection to e.g. a line after LocalFunctionStatement would cause FindNode to find enclosing
// Given selection is trimmed first to enable over
-
selection that spans multiple lines. Since trailing whitespace ends
// at newline boundary over
-
selection to e.g. a line after LocalFunctionStatement would cause FindNode to find enclosing
// block's Node. That is because in addition to LocalFunctionStatement the selection would also contain trailing trivia
// (whitespace) of following statement.
...
...
@@ -77,23 +77,23 @@ protected async Task<SyntaxNode> TryGetSelectedNodeAsync(Document document, Text
var
root
=
await
document
.
GetSyntaxRootAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
selectionTrimmed
=
await
CodeRefactoringHelpers
.
GetTrimmedTextSpan
(
document
,
selection
,
cancellationToken
).
ConfigureAwait
(
false
);
// Everytime a Node is considered by following algorithm (and tested with predicate) and the predicate fails
// Every
time a Node is considered by following algorithm (and tested with predicate) and the predicate fails
// extractNode is called on the node and the result is tested with predicate again. If any of those succeed
// a respective Node gets returned.
//
// That enables us to e.g. return node `b` when Node `var a = b;` is being considered without a complex (and potentially
// lang. & situation depend
a
nt) into Children descending code here. We can't just try extracted Node because we might
// lang. & situation depend
e
nt) into Children descending code here. We can't just try extracted Node because we might
// want the whole node `var a = b;`
//
// See local function TryGetAcceptedNodeOrExtracted DefaultNodeExtractor for more info.
// Handle selections:
// - The smallest node whose FullSpan in
lc
udes the whole (trimmed) selection
// - The smallest node whose FullSpan in
cl
udes the whole (trimmed) selection
// - Travels upwards through same-sized (FullSpan) nodes, extracting and testing predicate
// - Handles situations where:
// - Token with wanted Node as direct parent is selected (e.g. IdentifierToken for LocalFunctionStatement: `C [|Fun|]() {}`)
// - Most/the whole wanted Node is seleted (e.g. `C [|Fun() {}|]`
// - Most/the whole wanted Node is sele
c
ted (e.g. `C [|Fun() {}|]`
var
node
=
root
.
FindNode
(
selectionTrimmed
,
getInnermostNodeForTie
:
true
);
SyntaxNode
prevNode
;
do
...
...
@@ -120,10 +120,10 @@ protected async Task<SyntaxNode> TryGetSelectedNodeAsync(Document document, Text
// While having the (even empty) selection inside such token or to left of such Token is already handle
// by code above touching it from right `C methodName[||](){}` isn't (the FindNode for that returns Args node).
// - Secondly it is used for left/right edge climbing. E.g. `[||]C methodName(){}` the touching token's direct
// ancestor is TypeNode for the return type but it is still resonable to expect that the user might want to
// ancestor is TypeNode for the return type but it is still re
a
sonable to expect that the user might want to
// be given refactorings for the whole method (as he has caret on the edge of it). Therefore we travel the
// Node tree upwards and as long as we're on the left edge of a Node's span we consider such node & potentially
// continue travel
l
ing upwards. The situation for right edge (`C methodName(){}[||]`) is analogical.
// continue traveling upwards. The situation for right edge (`C methodName(){}[||]`) is analogical.
// E.g. for right edge `C methodName(){}[||]`: CloseBraceToken -> BlockSyntax -> LocalFunctionStatement -> null (higher
// node doesn't end on position anymore)
if
(!
selection
.
IsEmpty
)
...
...
@@ -215,11 +215,15 @@ static SyntaxNode TryGetAcceptedNodeOrExtracted(SyntaxNode node, Predicate<Synta
/// <summary>
/// <para>
/// Extractor function for <see cref="TryGetSelectedNodeAsync(Document, TextSpan, Predicate{SyntaxNode}, Func{SyntaxNode, ISyntaxFactsService, SyntaxNode}, CancellationToken)"/> methods
/// that retrieves expressions from declarations and assignments. Otherwise returns unchanged <paramref name="node"/>.
/// Extractor function for <see cref="TryGetSelectedNodeAsync(Document, TextSpan, Predicate{SyntaxNode}, Func{SyntaxNode, ISyntaxFactsService, SyntaxNode}, CancellationToken)"/> method
/// that retrieves nodes that should also be considered as refactoring targets given <paramref name="node"/> is considered.
/// Can extract both nodes above and under given <paramref name="node"/>.
/// </para>
/// <para>
/// The rationale is that when user selects e.g. entire local delaration statement [|var a = b;|] it is reasonable
/// E.g. extracts expressions from assignment statement (`a = b;` -> `b`) or lambda node for its body.
/// </para>
/// <para>
/// The rationale is that when user selects e.g. entire local declaration statement [|var a = b;|] it is reasonable
/// to provide refactoring for `b` node. Similarly for other types of refactorings.
/// </para>
/// </summary>
...
...
@@ -230,8 +234,8 @@ protected virtual SyntaxNode DefaultNodeExtractor(SyntaxNode node, ISyntaxFactsS
// that were found to be relevant for refactorings that were moved to `TryGetSelectedNodeAsync`.
// Feel free to extend it / refine current heuristics.
//
var a = b
;
// ->
b
//
`var a = b`
;
// ->
`b`
if
(
syntaxFacts
.
IsLocalDeclarationStatement
(
node
))
{
var
variables
=
syntaxFacts
.
GetVariablesOfLocalDeclarationStatement
(
node
);
...
...
@@ -251,14 +255,20 @@ protected virtual SyntaxNode DefaultNodeExtractor(SyntaxNode node, ISyntaxFactsS
}
}
//
a = b;
// ->
b
//
`a = b;`
// ->
`b`
if
(
syntaxFacts
.
IsSimpleAssignmentStatement
(
node
))
{
syntaxFacts
.
GetPartsOfAssignmentExpressionOrStatement
(
node
,
out
_
,
out
_
,
out
var
rightSide
);
return
rightSide
;
}
// a => `b`; -> `a => b;`
if
(
syntaxFacts
.
IsLambdaBody
(
node
))
{
return
node
.
Parent
;
}
return
node
;
}
}
...
...
src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
浏览文件 @
17a30872
...
...
@@ -1950,5 +1950,7 @@ public void GetPartsOfCastExpression(SyntaxNode node, out SyntaxNode type, out S
return
null
;
}
public
bool
IsLambdaBody
(
SyntaxNode
node
)
=>
node
.
Parent
!=
null
&&
node
.
Parent
is
LambdaExpressionSyntax
lambdaNode
&&
lambdaNode
.
Body
==
node
;
}
}
src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs
浏览文件 @
17a30872
...
...
@@ -264,6 +264,7 @@ internal interface ISyntaxFactsService : ILanguageService
bool
IsVariableDeclarator
(
SyntaxNode
node
);
bool
IsDeconstructionAssignment
(
SyntaxNode
node
);
bool
IsDeconstructionForEachStatement
(
SyntaxNode
node
);
bool
IsLambdaBody
(
SyntaxNode
node
);
/// <summary>
/// Returns true for nodes that represent the body of a method.
...
...
src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
浏览文件 @
17a30872
...
...
@@ -1944,5 +1944,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Public
Shadows
Function
SpansPreprocessorDirective
(
tokens
As
IEnumerable
(
Of
SyntaxToken
))
As
Boolean
Return
MyBase
.
SpansPreprocessorDirective
(
tokens
)
End
Function
Public
Function
IsLambdaBody
(
node
As
SyntaxNode
)
As
Boolean
Implements
ISyntaxFactsService
.
IsLambdaBody
If
node
.
Parent
IsNot
Nothing
And
TypeOf
node
.
Parent
Is
LambdaExpressionSyntax
Then
Dim
lambdaNode
=
CType
(
node
.
Parent
,
LambdaExpressionSyntax
)
Dim
lambdaBodies
=
lambdaNode
.
GetBodies
()
Return
lambdaBodies
.
Count
()
=
1
And
lambdaBodies
.
First
Is
node
End
If
Return
False
End
Function
End
Class
End
Namespace
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录