Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
92a5fb72
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,发现更多精彩内容 >>
提交
92a5fb72
编写于
6月 30, 2020
作者:
A
Allison Chou
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add tests and resource files
上级
b0fe7be3
变更
23
显示空白变更内容
内联
并排
Showing
23 changed file
with
471 addition
and
119 deletion
+471
-119
src/Analyzers/Core/CodeFixes/CodeFixesResources.resx
src/Analyzers/Core/CodeFixes/CodeFixesResources.resx
+3
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf
...Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf
...alyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf
+5
-0
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf
...alyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf
+5
-0
src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs
...ies/LanguageServer/AbstractLanguageServerProtocolTests.cs
+1
-1
src/Features/LanguageServer/Protocol/CustomProtocol/RunCodeActionParams.cs
...uageServer/Protocol/CustomProtocol/RunCodeActionParams.cs
+1
-1
src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs
.../Protocol/Handler/CodeActions/CodeActionResolveHandler.cs
+109
-58
src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs
...Server/Protocol/Handler/CodeActions/CodeActionsHandler.cs
+31
-22
src/Features/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs
...r/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs
+168
-0
src/Features/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs
...eServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs
+82
-27
src/VisualStudio/Core/Def/Implementation/LanguageClient/VisualStudioLspSolutionProvider.cs
...ntation/LanguageClient/VisualStudioLspSolutionProvider.cs
+0
-2
src/VisualStudio/LiveShare/Impl/PreviewCodeActionsHandler.cs
src/VisualStudio/LiveShare/Impl/PreviewCodeActionsHandler.cs
+1
-1
src/VisualStudio/LiveShare/Impl/RunCodeActionsHandler.cs
src/VisualStudio/LiveShare/Impl/RunCodeActionsHandler.cs
+10
-7
未找到文件。
src/Analyzers/Core/CodeFixes/CodeFixesResources.resx
浏览文件 @
92a5fb72
...
@@ -144,4 +144,7 @@
...
@@ -144,4 +144,7 @@
<data
name=
"Update_suppression_format"
xml:space=
"preserve"
>
<data
name=
"Update_suppression_format"
xml:space=
"preserve"
>
<value>
Update suppression format
</value>
<value>
Update suppression format
</value>
</data>
</data>
<data
name=
"Suppress_or_Configure_issues"
xml:space=
"preserve"
>
<value>
Suppress or Configure issues
</value>
</data>
</root>
</root>
\ No newline at end of file
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf
浏览文件 @
92a5fb72
...
@@ -32,6 +32,11 @@
...
@@ -32,6 +32,11 @@
<target
state=
"new"
>
Remove redundant suppression
</target>
<target
state=
"new"
>
Remove redundant suppression
</target>
<note
/>
<note
/>
</trans-unit>
</trans-unit>
<trans-unit
id=
"Suppress_or_Configure_issues"
>
<source>
Suppress or Configure issues
</source>
<target
state=
"new"
>
Suppress or Configure issues
</target>
<note
/>
</trans-unit>
<trans-unit
id=
"Update_suppression_format"
>
<trans-unit
id=
"Update_suppression_format"
>
<source>
Update suppression format
</source>
<source>
Update suppression format
</source>
<target
state=
"new"
>
Update suppression format
</target>
<target
state=
"new"
>
Update suppression format
</target>
...
...
src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs
浏览文件 @
92a5fb72
...
@@ -216,7 +216,7 @@ private protected static RunCodeActionParams CreateRunCodeActionParams(string co
...
@@ -216,7 +216,7 @@ private protected static RunCodeActionParams CreateRunCodeActionParams(string co
Range
=
location
.
Range
,
Range
=
location
.
Range
,
Context
=
new
LSP
.
CodeActionContext
()
Context
=
new
LSP
.
CodeActionContext
()
},
},
Title
=
codeActionTitle
Distinct
Title
=
codeActionTitle
};
};
/// <summary>
/// <summary>
...
...
src/Features/LanguageServer/Protocol/CustomProtocol/RunCodeActionParams.cs
浏览文件 @
92a5fb72
...
@@ -21,6 +21,6 @@ internal class RunCodeActionParams
...
@@ -21,6 +21,6 @@ internal class RunCodeActionParams
/// <summary>
/// <summary>
/// Title of the action to execute.
/// Title of the action to execute.
/// </summary>
/// </summary>
public
string
Title
{
get
;
set
;
}
public
string
Distinct
Title
{
get
;
set
;
}
}
}
}
}
src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs
浏览文件 @
92a5fb72
...
@@ -25,7 +25,7 @@
...
@@ -25,7 +25,7 @@
namespace
Microsoft.CodeAnalysis.LanguageServer.Handler
namespace
Microsoft.CodeAnalysis.LanguageServer.Handler
{
{
/// <summary>
/// <summary>
///
Handles the get code actions command
.
///
Resolves a code action by filling out its Edit or Command property
.
/// </summary>
/// </summary>
[
ExportLspMethod
(
MSLSPMethods
.
TextDocumentCodeActionResolveName
),
Shared
]
[
ExportLspMethod
(
MSLSPMethods
.
TextDocumentCodeActionResolveName
),
Shared
]
internal
class
CodeActionResolveHandler
:
AbstractRequestHandler
<
LSP
.
VSCodeAction
,
LSP
.
VSCodeAction
>
internal
class
CodeActionResolveHandler
:
AbstractRequestHandler
<
LSP
.
VSCodeAction
,
LSP
.
VSCodeAction
>
...
@@ -74,7 +74,7 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
...
@@ -74,7 +74,7 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
return
codeAction
;
return
codeAction
;
}
}
var
codeActionToResolve
=
GetCodeActionToResolve
(
data
,
codeActions
);
var
codeActionToResolve
=
GetCodeActionToResolve
(
data
.
DistinctTitle
,
codeActions
);
// We didn't find a matching action, so just return the action without an edit or command.
// We didn't find a matching action, so just return the action without an edit or command.
if
(
codeActionToResolve
==
null
)
if
(
codeActionToResolve
==
null
)
...
@@ -88,33 +88,79 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
...
@@ -88,33 +88,79 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
return
codeAction
;
return
codeAction
;
}
}
// TO-DO: We currently must execute code actions which add new documents on the server as commands,
// TO-DO:
// 1) We currently must execute code actions which add new documents on the server as commands,
// since there is no LSP support for adding documents yet. In the future, we should move these actions
// since there is no LSP support for adding documents yet. In the future, we should move these actions
// to primarily executing on the client.
// to execute on the client.
// 2) There is also a bug (same tracking item) where code actions that edit documents other than the
// one where the code action was invoked from do not work. We must temporarily execute these as commands
// as well.
// https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/
// https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/
var
runAsCommand
=
false
;
var
runAsCommand
=
false
;
var
applyChangesOperations
=
operations
.
Where
(
operation
=>
operation
is
ApplyChangesOperation
);
var
applyChangesOperations
=
operations
.
Where
(
operation
=>
operation
is
ApplyChangesOperation
);
if
(
applyChangesOperations
.
Any
())
if
(
applyChangesOperations
.
Any
())
{
var
workspaceEdits
=
await
ComputeWorkspaceEdits
(
applyChangesOperations
,
document
!,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
workspaceEdits
.
Any
())
{
codeAction
.
Edit
=
new
LSP
.
WorkspaceEdit
{
DocumentChanges
=
workspaceEdits
};
}
else
{
// The workspace edit is something we don't currently support, like adding a new document.
runAsCommand
=
true
;
}
}
// Set up to run as command on the server instead of using WorkspaceEdits.
var
commandOperations
=
operations
.
All
(
operation
=>
!(
operation
is
ApplyChangesOperation
));
if
(
commandOperations
||
runAsCommand
)
{
codeAction
.
Command
=
SetCommand
(
codeAction
,
data
);
}
return
codeAction
;
// Local functions
static
async
Task
<
TextDocumentEdit
[
]>
ComputeWorkspaceEdits
(
IEnumerable
<
CodeActionOperation
>
applyChangesOperations
,
Document
document
,
CancellationToken
cancellationToken
)
{
{
using
var
_
=
ArrayBuilder
<
TextDocumentEdit
>.
GetInstance
(
out
var
textDocumentEdits
);
using
var
_
=
ArrayBuilder
<
TextDocumentEdit
>.
GetInstance
(
out
var
textDocumentEdits
);
foreach
(
ApplyChangesOperation
applyChangesOperation
in
applyChangesOperations
)
foreach
(
ApplyChangesOperation
applyChangesOperation
in
applyChangesOperations
)
{
{
var
solution
=
document
!
.
Project
.
Solution
;
var
solution
=
document
.
Project
.
Solution
;
var
changes
=
applyChangesOperation
.
ChangedSolution
.
GetChanges
(
solution
);
var
changes
=
applyChangesOperation
.
ChangedSolution
.
GetChanges
(
solution
);
var
projectChanges
=
changes
.
GetProjectChanges
();
var
projectChanges
=
changes
.
GetProjectChanges
();
// If the change involves adding a document, execute via command instead of WorkspaceEdit.
// TO-DO: If the change involves adding a document, execute via command instead of WorkspaceEdit
// until adding documents is supported in LSP: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/
// After support is added, remove the below if-statement and add code to support adding documents.
var
addedDocuments
=
projectChanges
.
SelectMany
(
var
addedDocuments
=
projectChanges
.
SelectMany
(
pc
=>
pc
.
GetAddedDocuments
().
Concat
(
pc
.
GetAddedAdditionalDocuments
().
Concat
(
pc
.
GetAddedAnalyzerConfigDocuments
())));
pc
=>
pc
.
GetAddedDocuments
().
Concat
(
pc
.
GetAddedAdditionalDocuments
().
Concat
(
pc
.
GetAddedAnalyzerConfigDocuments
())));
if
(
addedDocuments
.
Any
())
if
(
addedDocuments
.
Any
())
{
{
runAsCommand
=
true
;
return
textDocumentEdits
.
ToArray
();
break
;
}
}
// Changed documents
var
changedDocuments
=
projectChanges
.
SelectMany
(
pc
=>
pc
.
GetChangedDocuments
());
var
changedDocuments
=
projectChanges
.
SelectMany
(
pc
=>
pc
.
GetChangedDocuments
());
var
changedAnalyzerConfigDocuments
=
projectChanges
.
SelectMany
(
pc
=>
pc
.
GetChangedAnalyzerConfigDocuments
());
var
changedAdditionalDocuments
=
projectChanges
.
SelectMany
(
pc
=>
pc
.
GetChangedAdditionalDocuments
());
// TO-DO: If the change involves modifying any document besides the document where the code action
// was invoked, temporarily execute via command instead of WorkspaceEdit until LSP bug is fixed:
// https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/
// After bug is fixed, remove the below if-statement and the existing code should work.
if
(
changedDocuments
.
Any
(
d
=>
d
!=
document
.
Id
)
||
changedAnalyzerConfigDocuments
.
Any
()
||
changedAdditionalDocuments
.
Any
())
{
return
textDocumentEdits
.
ToArray
();
}
// Changed documents
foreach
(
var
docId
in
changedDocuments
)
foreach
(
var
docId
in
changedDocuments
)
{
{
var
newDoc
=
applyChangesOperation
.
ChangedSolution
.
GetDocument
(
docId
);
var
newDoc
=
applyChangesOperation
.
ChangedSolution
.
GetDocument
(
docId
);
...
@@ -128,7 +174,8 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
...
@@ -128,7 +174,8 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
}
}
// Changed analyzer config documents
// Changed analyzer config documents
var
changedAnalyzerConfigDocuments
=
projectChanges
.
SelectMany
(
pc
=>
pc
.
GetChangedAnalyzerConfigDocuments
());
// This for loop won't currently execute until https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/
// is fixed.
foreach
(
var
docId
in
changedAnalyzerConfigDocuments
)
foreach
(
var
docId
in
changedAnalyzerConfigDocuments
)
{
{
var
newDoc
=
applyChangesOperation
.
ChangedSolution
.
GetAnalyzerConfigDocument
(
docId
);
var
newDoc
=
applyChangesOperation
.
ChangedSolution
.
GetAnalyzerConfigDocument
(
docId
);
...
@@ -140,36 +187,26 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
...
@@ -140,36 +187,26 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
await
GetTextDocumentEdits
(
textDocumentEdits
,
newDoc
,
oldDoc
,
cancellationToken
).
ConfigureAwait
(
false
);
await
GetTextDocumentEdits
(
textDocumentEdits
,
newDoc
,
oldDoc
,
cancellationToken
).
ConfigureAwait
(
false
);
}
}
}
if
(!
runAsCommand
)
// Changed additional documents
// This for loop won't currently execute until https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/
// is fixed.
foreach
(
var
docId
in
changedAdditionalDocuments
)
{
{
codeAction
.
Edit
=
new
LSP
.
WorkspaceEdit
{
DocumentChanges
=
textDocumentEdits
.
ToArray
()
};
var
newDoc
=
applyChangesOperation
.
ChangedSolution
.
GetAdditionalDocument
(
docId
);
}
var
oldDoc
=
solution
.
GetAdditionalDocument
(
docId
);
}
if
(
oldDoc
==
null
||
newDoc
==
null
)
// Running as command instead
var
commandOperations
=
operations
.
Where
(
operation
=>
!(
operation
is
ApplyChangesOperation
));
if
(
commandOperations
.
Any
()
||
runAsCommand
)
{
codeAction
.
Command
=
new
LSP
.
Command
{
CommandIdentifier
=
CodeActionsHandler
.
RunCodeActionCommandName
,
Title
=
codeAction
.
Title
,
Arguments
=
new
object
[]
{
new
RunCodeActionParams
{
{
CodeActionParams
=
data
.
CodeActionParams
,
continue
;
Title
=
codeAction
.
Title
}
}
await
GetTextDocumentEdits
(
textDocumentEdits
,
newDoc
,
oldDoc
,
cancellationToken
).
ConfigureAwait
(
false
);
}
}
};
}
}
return
codeAction
;
return
textDocumentEdits
.
ToArray
();
}
// Local functions
static
async
Task
GetTextDocumentEdits
(
static
async
Task
GetTextDocumentEdits
(
ArrayBuilder
<
TextDocumentEdit
>
textDocumentEdits
,
ArrayBuilder
<
TextDocumentEdit
>
textDocumentEdits
,
TextDocument
newDoc
,
TextDocument
newDoc
,
...
@@ -186,15 +223,30 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
...
@@ -186,15 +223,30 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
textDocumentEdits
.
Add
(
new
TextDocumentEdit
()
{
TextDocument
=
documentIdentifier
,
Edits
=
edits
.
ToArray
()
});
textDocumentEdits
.
Add
(
new
TextDocumentEdit
()
{
TextDocument
=
documentIdentifier
,
Edits
=
edits
.
ToArray
()
});
}
}
static
CodeAction
?
GetCodeActionToResolve
(
CodeActionResolveData
data
,
IEnumerable
<
CodeAction
>
codeActions
)
static
LSP
.
Command
SetCommand
(
VSCodeAction
codeAction
,
CodeActionResolveData
data
)
=>
new
LSP
.
Command
{
CommandIdentifier
=
CodeActionsHandler
.
RunCodeActionCommandName
,
Title
=
codeAction
.
Title
,
Arguments
=
new
object
[]
{
new
RunCodeActionParams
{
{
// First, we search for the matching code action. We compare against the distinct title
CodeActionParams
=
data
.
CodeActionParams
,
// instead of the regular title since there's a chance that multiple code actions may have
DistinctTitle
=
data
.
DistinctTitle
// the same name, e.g. configure code actions ("None", "Warning", etc.).
}
}
};
}
internal
static
CodeAction
?
GetCodeActionToResolve
(
string
distinctTitle
,
IEnumerable
<
CodeAction
>
codeActions
)
{
// Searching for the matching code action. We compare against the distinct title (e.g. "Suppress IDExxxxNone")
// instead of the regular title (e.g. "None") since there's a chance that multiple code actions may have
// the same regular title.
CodeAction
?
codeActionToResolve
=
null
;
CodeAction
?
codeActionToResolve
=
null
;
foreach
(
var
c
in
codeActions
)
foreach
(
var
c
in
codeActions
)
{
{
var
action
=
CheckForMatchingAction
(
c
,
data
.
D
istinctTitle
,
currentTitle
:
""
);
var
action
=
CheckForMatchingAction
(
c
,
d
istinctTitle
,
currentTitle
:
""
);
if
(
action
!=
null
)
if
(
action
!=
null
)
{
{
codeActionToResolve
=
action
;
codeActionToResolve
=
action
;
...
@@ -205,7 +257,7 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
...
@@ -205,7 +257,7 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
return
codeActionToResolve
;
return
codeActionToResolve
;
}
}
static
CodeAction
?
CheckForMatchingAction
(
CodeAction
codeAction
,
string
goalTitle
,
string
currentTitle
)
private
static
CodeAction
?
CheckForMatchingAction
(
CodeAction
codeAction
,
string
goalTitle
,
string
currentTitle
)
{
{
if
(
currentTitle
+
codeAction
.
Title
==
goalTitle
)
if
(
currentTitle
+
codeAction
.
Title
==
goalTitle
)
{
{
...
@@ -224,5 +276,4 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
...
@@ -224,5 +276,4 @@ internal class CodeActionResolveHandler : AbstractRequestHandler<LSP.VSCodeActio
return
null
;
return
null
;
}
}
}
}
}
}
}
src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs
浏览文件 @
92a5fb72
...
@@ -17,6 +17,7 @@
...
@@ -17,6 +17,7 @@
using
Microsoft.CodeAnalysis.Editor
;
using
Microsoft.CodeAnalysis.Editor
;
using
Microsoft.CodeAnalysis.Host.Mef
;
using
Microsoft.CodeAnalysis.Host.Mef
;
using
Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions
;
using
Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Microsoft.VisualStudio.LanguageServer.Protocol
;
using
Microsoft.VisualStudio.LanguageServer.Protocol
;
using
static
Microsoft
.
CodeAnalysis
.
CodeActions
.
CodeAction
;
using
static
Microsoft
.
CodeAnalysis
.
CodeActions
.
CodeAction
;
using
CodeAction
=
Microsoft
.
CodeAnalysis
.
CodeActions
.
CodeAction
;
using
CodeAction
=
Microsoft
.
CodeAnalysis
.
CodeActions
.
CodeAction
;
...
@@ -63,11 +64,18 @@ internal class CodeActionsHandler : AbstractRequestHandler<LSP.CodeActionParams,
...
@@ -63,11 +64,18 @@ internal class CodeActionsHandler : AbstractRequestHandler<LSP.CodeActionParams,
// Filter out code actions with options since they'll show dialogs and we can't remote the UI and the options.
// Filter out code actions with options since they'll show dialogs and we can't remote the UI and the options.
codeActions
=
codeActions
.
Where
(
c
=>
!(
c
.
Key
is
CodeActionWithOptions
));
codeActions
=
codeActions
.
Where
(
c
=>
!(
c
.
Key
is
CodeActionWithOptions
));
return
GetVSCodeActions
(
request
,
codeActions
);
// Local functions
static
VSCodeAction
[]
GetVSCodeActions
(
CodeActionParams
request
,
IEnumerable
<
KeyValuePair
<
CodeAction
,
CodeActionKind
>>
codeActions
)
{
var
suppressionActions
=
codeActions
.
Where
(
var
suppressionActions
=
codeActions
.
Where
(
a
=>
a
.
Key
is
AbstractConfigurationActionWithNestedActions
&&
a
=>
a
.
Key
is
AbstractConfigurationActionWithNestedActions
&&
(
a
.
Key
as
AbstractConfigurationActionWithNestedActions
)?.
IsBulkConfigurationAction
==
false
);
(
a
.
Key
as
AbstractConfigurationActionWithNestedActions
)?.
IsBulkConfigurationAction
==
false
);
var
results
=
new
List
<
VSCodeAction
>(
);
using
var
_
=
ArrayBuilder
<
VSCodeAction
>.
GetInstance
(
out
var
results
);
foreach
(
var
codeAction
in
codeActions
)
foreach
(
var
codeAction
in
codeActions
)
{
{
// Temporarily filter out suppress and configure code actions, as we'll later combine them under a top-level
// Temporarily filter out suppress and configure code actions, as we'll later combine them under a top-level
...
@@ -86,11 +94,12 @@ internal class CodeActionsHandler : AbstractRequestHandler<LSP.CodeActionParams,
...
@@ -86,11 +94,12 @@ internal class CodeActionsHandler : AbstractRequestHandler<LSP.CodeActionParams,
if
(
configureSuppressActions
.
Any
())
if
(
configureSuppressActions
.
Any
())
{
{
results
.
Add
(
GenerateVSCodeAction
(
request
,
new
CodeActionWithNestedActions
(
results
.
Add
(
GenerateVSCodeAction
(
request
,
new
CodeActionWithNestedActions
(
"Suppress or Configure issues"
,
CodeFixesResources
.
Suppress_or_Configure_issues
,
configureSuppressActions
.
Select
(
a
=>
a
.
Key
).
ToImmutableArray
(),
true
),
CodeActionKind
.
QuickFix
));
configureSuppressActions
.
Select
(
a
=>
a
.
Key
).
ToImmutableArray
(),
true
),
CodeActionKind
.
QuickFix
));
}
}
return
results
.
ToArray
();
return
results
.
ToArray
();
}
static
VSCodeAction
GenerateVSCodeAction
(
static
VSCodeAction
GenerateVSCodeAction
(
CodeActionParams
request
,
CodeActionParams
request
,
...
@@ -98,7 +107,7 @@ internal class CodeActionsHandler : AbstractRequestHandler<LSP.CodeActionParams,
...
@@ -98,7 +107,7 @@ internal class CodeActionsHandler : AbstractRequestHandler<LSP.CodeActionParams,
CodeActionKind
codeActionKind
,
CodeActionKind
codeActionKind
,
string
parentTitle
=
""
)
string
parentTitle
=
""
)
{
{
var
nestedActions
=
new
List
<
VSCodeAction
>(
);
using
var
_
=
ArrayBuilder
<
VSCodeAction
>.
GetInstance
(
out
var
nestedActions
);
foreach
(
var
action
in
codeAction
.
NestedCodeActions
)
foreach
(
var
action
in
codeAction
.
NestedCodeActions
)
{
{
nestedActions
.
Add
(
GenerateVSCodeAction
(
request
,
action
,
codeActionKind
,
codeAction
.
Title
));
nestedActions
.
Add
(
GenerateVSCodeAction
(
request
,
action
,
codeActionKind
,
codeAction
.
Title
));
...
...
src/Features/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs
0 → 100644
浏览文件 @
92a5fb72
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using
System
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.CSharp
;
using
Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions
;
using
Microsoft.VisualStudio.LanguageServer.Protocol
;
using
Roslyn.Test.Utilities
;
using
Xunit
;
using
LSP
=
Microsoft
.
VisualStudio
.
LanguageServer
.
Protocol
;
namespace
Microsoft.CodeAnalysis.LanguageServer.UnitTests.CodeActions
{
public
class
CodeActionResolveTests
:
AbstractLanguageServerProtocolTests
{
[
Fact
]
public
async
Task
TestCodeActionResolveHandlerAsync
()
{
var
initialMarkup
=
@"class A
{
void M()
{
{|caret:|}int i = 1;
}
}"
;
using
var
workspace
=
CreateTestWorkspace
(
initialMarkup
,
out
var
locations
);
var
unresolvedCodeAction
=
CodeActionsTests
.
CreateCodeAction
(
title
:
CSharpAnalyzersResources
.
Use_implicit_type
,
kind
:
CodeActionKind
.
Refactor
,
children
:
Array
.
Empty
<
LSP
.
VSCodeAction
>(),
data
:
new
CodeActionResolveData
{
CodeActionParams
=
CodeActionsTests
.
CreateCodeActionParams
(
locations
[
"caret"
].
Single
()),
DistinctTitle
=
CSharpAnalyzersResources
.
Use_implicit_type
},
diagnostics
:
null
);
var
expectedMarkup
=
@"class A
{
void M()
{
var i = 1;
}
}"
;
var
expected
=
CodeActionsTests
.
CreateCodeAction
(
title
:
CSharpAnalyzersResources
.
Use_implicit_type
,
kind
:
CodeActionKind
.
Refactor
,
children
:
Array
.
Empty
<
LSP
.
VSCodeAction
>(),
data
:
new
CodeActionResolveData
{
CodeActionParams
=
CodeActionsTests
.
CreateCodeActionParams
(
locations
[
"caret"
].
Single
()),
DistinctTitle
=
CSharpAnalyzersResources
.
Use_implicit_type
},
diagnostics
:
null
,
edit
:
new
LSP
.
WorkspaceEdit
()
{
DocumentChanges
=
new
TextDocumentEdit
[]
{
new
TextDocumentEdit
()
{
TextDocument
=
new
VersionedTextDocumentIdentifier
()
{
Uri
=
locations
[
"caret"
].
Single
().
Uri
},
Edits
=
new
TextEdit
[]
{
new
TextEdit
()
{
NewText
=
expectedMarkup
,
Range
=
new
LSP
.
Range
()
{
Start
=
new
Position
(
0
,
0
),
End
=
new
Position
(
6
,
1
)
}
}
}
}
}
});
var
result
=
await
RunGetCodeActionResolveAsync
(
workspace
.
CurrentSolution
,
unresolvedCodeAction
);
AssertJsonEquals
(
expected
,
result
);
}
[
Fact
]
public
async
Task
TestCodeActionResolveHandlerAsync_NestedAction
()
{
var
initialMarkup
=
@"class A
{
void M()
{
int {|caret:|}i = 1;
}
}"
;
using
var
workspace
=
CreateTestWorkspace
(
initialMarkup
,
out
var
locations
);
var
unresolvedCodeAction
=
CodeActionsTests
.
CreateCodeAction
(
title
:
string
.
Format
(
FeaturesResources
.
Introduce_constant_for_0
,
"1"
),
kind
:
CodeActionKind
.
Refactor
,
children
:
Array
.
Empty
<
LSP
.
VSCodeAction
>(),
data
:
new
CodeActionResolveData
{
CodeActionParams
=
CodeActionsTests
.
CreateCodeActionParams
(
locations
[
"caret"
].
Single
()),
DistinctTitle
=
FeaturesResources
.
Introduce_constant
+
string
.
Format
(
FeaturesResources
.
Introduce_constant_for_0
,
"1"
),
},
diagnostics
:
null
);
var
expectedMarkup
=
@"class A
{
private const int V = 1;
void M()
{
int i = V;
}
}"
;
var
expected
=
CodeActionsTests
.
CreateCodeAction
(
title
:
string
.
Format
(
FeaturesResources
.
Introduce_constant_for_0
,
"1"
),
kind
:
CodeActionKind
.
Refactor
,
children
:
Array
.
Empty
<
LSP
.
VSCodeAction
>(),
data
:
new
CodeActionResolveData
{
CodeActionParams
=
CodeActionsTests
.
CreateCodeActionParams
(
locations
[
"caret"
].
Single
()),
DistinctTitle
=
FeaturesResources
.
Introduce_constant
+
string
.
Format
(
FeaturesResources
.
Introduce_constant_for_0
,
"1"
),
},
diagnostics
:
null
,
edit
:
new
LSP
.
WorkspaceEdit
()
{
DocumentChanges
=
new
TextDocumentEdit
[]
{
new
TextDocumentEdit
()
{
TextDocument
=
new
VersionedTextDocumentIdentifier
()
{
Uri
=
locations
[
"caret"
].
Single
().
Uri
},
Edits
=
new
TextEdit
[]
{
new
TextEdit
()
{
NewText
=
expectedMarkup
,
Range
=
new
LSP
.
Range
()
{
Start
=
new
Position
(
0
,
0
),
End
=
new
Position
(
6
,
1
)
}
}
}
}
}
});
var
result
=
await
RunGetCodeActionResolveAsync
(
workspace
.
CurrentSolution
,
unresolvedCodeAction
);
AssertJsonEquals
(
expected
,
result
);
}
private
static
async
Task
<
LSP
.
VSCodeAction
>
RunGetCodeActionResolveAsync
(
Solution
solution
,
VSCodeAction
unresolvedCodeAction
,
LSP
.
ClientCapabilities
clientCapabilities
=
null
)
{
var
result
=
await
GetLanguageServer
(
solution
).
ExecuteRequestAsync
<
LSP
.
VSCodeAction
,
LSP
.
VSCodeAction
>(
LSP
.
MSLSPMethods
.
TextDocumentCodeActionResolveName
,
unresolvedCodeAction
,
clientCapabilities
,
null
,
CancellationToken
.
None
);
return
result
;
}
}
}
src/Features/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs
浏览文件 @
92a5fb72
...
@@ -2,11 +2,13 @@
...
@@ -2,11 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// See the LICENSE file in the project root for more information.
using
System
;
using
System.Linq
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.CSharp
;
using
Microsoft.CodeAnalysis.CSharp
;
using
Newtonsoft.Json.Linq
;
using
Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions
;
using
Microsoft.VisualStudio.LanguageServer.Protocol
;
using
Roslyn.Test.Utilities
;
using
Roslyn.Test.Utilities
;
using
Xunit
;
using
Xunit
;
using
LSP
=
Microsoft
.
VisualStudio
.
LanguageServer
.
Protocol
;
using
LSP
=
Microsoft
.
VisualStudio
.
LanguageServer
.
Protocol
;
...
@@ -16,7 +18,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.CodeActions
...
@@ -16,7 +18,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.CodeActions
public
class
CodeActionsTests
:
AbstractLanguageServerProtocolTests
public
class
CodeActionsTests
:
AbstractLanguageServerProtocolTests
{
{
[
Fact
]
[
Fact
]
public
async
Task
Test
GetCodeActions
Async
()
public
async
Task
Test
CodeActionHandler
Async
()
{
{
var
markup
=
var
markup
=
@"class A
@"class A
...
@@ -27,31 +29,68 @@ void M()
...
@@ -27,31 +29,68 @@ void M()
}
}
}"
;
}"
;
using
var
workspace
=
CreateTestWorkspace
(
markup
,
out
var
locations
);
using
var
workspace
=
CreateTestWorkspace
(
markup
,
out
var
locations
);
var
expected
=
CreateCommand
(
CSharpAnalyzersResources
.
Use_implicit_type
,
locations
[
"caret"
].
Single
());
var
clientCapabilities
=
CreateClientCapabilitiesWithExperimentalValue
(
"supportsWorkspaceEdits"
,
JToken
.
FromObject
(
false
));
var
results
=
await
RunGetCodeActionsAsync
(
workspace
.
CurrentSolution
,
locations
[
"caret"
].
Single
(),
clientCapabilities
);
var
expected
=
CreateCodeAction
(
var
useImplicitTypeResult
=
results
.
Single
(
r
=>
r
.
Title
==
CSharpAnalyzersResources
.
Use_implicit_type
);
title
:
CSharpAnalyzersResources
.
Use_implicit_type
,
AssertJsonEquals
(
expected
,
useImplicitTypeResult
);
kind
:
CodeActionKind
.
Refactor
,
children
:
Array
.
Empty
<
LSP
.
VSCodeAction
>(),
data
:
new
CodeActionResolveData
{
CodeActionParams
=
CreateCodeActionParams
(
locations
[
"caret"
].
Single
()),
DistinctTitle
=
CSharpAnalyzersResources
.
Use_implicit_type
},
diagnostics
:
null
);
var
results
=
await
RunGetCodeActionsAsync
(
workspace
.
CurrentSolution
,
locations
[
"caret"
].
Single
());
var
useImplicitType
=
results
.
FirstOrDefault
(
r
=>
r
.
Title
==
CSharpAnalyzersResources
.
Use_implicit_type
);
AssertJsonEquals
(
expected
,
useImplicitType
);
}
}
private
static
async
Task
<
LSP
.
Command
[
]>
RunGetCodeActionsAsync
(
Solution
solution
,
LSP
.
Location
caret
,
LSP
.
ClientCapabilities
clientCapabilities
=
null
)
[
Fact
]
public
async
Task
TestCodeActionHandlerAsync_NestedAction
()
{
{
var
results
=
await
GetLanguageServer
(
solution
).
ExecuteRequestAsync
<
LSP
.
CodeActionParams
,
LSP
.
SumType
<
LSP
.
Command
,
LSP
.
CodeAction
>[
]>
(
LSP
.
Methods
.
TextDocumentCodeActionName
,
var
markup
=
CreateCodeActionParams
(
caret
),
clientCapabilities
,
null
,
CancellationToken
.
None
);
@"class A
return
results
.
Select
(
r
=>
(
LSP
.
Command
)
r
).
ToArray
();
{
void M()
{
int {|caret:|}i = 1;
}
}
}"
;
using
var
workspace
=
CreateTestWorkspace
(
markup
,
out
var
locations
);
private
static
LSP
.
ClientCapabilities
CreateClientCapabilitiesWithExperimentalValue
(
string
experimentalProperty
,
JToken
value
)
var
expected
=
CreateCodeAction
(
=>
new
LSP
.
ClientCapabilities
()
title
:
string
.
Format
(
FeaturesResources
.
Introduce_constant_for_0
,
"1"
),
kind
:
CodeActionKind
.
Refactor
,
children
:
Array
.
Empty
<
LSP
.
VSCodeAction
>(),
data
:
new
CodeActionResolveData
{
{
Experimental
=
new
JObject
CodeActionParams
=
CreateCodeActionParams
(
locations
[
"caret"
].
Single
()),
DistinctTitle
=
FeaturesResources
.
Introduce_constant
+
string
.
Format
(
FeaturesResources
.
Introduce_constant_for_0
,
"1"
),
},
diagnostics
:
null
);
var
results
=
await
RunGetCodeActionsAsync
(
workspace
.
CurrentSolution
,
locations
[
"caret"
].
Single
());
var
introduceConstant
=
results
[
0
].
Children
.
FirstOrDefault
(
r
=>
((
CodeActionResolveData
)
r
.
Data
).
DistinctTitle
==
FeaturesResources
.
Introduce_constant
+
string
.
Format
(
FeaturesResources
.
Introduce_constant_for_0
,
"1"
));
AssertJsonEquals
(
expected
,
introduceConstant
);
}
private
static
async
Task
<
LSP
.
VSCodeAction
[
]>
RunGetCodeActionsAsync
(
Solution
solution
,
LSP
.
Location
caret
,
LSP
.
ClientCapabilities
clientCapabilities
=
null
)
{
{
{
experimentalProperty
,
value
}
var
result
=
await
GetLanguageServer
(
solution
).
ExecuteRequestAsync
<
LSP
.
CodeActionParams
,
LSP
.
VSCodeAction
[
]>
(
LSP
.
Methods
.
TextDocumentCodeActionName
,
CreateCodeActionParams
(
caret
),
clientCapabilities
,
null
,
CancellationToken
.
None
);
return
result
;
}
}
};
private
static
LSP
.
CodeActionParams
CreateCodeActionParams
(
LSP
.
Location
caret
)
internal
static
LSP
.
CodeActionParams
CreateCodeActionParams
(
LSP
.
Location
caret
)
=>
new
LSP
.
CodeActionParams
()
=>
new
LSP
.
CodeActionParams
()
{
{
TextDocument
=
CreateTextDocumentIdentifier
(
caret
.
Uri
),
TextDocument
=
CreateTextDocumentIdentifier
(
caret
.
Uri
),
...
@@ -62,15 +101,31 @@ private static LSP.CodeActionParams CreateCodeActionParams(LSP.Location caret)
...
@@ -62,15 +101,31 @@ private static LSP.CodeActionParams CreateCodeActionParams(LSP.Location caret)
}
}
};
};
private
static
LSP
.
Command
CreateCommand
(
string
title
,
LSP
.
Location
location
)
internal
static
LSP
.
VSCodeAction
CreateCodeAction
(
=>
new
LSP
.
Command
()
string
title
,
LSP
.
CodeActionKind
kind
,
LSP
.
VSCodeAction
[]
children
,
CodeActionResolveData
data
,
LSP
.
Diagnostic
[]
diagnostics
,
LSP
.
WorkspaceEdit
edit
=
null
,
LSP
.
Command
command
=
null
)
{
var
action
=
new
LSP
.
VSCodeAction
{
{
Title
=
title
,
Title
=
title
,
CommandIdentifier
=
"Roslyn.RunCodeAction"
,
Kind
=
kind
,
Arguments
=
new
object
[]
Children
=
children
,
Data
=
data
,
Diagnostics
=
diagnostics
,
};
if
(
edit
!=
null
)
{
{
CreateRunCodeActionParams
(
title
,
location
)
action
.
Edit
=
edit
;
}
if
(
command
!=
null
)
{
action
.
Command
=
command
;
}
return
action
;
}
}
};
}
}
}
}
src/VisualStudio/Core/Def/Implementation/LanguageClient/VisualStudioLspSolutionProvider.cs
浏览文件 @
92a5fb72
...
@@ -7,11 +7,9 @@
...
@@ -7,11 +7,9 @@
using
System
;
using
System
;
using
System.Collections.Immutable
;
using
System.Collections.Immutable
;
using
System.Composition
;
using
System.Composition
;
using
System.Linq
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.Host.Mef
;
using
Microsoft.CodeAnalysis.Host.Mef
;
using
Microsoft.CodeAnalysis.LanguageServer
;
using
Microsoft.CodeAnalysis.LanguageServer
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.LanguageClient
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.LanguageClient
...
...
src/VisualStudio/LiveShare/Impl/PreviewCodeActionsHandler.cs
浏览文件 @
92a5fb72
...
@@ -41,7 +41,7 @@ public async Task<LSP.TextEdit[]> HandleAsync(RunCodeActionParams request, Reque
...
@@ -41,7 +41,7 @@ public async Task<LSP.TextEdit[]> HandleAsync(RunCodeActionParams request, Reque
request
.
CodeActionParams
.
Range
,
request
.
CodeActionParams
.
Range
,
cancellationToken
).
ConfigureAwait
(
false
);
cancellationToken
).
ConfigureAwait
(
false
);
var
actionToRun
=
codeActions
?.
FirstOrDefault
(
a
=>
a
.
Title
==
request
.
Title
);
var
actionToRun
=
codeActions
?.
FirstOrDefault
(
a
=>
a
.
Title
==
request
.
Distinct
Title
);
if
(
actionToRun
!=
null
)
if
(
actionToRun
!=
null
)
{
{
...
...
src/VisualStudio/LiveShare/Impl/RunCodeActionsHandler.cs
浏览文件 @
92a5fb72
...
@@ -7,7 +7,6 @@
...
@@ -7,7 +7,6 @@
using
System.Linq
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.CodeFixes
;
using
Microsoft.CodeAnalysis.CodeFixes
;
using
Microsoft.CodeAnalysis.CodeRefactorings
;
using
Microsoft.CodeAnalysis.CodeRefactorings
;
using
Microsoft.CodeAnalysis.Editor.Shared.Utilities
;
using
Microsoft.CodeAnalysis.Editor.Shared.Utilities
;
...
@@ -22,8 +21,8 @@
...
@@ -22,8 +21,8 @@
namespace
Microsoft.VisualStudio.LanguageServices.LiveShare
namespace
Microsoft.VisualStudio.LanguageServices.LiveShare
{
{
/// <summary>
/// <summary>
/// Run
code actions handler. Called when lightbulb invoked
.
/// Run
s code actions as a command on the server
.
/// Co
de action
s must be applied from the UI thread in VS.
/// Co
mmand
s must be applied from the UI thread in VS.
/// </summary>
/// </summary>
[
ExportExecuteWorkspaceCommand
(
CodeActionsHandler
.
RunCodeActionCommandName
)]
[
ExportExecuteWorkspaceCommand
(
CodeActionsHandler
.
RunCodeActionCommandName
)]
internal
class
RunCodeActionsHandler
:
IExecuteWorkspaceCommandHandler
internal
class
RunCodeActionsHandler
:
IExecuteWorkspaceCommandHandler
...
@@ -56,12 +55,14 @@ internal class RunCodeActionsHandler : IExecuteWorkspaceCommandHandler
...
@@ -56,12 +55,14 @@ internal class RunCodeActionsHandler : IExecuteWorkspaceCommandHandler
var
document
=
_solutionProvider
.
GetDocument
(
runRequest
.
CodeActionParams
.
TextDocument
);
var
document
=
_solutionProvider
.
GetDocument
(
runRequest
.
CodeActionParams
.
TextDocument
);
var
codeActions
=
await
CodeActionsHandler
.
GetCodeActionsAsync
(
document
,
_codeFixService
,
_codeRefactoringService
,
var
codeActions
=
await
CodeActionsHandler
.
GetCodeActionsAsync
(
document
,
_codeFixService
,
_codeRefactoringService
,
runRequest
.
CodeActionParams
.
Range
,
cancellationToken
).
ConfigureAwait
(
false
);
runRequest
.
CodeActionParams
.
Range
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
codeActions
==
null
)
{
return
false
;
}
var
actionToRun
=
codeActions
?.
FirstOrDefault
(
a
=>
a
.
Title
==
runRequest
.
Title
);
var
actionToRun
=
CodeActionResolveHandler
.
GetCodeActionToResolve
(
runRequest
.
DistinctTitle
,
codeActions
);
if
(
actionToRun
!=
null
)
if
(
actionToRun
!=
null
)
{
{
// add check here
foreach
(
var
operation
in
await
actionToRun
.
GetOperationsAsync
(
cancellationToken
).
ConfigureAwait
(
false
))
foreach
(
var
operation
in
await
actionToRun
.
GetOperationsAsync
(
cancellationToken
).
ConfigureAwait
(
false
))
{
{
// TODO - This UI thread dependency should be removed.
// TODO - This UI thread dependency should be removed.
...
@@ -69,9 +70,11 @@ internal class RunCodeActionsHandler : IExecuteWorkspaceCommandHandler
...
@@ -69,9 +70,11 @@ internal class RunCodeActionsHandler : IExecuteWorkspaceCommandHandler
await
_threadingContext
.
JoinableTaskFactory
.
SwitchToMainThreadAsync
(
cancellationToken
);
await
_threadingContext
.
JoinableTaskFactory
.
SwitchToMainThreadAsync
(
cancellationToken
);
operation
.
Apply
(
document
.
Project
.
Solution
.
Workspace
,
cancellationToken
);
operation
.
Apply
(
document
.
Project
.
Solution
.
Workspace
,
cancellationToken
);
}
}
}
return
true
;
return
true
;
}
}
return
false
;
}
}
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录