Skip to content

Commit 528d642

Browse files
committed
Make the Fix-It JSON writer produce proper JSON
While here, also sort and deduplicate output entries, and stop having the Python script try to The Python script is still messing up the files in some cases, but I haven't tracked it down. Instead, I have a small Swift program that does the same thing more easily.
1 parent 997dfc6 commit 528d642

File tree

3 files changed

+42
-9
lines changed

3 files changed

+42
-9
lines changed

lib/Basic/Edit.cpp

+40-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/Support/raw_ostream.h"
1414
#include "swift/Basic/Edit.h"
1515
#include "swift/Basic/SourceManager.h"
16+
#include <algorithm>
1617

1718
using namespace swift;
1819

@@ -34,8 +35,42 @@ void SourceEdits::addEdit(SourceManager &SM, CharSourceRange Range,
3435

3536
void swift::
3637
writeEditsInJson(const SourceEdits &AllEdits, llvm::raw_ostream &OS) {
37-
OS << "[\n";
38-
for (auto &Edit : AllEdits.getEdits()) {
38+
// Sort the edits so they occur from the last to the first within a given
39+
// source file. That's the order in which applying non-overlapping edits
40+
// will succeed.
41+
std::vector<SourceEdits::Edit> allEdits(AllEdits.getEdits().begin(),
42+
AllEdits.getEdits().end());
43+
std::sort(allEdits.begin(), allEdits.end(),
44+
[&](const SourceEdits::Edit &lhs, const SourceEdits::Edit &rhs) {
45+
// Sort first based on the path. This keeps the edits for a given
46+
// file together.
47+
if (lhs.Path < rhs.Path)
48+
return true;
49+
else if (lhs.Path > rhs.Path)
50+
return false;
51+
52+
// Then sort based on offset, with larger offsets coming earlier.
53+
return lhs.Offset > rhs.Offset;
54+
});
55+
56+
// Remove duplicate edits.
57+
allEdits.erase(
58+
std::unique(allEdits.begin(), allEdits.end(),
59+
[&](const SourceEdits::Edit &lhs, const SourceEdits::Edit &rhs) {
60+
return lhs.Path == rhs.Path && lhs.Text == rhs.Text &&
61+
lhs.Offset == rhs.Offset && lhs.Length == rhs.Length;
62+
}),
63+
allEdits.end());
64+
65+
OS << "[";
66+
bool first = true;
67+
for (auto &Edit : allEdits) {
68+
if (first) {
69+
first = false;
70+
} else {
71+
OS << ",";
72+
}
73+
OS << "\n";
3974
OS << " {\n";
4075
OS << " \"file\": \"";
4176
OS.write_escaped(Edit.Path) << "\",\n";
@@ -44,9 +79,9 @@ writeEditsInJson(const SourceEdits &AllEdits, llvm::raw_ostream &OS) {
4479
OS << " \"remove\": " << Edit.Length << ",\n";
4580
if (!Edit.Text.empty()) {
4681
OS << " \"text\": \"";
47-
OS.write_escaped(Edit.Text) << "\",\n";
82+
OS.write_escaped(Edit.Text) << "\"\n";
4883
}
49-
OS << " },\n";
84+
OS << " }";
5085
}
51-
OS << "]\n";
86+
OS << "\n]\n";
5287
}

test/diagnostics/verifier.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,5 @@ extension Crap {} // expected-error {{non-nominal type 'Crap' (aka '() -> ()') c
5050
// CHECK-FIXITS: {
5151
// CHECK-FIXITS: "file":
5252
// CHECK-FIXITS: "offset":
53-
// CHECK-FIXITS: "text": " as! Int",
54-
// CHECK-FIXITS: },
53+
// CHECK-FIXITS: "text": " as! Int"
54+
// CHECK-FIXITS: }

utils/apply-fixit-edits.py

-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ def apply_edits(path):
3434
for remap_file in remap_files:
3535
with open(remap_file) as f:
3636
json_data = f.read()
37-
json_data = json_data.replace(",\n }", "\n }")
38-
json_data = json_data.replace(",\n]", "\n]")
3937
curr_edits = json.loads(json_data)
4038
for ed in curr_edits:
4139
fname = ed["file"]

0 commit comments

Comments
 (0)