Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
fd755683
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,发现更多精彩内容 >>
提交
fd755683
编写于
7月 14, 2017
作者:
C
CyrusNajmabadi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Switch to a diagnostic analyzer.
上级
073282b9
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
129 addition
and
44 deletion
+129
-44
src/EditorFeatures/CSharpTest/UsePatternMatching/CSharpIsAndCastCheckCodeRefactoringProviderTests.cs
...ching/CSharpIsAndCastCheckCodeRefactoringProviderTests.cs
+6
-5
src/Features/CSharp/Portable/UsePatternMatching/CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer.cs
...hing/CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer.cs
+112
-38
src/Features/Core/Portable/Diagnostics/Analyzers/IDEDiagnosticIds.cs
...s/Core/Portable/Diagnostics/Analyzers/IDEDiagnosticIds.cs
+3
-0
src/Workspaces/Core/Portable/CodeFixes/SyntaxEditorBasedCodeFixProvider.cs
...re/Portable/CodeFixes/SyntaxEditorBasedCodeFixProvider.cs
+8
-1
未找到文件。
src/EditorFeatures/CSharpTest/UsePatternMatching/CSharpIsAndCastCheckCodeRefactoringProviderTests.cs
浏览文件 @
fd755683
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Code
Refactoring
s
;
using
Microsoft.CodeAnalysis.Code
Fixe
s
;
using
Microsoft.CodeAnalysis.CSharp.UsePatternMatching
;
using
Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings
;
using
Microsoft.CodeAnalysis.Diagnostics
;
using
Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics
;
using
Roslyn.Test.Utilities
;
using
Xunit
;
namespace
Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UsePatternMatching
{
public
partial
class
CSharpIsAndCastCheckCodeRefactoringProviderTests
:
AbstractCSharp
CodeAction
Test
public
partial
class
CSharpIsAndCastCheckCodeRefactoringProviderTests
:
AbstractCSharp
DiagnosticProviderBasedUserDiagnostic
Test
{
protected
override
CodeRefactoringProvider
CreateCodeRefactoringProvider
(
Workspace
workspace
,
TestParameters
parameters
)
=>
new
CSharpIsAndCastCheckCodeRefactoringProvider
(
);
internal
override
(
DiagnosticAnalyzer
,
CodeFixProvider
)
CreateDiagnosticProviderAndFixer
(
Workspace
workspace
)
=>
(
new
CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer
(),
new
CSharpIsAndCastCheckWithoutNameCodeFixProvider
()
);
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsInlineTypeCheck
)]
public
async
Task
TestBinaryExpression
()
...
...
src/Features/CSharp/Portable/UsePatternMatching/CSharpIsAndCastCheck
CodeRefactoringProvid
er.cs
→
src/Features/CSharp/Portable/UsePatternMatching/CSharpIsAndCastCheck
WithoutNameDiagnosticAnalyz
er.cs
浏览文件 @
fd755683
...
...
@@ -4,13 +4,17 @@
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Composition
;
using
System.Diagnostics
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.CodeActions
;
using
Microsoft.CodeAnalysis.CodeFixes
;
using
Microsoft.CodeAnalysis.CodeRefactorings
;
using
Microsoft.CodeAnalysis.CodeStyle
;
using
Microsoft.CodeAnalysis.CSharp.Extensions
;
using
Microsoft.CodeAnalysis.CSharp.Syntax
;
using
Microsoft.CodeAnalysis.Diagnostics
;
using
Microsoft.CodeAnalysis.Editing
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.CodeAnalysis.Shared.Utilities
;
...
...
@@ -19,7 +23,7 @@
namespace
Microsoft.CodeAnalysis.CSharp.UsePatternMatching
{
/// <summary>
///
Refactoring
that looks for is-tests and cast-expressions, and offers to convert them
///
DiagnosticAnalyzer
that looks for is-tests and cast-expressions, and offers to convert them
/// to use patterns. i.e. if the user has <code>obj is TestFile && ((TestFile)obj).Name == "Test"</code>
/// it will offer to convert that <code>obj is TestFile file && file.Name == "Test"</code>.
///
...
...
@@ -28,26 +32,38 @@ namespace Microsoft.CodeAnalysis.CSharp.UsePatternMatching
/// code that can be used).
/// </summary>
[
ExportCodeRefactoringProvider
(
LanguageNames
.
CSharp
),
Shared
]
internal
class
CSharpIsAndCastCheck
CodeRefactoringProvider
:
CodeRefactoringProvid
er
internal
class
CSharpIsAndCastCheck
WithoutNameDiagnosticAnalyzer
:
AbstractCodeStyleDiagnosticAnalyz
er
{
private
const
string
CS0165
=
nameof
(
CS0165
);
// Use of unassigned local variable 's'
private
static
readonly
SyntaxAnnotation
s_referenceAnnotation
=
new
SyntaxAnnotation
();
public
override
async
Task
ComputeRefactoringsAsync
(
CodeRefactoringContext
context
)
public
static
readonly
CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer
Instance
=
new
CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer
();
public
override
bool
OpenFileOnly
(
Workspace
workspace
)
=>
false
;
public
CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer
()
:
base
(
IDEDiagnosticIds
.
InlineIsTypeWithoutNameCheckId
,
new
LocalizableResourceString
(
nameof
(
FeaturesResources
.
Use_pattern_matching
),
FeaturesResources
.
ResourceManager
,
typeof
(
FeaturesResources
)))
{
if
(!
context
.
Span
.
IsEmpty
)
{
return
;
}
}
var
document
=
context
.
Document
;
public
override
DiagnosticAnalyzerCategory
GetAnalyzerCategory
()
=>
DiagnosticAnalyzerCategory
.
SemanticSpanAnalysis
;
protected
override
void
InitializeWorker
(
AnalysisContext
context
)
=>
context
.
RegisterSyntaxNodeAction
(
SyntaxNodeAction
,
SyntaxKind
.
IsExpression
);
private
void
SyntaxNodeAction
(
SyntaxNodeAnalysisContext
context
)
{
var
cancellationToken
=
context
.
CancellationToken
;
var
semanticModel
=
context
.
SemanticModel
;
var
root
=
semanticModel
.
SyntaxTree
.
GetRoot
(
cancellationToken
);
var
semanticModel
=
await
document
.
GetSemanticModelAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
root
=
await
document
.
GetSyntaxRootAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
node
=
root
.
FindNode
(
context
.
Span
);
var
isExpression
=
node
.
FirstAncestorOrSelf
<
BinaryExpressionSyntax
>(
b
=>
b
.
IsKind
(
SyntaxKind
.
IsExpression
));
if
(
isExpression
==
null
)
var
isExpression
=
(
BinaryExpressionSyntax
)
context
.
Node
;
var
workspace
=
(
context
.
Options
as
WorkspaceAnalyzerOptions
)?.
Services
.
Workspace
;
if
(
workspace
==
null
)
{
return
;
}
...
...
@@ -60,10 +76,30 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
return
;
}
var
(
matches
,
_
)
=
AnalyzeExpression
(
workspace
,
semanticModel
,
isExpression
,
cancellationToken
);
if
(
matches
==
null
||
matches
.
Count
==
0
)
{
return
;
}
context
.
ReportDiagnostic
(
Diagnostic
.
Create
(
this
.
HiddenDescriptor
,
isExpression
.
GetLocation
()));
//context.RegisterRefactoring(new MyCodeAction(
// c => ReplaceMatchesAsync(
// document, root, isExpression, localName, matches, c)));
}
public
(
HashSet
<
CastExpressionSyntax
>,
string
localName
)
AnalyzeExpression
(
Workspace
workspace
,
SemanticModel
semanticModel
,
BinaryExpressionSyntax
isExpression
,
CancellationToken
cancellationToken
)
{
var
container
=
GetContainer
(
isExpression
);
if
(
container
==
null
)
{
return
;
return
default
;
}
var
expr
=
isExpression
.
Left
.
WalkDownParentheses
();
...
...
@@ -73,7 +109,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
if
(
typeSymbol
==
null
||
typeSymbol
.
IsNullable
())
{
// not legal to write "(x is int? y)"
return
;
return
default
;
}
// First, find all the potential cast locations we can replace with a reference to
...
...
@@ -83,7 +119,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
if
(
matches
.
Count
==
0
)
{
return
;
return
default
;
}
// Find a reasonable name for the local we're going to make. It should ideally
...
...
@@ -104,25 +140,18 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
foreach
(
var
castExpression
in
matches
.
ToArray
())
{
tempMatches
.
Add
(
castExpression
);
var
updated
Document
=
await
ReplaceMatchesAsync
(
document
,
root
,
isExpression
,
localName
,
tempMatches
,
cancellationToken
).
ConfigureAwait
(
false
);
var
updated
SemanticModel
=
ReplaceMatches
(
workspace
,
semanticModel
,
isExpression
,
localName
,
tempMatches
,
cancellationToken
);
tempMatches
.
Clear
();
var
causesError
=
await
ReplacementCausesErrorAsync
(
updatedDocument
,
cancellationToken
).
ConfigureAwait
(
false
);
var
causesError
=
ReplacementCausesError
(
updatedSemanticModel
,
cancellationToken
);
if
(
causesError
)
{
matches
.
Remove
(
castExpression
);
}
}
if
(
matches
.
Count
==
0
)
{
return
;
}
context
.
RegisterRefactoring
(
new
MyCodeAction
(
c
=>
ReplaceMatchesAsync
(
document
,
root
,
isExpression
,
localName
,
matches
,
c
)));
return
(
matches
,
localName
);
}
private
static
IEnumerable
<
ISymbol
>
GetExistingSymbols
(
...
...
@@ -134,24 +163,24 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
.
Where
(
s
=>
!
s
.
IsAnonymousTypeProperty
()
&&
!
s
.
IsTupleField
());
}
private
async
Task
<
bool
>
ReplacementCausesErrorAsync
(
Document
updatedDocument
,
CancellationToken
cancellationToken
)
private
bool
ReplacementCausesError
(
SemanticModel
updatedSemanticModel
,
CancellationToken
cancellationToken
)
{
var
semanticModel
=
await
updatedDocument
.
GetSemanticModelAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
root
=
await
updatedDocument
.
GetSyntaxRootAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
root
=
updatedSemanticModel
.
SyntaxTree
.
GetRoot
(
cancellationToken
);
var
currentNode
=
root
.
GetAnnotatedNodes
(
s_referenceAnnotation
).
Single
();
var
diagnostics
=
s
emanticModel
.
GetDiagnostics
(
currentNode
.
Span
,
cancellationToken
);
var
diagnostics
=
updatedS
emanticModel
.
GetDiagnostics
(
currentNode
.
Span
,
cancellationToken
);
return
diagnostics
.
Any
(
d
=>
d
.
Id
==
CS0165
);
}
p
rivate
Task
<
Document
>
ReplaceMatchesAsync
(
Document
document
,
SyntaxNode
root
,
BinaryExpressionSyntax
isExpression
,
p
ublic
SemanticModel
ReplaceMatches
(
Workspace
workspace
,
SemanticModel
semanticModel
,
BinaryExpressionSyntax
isExpression
,
string
localName
,
HashSet
<
CastExpressionSyntax
>
matches
,
CancellationToken
cancellationToken
)
{
var
editor
=
new
SyntaxEditor
(
root
,
document
.
Project
.
Solution
.
Workspace
);
var
root
=
semanticModel
.
SyntaxTree
.
GetRoot
(
cancellationToken
);
var
editor
=
new
SyntaxEditor
(
root
,
workspace
);
// now, replace "x is Y" with "x is Y y" and put a rename-annotation on 'y' so that
// the user can actually name the variable whatever they want.
...
...
@@ -177,8 +206,12 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
}
var
changedRoot
=
editor
.
GetChangedRoot
();
var
newDocument
=
document
.
WithSyntaxRoot
(
changedRoot
);
return
Task
.
FromResult
(
newDocument
);
var
updatedSyntaxTree
=
semanticModel
.
SyntaxTree
.
WithRootAndOptions
(
changedRoot
,
semanticModel
.
SyntaxTree
.
Options
);
var
updatedCompilation
=
semanticModel
.
Compilation
.
ReplaceSyntaxTree
(
semanticModel
.
SyntaxTree
,
updatedSyntaxTree
);
return
updatedCompilation
.
GetSemanticModel
(
updatedSyntaxTree
);
}
private
SyntaxNode
GetContainer
(
BinaryExpressionSyntax
isExpression
)
...
...
@@ -226,10 +259,51 @@ private SyntaxNode GetContainer(BinaryExpressionSyntax isExpression)
}
}
}
}
[
ExportCodeFixProvider
(
LanguageNames
.
CSharp
),
Shared
]
internal
partial
class
CSharpIsAndCastCheckWithoutNameCodeFixProvider
:
SyntaxEditorBasedCodeFixProvider
{
public
CSharpIsAndCastCheckWithoutNameCodeFixProvider
()
:
base
(
supportsFixAll
:
false
)
{
}
public
override
ImmutableArray
<
string
>
FixableDiagnosticIds
=>
ImmutableArray
.
Create
(
IDEDiagnosticIds
.
InlineIsTypeWithoutNameCheckId
);
public
override
Task
RegisterCodeFixesAsync
(
CodeFixContext
context
)
{
context
.
RegisterCodeFix
(
new
MyCodeAction
(
c
=>
FixAsync
(
context
.
Document
,
context
.
Diagnostics
.
First
(),
c
)),
context
.
Diagnostics
);
return
SpecializedTasks
.
EmptyTask
;
}
protected
override
async
Task
FixAllAsync
(
Document
document
,
ImmutableArray
<
Diagnostic
>
diagnostics
,
SyntaxEditor
editor
,
CancellationToken
cancellationToken
)
{
Debug
.
Assert
(
diagnostics
.
Length
==
1
);
var
location
=
diagnostics
[
0
].
Location
;
var
isExpression
=
(
BinaryExpressionSyntax
)
location
.
FindNode
(
getInnermostNodeForTie
:
true
,
cancellationToken
:
cancellationToken
);
var
workspace
=
document
.
Project
.
Solution
.
Workspace
;
var
semanticModel
=
await
document
.
GetSemanticModelAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
(
matches
,
localName
)
=
CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer
.
Instance
.
AnalyzeExpression
(
workspace
,
semanticModel
,
isExpression
,
cancellationToken
);
var
updatedSemanticModel
=
CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer
.
Instance
.
ReplaceMatches
(
workspace
,
semanticModel
,
isExpression
,
localName
,
matches
,
cancellationToken
);
var
updatedRoot
=
updatedSemanticModel
.
SyntaxTree
.
GetRoot
(
cancellationToken
);
editor
.
ReplaceNode
(
editor
.
OriginalRoot
,
updatedRoot
);
}
private
class
MyCodeAction
:
CodeAction
.
DocumentChangeAction
{
public
MyCodeAction
(
Func
<
CancellationToken
,
Task
<
Document
>>
createChangedDocument
)
public
MyCodeAction
(
Func
<
CancellationToken
,
Task
<
Document
>>
createChangedDocument
)
:
base
(
FeaturesResources
.
Use_pattern_matching
,
createChangedDocument
)
{
}
...
...
src/Features/Core/Portable/Diagnostics/Analyzers/IDEDiagnosticIds.cs
浏览文件 @
fd755683
...
...
@@ -52,6 +52,9 @@ internal static class IDEDiagnosticIds
public
const
string
UseInferredMemberNameDiagnosticId
=
"IDE0037"
;
public
const
string
InlineIsTypeWithoutNameCheckId
=
"IDE0038"
;
// Analyzer error Ids
public
const
string
AnalyzerChangedId
=
"IDE1001"
;
public
const
string
AnalyzerDependencyConflictId
=
"IDE1002"
;
...
...
src/Workspaces/Core/Portable/CodeFixes/SyntaxEditorBasedCodeFixProvider.cs
浏览文件 @
fd755683
...
...
@@ -11,8 +11,15 @@ namespace Microsoft.CodeAnalysis.CodeFixes
{
internal
abstract
partial
class
SyntaxEditorBasedCodeFixProvider
:
CodeFixProvider
{
private
readonly
bool
_supportsFixAll
;
protected
SyntaxEditorBasedCodeFixProvider
(
bool
supportsFixAll
=
true
)
{
_supportsFixAll
=
supportsFixAll
;
}
public
sealed
override
FixAllProvider
GetFixAllProvider
()
=>
new
SyntaxEditorBasedFixAllProvider
(
this
)
;
=>
_supportsFixAll
?
new
SyntaxEditorBasedFixAllProvider
(
this
)
:
null
;
protected
Task
<
Document
>
FixAsync
(
Document
document
,
Diagnostic
diagnostic
,
CancellationToken
cancellationToken
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录