Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
1a1120cc
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,发现更多精彩内容 >>
未验证
提交
1a1120cc
编写于
3月 11, 2019
作者:
D
dotnet-automerge-bot
提交者:
GitHub
3月 11, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #34023 from dotnet/merges/dev16.0-to-dev16.0-vs-deps
Merge dev16.0 to dev16.0-vs-deps
上级
d57da974
aaa74511
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
303 addition
and
16 deletion
+303
-16
src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/SyncNamespaceTests_ChangeNamespace.cs
...tions/SyncNamespace/SyncNamespaceTests_ChangeNamespace.cs
+232
-0
src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs
...actorings/SyncNamespace/AbstractChangeNamespaceService.cs
+71
-16
未找到文件。
src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/SyncNamespaceTests_ChangeNamespace.cs
浏览文件 @
1a1120cc
...
...
@@ -1842,5 +1842,237 @@ class RefClass
}"
;
await
TestChangeNamespaceAsync
(
code
,
expectedSourceOriginal
,
expectedSourceReference
);
}
[
WorkItem
(
33890
,
"https://github.com/dotnet/roslyn/issues/33890"
)]
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsSyncNamespace
)]
public
async
Task
ChangeNamespace_ExtensionMethodInReducedForm
()
{
var
defaultNamespace
=
"A"
;
var
documentPath1
=
CreateDocumentFilePath
(
new
[]
{
"B"
,
"C"
},
"File1.cs"
);
var
documentPath2
=
CreateDocumentFilePath
(
Array
.
Empty
<
string
>(),
"File2.cs"
);
var
code
=
$@"
<Workspace>
<Project Language=""C#"" AssemblyName=""Assembly1"" FilePath=""
{
ProjectFilePath
}
"" RootNamespace=""
{
defaultNamespace
}
"" CommonReferences=""true"">
<Document Folders=""
{
documentPath1
.
folder
}
"" FilePath=""
{
documentPath1
.
filePath
}
"">
namespace [||]
{
defaultNamespace
}
{{
public
static
class
Extensions
{{
public
static
bool
Foo
(
this
Class1
c1
)
=>
true
;
}}
}}
</Document>
<Document Folders=""
{
documentPath2
.
folder
}
"" FilePath=""
{
documentPath2
.
filePath
}
"">
namespace
{
defaultNamespace
}
{{
using
System
;
public
class
Class1
{{
public
bool
Bar
(
Class1
c1
)
=>
c1
.
Foo
();
}}
}}
</Document>
</Project>
</Workspace>"
;
var
expectedSourceOriginal
=
$@"namespace A.B.C
{{
public
static
class
Extensions
{{
public
static
bool
Foo
(
this
Class1
c1
)
=>
true
;
}}
}}
"
;
var
expectedSourceReference
=
$@"
namespace
{
defaultNamespace
}
{{
using
System
;
using
A.B.C
;
public
class
Class1
{{
public
bool
Bar
(
Class1
c1
)
=>
c1
.
Foo
();
}}
}}
"
;
await
TestChangeNamespaceAsync
(
code
,
expectedSourceOriginal
,
expectedSourceReference
);
}
[
WorkItem
(
33890
,
"https://github.com/dotnet/roslyn/issues/33890"
)]
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsSyncNamespace
)]
public
async
Task
ChangeNamespace_ExternsionMethodInRegularForm
()
{
var
defaultNamespace
=
"A"
;
var
documentPath1
=
CreateDocumentFilePath
(
new
[]
{
"B"
,
"C"
},
"File1.cs"
);
var
documentPath2
=
CreateDocumentFilePath
(
Array
.
Empty
<
string
>(),
"File2.cs"
);
var
code
=
$@"
<Workspace>
<Project Language=""C#"" AssemblyName=""Assembly1"" FilePath=""
{
ProjectFilePath
}
"" RootNamespace=""
{
defaultNamespace
}
"" CommonReferences=""true"">
<Document Folders=""
{
documentPath1
.
folder
}
"" FilePath=""
{
documentPath1
.
filePath
}
"">
namespace [||]A
{{
public
static
class
Extensions
{{
public
static
bool
Foo
(
this
Class1
c1
)
=>
true
;
}}
}}
</Document>
<Document Folders=""
{
documentPath2
.
folder
}
"" FilePath=""
{
documentPath2
.
filePath
}
"">
using System;
namespace A
{{
public
class
Class1
{{
public
bool
Bar
(
Class1
c1
)
=>
Extensions
.
Foo
(
c1
);
}}
}}
</Document>
</Project>
</Workspace>"
;
var
expectedSourceOriginal
=
$@"namespace A.B.C
{{
public
static
class
Extensions
{{
public
static
bool
Foo
(
this
Class1
c1
)
=>
true
;
}}
}}
"
;
var
expectedSourceReference
=
$@"
using System;
using A.B.C;
namespace A
{{
public
class
Class1
{{
public
bool
Bar
(
Class1
c1
)
=>
Extensions
.
Foo
(
c1
);
}}
}}
"
;
await
TestChangeNamespaceAsync
(
code
,
expectedSourceOriginal
,
expectedSourceReference
);
}
[
WorkItem
(
33890
,
"https://github.com/dotnet/roslyn/issues/33890"
)]
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsSyncNamespace
)]
public
async
Task
ChangeNamespace_ContainsBothTypeAndExternsionMethod
()
{
var
defaultNamespace
=
"A"
;
var
documentPath1
=
CreateDocumentFilePath
(
new
[]
{
"B"
,
"C"
},
"File1.cs"
);
var
documentPath2
=
CreateDocumentFilePath
(
Array
.
Empty
<
string
>(),
"File2.cs"
);
var
code
=
$@"
<Workspace>
<Project Language=""C#"" AssemblyName=""Assembly1"" FilePath=""
{
ProjectFilePath
}
"" RootNamespace=""
{
defaultNamespace
}
"" CommonReferences=""true"">
<Document Folders=""
{
documentPath1
.
folder
}
"" FilePath=""
{
documentPath1
.
filePath
}
"">
namespace [||]A
{{
public
static
class
Extensions
{{
public
static
bool
Foo
(
this
Class1
c1
)
=>
true
;
}}
public
class
Class2
{{
}}
}}
</Document>
<Document Folders=""
{
documentPath2
.
folder
}
"" FilePath=""
{
documentPath2
.
filePath
}
"">
using System;
namespace A
{{
public
class
Class1
{{
public
bool
Bar
(
Class1
c1
,
Class2
c2
)
=>
c2
==
null
?
c1
.
Foo
()
:
true
;
}}
}}
</Document>
</Project>
</Workspace>"
;
var
expectedSourceOriginal
=
@"namespace A.B.C
{
public static class Extensions
{
public static bool Foo(this Class1 c1) => true;
}
public class Class2
{ }
}"
;
var
expectedSourceReference
=
@"
using System;
using A.B.C;
namespace A
{
public class Class1
{
public bool Bar(Class1 c1, Class2 c2) => c2 == null ? c1.Foo() : true;
}
}"
;
await
TestChangeNamespaceAsync
(
code
,
expectedSourceOriginal
,
expectedSourceReference
);
}
[
WorkItem
(
33890
,
"https://github.com/dotnet/roslyn/issues/33890"
)]
[
WpfFact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
CodeActionsSyncNamespace
)]
public
async
Task
ChangeNamespace_WithExtensionMethodReferencesInVBDocument
()
{
var
defaultNamespace
=
"A.B.C"
;
var
declaredNamespace
=
"A.B.C.D"
;
var
documentPath1
=
CreateDocumentFilePath
(
Array
.
Empty
<
string
>(),
"File1.cs"
);
var
code
=
$@"
<Workspace>
<Project Language=""C#"" AssemblyName=""Assembly1"" FilePath=""
{
ProjectFilePath
}
"" RootNamespace=""
{
defaultNamespace
}
"" CommonReferences=""true"">
<Document Folders=""
{
documentPath1
.
folder
}
"" FilePath=""
{
documentPath1
.
filePath
}
"">
using System;
namespace [||]
{
declaredNamespace
}
{{
public
static
class
Extensions
{{
public
static
bool
Foo
(
this
String
s
)
=>
true
;
}}
}}
</Document>
</Project>
<Project Language=""Visual Basic"" AssemblyName=""Assembly2"" CommonReferences=""true"">
<Document>
Imports
{
declaredNamespace
}
Public Class VBClass
Public Function Foo(s As string) As Boolean
Return s.Foo()
End Function
End Class</Document>
</Project>
</Workspace>"
;
var
expectedSourceOriginal
=
$@"
using System;
namespace
{
defaultNamespace
}
{{
public
static
class
Extensions
{{
public
static
bool
Foo
(
this
string
s
)
=>
true
;
}}
}}
"
;
var
expectedSourceReference
=
$@"
Imports
{
defaultNamespace
}
Public Class VBClass
Public Function Foo(s As string) As Boolean
Return s.Foo()
End Function
End Class"
;
await
TestChangeNamespaceAsync
(
code
,
expectedSourceOriginal
,
expectedSourceReference
);
}
}
}
src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs
浏览文件 @
1a1120cc
...
...
@@ -383,8 +383,8 @@ private static SyntaxNode CreateImport(SyntaxGenerator syntaxGenerator, string n
// Separating references to declaredSymbols into two groups based on wheter it's located in the same
// document as the namespace declaration. This is because code change required for them are different.
var
refLocationsInCurrentDocument
=
new
List
<
ReferenceLocation
>();
var
refLocationsInOtherDocuments
=
new
List
<
ReferenceLocation
>();
var
refLocationsInCurrentDocument
=
new
List
<
LocationForAffectedSymbol
>();
var
refLocationsInOtherDocuments
=
new
List
<
LocationForAffectedSymbol
>();
var
refLocations
=
await
Task
.
WhenAll
(
declaredSymbols
.
Select
(
declaredSymbol
...
...
@@ -434,13 +434,65 @@ private static async Task<Solution> MergeDocumentChangesAsync(Solution originalS
return
originalSolution
;
}
private
static
async
Task
<
ImmutableArray
<
ReferenceLocation
>>
FindReferenceLocationsForSymbol
(
private
readonly
struct
LocationForAffectedSymbol
{
public
LocationForAffectedSymbol
(
ReferenceLocation
location
,
bool
isReferenceToExtensionMethod
)
{
ReferenceLocation
=
location
;
IsReferenceToExtensionMethod
=
isReferenceToExtensionMethod
;
}
public
ReferenceLocation
ReferenceLocation
{
get
;
}
public
bool
IsReferenceToExtensionMethod
{
get
;
}
public
Document
Document
=>
ReferenceLocation
.
Document
;
}
private
static
async
Task
<
ImmutableArray
<
LocationForAffectedSymbol
>>
FindReferenceLocationsForSymbol
(
Document
document
,
ISymbol
symbol
,
CancellationToken
cancellationToken
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
var
builder
=
ArrayBuilder
<
LocationForAffectedSymbol
>.
GetInstance
();
try
{
var
referencedSymbols
=
await
FindReferencesAsync
(
symbol
,
document
,
cancellationToken
).
ConfigureAwait
(
false
);
builder
.
AddRange
(
referencedSymbols
.
Where
(
refSymbol
=>
refSymbol
.
Definition
.
Equals
(
symbol
))
.
SelectMany
(
refSymbol
=>
refSymbol
.
Locations
)
.
Select
(
location
=>
new
LocationForAffectedSymbol
(
location
,
isReferenceToExtensionMethod
:
false
)));
// So far we only have references to types declared in affected namespace. We also need to
// handle invocation of extension methods (in reduced form) that are declared in those types.
// Therefore additional calls to find references are needed for those extension methods.
// This will returns all the references, not just in the reduced form. But we will
// not further distinguish the usage. In the worst case, those references are redundant because
// they are already covered by the type references found above.
if
(
symbol
is
INamedTypeSymbol
typeSymbol
&&
typeSymbol
.
MightContainExtensionMethods
)
{
foreach
(
var
methodSymbol
in
typeSymbol
.
GetMembers
().
OfType
<
IMethodSymbol
>())
{
if
(
methodSymbol
.
IsExtensionMethod
)
{
var
referencedMethodSymbols
=
await
FindReferencesAsync
(
methodSymbol
,
document
,
cancellationToken
).
ConfigureAwait
(
false
);
builder
.
AddRange
(
referencedMethodSymbols
.
SelectMany
(
refSymbol
=>
refSymbol
.
Locations
)
.
Select
(
location
=>
new
LocationForAffectedSymbol
(
location
,
isReferenceToExtensionMethod
:
true
)));
}
}
}
var
progress
=
new
StreamingProgressCollector
(
StreamingFindReferencesProgress
.
Instance
);
return
builder
.
ToImmutable
();
}
finally
{
builder
.
Free
();
}
}
private
static
async
Task
<
ImmutableArray
<
ReferencedSymbol
>>
FindReferencesAsync
(
ISymbol
symbol
,
Document
document
,
CancellationToken
cancellationToken
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
var
progress
=
new
StreamingProgressCollector
(
StreamingFindReferencesProgress
.
Instance
);
await
SymbolFinder
.
FindReferencesAsync
(
symbolAndProjectId
:
SymbolAndProjectId
.
Create
(
symbol
,
document
.
Project
.
Id
),
solution
:
document
.
Project
.
Solution
,
...
...
@@ -449,14 +501,12 @@ private static async Task<Solution> MergeDocumentChangesAsync(Solution originalS
options
:
FindReferencesSearchOptions
.
Default
,
cancellationToken
:
cancellationToken
).
ConfigureAwait
(
false
);
var
referencedSymbols
=
progress
.
GetReferencedSymbols
();
return
referencedSymbols
.
Where
(
refSymbol
=>
refSymbol
.
Definition
.
Equals
(
symbol
))
.
SelectMany
(
refSymbol
=>
refSymbol
.
Locations
).
ToImmutableArray
();
return
progress
.
GetReferencedSymbols
();
}
private
async
Task
<
Document
>
FixDeclarationDocumentAsync
(
Document
document
,
IReadOnlyList
<
ReferenceLocation
>
refLocations
,
IReadOnlyList
<
LocationForAffectedSymbol
>
refLocations
,
string
oldNamespace
,
string
newNamespace
,
CancellationToken
cancellationToken
)
...
...
@@ -529,7 +579,7 @@ private static async Task<Solution> MergeDocumentChangesAsync(Solution originalS
private
async
Task
<
Document
>
FixReferencingDocumentAsync
(
Document
document
,
IEnumerable
<
ReferenceLocation
>
refLocations
,
IEnumerable
<
LocationForAffectedSymbol
>
refLocations
,
string
newNamespace
,
CancellationToken
cancellationToken
)
{
...
...
@@ -576,7 +626,7 @@ await FixReferencesAsync(document, changeNamespaceService, addImportService, ref
Document
document
,
IChangeNamespaceService
changeNamespaceService
,
IAddImportsService
addImportService
,
IEnumerable
<
ReferenceLocation
>
refLocations
,
IEnumerable
<
LocationForAffectedSymbol
>
refLocations
,
ImmutableArray
<
string
>
newNamespaceParts
,
CancellationToken
cancellationToken
)
{
...
...
@@ -598,7 +648,7 @@ await FixReferencesAsync(document, changeNamespaceService, addImportService, ref
// Ignore references via alias. For simple cases where the alias is defined as the type we are interested,
// it will be handled properly because it is one of the reference to the type symbol. Otherwise, we don't
// attempt to make a potential fix, and user might end up with errors as a result.
if
(
refLoc
.
Alias
!=
null
)
if
(
refLoc
.
ReferenceLocation
.
Alias
!=
null
)
{
continue
;
}
...
...
@@ -614,11 +664,16 @@ await FixReferencesAsync(document, changeNamespaceService, addImportService, ref
// For the reference to Foo where it is used as a base class, the BaseTypeSyntax and the TypeSyntax
// have exact same span.
var
refNode
=
root
.
FindNode
(
refLoc
.
Location
.
SourceSpan
,
findInsideTrivia
:
true
,
getInnermostNodeForTie
:
true
);
if
(
abstractChangeNamespaceService
.
TryGetReplacementReferenceSyntax
(
refNode
,
newNamespaceParts
,
syntaxFacts
,
out
var
oldNode
,
out
var
newNode
))
var
refNode
=
root
.
FindNode
(
refLoc
.
ReferenceLocation
.
Location
.
SourceSpan
,
findInsideTrivia
:
true
,
getInnermostNodeForTie
:
true
);
// For invocation of extension method, we only need to add missing import.
if
(!
refLoc
.
IsReferenceToExtensionMethod
)
{
editor
.
ReplaceNode
(
oldNode
,
newNode
.
WithAdditionalAnnotations
(
Simplifier
.
Annotation
));
if
(
abstractChangeNamespaceService
.
TryGetReplacementReferenceSyntax
(
refNode
,
newNamespaceParts
,
syntaxFacts
,
out
var
oldNode
,
out
var
newNode
))
{
editor
.
ReplaceNode
(
oldNode
,
newNode
.
WithAdditionalAnnotations
(
Simplifier
.
Annotation
));
}
}
// Use a dummy import node to figure out which container the new import will be added to.
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录