Skip to content

Commit 80085e0

Browse files
committed
[SyntaxParse] Make ParsedRawSyntaxNode move-only
So that we can easily detect 'ParsedSyntaxNode' leaking. When it's moved, the original node become "null" node. In the destructor of 'ParsedSyntaxNode', assert the node is not "recorded" node.
1 parent da95961 commit 80085e0

18 files changed

+432
-292
lines changed

include/swift/Parse/LibSyntaxGenerator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class LibSyntaxGenerator {
4444

4545
auto Recorded = Recorder.recordToken(Kind, Range, LeadingTriviaPieces,
4646
TrailingTriviaPieces);
47-
auto Raw = static_cast<RawSyntax *>(Recorded.getOpaqueNode());
47+
auto Raw = static_cast<RawSyntax *>(Recorded.takeOpaqueNode());
4848
return make<TokenSyntax>(Raw);
4949
}
5050

@@ -55,7 +55,7 @@ class LibSyntaxGenerator {
5555
auto Children = Node.getDeferredChildren();
5656

5757
auto Recorded = Recorder.recordRawSyntax(Kind, Children);
58-
RC<RawSyntax> Raw {static_cast<RawSyntax *>(Recorded.getOpaqueNode()) };
58+
RC<RawSyntax> Raw {static_cast<RawSyntax *>(Recorded.takeOpaqueNode()) };
5959
Raw->Release(); // -1 since it's transfer of ownership.
6060
return make<SyntaxNode>(Raw);
6161
}

include/swift/Parse/ParsedRawSyntaxNode.h

Lines changed: 96 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class ParsedRawSyntaxNode {
5151
CharSourceRange Range;
5252
};
5353
struct DeferredLayoutNode {
54-
ArrayRef<ParsedRawSyntaxNode> Children;
54+
MutableArrayRef<ParsedRawSyntaxNode> Children;
5555
};
5656
struct DeferredTokenNode {
5757
const ParsedTriviaPiece *TriviaPieces;
@@ -73,8 +73,8 @@ class ParsedRawSyntaxNode {
7373
bool IsMissing = false;
7474

7575
ParsedRawSyntaxNode(syntax::SyntaxKind k,
76-
ArrayRef<ParsedRawSyntaxNode> deferredNodes)
77-
: DeferredLayout{deferredNodes},
76+
MutableArrayRef<ParsedRawSyntaxNode> deferredNodes)
77+
: DeferredLayout({deferredNodes}),
7878
SynKind(uint16_t(k)), TokKind(uint16_t(tok::unknown)),
7979
DK(DataKind::DeferredLayout) {
8080
assert(getKind() == k && "Syntax kind with too large value!");
@@ -97,6 +97,8 @@ class ParsedRawSyntaxNode {
9797
assert(DeferredToken.NumTrailingTrivia == numTrailingTrivia &&
9898
"numLeadingTrivia is too large value!");
9999
}
100+
ParsedRawSyntaxNode(ParsedRawSyntaxNode &other) = delete;
101+
ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &other) = delete;
100102

101103
public:
102104
ParsedRawSyntaxNode()
@@ -115,6 +117,35 @@ class ParsedRawSyntaxNode {
115117
assert(getTokenKind() == tokKind && "Token kind with too large value!");
116118
}
117119

120+
ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &&other) {
121+
assert(DK != DataKind::Recorded);
122+
switch (other.DK) {
123+
case DataKind::Null:
124+
break;
125+
case DataKind::Recorded:
126+
RecordedData = std::move(other.RecordedData);
127+
break;
128+
case DataKind::DeferredLayout:
129+
DeferredLayout = std::move(other.DeferredLayout);
130+
break;
131+
case DataKind::DeferredToken:
132+
DeferredToken = std::move(other.DeferredToken);
133+
break;
134+
}
135+
SynKind = std::move(other.SynKind);
136+
TokKind = std::move(other.TokKind);
137+
DK = std::move(other.DK);
138+
IsMissing = std::move(other.IsMissing);
139+
other.reset();
140+
return *this;
141+
}
142+
ParsedRawSyntaxNode(ParsedRawSyntaxNode &&other) : ParsedRawSyntaxNode() {
143+
*this = std::move(other);
144+
}
145+
~ParsedRawSyntaxNode() {
146+
assert(DK != DataKind::Recorded);
147+
}
148+
118149
syntax::SyntaxKind getKind() const { return syntax::SyntaxKind(SynKind); }
119150
tok getTokenKind() const { return tok(TokKind); }
120151

