Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
2d6f5d31
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,发现更多精彩内容 >>
提交
2d6f5d31
编写于
6月 03, 2016
作者:
C
CyrusNajmabadi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Properly handle trivia when replacing a property with methods.
上级
e49822fd
变更
2
显示空白变更内容
内联
并排
Showing
2 changed file
with
168 addition
and
31 deletion
+168
-31
src/EditorFeatures/CSharpTest/CodeActions/ReplacePropertyWithMethods/ReplacePropertyWithMethodsTests.cs
...acePropertyWithMethods/ReplacePropertyWithMethodsTests.cs
+108
-0
src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs
...yWithMethods/AbstractReplacePropertyWithMethodsService.cs
+60
-31
未找到文件。
src/EditorFeatures/CSharpTest/CodeActions/ReplacePropertyWithMethods/ReplacePropertyWithMethodsTests.cs
浏览文件 @
2d6f5d31
...
...
@@ -453,5 +453,113 @@ public async Task TestUniqueName3()
public abstract void SetProp(dynamic i);
}"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsReplacePropertyWithMethods
)]
public
async
Task
TestTrivia1
()
{
await
TestAsync
(
@"class C
{
int [||]Prop { get; set; }
void M()
{
Prop++;
}
}"
,
@"class C
{
private int prop;
private int GetProp()
{
return this.prop;
}
private void SetProp(int value)
{
this.prop = value;
}
void M()
{
SetProp(GetProp() + 1);
}
}"
,
compareTokens
:
false
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsReplacePropertyWithMethods
)]
public
async
Task
TestTrivia2
()
{
await
TestAsync
(
@"class C
{
int [||]Prop { get; set; }
void M()
{
/* Leading */
Prop++; /* Trailing */
}
}"
,
@"class C
{
private int prop;
private int GetProp()
{
return this.prop;
}
private void SetProp(int value)
{
this.prop = value;
}
void M()
{
/* Leading */
SetProp(GetProp() + 1); /* Trailing */
}
}"
,
compareTokens
:
false
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsReplacePropertyWithMethods
)]
public
async
Task
TestTrivia3
()
{
await
TestAsync
(
@"class C
{
int [||]Prop { get; set; }
void M()
{
/* Leading */
Prop += 1 /* Trailing */ ;
}
}"
,
@"class C
{
private int prop;
private int GetProp()
{
return this.prop;
}
private void SetProp(int value)
{
this.prop = value;
}
void M()
{
/* Leading */
SetProp(GetProp() + 1 /* Trailing */ );
}
}"
,
compareTokens
:
false
);
}
}
}
src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs
浏览文件 @
2d6f5d31
...
...
@@ -110,7 +110,8 @@ public void Do()
// Code wasn't legal (you can't reference a property in an out/ref position in C#).
// Just replace this with a simple GetCall, but mark it so it's clear there's an error.
ReplaceRead
(
FeaturesResources
.
Property_cannot_safely_be_replaced_with_a_method_call
);
keepTrivia
:
true
,
conflictMessage
:
FeaturesResources
.
Property_cannot_safely_be_replaced_with_a_method_call
);
}
else
if
(
_syntaxFacts
.
IsAttributeNamedArgumentIdentifier
(
_expression
))
{
...
...
@@ -124,7 +125,10 @@ public void Do()
{
// We're only being written to here. This is safe to replace with a call to the
// setter.
ReplaceWrite
(
writeValue
:
(
TExpressionSyntax
)
_syntaxFacts
.
GetRightHandSideOfAssignment
(
_expression
.
Parent
));
ReplaceWrite
(
writeValue
:
(
TExpressionSyntax
)
_syntaxFacts
.
GetRightHandSideOfAssignment
(
_expression
.
Parent
),
keepTrivia
:
true
,
conflictMessage
:
null
);
}
else
if
(
_syntaxFacts
.
IsLeftSideOfAnyAssignment
(
_expression
))
{
...
...
@@ -134,21 +138,21 @@ public void Do()
{
// We're being read from and written to (i.e. Prop++), we need to replace with a
// Get and a Set call.
var
readExpression
=
GetReadExpression
(
conflictMessage
:
null
);
var
readExpression
=
GetReadExpression
(
keepTrivia
:
false
,
conflictMessage
:
null
);
var
literalOne
=
Generator
.
LiteralExpression
(
1
);
var
writeValue
=
_syntaxFacts
.
IsOperandOfIncrementExpression
(
_expression
)
?
Generator
.
AddExpression
(
readExpression
,
literalOne
)
:
Generator
.
SubtractExpression
(
readExpression
,
literalOne
);
ReplaceWrite
((
TExpressionSyntax
)
writeValue
);
ReplaceWrite
((
TExpressionSyntax
)
writeValue
,
keepTrivia
:
true
,
conflictMessage
:
null
);
}
else
if
(
_syntaxFacts
.
IsInferredAnonymousObjectMemberDeclarator
(
_expression
.
Parent
))
//.IsParentKind(SyntaxKind.AnonymousObjectMemberDeclarator))
{
// If we have: new { this.Prop }. We need ot convert it to:
// new { Prop = this.GetProp() }
var
declarator
=
_expression
.
Parent
;
var
readExpression
=
GetReadExpression
(
conflictMessage
:
null
);
var
readExpression
=
GetReadExpression
(
keepTrivia
:
true
,
conflictMessage
:
null
);
var
newDeclarator
=
Generator
.
NamedAnonymousObjectMemberDeclarator
(
_identifierName
.
WithoutTrivia
(),
...
...
@@ -159,19 +163,22 @@ public void Do()
else
{
// No writes. Replace this with an appropriate read.
ReplaceRead
(
conflictMessage
:
null
);
ReplaceRead
(
keepTrivia
:
true
,
conflictMessage
:
null
);
}
}
private
void
ReplaceRead
(
string
conflictMessage
)
private
void
ReplaceRead
(
bool
keepTrivia
,
string
conflictMessage
)
{
var
readExpression
=
GetReadExpression
(
conflictMessage
);
var
readExpression
=
GetReadExpression
(
keepTrivia
,
conflictMessage
);
_editor
.
ReplaceNode
(
_expression
,
readExpression
);
}
private
void
ReplaceWrite
(
TExpressionSyntax
writeValue
)
private
void
ReplaceWrite
(
TExpressionSyntax
writeValue
,
bool
keepTrivia
,
string
conflictMessage
)
{
var
writeExpression
=
GetWriteExpression
(
writeValue
);
var
writeExpression
=
GetWriteExpression
(
writeValue
,
keepTrivia
,
conflictMessage
);
if
(
_expression
.
Parent
is
TStatementSyntax
)
{
writeExpression
=
Generator
.
ExpressionStatement
(
writeExpression
);
...
...
@@ -181,28 +188,41 @@ private void ReplaceWrite(TExpressionSyntax writeValue)
}
private
TExpressionSyntax
GetReadExpression
(
string
conflictMessage
)
bool
keepTrivia
,
string
conflictMessage
)
{
if
(
ShouldReadFromBackingField
())
{
var
newIdentifierToken
=
AddConflictAnnotation
(
Generator
.
Identifier
(
_propertyBackingField
.
Name
),
conflictMessage
);
var
newIdentifierName
=
Generator
.
IdentifierName
(
newIdentifierToken
).
WithTriviaFrom
(
_identifierName
);
var
newIdentifierName
=
Generator
.
IdentifierName
(
newIdentifierToken
);
if
(
keepTrivia
)
{
newIdentifierName
=
newIdentifierName
.
WithTriviaFrom
(
_identifierName
);
}
return
_expression
.
ReplaceNode
(
_identifierName
,
newIdentifierName
);
}
else
{
return
GetGetInvocationExpression
(
conflictMessage
);
return
GetGetInvocationExpression
(
keepTrivia
,
conflictMessage
);
}
}
private
SyntaxNode
GetWriteExpression
(
TExpressionSyntax
writeValue
)
private
SyntaxNode
GetWriteExpression
(
TExpressionSyntax
writeValue
,
bool
keepTrivia
,
string
conflictMessage
)
{
if
(
ShouldWriteToBackingField
())
{
var
newIdentifierName
=
Generator
.
IdentifierName
(
_propertyBackingField
.
Name
)
.
WithTriviaFrom
(
_identifierName
);
var
newIdentifierName
=
(
TIdentifierNameSyntax
)
Generator
.
IdentifierName
(
_propertyBackingField
.
Name
);
if
(
keepTrivia
)
{
newIdentifierName
=
newIdentifierName
.
WithTriviaFrom
(
_identifierName
);
}
newIdentifierName
=
AddConflictAnnotation
(
newIdentifierName
,
conflictMessage
);
return
Generator
.
AssignmentStatement
(
_expression
.
ReplaceNode
(
_identifierName
,
newIdentifierName
),
...
...
@@ -210,32 +230,39 @@ private SyntaxNode GetWriteExpression(TExpressionSyntax writeValue)
}
else
{
return
GetSetInvocationExpression
(
writeValue
);
return
GetSetInvocationExpression
(
writeValue
,
keepTrivia
,
conflictMessage
);
}
}
private
TExpressionSyntax
GetGetInvocationExpression
(
string
conflictMessage
)
bool
keepTrivia
,
string
conflictMessage
)
{
return
GetInvocationExpression
(
_desiredGetMethodName
,
argument
:
null
,
conflictMessage
:
conflictMessage
);
return
GetInvocationExpression
(
_desiredGetMethodName
,
argument
:
null
,
keepTrivia
:
keepTrivia
,
conflictMessage
:
conflictMessage
);
}
private
TExpressionSyntax
GetInvocationExpression
(
string
desiredName
,
SyntaxNode
argument
,
string
conflictMessage
)
string
desiredName
,
SyntaxNode
argument
,
bool
keepTrivia
,
string
conflictMessage
)
{
var
newIdentifier
=
AddConflictAnnotation
(
Generator
.
Identifier
(
desiredName
),
conflictMessage
);
var
updatedExpression
=
_expression
.
ReplaceNode
(
_identifierName
,
Generator
.
IdentifierName
(
newIdentifier
)
.
WithLeadingTrivia
(
_identifierName
.
GetLeadingTrivia
()));
var
newIdentifierName
=
Generator
.
IdentifierName
(
newIdentifier
);
if
(
keepTrivia
)
{
newIdentifierName
=
newIdentifierName
.
WithLeadingTrivia
(
_identifierName
.
GetLeadingTrivia
());
}
var
updatedExpression
=
_expression
.
ReplaceNode
(
_identifierName
,
newIdentifierName
);
var
arguments
=
argument
==
null
?
SpecializedCollections
.
EmptyEnumerable
<
SyntaxNode
>()
:
SpecializedCollections
.
SingletonEnumerable
(
argument
);
var
invocation
=
Generator
.
InvocationExpression
(
updatedExpression
,
arguments
)
.
WithTrailingTrivia
(
_identifierName
.
GetTrailingTrivia
());
var
invocation
=
Generator
.
InvocationExpression
(
updatedExpression
,
arguments
);
if
(
keepTrivia
)
{
invocation
=
invocation
.
WithTrailingTrivia
(
_identifierName
.
GetTrailingTrivia
());
}
return
(
TExpressionSyntax
)
invocation
;
}
...
...
@@ -246,10 +273,12 @@ private bool ShouldReadFromBackingField()
}
private
SyntaxNode
GetSetInvocationExpression
(
TExpressionSyntax
writeValue
,
string
conflictMessage
=
null
)
TExpressionSyntax
writeValue
,
bool
keepTrivia
,
string
conflictMessage
)
{
return
GetInvocationExpression
(
_desiredSetMethodName
,
argument
:
Generator
.
Argument
(
writeValue
),
conflictMessage
:
conflictMessage
);
argument
:
Generator
.
Argument
(
writeValue
),
keepTrivia
:
keepTrivia
,
conflictMessage
:
conflictMessage
);
}
private
bool
ShouldWriteToBackingField
()
...
...
@@ -262,12 +291,12 @@ private void HandleCompoundAssignExpression()
// We're being read from and written to from a compound assignment
// (i.e. Prop *= X), we need to replace with a Get and a Set call.
var
readExpression
=
GetReadExpression
(
conflictMessage
:
null
);
var
readExpression
=
GetReadExpression
(
keepTrivia
:
false
,
conflictMessage
:
null
);
// Convert "Prop *= X" into "Prop * X".
var
writeValue
=
_service
.
UnwrapCompoundAssignment
(
_expression
.
Parent
,
readExpression
);
ReplaceWrite
(
writeValue
);
ReplaceWrite
(
writeValue
,
keepTrivia
:
true
,
conflictMessage
:
null
);
}
private
static
TIdentifierNameSyntax
AddConflictAnnotation
(
TIdentifierNameSyntax
name
,
string
conflictMessage
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录