Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
7f2b6acf
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,发现更多精彩内容 >>
提交
7f2b6acf
编写于
8月 11, 2020
作者:
A
Allison Chou
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Address code review feedback
上级
a76bd3df
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
104 addition
and
113 deletion
+104
-113
src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionSet.cs
.../Portable/UnifiedSuggestions/UnifiedSuggestedActionSet.cs
+1
-39
src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedSuggestedAction.cs
...estions/UnifiedSuggestedActions/UnifiedSuggestedAction.cs
+1
-33
src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs
...eServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs
+3
-3
src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsCache.cs
...geServer/Protocol/Handler/CodeActions/CodeActionsCache.cs
+30
-21
src/Features/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs
...eServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs
+69
-17
未找到文件。
src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionSet.cs
浏览文件 @
7f2b6acf
...
...
@@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.UnifiedSuggestions
/// Similar to SuggestedActionSet, but in a location that can be used
/// by both local Roslyn and LSP.
/// </summary>
internal
class
UnifiedSuggestedActionSet
:
IEquatable
<
UnifiedSuggestedActionSet
>
internal
class
UnifiedSuggestedActionSet
{
public
string
?
CategoryName
{
get
;
}
...
...
@@ -42,43 +42,5 @@ internal class UnifiedSuggestedActionSet : IEquatable<UnifiedSuggestedActionSet>
Priority
=
priority
;
ApplicableToSpan
=
applicableToSpan
;
}
public
override
bool
Equals
(
object
?
obj
)
=>
obj
is
UnifiedSuggestedActionSet
actionSet
&&
Equals
(
actionSet
);
public
bool
Equals
(
UnifiedSuggestedActionSet
?
otherSuggestedActionSet
)
{
if
(
otherSuggestedActionSet
==
null
)
{
return
false
;
}
if
(
this
==
otherSuggestedActionSet
)
{
return
true
;
}
if
(
Title
!=
otherSuggestedActionSet
.
Title
||
Priority
!=
otherSuggestedActionSet
.
Priority
||
CategoryName
!=
otherSuggestedActionSet
.
CategoryName
||
ApplicableToSpan
!=
otherSuggestedActionSet
.
ApplicableToSpan
)
{
return
false
;
}
if
(!
Actions
.
SequenceEqual
(
otherSuggestedActionSet
.
Actions
))
{
return
false
;
}
return
true
;
}
public
override
int
GetHashCode
()
{
return
Hash
.
Combine
(
CategoryName
!=
null
?
CategoryName
.
GetHashCode
()
:
0
,
Hash
.
Combine
(
Actions
.
GetHashCode
(),
Hash
.
Combine
(
Title
!=
null
?
Title
.
GetHashCode
()
:
0
,
Hash
.
Combine
(
Priority
.
GetHashCode
(),
ApplicableToSpan
.
GetHashCode
()))));
}
}
}
src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedSuggestedAction.cs
浏览文件 @
7f2b6acf
...
...
@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.UnifiedSuggestions
/// Similar to SuggestedAction, but in a location that can be used by
/// both local Roslyn and LSP.
/// </summary>
internal
class
UnifiedSuggestedAction
:
IUnifiedSuggestedAction
,
IEquatable
<
IUnifiedSuggestedAction
>
internal
class
UnifiedSuggestedAction
:
IUnifiedSuggestedAction
{
public
Workspace
Workspace
{
get
;
}
...
...
@@ -27,37 +27,5 @@ public UnifiedSuggestedAction(Workspace workspace, CodeAction codeAction, CodeAc
OriginalCodeAction
=
codeAction
;
CodeActionPriority
=
codeActionPriority
;
}
public
bool
Equals
(
IUnifiedSuggestedAction
?
other
)
=>
other
is
UnifiedSuggestedAction
action
&&
Equals
(
action
);
public
override
bool
Equals
(
object
?
obj
)
=>
obj
is
UnifiedSuggestedAction
action
&&
Equals
(
action
);
internal
bool
Equals
(
UnifiedSuggestedAction
otherSuggestedAction
)
{
if
(
this
==
otherSuggestedAction
)
{
return
true
;
}
if
(
OriginalCodeAction
.
EquivalenceKey
!=
null
&&
otherSuggestedAction
.
OriginalCodeAction
.
EquivalenceKey
!=
null
&&
OriginalCodeAction
.
EquivalenceKey
==
otherSuggestedAction
.
OriginalCodeAction
.
EquivalenceKey
)
{
return
true
;
}
return
OriginalCodeAction
.
Title
==
otherSuggestedAction
.
OriginalCodeAction
.
Title
;
}
public
override
int
GetHashCode
()
{
if
(
OriginalCodeAction
.
EquivalenceKey
!=
null
)
{
return
OriginalCodeAction
.
EquivalenceKey
.
GetHashCode
();
}
return
OriginalCodeAction
.
Title
.
GetHashCode
();
}
}
}
src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs
浏览文件 @
7f2b6acf
...
...
@@ -46,7 +46,7 @@ internal static class CodeActionHelpers
return
Array
.
Empty
<
VSCodeAction
>();
}
await
codeActionsCache
.
Update
Cache
Async
(
document
,
request
.
Range
,
actionSets
.
Value
,
cancellationToken
).
ConfigureAwait
(
false
);
await
codeActionsCache
.
Update
ActionSets
Async
(
document
,
request
.
Range
,
actionSets
.
Value
,
cancellationToken
).
ConfigureAwait
(
false
);
var
_
=
ArrayBuilder
<
VSCodeAction
>.
GetInstance
(
out
var
codeActions
);
foreach
(
var
set
in
actionSets
)
...
...
@@ -115,7 +115,7 @@ internal static class CodeActionHelpers
IThreadingContext
threadingContext
,
CancellationToken
cancellationToken
)
{
var
actionSets
=
await
codeActionsCache
.
Get
Cache
Async
(
document
,
selection
,
cancellationToken
).
ConfigureAwait
(
false
);
var
actionSets
=
await
codeActionsCache
.
Get
ActionSets
Async
(
document
,
selection
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
actionSets
==
null
)
{
actionSets
=
await
GetActionSetsAsync
(
...
...
@@ -126,7 +126,7 @@ internal static class CodeActionHelpers
return
ImmutableArray
<
CodeAction
>.
Empty
;
}
await
codeActionsCache
.
Update
Cache
Async
(
document
,
selection
,
actionSets
.
Value
,
cancellationToken
).
ConfigureAwait
(
false
);
await
codeActionsCache
.
Update
ActionSets
Async
(
document
,
selection
,
actionSets
.
Value
,
cancellationToken
).
ConfigureAwait
(
false
);
}
var
_
=
ArrayBuilder
<
CodeAction
>.
GetInstance
(
out
var
codeActions
);
...
...
src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsCache.cs
浏览文件 @
7f2b6acf
...
...
@@ -33,7 +33,7 @@ internal class CodeActionsCache
/// <summary>
/// Maximum number of cached items.
/// </summary>
private
readonly
int
_m
axCacheSize
=
3
;
private
const
int
M
axCacheSize
=
3
;
/// <summary>
/// Current list of cached items.
...
...
@@ -46,7 +46,7 @@ public CodeActionsCache()
{
}
public
async
Task
Update
Cache
Async
(
public
async
Task
Update
ActionSets
Async
(
Document
document
,
LSP
.
Range
range
,
ImmutableArray
<
UnifiedSuggestedActionSet
>
cachedSuggestedActionSets
,
...
...
@@ -55,21 +55,14 @@ public CodeActionsCache()
using
(
await
_semaphore
.
DisposableWaitAsync
(
cancellationToken
).
ConfigureAwait
(
false
))
{
// If there's a value in the cache with the same document and range we're searching for,
// remove and replace it with our updated value if the updated value is different.
var
previousCachedItem
=
_cachedItems
.
Where
(
c
=>
c
.
Document
==
document
&&
c
.
Range
.
Start
==
range
.
Start
&&
c
.
Range
.
End
==
range
.
End
);
if
(
previousCachedItem
.
Any
())
// remove and replace it with our updated value.
var
previousCachedItem
=
_cachedItems
.
Where
(
c
=>
IsMatch
(
document
,
range
,
c
));
if
(!
previousCachedItem
.
IsEmpty
())
{
var
item
=
previousCachedItem
.
First
();
if
(
item
.
CachedSuggestedActionSets
.
SequenceEqual
(
cachedSuggestedActionSets
))
{
return
;
}
_cachedItems
.
Remove
(
item
);
_cachedItems
.
Remove
(
previousCachedItem
.
First
());
}
// If the cache is full, remove the oldest cached value.
else
if
(
_cachedItems
.
Count
>=
_m
axCacheSize
)
else
if
(
_cachedItems
.
Count
>=
M
axCacheSize
)
{
_cachedItems
.
RemoveAt
(
0
);
}
...
...
@@ -82,7 +75,7 @@ public CodeActionsCache()
/// Attempts to retrieve the cached action sets that match the given document and range.
/// Returns null if no match is found.
/// </summary>
public
async
Task
<
ImmutableArray
<
UnifiedSuggestedActionSet
>?>
Get
Cache
Async
(
public
async
Task
<
ImmutableArray
<
UnifiedSuggestedActionSet
>?>
Get
ActionSets
Async
(
Document
document
,
LSP
.
Range
range
,
CancellationToken
cancellationToken
)
...
...
@@ -91,8 +84,7 @@ public CodeActionsCache()
{
foreach
(
var
cachedItem
in
_cachedItems
)
{
if
(
document
==
cachedItem
.
Document
&&
document
.
Project
.
Solution
==
cachedItem
.
Document
.
Project
.
Solution
&&
range
.
Start
==
cachedItem
.
Range
?.
Start
&&
range
.
End
==
cachedItem
.
Range
?.
End
)
if
(
IsMatch
(
document
,
range
,
cachedItem
))
{
return
cachedItem
.
CachedSuggestedActionSets
;
}
...
...
@@ -102,10 +94,11 @@ public CodeActionsCache()
}
}
/// <summary>
/// Returns the current number of cached items.
/// </summary>
public
int
GetNumCacheItems
()
=>
_cachedItems
.
Count
;
private
static
bool
IsMatch
(
Document
document
,
LSP
.
Range
range
,
CodeActionsCacheItem
cachedItem
)
=>
document
==
cachedItem
.
Document
&&
document
.
Project
.
Solution
==
cachedItem
.
Document
.
Project
.
Solution
&&
range
.
Start
==
cachedItem
.
Range
.
Start
&&
range
.
End
==
cachedItem
.
Range
.
End
;
/// <summary>
/// Contains the necessary information for each cached item.
...
...
@@ -126,5 +119,21 @@ public CodeActionsCache()
CachedSuggestedActionSets
=
cachedSuggestedActionSets
;
}
}
internal
TestAccessor
GetTestAccessor
()
=>
new
TestAccessor
(
this
);
internal
readonly
struct
TestAccessor
{
private
readonly
CodeActionsCache
_codeActionsCache
;
public
static
int
MaximumCacheSize
=>
MaxCacheSize
;
public
TestAccessor
(
CodeActionsCache
codeActionsCache
)
=>
_codeActionsCache
=
codeActionsCache
;
public
List
<(
Document
Document
,
LSP
.
Range
Range
)>
GetDocumentsAndRangesInCache
()
=>
_codeActionsCache
.
_cachedItems
.
Select
(
c
=>
(
c
.
Document
,
c
.
Range
)).
ToList
();
}
}
}
src/Features/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs
浏览文件 @
7f2b6acf
...
...
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using
System
;
using
System.Collections.Immutable
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
...
...
@@ -10,6 +11,7 @@
using
Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
;
using
Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions
;
using
Microsoft.CodeAnalysis.Text
;
using
Microsoft.CodeAnalysis.UnifiedSuggestions
;
using
Microsoft.VisualStudio.LanguageServer.Protocol
;
using
Newtonsoft.Json.Linq
;
using
Roslyn.Test.Utilities
;
...
...
@@ -91,50 +93,100 @@ void M()
}"
;
using
var
workspace
=
CreateTestWorkspace
(
markup
,
out
var
locations
);
var
cache
=
GetCodeActionsCache
(
workspace
);
var
testAccessor
=
cache
.
GetTestAccessor
();
var
caretLocation
=
locations
[
"caret"
].
Single
();
await
RunGetCodeActionsAsync
(
workspace
.
CurrentSolution
,
caretLocation
);
// This test assumes that the maximum cache size is 3, and will have to modified if this number changes.
Assert
.
True
(
CodeActionsCache
.
TestAccessor
.
MaximumCacheSize
==
3
);
var
caretLocation
=
locations
[
"caret"
].
Single
();
var
document
=
GetDocument
(
workspace
,
CreateTextDocumentIdentifier
(
caretLocation
.
Uri
));
var
cacheResults
=
await
cache
.
GetCacheAsync
(
document
,
caretLocation
.
Range
,
CancellationToken
.
None
);
Assert
.
NotNull
(
cacheResults
);
Assert
.
True
(
cache
.
GetNumCacheItems
()
==
1
);
// Invoking code actions on the same unmodified document and range should use the existing cached item
// 1. Invoking code actions on document with empty cache.
await
RunCodeActionsAndAssertActionsInCacheAsync
(
workspace
,
cache
,
caretLocation
,
document
);
// Ensuring contents of cache are as expected.
var
docAndRange
=
testAccessor
.
GetDocumentsAndRangesInCache
().
Single
();
AssertRangeAndDocEqual
(
caretLocation
.
Range
,
document
,
docAndRange
);
// 2. Invoking code actions on the same unmodified document and range should use the existing cached item
// instead of generating a new cached item.
await
RunGetCodeActionsAsync
(
workspace
.
CurrentSolution
,
caretLocation
);
cacheResults
=
await
cache
.
GetCacheAsync
(
document
,
caretLocation
.
Range
,
CancellationToken
.
None
);
Assert
.
True
(
cache
.
GetNumCacheItems
()
==
1
);
await
RunCodeActionsAndAssertActionsInCacheAsync
(
workspace
,
cache
,
caretLocation
,
document
);
// Ensuring contents of cache are as expected.
docAndRange
=
testAccessor
.
GetDocumentsAndRangesInCache
().
Single
();
AssertRangeAndDocEqual
(
caretLocation
.
Range
,
document
,
docAndRange
);
var
originalRange
=
caretLocation
.
Range
;
// Invoking code actions on a different range should generate a new cached item.
//
3.
Invoking code actions on a different range should generate a new cached item.
caretLocation
.
Range
=
new
LSP
.
Range
{
Start
=
new
LSP
.
Position
()
{
Line
=
0
,
Character
=
0
},
End
=
new
LSP
.
Position
()
{
Line
=
0
,
Character
=
0
}
};
await
RunGetCodeActionsAsync
(
workspace
.
CurrentSolution
,
caretLocation
);
Assert
.
True
(
cache
.
GetNumCacheItems
()
==
2
);
await
RunCodeActionsAndAssertActionsInCacheAsync
(
workspace
,
cache
,
caretLocation
,
document
);
// Ensuring contents of cache are as expected.
var
docsAndRanges
=
testAccessor
.
GetDocumentsAndRangesInCache
();
Assert
.
True
(
docsAndRanges
.
Count
==
2
);
AssertRangeAndDocEqual
(
originalRange
,
document
,
docsAndRanges
[
0
]);
AssertRangeAndDocEqual
(
caretLocation
.
Range
,
document
,
docsAndRanges
[
1
]);
// Changing the document should generate a new cached item.
//
4.
Changing the document should generate a new cached item.
var
currentDocText
=
await
document
.
GetTextAsync
();
var
changedSourceText
=
currentDocText
.
WithChanges
(
new
TextChange
(
new
TextSpan
(
0
,
0
),
"class D { } \n"
));
var
docId
=
((
TestWorkspace
)
workspace
).
Documents
.
First
().
Id
;
((
TestWorkspace
)
workspace
).
ChangeDocument
(
docId
,
changedSourceText
);
UpdateSolutionProvider
((
TestWorkspace
)
workspace
,
workspace
.
CurrentSolution
);
var
updatedDocument
=
GetDocument
(
workspace
,
CreateTextDocumentIdentifier
(
caretLocation
.
Uri
));
await
RunGetCodeActionsAsync
(
workspace
.
CurrentSolution
,
caretLocation
);
Assert
.
True
(
cache
.
GetNumCacheItems
()
==
3
);
await
RunCodeActionsAndAssertActionsInCacheAsync
(
workspace
,
cache
,
caretLocation
,
updatedDocument
);
// Ensuring contents of cache are as expected.
docsAndRanges
=
testAccessor
.
GetDocumentsAndRangesInCache
();
AssertRangeAndDocEqual
(
originalRange
,
document
,
docsAndRanges
[
0
]);
AssertRangeAndDocEqual
(
caretLocation
.
Range
,
document
,
docsAndRanges
[
1
]);
AssertRangeAndDocEqual
(
caretLocation
.
Range
,
updatedDocument
,
docsAndRanges
[
2
]);
var
updatedRange
=
caretLocation
.
Range
;
// The current cache size is 3. Adding a 4th item to the cache should still keep the cache size the same.
// 5. The current cache size is 3. Adding a 4th item to the cache should still keep the cache size the same,
// and boot out the oldest item in the cache.
caretLocation
.
Range
=
new
LSP
.
Range
{
Start
=
new
LSP
.
Position
()
{
Line
=
0
,
Character
=
0
},
End
=
new
LSP
.
Position
()
{
Line
=
0
,
Character
=
1
}
};
await
RunCodeActionsAndAssertActionsInCacheAsync
(
workspace
,
cache
,
caretLocation
,
updatedDocument
);
// Ensuring contents of cache are as expected.
docsAndRanges
=
testAccessor
.
GetDocumentsAndRangesInCache
();
AssertRangeAndDocEqual
(
updatedRange
,
document
,
docsAndRanges
[
0
]);
AssertRangeAndDocEqual
(
updatedRange
,
updatedDocument
,
docsAndRanges
[
1
]);
AssertRangeAndDocEqual
(
caretLocation
.
Range
,
updatedDocument
,
docsAndRanges
[
2
]);
}
private
static
async
Task
RunCodeActionsAndAssertActionsInCacheAsync
(
Workspace
workspace
,
CodeActionsCache
cache
,
LSP
.
Location
caretLocation
,
Document
document
)
{
await
RunGetCodeActionsAsync
(
workspace
.
CurrentSolution
,
caretLocation
);
Assert
.
True
(
cache
.
GetNumCacheItems
()
==
3
);
var
cacheResults
=
await
cache
.
GetActionSetsAsync
(
document
,
caretLocation
.
Range
,
CancellationToken
.
None
);
Assert
.
NotNull
(
cacheResults
);
}
private
static
void
AssertRangeAndDocEqual
(
LSP
.
Range
range
,
Document
document
,
(
Document
Document
,
LSP
.
Range
Range
)
actualDocAndRange
)
{
Assert
.
Equal
(
document
,
actualDocAndRange
.
Document
);
Assert
.
Equal
(
range
.
Start
,
actualDocAndRange
.
Range
.
Start
);
Assert
.
Equal
(
range
.
End
,
actualDocAndRange
.
Range
.
End
);
}
private
static
async
Task
<
LSP
.
VSCodeAction
[
]>
RunGetCodeActionsAsync
(
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录