@@ -136,6 +167,36 @@ class ParsedRawSyntaxNode {
136167
/// Primary used for a deferred missing token.
137168
bool isMissing() const { return IsMissing; }
138169

170+
void reset() {
171+
RecordedData = {};
172+
SynKind = uint16_t(syntax::SyntaxKind::Unknown);
173+
TokKind = uint16_t(tok::unknown);
174+
DK = DataKind::Null;
175+
IsMissing = false;
176+
}
177+
178+
ParsedRawSyntaxNode unsafeCopy() const {
179+
ParsedRawSyntaxNode copy;
180+
switch (DK) {
181+
case DataKind::DeferredLayout:
182+
copy.DeferredLayout = DeferredLayout;
183+
break;
184+
case DataKind::DeferredToken:
185+
copy.DeferredToken = DeferredToken;
186+
break;
187+
case DataKind::Recorded:
188+
copy.RecordedData = RecordedData;
189+
break;
190+
case DataKind::Null:
191+
break;
192+
}
193+
copy.SynKind = SynKind;
194+
copy.TokKind = TokKind;
195+
copy.DK = DK;
196+
copy.IsMissing = IsMissing;
197+
return copy;
198+
}
199+
139200
CharSourceRange getDeferredRange() const {
140201
switch (DK) {
141202
case DataKind::DeferredLayout:
@@ -153,18 +214,24 @@ class ParsedRawSyntaxNode {
153214
assert(isRecorded());
154215
return RecordedData.Range;
155216
}
156-
OpaqueSyntaxNode getOpaqueNode() const {
217+
const OpaqueSyntaxNode &getOpaqueNode() const {
157218
assert(isRecorded());
158219
return RecordedData.OpaqueNode;
159220
}
221+
OpaqueSyntaxNode takeOpaqueNode() {
222+
assert(isRecorded());
223+
auto opaque = RecordedData.OpaqueNode;
224+
reset();
225+
return opaque;
226+
}
160227

161228
// Deferred Layout Data ====================================================//
162229

163230
CharSourceRange getDeferredLayoutRange() const {
164231
assert(DK == DataKind::DeferredLayout);
165232
assert(!DeferredLayout.Children.empty());
166-
auto getLastNonNullChild = [this]() {
167-
for (auto &&Child : llvm::reverse(getDeferredChildren()))
233+
auto getLastNonNullChild = [this]() -> const ParsedRawSyntaxNode & {
234+
for (auto &Child : llvm::reverse(getDeferredChildren()))
168235
if (!Child.isNull())
169236
return Child;
170237
llvm_unreachable("layout node without non-null children");
@@ -178,6 +245,28 @@ class ParsedRawSyntaxNode {
178245
assert(DK == DataKind::DeferredLayout);
179246
return DeferredLayout.Children;
180247
}
248+
MutableArrayRef<ParsedRawSyntaxNode> getDeferredChildren() {
249+
assert(DK == DataKind::DeferredLayout);
250+
return DeferredLayout.Children;
251+
}
252+
ParsedRawSyntaxNode copyDeferred() const {
253+
ParsedRawSyntaxNode copy;
254+
switch (DK) {
255+
case DataKind::DeferredLayout:
256+
copy.DeferredLayout = DeferredLayout;
257+
break;
258+
case DataKind::DeferredToken:
259+
copy.DeferredToken = DeferredToken;
260+
break;
261+
default:
262+
llvm_unreachable("node not deferred");
263+
}
264+
copy.SynKind = SynKind;
265+
copy.TokKind = TokKind;
266+
copy.DK = DK;
267+
copy.IsMissing = IsMissing;
268+
return copy;
269+
}
181270

182271
// Deferred Token Data =====================================================//
183272

@@ -214,7 +303,7 @@ class ParsedRawSyntaxNode {
214303

215304
/// Form a deferred syntax layout node.
216305
static ParsedRawSyntaxNode makeDeferred(syntax::SyntaxKind k,
217-
ArrayRef<ParsedRawSyntaxNode> deferredNodes,
306+
MutableArrayRef<ParsedRawSyntaxNode> deferredNodes,
218307
SyntaxParsingContext &ctx);
219308

220309
/// Form a deferred token node.

include/swift/Parse/ParsedRawSyntaxRecorder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class ParsedRawSyntaxRecorder {
6060
/// \p kind. Missing optional elements are represented with a null
6161
/// ParsedRawSyntaxNode object.
6262
ParsedRawSyntaxNode recordRawSyntax(syntax::SyntaxKind kind,
63-
ArrayRef<ParsedRawSyntaxNode> elements);
63+
MutableArrayRef<ParsedRawSyntaxNode> elements);
6464

6565
/// Record a raw syntax collecton without eny elements. \p loc can be invalid
6666
/// or an approximate location of where an element of the collection would be

include/swift/Parse/ParsedSyntax.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class ParsedSyntax {
2626
: RawNode(std::move(rawNode)) {}
2727

2828
const ParsedRawSyntaxNode &getRaw() const { return RawNode; }
29+
ParsedRawSyntaxNode takeRaw() { return std::move(RawNode); }
2930
syntax::SyntaxKind getKind() const { return RawNode.getKind(); }
3031

3132
/// Returns true if the syntax node is of the given type.
@@ -39,7 +40,7 @@ class ParsedSyntax {
3940
template <typename T>
4041
T castTo() const {
4142
assert(is<T>() && "castTo<T>() node of incompatible type!");
42-
return T { RawNode };
43+
return T { RawNode.copyDeferred() };
4344
}
4445

4546
/// If this Syntax node is of the right kind, cast and return it,
@@ -52,6 +53,10 @@ class ParsedSyntax {
5253
return llvm::None;
5354
}
5455

56+
ParsedSyntax copyDeferred() const {
57+
return ParsedSyntax { RawNode.copyDeferred() };
58+
}
59+
5560
static bool kindof(syntax::SyntaxKind Kind) {
5661
return true;
5762
}
@@ -65,7 +70,7 @@ class ParsedSyntax {
6570
class ParsedTokenSyntax final : public ParsedSyntax {
6671
public:
6772
explicit ParsedTokenSyntax(ParsedRawSyntaxNode rawNode)
68-
: ParsedSyntax(rawNode) {}
73+
: ParsedSyntax(std::move(rawNode)) {}
6974

7075
tok getTokenKind() const {
7176
return getRaw().getTokenKind();

include/swift/Parse/ParsedSyntaxRecorder.h.gyb

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,32 +53,32 @@ public:
5353
% elif node.is_syntax_collection():
5454
private:
5555
static Parsed${node.name} record${node.syntax_kind}(
56-
ArrayRef<Parsed${node.collection_element_type}> elts,
56+
MutableArrayRef<Parsed${node.collection_element_type}> elts,
5757
ParsedRawSyntaxRecorder &rec);
5858

5959
public:
6060
static Parsed${node.name} defer${node.syntax_kind}(
61-
ArrayRef<Parsed${node.collection_element_type}> elts,
61+
MutableArrayRef<Parsed${node.collection_element_type}> elts,
6262
SyntaxParsingContext &SPCtx);
6363
static Parsed${node.name} make${node.syntax_kind}(
64-
ArrayRef<Parsed${node.collection_element_type}> elts,
64+
MutableArrayRef<Parsed${node.collection_element_type}> elts,
6565
SyntaxParsingContext &SPCtx);
6666

6767
static Parsed${node.name} makeBlank${node.syntax_kind}(SourceLoc loc,
6868
SyntaxParsingContext &SPCtx);
6969
% elif node.is_unknown():
7070
private:
7171
static Parsed${node.name} record${node.syntax_kind}(
72-
ArrayRef<ParsedSyntax> elts,
72+
MutableArrayRef<ParsedSyntax> elts,
7373
ParsedRawSyntaxRecorder &rec);
7474

7575
public:
7676
static Parsed${node.name} defer${node.syntax_kind}(
77-
ArrayRef<ParsedSyntax> elts,
77+
MutableArrayRef<ParsedSyntax> elts,
7878
SyntaxParsingContext &SPCtx);
7979

8080
static Parsed${node.name} make${node.syntax_kind}(
81-
ArrayRef<ParsedSyntax> elts,
81+
MutableArrayRef<ParsedSyntax> elts,
8282
SyntaxParsingContext &SPCtx);
8383
% end
8484
% end
@@ -95,18 +95,21 @@ public:
9595
/// optional trailing comma.
9696
static ParsedTupleTypeElementSyntax
9797
makeTupleTypeElement(ParsedTypeSyntax Type,
98-
Optional<ParsedTokenSyntax> TrailingComma,
99-
SyntaxParsingContext &SPCtx);
98+
Optional<ParsedTokenSyntax> TrailingComma,
99+
SyntaxParsingContext &SPCtx);
100100

101101
/// The provided \c elements are in the appropriate order for the syntax
102102
/// \c kind's layout but optional elements are not be included.
103103
/// This function will form the exact layout based on the provided elements,
104104
/// substituting missing parts with a null ParsedRawSyntaxNode object.
105105
///
106106
/// \returns true if the layout could be formed, false otherwise.
107-
static bool formExactLayoutFor(syntax::SyntaxKind kind,
108-
ArrayRef<ParsedRawSyntaxNode> elements,
109-
function_ref<void(syntax::SyntaxKind, ArrayRef<ParsedRawSyntaxNode>)> receiver);
107+
static bool
108+
formExactLayoutFor(syntax::SyntaxKind kind,
109+
MutableArrayRef<ParsedRawSyntaxNode> elements,
110+
function_ref<void(syntax::SyntaxKind,
111+
MutableArrayRef<ParsedRawSyntaxNode>)>
112+
receiver);
110113
};
111114
}
112115

include/swift/Parse/SyntaxParserResult.h

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,18 @@ template <typename ParsedSyntaxNode> class ParsedSyntaxResult {
4040
assert(Status.isError());
4141
}
4242

43-
explicit ParsedSyntaxResult(ParsedRawSyntaxNode Raw)
44-
: Raw(Raw), Status() {}
43+
explicit ParsedSyntaxResult(ParsedRawSyntaxNode &&Raw)
44+
: Raw(std::move(Raw)), Status() {}
4545

46-
explicit ParsedSyntaxResult(ParsedSyntaxNode Node)
47-
: ParsedSyntaxResult(Node.getRaw()) {}
46+
explicit ParsedSyntaxResult(ParsedSyntaxNode &&Node)
47+
: ParsedSyntaxResult(Node.takeRaw()) {}
4848

4949
template <typename OtherParsedSyntaxNode,
5050
typename Enable = typename std::enable_if<std::is_base_of<
5151
ParsedSyntaxNode, OtherParsedSyntaxNode>::value>::type>
52-
ParsedSyntaxResult(ParsedSyntaxResult<OtherParsedSyntaxNode> other) {
53-
Raw = other.Raw;
54-
Status = other.Status;
52+
ParsedSyntaxResult(ParsedSyntaxResult<OtherParsedSyntaxNode> &&other) {
53+
Raw = std::move(other.Raw);
54+
Status = std::move(other.Status);
5555
}
5656

5757
bool isSuccess() const {
@@ -72,11 +72,20 @@ template <typename ParsedSyntaxNode> class ParsedSyntaxResult {
7272
Status.setHasCodeCompletion();
7373
}
7474

75-
ParsedSyntaxNode get() const {
75+
ParsedSyntaxNode get() {
7676
assert(!isNull());
77-
return ParsedSyntaxNode(Raw);
77+
return ParsedSyntaxNode(std::move(Raw));
7878
}
79-
Optional<ParsedSyntaxNode> getOrNull() const {
79+
80+
template<typename NewSyntaxNode>
81+
Optional<NewSyntaxNode> getAs() {
82+
assert(!isNull());
83+
if (NewSyntaxNode::kindof(Raw.getKind()))
84+
return NewSyntaxNode(std::move(Raw));
85+
return None;
86+
}
87+
88+
Optional<ParsedSyntaxNode> getOrNull() {
8089
if (isNull())
8190
return None;
8291
return get();
@@ -94,13 +103,13 @@ template <typename ParsedSyntaxNode> class ParsedSyntaxResult {
94103
template <typename ParsedSyntaxNode>
95104
static ParsedSyntaxResult<ParsedSyntaxNode>
96105
makeParsedResult(ParsedSyntaxNode node) {
97-
return ParsedSyntaxResult<ParsedSyntaxNode>(node);
106+
return ParsedSyntaxResult<ParsedSyntaxNode>(std::move(node));
98107
}
99108

100109
template <typename ParsedSyntaxNode>
101110
static ParsedSyntaxResult<ParsedSyntaxNode>
102111
makeParsedError(ParsedSyntaxNode node) {
103-
auto result = ParsedSyntaxResult<ParsedSyntaxNode>(node);
112+
auto result = ParsedSyntaxResult<ParsedSyntaxNode>(std::move(node));
104113
result.setIsError();
105114
return result;
106115
}
@@ -113,15 +122,15 @@ static ParsedSyntaxResult<ParsedSyntaxNode> makeParsedError() {
113122
template <typename ParsedSyntaxNode>
114123
static ParsedSyntaxResult<ParsedSyntaxNode>
115124
makeParsedCodeCompletion(ParsedSyntaxNode node) {
116-
auto result = ParsedSyntaxResult<ParsedSyntaxNode>(node);
125+
auto result = ParsedSyntaxResult<ParsedSyntaxNode>(std::move(node));
117126
result.setHasCodeCompletion();
118127
return result;
119128
}
120129

121130
template <typename ParsedSyntaxNode>
122131
static ParsedSyntaxResult<ParsedSyntaxNode>
123132
makeParsedResult(ParsedSyntaxNode node, ParserStatus Status) {
124-
auto result = ParsedSyntaxResult<ParsedSyntaxNode>(node);
133+
auto result = ParsedSyntaxResult<ParsedSyntaxNode>(std::move(node));
125134
if (Status.hasCodeCompletion())
126135
result.setHasCodeCompletion();
127136
else if (Status.isError())

0 commit comments

Comments
 (0)