Skip to content

Commit 63becb5

Browse files
committed
[incrParse] Fix bug in translation of post-edit to pre-edit positions
1 parent 5c568af commit 63becb5

File tree

4 files changed

+142
-15
lines changed

4 files changed

+142
-15
lines changed

include/swift/Parse/SyntaxParsingCache.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
#include "llvm/Support/raw_ostream.h"
1919
#include <unordered_set>
2020

21-
namespace {
21+
namespace swift {
22+
23+
using namespace swift::syntax;
2224

2325
/// A single edit to the original source file in which a continuous range of
2426
/// characters have been replaced by a new string
@@ -42,12 +44,6 @@ struct SourceEdit {
4244
}
4345
};
4446

45-
} // anonymous namespace
46-
47-
namespace swift {
48-
49-
using namespace swift::syntax;
50-
5147
struct SyntaxReuseRegion {
5248
AbsolutePosition Start;
5349
AbsolutePosition End;
@@ -89,6 +85,13 @@ class SyntaxParsingCache {
8985
std::vector<SyntaxReuseRegion>
9086
getReusedRegions(const SourceFileSyntax &SyntaxTree) const;
9187

88+
/// Translates a post-edit position to a pre-edit position by undoing the
89+
/// specified edits.
90+
/// Should not be invoked externally. Only public for testing purposes.
91+
static size_t
92+
translateToPreEditPosition(size_t PostEditPosition,
93+
llvm::SmallVector<SourceEdit, 4> Edits);
94+
9295
private:
9396
llvm::Optional<Syntax> lookUpFrom(const Syntax &Node, size_t NodeStart,
9497
size_t Position, SyntaxKind Kind);

lib/Parse/SyntaxParsingCache.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,21 @@ llvm::Optional<Syntax> SyntaxParsingCache::lookUpFrom(const Syntax &Node,
7979
return llvm::None;
8080
}
8181

82-
llvm::Optional<Syntax> SyntaxParsingCache::lookUp(size_t NewPosition,
83-
SyntaxKind Kind) {
84-
// Undo the edits in reverse order
85-
size_t OldPosition = NewPosition;
86-
for (auto I = Edits.rbegin(), E = Edits.rend(); I != E; ++I) {
82+
size_t SyntaxParsingCache::translateToPreEditPosition(
83+
size_t PostEditPosition, llvm::SmallVector<SourceEdit, 4> Edits) {
84+
size_t Position = PostEditPosition;
85+
for (auto I = Edits.begin(), E = Edits.end(); I != E; ++I) {
8786
auto Edit = *I;
88-
if (Edit.End < OldPosition) {
89-
OldPosition =
90-
OldPosition - Edit.ReplacementLength + Edit.originalLength();
87+
if (Edit.End + Edit.ReplacementLength - Edit.originalLength() <= Position) {
88+
Position = Position - Edit.ReplacementLength + Edit.originalLength();
9189
}
9290
}
91+
return Position;
92+
}
93+
94+
llvm::Optional<Syntax> SyntaxParsingCache::lookUp(size_t NewPosition,
95+
SyntaxKind Kind) {
96+
size_t OldPosition = translateToPreEditPosition(NewPosition, Edits);
9397

9498
auto Node = lookUpFrom(OldSyntaxTree, /*NodeStart=*/0, OldPosition, Kind);
9599
if (Node.hasValue()) {

unittests/Parse/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_swift_unittest(SwiftParseTests
22
BuildConfigTests.cpp
33
LexerTests.cpp
44
LexerTriviaTests.cpp
5+
SyntaxParsingCacheTests.cpp
56
TokenizerTests.cpp
67
)
78

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#include "swift/Parse/SyntaxParsingCache.h"
2+
#include "gtest/gtest.h"
3+
4+
using namespace swift;
5+
using namespace llvm;
6+
7+
class TranslateToPreEditPositionTest : public ::testing::Test {};
8+
9+
TEST_F(TranslateToPreEditPositionTest, SingleEditBefore) {
10+
// Old: ab_xy
11+
// New: a1b_xy
12+
//
13+
// Edits:
14+
// (1) 1-2: a -> a1
15+
//
16+
// Lookup for _ at new position 4
17+
18+
llvm::SmallVector<SourceEdit, 4> Edits = {
19+
{1, 2, 2}
20+
};
21+
22+
size_t PreEditPos = SyntaxParsingCache::translateToPreEditPosition(4, Edits);
23+
EXPECT_EQ(PreEditPos, 3u);
24+
}
25+
26+
TEST_F(TranslateToPreEditPositionTest, SingleEditDirectlyBefore) {
27+
// Old: ab_xy
28+
// New: ablah_xy
29+
//
30+
// Edits:
31+
// (1) 2-3: b -> blah
32+
//
33+
// Lookup for _ at new position 6
34+
35+
llvm::SmallVector<SourceEdit, 4> Edits = {
36+
{2, 3, 4}
37+
};
38+
39+
size_t PreEditPos = SyntaxParsingCache::translateToPreEditPosition(6, Edits);
40+
EXPECT_EQ(PreEditPos, 3u);
41+
}
42+
43+
TEST_F(TranslateToPreEditPositionTest, SingleMultiCharacterEdit) {
44+
// Old: ab_xy
45+
// New: abcdef_xy
46+
//
47+
// Edits:
48+
// (1) 1-3: ab -> abcdef
49+
//
50+
// Lookup for _ at new position 7
51+
52+
llvm::SmallVector<SourceEdit, 4> Edits = {
53+
{1, 3, 6}
54+
};
55+
56+
size_t PreEditPos = SyntaxParsingCache::translateToPreEditPosition(7, Edits);
57+
EXPECT_EQ(PreEditPos, 3u);
58+
}
59+
60+
TEST_F(TranslateToPreEditPositionTest, EditAfterLookup) {
61+
// Old: ab_xy
62+
// New: ab_xyz
63+
//
64+
// Edits:
65+
// (1) 4-6: xy -> xyz
66+
//
67+
// Lookup for _ at new position 3
68+
69+
llvm::SmallVector<SourceEdit, 4> Edits = {{4, 6, 4}};
70+
71+
size_t PreEditPos = SyntaxParsingCache::translateToPreEditPosition(3, Edits);
72+
EXPECT_EQ(PreEditPos, 3u);
73+
}
74+
75+
TEST_F(TranslateToPreEditPositionTest, SimpleMultiEdit) {
76+
// Old: ab_xy
77+
// New: a1b2_x3y4
78+
//
79+
// Edits:
80+
// (1) 1-2: a -> a1
81+
// (2) 2-3: b -> b2
82+
// (3) 4-5: x -> x3
83+
// (4) 5-6: y -> y4
84+
//
85+
// Lookup for _ at new position 5
86+
87+
llvm::SmallVector<SourceEdit, 4> Edits = {
88+
{1, 2, 2},
89+
{2, 3, 2},
90+
{4, 5, 2},
91+
{5, 6, 2},
92+
};
93+
94+
size_t PreEditPos = SyntaxParsingCache::translateToPreEditPosition(5, Edits);
95+
EXPECT_EQ(PreEditPos, 3u);
96+
}
97+
98+
TEST_F(TranslateToPreEditPositionTest, LongMultiEdit) {
99+
// Old: ab_xy
100+
// New: a11111b2_x3y4
101+
//
102+
// Edits:
103+
// (1) 1-2: a -> a11111
104+
// (2) 2-3: b -> b2
105+
// (3) 4-5: x -> x3
106+
// (4) 5-6: y -> y4
107+
//
108+
// Lookup for _ at new position
109+
110+
llvm::SmallVector<SourceEdit, 4> Edits = {
111+
{1, 2, 6},
112+
{2, 3, 2},
113+
{4, 5, 2},
114+
{5, 6, 2},
115+
};
116+
117+
size_t PreEditPos = SyntaxParsingCache::translateToPreEditPosition(9, Edits);
118+
EXPECT_EQ(PreEditPos, 3u);
119+
}

0 commit comments

Comments
 (0)