未验证 提交 2addfa50 编写于 作者: M msftbot[bot] 提交者: GitHub

Merge pull request #42117 from CyrusNajmabadi/conflictMarkerFixAll

Add 'fix all' support for picking conflict-marker regions.
......@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConflictMarkerResolution
......@@ -448,6 +449,147 @@ static void Main2(string[] args)
}
}
}", index: 2);
}
[WorkItem(21107, "https://github.com/dotnet/roslyn/issues/21107")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)]
public async Task TestFixAll1()
{
await TestInRegularAndScript1Async(
@"
using System;
namespace N
{
{|FixAllInDocument:<<<<<<<|} This is mine!
class Program
{
}
=======
class Program2
{
}
>>>>>>> This is theirs!
<<<<<<< This is mine!
class Program3
{
}
=======
class Program4
{
}
>>>>>>> This is theirs!
}",
@"
using System;
namespace N
{
class Program
{
}
class Program3
{
}
}", index: 0);
}
[WorkItem(21107, "https://github.com/dotnet/roslyn/issues/21107")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)]
public async Task TestFixAll2()
{
await TestInRegularAndScript1Async(
@"
using System;
namespace N
{
{|FixAllInDocument:<<<<<<<|} This is mine!
class Program
{
}
=======
class Program2
{
}
>>>>>>> This is theirs!
<<<<<<< This is mine!
class Program3
{
}
=======
class Program4
{
}
>>>>>>> This is theirs!
}",
@"
using System;
namespace N
{
class Program2
{
}
class Program4
{
}
}", index: 1);
}
[WorkItem(21107, "https://github.com/dotnet/roslyn/issues/21107")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)]
public async Task TestFixAll3()
{
await TestInRegularAndScript1Async(
@"
using System;
namespace N
{
{|FixAllInDocument:<<<<<<<|} This is mine!
class Program
{
}
=======
class Program2
{
}
>>>>>>> This is theirs!
<<<<<<< This is mine!
class Program3
{
}
=======
class Program4
{
}
>>>>>>> This is theirs!
}",
@"
using System;
namespace N
{
class Program
{
}
class Program2
{
}
class Program3
{
}
class Program4
{
}
}", index: 2);
}
}
......
......@@ -126,6 +126,118 @@ namespace N
Console.WriteLine(""Their section"")
end sub
end class
end namespace", index:=2)
End Function
<WorkItem(21107, "https://github.com/dotnet/roslyn/issues/21107")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)>
Public Async Function TestFixAll1() As Task
Await TestInRegularAndScript1Async(
"
imports System
namespace N
{|FixAllInDocument:<<<<<<<|} This is mine!
class Program
end class
=======
class Program2
end class
>>>>>>> This is theirs!
<<<<<<< This is mine!
class Program3
end class
=======
class Program4
end class
>>>>>>> This is theirs!
end namespace",
"
imports System
namespace N
class Program
end class
class Program3
end class
end namespace", index:=0)
End Function
<WorkItem(21107, "https://github.com/dotnet/roslyn/issues/21107")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)>
Public Async Function TestFixAll2() As Task
Await TestInRegularAndScript1Async(
"
imports System
namespace N
{|FixAllInDocument:<<<<<<<|} This is mine!
class Program
end class
=======
class Program2
end class
>>>>>>> This is theirs!
<<<<<<< This is mine!
class Program3
end class
=======
class Program4
end class
>>>>>>> This is theirs!
end namespace",
"
imports System
namespace N
class Program2
end class
class Program4
end class
end namespace", index:=1)
End Function
<WorkItem(21107, "https://github.com/dotnet/roslyn/issues/21107")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsResolveConflictMarker)>
Public Async Function TestFixAll3() As Task
Await TestInRegularAndScript1Async(
"
imports System
namespace N
{|FixAllInDocument:<<<<<<<|} This is mine!
class Program
end class
=======
class Program2
end class
>>>>>>> This is theirs!
<<<<<<< This is mine!
class Program3
end class
=======
class Program4
end class
>>>>>>> This is theirs!
end namespace",
"
imports System
namespace N
class Program
end class
class Program2
end class
class Program3
end class
class Program4
end class
end namespace", index:=2)
End Function
End Class
......
......@@ -6,18 +6,25 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.ConflictMarkerResolution
{
internal abstract class AbstractResolveConflictMarkerCodeFixProvider : CodeFixProvider
internal abstract partial class AbstractResolveConflictMarkerCodeFixProvider : CodeFixProvider
{
private const string TakeTopEquivalenceKey = nameof(TakeTopEquivalenceKey);
private const string TakeBottomEquivalenceKey = nameof(TakeBottomEquivalenceKey);
private const string TakeBothEquivalenceKey = nameof(TakeBothEquivalenceKey);
private static readonly int s_mergeConflictLength = "<<<<<<<".Length;
private readonly ISyntaxKinds _syntaxKinds;
......@@ -29,15 +36,11 @@ internal abstract class AbstractResolveConflictMarkerCodeFixProvider : CodeFixPr
_syntaxKinds = syntaxKinds;
}
public override FixAllProvider? GetFixAllProvider()
{
// Fix All is not currently supported for this code fix
// https://github.com/dotnet/roslyn/issues/34461
return null;
}
public override ImmutableArray<string> FixableDiagnosticIds { get; }
public override FixAllProvider GetFixAllProvider()
=> new ConflictMarkerFixAllProvider(this);
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var cancellationToken = context.CancellationToken;
......@@ -46,17 +49,24 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var startTrivia = root.FindTrivia(context.Span.Start);
if (!IsConflictMarker(text, startTrivia, '<'))
{
return;
}
var conflictTrivia = TryGetConflictTrivia(text, startTrivia);
if (conflictTrivia == null)
return;
var (equalsTrivia, endTrivia) = conflictTrivia.Value;
RegisterCodeFixes(context, startTrivia, equalsTrivia, endTrivia);
}
private (SyntaxTrivia equalsTrivia, SyntaxTrivia endTrivia)? TryGetConflictTrivia(SourceText text, SyntaxTrivia startTrivia)
{
var token = startTrivia.Token;
while (true)
{
var index = GetEqualsConflictMarkerIndex(text, token);
var index = GetEqualsConflictMarkerIndex(text, token, afterPosition: startTrivia.SpanStart);
if (index >= 0)
{
var leadingTrivia = token.LeadingTrivia;
......@@ -74,8 +84,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
_syntaxKinds.DisabledTextTrivia == disabledTrivia.RawKind &&
IsConflictMarker(text, endTrivia, '>'))
{
RegisterCodeFixes(context, startTrivia, equalsTrivia, endTrivia);
return;
return (equalsTrivia, endTrivia);
}
}
......@@ -90,8 +99,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
if (_syntaxKinds.EndOfLineTrivia == endOfLineTrivia.RawKind &&
IsConflictMarker(text, endTrivia, '>'))
{
RegisterCodeFixes(context, startTrivia, equalsTrivia, endTrivia);
return;
return (equalsTrivia, endTrivia);
}
}
}
......@@ -99,7 +107,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
token = token.GetNextToken(includeZeroWidth: true);
if (token.RawKind == 0)
{
return;
return null;
}
}
}
......@@ -125,77 +133,99 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
context.RegisterCodeFix(
new MyCodeAction(takeTopText,
c => TakeTopAsync(document, startPos, equalsPos, endPos, c)),
c => TakeTopAsync(document, startPos, equalsPos, endPos, c),
TakeTopEquivalenceKey),
context.Diagnostics);
context.RegisterCodeFix(
new MyCodeAction(takeBottomText,
c => TakeBottomAsync(document, startPos, equalsPos, endPos, c)),
c => TakeBottomAsync(document, startPos, equalsPos, endPos, c),
TakeBottomEquivalenceKey),
context.Diagnostics);
context.RegisterCodeFix(
new MyCodeAction(FeaturesResources.Take_both,
c => TakeBothAsync(document, startPos, equalsPos, endPos, c)),
c => TakeBothAsync(document, startPos, equalsPos, endPos, c),
TakeBothEquivalenceKey),
context.Diagnostics);
}
private async Task<Document> TakeTopAsync(
private async Task<Document> AddEditsAsync(
Document document, int startPos, int equalsPos, int endPos,
Action<SourceText, ArrayBuilder<TextChange>, int, int, int> addEdits,
CancellationToken cancellationToken)
{
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var bottomEnd = GetEndIncludingLineBreak(text, endPos);
var newText = text.Replace(TextSpan.FromBounds(equalsPos, bottomEnd), "");
using var _ = ArrayBuilder<TextChange>.GetInstance(out var edits);
addEdits(text, edits, startPos, equalsPos, endPos);
var startEnd = GetEndIncludingLineBreak(text, startPos);
var finaltext = newText.Replace(TextSpan.FromBounds(startPos, startEnd), "");
return document.WithText(finaltext);
var finalText = text.WithChanges(edits);
return document.WithText(finalText);
}
private async Task<Document> TakeBottomAsync(
Document document, int startPos, int equalsPos, int endPos,
CancellationToken cancellationToken)
private static void AddTopEdits(
SourceText text, ArrayBuilder<TextChange> edits,
int startPos, int equalsPos, int endPos)
{
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
// Delete the line containing <<<<<<<
var startEnd = GetEndIncludingLineBreak(text, startPos);
edits.Add(new TextChange(TextSpan.FromBounds(startPos, startEnd), ""));
// Remove the chunk of text (inclusive) from ======= through >>>>>>>
var bottomEnd = GetEndIncludingLineBreak(text, endPos);
var newText = text.Replace(TextSpan.FromBounds(endPos, bottomEnd), "");
edits.Add(new TextChange(TextSpan.FromBounds(equalsPos, bottomEnd), ""));
}
private static void AddBottomEdits(
SourceText text, ArrayBuilder<TextChange> edits,
int startPos, int equalsPos, int endPos)
{
// Remove the chunk of text (inclusive) from <<<<<<< through =======
var equalsEnd = GetEndIncludingLineBreak(text, equalsPos);
var finaltext = newText.Replace(TextSpan.FromBounds(startPos, equalsEnd), "");
edits.Add(new TextChange(TextSpan.FromBounds(startPos, equalsEnd), ""));
return document.WithText(finaltext);
// Delete the line containing >>>>>>>
var bottomEnd = GetEndIncludingLineBreak(text, endPos);
edits.Add(new TextChange(TextSpan.FromBounds(endPos, bottomEnd), ""));
}
private async Task<Document> TakeBothAsync(
Document document, int startPos, int equalsPos, int endPos,
CancellationToken cancellationToken)
private static void AddBothEdits(
SourceText text, ArrayBuilder<TextChange> edits,
int startPos, int equalsPos, int endPos)
{
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
// Delete the line containing <<<<<<<
var startEnd = GetEndIncludingLineBreak(text, startPos);
edits.Add(new TextChange(TextSpan.FromBounds(startPos, startEnd), ""));
// Delete the line containing =======
var equalsEnd = GetEndIncludingLineBreak(text, equalsPos);
edits.Add(new TextChange(TextSpan.FromBounds(equalsPos, equalsEnd), ""));
// Delete the line containing >>>>>>>
var bottomEnd = GetEndIncludingLineBreak(text, endPos);
var newText = text.Replace(TextSpan.FromBounds(endPos, bottomEnd), "");
edits.Add(new TextChange(TextSpan.FromBounds(endPos, bottomEnd), ""));
}
var equalsEnd = GetEndIncludingLineBreak(text, equalsPos);
newText = newText.Replace(TextSpan.FromBounds(equalsPos, equalsEnd), "");
private Task<Document> TakeTopAsync(Document document, int startPos, int equalsPos, int endPos, CancellationToken cancellationToken)
=> AddEditsAsync(document, startPos, equalsPos, endPos, AddTopEdits, cancellationToken);
var startEnd = GetEndIncludingLineBreak(text, startPos);
var finaltext = newText.Replace(TextSpan.FromBounds(startPos, startEnd), "");
private Task<Document> TakeBottomAsync(Document document, int startPos, int equalsPos, int endPos, CancellationToken cancellationToken)
=> AddEditsAsync(document, startPos, equalsPos, endPos, AddBottomEdits, cancellationToken);
return document.WithText(finaltext);
}
private Task<Document> TakeBothAsync(Document document, int startPos, int equalsPos, int endPos, CancellationToken cancellationToken)
=> AddEditsAsync(document, startPos, equalsPos, endPos, AddBothEdits, cancellationToken);
private int GetEndIncludingLineBreak(SourceText text, int position)
private static int GetEndIncludingLineBreak(SourceText text, int position)
=> text.Lines.GetLineFromPosition(position).SpanIncludingLineBreak.End;
private int GetEqualsConflictMarkerIndex(SourceText text, SyntaxToken token)
private int GetEqualsConflictMarkerIndex(SourceText text, SyntaxToken token, int afterPosition)
{
if (token.HasLeadingTrivia)
{
var i = 0;
foreach (var trivia in token.LeadingTrivia)
{
if (IsConflictMarker(text, trivia, '='))
if (trivia.SpanStart >= afterPosition &&
IsConflictMarker(text, trivia, '='))
{
return i;
}
......@@ -207,11 +237,6 @@ private int GetEqualsConflictMarkerIndex(SourceText text, SyntaxToken token)
return -1;
}
private SyntaxTrivia GetEqualsConflictMarker(SyntaxToken token)
{
throw new NotImplementedException();
}
private bool IsConflictMarker(SourceText text, SyntaxTrivia trivia, char ch)
{
return
......@@ -220,10 +245,75 @@ private bool IsConflictMarker(SourceText text, SyntaxTrivia trivia, char ch)
text[trivia.SpanStart] == ch;
}
private async Task<SyntaxNode> FixAllAsync(
Document document, ImmutableArray<Diagnostic> diagnostics,
string equivalenceKey, CancellationToken cancellationToken)
{
Debug.Assert(
equivalenceKey == TakeTopEquivalenceKey ||
equivalenceKey == TakeBottomEquivalenceKey ||
equivalenceKey == TakeBothEquivalenceKey);
// Process diagnostics in order so we produce edits in the right order.
var orderedDiagnostics = diagnostics.OrderBy(
(d1, d2) => d1.Location.SourceSpan.Start - d2.Location.SourceSpan.Start).ToImmutableArray();
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
// Create a single array of edits to apply. Then walk over all the
// conflict-marker-regions we want to fix and add the edits for each
// region into that array. Then apply the array just once to get the
// final document.
using var _ = ArrayBuilder<TextChange>.GetInstance(out var edits);
foreach (var diagnostic in diagnostics)
{
var startTrivia = root.FindTrivia(diagnostic.Location.SourceSpan.Start);
// We'll be called on all the conflict marker diagnostics (i.e. for <<<<<<< =======
// and >>>>>>>). We only care about the <<<<<<< ones as that controls which chunks
// we'll be processing.
if (!IsConflictMarker(text, startTrivia, '<'))
continue;
var conflictTrivia = TryGetConflictTrivia(text, startTrivia);
if (conflictTrivia == null)
continue;
var startPos = startTrivia.SpanStart;
var equalsPos = conflictTrivia.Value.equalsTrivia.SpanStart;
var endPos = conflictTrivia.Value.endTrivia.SpanStart;
switch (equivalenceKey)
{
case TakeTopEquivalenceKey:
AddTopEdits(text, edits, startPos, equalsPos, endPos);
continue;
case TakeBottomEquivalenceKey:
AddBottomEdits(text, edits, startPos, equalsPos, endPos);
continue;
case TakeBothEquivalenceKey:
AddBothEdits(text, edits, startPos, equalsPos, endPos);
continue;
default:
throw ExceptionUtilities.UnexpectedValue(equivalenceKey);
}
}
var finalText = text.WithChanges(edits);
var finalDoc = document.WithText(finalText);
return await finalDoc.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
}
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument)
: base(title, createChangedDocument)
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument, string equivalenceKey)
: base(title, createChangedDocument, equivalenceKey)
{
}
}
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeStyle;
namespace Microsoft.CodeAnalysis.ConflictMarkerResolution
{
internal abstract partial class AbstractResolveConflictMarkerCodeFixProvider
{
private class ConflictMarkerFixAllProvider : DocumentBasedFixAllProvider
{
private readonly AbstractResolveConflictMarkerCodeFixProvider _codeFixProvider;
public ConflictMarkerFixAllProvider(AbstractResolveConflictMarkerCodeFixProvider codeFixProvider)
=> _codeFixProvider = codeFixProvider;
protected override string CodeActionTitle
=> FeaturesResources.Resolve_conflict_markers;
protected override Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document, ImmutableArray<Diagnostic> diagnostics)
=> _codeFixProvider.FixAllAsync(document, diagnostics, fixAllContext.CodeActionEquivalenceKey, fixAllContext.CancellationToken);
}
}
}
......@@ -1762,4 +1762,7 @@ This version used in: {2}</value>
<data name="Implement_explicitly" xml:space="preserve">
<value>Implement explicitly</value>
</data>
<data name="Resolve_conflict_markers" xml:space="preserve">
<value>Resolve conflict markers</value>
</data>
</root>
\ No newline at end of file
......@@ -547,6 +547,11 @@
<target state="translated">Místo {0} použijte {1}</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">Hrubá úprava</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">"{0}" durch "{1}" ersetzen</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">Grobe Bearbeitung</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">Reemplazar "{0}" por "{1}"</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">Edición superficial</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">Remplacer '{0}' par '{1}'</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">Modification non applicable</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">Sostituisci '{0}' con '{1}'</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">Modifica non applicabile</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">'{0}' を '{1}' に置き換える</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">Rude 編集</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">'{0}'을(를) '{1}'(으)로 바꾸기</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">편집 다시 실행</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">Zamień element „{0}” na element „{1}”</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">Edycja reguły</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">Substituir '{0}' por '{1}'</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">Edição rudimentar</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">Замените '{0}' на '{1}'</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">Грубая редакция</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">'{0}' öğesini '{1}' ile değiştir</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">İşlenmemiş düzenleme</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">将 "{0}" 替换为 "{1}"</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">原始编辑</target>
......
......@@ -547,6 +547,11 @@
<target state="translated">將 ‘{0}’ 取代為 ‘{1}'</target>
<note />
</trans-unit>
<trans-unit id="Resolve_conflict_markers">
<source>Resolve conflict markers</source>
<target state="new">Resolve conflict markers</target>
<note />
</trans-unit>
<trans-unit id="RudeEdit">
<source>Rude edit</source>
<target state="translated">粗略編輯</target>
......
......@@ -8,6 +8,8 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
#pragma warning disable RS0005 // Do not use generic CodeAction.Create to create CodeAction
......@@ -92,28 +94,28 @@ private async Task<Solution> GetSolutionFixesAsync(FixAllContext fixAllContext,
{
var documentDiagnosticsToFix = await FixAllContextHelper.GetDocumentDiagnosticsToFixAsync(fixAllContext, progressTrackerOpt: null).ConfigureAwait(false);
var solution = fixAllContext.Solution;
var newDocuments = new List<Task<SyntaxNode>>(documents.Length);
using var _ = PooledDictionary<DocumentId, Task<SyntaxNode>>.GetInstance(out var documentIdToNewNode);
foreach (var document in documents)
{
// Don't bother examining any documents that aren't in the list of docs that
// actually have diagnostics.
if (!documentDiagnosticsToFix.TryGetValue(document, out var diagnostics))
{
newDocuments.Add(document.GetSyntaxRootAsync(fixAllContext.CancellationToken));
continue;
}
newDocuments.Add(FixAllInDocumentAsync(fixAllContext, document, diagnostics));
documentIdToNewNode.Add(document.Id, FixAllInDocumentAsync(fixAllContext, document, diagnostics));
}
for (var i = 0; i < documents.Length; i++)
// Allow the processing of all the documents to happen concurrently.
await Task.WhenAll(documentIdToNewNode.Values).ConfigureAwait(false);
var solution = fixAllContext.Solution;
foreach (var (docId, syntaxNodeTask) in documentIdToNewNode)
{
var newDocumentRoot = await newDocuments[i].ConfigureAwait(false);
var newDocumentRoot = await syntaxNodeTask.ConfigureAwait(false);
if (newDocumentRoot == null)
{
continue;
}
solution = solution.WithDocumentSyntaxRoot(documents[i].Id, newDocumentRoot);
solution = solution.WithDocumentSyntaxRoot(docId, newDocumentRoot);
}
return solution;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册