diff --git a/lldb/include/lldb/Expression/UserExpression.h b/lldb/include/lldb/Expression/UserExpression.h index 2d62fa37a24c2..03aa5e87c4cd5 100644 --- a/lldb/include/lldb/Expression/UserExpression.h +++ b/lldb/include/lldb/Expression/UserExpression.h @@ -192,6 +192,8 @@ class UserExpression : public Expression { /// expression. Text() should contain the definition of this function. const char *FunctionName() override { return "$__lldb_expr"; } + /// Returns whether the call to Parse on this user expression is cacheable. + virtual bool IsParseCacheable() { return true; } /// Return the language that should be used when parsing. To use the /// default, return eLanguageTypeUnknown. lldb::LanguageType Language() const override { return m_language; } diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp index 3ead1eca69134..a5f1eea8a73dc 100644 --- a/lldb/source/Breakpoint/BreakpointLocation.cpp +++ b/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -250,6 +250,7 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx, DiagnosticManager diagnostics; if (condition_hash != m_condition_hash || !m_user_expression_sp || + !m_user_expression_sp->IsParseCacheable() || !m_user_expression_sp->MatchesContext(exe_ctx)) { LanguageType language = eLanguageTypeUnknown; // See if we can figure out the language from the frame, otherwise use the diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp index 616bde3cac015..2b48f00f0b966 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp @@ -1725,6 +1725,16 @@ SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager, return ParseResult::unrecoverable_error; } + // If any generics are present, this expression is not parseable. + if (parsed_expr->code_manipulator) + m_is_cacheable = + !llvm::any_of(parsed_expr->code_manipulator->GetVariableInfo(), + [](const auto &variable) { + return variable.IsMetadataPointer() || + variable.IsPackCount() || + variable.IsUnboundPack(); + }); + auto dumpModule = [&](const char *msg) { std::string s; llvm::raw_string_ostream ss(s); diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.h b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.h index 32e92e9e5b5d8..39531093c4c12 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.h +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.h @@ -97,6 +97,11 @@ class SwiftExpressionParser : public ExpressionParser { ParseResult Parse(DiagnosticManager &diagnostic_manager, uint32_t first_line = 0, uint32_t last_line = UINT32_MAX); + /// Returns true if the call to parse of this type is cacheable. + bool IsParseCacheable() const { + return m_is_cacheable; + } + //------------------------------------------------------------------ /// Ready an already-parsed expression for execution, possibly /// evaluating it statically. @@ -198,6 +203,9 @@ class SwiftExpressionParser : public ExpressionParser { /// If true, we are running in REPL mode EvaluateExpressionOptions m_options; + + /// Indicates whether the call to Parse of this type is cacheable. + bool m_is_cacheable; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.h b/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.h index 1edf050c06e69..956691e5342d8 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.h +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.h @@ -139,6 +139,10 @@ class SwiftUserExpression : public LLVMUserExpression { void WillStartExecuting() override; void DidFinishExecuting() override; + bool IsParseCacheable() override { + return m_parser->IsParseCacheable(); + } + private: //------------------------------------------------------------------ /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the diff --git a/lldb/test/API/lang/swift/archetype_in_cond_breakpoint/TestArchetypeInConditionalBreakpoint.py b/lldb/test/API/lang/swift/archetype_in_cond_breakpoint/TestArchetypeInConditionalBreakpoint.py index 211a0ad4bc9d6..d553f27238ba7 100644 --- a/lldb/test/API/lang/swift/archetype_in_cond_breakpoint/TestArchetypeInConditionalBreakpoint.py +++ b/lldb/test/API/lang/swift/archetype_in_cond_breakpoint/TestArchetypeInConditionalBreakpoint.py @@ -7,28 +7,43 @@ class TestArchetypeInConditionalBreakpoint(TestBase): @swiftTest - def test_stops(self): + def test_stops_free_function(self): + self.stops("break here for free function") + + @swiftTest + def test_doesnt_stop_free_function(self): + self.doesnt_stop("break here for free function") + + @swiftTest + def test_stops_class(self): + self.stops("break here for class") + + @swiftTest + def test_doesnt_stop_class(self): + self.doesnt_stop("break here for class") + + def stops(self, breakpoint_string): """Tests that using archetypes in a conditional breakpoint's expression works correctly""" self.build() target = lldbutil.run_to_breakpoint_make_target(self) breakpoint = target.BreakpointCreateBySourceRegex( - "break here", lldb.SBFileSpec("main.swift") + breakpoint_string, lldb.SBFileSpec("main.swift") ) breakpoint.SetCondition("T.self == Int.self") _, process, _, _ = lldbutil.run_to_breakpoint_do_run(self, target, breakpoint) self.assertEqual(process.state, lldb.eStateStopped) + self.expect("expression T.self", substrs=["Int"]) - @swiftTest - def test_doesnt_stop(self): + def doesnt_stop(self, breakpoint_string): """Tests that using archetypes in a conditional breakpoint's expression works correctly""" self.build() target = lldbutil.run_to_breakpoint_make_target(self) breakpoint = target.BreakpointCreateBySourceRegex( - "break here", lldb.SBFileSpec("main.swift") + breakpoint_string, lldb.SBFileSpec("main.swift") ) breakpoint.SetCondition("T.self == Double.self") diff --git a/lldb/test/API/lang/swift/archetype_in_cond_breakpoint/main.swift b/lldb/test/API/lang/swift/archetype_in_cond_breakpoint/main.swift index 0bf8bc37a0b97..522f663dde384 100644 --- a/lldb/test/API/lang/swift/archetype_in_cond_breakpoint/main.swift +++ b/lldb/test/API/lang/swift/archetype_in_cond_breakpoint/main.swift @@ -1,4 +1,18 @@ + func f(t: T) { - print(1) // break here + print(1) // break here for free function } +f(t: "This is a string") +f(t: "This is another string") +f(t: true) f(t: 5) + +class MyClass { + func f() { + print(1) // break here for class + } +} +MyClass().f() +MyClass().f() +MyClass().f() +MyClass().f()