Skip to content

Commit c16e3bc

Browse files
authored
Merge pull request #20391 from rintaro/5.0-incrparse-rdar45259469
[5.0][incrParse] A couple of fixes for incrParse
2 parents c09d479 + 523a9bc commit c16e3bc

File tree

8 files changed

+153
-109
lines changed

8 files changed

+153
-109
lines changed

include/swift/Parse/SyntaxParsingCache.h

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ struct SourceEdit {
3434
/// The length of the string that replaced the range described above.
3535
size_t ReplacementLength;
3636

37+
SourceEdit(size_t Start, size_t End, size_t ReplacementLength)
38+
: Start(Start), End(End), ReplacementLength(ReplacementLength){};
39+
3740
/// The length of the range that has been replaced
38-
size_t originalLength() { return End - Start; }
41+
size_t originalLength() const { return End - Start; }
3942

4043
/// Check if the characters replaced by this edit fall into the given range
4144
/// or are directly adjacent to it
@@ -65,12 +68,16 @@ class SyntaxParsingCache {
6568
: OldSyntaxTree(OldSyntaxTree) {}
6669

6770
/// Add an edit that transformed the source file which created this cache into
68-
/// the source file that is now being parsed incrementally. The order in which
69-
/// the edits are added using this method needs to be the same order in which
70-
/// the edits were applied to the source file.
71-
void addEdit(size_t Start, size_t End, size_t ReplacementLength) {
72-
Edits.push_back({Start, End, ReplacementLength});
73-
}
71+
/// the source file that is now being parsed incrementally. \c Start must be a
72+
/// position from the *original* source file, and it must not overlap any
73+
/// other edits previously added. For instance, given:
74+
/// (aaa, bbb)
75+
/// 0123456789
76+
/// When you want to turn this into:
77+
/// (c, dddd)
78+
/// 0123456789
79+
/// edits should be: { 1, 4, 1 } and { 6, 9, 4 }.
80+
void addEdit(size_t Start, size_t End, size_t ReplacementLength);
7481

7582
/// Check if a syntax node of the given kind at the given position can be
7683
/// reused for a new syntax tree.
@@ -86,11 +93,13 @@ class SyntaxParsingCache {
8693
getReusedRegions(const SourceFileSyntax &SyntaxTree) const;
8794

8895
/// Translates a post-edit position to a pre-edit position by undoing the
89-
/// specified edits.
96+
/// specified edits. Returns \c None if no pre-edit position exists because
97+
/// the post-edit position has been inserted by an edit.
98+
///
9099
/// Should not be invoked externally. Only public for testing purposes.
91-
static size_t
100+
static Optional<size_t>
92101
translateToPreEditPosition(size_t PostEditPosition,
93-
llvm::SmallVector<SourceEdit, 4> Edits);
102+
ArrayRef<SourceEdit> Edits);
94103

95104
private:
96105
llvm::Optional<Syntax> lookUpFrom(const Syntax &Node, size_t NodeStart,

include/swift/Syntax/SyntaxData.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,16 @@ class SyntaxData final
133133
}
134134

135135
public:
136-
/// Get the node immediately before this current node. Return 0 if we cannot
137-
/// find such node.
136+
/// Get the node immediately before this current node that does contain a
137+
/// non-missing token. Return nullptr if we cannot find such node.
138138
RC<SyntaxData> getPreviousNode() const;
139139

140-
/// Get the node immediately after this current node. Return 0 if we cannot
141-
/// find such node.
140+
/// Get the node immediately after this current node that does contain a
141+
/// non-missing token. Return nullptr if we cannot find such node.
142142
RC<SyntaxData> getNextNode() const;
143143

144-
/// Get the first token node in this tree
144+
/// Get the first non-missing token node in this tree. Return nullptr if this
145+
/// node does not contain non-missing tokens.
145146
RC<SyntaxData> getFirstToken() const;
146147

147148
~SyntaxData() {

lib/Parse/SyntaxParsingCache.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616
using namespace swift;
1717
using namespace swift::syntax;
1818

19+
void SyntaxParsingCache::addEdit(size_t Start, size_t End,
20+
size_t ReplacementLength) {
21+
assert((Edits.empty() || Edits.back().End <= Start) &&
22+
"'Start' must be greater than or equal to 'End' of the previous edit");
23+
Edits.emplace_back(Start, End, ReplacementLength);
24+
}
25+
1926
bool SyntaxParsingCache::nodeCanBeReused(const Syntax &Node, size_t NodeStart,
2027
size_t Position,
2128
SyntaxKind Kind) const {
@@ -37,6 +44,7 @@ bool SyntaxParsingCache::nodeCanBeReused(const Syntax &Node, size_t NodeStart,
3744
if (auto NextNode = Node.getData().getNextNode()) {
3845
auto NextLeafNode = NextNode->getFirstToken();
3946
auto NextRawNode = NextLeafNode->getRaw();
47+
assert(NextRawNode->isPresent());
4048
NextLeafNodeLength += NextRawNode->getTokenText().size();
4149
for (auto TriviaPiece : NextRawNode->getLeadingTrivia()) {
4250
NextLeafNodeLength += TriviaPiece.getTextLength();
@@ -66,7 +74,7 @@ llvm::Optional<Syntax> SyntaxParsingCache::lookUpFrom(const Syntax &Node,
6674
size_t ChildStart = NodeStart;
6775
for (size_t I = 0, E = Node.getNumChildren(); I < E; ++I) {
6876
llvm::Optional<Syntax> Child = Node.getChild(I);
69-
if (!Child.hasValue()) {
77+
if (!Child.hasValue() || Child->isMissing()) {
7078
continue;
7179
}
7280
auto ChildEnd = ChildStart + Child->getTextLength();
@@ -79,23 +87,31 @@ llvm::Optional<Syntax> SyntaxParsingCache::lookUpFrom(const Syntax &Node,
7987
return llvm::None;
8088
}
8189

82-
size_t SyntaxParsingCache::translateToPreEditPosition(
83-
size_t PostEditPosition, llvm::SmallVector<SourceEdit, 4> Edits) {
90+
Optional<size_t>
91+
SyntaxParsingCache::translateToPreEditPosition(size_t PostEditPosition,
92+
ArrayRef<SourceEdit> Edits) {
8493
size_t Position = PostEditPosition;
85-
for (auto I = Edits.begin(), E = Edits.end(); I != E; ++I) {
86-
auto Edit = *I;
87-
if (Edit.End + Edit.ReplacementLength - Edit.originalLength() <= Position) {
88-
Position = Position - Edit.ReplacementLength + Edit.originalLength();
89-
}
94+
for (auto &Edit : Edits) {
95+
if (Edit.Start > Position)
96+
// Remaining edits doesn't affect the position. (Edits are sorted)
97+
break;
98+
if (Edit.Start + Edit.ReplacementLength > Position)
99+
// This is a position inserted by the edit, and thus doesn't exist in the
100+
// pre-edit version of the file.
101+
return None;
102+
103+
Position = Position - Edit.ReplacementLength + Edit.originalLength();
90104
}
91105
return Position;
92106
}
93107

94108
llvm::Optional<Syntax> SyntaxParsingCache::lookUp(size_t NewPosition,
95109
SyntaxKind Kind) {
96-
size_t OldPosition = translateToPreEditPosition(NewPosition, Edits);
110+
Optional<size_t> OldPosition = translateToPreEditPosition(NewPosition, Edits);
111+
if (!OldPosition.hasValue())
112+
return None;
97113

98-
auto Node = lookUpFrom(OldSyntaxTree, /*NodeStart=*/0, OldPosition, Kind);
114+
auto Node = lookUpFrom(OldSyntaxTree, /*NodeStart=*/0, *OldPosition, Kind);
99115
if (Node.hasValue()) {
100116
ReusedNodeIds.insert(Node->getId());
101117
}

lib/Syntax/SyntaxData.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ RC<SyntaxData> SyntaxData::getPreviousNode() const {
5959
if (hasParent()) {
6060
for (size_t I = N - 1; ; I--) {
6161
if (auto C = getParent()->getChild(I)) {
62-
return C;
62+
if (C->getRaw()->isPresent() && C->getFirstToken())
63+
return C;
6364
}
6465
if (I == 0)
6566
break;
@@ -73,27 +74,35 @@ RC<SyntaxData> SyntaxData::getNextNode() const {
7374
if (hasParent()) {
7475
for (size_t I = getIndexInParent() + 1, N = Parent->getNumChildren();
7576
I != N; I++) {
76-
if (auto C = getParent()->getChild(I))
77-
return C;
77+
if (auto C = getParent()->getChild(I)) {
78+
if (C->getRaw()->isPresent() && C->getFirstToken())
79+
return C;
80+
}
7881
}
7982
return Parent->getNextNode();
8083
}
8184
return nullptr;
8285
}
8386

8487
RC<SyntaxData> SyntaxData::getFirstToken() const {
88+
if (getRaw()->isToken()) {
89+
// Get a reference counted version of this
90+
assert(hasParent() && "The syntax tree should not conisist only of the root");
91+
return getParent()->getChild(getIndexInParent());
92+
}
93+
8594
for (size_t I = 0, E = getNumChildren(); I < E; ++I) {
8695
if (auto Child = getChild(I)) {
87-
if (!Child->getRaw()->isMissing()) {
88-
return Child->getFirstToken();
96+
if (Child->getRaw()->isMissing())
97+
continue;
98+
if (Child->getRaw()->isToken()) {
99+
return Child;
100+
} else if (auto Token = Child->getFirstToken()) {
101+
return Token;
89102
}
90103
}
91104
}
92-
93-
// Get a reference counted version of this
94-
assert(getRaw()->isToken() && "Leaf node that is no token?");
95-
assert(hasParent() && "The syntax tree should not conisist only of the root");
96-
return getParent()->getChild(getIndexInParent());
105+
return nullptr;
97106
}
98107

99108
AbsolutePosition SyntaxData::getAbsolutePositionBeforeLeadingTrivia() const {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %validate-incrparse %s --test-case ADD_ELSE
3+
4+
func container() {
5+
#if false
6+
<<ADD_ELSE<|||#else>>>
7+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %validate-incrparse %s --test-case INSERT_SPACE
3+
4+
class AnimationType {
5+
func foo(x: Blah) {
6+
switch x {
7+
case (.
8+
9+
extension AnimationType {
10+
public<<INSERT_SPACE<||| >>>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %validate-incrparse %s --test-case STRING
3+
4+
// SR-8995 rdar://problem/45259469
5+
6+
self = <<STRING<|||_ _>>>foo(1)[object1, object2] + o bar(1)

0 commit comments

Comments
 (0)