Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
a5309d1f
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,发现更多精彩内容 >>
提交
a5309d1f
编写于
10月 23, 2018
作者:
C
Cyrus Najmabadi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add more fix-all support.
上级
40d893ee
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
204 addition
and
116 deletion
+204
-116
src/EditorFeatures/CSharpTest/UseIndexOrRangeOperator/UseIndexOperatorTests.cs
...harpTest/UseIndexOrRangeOperator/UseIndexOperatorTests.cs
+3
-3
src/EditorFeatures/CSharpTest/UseIndexOrRangeOperator/UseRangeOperatorTests.cs
...harpTest/UseIndexOrRangeOperator/UseRangeOperatorTests.cs
+24
-0
src/Features/CSharp/Portable/UseIndexOrRangeOperator/CSharpUseIndexOperatorCodeFixProvider.cs
...xOrRangeOperator/CSharpUseIndexOperatorCodeFixProvider.cs
+1
-0
src/Features/CSharp/Portable/UseIndexOrRangeOperator/CSharpUseRangeOperatorCodeFixProvider.cs
...xOrRangeOperator/CSharpUseRangeOperatorCodeFixProvider.cs
+83
-66
src/Features/CSharp/Portable/UseIndexOrRangeOperator/CSharpUseRangeOperatorDiagnosticAnalyzer.cs
...RangeOperator/CSharpUseRangeOperatorDiagnosticAnalyzer.cs
+93
-47
未找到文件。
src/EditorFeatures/CSharpTest/UseIndexOrRangeOperator/UseIndexOperatorTests.cs
浏览文件 @
a5309d1f
...
...
@@ -408,15 +408,15 @@ class C
{
void Goo(string[] s)
{
var v1 = s[{|FixAllInDocument:|}s
[0][s[0].Length - 1
].Length - 1];
var v1 = s[{|FixAllInDocument:|}s
.Length - 2][s[s.Length - 2
].Length - 1];
}
}"
,
@"
class C
{
void Goo(string s)
void Goo(string
[]
s)
{
var v1 = s[^
(s[0][^1])
];
var v1 = s[^
2][^1
];
}
}"
,
parseOptions
:
s_parseOptions
);
}
...
...
src/EditorFeatures/CSharpTest/UseIndexOrRangeOperator/UseRangeOperatorTests.cs
浏览文件 @
a5309d1f
...
...
@@ -152,6 +152,30 @@ void Goo(S s)
{
var v = s.Slice(1..^1);
}
}"
,
parseOptions
:
s_parseOptions
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsUseRangeOperator
)]
public
async
Task
TestFixAllInvocationToElementAccess1
()
{
// Note: once the IOp tree has support for range operators, this should
// simplify even further.
await
TestAsync
(
@"
class C
{
void Goo(string s, string t)
{
var v = t.Substring(s.Substring({|FixAllInDocument:|}1, s.Length - 2)[0], t.Length - s.Substring(1, s.Length - 2)[0]);
}
}"
,
@"
class C
{
void Goo(string s, string t)
{
var v = t.Substring(s[1..^1][0], t.Length - s[1..^1][0]);
}
}"
,
parseOptions
:
s_parseOptions
);
}
}
...
...
src/Features/CSharp/Portable/UseIndexOrRangeOperator/CSharpUseIndexOperatorCodeFixProvider.cs
浏览文件 @
a5309d1f
...
...
@@ -36,6 +36,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
Document
document
,
ImmutableArray
<
Diagnostic
>
diagnostics
,
SyntaxEditor
editor
,
CancellationToken
cancellationToken
)
{
// Process diagnostics from innermost to outermost in case any are nested.
foreach
(
var
diagnostic
in
diagnostics
.
OrderByDescending
(
d
=>
d
.
Location
.
SourceSpan
.
Start
))
{
var
node
=
diagnostic
.
Location
.
FindNode
(
getInnermostNodeForTie
:
true
,
cancellationToken
);
...
...
src/Features/CSharp/Portable/UseIndexOrRangeOperator/CSharpUseRangeOperatorCodeFixProvider.cs
浏览文件 @
a5309d1f
...
...
@@ -3,6 +3,7 @@
using
System
;
using
System.Collections.Immutable
;
using
System.Composition
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.CodeActions
;
...
...
@@ -41,60 +42,87 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
Document
document
,
ImmutableArray
<
Diagnostic
>
diagnostics
,
SyntaxEditor
editor
,
CancellationToken
cancellationToken
)
{
var
semanticModel
=
await
document
.
GetSemanticModelAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
invocationNodes
=
diagnostics
.
Select
(
d
=>
GetInvocationExpression
(
d
,
cancellationToken
))
.
OrderByDescending
(
i
=>
i
.
SpanStart
)
.
ToImmutableArray
();
await
editor
.
ApplyExpressionLevelSemanticEditsAsync
(
document
,
invocationNodes
,
canReplace
:
(
_1
,
_2
)
=>
true
,
(
semanticModel
,
currentRoot
,
currentInvocation
)
=>
UpdateInvocation
(
semanticModel
,
currentRoot
,
currentInvocation
,
cancellationToken
),
cancellationToken
);
}
foreach
(
var
diagnostic
in
diagnostics
)
private
SyntaxNode
UpdateInvocation
(
SemanticModel
semanticModel
,
SyntaxNode
currentRoot
,
InvocationExpressionSyntax
currentInvocation
,
CancellationToken
cancellationToken
)
{
var
invocation
=
semanticModel
.
GetOperation
(
currentInvocation
,
cancellationToken
)
as
IInvocationOperation
;
if
(
invocation
!=
null
)
{
FixOne
(
semanticModel
,
editor
,
diagnostic
,
cancellationToken
);
var
infoCache
=
new
InfoCache
(
semanticModel
.
Compilation
);
var
resultOpt
=
AnalyzeInvocation
(
invocation
,
infoCache
,
analyzerOptionsOpt
:
null
,
cancellationToken
);
if
(
resultOpt
!=
null
)
{
var
result
=
resultOpt
.
Value
;
var
updatedNode
=
FixOne
(
semanticModel
,
result
,
cancellationToken
);
if
(
updatedNode
!=
null
)
{
return
currentRoot
.
ReplaceNode
(
result
.
Invocation
,
updatedNode
);
}
}
}
return
currentRoot
;
}
private
void
FixOne
(
SemanticModel
semanticModel
,
SyntaxEditor
editor
,
Diagnostic
diagnostic
,
CancellationToken
cancellationToken
)
private
static
InvocationExpressionSyntax
GetInvocationExpression
(
Diagnostic
d
,
CancellationToken
cancellationToken
)
=>
(
InvocationExpressionSyntax
)
d
.
AdditionalLocations
[
0
].
FindNode
(
getInnermostNodeForTie
:
true
,
cancellationToken
);
private
ExpressionSyntax
FixOne
(
SemanticModel
semanticModel
,
Result
result
,
CancellationToken
cancellationToken
)
{
var
invocation
=
(
InvocationExpressionSyntax
)
diagnostic
.
AdditionalLocations
[
0
].
FindNode
(
getInnermostNodeForTie
:
true
,
cancellationToken
)
;
var
invocation
=
result
.
Invocation
;
var
expression
=
invocation
.
Expression
is
MemberAccessExpressionSyntax
memberAccess
?
memberAccess
.
Expression
:
invocation
.
Expression
;
var
rangeExpression
=
CreateRangeExpression
(
semanticModel
,
diagnostic
,
invocation
,
cancellationToken
);
var
rangeExpression
=
CreateRangeExpression
(
semanticModel
,
result
,
cancellationToken
);
var
argument
=
Argument
(
rangeExpression
).
WithAdditionalAnnotations
(
Formatter
.
Annotation
);
var
arguments
=
SingletonSeparatedList
(
argument
);
if
(
diagnostic
.
Properties
.
ContainsKey
(
UseIndexer
)
)
if
(
result
.
MemberInfo
.
OverloadedMethodOpt
==
null
)
{
var
argList
=
invocation
.
ArgumentList
;
var
elementAccess
=
ElementAccessExpression
(
return
ElementAccessExpression
(
expression
,
BracketedArgumentList
(
Token
(
SyntaxKind
.
OpenBracketToken
).
WithTriviaFrom
(
argList
.
OpenParenToken
),
arguments
,
Token
(
SyntaxKind
.
CloseBracketToken
).
WithTriviaFrom
(
argList
.
CloseParenToken
)));
editor
.
ReplaceNode
(
invocation
,
elementAccess
);
}
else
{
editor
.
ReplaceNode
(
return
invocation
.
ReplaceNode
(
invocation
.
ArgumentList
,
invocation
.
ArgumentList
.
WithArguments
(
arguments
));
}
}
private
RangeExpressionSyntax
CreateRangeExpression
(
SemanticModel
semanticModel
,
Diagnostic
diagnostic
,
InvocationExpressionSyntax
invocation
,
CancellationToken
cancellationToken
)
SemanticModel
semanticModel
,
Result
result
,
CancellationToken
cancellationToken
)
{
var
properties
=
diagnostic
.
Properties
;
if
(
properties
.
ContainsKey
(
ComputedRange
))
if
(
result
.
RangeKind
==
ComputedRange
)
{
return
CreateComputedRange
(
semanticModel
,
diagnostic
,
invocation
,
cancellationToken
);
return
CreateComputedRange
(
semanticModel
,
result
,
cancellationToken
);
}
else
if
(
properties
.
ContainsKey
(
ConstantRange
)
)
else
if
(
result
.
RangeKind
==
ConstantRange
)
{
return
CreateConstantRange
(
semanticModel
,
diagnostic
,
cancellationToken
);
return
CreateConstantRange
(
semanticModel
,
result
,
cancellationToken
);
}
else
{
...
...
@@ -103,59 +131,48 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
}
private
RangeExpressionSyntax
CreateComputedRange
(
SemanticModel
semanticModel
,
Diagnostic
diagnostic
,
InvocationExpressionSyntax
invocation
,
CancellationToken
cancellationToken
)
SemanticModel
semanticModel
,
Result
result
,
CancellationToken
cancellationToken
)
{
var
startExpr
=
(
ExpressionSyntax
)
diagnostic
.
AdditionalLocations
[
1
].
FindNode
(
getInnermostNodeForTie
:
true
,
cancellationToken
);
var
endExpr
=
(
ExpressionSyntax
)
diagnostic
.
AdditionalLocations
[
2
].
FindNode
(
getInnermostNodeForTie
:
true
,
cancellationToken
);
// We have enough information now to generate `start..end`. However, this will often
// not be what the user wants. For example, generating `start..expr.Length` is not as
// desirable as `start..`. Similarly, `start..(expr.Length - 1)` is not as desirable as
// `start..^1`.
var
startOperation
=
result
.
Op1
;
var
endOperation
=
result
.
Op2
;
var
startExpr
=
(
ExpressionSyntax
)
startOperation
.
Syntax
;
var
endExpr
=
(
ExpressionSyntax
)
endOperation
.
Syntax
;
var
startFromEnd
=
false
;
var
endFromEnd
=
false
;
if
(
semanticModel
.
GetOperation
(
invocation
,
cancellationToken
)
is
IInvocationOperation
invocationOp
&&
IsSliceLikeMethod
(
invocationOp
.
TargetMethod
)
&&
invocationOp
.
Instance
!=
null
)
{
var
startOperation
=
semanticModel
.
GetOperation
(
startExpr
,
cancellationToken
);
var
endOperation
=
semanticModel
.
GetOperation
(
endExpr
,
cancellationToken
);
var
checker
=
new
InfoCache
(
semanticModel
.
Compilation
);
if
(
startOperation
!=
null
&&
endOperation
!=
null
&&
checker
.
TryGetMemberInfo
(
invocationOp
.
TargetMethod
,
out
var
memberInfo
))
{
var
lengthLikeProperty
=
memberInfo
.
LengthLikeProperty
;
var
lengthLikeProperty
=
result
.
MemberInfo
.
LengthLikeProperty
;
var
instance
=
result
.
InvocationOperation
.
Instance
;
// If our start-op is actually equivalent to `expr.Length - val`, then just change our
// start-op to be `val` and record that we should emit it as `^val`.
startFromEnd
=
IsFromEnd
(
lengthLikeProperty
,
invocationOp
.
I
nstance
,
ref
startOperation
);
startExpr
=
(
ExpressionSyntax
)
startOperation
.
Syntax
;
// If our start-op is actually equivalent to `expr.Length - val`, then just change our
// start-op to be `val` and record that we should emit it as `^val`.
startFromEnd
=
IsFromEnd
(
lengthLikeProperty
,
i
nstance
,
ref
startOperation
);
startExpr
=
(
ExpressionSyntax
)
startOperation
.
Syntax
;
// Similarly, if our end-op is actually equivalent to `expr.Length - val`, then just
// change our end-op to be `val` and record that we should emit it as `^val`.
endFromEnd
=
IsFromEnd
(
lengthLikeProperty
,
invocationOp
.
I
nstance
,
ref
endOperation
);
endExpr
=
(
ExpressionSyntax
)
endOperation
.
Syntax
;
// Similarly, if our end-op is actually equivalent to `expr.Length - val`, then just
// change our end-op to be `val` and record that we should emit it as `^val`.
endFromEnd
=
IsFromEnd
(
lengthLikeProperty
,
i
nstance
,
ref
endOperation
);
endExpr
=
(
ExpressionSyntax
)
endOperation
.
Syntax
;
// If the range operation goes to 'expr.Length' then we can just leave off the end part
// of the range. i.e. `start..`
if
(
IsInstanceLengthCheck
(
lengthLikeProperty
,
invocationOp
.
I
nstance
,
endOperation
))
{
endExpr
=
null
;
}
// If the range operation goes to 'expr.Length' then we can just leave off the end part
// of the range. i.e. `start..`
if
(
IsInstanceLengthCheck
(
lengthLikeProperty
,
i
nstance
,
endOperation
))
{
endExpr
=
null
;
}
// If we're starting the range operation from 0, then we can just leave off the start of
// the range. i.e. `..end`
if
(
startOperation
.
ConstantValue
.
HasValue
&&
startOperation
.
ConstantValue
.
Value
is
0
)
{
startExpr
=
null
;
}
}
// If we're starting the range operation from 0, then we can just leave off the start of
// the range. i.e. `..end`
if
(
startOperation
.
ConstantValue
.
HasValue
&&
startOperation
.
ConstantValue
.
Value
is
0
)
{
startExpr
=
null
;
}
return
RangeExpression
(
...
...
@@ -169,15 +186,15 @@ private static ExpressionSyntax GetExpression(ImmutableDictionary<string, string
:
props
.
ContainsKey
(
fromEndKey
)
?
IndexExpression
(
expr
)
:
expr
;
private
static
RangeExpressionSyntax
CreateConstantRange
(
SemanticModel
semanticModel
,
Diagnostic
diagnostic
,
CancellationToken
cancellationToken
)
SemanticModel
semanticModel
,
Result
result
,
CancellationToken
cancellationToken
)
{
var
constant1Syntax
=
(
ExpressionSyntax
)
diagnostic
.
AdditionalLocations
[
1
].
FindNode
(
getInnermostNodeForTie
:
true
,
cancellationToken
)
;
var
constant2Syntax
=
(
ExpressionSyntax
)
diagnostic
.
AdditionalLocations
[
2
].
FindNode
(
getInnermostNodeForTie
:
true
,
cancellationToken
)
;
var
constant1Syntax
=
(
ExpressionSyntax
)
result
.
Op1
.
Syntax
;
var
constant2Syntax
=
(
ExpressionSyntax
)
result
.
Op2
.
Syntax
;
// the form is s.Slice(constant1, s.Length - constant2). Want to generate
// s[constant1..(constant2-constant1)]
var
constant1
=
GetInt32Value
(
semanticModel
.
GetOperation
(
constant1Syntax
)
);
var
constant2
=
GetInt32Value
(
semanticModel
.
GetOperation
(
constant2Syntax
)
);
var
constant1
=
GetInt32Value
(
result
.
Op1
);
var
constant2
=
GetInt32Value
(
result
.
Op2
);
var
endExpr
=
(
ExpressionSyntax
)
CSharpSyntaxGenerator
.
Instance
.
LiteralExpression
(
constant2
-
constant1
);
return
RangeExpression
(
...
...
src/Features/CSharp/Portable/UseIndexOrRangeOperator/CSharpUseRangeOperatorDiagnosticAnalyzer.cs
浏览文件 @
a5309d1f
...
...
@@ -2,6 +2,7 @@
using
System.Collections.Immutable
;
using
System.Composition
;
using
System.Threading
;
using
Microsoft.CodeAnalysis.CodeStyle
;
using
Microsoft.CodeAnalysis.CSharp.CodeStyle
;
using
Microsoft.CodeAnalysis.CSharp.Syntax
;
...
...
@@ -29,11 +30,11 @@ namespace Microsoft.CodeAnalysis.CSharp.UseIndexOrRangeOperator
[
DiagnosticAnalyzer
(
LanguageNames
.
CSharp
),
Shared
]
internal
partial
class
CSharpUseRangeOperatorDiagnosticAnalyzer
:
AbstractBuiltInCodeStyleDiagnosticAnalyzer
{
public
const
string
UseIndexer
=
nameof
(
UseIndexer
);
//
public const string UseIndexer = nameof(UseIndexer);
public
const
string
ComputedRange
=
nameof
(
ComputedRange
);
public
const
string
ConstantRange
=
nameof
(
ConstantRange
);
public
CSharpUseRangeOperatorDiagnosticAnalyzer
()
public
CSharpUseRangeOperatorDiagnosticAnalyzer
()
:
base
(
IDEDiagnosticIds
.
UseRangeOperatorDiagnosticId
,
new
LocalizableResourceString
(
nameof
(
FeaturesResources
.
Use_range_operator
),
FeaturesResources
.
ResourceManager
,
typeof
(
FeaturesResources
)),
new
LocalizableResourceString
(
nameof
(
FeaturesResources
.
_0_can_be_simplified
),
FeaturesResources
.
ResourceManager
,
typeof
(
FeaturesResources
)))
...
...
@@ -59,44 +60,67 @@ protected override void InitializeWorker(AnalysisContext context)
private
void
AnalyzeInvocation
(
OperationAnalysisContext
context
,
InfoCache
infoCache
)
{
var
cancellationToken
=
context
.
CancellationToken
;
var
invocation
=
(
IInvocationOperation
)
context
.
Operation
;
var
resultOpt
=
AnalyzeInvocation
(
(
IInvocationOperation
)
context
.
Operation
,
infoCache
,
context
.
Options
,
context
.
CancellationToken
)
;
// Validate we're on a piece of syntax we expect. While not necessary for analysis, we
// want to make sure we're on something the fixer will know how to actually fix.
var
invocationSyntax
=
invocation
.
Syntax
as
InvocationExpressionSyntax
;
if
(
invocationSyntax
is
null
||
invocationSyntax
.
ArgumentList
is
null
)
if
(
resultOpt
==
null
)
{
return
;
}
// Check if we're at least on C# 8, and that the user wants these operators.
var
syntaxTree
=
invocationSyntax
.
SyntaxTree
;
var
parseOptions
=
(
CSharpParseOptions
)
syntaxTree
.
Options
;
if
(
parseOptions
.
LanguageVersion
<
LanguageVersion
.
CSharp8
)
{
return
;
}
var
result
=
resultOpt
.
Value
;
context
.
ReportDiagnostic
(
CreateDiagnostic
(
result
.
RangeKind
,
result
.
Option
,
result
.
Invocation
,
result
.
SliceLikeMethod
,
result
.
MemberInfo
,
result
.
Op1
,
result
.
Op2
));
}
var
optionSet
=
context
.
Options
.
GetDocumentOptionSetAsync
(
syntaxTree
,
cancellationToken
).
GetAwaiter
().
GetResult
();
if
(
optionSet
is
null
)
public
static
Result
?
AnalyzeInvocation
(
IInvocationOperation
invocation
,
InfoCache
infoCache
,
AnalyzerOptions
analyzerOptionsOpt
,
CancellationToken
cancellationToken
)
{
// Validate we're on a piece of syntax we expect. While not necessary for analysis, we
// want to make sure we're on something the fixer will know how to actually fix.
var
invocationSyntax
=
invocation
.
Syntax
as
InvocationExpressionSyntax
;
if
(
invocationSyntax
is
null
||
invocationSyntax
.
ArgumentList
is
null
)
{
return
;
return
default
;
}
var
option
=
optionSet
.
GetOption
(
CSharpCodeStyleOptions
.
PreferRangeOperator
)
;
if
(
!
option
.
Value
)
CodeStyleOption
<
bool
>
option
=
null
;
if
(
analyzerOptionsOpt
!=
null
)
{
return
;
// Check if we're at least on C# 8, and that the user wants these operators.
var
syntaxTree
=
invocationSyntax
.
SyntaxTree
;
var
parseOptions
=
(
CSharpParseOptions
)
syntaxTree
.
Options
;
if
(
parseOptions
.
LanguageVersion
<
LanguageVersion
.
CSharp8
)
{
return
default
;
}
var
optionSet
=
analyzerOptionsOpt
.
GetDocumentOptionSetAsync
(
syntaxTree
,
cancellationToken
).
GetAwaiter
().
GetResult
();
if
(
optionSet
is
null
)
{
return
default
;
}
option
=
optionSet
.
GetOption
(
CSharpCodeStyleOptions
.
PreferRangeOperator
);
if
(!
option
.
Value
)
{
return
default
;
}
}
// look for `s.Slice(e1, end - e2)`
if
(
invocation
.
Instance
is
null
||
invocation
.
Arguments
.
Length
!=
2
)
{
return
;
return
default
;
}
// See if the call is to something slice-like.
...
...
@@ -108,7 +132,7 @@ protected override void InitializeWorker(AnalysisContext context)
if
(!
IsSubtraction
(
invocation
.
Arguments
[
1
].
Value
,
out
var
subtraction
)
||
!
infoCache
.
TryGetMemberInfo
(
targetMethod
,
out
var
memberInfo
))
{
return
;
return
default
;
}
// See if we have: (start, end - start). Specifically where the start operation it the
...
...
@@ -117,10 +141,11 @@ protected override void InitializeWorker(AnalysisContext context)
if
(
CSharpSyntaxFactsService
.
Instance
.
AreEquivalent
(
startOperation
.
Syntax
,
subtraction
.
RightOperand
.
Syntax
))
{
context
.
ReportDiagnostic
(
CreateDiagnostic
(
ComputedRange
,
option
,
invocationSyntax
,
targetMethod
,
memberInfo
,
startOperation
,
subtraction
.
LeftOperand
));
return
;
return
new
Result
(
ComputedRange
,
option
,
invocation
,
invocationSyntax
,
targetMethod
,
memberInfo
,
startOperation
,
subtraction
.
LeftOperand
);
}
// See if we have: (constant1, s.Length - constant2). The constants don't have to be
...
...
@@ -129,30 +154,23 @@ protected override void InitializeWorker(AnalysisContext context)
IsConstantInt32
(
subtraction
.
RightOperand
)
&&
IsInstanceLengthCheck
(
memberInfo
.
LengthLikeProperty
,
invocation
.
Instance
,
subtraction
.
LeftOperand
))
{
context
.
ReportDiagnostic
(
CreateDiagnostic
(
ConstantRange
,
option
,
invocationSyntax
,
targetMethod
,
memberInfo
,
startOperation
,
subtraction
.
RightOperand
));
return
;
return
new
Result
(
ConstantRange
,
option
,
invocation
,
invocationSyntax
,
targetMethod
,
memberInfo
,
startOperation
,
subtraction
.
RightOperand
);
}
return
default
;
}
private
Diagnostic
CreateDiagnostic
(
string
rangeKind
,
CodeStyleOption
<
bool
>
option
,
InvocationExpressionSyntax
invocation
,
string
rangeKind
,
CodeStyleOption
<
bool
>
option
,
InvocationExpressionSyntax
invocation
,
IMethodSymbol
sliceLikeMethod
,
MemberInfo
memberInfo
,
IOperation
op1
,
IOperation
op2
)
{
var
properties
=
ImmutableDictionary
<
string
,
string
>.
Empty
.
Add
(
rangeKind
,
rangeKind
);
if
(
memberInfo
.
OverloadedMethodOpt
==
null
)
{
properties
=
properties
.
Add
(
UseIndexer
,
UseIndexer
);
}
// Keep track of the syntax nodes from the start/end ops so that we can easily
// generate the range-expression in the fixer.
// Keep track of the invocation node
var
additionalLocations
=
ImmutableArray
.
Create
(
invocation
.
GetLocation
(),
op1
.
Syntax
.
GetLocation
(),
op2
.
Syntax
.
GetLocation
());
invocation
.
GetLocation
());
// Mark the span under the two arguments to .Slice(..., ...) as what we will be
// updating.
...
...
@@ -165,11 +183,39 @@ protected override void InitializeWorker(AnalysisContext context)
location
,
option
.
Notification
.
Severity
,
additionalLocations
,
properties
,
ImmutableDictionary
<
string
,
string
>.
Empty
,
sliceLikeMethod
.
Name
);
}
private
static
bool
IsConstantInt32
(
IOperation
operation
)
=>
operation
.
ConstantValue
.
HasValue
&&
operation
.
ConstantValue
.
Value
is
int
;
public
readonly
struct
Result
{
public
readonly
string
RangeKind
;
public
readonly
CodeStyleOption
<
bool
>
Option
;
public
readonly
IInvocationOperation
InvocationOperation
;
public
readonly
InvocationExpressionSyntax
Invocation
;
public
readonly
IMethodSymbol
SliceLikeMethod
;
public
readonly
MemberInfo
MemberInfo
;
public
readonly
IOperation
Op1
;
public
readonly
IOperation
Op2
;
public
Result
(
string
rangeKind
,
CodeStyleOption
<
bool
>
option
,
IInvocationOperation
invocationOperation
,
InvocationExpressionSyntax
invocation
,
IMethodSymbol
sliceLikeMethod
,
MemberInfo
memberInfo
,
IOperation
op1
,
IOperation
op2
)
{
RangeKind
=
rangeKind
;
Option
=
option
;
InvocationOperation
=
invocationOperation
;
Invocation
=
invocation
;
SliceLikeMethod
=
sliceLikeMethod
;
MemberInfo
=
memberInfo
;
Op1
=
op1
;
Op2
=
op2
;
}
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录