Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
a31ac79d
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,发现更多精彩内容 >>
提交
a31ac79d
编写于
3月 12, 2019
作者:
A
Andrew Hall (METAL)
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add new function to IMoveTypeService
上级
0196c9d5
变更
9
显示空白变更内容
内联
并排
Showing
9 changed file
with
950 addition
and
40 deletion
+950
-40
src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveScope.cs
...SharpTest/CodeActions/MoveType/MoveTypeTests.MoveScope.cs
+682
-0
src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeCodeAction.cs
...gs/MoveType/AbstractMoveTypeService.MoveTypeCodeAction.cs
+15
-9
src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeScopeEditor.cs
...s/MoveType/AbstractMoveTypeService.MoveTypeScopeEditor.cs
+169
-0
src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.cs
...able/CodeRefactorings/MoveType/AbstractMoveTypeService.cs
+61
-31
src/Features/Core/Portable/CodeRefactorings/MoveType/IMoveTypeService.cs
...re/Portable/CodeRefactorings/MoveType/IMoveTypeService.cs
+1
-0
src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeOperationKind.cs
...rtable/CodeRefactorings/MoveType/MoveTypeOperationKind.cs
+14
-0
src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
...arp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
+3
-0
src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs
...anguageServices/SyntaxFactsService/ISyntaxFactsService.cs
+1
-0
src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
...ortable/LanguageServices/VisualBasicSyntaxFactsService.vb
+4
-0
未找到文件。
src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveScope.cs
0 → 100644
浏览文件 @
a31ac79d
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.CodeRefactorings.MoveType
;
using
Microsoft.CodeAnalysis.Formatting
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.CodeAnalysis.Test.Utilities
;
using
Roslyn.Test.Utilities
;
using
Xunit
;
namespace
Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeActions.MoveType
{
public
partial
class
MoveTypeTests
:
CSharpMoveTypeTestsBase
{
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_SingleItem
()
{
var
code
=
@"namespace N1
{
class [||]Class1
{
}
}"
;
var
expected
=
@"namespace N1
{
class Class1
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_ItemAtTop
()
{
var
code
=
@"namespace N1
{
class [||]Class1
{
}
class Class2
{
}
}"
;
var
expected
=
@"namespace N1
{
class Class1
{
}
}
namespace N1
{
class Class2
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_ItemAtTopWithComments
()
{
var
code
=
@"namespace N1
{
// Class1 Comment
class [||]Class1
{
}
// Class2 Comment
class Class2
{
}
}"
;
var
expected
=
@"namespace N1
{
// Class1 Comment
class Class1
{
}
}
namespace N1
{
// Class2 Comment
class Class2
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_ItemAtTopWithXmlComments
()
{
var
code
=
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class [||]Class1
{
}
/// <summary>
/// Class2 summary
/// </summary>
class Class2
{
}
}"
;
var
expected
=
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class Class1
{
}
}
namespace N1
{
/// <summary>
/// Class2 summary
/// </summary>
class Class2
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_ItemAtBottom
()
{
var
code
=
@"namespace N1
{
class Class1
{
}
class [||]Class2
{
}
}"
;
var
expected
=
@"namespace N1
{
class Class1
{
}
}
namespace N1
{
class Class2
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_ItemAtBottomWithComments
()
{
var
code
=
@"namespace N1
{
// Class1 comment
class Class1
{
}
// Class2 comment
class [||]Class2
{
}
}"
;
var
expected
=
@"namespace N1
{
// Class1 comment
class Class1
{
}
}
namespace N1
{
// Class2 comment
class Class2
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_ItemAtBottomWithXmlComments
()
{
var
code
=
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class Class1
{
}
/// <summary>
/// Class2 summary
/// </summary>
class [||]Class2
{
}
}"
;
var
expected
=
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class Class1
{
}
}
namespace N1
{
/// <summary>
/// Class2 summary
/// </summary>
class Class2
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_ItemInMiddle
()
{
var
code
=
@"namespace N1
{
class Class1
{
}
class Class2
{
}
class [||]Class3
{
}
class Class4
{
}
class Class5
{
}
}"
;
var
expected
=
@"namespace N1
{
class Class1
{
}
class Class2
{
}
}
namespace N1
{
class Class3
{
}
}
namespace N1
{
class Class4
{
}
class Class5
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_ItemInMiddleWithComments
()
{
var
code
=
@"namespace N1
{
// Class1 comment
class Class1
{
}
// Class2 comment
class Class2
{
}
// Class3 comment
class [||]Class3
{
}
// Class4 comment
class Class4
{
}
// Class5 comment
class Class5
{
}
}"
;
var
expected
=
@"namespace N1
{
// Class1 comment
class Class1
{
}
// Class2 comment
class Class2
{
}
}
namespace N1
{
// Class3 comment
class Class3
{
}
}
namespace N1
{
// Class4 comment
class Class4
{
}
// Class5 comment
class Class5
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_ItemInMiddleWithXmlComments
()
{
var
code
=
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class Class1
{
}
/// <summary>
/// Class2 summary
/// </summary>
class Class2
{
}
/// <summary>
/// Class3 summary
/// </summary>
class [||]Class3
{
}
/// <summary>
/// Class4 summary
/// </summary>
class Class4
{
}
/// <summary>
/// Class5 summary
/// </summary>
class Class5
{
}
}"
;
var
expected
=
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class Class1
{
}
/// <summary>
/// Class2 summary
/// </summary>
class Class2
{
}
}
namespace N1
{
/// <summary>
/// Class3 summary
/// </summary>
class Class3
{
}
}
namespace N1
{
/// <summary>
/// Class4 summary
/// </summary>
class Class4
{
}
/// <summary>
/// Class5 summary
/// </summary>
class Class5
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_ItemInMiddleWithInterface
()
{
var
code
=
@"namespace N1
{
// Class1 comment
class Class1
{
}
// IClass3 comment
interface IClass3
{
void DoStuff();
}
// Class3 comment
class [||]Class3 : IClass3
{
public void DoStuff() { }
}
// Class4 comment
class Class4
{
}
// Class5 comment
class Class5
{
}
}"
;
var
expected
=
@"namespace N1
{
// Class1 comment
class Class1
{
}
// IClass3 comment
interface IClass3
{
void DoStuff();
}
}
namespace N1
{
// Class3 comment
class Class3 : IClass3
{
public void DoStuff() { }
}
}
namespace N1
{
// Class4 comment
class Class4
{
}
// Class5 comment
class Class5
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_TwoItemsInDifferentNamespace
()
{
var
code
=
@"namespace N1
{
class [||]Class1
{
}
}
namespace N2
{
class Class2
{
}
}"
;
var
expected
=
@"namespace N1
{
class Class1
{
}
}
namespace N2
{
class Class2
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsMoveType
)]
public
Task
MoveType_NamespaceScope_ItemsInDifferentNamespace
()
{
var
code
=
@"namespace N1
{
interface IClass1
{
}
class [||]Class1 : IClass1
{
}
}
namespace N2
{
class Class2
{
}
}"
;
var
expected
=
@"namespace N1
{
interface IClass1
{
}
}
namespace N1
{
class Class1 : IClass1
{
}
}
namespace N2
{
class Class2
{
}
}"
;
return
TestNamespaceMove
(
code
,
expected
,
expectOperation
:
false
);
}
private
async
Task
TestNamespaceMove
(
string
originalCode
,
string
expectedCode
,
bool
expectOperation
=
true
)
{
using
(
var
workspace
=
CreateWorkspaceFromOptions
(
originalCode
,
default
))
{
var
documentToModifyId
=
workspace
.
Documents
[
0
].
Id
;
var
textSpan
=
workspace
.
Documents
[
0
].
SelectedSpans
[
0
];
var
documentToModify
=
workspace
.
CurrentSolution
.
GetDocument
(
documentToModifyId
);
var
moveTypeService
=
documentToModify
.
GetLanguageService
<
IMoveTypeService
>();
Assert
.
NotNull
(
moveTypeService
);
var
refactorings
=
await
moveTypeService
.
GetRefactoringAsync
(
documentToModify
,
textSpan
,
MoveTypeOperationKind
.
MoveTypeScope
,
CancellationToken
.
None
).
ConfigureAwait
(
false
);
Assert
.
NotEmpty
(
refactorings
);
foreach
(
var
refactoring
in
refactorings
)
{
Assert
.
True
(
refactoring
.
IsApplicable
(
workspace
));
var
operations
=
await
refactoring
.
GetOperationsAsync
(
CancellationToken
.
None
).
ConfigureAwait
(
false
);
if
(
expectOperation
)
{
Assert
.
NotEmpty
(
operations
);
}
foreach
(
var
operation
in
operations
)
{
operation
.
Apply
(
workspace
,
CancellationToken
.
None
);
}
}
var
modifiedDocument
=
workspace
.
CurrentSolution
.
GetDocument
(
documentToModifyId
);
var
formattedDocument
=
await
Formatter
.
FormatAsync
(
modifiedDocument
).
ConfigureAwait
(
false
);
var
formattedText
=
await
formattedDocument
.
GetTextAsync
().
ConfigureAwait
(
false
);
Assert
.
Equal
(
expectedCode
,
formattedText
.
ToString
());
}
}
}
}
src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeCodeAction.cs
浏览文件 @
a31ac79d
...
@@ -15,14 +15,14 @@ private class MoveTypeCodeAction : CodeAction
...
@@ -15,14 +15,14 @@ private class MoveTypeCodeAction : CodeAction
{
{
private
readonly
State
_state
;
private
readonly
State
_state
;
private
readonly
TService
_service
;
private
readonly
TService
_service
;
private
readonly
OperationKind
_operationKind
;
private
readonly
MoveType
OperationKind
_operationKind
;
private
readonly
string
_title
;
private
readonly
string
_title
;
private
readonly
string
_fileName
;
private
readonly
string
_fileName
;
public
MoveTypeCodeAction
(
public
MoveTypeCodeAction
(
TService
service
,
TService
service
,
State
state
,
State
state
,
OperationKind
operationKind
,
MoveType
OperationKind
operationKind
,
string
fileName
)
string
fileName
)
{
{
_state
=
state
;
_state
=
state
;
...
@@ -36,12 +36,14 @@ private string CreateDisplayText()
...
@@ -36,12 +36,14 @@ private string CreateDisplayText()
{
{
switch
(
_operationKind
)
switch
(
_operationKind
)
{
{
case
OperationKind
.
MoveType
:
case
MoveType
OperationKind
.
MoveType
:
return
string
.
Format
(
FeaturesResources
.
Move_type_to_0
,
_fileName
);
return
string
.
Format
(
FeaturesResources
.
Move_type_to_0
,
_fileName
);
case
OperationKind
.
RenameType
:
case
MoveType
OperationKind
.
RenameType
:
return
string
.
Format
(
FeaturesResources
.
Rename_type_to_0
,
_state
.
DocumentNameWithoutExtension
);
return
string
.
Format
(
FeaturesResources
.
Rename_type_to_0
,
_state
.
DocumentNameWithoutExtension
);
case
OperationKind
.
RenameFile
:
case
MoveType
OperationKind
.
RenameFile
:
return
string
.
Format
(
FeaturesResources
.
Rename_file_to_0
,
_fileName
);
return
string
.
Format
(
FeaturesResources
.
Rename_file_to_0
,
_fileName
);
case
MoveTypeOperationKind
.
MoveTypeScope
:
return
string
.
Empty
;
default
:
default
:
throw
ExceptionUtilities
.
UnexpectedValue
(
_operationKind
);
throw
ExceptionUtilities
.
UnexpectedValue
(
_operationKind
);
}
}
...
@@ -59,12 +61,14 @@ private Editor GetEditor(CancellationToken cancellationToken)
...
@@ -59,12 +61,14 @@ private Editor GetEditor(CancellationToken cancellationToken)
{
{
switch
(
_operationKind
)
switch
(
_operationKind
)
{
{
case
OperationKind
.
MoveType
:
case
MoveType
OperationKind
.
MoveType
:
return
new
MoveTypeEditor
(
_service
,
_state
,
_fileName
,
cancellationToken
);
return
new
MoveTypeEditor
(
_service
,
_state
,
_fileName
,
cancellationToken
);
case
OperationKind
.
RenameType
:
case
MoveType
OperationKind
.
RenameType
:
return
new
RenameTypeEditor
(
_service
,
_state
,
_fileName
,
cancellationToken
);
return
new
RenameTypeEditor
(
_service
,
_state
,
_fileName
,
cancellationToken
);
case
OperationKind
.
RenameFile
:
case
MoveType
OperationKind
.
RenameFile
:
return
new
RenameFileEditor
(
_service
,
_state
,
_fileName
,
cancellationToken
);
return
new
RenameFileEditor
(
_service
,
_state
,
_fileName
,
cancellationToken
);
case
MoveTypeOperationKind
.
MoveTypeScope
:
return
new
MoveTypeScopeEditor
(
_service
,
_state
,
_fileName
,
cancellationToken
);
default
:
default
:
throw
ExceptionUtilities
.
UnexpectedValue
(
_operationKind
);
throw
ExceptionUtilities
.
UnexpectedValue
(
_operationKind
);
}
}
...
@@ -76,8 +80,10 @@ internal override bool IsApplicable(Workspace workspace)
...
@@ -76,8 +80,10 @@ internal override bool IsApplicable(Workspace workspace)
{
{
switch
(
_operationKind
)
switch
(
_operationKind
)
{
{
case
OperationKind
.
RenameFile
:
case
MoveType
OperationKind
.
RenameFile
:
return
workspace
.
CanRenameFilesDuringCodeActions
(
_state
.
SemanticDocument
.
Document
.
Project
);
return
workspace
.
CanRenameFilesDuringCodeActions
(
_state
.
SemanticDocument
.
Document
.
Project
);
case
MoveTypeOperationKind
.
MoveTypeScope
:
return
_state
.
TypeNode
.
Parent
is
TNamespaceDeclarationSyntax
;
}
}
return
true
;
return
true
;
...
...
src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeScopeEditor.cs
0 → 100644
浏览文件 @
a31ac79d
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Diagnostics
;
using
System.Linq
;
using
System.Text
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.CodeActions
;
using
Microsoft.CodeAnalysis.Editing
;
using
Microsoft.CodeAnalysis.Formatting
;
using
Microsoft.CodeAnalysis.LanguageServices
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
namespace
Microsoft.CodeAnalysis.CodeRefactorings.MoveType
{
internal
abstract
partial
class
AbstractMoveTypeService
<
TService
,
TTypeDeclarationSyntax
,
TNamespaceDeclarationSyntax
,
TMemberDeclarationSyntax
,
TCompilationUnitSyntax
>
{
/// <summary>
/// Editor that takes a type in a scope and creates a scope beside it. For example, if the type is contained within a namespace
/// it will evaluate if the namespace scope needs to be closed and reopened to create a new scope.
/// </summary>
private
class
MoveTypeScopeEditor
:
Editor
{
public
MoveTypeScopeEditor
(
TService
service
,
State
state
,
string
fileName
,
CancellationToken
cancellationToken
)
:
base
(
service
,
state
,
fileName
,
cancellationToken
)
{
}
internal
override
async
Task
<
ImmutableArray
<
CodeActionOperation
>>
GetOperationsAsync
()
{
var
node
=
State
.
TypeNode
;
var
documentToEdit
=
State
.
SemanticDocument
.
Document
;
var
parent
=
node
.
Parent
;
if
(
parent
==
null
)
{
return
ImmutableArray
<
CodeActionOperation
>.
Empty
;
}
CodeActionOperation
operationToPerform
=
null
;
switch
(
parent
)
{
case
TNamespaceDeclarationSyntax
namespaceDeclaration
:
operationToPerform
=
await
GetNamespaceScopeOperationAsync
(
namespaceDeclaration
,
node
,
documentToEdit
,
CancellationToken
.
None
).
ConfigureAwait
(
false
);
break
;
case
TTypeDeclarationSyntax
_
:
Debug
.
Assert
(
false
,
"Moving a nested type is not supported"
);
break
;
}
if
(
operationToPerform
==
null
)
{
return
ImmutableArray
<
CodeActionOperation
>.
Empty
;
}
return
ImmutableArray
.
Create
(
operationToPerform
);
}
private
async
Task
<
CodeActionOperation
>
GetNamespaceScopeOperationAsync
(
TNamespaceDeclarationSyntax
namespaceDeclaration
,
TTypeDeclarationSyntax
typeToMove
,
Document
documentToEdit
,
CancellationToken
cancellationToken
)
{
var
syntaxFactsService
=
documentToEdit
.
GetLanguageService
<
ISyntaxFactsService
>();
var
childNodes
=
syntaxFactsService
.
GetMembersOfNamespaceDeclaration
(
namespaceDeclaration
);
if
(
childNodes
.
Count
<=
1
)
{
return
null
;
}
var
editor
=
await
DocumentEditor
.
CreateAsync
(
documentToEdit
,
cancellationToken
).
ConfigureAwait
(
false
);
var
syntaxGenerator
=
editor
.
Generator
;
var
index
=
childNodes
.
IndexOf
(
typeToMove
);
var
itemsBefore
=
index
>
0
?
childNodes
.
Take
(
index
)
:
Enumerable
.
Empty
<
SyntaxNode
>();
var
itemsAfter
=
index
<
childNodes
.
Count
-
1
?
childNodes
.
Skip
(
index
+
1
)
:
Enumerable
.
Empty
<
SyntaxNode
>();
var
name
=
syntaxFactsService
.
GetDisplayName
(
namespaceDeclaration
,
DisplayNameOptions
.
IncludeNamespaces
);
var
newNamespaceDeclaration
=
syntaxGenerator
.
NamespaceDeclaration
(
name
,
WithElasticTrivia
(
typeToMove
));
editor
.
RemoveNode
(
typeToMove
,
SyntaxRemoveOptions
.
KeepNoTrivia
);
if
(
itemsBefore
.
Any
()
&&
itemsAfter
.
Any
())
{
var
itemsAfterNamespaceDeclaration
=
syntaxGenerator
.
NamespaceDeclaration
(
name
,
WithElasticTrivia
(
itemsAfter
));
foreach
(
var
nodeToRemove
in
itemsAfter
)
{
editor
.
RemoveNode
(
nodeToRemove
,
SyntaxRemoveOptions
.
KeepNoTrivia
);
}
editor
.
InsertAfter
(
namespaceDeclaration
,
new
[]
{
newNamespaceDeclaration
,
itemsAfterNamespaceDeclaration
});
}
else
if
(
itemsBefore
.
Any
())
{
editor
.
InsertAfter
(
namespaceDeclaration
,
newNamespaceDeclaration
);
var
nodeToCleanup
=
itemsBefore
.
Last
();
editor
.
ReplaceNode
(
nodeToCleanup
,
WithElasticTrivia
(
nodeToCleanup
,
leading
:
false
));
}
else
if
(
itemsAfter
.
Any
())
{
editor
.
InsertBefore
(
namespaceDeclaration
,
newNamespaceDeclaration
);
var
nodeToCleanup
=
itemsAfter
.
First
();
editor
.
ReplaceNode
(
nodeToCleanup
,
WithElasticTrivia
(
nodeToCleanup
,
trailing
:
false
));
}
else
{
throw
new
Exception
(
"WTF Happened"
);
}
return
new
ApplyChangesOperation
(
editor
.
GetChangedDocument
().
Project
.
Solution
);
}
private
SyntaxNode
WithElasticTrivia
(
SyntaxNode
syntaxNode
,
bool
leading
=
true
,
bool
trailing
=
true
)
{
if
(
leading
&&
syntaxNode
.
HasLeadingTrivia
)
{
syntaxNode
=
syntaxNode
.
WithLeadingTrivia
(
syntaxNode
.
GetLeadingTrivia
().
Select
(
AsElasticTrivia
));
}
if
(
trailing
&&
syntaxNode
.
HasTrailingTrivia
)
{
syntaxNode
=
syntaxNode
.
WithTrailingTrivia
(
syntaxNode
.
GetTrailingTrivia
().
Select
(
AsElasticTrivia
));
}
return
syntaxNode
.
WithAdditionalAnnotations
(
Formatter
.
Annotation
);
}
private
IEnumerable
<
SyntaxNode
>
WithElasticTrivia
(
IEnumerable
<
SyntaxNode
>
syntaxNodes
)
{
if
(
syntaxNodes
.
Any
())
{
var
firstNode
=
syntaxNodes
.
FirstOrDefault
();
var
lastNode
=
syntaxNodes
.
LastOrDefault
();
if
(
firstNode
==
lastNode
)
{
yield
return
WithElasticTrivia
(
firstNode
);
}
else
{
yield
return
WithElasticTrivia
(
firstNode
,
trailing
:
false
);
foreach
(
var
node
in
syntaxNodes
.
Skip
(
1
))
{
if
(
node
!=
lastNode
)
{
yield
return
node
;
}
else
{
yield
return
WithElasticTrivia
(
node
,
leading
:
false
);
}
}
}
}
}
private
SyntaxTrivia
AsElasticTrivia
(
SyntaxTrivia
trivia
)
{
return
trivia
.
WithAdditionalAnnotations
(
SyntaxAnnotation
.
ElasticAnnotation
);
}
}
}
}
src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.cs
浏览文件 @
a31ac79d
...
@@ -24,40 +24,70 @@ internal abstract partial class AbstractMoveTypeService<TService, TTypeDeclarati
...
@@ -24,40 +24,70 @@ internal abstract partial class AbstractMoveTypeService<TService, TTypeDeclarati
where
TMemberDeclarationSyntax
:
SyntaxNode
where
TMemberDeclarationSyntax
:
SyntaxNode
where
TCompilationUnitSyntax
:
SyntaxNode
where
TCompilationUnitSyntax
:
SyntaxNode
{
{
private
enum
OperationKind
{
MoveType
,
RenameType
,
RenameFile
}
public
async
Task
<
ImmutableArray
<
CodeAction
>>
GetRefactoringAsync
(
public
async
Task
<
ImmutableArray
<
CodeAction
>>
GetRefactoringAsync
(
Document
document
,
TextSpan
textSpan
,
CancellationToken
cancellationToken
)
Document
document
,
TextSpan
textSpan
,
CancellationToken
cancellationToken
)
{
{
if
(
textSpan
.
IsEmpty
)
var
state
=
await
CreateStateAsync
(
document
,
textSpan
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
state
==
null
)
{
{
var
root
=
await
document
.
GetSyntaxRootAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
return
ImmutableArray
<
CodeAction
>.
Empty
;
var
nodeToAnalyze
=
root
.
FindToken
(
textSpan
.
Start
).
GetAncestor
<
TTypeDeclarationSyntax
>();
}
if
(
nodeToAnalyze
!=
null
)
var
actions
=
CreateActions
(
state
,
cancellationToken
);
Debug
.
Assert
(
actions
.
Count
()
!=
0
,
"No code actions found for MoveType Refactoring"
);
return
actions
;
}
public
async
Task
<
ImmutableArray
<
CodeAction
>>
GetRefactoringAsync
(
Document
document
,
TextSpan
textSpan
,
MoveTypeOperationKind
operationKind
,
CancellationToken
cancellationToken
)
{
{
var
syntaxFacts
=
document
.
GetLanguageService
<
ISyntaxFactsService
>();
var
state
=
await
CreateStateAsync
(
document
,
textSpan
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
syntaxFacts
.
IsOnTypeHeader
(
root
,
textSpan
.
Start
))
if
(
state
==
null
)
{
{
var
semanticDocument
=
await
SemanticDocument
.
CreateAsync
(
document
,
cancellationToken
).
ConfigureAwait
(
false
);
return
ImmutableArray
<
CodeAction
>.
Empty
;
var
state
=
State
.
Generate
(
}
semanticDocument
,
textSpan
,
nodeToAnalyze
,
cancellationToken
);
if
(
state
!=
null
)
ImmutableArray
<
CodeAction
>
actions
;
switch
(
operationKind
)
{
{
var
actions
=
CreateActions
(
state
,
cancellationToken
);
case
MoveTypeOperationKind
.
MoveTypeScope
:
actions
=
ImmutableArray
.
Create
(
GetCodeAction
(
state
,
state
.
SemanticDocument
.
Document
.
Name
,
operationKind
:
operationKind
));
break
;
default
:
actions
=
CreateActions
(
state
,
cancellationToken
);
break
;
}
Debug
.
Assert
(
actions
.
Count
()
!=
0
,
"No code actions found for MoveType Refactoring"
);
Debug
.
Assert
(
actions
.
Count
()
!=
0
,
"No code actions found for MoveType Refactoring"
);
return
actions
;
return
actions
;
}
}
private
async
Task
<
State
>
CreateStateAsync
(
Document
document
,
TextSpan
textSpan
,
CancellationToken
cancellationToken
)
{
if
(!
textSpan
.
IsEmpty
)
{
return
null
;
}
}
var
root
=
await
document
.
GetSyntaxRootAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
nodeToAnalyze
=
root
.
FindToken
(
textSpan
.
Start
).
GetAncestor
<
TTypeDeclarationSyntax
>();
if
(
nodeToAnalyze
==
null
)
{
return
null
;
}
}
var
syntaxFacts
=
document
.
GetLanguageService
<
ISyntaxFactsService
>();
if
(!
syntaxFacts
.
IsOnTypeHeader
(
root
,
textSpan
.
Start
))
{
return
null
;
}
}
return
ImmutableArray
<
CodeAction
>.
Empty
;
var
semanticDocument
=
await
SemanticDocument
.
CreateAsync
(
document
,
cancellationToken
).
ConfigureAwait
(
false
);
return
State
.
Generate
(
semanticDocument
,
textSpan
,
nodeToAnalyze
,
cancellationToken
);
}
}
private
ImmutableArray
<
CodeAction
>
CreateActions
(
State
state
,
CancellationToken
cancellationToken
)
private
ImmutableArray
<
CodeAction
>
CreateActions
(
State
state
,
CancellationToken
cancellationToken
)
...
@@ -83,7 +113,7 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken
...
@@ -83,7 +113,7 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken
{
{
foreach
(
var
fileName
in
suggestedFileNames
)
foreach
(
var
fileName
in
suggestedFileNames
)
{
{
actions
.
Add
(
GetCodeAction
(
state
,
fileName
,
operationKind
:
OperationKind
.
MoveType
));
actions
.
Add
(
GetCodeAction
(
state
,
fileName
,
operationKind
:
MoveType
OperationKind
.
MoveType
));
}
}
}
}
...
@@ -93,7 +123,7 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken
...
@@ -93,7 +123,7 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken
{
{
foreach
(
var
fileName
in
suggestedFileNames
)
foreach
(
var
fileName
in
suggestedFileNames
)
{
{
actions
.
Add
(
GetCodeAction
(
state
,
fileName
,
operationKind
:
OperationKind
.
RenameFile
));
actions
.
Add
(
GetCodeAction
(
state
,
fileName
,
operationKind
:
MoveType
OperationKind
.
RenameFile
));
}
}
// only if the document name can be legal identifier in the language,
// only if the document name can be legal identifier in the language,
...
@@ -102,14 +132,14 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken
...
@@ -102,14 +132,14 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken
{
{
actions
.
Add
(
GetCodeAction
(
actions
.
Add
(
GetCodeAction
(
state
,
fileName
:
state
.
DocumentNameWithoutExtension
,
state
,
fileName
:
state
.
DocumentNameWithoutExtension
,
operationKind
:
OperationKind
.
RenameType
));
operationKind
:
MoveType
OperationKind
.
RenameType
));
}
}
}
}
return
actions
.
ToImmutableArray
();
return
actions
.
ToImmutableArray
();
}
}
private
CodeAction
GetCodeAction
(
State
state
,
string
fileName
,
OperationKind
operationKind
)
=>
private
CodeAction
GetCodeAction
(
State
state
,
string
fileName
,
MoveType
OperationKind
operationKind
)
=>
new
MoveTypeCodeAction
((
TService
)
this
,
state
,
operationKind
,
fileName
);
new
MoveTypeCodeAction
((
TService
)
this
,
state
,
operationKind
,
fileName
);
private
bool
IsNestedType
(
TTypeDeclarationSyntax
typeNode
)
=>
private
bool
IsNestedType
(
TTypeDeclarationSyntax
typeNode
)
=>
...
...
src/Features/Core/Portable/CodeRefactorings/MoveType/IMoveTypeService.cs
浏览文件 @
a31ac79d
...
@@ -12,5 +12,6 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType
...
@@ -12,5 +12,6 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType
internal
interface
IMoveTypeService
:
ILanguageService
internal
interface
IMoveTypeService
:
ILanguageService
{
{
Task
<
ImmutableArray
<
CodeAction
>>
GetRefactoringAsync
(
Document
document
,
TextSpan
textSpan
,
CancellationToken
cancellationToken
);
Task
<
ImmutableArray
<
CodeAction
>>
GetRefactoringAsync
(
Document
document
,
TextSpan
textSpan
,
CancellationToken
cancellationToken
);
Task
<
ImmutableArray
<
CodeAction
>>
GetRefactoringAsync
(
Document
document
,
TextSpan
textSpan
,
MoveTypeOperationKind
operationKind
,
CancellationToken
cancellationToken
);
}
}
}
}
src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeOperationKind.cs
0 → 100644
浏览文件 @
a31ac79d
using
System
;
using
System.Collections.Generic
;
using
System.Text
;
namespace
Microsoft.CodeAnalysis.CodeRefactorings.MoveType
{
internal
enum
MoveTypeOperationKind
{
MoveType
,
MoveTypeScope
,
RenameType
,
RenameFile
}
}
src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
浏览文件 @
a31ac79d
...
@@ -1049,6 +1049,9 @@ public List<SyntaxNode> GetMethodLevelMembers(SyntaxNode root)
...
@@ -1049,6 +1049,9 @@ public List<SyntaxNode> GetMethodLevelMembers(SyntaxNode root)
public
SyntaxList
<
SyntaxNode
>
GetMembersOfTypeDeclaration
(
SyntaxNode
typeDeclaration
)
public
SyntaxList
<
SyntaxNode
>
GetMembersOfTypeDeclaration
(
SyntaxNode
typeDeclaration
)
=>
((
TypeDeclarationSyntax
)
typeDeclaration
).
Members
;
=>
((
TypeDeclarationSyntax
)
typeDeclaration
).
Members
;
public
SyntaxList
<
SyntaxNode
>
GetMembersOfNamespaceDeclaration
(
SyntaxNode
namespaceDeclaration
)
=>
((
NamespaceDeclarationSyntax
)
namespaceDeclaration
).
Members
;
private
void
AppendMethodLevelMembers
(
SyntaxNode
node
,
List
<
SyntaxNode
>
list
)
private
void
AppendMethodLevelMembers
(
SyntaxNode
node
,
List
<
SyntaxNode
>
list
)
{
{
foreach
(
var
member
in
node
.
GetMembers
())
foreach
(
var
member
in
node
.
GetMembers
())
...
...
src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs
浏览文件 @
a31ac79d
...
@@ -369,6 +369,7 @@ internal interface ISyntaxFactsService : ILanguageService
...
@@ -369,6 +369,7 @@ internal interface ISyntaxFactsService : ILanguageService
SyntaxToken
ToIdentifierToken
(
string
name
);
SyntaxToken
ToIdentifierToken
(
string
name
);
List
<
SyntaxNode
>
GetMethodLevelMembers
(
SyntaxNode
root
);
List
<
SyntaxNode
>
GetMethodLevelMembers
(
SyntaxNode
root
);
SyntaxList
<
SyntaxNode
>
GetMembersOfTypeDeclaration
(
SyntaxNode
typeDeclaration
);
SyntaxList
<
SyntaxNode
>
GetMembersOfTypeDeclaration
(
SyntaxNode
typeDeclaration
);
SyntaxList
<
SyntaxNode
>
GetMembersOfNamespaceDeclaration
(
SyntaxNode
namespaceDeclaration
);
bool
ContainsInMemberBody
(
SyntaxNode
node
,
TextSpan
span
);
bool
ContainsInMemberBody
(
SyntaxNode
node
,
TextSpan
span
);
int
GetMethodLevelMemberId
(
SyntaxNode
root
,
SyntaxNode
node
);
int
GetMethodLevelMemberId
(
SyntaxNode
root
,
SyntaxNode
node
);
...
...
src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
浏览文件 @
a31ac79d
...
@@ -986,6 +986,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
...
@@ -986,6 +986,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return
DirectCast
(
typeDeclaration
,
TypeBlockSyntax
).
Members
Return
DirectCast
(
typeDeclaration
,
TypeBlockSyntax
).
Members
End
Function
End
Function
Public
Function
GetMembersOfNamespaceDeclaration
(
namespaceDeclaration
As
SyntaxNode
)
As
SyntaxList
(
Of
SyntaxNode
)
Implements
ISyntaxFactsService
.
GetMembersOfNamespaceDeclaration
Return
DirectCast
(
namespaceDeclaration
,
NamespaceBlockSyntax
).
Members
End
Function
Public
Function
IsTopLevelNodeWithMembers
(
node
As
SyntaxNode
)
As
Boolean
Implements
ISyntaxFactsService
.
IsTopLevelNodeWithMembers
Public
Function
IsTopLevelNodeWithMembers
(
node
As
SyntaxNode
)
As
Boolean
Implements
ISyntaxFactsService
.
IsTopLevelNodeWithMembers
Return
TypeOf
node
Is
NamespaceBlockSyntax
OrElse
Return
TypeOf
node
Is
NamespaceBlockSyntax
OrElse
TypeOf
node
Is
TypeBlockSyntax
OrElse
TypeOf
node
Is
TypeBlockSyntax
OrElse
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录