Skip to content

Commit 3fd8481

Browse files
authored
Merge pull request swiftlang#27308 from rintaro/parse-debuggercontextchange
[Parse] Give own header to DebuggerContextChange. NFC
2 parents e9bf767 + 33cf983 commit 3fd8481

File tree

2 files changed

+152
-136
lines changed

2 files changed

+152
-136
lines changed

lib/Parse/DebuggerContextChange.h

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//===--- DebuggerContextChange.h --------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_PARSE_DEBUGGERCONTEXTCHANGE_H
14+
#define SWIFT_PARSE_DEBUGGERCONTEXTCHANGE_H
15+
16+
#include "swift/AST/DebuggerClient.h"
17+
#include "swift/AST/Decl.h"
18+
#include "swift/AST/Identifier.h"
19+
#include "swift/AST/SourceFile.h"
20+
#include "swift/Parse/Parser.h"
21+
22+
namespace swift {
23+
24+
/// A RAII object for deciding whether this DeclKind needs special
25+
/// treatment when parsing in the "debugger context", and implementing
26+
/// that treatment. The problem arises because, when lldb
27+
/// uses swift to parse expressions, it needs to emulate the current
28+
/// frame's scope. We do that, for instance, by making a class extension
29+
/// and running the code in a function in that extension.
30+
///
31+
/// This causes two kinds of issues:
32+
/// 1) Some DeclKinds require to be parsed in TopLevel contexts only.
33+
/// 2) Sometimes the debugger wants a Decl to live beyond the current
34+
/// function invocation, in which case it should be parsed at the
35+
/// file scope level so it will be set up correctly for this purpose.
36+
///
37+
/// Creating an instance of this object will cause it to figure out
38+
/// whether we are in the debugger function, whether it needs to swap
39+
/// the Decl that is currently being parsed.
40+
/// If you have created the object, instead of returning the result
41+
/// with makeParserResult, use the object's fixupParserResult. If
42+
/// no swap has occurred, these methods will work the same.
43+
/// If the decl has been moved, then Parser::markWasHandled will be
44+
/// called on the Decl, and you should call declWasHandledAlready
45+
/// before you consume the Decl to see if you actually need to
46+
/// consume it.
47+
/// If you are making one of these objects to address issue 1, call
48+
/// the constructor that only takes a DeclKind, and it will be moved
49+
/// unconditionally. Otherwise pass in the Name and DeclKind and the
50+
/// DebuggerClient will be asked whether to move it or not.
51+
class DebuggerContextChange {
52+
protected:
53+
Parser &P;
54+
Identifier Name;
55+
SourceFile *SF;
56+
Optional<Parser::ContextChange> CC;
57+
58+
public:
59+
DebuggerContextChange(Parser &P) : P(P), SF(nullptr) {
60+
if (!inDebuggerContext())
61+
return;
62+
else
63+
switchContext();
64+
}
65+
66+
DebuggerContextChange(Parser &P, Identifier &Name, DeclKind Kind)
67+
: P(P), Name(Name), SF(nullptr) {
68+
if (!inDebuggerContext())
69+
return;
70+
bool globalize = false;
71+
72+
DebuggerClient *debug_client = getDebuggerClient();
73+
if (!debug_client)
74+
return;
75+
76+
globalize = debug_client->shouldGlobalize(Name, Kind);
77+
78+
if (globalize)
79+
switchContext();
80+
}
81+
82+
bool movedToTopLevel() { return CC.hasValue(); }
83+
84+
template <typename T>
85+
ParserResult<T> fixupParserResult(ParserResult<T> &Result) {
86+
ParserStatus Status = Result;
87+
return fixupParserResult(Status, Result.getPtrOrNull());
88+
}
89+
90+
template <typename T> ParserResult<T> fixupParserResult(T *D) {
91+
if (CC.hasValue()) {
92+
swapDecl(D);
93+
}
94+
return ParserResult<T>(D);
95+
}
96+
97+
template <typename T>
98+
ParserResult<T> fixupParserResult(ParserStatus Status, T *D) {
99+
if (CC.hasValue() && !Status.isError()) {
100+
// If there is an error, don't do our splicing trick,
101+
// just return the Decl and the status for reporting.
102+
swapDecl(D);
103+
}
104+
return makeParserResult(Status, D);
105+
}
106+
107+
// The destructor doesn't need to do anything, the CC's destructor will
108+
// pop the context if we set it.
109+
~DebuggerContextChange() {}
110+
111+
protected:
112+
DebuggerClient *getDebuggerClient() {
113+
ModuleDecl *PM = P.CurDeclContext->getParentModule();
114+
if (!PM)
115+
return nullptr;
116+
else
117+
return PM->getDebugClient();
118+
}
119+
120+
bool inDebuggerContext() {
121+
if (!P.Context.LangOpts.DebuggerSupport)
122+
return false;
123+
if (!P.CurDeclContext)
124+
return false;
125+
auto *func_decl = dyn_cast<FuncDecl>(P.CurDeclContext);
126+
if (!func_decl)
127+
return false;
128+
129+
if (!func_decl->getAttrs().hasAttribute<LLDBDebuggerFunctionAttr>())
130+
return false;
131+
132+
return true;
133+
}
134+
135+
void switchContext() {
136+
SF = P.CurDeclContext->getParentSourceFile();
137+
CC.emplace(P, SF);
138+
}
139+
140+
void swapDecl(Decl *D) {
141+
assert(SF);
142+
DebuggerClient *debug_client = getDebuggerClient();
143+
assert(debug_client);
144+
debug_client->didGlobalize(D);
145+
SF->Decls.push_back(D);
146+
P.markWasHandled(D);
147+
}
148+
};
149+
} // namespace swift
150+
151+
#endif

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17+
#include "DebuggerContextChange.h"
1718
#include "swift/Parse/Parser.h"
1819
#include "swift/Parse/CodeCompletionCallbacks.h"
1920
#include "swift/Parse/ParsedSyntaxBuilders.h"
@@ -46,142 +47,6 @@
4647
using namespace swift;
4748
using namespace syntax;
4849

