-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Re-implement DebuggerContextChange using a new mechanism #33795
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fae8f94
4923aab
5d602dc
5746322
b9cd6ca
0bedd20
f3e7963
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,48 +60,34 @@ namespace { | |
/// file scope level so it will be set up correctly for this purpose. | ||
/// | ||
/// Creating an instance of this object will cause it to figure out | ||
/// whether we are in the debugger function, whether it needs to swap | ||
/// whether we are in the debugger function, and whether it needs to swap | ||
/// the Decl that is currently being parsed. | ||
/// If you have created the object, instead of returning the result | ||
/// with makeParserResult, use the object's fixupParserResult. If | ||
/// no swap has occurred, these methods will work the same. | ||
/// If the decl has been moved, then Parser::markWasHandled will be | ||
/// called on the Decl, and you should call declWasHandledAlready | ||
/// before you consume the Decl to see if you actually need to | ||
/// consume it. | ||
/// | ||
/// If you are making one of these objects to address issue 1, call | ||
/// the constructor that only takes a DeclKind, and it will be moved | ||
/// unconditionally. Otherwise pass in the Name and DeclKind and the | ||
/// DebuggerClient will be asked whether to move it or not. | ||
class DebuggerContextChange { | ||
protected: | ||
Parser &P; | ||
Identifier Name; | ||
SourceFile *SF; | ||
Optional<Parser::ContextChange> CC; | ||
SourceFile *SF; | ||
public: | ||
DebuggerContextChange (Parser &P) | ||
: P(P), SF(nullptr) { | ||
DebuggerContextChange(Parser &P) : P(P), SF(nullptr) { | ||
if (!inDebuggerContext()) | ||
return; | ||
else | ||
switchContext(); | ||
|
||
switchContext(); | ||
} | ||
|
||
DebuggerContextChange (Parser &P, Identifier &Name, DeclKind Kind) | ||
: P(P), Name(Name), SF(nullptr) { | ||
DebuggerContextChange(Parser &P, Identifier Name, DeclKind Kind) | ||
: P(P), SF(nullptr) { | ||
if (!inDebuggerContext()) | ||
return; | ||
bool globalize = false; | ||
|
||
DebuggerClient *debug_client = getDebuggerClient(); | ||
if (!debug_client) | ||
return; | ||
|
||
globalize = debug_client->shouldGlobalize(Name, Kind); | ||
|
||
if (globalize) | ||
switchContext(); | ||
|
||
if (auto *client = getDebuggerClient()) | ||
if (client->shouldGlobalize(Name, Kind)) | ||
switchContext(); | ||
} | ||
|
||
bool movedToTopLevel() { | ||
|
@@ -118,19 +104,21 @@ namespace { | |
template <typename T> | ||
ParserResult<T> | ||
fixupParserResult(T *D) { | ||
if (CC.hasValue()) { | ||
swapDecl(D); | ||
if (movedToTopLevel()) { | ||
D->setHoisted(); | ||
SF->addHoistedDecl(D); | ||
getDebuggerClient()->didGlobalize(D); | ||
Comment on lines
+108
to
+110
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is an invariant here, I'm guessing that these three always go together. If so, how about factoring this out, and lines 118-121 into a separate function? I'm guessing you've also added assertions for the invariant. |
||
} | ||
return ParserResult<T>(D); | ||
} | ||
|
||
template <typename T> | ||
ParserResult<T> | ||
fixupParserResult(ParserStatus Status, T *D) { | ||
if (CC.hasValue() && !Status.isError()) { | ||
// If there is an error, don't do our splicing trick, | ||
// just return the Decl and the status for reporting. | ||
swapDecl(D); | ||
if (movedToTopLevel()) { | ||
D->setHoisted(); | ||
SF->addHoistedDecl(D); | ||
getDebuggerClient()->didGlobalize(D); | ||
} | ||
return makeParserResult(Status, D); | ||
} | ||
|
@@ -140,43 +128,29 @@ namespace { | |
~DebuggerContextChange () {} | ||
protected: | ||
|
||
DebuggerClient *getDebuggerClient() | ||
{ | ||
ModuleDecl *PM = P.CurDeclContext->getParentModule(); | ||
if (!PM) | ||
return nullptr; | ||
else | ||
return PM->getDebugClient(); | ||
DebuggerClient *getDebuggerClient() { | ||
ModuleDecl *M = P.CurDeclContext->getParentModule(); | ||
return M->getDebugClient(); | ||
} | ||
|
||
bool inDebuggerContext() { | ||
if (!P.Context.LangOpts.DebuggerSupport) | ||
return false; | ||
if (!P.CurDeclContext) | ||
return false; | ||
auto *func_decl = dyn_cast<FuncDecl>(P.CurDeclContext); | ||
if (!func_decl) | ||
auto *func = dyn_cast<FuncDecl>(P.CurDeclContext); | ||
if (!func) | ||
return false; | ||
if (!func_decl->getAttrs().hasAttribute<LLDBDebuggerFunctionAttr>()) | ||
|
||
if (!func->getAttrs().hasAttribute<LLDBDebuggerFunctionAttr>()) | ||
return false; | ||
|
||
return true; | ||
} | ||
|
||
void switchContext () { | ||
void switchContext() { | ||
SF = P.CurDeclContext->getParentSourceFile(); | ||
CC.emplace (P, SF); | ||
} | ||
|
||
void swapDecl (Decl *D) | ||
{ | ||
assert (SF); | ||
DebuggerClient *debug_client = getDebuggerClient(); | ||
assert (debug_client); | ||
debug_client->didGlobalize(D); | ||
P.ContextSwitchedTopLevelDecls.push_back(D); | ||
P.markWasHandled(D); | ||
CC.emplace(P, SF); | ||
} | ||
}; | ||
} // end anonymous namespace | ||
|
@@ -225,10 +199,6 @@ void Parser::parseTopLevel(SmallVectorImpl<Decl *> &decls) { | |
} | ||
} | ||
|
||
// First append any decls that LLDB requires be inserted at the top-level. | ||
decls.append(ContextSwitchedTopLevelDecls.begin(), | ||
ContextSwitchedTopLevelDecls.end()); | ||
|
||
// Then append the top-level decls we parsed. | ||
for (auto item : items) { | ||
auto *decl = item.get<Decl *>(); | ||
|
@@ -7726,8 +7696,9 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags, | |
SourceLoc precedenceGroupLoc = consumeToken(tok::kw_precedencegroup); | ||
DebuggerContextChange DCC (*this); | ||
|
||
if (!CodeCompletion && !DCC.movedToTopLevel() && !(flags & PD_AllowTopLevel)) | ||
{ | ||
if (!CodeCompletion && | ||
!DCC.movedToTopLevel() && | ||
!(flags & PD_AllowTopLevel)) { | ||
diagnose(precedenceGroupLoc, diag::decl_inner_scope); | ||
return nullptr; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -215,11 +215,17 @@ void swift::bindExtensions(ModuleDecl &mod) { | |
if (!SF) | ||
continue; | ||
|
||
for (auto D : SF->getTopLevelDecls()) { | ||
auto visitTopLevelDecl = [&](Decl *D) { | ||
if (auto ED = dyn_cast<ExtensionDecl>(D)) | ||
if (!tryBindExtension(ED)) | ||
worklist.push_back(ED); | ||
} | ||
worklist.push_back(ED);; | ||
}; | ||
|
||
for (auto *D : SF->getTopLevelDecls()) | ||
visitTopLevelDecl(D); | ||
|
||
for (auto *D : SF->getHoistedDecls()) | ||
visitTopLevelDecl(D); | ||
Comment on lines
+224
to
+228
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be the place for the consistency-checking assertion. |
||
} | ||
|
||
// Phase 2 - repeatedly go through the worklist and attempt to bind each | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent!