fix(worker): preview_merge_set no longer reports a symbol the same diff re-declares
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
c834f17c78
commit
06fb73c4dd
+50
-8
@@ -744,7 +744,7 @@ public sealed class MergeMcpTools
|
|||||||
// One line of a unified diff, tagged with the file it belongs to ('-'/'+' only; context lines
|
// One line of a unified diff, tagged with the file it belongs to ('-'/'+' only; context lines
|
||||||
// are dropped). File is set from the `diff --git a/<path> b/<path>` header, which (unlike
|
// are dropped). File is set from the `diff --git a/<path> b/<path>` header, which (unlike
|
||||||
// `+++ b/...`) is present and names the real path even for a deleted file (`+++ /dev/null`).
|
// `+++ b/...`) is present and names the real path even for a deleted file (`+++ /dev/null`).
|
||||||
private readonly record struct DiffLine(string? File, char Sign, string Text);
|
internal readonly record struct DiffLine(string? File, char Sign, string Text);
|
||||||
|
|
||||||
private static List<DiffLine> ParseDiffLines(string diff)
|
private static List<DiffLine> ParseDiffLines(string diff)
|
||||||
{
|
{
|
||||||
@@ -783,22 +783,64 @@ public sealed class MergeMcpTools
|
|||||||
@"|[\w<>\[\],.?]+\??\s+(?<name>[A-Za-z_]\w*)\s*(?:\(|\{|=>|;|=))",
|
@"|[\w<>\[\],.?]+\??\s+(?<name>[A-Za-z_]\w*)\s*(?:\(|\{|=>|;|=))",
|
||||||
RegexOptions.Compiled);
|
RegexOptions.Compiled);
|
||||||
|
|
||||||
private static List<RemovedSymbolDto> ExtractRemovedSymbols(List<DiffLine> diffLines)
|
private static bool IsScannedFile(string? file)
|
||||||
|
=> file is not null &&
|
||||||
|
!file.EndsWith(".axaml", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
!file.EndsWith(".json", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
// Names this diff declares on '+' lines, per file. A [ObservableProperty] field `_camelName` /
|
||||||
|
// `camelName` generates `CamelName`, so it counts as declaring that; the attribute may sit on its
|
||||||
|
// own '+' line(s) directly above the field.
|
||||||
|
private static HashSet<(string Name, string File)> ExtractAddedDeclarations(List<DiffLine> diffLines)
|
||||||
{
|
{
|
||||||
|
var added = new HashSet<(string Name, string File)>();
|
||||||
|
var observablePending = false;
|
||||||
|
foreach (var line in diffLines)
|
||||||
|
{
|
||||||
|
if (line.Sign != '+' || !IsScannedFile(line.File)) { observablePending = false; continue; }
|
||||||
|
|
||||||
|
var trimmed = line.Text.Trim();
|
||||||
|
var isObservable = trimmed.Contains("[ObservableProperty", StringComparison.Ordinal);
|
||||||
|
if (trimmed.StartsWith('[') && trimmed.EndsWith(']'))
|
||||||
|
{
|
||||||
|
observablePending |= isObservable;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var match = RemovedDeclarationRegex.Match(line.Text);
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
var name = match.Groups["name"].Value;
|
||||||
|
added.Add((name, line.File!));
|
||||||
|
if (isObservable || observablePending)
|
||||||
|
{
|
||||||
|
var bare = name.TrimStart('_');
|
||||||
|
if (bare.Length > 0)
|
||||||
|
added.Add((char.ToUpperInvariant(bare[0]) + bare[1..], line.File!));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
observablePending = false;
|
||||||
|
}
|
||||||
|
return added;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static List<RemovedSymbolDto> ExtractRemovedSymbols(List<DiffLine> diffLines)
|
||||||
|
{
|
||||||
|
var added = ExtractAddedDeclarations(diffLines);
|
||||||
var seen = new HashSet<(string Name, string File)>();
|
var seen = new HashSet<(string Name, string File)>();
|
||||||
var result = new List<RemovedSymbolDto>();
|
var result = new List<RemovedSymbolDto>();
|
||||||
foreach (var line in diffLines)
|
foreach (var line in diffLines)
|
||||||
{
|
{
|
||||||
if (line.Sign != '-' || line.File is null) continue;
|
if (line.Sign != '-' || !IsScannedFile(line.File)) continue;
|
||||||
if (line.File.EndsWith(".axaml", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
line.File.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var match = RemovedDeclarationRegex.Match(line.Text);
|
var match = RemovedDeclarationRegex.Match(line.Text);
|
||||||
if (!match.Success) continue;
|
if (!match.Success) continue;
|
||||||
|
|
||||||
if (seen.Add((match.Groups["name"].Value, line.File)))
|
var key = (match.Groups["name"].Value, line.File!);
|
||||||
result.Add(new RemovedSymbolDto(match.Groups["name"].Value, line.File));
|
if (added.Contains(key)) continue;
|
||||||
|
|
||||||
|
if (seen.Add(key))
|
||||||
|
result.Add(new RemovedSymbolDto(key.Item1, key.Item2));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1359,6 +1359,47 @@ public sealed class MergeMcpToolsTests : IDisposable
|
|||||||
Assert.Equal("Bar.cs", warning.ReferencedInFile);
|
Assert.Equal("Bar.cs", warning.ReferencedInFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<MergeMcpTools.DiffLine> Diff(string file, params string[] lines)
|
||||||
|
=> lines.Select(l => new MergeMcpTools.DiffLine(file, l[0], l[1..])).ToList();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExtractRemovedSymbols_AutoPropertyBecomesObservableField_NotReported()
|
||||||
|
{
|
||||||
|
var onOwnLine = Diff("Vm.cs",
|
||||||
|
"- public bool IsListHandler { get; set; }",
|
||||||
|
"+ [ObservableProperty]",
|
||||||
|
"+ private bool _isListHandler;");
|
||||||
|
var inline = Diff("Vm.cs",
|
||||||
|
"- public bool IsListHandler { get; set; }",
|
||||||
|
"+ [ObservableProperty] private bool isListHandler;");
|
||||||
|
|
||||||
|
Assert.Empty(MergeMcpTools.ExtractRemovedSymbols(onOwnLine));
|
||||||
|
Assert.Empty(MergeMcpTools.ExtractRemovedSymbols(inline));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExtractRemovedSymbols_ChangedMethodSignatureInSameFile_NotReported()
|
||||||
|
{
|
||||||
|
var diff = Diff("Foo.cs",
|
||||||
|
"- public void Run(int a)",
|
||||||
|
"+ public void Run(int a, string b)");
|
||||||
|
|
||||||
|
Assert.Empty(MergeMcpTools.ExtractRemovedSymbols(diff));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExtractRemovedSymbols_RealRemovalOrCrossFileMove_StillReported()
|
||||||
|
{
|
||||||
|
var diff = Diff("Foo.cs", "- private void Gone()", "- public void Moved()")
|
||||||
|
.Concat(Diff("Other.cs", "+ public void Moved()")).ToList();
|
||||||
|
|
||||||
|
var removed = MergeMcpTools.ExtractRemovedSymbols(diff);
|
||||||
|
|
||||||
|
Assert.Equal(2, removed.Count);
|
||||||
|
Assert.Contains(removed, s => s.Name == "Gone" && s.File == "Foo.cs");
|
||||||
|
Assert.Contains(removed, s => s.Name == "Moved" && s.File == "Foo.cs");
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task PreviewMergeSet_TwoTasksAddDifferentJsonKeys_ReportsNoOverlap()
|
public async Task PreviewMergeSet_TwoTasksAddDifferentJsonKeys_ReportsNoOverlap()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user