Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
edc99e42
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,发现更多精彩内容 >>
提交
edc99e42
编写于
4月 07, 2016
作者:
C
CyrusNajmabadi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Move to using an IOperation analyzer for PopulateSwitch.
上级
43f2abfa
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
131 addition
and
61 deletion
+131
-61
src/Features/Core/Portable/Features.csproj
src/Features/Core/Portable/Features.csproj
+1
-1
src/Features/Core/Portable/PopulateSwitch/AbstractPopulateSwitchCodeFixProvider.cs
...e/PopulateSwitch/AbstractPopulateSwitchCodeFixProvider.cs
+9
-12
src/Features/Core/Portable/PopulateSwitch/PopulateSwitchDiagnosticAnalyzer.cs
...rtable/PopulateSwitch/PopulateSwitchDiagnosticAnalyzer.cs
+22
-29
src/Features/Core/Portable/PopulateSwitch/PopulateSwitchHelpers.cs
...res/Core/Portable/PopulateSwitch/PopulateSwitchHelpers.cs
+99
-19
未找到文件。
src/Features/Core/Portable/Features.csproj
浏览文件 @
edc99e42
...
@@ -294,7 +294,7 @@
...
@@ -294,7 +294,7 @@
<Compile
Include=
"Navigation\NavigationOptions.cs"
/>
<Compile
Include=
"Navigation\NavigationOptions.cs"
/>
<Compile
Include=
"Navigation\NavigationOptionsProvider.cs"
/>
<Compile
Include=
"Navigation\NavigationOptionsProvider.cs"
/>
<Compile
Include=
"PopulateSwitch\AbstractPopulateSwitchCodeFixProvider.cs"
/>
<Compile
Include=
"PopulateSwitch\AbstractPopulateSwitchCodeFixProvider.cs"
/>
<Compile
Include=
"PopulateSwitch\
Abstract
PopulateSwitchDiagnosticAnalyzer.cs"
/>
<Compile
Include=
"PopulateSwitch\PopulateSwitchDiagnosticAnalyzer.cs"
/>
<Compile
Include=
"PopulateSwitch\PopulateSwitchHelpers.cs"
/>
<Compile
Include=
"PopulateSwitch\PopulateSwitchHelpers.cs"
/>
<Compile
Include=
"QuickInfo\QuickInfoUtilities.cs"
/>
<Compile
Include=
"QuickInfo\QuickInfoUtilities.cs"
/>
<Compile
Include=
"RemoveUnnecessaryImports\AbstractRemoveUnnecessaryImportsService.cs"
/>
<Compile
Include=
"RemoveUnnecessaryImports\AbstractRemoveUnnecessaryImportsService.cs"
/>
...
...
src/Features/Core/Portable/PopulateSwitch/AbstractPopulateSwitchCodeFixProvider.cs
浏览文件 @
edc99e42
...
@@ -10,15 +10,16 @@
...
@@ -10,15 +10,16 @@
using
Microsoft.CodeAnalysis.Diagnostics
;
using
Microsoft.CodeAnalysis.Diagnostics
;
using
Microsoft.CodeAnalysis.Editing
;
using
Microsoft.CodeAnalysis.Editing
;
using
Microsoft.CodeAnalysis.Formatting
;
using
Microsoft.CodeAnalysis.Formatting
;
using
Microsoft.CodeAnalysis.Semantics
;
using
Microsoft.CodeAnalysis.Simplification
;
using
Microsoft.CodeAnalysis.Simplification
;
using
Roslyn.Utilities
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.PopulateSwitch
namespace
Microsoft.CodeAnalysis.PopulateSwitch
{
{
internal
abstract
class
AbstractPopulateSwitchCodeFixProvider
<
TSwitchBlockSyntax
,
TExpressionSyntax
,
TSwitchSectionSyntax
>
:
CodeFixProvider
internal
abstract
class
AbstractPopulateSwitchCodeFixProvider
<
TSwitchBlockSyntax
,
TExpressionSyntax
,
TSwitchSectionSyntax
>
:
CodeFixProvider
where
TSwitchBlockSyntax
:
SyntaxNode
where
TSwitchBlockSyntax
:
SyntaxNode
where
TSwitchSectionSyntax
:
SyntaxNode
where
TSwitchSectionSyntax
:
SyntaxNode
where
TExpressionSyntax
:
SyntaxNode
where
TExpressionSyntax
:
SyntaxNode
{
{
public
override
ImmutableArray
<
string
>
FixableDiagnosticIds
=>
ImmutableArray
.
Create
(
IDEDiagnosticIds
.
PopulateSwitchDiagnosticId
);
public
override
ImmutableArray
<
string
>
FixableDiagnosticIds
=>
ImmutableArray
.
Create
(
IDEDiagnosticIds
.
PopulateSwitchDiagnosticId
);
...
@@ -63,16 +64,12 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
...
@@ -63,16 +64,12 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
return
SpecializedTasks
.
EmptyTask
;
return
SpecializedTasks
.
EmptyTask
;
}
}
protected
abstract
TExpressionSyntax
GetSwitchExpression
(
TSwitchBlockSyntax
switchBlock
);
protected
abstract
int
InsertPosition
(
SyntaxList
<
TSwitchSectionSyntax
>
sections
);
protected
abstract
int
InsertPosition
(
SyntaxList
<
TSwitchSectionSyntax
>
sections
);
protected
abstract
SyntaxList
<
TSwitchSectionSyntax
>
GetSwitchSections
(
TSwitchBlockSyntax
switchBlock
);
protected
abstract
SyntaxList
<
TSwitchSectionSyntax
>
GetSwitchSections
(
TSwitchBlockSyntax
switchBlock
);
protected
abstract
TSwitchBlockSyntax
NewSwitchNode
(
TSwitchBlockSyntax
switchBlock
,
SyntaxList
<
TSwitchSectionSyntax
>
sections
);
protected
abstract
TSwitchBlockSyntax
NewSwitchNode
(
TSwitchBlockSyntax
switchBlock
,
SyntaxList
<
TSwitchSectionSyntax
>
sections
);
protected
abstract
List
<
TExpressionSyntax
>
GetCaseLabels
(
TSwitchBlockSyntax
switchBlock
,
out
bool
containsDefaultLabel
);
private
async
Task
<
Document
>
AddMissingSwitchCasesAsync
(
private
async
Task
<
Document
>
AddMissingSwitchCasesAsync
(
CodeFixContext
context
,
bool
includeMissingCases
,
bool
includeDefaultCase
)
CodeFixContext
context
,
bool
includeMissingCases
,
bool
includeDefaultCase
)
{
{
...
@@ -82,13 +79,13 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
...
@@ -82,13 +79,13 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
var
root
=
await
document
.
GetSyntaxRootAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
root
=
await
document
.
GetSyntaxRootAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
model
=
await
document
.
GetSemanticModelAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
model
=
await
document
.
GetSemanticModelAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
switchNode
=
(
TSwitchBlockSyntax
)
root
.
FindNode
(
span
);
var
enumType
=
(
INamedTypeSymbol
)
model
.
GetTypeInfo
(
GetSwitchExpression
(
switchNode
)).
Type
;
var
switchNode
=
(
TSwitchBlockSyntax
)
root
.
FindNode
(
span
);
var
switchStatement
=
(
ISwitchStatement
)
model
.
GetOperation
(
switchNode
,
cancellationToken
);
var
enumType
=
switchStatement
.
Value
.
Type
;
bool
containsDefaultCase
;
var
containsDefaultCase
=
PopulateSwitchHelpers
.
HasDefaultCase
(
switchStatement
);
var
caseLabels
=
GetCaseLabels
(
switchNode
,
out
containsDefaultCase
);
var
missingLabels
=
PopulateSwitchHelpers
.
GetMissingEnumMembers
(
switchStatement
,
enumType
);
var
missingLabels
=
PopulateSwitchHelpers
.
GetMissingSwitchCases
(
model
,
enumType
,
caseLabels
);
var
generator
=
SyntaxGenerator
.
GetGenerator
(
document
);
var
generator
=
SyntaxGenerator
.
GetGenerator
(
document
);
...
...
src/Features/Core/Portable/PopulateSwitch/
Abstract
PopulateSwitchDiagnosticAnalyzer.cs
→
src/Features/Core/Portable/PopulateSwitch/PopulateSwitchDiagnosticAnalyzer.cs
浏览文件 @
edc99e42
...
@@ -3,13 +3,14 @@
...
@@ -3,13 +3,14 @@
using
System.Collections.Immutable
;
using
System.Collections.Immutable
;
using
Microsoft.CodeAnalysis.Diagnostics
;
using
Microsoft.CodeAnalysis.Diagnostics
;
using
System.Diagnostics
;
using
System.Diagnostics
;
using
Microsoft.CodeAnalysis.Semantics
;
using
System.Linq
;
using
System
;
namespace
Microsoft.CodeAnalysis.PopulateSwitch
namespace
Microsoft.CodeAnalysis.PopulateSwitch
{
{
internal
abstract
class
AbstractPopulateSwitchDiagnosticAnalyzerBase
<
TLanguageKindEnum
,
TSwitchBlockSyntax
,
TExpressionSyntax
>
:
DiagnosticAnalyzer
,
IBuiltInAnalyzer
[
DiagnosticAnalyzer
(
LanguageNames
.
CSharp
,
LanguageNames
.
VisualBasic
)]
where
TLanguageKindEnum
:
struct
internal
class
PopulateSwitchDiagnosticAnalyzer
:
DiagnosticAnalyzer
,
IBuiltInAnalyzer
where
TSwitchBlockSyntax
:
SyntaxNode
where
TExpressionSyntax
:
SyntaxNode
{
{
private
static
readonly
LocalizableString
s_localizableTitle
=
new
LocalizableResourceString
(
nameof
(
FeaturesResources
.
Add_missing_switch_cases
),
FeaturesResources
.
ResourceManager
,
typeof
(
FeaturesResources
));
private
static
readonly
LocalizableString
s_localizableTitle
=
new
LocalizableResourceString
(
nameof
(
FeaturesResources
.
Add_missing_switch_cases
),
FeaturesResources
.
ResourceManager
,
typeof
(
FeaturesResources
));
private
static
readonly
LocalizableString
s_localizableMessage
=
new
LocalizableResourceString
(
nameof
(
WorkspacesResources
.
PopulateSwitch
),
WorkspacesResources
.
ResourceManager
,
typeof
(
WorkspacesResources
));
private
static
readonly
LocalizableString
s_localizableMessage
=
new
LocalizableResourceString
(
nameof
(
WorkspacesResources
.
PopulateSwitch
),
WorkspacesResources
.
ResourceManager
,
typeof
(
WorkspacesResources
));
...
@@ -23,26 +24,22 @@ internal abstract class AbstractPopulateSwitchDiagnosticAnalyzerBase<TLanguageKi
...
@@ -23,26 +24,22 @@ internal abstract class AbstractPopulateSwitchDiagnosticAnalyzerBase<TLanguageKi
#
region
Interface
methods
#
region
Interface
methods
protected
abstract
ImmutableArray
<
TLanguageKindEnum
>
SyntaxKindsOfInterest
{
get
;
}
protected
abstract
TExpressionSyntax
GetExpression
(
TSwitchBlockSyntax
node
);
protected
abstract
List
<
TExpressionSyntax
>
GetCaseLabels
(
TSwitchBlockSyntax
switchBlock
,
out
bool
hasDefaultCase
);
public
override
ImmutableArray
<
DiagnosticDescriptor
>
SupportedDiagnostics
=>
ImmutableArray
.
Create
(
s_descriptor
);
public
override
ImmutableArray
<
DiagnosticDescriptor
>
SupportedDiagnostics
=>
ImmutableArray
.
Create
(
s_descriptor
);
public
override
void
Initialize
(
AnalysisContext
context
)
public
override
void
Initialize
(
AnalysisContext
context
)
{
{
context
.
Register
SyntaxNodeAction
(
AnalyzeNode
,
SyntaxKindsOfInteres
t
);
context
.
Register
OperationAction
(
AnalyzeOperation
,
OperationKind
.
SwitchStatemen
t
);
}
}
private
void
Analyze
Node
(
SyntaxNode
AnalysisContext
context
)
private
void
Analyze
Operation
(
Operation
AnalysisContext
context
)
{
{
var
model
=
context
.
SemanticModel
;
var
switchOperation
=
(
ISwitchStatement
)
context
.
Operation
;
var
tree
=
model
.
SyntaxTree
;
var
switchBlock
=
switchOperation
.
Syntax
;
var
switchBlock
=
(
TSwitchBlockSyntax
)
context
.
Nod
e
;
var
tree
=
switchBlock
.
SyntaxTre
e
;
bool
missingCases
;
bool
missingCases
;
bool
missingDefaultCase
;
bool
missingDefaultCase
;
if
(
SwitchIsIncomplete
(
model
,
switchBlock
,
out
missingCases
,
out
missingDefaultCase
)
&&
if
(
SwitchIsIncomplete
(
switchOperation
,
out
missingCases
,
out
missingDefaultCase
)
&&
!
tree
.
OverlapsHiddenPosition
(
switchBlock
.
Span
,
context
.
CancellationToken
))
!
tree
.
OverlapsHiddenPosition
(
switchBlock
.
Span
,
context
.
CancellationToken
))
{
{
Debug
.
Assert
(
missingCases
||
missingDefaultCase
);
Debug
.
Assert
(
missingCases
||
missingDefaultCase
);
...
@@ -59,32 +56,28 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
...
@@ -59,32 +56,28 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
#
endregion
#
endregion
private
bool
SwitchIsIncomplete
(
private
bool
SwitchIsIncomplete
(
SemanticModel
model
,
TSwitchBlockSyntax
node
,
ISwitchStatement
switchStatement
,
out
bool
missingCases
,
out
bool
missingDefaultCase
)
out
bool
missingCases
,
out
bool
missingDefaultCase
)
{
{
bool
hasDefaultCase
;
missingDefaultCase
=
!
PopulateSwitchHelpers
.
HasDefaultCase
(
switchStatement
);
var
caseLabels
=
GetCaseLabels
(
node
,
out
hasDefaultCase
);
missingDefaultCase
=
!
hasDefaultCase
;
missingCases
=
false
;
missingCases
=
false
;
// We know the switch has a 'default' label. Now we need to determine if there are
var
switchExpression
=
switchStatement
.
Value
;
// any missing labels so that we can offer to generate them for the user.
var
switchExpressionType
=
switchExpression
?.
Type
;
// If we can't determine the type of this switch, or we're switching over someting
if
(
switchExpressionType
?.
TypeKind
==
TypeKind
.
Enum
)
// that sin't an enum, just consider this switch complete. We can't add any cases
// here.
var
enumType
=
model
.
GetTypeInfo
(
GetExpression
(
node
)).
Type
as
INamedTypeSymbol
;
if
(
enumType
!=
null
&&
enumType
.
TypeKind
==
TypeKind
.
Enum
)
{
{
var
missingSwitchCases
=
PopulateSwitchHelpers
.
GetMissingSwitchCases
(
model
,
enumType
,
caseLabels
);
var
missingEnumMembers
=
PopulateSwitchHelpers
.
GetMissingEnumMembers
(
missingCases
=
missingSwitchCases
.
Count
>
0
;
switchStatement
,
switchExpressionType
);
missingCases
=
missingEnumMembers
.
Count
>
0
;
}
}
// The switch is incomplete if we're missing any cases or we're missing a default case.
// The switch is incomplete if we're missing any cases or we're missing a default case.
return
missingDefaultCase
||
missingCases
;
return
missingDefaultCase
||
missingCases
;
}
}
public
DiagnosticAnalyzerCategory
GetAnalyzerCategory
()
=>
DiagnosticAnalyzerCategory
.
SyntaxAnalysis
;
public
DiagnosticAnalyzerCategory
GetAnalyzerCategory
()
=>
DiagnosticAnalyzerCategory
.
SemanticSpanAnalysis
;
}
}
}
}
\ No newline at end of file
src/Features/Core/Portable/PopulateSwitch/PopulateSwitchHelpers.cs
浏览文件 @
edc99e42
using
System.Collections.Generic
;
using
System
;
using
System.Collections.Generic
;
using
Microsoft.CodeAnalysis.Semantics
;
using
Microsoft.CodeAnalysis.Shared.Utilities
;
using
Roslyn.Utilities
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.PopulateSwitch
namespace
Microsoft.CodeAnalysis.PopulateSwitch
...
@@ -8,12 +11,89 @@ internal static class PopulateSwitchHelpers
...
@@ -8,12 +11,89 @@ internal static class PopulateSwitchHelpers
public
const
string
MissingCases
=
nameof
(
MissingCases
);
public
const
string
MissingCases
=
nameof
(
MissingCases
);
public
const
string
MissingDefaultCase
=
nameof
(
MissingDefaultCase
);
public
const
string
MissingDefaultCase
=
nameof
(
MissingDefaultCase
);
public
static
IReadOnlyList
<
ISymbol
>
GetMissingSwitchCases
<
TExpressionSyntax
>(
public
static
bool
HasDefaultCase
(
ISwitchStatement
switchStatement
)
SemanticModel
model
,
{
INamedTypeSymbol
enumType
,
foreach
(
var
switchCase
in
switchStatement
.
Cases
)
IReadOnlyList
<
TExpressionSyntax
>
labelNames
)
where
TExpressionSyntax
:
SyntaxNode
{
if
(
HasDefaultCase
(
switchCase
))
{
return
true
;
}
}
return
false
;
}
private
static
bool
HasDefaultCase
(
ISwitchCase
switchCase
)
{
foreach
(
var
clause
in
switchCase
.
Clauses
)
{
if
(
clause
.
CaseKind
==
CaseKind
.
Default
)
{
return
true
;
}
}
return
false
;
}
public
static
ICollection
<
ISymbol
>
GetMissingEnumMembers
(
ISwitchStatement
switchStatement
,
ITypeSymbol
enumType
)
{
var
enumMembers
=
new
Dictionary
<
long
,
ISymbol
>();
if
(!
TryGetAllEnumMembers
(
enumType
,
enumMembers
)
||
!
TryRemoveExistingEnumMembers
(
switchStatement
,
enumMembers
))
{
return
SpecializedCollections
.
EmptyCollection
<
ISymbol
>();
}
return
enumMembers
.
Values
;
}
private
static
bool
TryRemoveExistingEnumMembers
(
ISwitchStatement
switchStatement
,
Dictionary
<
long
,
ISymbol
>
enumValues
)
{
foreach
(
var
switchCase
in
switchStatement
.
Cases
)
{
foreach
(
var
clause
in
switchCase
.
Clauses
)
{
switch
(
clause
.
CaseKind
)
{
default
:
case
CaseKind
.
None
:
case
CaseKind
.
Relational
:
case
CaseKind
.
Range
:
// This was some sort of complex switch. For now just ignore
// these and assume that they're complete.
return
false
;
case
CaseKind
.
Default
:
// ignore the 'default/else' clause.
continue
;
case
CaseKind
.
SingleValue
:
var
value
=
((
ISingleValueCaseClause
)
clause
).
Value
;
if
(!
value
.
ConstantValue
.
HasValue
)
{
// We had a case which didn't resolve properly.
// Assume the switch is complete.
return
false
;
}
var
caseValue
=
IntegerUtilities
.
ToInt64
(
value
.
ConstantValue
.
Value
);
enumValues
.
Remove
(
caseValue
);
break
;
}
}
}
return
true
;
}
private
static
bool
TryGetAllEnumMembers
(
ITypeSymbol
enumType
,
Dictionary
<
long
,
ISymbol
>
enumValues
)
{
{
var
missingSwitchCases
=
new
List
<
ISymbol
>();
foreach
(
var
member
in
enumType
.
GetMembers
())
foreach
(
var
member
in
enumType
.
GetMembers
())
{
{
// skip `.ctor` and `__value`
// skip `.ctor` and `__value`
...
@@ -23,24 +103,24 @@ internal static class PopulateSwitchHelpers
...
@@ -23,24 +103,24 @@ internal static class PopulateSwitchHelpers
continue
;
continue
;
}
}
missingSwitchCases
.
Add
(
member
);
if
(
fieldSymbol
.
ConstantValue
==
null
)
}
foreach
(
var
label
in
labelNames
)
{
var
symbol
=
model
.
GetSymbolInfo
(
label
).
Symbol
;
if
(
symbol
==
null
)
{
{
//
something is wrong with the label and the SemanticModel was unable to
//
We have an enum that has problems with it (i.e. non-const members). We won't
//
determine its symbol. Abort the analyzer by considering this switch
//
be able to determine properly if the switch is complete. Assume it is so we
//
statement as complete
.
//
don't offer to do anything
.
return
SpecializedCollections
.
EmptyReadOnlyList
<
ISymbol
>()
;
return
false
;
}
}
missingSwitchCases
.
Remove
(
symbol
);
// Multiple enum members may have the same value. Only consider the first one
// we run int.
var
enumValue
=
IntegerUtilities
.
ToInt64
(
fieldSymbol
.
ConstantValue
);
if
(!
enumValues
.
ContainsKey
(
enumValue
))
{
enumValues
.
Add
(
enumValue
,
fieldSymbol
);
}
}
}
return
missingSwitchCases
;
return
true
;
}
}
}
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录