Skip to content

Commit f2bf1e4

Browse files
author
git apple-llvm automerger
committed
Merge commit '15a147949532' from swift/release/6.2 into stable/20240723
2 parents ef2c220 + 15a1479 commit f2bf1e4

File tree

16 files changed

+581
-23
lines changed

16 files changed

+581
-23
lines changed

lldb/include/lldb/Expression/DiagnosticManager.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ class DiagnosticManager {
107107
m_fixed_expression.clear();
108108
}
109109

110-
const DiagnosticList &Diagnostics() { return m_diagnostics; }
110+
const DiagnosticList &Diagnostics() const { return m_diagnostics; }
111+
DiagnosticList &Diagnostics() { return m_diagnostics; }
111112

112113
bool HasFixIts() const {
113114
return llvm::any_of(m_diagnostics,

lldb/include/lldb/Symbol/Variable.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ class Variable : public UserID, public std::enable_shared_from_this<Variable> {
9191

9292
bool IsInScope(StackFrame *frame);
9393

94+
/// Returns true if this variable is in scope at `addr` inside `block`.
95+
bool IsInScope(const Block &block, const Address &addr);
96+
9497
bool LocationIsValidForFrame(StackFrame *frame);
9598

9699
bool LocationIsValidForAddress(const Address &address);

lldb/include/lldb/Symbol/VariableList.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ class VariableList {
2424
VariableList();
2525
virtual ~VariableList();
2626

27+
VariableList(VariableList &&) = default;
28+
VariableList &operator=(VariableList &&) = default;
29+
2730
void AddVariable(const lldb::VariableSP &var_sp);
2831

2932
bool AddVariableIfUnique(const lldb::VariableSP &var_sp);

lldb/include/lldb/Target/Language.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,28 @@ class Language : public PluginInterface {
401401

402402
virtual FormatEntity::Entry GetFunctionNameFormat() const { return {}; }
403403

404+
// BEGIN SWIFT
405+
// Implement LanguageCPlusPlus::GetParentNameIfClosure and upstream this.
406+
// rdar://152321823
407+
408+
/// If `mangled_name` refers to a function that is a "closure-like" function,
409+
/// returns the name of the parent function where the input closure was
410+
/// defined. Returns an empty string if there is no such parent, or if the
411+
/// query does not make sense for this language.
412+
virtual std::string
413+
GetParentNameIfClosure(llvm::StringRef mangled_name) const {
414+
return "";
415+
}
416+
417+
/// If `sc` corresponds to a "closure-like" function (as defined in
418+
/// `GetParentNameIfClosure`), returns the parent Function*
419+
/// where a variable named `variable_name` exists.
420+
/// Returns nullptr if `sc` is not a closure, or if the query does
421+
/// not make sense for this language.
422+
Function *FindParentOfClosureWithVariable(llvm::StringRef variable_name,
423+
const SymbolContext &sc) const;
424+
// END SWIFT
425+
404426
protected:
405427
// Classes that inherit from Language can see and modify these
406428

lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "lldb/Symbol/Type.h"
3636
#include "lldb/Symbol/Variable.h"
3737
#include "lldb/Symbol/VariableList.h"
38+
#include "lldb/Target/Language.h"
3839
#include "lldb/Utility/LLDBAssert.h"
3940
#include "lldb/Utility/LLDBLog.h"
4041
#include "lldb/Utility/Log.h"
@@ -700,6 +701,68 @@ SwiftUserExpression::GetTextAndSetExpressionParser(
700701
return parse_result;
701702
}
702703

704+
/// If `sc` represents a "closure-like" function according to `lang`, and
705+
/// `var_name` can be found in a parent context, create a diagnostic
706+
/// explaining that this variable is available but not captured by the closure.
707+
static std::string
708+
CreateVarInParentScopeDiagnostic(StringRef var_name,
709+
StringRef parent_func_name) {
710+
return llvm::formatv("A variable named '{0}' existed in function '{1}', but "
711+
"it was not captured in the closure.\nHint: the "
712+
"variable may be available in a parent frame.",
713+
var_name, parent_func_name);
714+
}
715+
716+
/// If `diagnostic_manager` contains a "cannot find <var_name> in scope"
717+
/// diagnostic, attempt to enhance it by showing if `var_name` is used inside a
718+
/// closure, not captured, but defined in a parent scope.
719+
static void EnhanceNotInScopeDiagnostics(DiagnosticManager &diagnostic_manager,
720+
ExecutionContextScope *exe_scope) {
721+
if (!exe_scope)
722+
return;
723+
lldb::StackFrameSP stack_frame = exe_scope->CalculateStackFrame();
724+
if (!stack_frame)
725+
return;
726+
SymbolContext sc =
727+
stack_frame->GetSymbolContext(lldb::eSymbolContextEverything);
728+
Language *swift_lang =
729+
Language::FindPlugin(lldb::LanguageType::eLanguageTypeSwift);
730+
if (!swift_lang)
731+
return;
732+
733+
static const RegularExpression not_in_scope_regex =
734+
RegularExpression("(.*): cannot find '([^']+)' in scope\n(.*)");
735+
for (auto &diag : diagnostic_manager.Diagnostics()) {
736+
if (!diag)
737+
continue;
738+
739+
llvm::SmallVector<StringRef, 4> match_groups;
740+
741+
if (StringRef old_rendered_msg = diag->GetDetail().rendered;
742+
!not_in_scope_regex.Execute(old_rendered_msg, &match_groups))
743+
continue;
744+
745+
StringRef prefix = match_groups[1];
746+
StringRef var_name = match_groups[2];
747+
StringRef suffix = match_groups[3];
748+
749+
Function *parent_func =
750+
swift_lang->FindParentOfClosureWithVariable(var_name, sc);
751+
if (!parent_func)
752+
continue;
753+
std::string new_message = CreateVarInParentScopeDiagnostic(
754+
var_name, parent_func->GetDisplayName());
755+
756+
std::string new_rendered =
757+
llvm::formatv("{0}: {1}\n{2}", prefix, new_message, suffix);
758+
const DiagnosticDetail &old_detail = diag->GetDetail();
759+
diag = std::make_unique<Diagnostic>(
760+
diag->getKind(), diag->GetCompilerID(),
761+
DiagnosticDetail{old_detail.source_location, old_detail.severity,
762+
std::move(new_message), std::move(new_rendered)});
763+
}
764+
}
765+
703766
bool SwiftUserExpression::Parse(DiagnosticManager &diagnostic_manager,
704767
ExecutionContext &exe_ctx,
705768
lldb_private::ExecutionPolicy execution_policy,
@@ -895,6 +958,7 @@ bool SwiftUserExpression::Parse(DiagnosticManager &diagnostic_manager,
895958
fixed_expression.substr(fixed_start, fixed_end - fixed_start);
896959
}
897960
}
961+
EnhanceNotInScopeDiagnostics(diagnostic_manager, exe_scope);
898962
return false;
899963
case ParseResult::success:
900964
llvm_unreachable("Success case is checked separately before switch!");

lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,6 +2018,11 @@ SwiftLanguage::AreEqualForFrameComparison(const SymbolContext &sc1,
20182018
llvm_unreachable("unhandled enumeration in AreEquivalentFunctions");
20192019
}
20202020

2021+
std::string
2022+
SwiftLanguage::GetParentNameIfClosure(llvm::StringRef mangled_name) const {
2023+
return SwiftLanguageRuntime::GetParentNameIfClosure(mangled_name);
2024+
}
2025+
20212026
//------------------------------------------------------------------
20222027
// Static Functions
20232028
//------------------------------------------------------------------

lldb/source/Plugins/Language/Swift/SwiftLanguage.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ class SwiftLanguage : public Language {
112112
std::optional<bool>
113113
AreEqualForFrameComparison(const SymbolContext &sc1,
114114
const SymbolContext &sc2) const override;
115+
116+
std::string
117+
GetParentNameIfClosure(llvm::StringRef mangled_name) const override;
115118
//------------------------------------------------------------------
116119
// Static Functions
117120
//------------------------------------------------------------------

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ class SwiftLanguageRuntime : public LanguageRuntime {
205205
const SymbolContext *sc = nullptr,
206206
const ExecutionContext *exe_ctx = nullptr);
207207

208+
static std::string GetParentNameIfClosure(llvm::StringRef mangled_name);
209+
208210
/// Demangle a symbol to a swift::Demangle node tree.
209211
///
210212
/// This is a central point of access, for purposes such as logging.

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeNames.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "Plugins/TypeSystem/Swift/SwiftASTContext.h"
14+
#include "Plugins/TypeSystem/Swift/SwiftDemangle.h"
1315
#include "SwiftLanguageRuntime.h"
1416

1517
#include "lldb/Breakpoint/StoppointCallbackContext.h"
@@ -1497,4 +1499,30 @@ SwiftLanguageRuntime::GetGenericSignature(llvm::StringRef function_name,
14971499
return signature;
14981500
}
14991501

1502+
std::string SwiftLanguageRuntime::GetParentNameIfClosure(StringRef name) {
1503+
using Kind = Node::Kind;
1504+
swift::Demangle::Context ctx;
1505+
auto *node = SwiftLanguageRuntime::DemangleSymbolAsNode(name, ctx);
1506+
if (!node || node->getKind() != Node::Kind::Global)
1507+
return "";
1508+
1509+
// Replace the top level closure node with the child function-like node, and
1510+
// attempt to remangle. If successful, this produces the parent function-like
1511+
// entity.
1512+
static const auto closure_kinds = {Kind::ImplicitClosure,
1513+
Kind::ExplicitClosure};
1514+
static const auto function_kinds = {Kind::ImplicitClosure,
1515+
Kind::ExplicitClosure, Kind::Function};
1516+
auto *closure_node = swift_demangle::GetFirstChildOfKind(node, closure_kinds);
1517+
auto *parent_func_node =
1518+
swift_demangle::GetFirstChildOfKind(closure_node, function_kinds);
1519+
if (!parent_func_node)
1520+
return "";
1521+
swift_demangle::ReplaceChildWith(*node, *closure_node, *parent_func_node);
1522+
1523+
if (ManglingErrorOr<std::string> mangled = swift::Demangle::mangleNode(node);
1524+
mangled.isSuccess())
1525+
return mangled.result();
1526+
return "";
1527+
}
15001528
} // namespace lldb_private

lldb/source/Plugins/TypeSystem/Swift/SwiftDemangle.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,32 @@
2222
namespace lldb_private {
2323
namespace swift_demangle {
2424

25+
using NodePointer = swift::Demangle::NodePointer;
26+
using Node = swift::Demangle::Node;
27+
28+
/// Returns the first child of `node` whose kind is in `kinds`.
29+
inline NodePointer GetFirstChildOfKind(NodePointer node,
30+
llvm::ArrayRef<Node::Kind> kinds) {
31+
if (!node)
32+
return nullptr;
33+
for (auto *child : *node)
34+
if (llvm::is_contained(kinds, child->getKind()))
35+
return child;
36+
return nullptr;
37+
}
38+
39+
/// Assumes that `to_replace` is a child of `parent`, and replaces it with
40+
/// `new_child`. The Nodes must all be owned by the same context.
41+
inline void ReplaceChildWith(Node &parent, Node &to_replace, Node &new_child) {
42+
for (unsigned idx = 0; idx < parent.getNumChildren(); idx++) {
43+
auto *child = parent.getChild(idx);
44+
if (child == &to_replace)
45+
parent.replaceChild(idx, &new_child);
46+
return;
47+
}
48+
llvm_unreachable("invalid child passed to replaceChildWith");
49+
}
50+
2551
/// Access an inner node by following the given Node::Kind path.
2652
///
2753
/// Note: The Node::Kind path is relative to the given root node. The root

lldb/source/Symbol/Variable.cpp

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -291,28 +291,9 @@ bool Variable::IsInScope(StackFrame *frame) {
291291
// this variable was defined in is currently
292292
Block *deepest_frame_block =
293293
frame->GetSymbolContext(eSymbolContextBlock).block;
294-
if (deepest_frame_block) {
295-
SymbolContext variable_sc;
296-
CalculateSymbolContext(&variable_sc);
297-
298-
// Check for static or global variable defined at the compile unit
299-
// level that wasn't defined in a block
300-
if (variable_sc.block == nullptr)
301-
return true;
302-
303-
// Check if the variable is valid in the current block
304-
if (variable_sc.block != deepest_frame_block &&
305-
!variable_sc.block->Contains(deepest_frame_block))
306-
return false;
307-
308-
// If no scope range is specified then it means that the scope is the
309-
// same as the scope of the enclosing lexical block.
310-
if (m_scope_range.IsEmpty())
311-
return true;
312-
313-
addr_t file_address = frame->GetFrameCodeAddress().GetFileAddress();
314-
return m_scope_range.FindEntryThatContains(file_address) != nullptr;
315-
}
294+
Address frame_addr = frame->GetFrameCodeAddress();
295+
if (deepest_frame_block)
296+
return IsInScope(*deepest_frame_block, frame_addr);
316297
}
317298
break;
318299

@@ -322,6 +303,27 @@ bool Variable::IsInScope(StackFrame *frame) {
322303
return false;
323304
}
324305

306+
bool Variable::IsInScope(const Block &block, const Address &addr) {
307+
SymbolContext variable_sc;
308+
CalculateSymbolContext(&variable_sc);
309+
310+
// Check for static or global variable defined at the compile unit
311+
// level that wasn't defined in a block
312+
if (variable_sc.block == nullptr)
313+
return true;
314+
315+
// Check if the variable is valid in the current block
316+
if (variable_sc.block != &block && !variable_sc.block->Contains(&block))
317+
return false;
318+
319+
// If no scope range is specified then it means that the scope is the
320+
// same as the scope of the enclosing lexical block.
321+
if (m_scope_range.IsEmpty())
322+
return true;
323+
324+
return m_scope_range.FindEntryThatContains(addr.GetFileAddress()) != nullptr;
325+
}
326+
325327
Status Variable::GetValuesForVariableExpressionPath(
326328
llvm::StringRef variable_expr_path, ExecutionContextScope *scope,
327329
GetVariableCallback callback, void *baton, VariableList &variable_list,

0 commit comments

Comments
 (0)