Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lldb/include/lldb/Expression/UserExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,16 @@ class UserExpression : public Expression {
lldb::ProcessSP &process_sp,
lldb::StackFrameSP &frame_sp);

/// Called by expression evaluator when a parse error occurs. Gives this
/// UserExpression object a chance to inspect and adjust the error diagnostics
/// contained in the specified \c diagnostic_manager.
///
/// \param[in,out] diagnostic_manager DiagnosticManager manager holding the
/// parse error diagnostics. This function may mutate the diagnostics.
///
virtual void
FixupParseErrorDiagnostics(DiagnosticManager &diagnostic_manager) const {}

/// The address the process is stopped in.
Address m_address;
/// The text of the expression, as typed by the user.
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Expression/UserExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,9 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx,
}

if (!parse_success) {
if (user_expression_sp)
user_expression_sp->FixupParseErrorDiagnostics(diagnostic_manager);

if (target->GetEnableNotifyAboutFixIts() && fixed_expression &&
!fixed_expression->empty()) {
std::string fixit =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/ExpressionSourceCode.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRInterpreter.h"
Expand Down Expand Up @@ -55,6 +56,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"

#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/BinaryFormat/Dwarf.h"

Expand Down Expand Up @@ -946,6 +948,46 @@ lldb::ExpressionVariableSP ClangUserExpression::GetResultAfterDematerialization(
return m_result_delegate.GetVariable();
}

void ClangUserExpression::FixupParseErrorDiagnostics(
DiagnosticManager &diagnostic_manager) const {
const bool is_fixable_cvr_error = llvm::any_of(
diagnostic_manager.Diagnostics(),
[](std::unique_ptr<Diagnostic> const &diag) {
switch (diag->GetCompilerID()) {
case clang::diag::err_member_function_call_bad_cvr:
return true;
case clang::diag::err_typecheck_assign_const:
// FIXME: can we split this particular error into a separate
// diagnostic ID so we don't need to scan the error message?
return diag->GetDetail().message.find(
"within const member function") != std::string::npos;
default:
return false;
}
});

// Nothing to report.
if (!is_fixable_cvr_error)
return;

// If the user already tried ignoring function qualifiers but
// the expression still failed, we don't want to suggest the hint again.
if (m_options.GetCppIgnoreContextQualifiers()) {
// Hard to prove that we don't get here so don't emit a diagnostic n
// non-asserts builds. But we do want a signal in asserts builds.
assert(false &&
"CppIgnoreContextQualifiers didn't resolve compiler diagnostic.");
return;
}

diagnostic_manager.Printf(
lldb::eSeverityInfo,
"Possibly trying to mutate object in a const context. Try "
"running the expression with: expression --c++-ignore-context-qualifiers "
"-- %s",
!m_fixed_text.empty() ? m_fixed_text.c_str() : m_expr_text.c_str());
}

char ClangUserExpression::ClangUserExpressionHelper::ID;

void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ class ClangUserExpression : public LLVMUserExpression {

llvm::StringRef GetFilename() const { return m_filename; }

protected:
void FixupParseErrorDiagnostics(
DiagnosticManager &diagnostic_manager) const override;

private:
/// Populate m_in_cplusplus_method and m_in_objectivec_method based on the
/// environment.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ def test(self):
"expression m_const_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member",
"with const-qualified type",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
matching=False,
)
self.expect(
"expression m_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
"cannot assign to non-static data member within const member function",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)
self.expect_expr("m_mem", result_value="-2")
Expand Down Expand Up @@ -60,7 +61,8 @@ def test(self):
"expression x = 7.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
"cannot assign to non-static data member within const member function",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)
self.expect_expr("x", result_value="2")
Expand All @@ -87,15 +89,16 @@ def test(self):
"expression m_const_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member",
"with const-qualified type",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
matching=False,
)
self.expect(
"expression m_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
"cannot assign to non-static data member within const member function",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)
self.expect_expr("m_mem", result_value="-2")
Expand All @@ -117,15 +120,16 @@ def test(self):
"expression m_const_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member",
"with const-qualified type",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
matching=False,
)
self.expect(
"expression m_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
"cannot assign to non-static data member within const member function",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)
self.expect_expr("m_mem", result_value="-1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ def test(self):
self.expect(
"expression volatile_method()",
error=True,
substrs=["has type 'const Foo'", "but function is not marked const"],
substrs=[
"has type 'const Foo'",
"but function is not marked const",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)

options = lldb.SBExpressionOptions()
Expand All @@ -41,7 +45,11 @@ def test(self):
self.expect(
"expression const_method()",
error=True,
substrs=["has type 'volatile Foo'", "but function is not marked volatile"],
substrs=[
"has type 'volatile Foo'",
"but function is not marked volatile",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)
self.expect_expr("volatile_method()")

Expand All @@ -65,6 +73,7 @@ def test(self):
substrs=[
"has type 'const volatile Foo'",
"but function is not marked const or volatile",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)
self.expect(
Expand All @@ -73,6 +82,7 @@ def test(self):
substrs=[
"has type 'const volatile Foo'",
"but function is not marked const or volatile",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ def test(self):
substrs=[
"member reference type 'const Bar' is not a pointer",
"but function is not marked const",
"Possibly trying to mutate object in a const context. Try running the expression with",
"expression --c++-ignore-context-qualifiers -- m_bar.method()",
],
)

# Two fix-its
# Two fix-its...
self.expect(
"expression -- m_bar->method() + m_bar->method()",
error=True,
Expand All @@ -32,11 +34,36 @@ def test(self):
],
)

# ...only emit a single hint.
self.assertEqual(
self.res.GetError().count(
"Possibly trying to mutate object in a const context."
),
1,
)

self.expect(
"expression -Q -- m_bar->method()",
error=True,
substrs=["Evaluated this expression after applying Fix-It(s):"],
)

self.expect(
"expression m_bar->method() + blah",
error=True,
substrs=[
"member reference type 'const Bar' is not a pointer",
"but function is not marked const",
"Possibly trying to mutate object in a const context. Try running the expression with",
"expression --c++-ignore-context-qualifiers -- m_bar.method() + blah",
],
)

self.expect(
"expression -Q -- m_bar->method() + blah",
error=True,
substrs=[
"Possibly trying to mutate object in a const context. Try running the expression with",
],
matching=False,
)
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ def test(self):
"expression x = 7.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
"cannot assign to non-static data member within const member function",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def test(self):
"expression m_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
"cannot assign to non-static data member within const member function",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)
self.expect_expr("((Foo*)this)->bar()", result_type="double", result_value="5")
Expand All @@ -44,7 +45,8 @@ def test(self):
"expression x = 7.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
"cannot assign to non-static data member within const member function",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)
self.expect_expr("x = -7.0; x", options=options, result_value="-7")
Expand Down Expand Up @@ -77,7 +79,8 @@ def test(self):
"expression m_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
"cannot assign to non-static data member within const member function",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)
self.expect_expr("m_mem", result_value="-2")
Expand Down Expand Up @@ -105,7 +108,8 @@ def test(self):
"expression m_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
"cannot assign to non-static data member within const member function",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
],
)
self.expect_expr("m_mem = -11.0; m_mem", options=options, result_value="-11")
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ def test(self):
"expression x = 7.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
"cannot assign to non-static data member within const member function",
"note: Possibly trying to mutate object in a const context. Try running the expression with",
"expression --c++-ignore-context-qualifiers -- x = 7.0",
],
)

Expand Down
3 changes: 2 additions & 1 deletion lldb/test/API/lang/cpp/this/TestCPPThis.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ def test_with_run_command(self):
"expression -- m_a = 2",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
"cannot assign to non-static data member within const member function",
"Possibly trying to mutate object in a const context. Try running the expression with: expression --c++-ignore-context-qualifiers -- m_a = 2",
],
)

Expand Down
Loading