Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
20452ab2
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,发现更多精彩内容 >>
提交
20452ab2
编写于
4月 23, 2020
作者:
A
Alireza Habibi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Start work on 'use pattern combinators' feature
上级
5ee3f8c6
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
690 addition
and
0 deletion
+690
-0
src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs
src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs
+2
-0
src/EditorFeatures/CSharpTest/UsePatternCombinators/CSharpUsePatternMatchingDiagnosticAnalyzerTests.cs
...nators/CSharpUsePatternMatchingDiagnosticAnalyzerTests.cs
+118
-0
src/Features/CSharp/Portable/UsePatternCombinators/AnalyzedPattern.cs
.../CSharp/Portable/UsePatternCombinators/AnalyzedPattern.cs
+124
-0
src/Features/CSharp/Portable/UsePatternCombinators/CSharpUsePatternCombinatorsAnalyzer.cs
...PatternCombinators/CSharpUsePatternCombinatorsAnalyzer.cs
+203
-0
src/Features/CSharp/Portable/UsePatternCombinators/CSharpUsePatternCombinatorsCodeFixProvider.cs
...Combinators/CSharpUsePatternCombinatorsCodeFixProvider.cs
+114
-0
src/Features/CSharp/Portable/UsePatternCombinators/CSharpUsePatternCombinatorsDiagnosticAnalyzer.cs
...binators/CSharpUsePatternCombinatorsDiagnosticAnalyzer.cs
+78
-0
src/Features/CSharp/Portable/UsePatternCombinators/CSharpUsePatternCombinatorsHelpers.cs
...ePatternCombinators/CSharpUsePatternCombinatorsHelpers.cs
+50
-0
src/Test/Utilities/Portable/Traits/Traits.cs
src/Test/Utilities/Portable/Traits/Traits.cs
+1
-0
未找到文件。
src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs
浏览文件 @
20452ab2
...
...
@@ -130,6 +130,8 @@ internal static class IDEDiagnosticIds
public
const
string
SimplifyConditionalExpressionDiagnosticId
=
"IDE0075"
;
public
const
string
UsePatternCombinatorsDiagnosticId
=
"IDE0076"
;
// Analyzer error Ids
public
const
string
AnalyzerChangedId
=
"IDE1001"
;
public
const
string
AnalyzerDependencyConflictId
=
"IDE1002"
;
...
...
src/EditorFeatures/CSharpTest/UsePatternCombinators/CSharpUsePatternMatchingDiagnosticAnalyzerTests.cs
0 → 100644
浏览文件 @
20452ab2
// 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.Threading.Tasks
;
using
Microsoft.CodeAnalysis.CodeFixes
;
using
Microsoft.CodeAnalysis.CSharp.UsePatternCombinators
;
using
Microsoft.CodeAnalysis.Diagnostics
;
using
Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics
;
using
Microsoft.CodeAnalysis.Test.Utilities
;
using
Xunit
;
namespace
Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UsePatternCombinators
{
public
class
CSharpUsePatternMatchingDiagnosticAnalyzerTests
:
AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal
override
(
DiagnosticAnalyzer
,
CodeFixProvider
)
CreateDiagnosticProviderAndFixer
(
Workspace
workspace
)
=>
(
new
CSharpUsePatternCombinatorsDiagnosticAnalyzer
(),
new
CSharpUsePatternCombinatorsCodeFixProvider
());
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUsePatternCombinators
)]
public
async
Task
Test00
()
{
await
TestInRegularAndScript1Async
(
@"class C
{
void Missing(int i, object o)
{
if (i == 0) { }
if (i > 0) { }
if (i is C) { }
if (i is C c) { }
if (!(i > 0)) { }
if (p != null) { }
}
void Good(int i, object o)
{
if (!(o is C c)) { }
if (!(o is C)) { }
if ({|FixAllInDocument:i == 1 || 2 == i|}) { }
if (i != 1 || 2 != i) { }
if (!(i != 1 || 2 != i)) { }
if (i < 1 && 2 <= i) { }
if (i < 1 && 2 <= i && i is not 0) { }
}
}"
,
@"class C
{
void Missing(int i, object o)
{
if (i == 0) { }
if (i > 0) { }
if (i is C) { }
if (i is C c) { }
if (!(i > 0)) { }
if (p != null) { }
}
void Good(int i, object o)
{
if (o is not C c) { }
if (o is not C) { }
if (i is 1 or 2) { }
if (i is not (1 and 2)) { }
if (i is 1 and 2) { }
if (i is < 1 and >= 2) { }
if (i is < 1 and >= 2 and not 0) { }
}
}"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUsePatternCombinators
)]
public
async
Task
TestReturn
()
{
await
TestInRegularAndScript1Async
(
@"class C
{
bool M(int variable)
{
return [|variable == 0 ||
variable == 1 ||
variable == 2|];
}
}"
,
@"class C
{
bool M(int variable)
{
return variable is 0 or
1 or
2;
}
}"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUsePatternCombinators
)]
public
async
Task
TestReturn_Not
()
{
await
TestInRegularAndScript1Async
(
@"class C
{
bool M(int variable)
{
return [|variable != 0 &&
variable != 1 &&
variable != 2|];
}
}"
,
@"class C
{
bool M(int variable)
{
return variable is not (0 or
1 or
2);
}
}"
);
}
}
}
src/Features/CSharp/Portable/UsePatternCombinators/AnalyzedPattern.cs
0 → 100644
浏览文件 @
20452ab2
// 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.
#
nullable
enable
using
Microsoft.CodeAnalysis.CSharp.Syntax
;
using
Microsoft.CodeAnalysis.Operations
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.CSharp.UsePatternCombinators
{
/// <summary>
/// Base class to represent a pattern constructed from various checks
/// </summary>
internal
abstract
class
AnalyzedPattern
{
private
AnalyzedPattern
()
{
}
/// <summary>
/// Represents a type-pattern, constructed from is-expression
/// </summary>
internal
sealed
class
Type
:
AnalyzedPattern
{
public
readonly
TypeSyntax
TypeSyntax
;
public
Type
(
TypeSyntax
expression
)
=>
TypeSyntax
=
expression
;
}
/// <summary>
/// Represents a source-pattern, constructed from C# patterns
/// </summary>
internal
sealed
class
Source
:
AnalyzedPattern
{
public
readonly
PatternSyntax
PatternSyntax
;
public
Source
(
PatternSyntax
patternSyntax
)
=>
PatternSyntax
=
patternSyntax
;
}
/// <summary>
/// Represents a constant-pattern, constructed from an equality check
/// </summary>
internal
sealed
class
Constant
:
AnalyzedPattern
{
public
readonly
ExpressionSyntax
ExpressionSyntax
;
public
Constant
(
ExpressionSyntax
expression
)
=>
ExpressionSyntax
=
expression
;
}
/// <summary>
/// Represents a relational-pattern, constructed from relational operators
/// </summary>
internal
sealed
class
Relational
:
AnalyzedPattern
{
public
readonly
BinaryOperatorKind
OperatorKind
;
public
readonly
ExpressionSyntax
Value
;
public
Relational
(
BinaryOperatorKind
operatorKind
,
ExpressionSyntax
value
)
{
OperatorKind
=
operatorKind
;
Value
=
value
;
}
}
/// <summary>
/// Represents an and/or pattern, constructed from a logical and/or expression.
/// </summary>
internal
sealed
class
Binary
:
AnalyzedPattern
{
public
readonly
AnalyzedPattern
Left
;
public
readonly
AnalyzedPattern
Right
;
public
readonly
bool
IsDisjunctive
;
public
readonly
SyntaxToken
Token
;
private
Binary
(
AnalyzedPattern
leftPattern
,
AnalyzedPattern
rightPattern
,
bool
isDisjunctive
,
SyntaxToken
token
)
{
Left
=
leftPattern
;
Right
=
rightPattern
;
IsDisjunctive
=
isDisjunctive
;
Token
=
token
;
}
public
static
AnalyzedPattern
Create
(
AnalyzedPattern
leftPattern
,
AnalyzedPattern
rightPattern
,
bool
isDisjunctive
,
SyntaxToken
token
)
{
return
(
leftPattern
,
rightPattern
)
switch
{
(
Not
left
,
Not
right
)
=>
Not
.
Create
(
new
Binary
(
left
.
Pattern
,
right
.
Pattern
,
!
isDisjunctive
,
token
)),
_
=>
new
Binary
(
leftPattern
,
rightPattern
,
isDisjunctive
,
token
)
};
}
}
/// <summary>
/// Represents a not-pattern, constructed from inequality check or a logical-not expression.
/// </summary>
internal
sealed
class
Not
:
AnalyzedPattern
{
public
readonly
AnalyzedPattern
Pattern
;
private
Not
(
AnalyzedPattern
pattern
)
=>
Pattern
=
pattern
;
private
static
BinaryOperatorKind
Negate
(
BinaryOperatorKind
kind
)
=>
kind
switch
{
BinaryOperatorKind
.
LessThan
=>
BinaryOperatorKind
.
GreaterThanOrEqual
,
BinaryOperatorKind
.
GreaterThan
=>
BinaryOperatorKind
.
LessThanOrEqual
,
BinaryOperatorKind
.
LessThanOrEqual
=>
BinaryOperatorKind
.
GreaterThan
,
BinaryOperatorKind
.
GreaterThanOrEqual
=>
BinaryOperatorKind
.
LessThan
,
var
v
=>
throw
ExceptionUtilities
.
UnexpectedValue
(
v
)
};
public
static
AnalyzedPattern
Create
(
AnalyzedPattern
pattern
)
=>
pattern
switch
{
Not
p
=>
p
.
Pattern
,
Relational
p
=>
new
Relational
(
Negate
(
p
.
OperatorKind
),
p
.
Value
),
_
=>
new
Not
(
pattern
)
};
}
}
}
src/Features/CSharp/Portable/UsePatternCombinators/CSharpUsePatternCombinatorsAnalyzer.cs
0 → 100644
浏览文件 @
20452ab2
// 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.
#
nullable
enable
using
Microsoft.CodeAnalysis.CSharp.Syntax
;
using
Microsoft.CodeAnalysis.Operations
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.CSharp.UsePatternCombinators
{
using
static
BinaryOperatorKind
;
using
static
AnalyzedPattern
;
internal
sealed
class
CSharpUsePatternCombinatorsAnalyzer
{
private
ExpressionSyntax
_targetExpression
=
null
!;
public
static
AnalyzedPattern
?
Analyze
(
IOperation
operation
,
out
ExpressionSyntax
targetExpression
)
{
var
patternAnalyzer
=
new
CSharpUsePatternCombinatorsAnalyzer
();
var
analyzedPattern
=
patternAnalyzer
.
ParsePattern
(
operation
);
targetExpression
=
patternAnalyzer
.
_targetExpression
;
return
analyzedPattern
;
}
private
enum
ConstantResult
{
/// <summary>
/// None of operands were constant.
/// </summary>
None
,
/// <summary>
/// Signifies that the left operand is the constant.
/// </summary>
Left
,
/// <summary>
/// Signifies that the right operand is the constant.
/// </summary>
Right
,
}
private
AnalyzedPattern
?
ParsePattern
(
IOperation
operation
)
{
switch
(
operation
)
{
case
IBinaryOperation
{
OperatorKind
:
BinaryOperatorKind
.
Equals
}
op
:
return
ParseConstantPattern
(
op
);
case
IBinaryOperation
{
OperatorKind
:
NotEquals
}
op
:
{
var
pattern
=
ParseConstantPattern
(
op
);
if
(
pattern
==
null
)
break
;
return
Not
.
Create
(
pattern
);
}
case
IBinaryOperation
{
OperatorKind
:
ConditionalOr
,
Syntax
:
BinaryExpressionSyntax
syntax
}
op
:
return
ParseBinaryPattern
(
op
,
isDisjunctive
:
true
,
syntax
.
OperatorToken
);
case
IBinaryOperation
{
OperatorKind
:
ConditionalAnd
,
Syntax
:
BinaryExpressionSyntax
syntax
}
op
:
return
ParseBinaryPattern
(
op
,
isDisjunctive
:
false
,
syntax
.
OperatorToken
);
case
IBinaryOperation
op
when
IsRelationalOperator
(
op
.
OperatorKind
):
return
ParseRelationalPattern
(
op
);
case
IUnaryOperation
{
OperatorKind
:
UnaryOperatorKind
.
Not
}
op
:
{
var
pattern
=
ParsePattern
(
op
.
Operand
);
if
(
pattern
==
null
)
break
;
return
Not
.
Create
(
pattern
);
}
case
IIsTypeOperation
op
when
CheckTargetExpression
(
op
.
ValueOperand
)
&&
op
.
Syntax
is
BinaryExpressionSyntax
{
Right
:
TypeSyntax
type
}:
return
new
Type
(
type
);
case
IIsPatternOperation
op
when
CheckTargetExpression
(
op
.
Value
)
&&
op
.
Pattern
.
Syntax
is
PatternSyntax
pattern
:
return
new
Source
(
pattern
);
case
IParenthesizedOperation
op
:
return
ParsePattern
(
op
.
Operand
);
}
return
null
;
}
private
AnalyzedPattern
?
ParseBinaryPattern
(
IBinaryOperation
op
,
bool
isDisjunctive
,
SyntaxToken
token
)
{
var
leftPattern
=
ParsePattern
(
op
.
LeftOperand
);
if
(
leftPattern
==
null
)
return
null
;
var
rightPattern
=
ParsePattern
(
op
.
RightOperand
);
if
(
rightPattern
==
null
)
return
null
;
return
Binary
.
Create
(
leftPattern
,
rightPattern
,
isDisjunctive
,
token
);
}
private
ConstantResult
DetermineConstant
(
IBinaryOperation
op
)
{
return
(
op
.
LeftOperand
,
op
.
RightOperand
)
switch
{
var
(
e
,
v
)
when
IsConstant
(
v
)
&&
CheckTargetExpression
(
e
)
=>
ConstantResult
.
Right
,
var
(
v
,
e
)
when
IsConstant
(
v
)
&&
CheckTargetExpression
(
e
)
=>
ConstantResult
.
Left
,
_
=>
ConstantResult
.
None
,
};
}
private
AnalyzedPattern
?
ParseRelationalPattern
(
IBinaryOperation
op
)
{
return
DetermineConstant
(
op
)
switch
{
ConstantResult
.
Left
when
op
.
LeftOperand
.
Syntax
is
ExpressionSyntax
left
=>
new
Relational
(
Flip
(
op
.
OperatorKind
),
left
),
ConstantResult
.
Right
when
op
.
RightOperand
.
Syntax
is
ExpressionSyntax
right
=>
new
Relational
(
op
.
OperatorKind
,
right
),
_
=>
null
};
}
private
AnalyzedPattern
?
ParseConstantPattern
(
IBinaryOperation
op
)
{
return
DetermineConstant
(
op
)
switch
{
ConstantResult
.
Left
when
op
.
LeftOperand
.
Syntax
is
ExpressionSyntax
left
=>
new
Constant
(
left
),
ConstantResult
.
Right
when
op
.
RightOperand
.
Syntax
is
ExpressionSyntax
right
=>
new
Constant
(
right
),
_
=>
null
};
}
private
static
bool
IsRelationalOperator
(
BinaryOperatorKind
operatorKind
)
{
switch
(
operatorKind
)
{
case
LessThan
:
case
LessThanOrEqual
:
case
GreaterThanOrEqual
:
case
GreaterThan
:
return
true
;
default
:
return
false
;
}
}
/// <summary>
/// Changes the direction the operator is pointing
/// </summary>
public
static
BinaryOperatorKind
Flip
(
BinaryOperatorKind
operatorKind
)
{
return
operatorKind
switch
{
LessThan
=>
GreaterThan
,
LessThanOrEqual
=>
GreaterThanOrEqual
,
GreaterThanOrEqual
=>
LessThanOrEqual
,
GreaterThan
=>
LessThan
,
var
v
=>
throw
ExceptionUtilities
.
UnexpectedValue
(
v
)
};
}
private
static
bool
IsConstant
(
IOperation
operation
)
{
// Constants do not propagate to conversions
return
operation
is
IConversionOperation
op
?
IsConstant
(
op
.
Operand
)
:
operation
.
ConstantValue
.
HasValue
;
}
private
bool
CheckTargetExpression
(
IOperation
operation
)
{
if
(
operation
is
IConversionOperation
{
IsImplicit
:
false
}
op
)
{
// Unwrap explicit casts because the pattern will emit those anyways
operation
=
op
.
Operand
;
}
if
(!(
operation
.
Syntax
is
ExpressionSyntax
expression
))
{
return
false
;
}
// If we have not figured the target expression yet,
// we will assume that the first expression is the one.
if
(
_targetExpression
is
null
)
{
_targetExpression
=
expression
;
return
true
;
}
return
SyntaxFactory
.
AreEquivalent
(
expression
,
_targetExpression
);
}
}
}
src/Features/CSharp/Portable/UsePatternCombinators/CSharpUsePatternCombinatorsCodeFixProvider.cs
0 → 100644
浏览文件 @
20452ab2
// 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.
#
nullable
enable
using
System
;
using
System.Collections.Immutable
;
using
System.Composition
;
using
System.Diagnostics.CodeAnalysis
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.CodeActions
;
using
Microsoft.CodeAnalysis.CodeFixes
;
using
Microsoft.CodeAnalysis.CSharp.Extensions
;
using
Microsoft.CodeAnalysis.CSharp.Syntax
;
using
Microsoft.CodeAnalysis.Diagnostics
;
using
Microsoft.CodeAnalysis.Editing
;
using
Microsoft.CodeAnalysis.Formatting
;
using
Roslyn.Utilities
;
using
Microsoft.CodeAnalysis.Operations
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
namespace
Microsoft.CodeAnalysis.CSharp.UsePatternCombinators
{
using
static
SyntaxFactory
;
using
static
AnalyzedPattern
;
[
ExportCodeFixProvider
(
LanguageNames
.
CSharp
),
Shared
]
internal
class
CSharpUsePatternCombinatorsCodeFixProvider
:
SyntaxEditorBasedCodeFixProvider
{
[
ImportingConstructor
]
[
SuppressMessage
(
"RoslynDiagnosticsReliability"
,
"RS0033:Importing constructor should be [Obsolete]"
,
Justification
=
"Used in test code: https://github.com/dotnet/roslyn/issues/42814"
)]
public
CSharpUsePatternCombinatorsCodeFixProvider
()
:
base
(
supportsFixAll
:
true
)
{
}
private
static
SyntaxKind
MapToSyntaxKind
(
BinaryOperatorKind
kind
)
=>
kind
switch
{
BinaryOperatorKind
.
LessThan
=>
SyntaxKind
.
LessThanToken
,
BinaryOperatorKind
.
GreaterThan
=>
SyntaxKind
.
GreaterThanToken
,
BinaryOperatorKind
.
LessThanOrEqual
=>
SyntaxKind
.
LessThanEqualsToken
,
BinaryOperatorKind
.
GreaterThanOrEqual
=>
SyntaxKind
.
GreaterThanEqualsToken
,
_
=>
throw
ExceptionUtilities
.
UnexpectedValue
(
kind
)
};
public
override
ImmutableArray
<
string
>
FixableDiagnosticIds
=>
ImmutableArray
.
Create
(
IDEDiagnosticIds
.
UsePatternCombinatorsDiagnosticId
);
internal
sealed
override
CodeFixCategory
CodeFixCategory
=>
CodeFixCategory
.
CodeStyle
;
public
override
Task
RegisterCodeFixesAsync
(
CodeFixContext
context
)
{
context
.
RegisterCodeFix
(
new
MyCodeAction
(
c
=>
FixAsync
(
context
.
Document
,
context
.
Diagnostics
.
First
(),
c
)),
context
.
Diagnostics
);
return
Task
.
CompletedTask
;
}
protected
override
async
Task
FixAllAsync
(
Document
document
,
ImmutableArray
<
Diagnostic
>
diagnostics
,
SyntaxEditor
editor
,
CancellationToken
cancellationToken
)
{
var
semanticModel
=
await
document
.
RequireSemanticModelAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
foreach
(
var
diagnostic
in
diagnostics
)
{
var
location
=
diagnostic
.
AdditionalLocations
[
0
];
var
node
=
editor
.
OriginalRoot
.
FindNode
(
location
.
SourceSpan
);
var
expression
=
FixNode
(
CSharpUsePatternCombinatorsHelpers
.
GetExpression
(
node
));
var
operation
=
semanticModel
.
GetOperation
(
expression
!);
var
pattern
=
CSharpUsePatternCombinatorsAnalyzer
.
Analyze
(
operation
!,
out
var
targetExpression
);
var
patternSyntax
=
AsPatternSyntax
(
pattern
!).
WithAdditionalAnnotations
(
Formatter
.
Annotation
);
editor
.
ReplaceNode
(
expression
,
IsPatternExpression
(
targetExpression
,
patternSyntax
));
}
}
private
static
ExpressionSyntax
?
FixNode
(
ExpressionSyntax
?
e
)
{
return
e
switch
{
AssignmentExpressionSyntax
n
=>
n
.
Right
,
LambdaExpressionSyntax
n
=>
n
.
ExpressionBody
,
var
n
=>
n
,
};
}
private
static
PatternSyntax
AsPatternSyntax
(
AnalyzedPattern
pattern
)
=>
pattern
switch
{
Binary
p
=>
BinaryPattern
(
p
.
IsDisjunctive
?
SyntaxKind
.
OrPattern
:
SyntaxKind
.
AndPattern
,
AsPatternSyntax
(
p
.
Left
).
Parenthesize
(),
Token
(
p
.
Token
.
LeadingTrivia
,
p
.
IsDisjunctive
?
SyntaxKind
.
OrKeyword
:
SyntaxKind
.
AndKeyword
,
TriviaList
(
p
.
Token
.
GetAllTrailingTrivia
())),
AsPatternSyntax
(
p
.
Right
).
Parenthesize
()),
Constant
p
=>
ConstantPattern
(
p
.
ExpressionSyntax
),
Source
p
=>
p
.
PatternSyntax
,
Type
p
=>
TypePattern
(
p
.
TypeSyntax
),
Relational
p
=>
RelationalPattern
(
Token
(
MapToSyntaxKind
(
p
.
OperatorKind
)),
p
.
Value
),
Not
p
=>
UnaryPattern
(
AsPatternSyntax
(
p
.
Pattern
).
Parenthesize
()),
var
p
=>
throw
ExceptionUtilities
.
UnexpectedValue
(
p
)
};
private
class
MyCodeAction
:
CodeAction
.
DocumentChangeAction
{
public
MyCodeAction
(
Func
<
CancellationToken
,
Task
<
Document
>>
createChangedDocument
)
:
base
(
CSharpAnalyzersResources
.
Use_pattern_matching
,
createChangedDocument
)
{
}
internal
override
CodeActionPriority
Priority
=>
CodeActionPriority
.
Low
;
}
}
}
src/Features/CSharp/Portable/UsePatternCombinators/CSharpUsePatternCombinatorsDiagnosticAnalyzer.cs
0 → 100644
浏览文件 @
20452ab2
// 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.
#
nullable
enable
using
Microsoft.CodeAnalysis.CodeStyle
;
using
Microsoft.CodeAnalysis.Diagnostics
;
namespace
Microsoft.CodeAnalysis.CSharp.UsePatternCombinators
{
using
static
AnalyzedPattern
;
[
DiagnosticAnalyzer
(
LanguageNames
.
CSharp
)]
internal
sealed
class
CSharpUsePatternCombinatorsDiagnosticAnalyzer
:
AbstractBuiltInCodeStyleDiagnosticAnalyzer
{
public
CSharpUsePatternCombinatorsDiagnosticAnalyzer
()
:
base
(
IDEDiagnosticIds
.
UsePatternCombinatorsDiagnosticId
,
option
:
null
,
new
LocalizableResourceString
(
nameof
(
CSharpAnalyzersResources
.
Use_pattern_matching
),
CSharpAnalyzersResources
.
ResourceManager
,
typeof
(
CSharpAnalyzersResources
)))
{
}
protected
override
void
InitializeWorker
(
AnalysisContext
context
)
=>
context
.
RegisterSyntaxNodeAction
(
AnalyzeNode
,
CSharpUsePatternCombinatorsHelpers
.
SyntaxKinds
);
public
void
AnalyzeNode
(
SyntaxNodeAnalysisContext
context
)
{
// TODO need an option for user to disable the feature
// TODO need to check language version >= C# 9.0
var
parentNode
=
context
.
Node
;
var
expression
=
CSharpUsePatternCombinatorsHelpers
.
GetExpression
(
parentNode
);
if
(
expression
is
null
)
return
;
var
operation
=
context
.
SemanticModel
.
GetOperation
(
expression
);
if
(
operation
is
null
)
return
;
var
pattern
=
CSharpUsePatternCombinatorsAnalyzer
.
Analyze
(
operation
,
out
_
);
if
(
pattern
is
null
)
return
;
if
(!
ShouldReportDiagnostic
(
pattern
))
return
;
context
.
ReportDiagnostic
(
DiagnosticHelper
.
Create
(
Descriptor
,
location
:
expression
.
GetLocation
(),
effectiveSeverity
:
ReportDiagnostic
.
Warn
,
additionalLocations
:
new
[]
{
parentNode
.
GetLocation
()
},
properties
:
null
,
messageArgs
:
null
));
}
private
static
bool
ShouldReportDiagnostic
(
AnalyzedPattern
pattern
)
{
switch
(
pattern
)
{
case
Not
{
Pattern
:
Constant
_
}:
break
;
case
Not
_
:
case
Binary
_
:
return
true
;
}
return
false
;
}
public
override
DiagnosticAnalyzerCategory
GetAnalyzerCategory
()
=>
DiagnosticAnalyzerCategory
.
SemanticSpanAnalysis
;
}
}
src/Features/CSharp/Portable/UsePatternCombinators/CSharpUsePatternCombinatorsHelpers.cs
0 → 100644
浏览文件 @
20452ab2
// 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.
#
nullable
enable
using
Microsoft.CodeAnalysis.CSharp.Syntax
;
namespace
Microsoft.CodeAnalysis.CSharp.UsePatternCombinators
{
internal
static
class
CSharpUsePatternCombinatorsHelpers
{
public
static
SyntaxKind
[]
SyntaxKinds
=>
new
[]
{
SyntaxKind
.
ForStatement
,
SyntaxKind
.
EqualsValueClause
,
SyntaxKind
.
IfStatement
,
SyntaxKind
.
WhenClause
,
SyntaxKind
.
WhileStatement
,
SyntaxKind
.
DoStatement
,
SyntaxKind
.
ReturnStatement
,
SyntaxKind
.
SimpleAssignmentExpression
,
SyntaxKind
.
ArrowExpressionClause
,
SyntaxKind
.
SimpleLambdaExpression
,
SyntaxKind
.
ParenthesizedLambdaExpression
,
SyntaxKind
.
Argument
,
};
public
static
ExpressionSyntax
?
GetExpression
(
SyntaxNode
node
)
{
return
node
switch
{
ForStatementSyntax
n
=>
n
.
Condition
,
EqualsValueClauseSyntax
n
=>
n
.
Value
,
IfStatementSyntax
n
=>
n
.
Condition
,
WhenClauseSyntax
n
=>
n
.
Condition
,
WhileStatementSyntax
n
=>
n
.
Condition
,
DoStatementSyntax
n
=>
n
.
Condition
,
ReturnStatementSyntax
n
=>
n
.
Expression
,
YieldStatementSyntax
n
=>
n
.
Expression
,
ArrowExpressionClauseSyntax
n
=>
n
.
Expression
,
AssignmentExpressionSyntax
n
=>
n
.
Right
,
LambdaExpressionSyntax
n
=>
n
.
ExpressionBody
,
ArgumentSyntax
{
RefKindKeyword
:
{
RawKind
:
0
}
}
n
=>
n
.
Expression
,
_
=>
null
,
};
}
}
}
src/Test/Utilities/Portable/Traits/Traits.cs
浏览文件 @
20452ab2
...
...
@@ -179,6 +179,7 @@ public static class Features
public
const
string
CodeActionsUseIsNullCheck
=
"CodeActions.UseIsNullCheck"
;
public
const
string
CodeActionsUseLocalFunction
=
"CodeActions.UseLocalFunction"
;
public
const
string
CodeActionsUseNamedArguments
=
"CodeActions.UseNamedArguments"
;
public
const
string
CodeActionsUsePatternCombinators
=
"CodeActions.UsePatternCombinators"
;
public
const
string
CodeActionsUseNullPropagation
=
"CodeActions.UseNullPropagation"
;
public
const
string
CodeActionsUseObjectInitializer
=
"CodeActions.UseObjectInitializer"
;
public
const
string
CodeActionsUseRangeOperator
=
"CodeActions.UseRangeOperator"
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录