49-
namespace {
50-
/// A RAII object for deciding whether this DeclKind needs special
51-
/// treatment when parsing in the "debugger context", and implementing
52-
/// that treatment. The problem arises because, when lldb
53-
/// uses swift to parse expressions, it needs to emulate the current
54-
/// frame's scope. We do that, for instance, by making a class extension
55-
/// and running the code in a function in that extension.
56-
///
57-
/// This causes two kinds of issues:
58-
/// 1) Some DeclKinds require to be parsed in TopLevel contexts only.
59-
/// 2) Sometimes the debugger wants a Decl to live beyond the current
60-
/// function invocation, in which case it should be parsed at the
61-
/// file scope level so it will be set up correctly for this purpose.
62-
///
63-
/// Creating an instance of this object will cause it to figure out
64-
/// whether we are in the debugger function, whether it needs to swap
65-
/// the Decl that is currently being parsed.
66-
/// If you have created the object, instead of returning the result
67-
/// with makeParserResult, use the object's fixupParserResult. If
68-
/// no swap has occurred, these methods will work the same.
69-
/// If the decl has been moved, then Parser::markWasHandled will be
70-
/// called on the Decl, and you should call declWasHandledAlready
71-
/// before you consume the Decl to see if you actually need to
72-
/// consume it.
73-
/// If you are making one of these objects to address issue 1, call
74-
/// the constructor that only takes a DeclKind, and it will be moved
75-
/// unconditionally. Otherwise pass in the Name and DeclKind and the
76-
/// DebuggerClient will be asked whether to move it or not.
77-
class DebuggerContextChange {
78-
protected:
79-
Parser &P;
80-
Identifier Name;
81-
SourceFile *SF;
82-
Optional<Parser::ContextChange> CC;
83-
public:
84-
DebuggerContextChange (Parser &P)
85-
: P(P), SF(nullptr) {
86-
if (!inDebuggerContext())
87-
return;
88-
else
89-
switchContext();
90-
}
91-
92-
DebuggerContextChange (Parser &P, Identifier &Name, DeclKind Kind)
93-
: P(P), Name(Name), SF(nullptr) {
94-
if (!inDebuggerContext())
95-
return;
96-
bool globalize = false;
97-
98-
DebuggerClient *debug_client = getDebuggerClient();
99-
if (!debug_client)
100-
return;
101-
102-
globalize = debug_client->shouldGlobalize(Name, Kind);
103-
104-
if (globalize)
105-
switchContext();
106-
}
107-
108-
bool movedToTopLevel() {
109-
return CC.hasValue();
110-
}
111-
112-
template <typename T>
113-
ParserResult<T>
114-
fixupParserResult(ParserResult<T> &Result) {
115-
ParserStatus Status = Result;
116-
return fixupParserResult(Status, Result.getPtrOrNull());
117-
}
118-
119-
template <typename T>
120-
ParserResult<T>
121-
fixupParserResult(T *D) {
122-
if (CC.hasValue()) {
123-
swapDecl(D);
124-
}
125-
return ParserResult<T>(D);
126-
}
127-
128-
template <typename T>
129-
ParserResult<T>
130-
fixupParserResult(ParserStatus Status, T *D) {
131-
if (CC.hasValue() && !Status.isError()) {
132-
// If there is an error, don't do our splicing trick,
133-
// just return the Decl and the status for reporting.
134-
swapDecl(D);
135-
}
136-
return makeParserResult(Status, D);
137-
}
138-
139-
// The destructor doesn't need to do anything, the CC's destructor will
140-
// pop the context if we set it.
141-
~DebuggerContextChange () {}
142-
protected:
143-
144-
DebuggerClient *getDebuggerClient()
145-
{
146-
ModuleDecl *PM = P.CurDeclContext->getParentModule();
147-
if (!PM)
148-
return nullptr;
149-
else
150-
return PM->getDebugClient();
151-
}
152-
153-
bool inDebuggerContext() {
154-
if (!P.Context.LangOpts.DebuggerSupport)
155-
return false;
156-
if (!P.CurDeclContext)
157-
return false;
158-
auto *func_decl = dyn_cast<FuncDecl>(P.CurDeclContext);
159-
if (!func_decl)
160-
return false;
161-
162-
if (!func_decl->getAttrs().hasAttribute<LLDBDebuggerFunctionAttr>())
163-
return false;
164-
165-
return true;
166-
}
167-
168-
void switchContext () {
169-
SF = P.CurDeclContext->getParentSourceFile();
170-
CC.emplace (P, SF);
171-
}
172-
173-
void swapDecl (Decl *D)
174-
{
175-
assert (SF);
176-
DebuggerClient *debug_client = getDebuggerClient();
177-
assert (debug_client);
178-
debug_client->didGlobalize(D);
179-
SF->Decls.push_back(D);
180-
P.markWasHandled(D);
181-
}
182-
};
183-
} // end anonymous namespace
184-
18550
/// Main entrypoint for the parser.
18651
///
18752
/// \verbatim

0 commit comments

Comments
 (0)