Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
e5e9ce4e
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,发现更多精彩内容 >>
未验证
提交
e5e9ce4e
编写于
4月 03, 2020
作者:
C
CyrusNajmabadi
提交者:
GitHub
4月 03, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #43045 from CyrusNajmabadi/renameWorkSimple
Remove callbacks from Rename api.
上级
a0c710f1
84965510
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
143 addition
and
119 deletion
+143
-119
src/EditorFeatures/Core.Wpf/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs
...tractEditorInlineRenameService.InlineRenameLocationSet.cs
+1
-1
src/EditorFeatures/Test2/Rename/RenameEngineResult.vb
src/EditorFeatures/Test2/Rename/RenameEngineResult.vb
+1
-1
src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs
...table/EncapsulateField/AbstractEncapsulateFieldService.cs
+35
-12
src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs
...UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs
+14
-31
src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs
...ortable/Rename/ConflictEngine/ConflictResolver.Session.cs
+54
-29
src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs
...s/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs
+17
-19
src/Workspaces/Core/Portable/Rename/RenameLocations.cs
src/Workspaces/Core/Portable/Rename/RenameLocations.cs
+7
-0
src/Workspaces/Core/Portable/Rename/Renamer.cs
src/Workspaces/Core/Portable/Rename/Renamer.cs
+7
-26
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/LocationExtensions.cs
...Extensions/Compiler/Core/Extensions/LocationExtensions.cs
+7
-0
未找到文件。
src/EditorFeatures/Core.Wpf/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs
浏览文件 @
e5e9ce4e
...
...
@@ -41,7 +41,7 @@ public async Task<IInlineRenameReplacementInfo> GetReplacementsAsync(string repl
{
var
conflicts
=
await
ConflictResolver
.
ResolveConflictsAsync
(
_renameLocationSet
,
_renameLocationSet
.
Symbol
.
Name
,
_renameInfo
.
GetFinalSymbolName
(
replacementText
),
optionSet
,
hasConflict
:
null
,
cancellationToken
:
cancellationToken
).
ConfigureAwait
(
false
);
_renameInfo
.
GetFinalSymbolName
(
replacementText
),
optionSet
,
nonConflictSymbols
:
null
,
cancellationToken
:
cancellationToken
).
ConfigureAwait
(
false
);
return
new
InlineRenameReplacementInfo
(
conflicts
);
}
...
...
src/EditorFeatures/Test2/Rename/RenameEngineResult.vb
浏览文件 @
e5e9ce4e
...
...
@@ -79,7 +79,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename
Dim
locations
=
RenameLocations
.
FindAsync
(
symbolAndProjectId
,
workspace
.
CurrentSolution
,
optionSet
,
CancellationToken
.
None
).
Result
Dim
originalName
=
symbol
.
Name
.
Split
(
"."
c
).
Last
()
Dim
result
=
ConflictResolver
.
ResolveConflictsAsync
(
locations
,
originalName
,
renameTo
,
optionSet
,
hasConflict
:
=
Nothing
,
cancellationToken
:
=
CancellationToken
.
None
).
Result
Dim
result
=
ConflictResolver
.
ResolveConflictsAsync
(
locations
,
originalName
,
renameTo
,
optionSet
,
nonConflictSymbols
:
=
Nothing
,
cancellationToken
:
=
CancellationToken
.
None
).
Result
engineResult
=
New
RenameEngineResult
(
workspace
,
result
,
renameTo
)
engineResult
.
AssertUnlabeledSpansRenamedAndHaveNoConflicts
()
...
...
src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs
浏览文件 @
e5e9ce4e
...
...
@@ -10,6 +10,7 @@
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.CodeGeneration
;
using
Microsoft.CodeAnalysis.Editing
;
using
Microsoft.CodeAnalysis.FindSymbols
;
...
...
@@ -244,27 +245,35 @@ private async Task<Result> EncapsulateFieldAsync(IFieldSymbol field, Document do
if
(
field
.
IsReadOnly
)
{
// Inside the constructor we want to rename references the field to the final field name.
var
constructor
Syntaxes
=
GetConstructorNodes
(
field
.
ContainingType
).
ToSet
(
);
if
(
finalFieldName
!=
field
.
Name
&&
constructor
Syntaxe
s
.
Count
>
0
)
var
constructor
Locations
=
GetConstructorLocations
(
field
.
ContainingType
);
if
(
finalFieldName
!=
field
.
Name
&&
constructor
Location
s
.
Count
>
0
)
{
solution
=
await
Renamer
.
RenameSymbolAsync
(
solution
,
SymbolAndProjectId
.
Create
(
field
,
projectId
),
finalFieldName
,
solution
.
Options
,
location
=>
constructorSyntaxes
.
Any
(
c
=>
c
.
Span
.
IntersectsWith
(
location
.
SourceSpan
)),
cancellationToken
:
cancellationToken
).
ConfigureAwait
(
false
);
var
initialLocations
=
await
Renamer
.
GetRenameLocationsAsync
(
solution
,
SymbolAndProjectId
.
Create
(
field
,
projectId
),
solution
.
Options
,
cancellationToken
).
ConfigureAwait
(
false
);
var
insideLocations
=
initialLocations
.
Filter
(
location
=>
IntersectsWithAny
(
location
,
constructorLocations
));
solution
=
await
Renamer
.
RenameAsync
(
insideLocations
,
finalFieldName
,
cancellationToken
:
cancellationToken
).
ConfigureAwait
(
false
);
document
=
solution
.
GetDocument
(
document
.
Id
);
var
compilation
=
await
document
.
Project
.
GetCompilationAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
field
=
field
.
GetSymbolKey
().
Resolve
(
compilation
,
cancellationToken
:
cancellationToken
).
Symbol
as
IFieldSymbol
;
constructorLocations
=
GetConstructorLocations
(
field
.
ContainingType
);
}
// Outside the constructor we want to rename references to the field to final property name.
return
await
Renamer
.
RenameSymbolAsync
(
solution
,
SymbolAndProjectId
.
Create
(
field
,
projectId
),
generatedPropertyName
,
solution
.
Options
,
location
=>
!
constructorSyntaxes
.
Any
(
c
=>
c
.
Span
.
IntersectsWith
(
location
.
SourceSpan
)),
cancellationToken
:
cancellationToken
).
ConfigureAwait
(
false
);
var
finalLocations
=
await
Renamer
.
GetRenameLocationsAsync
(
solution
,
SymbolAndProjectId
.
Create
(
field
,
projectId
),
solution
.
Options
,
cancellationToken
).
ConfigureAwait
(
false
);
var
outsideLocations
=
finalLocations
.
Filter
(
location
=>
!
IntersectsWithAny
(
location
,
constructorLocations
));
return
await
Renamer
.
RenameAsync
(
outsideLocations
,
generatedPropertyName
,
cancellationToken
:
cancellationToken
).
ConfigureAwait
(
false
);
}
else
{
...
...
@@ -275,6 +284,20 @@ private async Task<Result> EncapsulateFieldAsync(IFieldSymbol field, Document do
}
}
private
bool
IntersectsWithAny
(
Location
location
,
ISet
<
Location
>
constructorLocations
)
{
foreach
(
var
constructor
in
constructorLocations
)
{
if
(
location
.
IntersectsWith
(
constructor
))
return
true
;
}
return
false
;
}
private
ISet
<
Location
>
GetConstructorLocations
(
INamedTypeSymbol
containingType
)
=>
GetConstructorNodes
(
containingType
).
Select
(
n
=>
n
.
GetLocation
()).
ToSet
();
internal
abstract
IEnumerable
<
SyntaxNode
>
GetConstructorNodes
(
INamedTypeSymbol
containingType
);
protected
async
Task
<
Solution
>
AddPropertyAsync
(
Document
document
,
Solution
destinationSolution
,
IFieldSymbol
field
,
IPropertySymbol
property
,
CancellationToken
cancellationToken
)
...
...
src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs
浏览文件 @
e5e9ce4e
...
...
@@ -120,10 +120,20 @@ private async Task<Solution> ProcessResultAsync(CodeFixContext context, Diagnost
// Now, rename all usages of the field to point at the property. Except don't actually
// rename the field itself. We want to be able to find it again post rename.
var
updatedSolution
=
await
Renamer
.
RenameAsync
(
fieldLocations
,
propertySymbol
.
Name
,
location
=>
!
location
.
SourceSpan
.
IntersectsWith
(
declaratorLocation
.
SourceSpan
)
&&
CanEditDocument
(
solution
,
location
.
SourceTree
,
linkedFiles
,
canEdit
),
symbols
=>
HasConflict
(
symbols
,
propertySymbol
,
compilation
,
cancellationToken
),
//
// We're asking the rename API to update a bunch of references to an existing field to the same name as an
// existing property. Rename will often flag this situation as an unresolvable conflict because the new
// name won't bind to the field anymore.
//
// To address this, we let rename know that there is no conflict if the new symbol it resolves to is the
// same as the property we're trying to get the references pointing to.
var
updatedSolution
=
await
Renamer
.
RenameAsync
(
fieldLocations
.
Filter
(
location
=>
!
location
.
IntersectsWith
(
declaratorLocation
)
&&
CanEditDocument
(
solution
,
location
.
SourceTree
,
linkedFiles
,
canEdit
)),
propertySymbol
.
Name
,
nonConflictSymbols
:
ImmutableHashSet
.
Create
<
ISymbol
>(
propertySymbol
),
cancellationToken
).
ConfigureAwait
(
false
);
solution
=
updatedSolution
;
...
...
@@ -324,33 +334,6 @@ private async Task<SyntaxNode> FormatAsync(SyntaxNode newRoot, Document document
return
true
;
}
private
bool
?
HasConflict
(
IEnumerable
<
ISymbol
>
symbols
,
IPropertySymbol
property
,
Compilation
compilation
,
CancellationToken
cancellationToken
)
{
// We're asking the rename API to update a bunch of references to an existing field to
// the same name as an existing property. Rename will often flag this situation as
// an unresolvable conflict because the new name won't bind to the field anymore.
//
// To address this, we let rename know that there is no conflict if the new symbol it
// resolves to is the same as the property we're trying to get the references pointing
// to.
foreach
(
var
symbol
in
symbols
)
{
if
(
symbol
is
IPropertySymbol
otherProperty
)
{
var
mappedProperty
=
otherProperty
.
GetSymbolKey
().
Resolve
(
compilation
,
cancellationToken
:
cancellationToken
).
Symbol
as
IPropertySymbol
;
if
(
property
.
Equals
(
mappedProperty
))
{
// No conflict.
return
false
;
}
}
}
// Just do the default check.
return
null
;
}
private
class
UseAutoPropertyCodeAction
:
CodeAction
.
SolutionChangeAction
{
public
UseAutoPropertyCodeAction
(
string
title
,
Func
<
CancellationToken
,
Task
<
Solution
>>
createChangedSolution
,
CodeActionPriority
priority
)
...
...
src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs
浏览文件 @
e5e9ce4e
...
...
@@ -4,6 +4,7 @@
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Diagnostics
;
using
System.Linq
;
using
System.Threading
;
...
...
@@ -37,7 +38,7 @@ private class Session
private
readonly
string
_originalText
;
private
readonly
string
_replacementText
;
private
readonly
OptionSet
_optionSet
;
private
readonly
Func
<
IEnumerable
<
ISymbol
>,
bool
?>
_hasConflictCallback
;
private
readonly
ImmutableHashSet
<
ISymbol
>
_nonConflictSymbols
;
private
readonly
CancellationToken
_cancellationToken
;
private
readonly
RenameAnnotation
_renamedSymbolDeclarationAnnotation
;
...
...
@@ -58,7 +59,7 @@ private class Session
string
originalText
,
string
replacementText
,
OptionSet
optionSet
,
Func
<
IEnumerable
<
ISymbol
>,
bool
?>
newSymbolsAreValid
,
ImmutableHashSet
<
ISymbol
>
nonConflictSymbols
,
CancellationToken
cancellationToken
)
{
_renameLocationSet
=
renameLocationSet
;
...
...
@@ -66,7 +67,7 @@ private class Session
_originalText
=
originalText
;
_replacementText
=
replacementText
;
_optionSet
=
optionSet
;
_
hasConflictCallback
=
newSymbolsAreValid
;
_
nonConflictSymbols
=
nonConflictSymbols
;
_cancellationToken
=
cancellationToken
;
_renamedSymbolDeclarationAnnotation
=
new
RenameAnnotation
();
...
...
@@ -284,7 +285,7 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
// fixed them because of rename). Also, don't bother checking if a custom
// callback was provided. The caller might be ok with a rename that introduces
// errors.
if
(!
documentIdErrorStateLookup
[
documentId
]
&&
_
hasConflictCallback
==
null
)
if
(!
documentIdErrorStateLookup
[
documentId
]
&&
_
nonConflictSymbols
==
null
)
{
await
conflictResolution
.
NewSolution
.
GetDocument
(
documentId
).
VerifyNoErrorsAsync
(
"Rename introduced errors in error-free code"
,
_cancellationToken
,
ignoreErrorCodes
).
ConfigureAwait
(
false
);
}
...
...
@@ -335,6 +336,11 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
var
reverseMappedLocations
=
new
Dictionary
<
Location
,
Location
>();
// If we were giving any non-conflict-symbols then ensure that we know what those symbols are in
// the current project post after our edits so far.
var
currentProject
=
conflictResolution
.
NewSolution
.
GetProject
(
projectId
);
var
nonConflictSymbols
=
await
GetNonConflictSymbolsAsync
(
currentProject
).
ConfigureAwait
(
false
);
foreach
(
var
documentId
in
documentIdsForConflictResolution
)
{
var
newDocument
=
conflictResolution
.
NewSolution
.
GetDocument
(
documentId
);
...
...
@@ -359,7 +365,7 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
var
conflictAnnotation
=
annotation
;
reverseMappedLocations
[
tokenOrNode
.
GetLocation
()]
=
baseSyntaxTree
.
GetLocation
(
conflictAnnotation
.
OriginalSpan
);
var
originalLocation
=
conflictAnnotation
.
OriginalSpan
;
I
Enumerable
<
ISymbol
>
newReferencedSymbols
=
null
;
I
mmutableArray
<
ISymbol
>
newReferencedSymbols
=
default
;
var
hasConflict
=
_renameAnnotations
.
HasAnnotation
(
tokenOrNode
,
RenameInvalidIdentifierAnnotation
.
Instance
);
if
(!
hasConflict
)
...
...
@@ -374,13 +380,12 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
// the spans would have been modified and so we need to adjust the old position
// to the new position for which we use the renameSpanTracker, which was tracking
// & mapping the old span -> new span during rename
hasConflict
=
_hasConflictCallback
?.
Invoke
(
newReferencedSymbols
)
??
await
CheckForConflictAsync
(
conflictResolution
,
renamedSymbolInNewSolution
,
newDocument
,
conflictAnnotation
,
newReferencedSymbols
).
ConfigureAwait
(
false
);
}
hasConflict
=
!
IsConflictFreeChange
(
newReferencedSymbols
,
nonConflictSymbols
)
&&
await
CheckForConflictAsync
(
conflictResolution
,
renamedSymbolInNewSolution
,
conflictAnnotation
,
newReferencedSymbols
).
ConfigureAwait
(
false
);
if
(!
hasConflict
&&
!
conflictAnnotation
.
IsInvocationExpression
)
{
hasConflict
=
LocalVariableConflictPerLanguage
((
SyntaxToken
)
tokenOrNode
,
newDocument
,
newReferencedSymbols
);
if
(!
hasConflict
&&
!
conflictAnnotation
.
IsInvocationExpression
)
hasConflict
=
LocalVariableConflictPerLanguage
((
SyntaxToken
)
tokenOrNode
,
newDocument
,
newReferencedSymbols
);
}
if
(!
hasConflict
)
...
...
@@ -458,6 +463,33 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
}
}
private
async
Task
<
ImmutableHashSet
<
ISymbol
>>
GetNonConflictSymbolsAsync
(
Project
currentProject
)
{
if
(
_nonConflictSymbols
==
null
)
return
null
;
var
compilation
=
await
currentProject
.
GetCompilationAsync
(
_cancellationToken
).
ConfigureAwait
(
false
);
return
ImmutableHashSet
.
CreateRange
(
_nonConflictSymbols
.
Select
(
s
=>
s
.
GetSymbolKey
().
Resolve
(
compilation
).
GetAnySymbol
()).
WhereNotNull
());
}
private
bool
IsConflictFreeChange
(
ImmutableArray
<
ISymbol
>
symbols
,
ImmutableHashSet
<
ISymbol
>
nonConflictSymbols
)
{
if
(
_nonConflictSymbols
!=
null
)
{
foreach
(
var
symbol
in
symbols
)
{
// Reference not points at a symbol in the conflict-free list. This is a conflict-free change.
if
(
nonConflictSymbols
.
Contains
(
symbol
))
return
true
;
}
}
// Just do the default check.
return
false
;
}
/// <summary>
/// Gets the list of the nodes that were annotated for a conflict check
/// </summary>
...
...
@@ -473,9 +505,8 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
private
async
Task
<
bool
>
CheckForConflictAsync
(
ConflictResolution
conflictResolution
,
ISymbol
renamedSymbolInNewSolution
,
Document
newDocument
,
RenameActionAnnotation
conflictAnnotation
,
I
Enumerable
<
ISymbol
>
newReferencedSymbols
)
I
mmutableArray
<
ISymbol
>
newReferencedSymbols
)
{
try
{
...
...
@@ -512,15 +543,15 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
}
}
}
else
if
(!
conflictAnnotation
.
IsRenameLocation
&&
conflictAnnotation
.
IsOriginalTextLocation
&&
conflictAnnotation
.
RenameDeclarationLocationReferences
.
Length
>
1
&&
newReferencedSymbols
.
Count
()
==
1
)
else
if
(!
conflictAnnotation
.
IsRenameLocation
&&
conflictAnnotation
.
IsOriginalTextLocation
&&
conflictAnnotation
.
RenameDeclarationLocationReferences
.
Length
>
1
&&
newReferencedSymbols
.
Length
==
1
)
{
// an ambiguous situation was resolved through rename in non reference locations
hasConflict
=
false
;
}
else
if
(
newReferencedSymbols
.
Count
()
!=
conflictAnnotation
.
RenameDeclarationLocationReferences
.
Length
)
else
if
(
newReferencedSymbols
.
Length
!=
conflictAnnotation
.
RenameDeclarationLocationReferences
.
Length
)
{
// Don't show conflicts for errors in the old solution that now bind in the new solution.
if
(
newReferencedSymbols
.
Count
()
!=
0
&&
conflictAnnotation
.
RenameDeclarationLocationReferences
.
Length
==
0
)
if
(
newReferencedSymbols
.
Length
!=
0
&&
conflictAnnotation
.
RenameDeclarationLocationReferences
.
Length
==
0
)
{
hasConflict
=
false
;
}
...
...
@@ -611,31 +642,25 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
}
}
private
I
Enumerable
<
ISymbol
>
GetSymbolsInNewSolution
(
Document
newDocument
,
SemanticModel
newDocumentSemanticModel
,
RenameActionAnnotation
conflictAnnotation
,
SyntaxNodeOrToken
tokenOrNode
)
private
I
mmutableArray
<
ISymbol
>
GetSymbolsInNewSolution
(
Document
newDocument
,
SemanticModel
newDocumentSemanticModel
,
RenameActionAnnotation
conflictAnnotation
,
SyntaxNodeOrToken
tokenOrNode
)
{
IEnumerable
<
ISymbol
>
newReferencedSymbols
=
RenameUtilities
.
GetSymbolsTouchingPosition
(
tokenOrNode
.
Span
.
Start
,
newDocumentSemanticModel
,
newDocument
.
Project
.
Solution
.
Workspace
,
_cancellationToken
);
var
newReferencedSymbols
=
RenameUtilities
.
GetSymbolsTouchingPosition
(
tokenOrNode
.
Span
.
Start
,
newDocumentSemanticModel
,
newDocument
.
Project
.
Solution
.
Workspace
,
_cancellationToken
);
if
(
conflictAnnotation
.
IsInvocationExpression
)
{
IEnumerable
<
ISymbol
>
invocationReferencedSymbols
=
null
;
if
(
tokenOrNode
.
IsNode
)
{
invocationReferencedSymbols
=
SymbolsForEnclosingInvocationExpressionWorker
((
SyntaxNode
)
tokenOrNode
,
newDocumentSemanticModel
,
_cancellationToken
);
}
if
(
invocationReferencedSymbols
!=
null
)
{
newReferencedSymbols
=
invocationReferencedSymbols
;
var
invocationReferencedSymbols
=
SymbolsForEnclosingInvocationExpressionWorker
((
SyntaxNode
)
tokenOrNode
,
newDocumentSemanticModel
,
_cancellationToken
);
if
(!
invocationReferencedSymbols
.
IsDefault
)
newReferencedSymbols
=
invocationReferencedSymbols
;
}
}
// if there are more than one symbol, then remove the alias symbols.
// When using (not declaring) an alias, the alias symbol and the target symbol are returned
// by GetSymbolsTouchingPosition
if
(
newReferencedSymbols
.
Skip
(
1
).
Any
())
{
newReferencedSymbols
=
newReferencedSymbols
.
Where
(
a
=>
a
.
Kind
!=
SymbolKind
.
Alias
);
}
if
(
newReferencedSymbols
.
Length
>=
2
)
newReferencedSymbols
=
newReferencedSymbols
.
WhereAsArray
(
a
=>
a
.
Kind
!=
SymbolKind
.
Alias
);
return
newReferencedSymbols
;
}
...
...
src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs
浏览文件 @
e5e9ce4e
...
...
@@ -4,6 +4,7 @@
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Diagnostics
;
using
System.Linq
;
using
System.Text
;
...
...
@@ -36,16 +37,17 @@ internal static partial class ConflictResolver
private
const
string
s_metadataNameSeparators
=
" .,:<`>()\r\n"
;
/// <summary>
/// Performs the renaming of the symbol in the solution, identifies renaming conflicts and automatically resolves them where possible.
/// Performs the renaming of the symbol in the solution, identifies renaming conflicts and automatically
/// resolves them where possible.
/// </summary>
/// <param name="renameLocationSet">The locations to perform the renaming at.</param>
/// <param name="originalText">The original name of the identifier.</param>
/// <param name="replacementText">The new name of the identifier</param>
/// <param name="optionSet">The option for rename</param>
/// <param name="
hasConflict">Called after renaming references. Can be used by callers to
///
indicate if the new symbols that the reference binds to should be considered to be ok or
///
are in conflict. 'true' means they are conflicts. 'false' means they are not conflicts.
///
'null' means that the default conflict check should be used
.</param>
/// <param name="
nonConflictSymbols">Used after renaming references. References that now bind to any of these
///
symbols are not considered to be in conflict. Useful for features that want to rename existing references to
///
point at some existing symbol. Normally this would be a conflict, but this can be used to override that
///
behavior
.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A conflict resolution containing the new solution.</returns>
public
static
Task
<
ConflictResolution
>
ResolveConflictsAsync
(
...
...
@@ -53,7 +55,7 @@ internal static partial class ConflictResolver
string
originalText
,
string
replacementText
,
OptionSet
optionSet
,
Func
<
IEnumerable
<
ISymbol
>,
bool
?>
hasConflict
,
ImmutableHashSet
<
ISymbol
>
nonConflictSymbols
,
CancellationToken
cancellationToken
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
...
...
@@ -66,26 +68,22 @@ internal static partial class ConflictResolver
throw
new
ArgumentException
(
string
.
Format
(
WorkspacesResources
.
Symbol_0_is_not_from_source
,
renameLocationSet
.
Symbol
.
Name
));
}
var
session
=
new
Session
(
renameLocationSet
,
renameSymbolDeclarationLocation
,
originalText
,
replacementText
,
optionSet
,
hasConflict
,
cancellationToken
);
var
session
=
new
Session
(
renameLocationSet
,
renameSymbolDeclarationLocation
,
originalText
,
replacementText
,
optionSet
,
nonConflictSymbols
,
cancellationToken
);
return
session
.
ResolveConflictsAsync
();
}
/// <summary>
/// Used to find the symbols associated with the Invocation Expression surrounding the Token
/// </summary>
private
static
I
Enumerable
<
ISymbol
>
SymbolsForEnclosingInvocationExpressionWorker
(
SyntaxNode
invocationExpression
,
SemanticModel
semanticModel
,
CancellationToken
cancellationToken
)
private
static
I
mmutableArray
<
ISymbol
>
SymbolsForEnclosingInvocationExpressionWorker
(
SyntaxNode
invocationExpression
,
SemanticModel
semanticModel
,
CancellationToken
cancellationToken
)
{
var
symbolInfo
=
semanticModel
.
GetSymbolInfo
(
invocationExpression
,
cancellationToken
);
IEnumerable
<
ISymbol
>
symbols
=
null
;
if
(
symbolInfo
.
Symbol
==
null
)
{
return
null
;
}
else
{
symbols
=
SpecializedCollections
.
SingletonEnumerable
(
symbolInfo
.
Symbol
);
return
symbols
;
}
return
symbolInfo
.
Symbol
==
null
?
default
:
ImmutableArray
.
Create
(
symbolInfo
.
Symbol
);
}
private
static
SyntaxNode
GetExpansionTargetForLocationPerLanguage
(
SyntaxToken
tokenOrNode
,
Document
document
)
...
...
@@ -95,7 +93,7 @@ private static SyntaxNode GetExpansionTargetForLocationPerLanguage(SyntaxToken t
return
complexifiedTarget
;
}
private
static
bool
LocalVariableConflictPerLanguage
(
SyntaxToken
tokenOrNode
,
Document
document
,
I
Enumerable
<
ISymbol
>
newReferencedSymbols
)
private
static
bool
LocalVariableConflictPerLanguage
(
SyntaxToken
tokenOrNode
,
Document
document
,
I
mmutableArray
<
ISymbol
>
newReferencedSymbols
)
{
var
renameRewriterService
=
document
.
GetLanguageService
<
IRenameRewriterLanguageService
>();
var
isConflict
=
renameRewriterService
.
LocalVariableConflict
(
tokenOrNode
,
newReferencedSymbols
);
...
...
src/Workspaces/Core/Portable/Rename/RenameLocations.cs
浏览文件 @
e5e9ce4e
...
...
@@ -218,5 +218,12 @@ internal async Task<RenameLocations> FindWithUpdatedOptionsAsync(OptionSet optio
return
new
SearchResult
(
locations
,
implicitLocations
,
referencedSymbols
);
}
public
RenameLocations
Filter
(
Func
<
Location
,
bool
>
filter
)
=>
new
RenameLocations
(
this
.
Locations
.
Where
(
loc
=>
filter
(
loc
.
Location
)).
ToSet
(),
this
.
SymbolAndProjectId
,
this
.
Solution
,
this
.
ReferencedSymbols
,
this
.
ImplicitLocations
.
Where
(
loc
=>
filter
(
loc
.
Location
)),
this
.
Options
);
}
}
src/Workspaces/Core/Portable/Rename/Renamer.cs
浏览文件 @
e5e9ce4e
...
...
@@ -3,14 +3,12 @@
// See the LICENSE file in the project root for more information.
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Collections.Immutable
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.FindSymbols
;
using
Microsoft.CodeAnalysis.Options
;
using
Microsoft.CodeAnalysis.Rename.ConflictEngine
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.Rename
{
...
...
@@ -28,7 +26,7 @@ public static class Renamer
internal
static
Task
<
Solution
>
RenameSymbolAsync
(
Solution
solution
,
SymbolAndProjectId
symbolAndProjectId
,
string
newName
,
OptionSet
optionSet
,
CancellationToken
cancellationToken
=
default
)
{
return
RenameSymbolAsync
(
solution
,
symbolAndProjectId
,
newName
,
optionSet
,
filter
:
null
,
cancellationToken
:
cancellationToken
);
return
RenameSymbolAsync
(
solution
,
symbolAndProjectId
,
newName
,
optionSet
,
nonConflictSymbols
:
null
,
cancellationToken
);
}
internal
static
Task
<
RenameLocations
>
GetRenameLocationsAsync
(
...
...
@@ -54,29 +52,17 @@ public static class Renamer
internal
static
async
Task
<
Solution
>
RenameAsync
(
RenameLocations
locations
,
string
newName
,
Func
<
Location
,
bool
>
filter
=
null
,
Func
<
IEnumerable
<
ISymbol
>,
bool
?>
hasConflict
=
null
,
ImmutableHashSet
<
ISymbol
>
nonConflictSymbols
=
null
,
CancellationToken
cancellationToken
=
default
)
{
if
(
string
.
IsNullOrEmpty
(
newName
))
{
throw
new
ArgumentException
(
nameof
(
newName
));
}
cancellationToken
.
ThrowIfCancellationRequested
();
var
symbolAndProjectId
=
locations
.
SymbolAndProjectId
;
if
(
filter
!=
null
)
{
locations
=
new
RenameLocations
(
locations
.
Locations
.
Where
(
loc
=>
filter
(
loc
.
Location
)).
ToSet
(),
symbolAndProjectId
,
locations
.
Solution
,
locations
.
ReferencedSymbols
,
locations
.
ImplicitLocations
.
Where
(
loc
=>
filter
(
loc
.
Location
)),
locations
.
Options
);
}
var
conflictResolution
=
await
ConflictResolver
.
ResolveConflictsAsync
(
locations
,
symbolAndProjectId
.
Symbol
.
Name
,
newName
,
locations
.
Options
,
hasConflict
,
cancellationToken
).
ConfigureAwait
(
false
);
locations
,
locations
.
SymbolAndProjectId
.
Symbol
.
Name
,
newName
,
locations
.
Options
,
nonConflictSymbols
,
cancellationToken
).
ConfigureAwait
(
false
);
return
conflictResolution
.
NewSolution
;
}
...
...
@@ -86,25 +72,20 @@ public static class Renamer
SymbolAndProjectId
symbolAndProjectId
,
string
newName
,
OptionSet
options
,
Func
<
Location
,
bool
>
filter
,
Func
<
IEnumerable
<
ISymbol
>,
bool
?>
hasConflict
=
null
,
ImmutableHashSet
<
ISymbol
>
nonConflictSymbols
=
null
,
CancellationToken
cancellationToken
=
default
)
{
if
(
solution
==
null
)
{
throw
new
ArgumentNullException
(
nameof
(
solution
));
}
if
(
symbolAndProjectId
.
Symbol
==
null
)
{
throw
new
ArgumentNullException
(
nameof
(
symbolAndProjectId
));
}
cancellationToken
.
ThrowIfCancellationRequested
();
options
??=
solution
.
Workspace
.
Options
;
var
renameLocations
=
await
GetRenameLocationsAsync
(
solution
,
symbolAndProjectId
,
options
,
cancellationToken
).
ConfigureAwait
(
false
);
return
await
RenameAsync
(
renameLocations
,
newName
,
filter
,
hasConflict
,
cancellationToken
).
ConfigureAwait
(
false
);
return
await
RenameAsync
(
renameLocations
,
newName
,
nonConflictSymbols
,
cancellationToken
).
ConfigureAwait
(
false
);
}
}
}
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/LocationExtensions.cs
浏览文件 @
e5e9ce4e
...
...
@@ -4,6 +4,7 @@
#
nullable
enable
using
System.Diagnostics
;
using
System.Threading
;
using
Roslyn.Utilities
;
...
...
@@ -39,5 +40,11 @@ public static bool IsVisibleSourceLocation(this Location loc)
var
tree
=
loc
.
SourceTree
;
return
!(
tree
==
null
||
tree
.
IsHiddenPosition
(
loc
.
SourceSpan
.
Start
));
}
public
static
bool
IntersectsWith
(
this
Location
loc1
,
Location
loc2
)
{
Debug
.
Assert
(
loc1
.
IsInSource
&&
loc2
.
IsInSource
);
return
loc1
.
SourceTree
==
loc2
.
SourceTree
&&
loc1
.
SourceSpan
.
IntersectsWith
(
loc2
.
SourceSpan
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录