Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
08afa998
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,发现更多精彩内容 >>
提交
08afa998
编写于
8月 01, 2017
作者:
R
Ravi Chande
提交者:
GitHub
8月 01, 2017
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'dev15.4.x' into ctrl-click-gtd
上级
76f8f9fe
f86341a6
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
218 addition
and
121 deletion
+218
-121
build/Defaults/Portable/app.config
build/Defaults/Portable/app.config
+1
-1
src/Compilers/Extension/CompilerExtension.csproj
src/Compilers/Extension/CompilerExtension.csproj
+4
-4
src/EditorFeatures/Core/Implementation/CodeFixes/CodeFixService.cs
...rFeatures/Core/Implementation/CodeFixes/CodeFixService.cs
+59
-30
src/EditorFeatures/Core/Implementation/CodeFixes/ICodeFixService.cs
...Features/Core/Implementation/CodeFixes/ICodeFixService.cs
+1
-2
src/EditorFeatures/Core/Implementation/Suggestions/SuggestedActionsSource.cs
...Core/Implementation/Suggestions/SuggestedActionsSource.cs
+138
-79
src/EditorFeatures/Core/Implementation/Suggestions/SuggestedActionsSourceProvider.cs
...lementation/Suggestions/SuggestedActionsSourceProvider.cs
+4
-1
src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
+2
-2
src/Tools/GenerateSdkPackages/files.txt
src/Tools/GenerateSdkPackages/files.txt
+1
-0
src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
+3
-0
src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj
src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj
+5
-2
未找到文件。
build/Defaults/Portable/app.config
浏览文件 @
08afa998
...
...
@@ -75,7 +75,7 @@
</
dependentAssembly
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"Newtonsoft.Json"
publicKeyToken
=
"30ad4fe6b2a6aeed"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-
8.0.0.0"
newVersion
=
"8
.0.0.0"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-
9.0.0.0"
newVersion
=
"9
.0.0.0"
/>
</
dependentAssembly
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"Microsoft.VisualStudio.Validation"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
...
...
src/Compilers/Extension/CompilerExtension.csproj
浏览文件 @
08afa998
...
...
@@ -170,10 +170,10 @@
</PackageReference>
<PackageReference
Include=
"Microsoft.VisualStudio.Utilities"
>
<Version>
$(MicrosoftVisualStudioUtilitiesVersion)
</Version>
</PackageReference>
<PackageReference
Include=
"Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime"
>
<Version>
$(MicrosoftVisualStudioShellInterop153DesignTimeVersion)
</Version>
</PackageReference>
</PackageReference>
<PackageReference
Include=
"Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime"
>
<Version>
$(MicrosoftVisualStudioShellInterop153DesignTimeVersion)
</Version>
</PackageReference>
</ItemGroup>
<Import
Project=
"..\..\..\build\Targets\Imports.targets"
/>
</Project>
src/EditorFeatures/Core/Implementation/CodeFixes/CodeFixService.cs
浏览文件 @
08afa998
...
...
@@ -73,7 +73,7 @@ internal partial class CodeFixService : ForegroundThreadAffinitizedObject, ICode
_fixAllProviderMap
=
ImmutableDictionary
<
object
,
FixAllProviderInfo
>.
Empty
;
}
public
async
Task
<
FirstDiagnosticResult
>
Get
FirstDiagnosticWithFixAsyn
c
(
public
async
Task
<
FirstDiagnosticResult
>
Get
MostSevereFixableDiagnosti
c
(
Document
document
,
TextSpan
range
,
CancellationToken
cancellationToken
)
{
if
(
document
==
null
||
!
document
.
IsOpen
())
...
...
@@ -83,32 +83,61 @@ internal partial class CodeFixService : ForegroundThreadAffinitizedObject, ICode
using
(
var
diagnostics
=
SharedPools
.
Default
<
List
<
DiagnosticData
>>().
GetPooledObject
())
{
var
fullResult
=
await
_diagnosticService
.
TryAppendDiagnosticsForSpanAsync
(
document
,
range
,
diagnostics
.
Object
,
cancellationToken
:
cancellationToken
).
ConfigureAwait
(
false
);
foreach
(
var
diagnostic
in
diagnostics
.
Object
)
using
(
var
linkedTokenSource
=
CancellationTokenSource
.
CreateLinkedTokenSource
(
cancellationToken
))
{
cancellationToken
.
ThrowIfCancellationRequested
();
if
(!
range
.
IntersectsWith
(
diagnostic
.
TextSpan
))
{
continue
;
}
var
linkedToken
=
linkedTokenSource
.
Token
;
// This flag is used by SuggestedActionsSource to track what solution is was
// last able to get "full results" for.
var
isFullResult
=
await
_diagnosticService
.
TryAppendDiagnosticsForSpanAsync
(
document
,
range
,
diagnostics
.
Object
,
cancellationToken
:
linkedToken
).
ConfigureAwait
(
false
);
var
errorDiagnostics
=
diagnostics
.
Object
.
Where
(
d
=>
d
.
Severity
==
DiagnosticSeverity
.
Error
);
var
otherDiagnostics
=
diagnostics
.
Object
.
Where
(
d
=>
d
.
Severity
!=
DiagnosticSeverity
.
Error
);
// Kick off a task that will determine there's an Error Diagnostic with a fixer
var
errorDiagnosticsTask
=
Task
.
Run
(
()
=>
GetFirstDiagnosticWithFixAsync
(
document
,
errorDiagnostics
,
range
,
linkedToken
),
linkedToken
);
// Kick off a task that will determine if any non-Error Diagnostic has a fixer
var
otherDiagnosticsTask
=
Task
.
Run
(
()
=>
GetFirstDiagnosticWithFixAsync
(
document
,
otherDiagnostics
,
range
,
linkedToken
),
linkedToken
);
// If the error diagnostics task happens to complete with a non-null result before
// the other diagnostics task, we can cancel the other task.
var
diagnostic
=
await
errorDiagnosticsTask
.
ConfigureAwait
(
false
)
??
await
otherDiagnosticsTask
.
ConfigureAwait
(
false
);
linkedTokenSource
.
Cancel
();
return
new
FirstDiagnosticResult
(
partialResult
:
!
isFullResult
,
hasFix
:
diagnostic
!=
null
,
diagnostic
:
diagnostic
);
}
}
}
// REVIEW: 2 possible designs.
// 1. find the first fix and then return right away. if the lightbulb is actually expanded, find all fixes for the line synchronously. or
// 2. kick off a task that finds all fixes for the given range here but return once we find the first one.
// at the same time, let the task to run to finish. if the lightbulb is expanded, we just simply use the task to get all fixes.
//
// first approach is simpler, so I will implement that first. if the first approach turns out to be not good enough, then
// I will try the second approach which will be more complex but quicker
var
hasFix
=
await
ContainsAnyFix
(
document
,
diagnostic
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
hasFix
)
{
return
new
FirstDiagnosticResult
(!
fullResult
,
hasFix
,
diagnostic
);
}
private
async
Task
<
DiagnosticData
>
GetFirstDiagnosticWithFixAsync
(
Document
document
,
IEnumerable
<
DiagnosticData
>
severityGroup
,
TextSpan
range
,
CancellationToken
cancellationToken
)
{
foreach
(
var
diagnostic
in
severityGroup
)
{
if
(!
range
.
IntersectsWith
(
diagnostic
.
TextSpan
))
{
continue
;
}
return
new
FirstDiagnosticResult
(!
fullResult
,
false
,
default
(
DiagnosticData
));
if
(
await
ContainsAnyFixAsync
(
document
,
diagnostic
,
cancellationToken
).
ConfigureAwait
(
false
))
{
return
diagnostic
;
}
}
return
null
;
}
public
async
Task
<
ImmutableArray
<
CodeFixCollection
>>
GetFixesAsync
(
Document
document
,
TextSpan
range
,
bool
includeSuppressionFixes
,
CancellationToken
cancellationToken
)
...
...
@@ -142,7 +171,7 @@ public async Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document docu
foreach
(
var
spanAndDiagnostic
in
aggregatedDiagnostics
)
{
await
AppendFixesAsync
(
document
,
spanAndDiagnostic
.
Key
,
spanAndDiagnostic
.
Value
,
document
,
spanAndDiagnostic
.
Key
,
spanAndDiagnostic
.
Value
,
result
,
cancellationToken
).
ConfigureAwait
(
false
);
}
...
...
@@ -176,7 +205,7 @@ public async Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document docu
foreach
(
var
spanAndDiagnostic
in
aggregatedDiagnostics
)
{
await
AppendSuppressionsAsync
(
document
,
spanAndDiagnostic
.
Key
,
spanAndDiagnostic
.
Value
,
document
,
spanAndDiagnostic
.
Key
,
spanAndDiagnostic
.
Value
,
result
,
cancellationToken
).
ConfigureAwait
(
false
);
}
}
...
...
@@ -267,7 +296,7 @@ public async Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document docu
}
private
async
Task
AppendSuppressionsAsync
(
Document
document
,
TextSpan
span
,
IEnumerable
<
DiagnosticData
>
diagnostics
,
Document
document
,
TextSpan
span
,
IEnumerable
<
DiagnosticData
>
diagnostics
,
ArrayBuilder
<
CodeFixCollection
>
result
,
CancellationToken
cancellationToken
)
{
if
(!
_suppressionProvidersMap
.
TryGetValue
(
document
.
Project
.
Language
,
out
var
lazySuppressionProvider
)
||
lazySuppressionProvider
.
Value
==
null
)
...
...
@@ -276,10 +305,10 @@ public async Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document docu
}
await
AppendFixesOrSuppressionsAsync
(
document
,
span
,
diagnostics
,
result
,
lazySuppressionProvider
.
Value
,
document
,
span
,
diagnostics
,
result
,
lazySuppressionProvider
.
Value
,
hasFix
:
d
=>
lazySuppressionProvider
.
Value
.
CanBeSuppressedOrUnsuppressed
(
d
),
getFixes
:
dxs
=>
lazySuppressionProvider
.
Value
.
GetSuppressionsAsync
(
document
,
span
,
dxs
,
cancellationToken
),
document
,
span
,
dxs
,
cancellationToken
),
cancellationToken
:
cancellationToken
).
ConfigureAwait
(
false
);
}
...
...
@@ -293,7 +322,7 @@ public async Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document docu
Func
<
ImmutableArray
<
Diagnostic
>,
Task
<
ImmutableArray
<
CodeFix
>>>
getFixes
,
CancellationToken
cancellationToken
)
{
var
allDiagnostics
=
var
allDiagnostics
=
await
diagnosticsWithSameSpan
.
OrderByDescending
(
d
=>
d
.
Severity
)
.
ToDiagnosticsAsync
(
document
.
Project
,
cancellationToken
).
ConfigureAwait
(
false
);
var
diagnostics
=
allDiagnostics
.
WhereAsArray
(
hasFix
);
...
...
@@ -372,7 +401,7 @@ private async Task<IEnumerable<Diagnostic>> GetProjectDiagnosticsAsync(Project p
}
}
private
async
Task
<
bool
>
ContainsAnyFix
(
private
async
Task
<
bool
>
ContainsAnyFix
Async
(
Document
document
,
DiagnosticData
diagnostic
,
CancellationToken
cancellationToken
)
{
var
workspaceFixers
=
ImmutableArray
<
CodeFixProvider
>.
Empty
;
...
...
@@ -387,7 +416,7 @@ private async Task<IEnumerable<Diagnostic>> GetProjectDiagnosticsAsync(Project p
}
Lazy
<
ISuppressionFixProvider
>
lazySuppressionProvider
=
null
;
var
hasSuppressionFixer
=
var
hasSuppressionFixer
=
_suppressionProvidersMap
.
TryGetValue
(
document
.
Project
.
Language
,
out
lazySuppressionProvider
)
&&
lazySuppressionProvider
.
Value
!=
null
;
...
...
src/EditorFeatures/Core/Implementation/CodeFixes/ICodeFixService.cs
浏览文件 @
08afa998
...
...
@@ -10,9 +10,8 @@ namespace Microsoft.CodeAnalysis.CodeFixes
{
internal
interface
ICodeFixService
{
Task
<
FirstDiagnosticResult
>
GetFirstDiagnosticWithFixAsync
(
Document
document
,
TextSpan
textSpan
,
CancellationToken
cancellationToken
);
Task
<
ImmutableArray
<
CodeFixCollection
>>
GetFixesAsync
(
Document
document
,
TextSpan
textSpan
,
bool
includeSuppressionFixes
,
CancellationToken
cancellationToken
);
CodeFixProvider
GetSuppressionFixer
(
string
language
,
IEnumerable
<
string
>
diagnosticIds
);
Task
<
FirstDiagnosticResult
>
GetMostSevereFixableDiagnostic
(
Document
document
,
TextSpan
range
,
CancellationToken
cancellationToken
);
}
}
src/EditorFeatures/Core/Implementation/Suggestions/SuggestedActionsSource.cs
浏览文件 @
08afa998
...
...
@@ -24,14 +24,17 @@
using
Microsoft.VisualStudio.Text.Editor
;
using
Roslyn.Utilities
;
using
CodeFixGroupKey
=
System
.
Tuple
<
Microsoft
.
CodeAnalysis
.
Diagnostics
.
DiagnosticData
,
Microsoft
.
CodeAnalysis
.
CodeActions
.
CodeActionPriority
>;
namespace
Microsoft.CodeAnalysis.Editor.Implementation.Suggestions
{
using
CodeFixGroupKey
=
Tuple
<
DiagnosticData
,
CodeActionPriority
>;
internal
partial
class
SuggestedActionsSourceProvider
{
private
class
SuggestedActionsSource
:
ForegroundThreadAffinitizedObject
,
ISuggestedActionsSource
private
class
SuggestedActionsSource
:
ForegroundThreadAffinitizedObject
,
ISuggestedActionsSource
2
{
private
readonly
ISuggestedActionCategoryRegistryService
_suggestedActionCategoryRegistry
;
// state that will be only reset when source is disposed.
private
SuggestedActionsSourceProvider
_owner
;
private
ITextView
_textView
;
...
...
@@ -44,12 +47,17 @@ private class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISugge
public
event
EventHandler
<
EventArgs
>
SuggestedActionsChanged
;
public
SuggestedActionsSource
(
SuggestedActionsSourceProvider
owner
,
ITextView
textView
,
ITextBuffer
textBuffer
)
public
SuggestedActionsSource
(
SuggestedActionsSourceProvider
owner
,
ITextView
textView
,
ITextBuffer
textBuffer
,
ISuggestedActionCategoryRegistryService
suggestedActionCategoryRegistry
)
{
_owner
=
owner
;
_textView
=
textView
;
_textView
.
Closed
+=
OnTextViewClosed
;
_subjectBuffer
=
textBuffer
;
_suggestedActionCategoryRegistry
=
suggestedActionCategoryRegistry
;
_registration
=
Workspace
.
GetWorkspaceRegistration
(
textBuffer
.
AsTextContainer
());
_lastSolutionVersionReported
=
InvalidSolutionVersion
;
...
...
@@ -221,7 +229,7 @@ private SuggestedActionSet FilterActionSetByTitle(SuggestedActionSet set, HashSe
{
return
actions
.
Count
==
0
?
null
:
new
SuggestedActionSet
(
actions
.
ToImmutable
(),
set
.
Title
,
set
.
Priority
,
set
.
ApplicableToSpan
);
:
new
SuggestedActionSet
(
set
.
CategoryName
,
actions
.
ToImmutable
(),
set
.
Title
,
set
.
Priority
,
set
.
ApplicableToSpan
);
}
finally
{
...
...
@@ -261,7 +269,11 @@ private SuggestedActionSet InlineActions(SuggestedActionSet actionSet)
}
return
new
SuggestedActionSet
(
newActions
.
ToImmutableAndFree
(),
actionSet
.
Title
,
actionSet
.
Priority
,
actionSet
.
ApplicableToSpan
);
actionSet
.
CategoryName
,
newActions
.
ToImmutableAndFree
(),
actionSet
.
Title
,
actionSet
.
Priority
,
actionSet
.
ApplicableToSpan
);
}
private
ImmutableArray
<
SuggestedActionSet
>
GetCodeFixes
(
...
...
@@ -529,13 +541,29 @@ private CodeRefactoring FilterOnUIThread(CodeRefactoring refactoring, Workspace
// diagnostic from things like build shouldn't reach here since we don't support LB for those diagnostics
Contract
.
Requires
(
diag
.
Item1
.
HasTextSpan
);
sets
.
Add
(
new
SuggestedActionSet
(
group
,
priority
,
diag
.
Item1
.
TextSpan
.
ToSpan
()));
var
category
=
GetFixCategory
(
diag
.
Item1
.
Severity
);
sets
.
Add
(
new
SuggestedActionSet
(
category
,
group
,
priority
:
priority
,
applicableToSpan
:
diag
.
Item1
.
TextSpan
.
ToSpan
()));
}
}
return
sets
.
ToImmutableAndFree
();
}
private
static
string
GetFixCategory
(
DiagnosticSeverity
severity
)
{
switch
(
severity
)
{
case
DiagnosticSeverity
.
Hidden
:
case
DiagnosticSeverity
.
Info
:
case
DiagnosticSeverity
.
Warning
:
return
PredefinedSuggestedActionCategoryNames
.
CodeFix
;
case
DiagnosticSeverity
.
Error
:
return
PredefinedSuggestedActionCategoryNames
.
ErrorFix
;
default
:
throw
ExceptionUtilities
.
Unreachable
;
};
}
private
static
SuggestedActionSetPriority
GetSuggestedActionSetPriority
(
CodeActionPriority
key
)
{
switch
(
key
)
...
...
@@ -619,87 +647,81 @@ private static SuggestedActionSetPriority GetSuggestedActionSetPriority(CodeActi
}
return
new
SuggestedActionSet
(
PredefinedSuggestedActionCategoryNames
.
Refactoring
,
refactoringSuggestedActions
.
ToImmutableAndFree
(),
SuggestedActionSetPriority
.
Low
,
applicableSpan
);
priority
:
SuggestedActionSetPriority
.
Low
,
applicable
ToSpan
:
applicable
Span
);
}
public
async
Task
<
bool
>
HasSuggestedActionsAsync
(
public
Task
<
bool
>
HasSuggestedActionsAsync
(
ISuggestedActionCategorySet
requestedActionCategories
,
SnapshotSpan
range
,
CancellationToken
cancellationToken
)
{
var
provider
=
_owner
;
// We implement GetSuggestedActionCategoriesAsync so this should not be called
throw
new
NotImplementedException
(
$"We implement
{
nameof
(
GetSuggestedActionCategoriesAsync
)}
. This should not be called."
);
}
if
(
IsDisposed
)
private
async
Task
<
TextSpan
?>
GetSpanAsync
(
SnapshotSpan
range
)
{
// First, ensure that the snapshot we're being asked about is for an actual
// roslyn document. This can fail, for example, in projection scenarios where
// we are called with a range snapshot that refers to the projection buffer
// and not the actual roslyn code that is being projected into it.
var
document
=
range
.
Snapshot
.
GetOpenDocumentInCurrentContextWithChanges
();
if
(
document
==
null
)
{
// We've already been disposed. No point in continuing.
return
false
;
return
null
;
}
using
(
var
asyncToken
=
_owner
.
OperationListener
.
BeginAsyncOperation
(
"HasSuggestedActionsAsync"
))
{
// First, ensure that the snapshot we're being asked about is for an actual
// roslyn document. This can fail, for example, in projection scenarios where
// we are called with a range snapshot that refers to the projection buffer
// and not the actual roslyn code that is being projected into it.
var
document
=
range
.
Snapshot
.
GetOpenDocumentInCurrentContextWithChanges
();
if
(
document
==
null
)
{
return
false
;
}
// Next, before we do any async work, acquire the user's selection, directly grabbing
// it from the UI thread if htat's what we're on. That way we don't have any reentrancy
// blocking concerns if VS wants to block on this call (for example, if the user
// explicitly invokes the 'show smart tag' command).
//
// This work must happen on the UI thread as it needs to access the _textView's mutable
// state.
//
// Note: we may be called in one of two VS scenarios:
// 1) User has moved caret to a new line. In this case VS will call into us in the
// bg to see if we have any suggested actions for this line. In order to figure
// this out, we need to see what selectoin the user has (for refactorings), which
// necessitates going back to the fg.
//
// 2) User moves to a line and immediately hits ctrl-dot. In this case, on the UI
// thread VS will kick us off and then immediately block to get the results so
// that they can expand the lightbulb. In this case we cannot do BG work first,
// then call back into the UI thread to try to get the user selection. This will
// deadlock as the UI thread is blocked on us.
//
// There are two solution to '2'. Either introduce reentrancy (which we really don't
// like to do), or just ensure that we acquire and get the users selection up front.
// This means that when we're called from the UI therad, we never try to go back to the
// UI thread.
TextSpan
?
selection
=
null
;
if
(
IsForeground
())
{
selection
=
TryGetCodeRefactoringSelection
(
range
);
}
else
// Next, before we do any async work, acquire the user's selection, directly grabbing
// it from the UI thread if htat's what we're on. That way we don't have any reentrancy
// blocking concerns if VS wants to block on this call (for example, if the user
// explicitly invokes the 'show smart tag' command).
//
// This work must happen on the UI thread as it needs to access the _textView's mutable
// state.
//
// Note: we may be called in one of two VS scenarios:
// 1) User has moved caret to a new line. In this case VS will call into us in the
// bg to see if we have any suggested actions for this line. In order to figure
// this out, we need to see what selectoin the user has (for refactorings), which
// necessitates going back to the fg.
//
// 2) User moves to a line and immediately hits ctrl-dot. In this case, on the UI
// thread VS will kick us off and then immediately block to get the results so
// that they can expand the lightbulb. In this case we cannot do BG work first,
// then call back into the UI thread to try to get the user selection. This will
// deadlock as the UI thread is blocked on us.
//
// There are two solution to '2'. Either introduce reentrancy (which we really don't
// like to do), or just ensure that we acquire and get the users selection up front.
// This means that when we're called from the UI therad, we never try to go back to the
// UI thread.
TextSpan
?
selection
=
null
;
if
(
IsForeground
())
{
selection
=
TryGetCodeRefactoringSelection
(
range
);
}
else
{
await
InvokeBelowInputPriority
(()
=>
{
await
InvokeBelowInputPriority
(()
=>
// Make sure we were not disposed between kicking off this work and getting
// to this point.
if
(
IsDisposed
)
{
// Make sure we were not disposed between kicking off this work and getting
// to this point.
if
(
IsDisposed
)
{
return
;
}
selection
=
TryGetCodeRefactoringSelection
(
range
);
}).
ConfigureAwait
(
false
);
}
return
;
}
return
await
HasFixesAsync
(
provider
,
document
,
range
,
cancellationToken
).
ConfigureAwait
(
false
)
||
await
HasRefactoringsAsync
(
provider
,
document
,
selection
,
cancellationToken
).
ConfigureAwait
(
false
);
selection
=
TryGetCodeRefactoringSelection
(
range
);
}).
ConfigureAwait
(
false
);
}
return
selection
;
}
private
async
Task
<
bool
>
HasFixes
Async
(
private
async
Task
<
string
>
GetFixLevel
Async
(
SuggestedActionsSourceProvider
provider
,
Document
document
,
SnapshotSpan
range
,
...
...
@@ -712,28 +734,28 @@ private static SuggestedActionSetPriority GetSuggestedActionSetPriority(CodeActi
supportsFeatureService
.
SupportsCodeFixes
(
document
))
{
var
result
=
await
Task
.
Run
(
()
=>
provider
.
_codeFixService
.
Get
FirstDiagnosticWithFixAsyn
c
(
()
=>
provider
.
_codeFixService
.
Get
MostSevereFixableDiagnosti
c
(
document
,
range
.
Span
.
ToTextSpan
(),
cancellationToken
),
cancellationToken
).
ConfigureAwait
(
false
);
if
(
result
.
HasFix
)
{
Logger
.
Log
(
FunctionId
.
SuggestedActions_HasSuggestedActionsAsync
);
return
true
;
return
GetFixCategory
(
result
.
Diagnostic
.
Severity
)
;
}
if
(
result
.
PartialResult
)
{
// reset solution version number so that we can raise suggested action changed event
Volatile
.
Write
(
ref
_lastSolutionVersionReported
,
InvalidSolutionVersion
);
return
false
;
return
null
;
}
}
return
false
;
return
null
;
}
private
async
Task
<
bool
>
HasRefactorings
Async
(
private
async
Task
<
string
>
TryGetRefactoringSuggestedActionCategory
Async
(
SuggestedActionsSourceProvider
provider
,
Document
document
,
TextSpan
?
selection
,
...
...
@@ -743,7 +765,7 @@ private static SuggestedActionSetPriority GetSuggestedActionSetPriority(CodeActi
{
// this is here to fail test and see why it is failed.
Trace
.
WriteLine
(
"given range is not current"
);
return
false
;
return
null
;
}
var
workspace
=
document
.
Project
.
Solution
.
Workspace
;
...
...
@@ -753,13 +775,16 @@ private static SuggestedActionSetPriority GetSuggestedActionSetPriority(CodeActi
provider
.
_codeRefactoringService
!=
null
&&
supportsFeatureService
.
SupportsRefactorings
(
document
))
{
return
await
Task
.
Run
(
if
(
await
Task
.
Run
(
()
=>
provider
.
_codeRefactoringService
.
HasRefactoringsAsync
(
document
,
selection
.
Value
,
cancellationToken
),
cancellationToken
).
ConfigureAwait
(
false
);
cancellationToken
).
ConfigureAwait
(
false
))
{
return
PredefinedSuggestedActionCategoryNames
.
Refactoring
;
}
}
return
false
;
return
null
;
}
private
TextSpan
?
TryGetCodeRefactoringSelection
(
SnapshotSpan
range
)
...
...
@@ -860,6 +885,40 @@ private void OnSuggestedActionsChanged(Workspace currentWorkspace, DocumentId cu
Volatile
.
Write
(
ref
_lastSolutionVersionReported
,
solutionVersion
);
}
public
async
Task
<
ISuggestedActionCategorySet
>
GetSuggestedActionCategoriesAsync
(
ISuggestedActionCategorySet
requestedActionCategories
,
SnapshotSpan
range
,
CancellationToken
cancellationToken
)
{
var
provider
=
_owner
;
using
(
var
asyncToken
=
_owner
.
OperationListener
.
BeginAsyncOperation
(
nameof
(
GetSuggestedActionCategoriesAsync
)))
{
var
selection
=
await
GetSpanAsync
(
range
).
ConfigureAwait
(
false
);
if
(
selection
!=
null
)
{
var
document
=
range
.
Snapshot
.
GetOpenDocumentInCurrentContextWithChanges
();
using
(
var
linkedTokenSource
=
CancellationTokenSource
.
CreateLinkedTokenSource
(
cancellationToken
))
{
var
linkedToken
=
linkedTokenSource
.
Token
;
var
errorTask
=
Task
.
Run
(
()
=>
GetFixLevelAsync
(
provider
,
document
,
range
,
linkedToken
),
linkedToken
);
var
refactoringTask
=
Task
.
Run
(
()
=>
TryGetRefactoringSuggestedActionCategoryAsync
(
provider
,
document
,
selection
,
linkedToken
),
linkedToken
);
// If we happen to get the result of the error task before the refactoring task,
// and that result is non-null, we can just cancel the refactoring task.
var
result
=
await
errorTask
.
ConfigureAwait
(
false
)
??
await
refactoringTask
.
ConfigureAwait
(
false
);
linkedTokenSource
.
Cancel
();
return
result
==
null
?
null
:
_suggestedActionCategoryRegistry
.
CreateSuggestedActionCategorySet
(
result
);
}
}
}
return
null
;
}
}
}
}
\ No newline at end of file
src/EditorFeatures/Core/Implementation/Suggestions/SuggestedActionsSourceProvider.cs
浏览文件 @
08afa998
...
...
@@ -35,6 +35,7 @@ internal partial class SuggestedActionsSourceProvider : ISuggestedActionsSourceP
private
readonly
ICodeRefactoringService
_codeRefactoringService
;
private
readonly
IDiagnosticAnalyzerService
_diagnosticService
;
private
readonly
ICodeFixService
_codeFixService
;
private
readonly
ISuggestedActionCategoryRegistryService
_suggestedActionCategoryRegistry
;
public
readonly
ICodeActionEditHandlerService
EditHandler
;
public
readonly
IAsynchronousOperationListener
OperationListener
;
...
...
@@ -50,6 +51,7 @@ internal partial class SuggestedActionsSourceProvider : ISuggestedActionsSourceP
ICodeFixService
codeFixService
,
ICodeActionEditHandlerService
editHandler
,
IWaitIndicator
waitIndicator
,
ISuggestedActionCategoryRegistryService
suggestedActionCategoryRegistry
,
[
ImportMany
]
IEnumerable
<
Lazy
<
IAsynchronousOperationListener
,
FeatureMetadata
>>
asyncListeners
,
[
ImportMany
]
IEnumerable
<
Lazy
<
IImageMonikerService
,
OrderableMetadata
>>
imageMonikerServices
,
[
ImportMany
]
IEnumerable
<
Lazy
<
ISuggestedActionCallback
>>
actionCallbacks
)
...
...
@@ -57,6 +59,7 @@ internal partial class SuggestedActionsSourceProvider : ISuggestedActionsSourceP
_codeRefactoringService
=
codeRefactoringService
;
_diagnosticService
=
diagnosticService
;
_codeFixService
=
codeFixService
;
_suggestedActionCategoryRegistry
=
suggestedActionCategoryRegistry
;
ActionCallbacks
=
actionCallbacks
.
ToImmutableArray
();
EditHandler
=
editHandler
;
WaitIndicator
=
waitIndicator
;
...
...
@@ -70,7 +73,7 @@ public ISuggestedActionsSource CreateSuggestedActionsSource(ITextView textView,
Contract
.
ThrowIfNull
(
textView
);
Contract
.
ThrowIfNull
(
textBuffer
);
return
new
SuggestedActionsSource
(
this
,
textView
,
textBuffer
);
return
new
SuggestedActionsSource
(
this
,
textView
,
textBuffer
,
_suggestedActionCategoryRegistry
);
}
}
}
\ No newline at end of file
src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
浏览文件 @
08afa998
...
...
@@ -46,7 +46,7 @@ public async Task TestGetFirstDiagnosticWithFixAsync()
var
reference
=
new
MockAnalyzerReference
();
var
project
=
workspace
.
CurrentSolution
.
Projects
.
Single
().
AddAnalyzerReference
(
reference
);
var
document
=
project
.
Documents
.
Single
();
var
unused
=
await
fixService
.
Get
FirstDiagnosticWithFixAsyn
c
(
document
,
TextSpan
.
FromBounds
(
0
,
0
),
cancellationToken
:
CancellationToken
.
None
);
var
unused
=
await
fixService
.
Get
MostSevereFixableDiagnosti
c
(
document
,
TextSpan
.
FromBounds
(
0
,
0
),
cancellationToken
:
CancellationToken
.
None
);
var
fixer1
=
fixers
.
Single
().
Value
as
MockFixer
;
var
fixer2
=
reference
.
Fixer
as
MockFixer
;
...
...
@@ -127,7 +127,7 @@ public async Task GetFirstDiagnosticWithFixAsync(CodeFixProvider codefix)
using
(
var
workspace
=
tuple
.
Item1
)
{
GetDocumentAndExtensionManager
(
tuple
.
Item2
,
workspace
,
out
var
document
,
out
var
extensionManager
);
var
unused
=
await
tuple
.
Item3
.
Get
FirstDiagnosticWithFixAsyn
c
(
document
,
TextSpan
.
FromBounds
(
0
,
0
),
cancellationToken
:
CancellationToken
.
None
);
var
unused
=
await
tuple
.
Item3
.
Get
MostSevereFixableDiagnosti
c
(
document
,
TextSpan
.
FromBounds
(
0
,
0
),
cancellationToken
:
CancellationToken
.
None
);
Assert
.
True
(
extensionManager
.
IsDisabled
(
codefix
));
Assert
.
False
(
extensionManager
.
IsIgnored
(
codefix
));
}
...
...
src/Tools/GenerateSdkPackages/files.txt
浏览文件 @
08afa998
...
...
@@ -20,6 +20,7 @@ Microsoft.VisualStudio.Utilities.dll
Microsoft.VisualStudio.Platform.VSEditor.dll
Microsoft.VisualStudio.Platform.VSEditor.Interop.dll
Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime.dll
Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.dll
Microsoft.Internal.Performance.CodeMarkers.DesignTime.dll
PackageAndDeploy\Microsoft.VisualStudio.Shell.Framework.dll
PackageAndDeploy\Microsoft.VisualStudio.Shell.15.0.dll
...
...
src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
浏览文件 @
08afa998
...
...
@@ -345,6 +345,9 @@
</PackageReference>
<PackageReference
Include=
"Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime"
>
<Version>
$(MicrosoftVisualStudioShellInterop150DesignTimeVersion)
</Version>
</PackageReference>
<PackageReference
Include=
"Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime"
>
<Version>
$(MicrosoftVisualStudioShellInterop153DesignTimeVersion)
</Version>
</PackageReference>
<PackageReference
Include=
"Microsoft.VisualStudio.Shell.15.0"
>
<Version>
$(MicrosoftVisualStudioShell150Version)
</Version>
...
...
src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj
浏览文件 @
08afa998
...
...
@@ -126,12 +126,15 @@
<PackageReference
Include=
"Microsoft.VisualStudio.Diagnostics.PerformanceProvider"
>
<Version>
$(MicrosoftVisualStudioDiagnosticsPerformanceProviderVersion)
</Version>
</PackageReference>
<PackageReference
Include=
"Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime"
>
<PackageReference
Include=
"Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime"
>
<Version>
$(MicrosoftVisualStudioShellInterop153DesignTimeVersion)
</Version>
</PackageReference>
<PackageReference
Include=
"StreamJsonRPC"
>
<PackageReference
Include=
"StreamJsonRPC"
>
<Version>
$(StreamJsonRPCVersion)
</Version>
</PackageReference>
<PackageReference
Include=
"Microsoft.VisualStudio.Threading"
>
<Version>
$(MicrosoftVisualStudioThreadingVersion)
</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<PublicAPI
Include=
"PublicAPI.Shipped.txt"
/>
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录