[LLDB] Update DIL to pass current 'frame var' tests. (#145055)
As a preliminary to making DIL the default implementation for 'frame var', ran check-lldb forcing 'frame var' to always use DIL, and discovered a few failing tests. This fixes most of them. The only remaining failing test is TestDAP_evaluate.py, which now passes a test case that the test says should fail (still investigating this). Changes in this PR: - Sets correct VariableSP, as well as returning ValueObjectSP (needed for several watchpoint tests). - Updates error messages, when looking up members, to match what the rest of LLDB expects. Also update appropriate DIL tests to expect the updated error messages. - Updates DIL parser to look for and accept "(anonymous namespace)::" at the front of a variable name.
This commit is contained in:
@@ -562,6 +562,7 @@ ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath(
|
||||
return ValueObjectConstResult::Create(nullptr, std::move(error));
|
||||
}
|
||||
|
||||
var_sp = (*valobj_or_error)->GetVariable();
|
||||
return *valobj_or_error;
|
||||
}
|
||||
|
||||
|
||||
@@ -363,8 +363,8 @@ Interpreter::Visit(const MemberOfNode *node) {
|
||||
|
||||
if (!m_use_synthetic || !field_obj) {
|
||||
std::string errMsg = llvm::formatv(
|
||||
"no member named '{0}' in {1}", node->GetFieldName(),
|
||||
base->GetCompilerType().GetFullyUnqualifiedType().TypeDescription());
|
||||
"\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
|
||||
base->GetTypeName().AsCString("<invalid type>"), base->GetName());
|
||||
return llvm::make_error<DILDiagnosticError>(
|
||||
m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
|
||||
}
|
||||
@@ -383,9 +383,9 @@ Interpreter::Visit(const MemberOfNode *node) {
|
||||
CompilerType base_type = base->GetCompilerType();
|
||||
if (node->GetIsArrow() && base->IsPointerType())
|
||||
base_type = base_type.GetPointeeType();
|
||||
std::string errMsg =
|
||||
llvm::formatv("no member named '{0}' in {1}", node->GetFieldName(),
|
||||
base_type.GetFullyUnqualifiedType().TypeDescription());
|
||||
std::string errMsg = llvm::formatv(
|
||||
"\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
|
||||
base->GetTypeName().AsCString("<invalid type>"), base->GetName());
|
||||
return llvm::make_error<DILDiagnosticError>(
|
||||
m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
|
||||
}
|
||||
|
||||
@@ -183,12 +183,14 @@ ASTNodeUP DILParser::ParsePostfixExpression() {
|
||||
// "(" expression ")"
|
||||
//
|
||||
ASTNodeUP DILParser::ParsePrimaryExpression() {
|
||||
if (CurToken().IsOneOf({Token::coloncolon, Token::identifier})) {
|
||||
if (CurToken().IsOneOf(
|
||||
{Token::coloncolon, Token::identifier, Token::l_paren})) {
|
||||
// Save the source location for the diagnostics message.
|
||||
uint32_t loc = CurToken().GetLocation();
|
||||
auto identifier = ParseIdExpression();
|
||||
std::string identifier = ParseIdExpression();
|
||||
|
||||
return std::make_unique<IdentifierNode>(loc, identifier);
|
||||
if (!identifier.empty())
|
||||
return std::make_unique<IdentifierNode>(loc, identifier);
|
||||
}
|
||||
|
||||
if (CurToken().Is(Token::l_paren)) {
|
||||
@@ -232,16 +234,15 @@ std::string DILParser::ParseNestedNameSpecifier() {
|
||||
m_dil_lexer.LookAhead(4).Is(Token::coloncolon)) {
|
||||
m_dil_lexer.Advance(4);
|
||||
|
||||
assert(
|
||||
(CurToken().Is(Token::identifier) || CurToken().Is(Token::l_paren)) &&
|
||||
"Expected an identifier or anonymous namespace, but not found.");
|
||||
Expect(Token::coloncolon);
|
||||
m_dil_lexer.Advance();
|
||||
if (!CurToken().Is(Token::identifier) && !CurToken().Is(Token::l_paren)) {
|
||||
BailOut("Expected an identifier or anonymous namespace, but not found.",
|
||||
CurToken().GetLocation(), CurToken().GetSpelling().length());
|
||||
}
|
||||
// Continue parsing the nested_namespace_specifier.
|
||||
std::string identifier2 = ParseNestedNameSpecifier();
|
||||
if (identifier2.empty()) {
|
||||
Expect(Token::identifier);
|
||||
identifier2 = CurToken().GetSpelling();
|
||||
m_dil_lexer.Advance();
|
||||
}
|
||||
|
||||
return "(anonymous namespace)::" + identifier2;
|
||||
}
|
||||
|
||||
@@ -301,6 +302,9 @@ std::string DILParser::ParseIdExpression() {
|
||||
nested_name_specifier, unqualified_id);
|
||||
}
|
||||
|
||||
if (!CurToken().Is(Token::identifier))
|
||||
return "";
|
||||
|
||||
// No nested_name_specifier, but with global scope -- this is also a
|
||||
// qualified_id production. Follow the second production rule.
|
||||
if (global_scope) {
|
||||
|
||||
@@ -31,12 +31,19 @@ class TestFrameVarDILMemberOf(TestBase):
|
||||
self.expect_var_path("sp->x", value="1")
|
||||
self.expect_var_path("sp->r", type="int &")
|
||||
|
||||
self.expect("frame variable 'sp->foo'", error=True,
|
||||
substrs=["no member named 'foo' in 'Sx *'"])
|
||||
self.expect(
|
||||
"frame variable 'sp->foo'",
|
||||
error=True,
|
||||
substrs=['"foo" is not a member of "(Sx *) sp"'],
|
||||
)
|
||||
|
||||
self.expect("frame variable 'sp.x'", error=True,
|
||||
substrs=["member reference type 'Sx *' is a "
|
||||
"pointer; did you mean to use '->'"])
|
||||
self.expect(
|
||||
"frame variable 'sp.x'",
|
||||
error=True,
|
||||
substrs=[
|
||||
"member reference type 'Sx *' is a pointer; did you mean to use '->'"
|
||||
],
|
||||
)
|
||||
|
||||
# Test for record typedefs.
|
||||
self.expect_var_path("sa.x", value="3")
|
||||
|
||||
@@ -27,8 +27,11 @@ class TestFrameVarDILMemberOfAnonymousMember(TestBase):
|
||||
self.expect_var_path("a.x", value="1")
|
||||
self.expect_var_path("a.y", value="2")
|
||||
|
||||
self.expect("frame variable 'b.x'", error=True,
|
||||
substrs=["no member named 'x' in 'B'"])
|
||||
self.expect(
|
||||
"frame variable 'b.x'",
|
||||
error=True,
|
||||
substrs=['"x" is not a member of "(B) b"'],
|
||||
)
|
||||
#self.expect_var_path("b.y", value="0")
|
||||
self.expect_var_path("b.z", value="3")
|
||||
self.expect_var_path("b.w", value="4")
|
||||
@@ -43,19 +46,31 @@ class TestFrameVarDILMemberOfAnonymousMember(TestBase):
|
||||
self.expect_var_path("d.z", value="9")
|
||||
self.expect_var_path("d.w", value="10")
|
||||
|
||||
self.expect("frame variable 'e.x'", error=True,
|
||||
substrs=["no member named 'x' in 'E'"])
|
||||
self.expect("frame variable 'f.x'", error=True,
|
||||
substrs=["no member named 'x' in 'F'"])
|
||||
self.expect(
|
||||
"frame variable 'e.x'",
|
||||
error=True,
|
||||
substrs=['"x" is not a member of "(E) e"'],
|
||||
)
|
||||
self.expect(
|
||||
"frame variable 'f.x'",
|
||||
error=True,
|
||||
substrs=['"x" is not a member of "(F) f"'],
|
||||
)
|
||||
self.expect_var_path("f.named_field.x", value="12")
|
||||
|
||||
self.expect_var_path("unnamed_derived.y", value="2")
|
||||
self.expect_var_path("unnamed_derived.z", value="13")
|
||||
|
||||
self.expect("frame variable 'derb.x'", error=True,
|
||||
substrs=["no member named 'x' in 'DerivedB'"])
|
||||
self.expect("frame variable 'derb.y'", error=True,
|
||||
substrs=["no member named 'y' in 'DerivedB'"])
|
||||
self.expect(
|
||||
"frame variable 'derb.x'",
|
||||
error=True,
|
||||
substrs=['"x" is not a member of "(DerivedB) derb"'],
|
||||
)
|
||||
self.expect(
|
||||
"frame variable 'derb.y'",
|
||||
error=True,
|
||||
substrs=['"y" is not a member of "(DerivedB) derb"'],
|
||||
)
|
||||
self.expect_var_path("derb.w", value="14")
|
||||
self.expect_var_path("derb.k", value="15")
|
||||
self.expect_var_path("derb.a.x", value="1")
|
||||
|
||||
Reference in New Issue
Block a user