Skip to content

Commit 11ecd47

Browse files
authored
[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.
1 parent ace5108 commit 11ecd47

File tree

5 files changed

+59
-32
lines changed

5 files changed

+59
-32
lines changed

lldb/source/Target/StackFrame.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath(
562562
return ValueObjectConstResult::Create(nullptr, std::move(error));
563563
}
564564

565+
var_sp = (*valobj_or_error)->GetVariable();
565566
return *valobj_or_error;
566567
}
567568

lldb/source/ValueObject/DILEval.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,8 @@ Interpreter::Visit(const MemberOfNode *node) {
363363

364364
if (!m_use_synthetic || !field_obj) {
365365
std::string errMsg = llvm::formatv(
366-
"no member named '{0}' in {1}", node->GetFieldName(),
367-
base->GetCompilerType().GetFullyUnqualifiedType().TypeDescription());
366+
"\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
367+
base->GetTypeName().AsCString("<invalid type>"), base->GetName());
368368
return llvm::make_error<DILDiagnosticError>(
369369
m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
370370
}
@@ -383,9 +383,9 @@ Interpreter::Visit(const MemberOfNode *node) {
383383
CompilerType base_type = base->GetCompilerType();
384384
if (node->GetIsArrow() && base->IsPointerType())
385385
base_type = base_type.GetPointeeType();
386-
std::string errMsg =
387-
llvm::formatv("no member named '{0}' in {1}", node->GetFieldName(),
388-
base_type.GetFullyUnqualifiedType().TypeDescription());
386+
std::string errMsg = llvm::formatv(
387+
"\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
388+
base->GetTypeName().AsCString("<invalid type>"), base->GetName());
389389
return llvm::make_error<DILDiagnosticError>(
390390
m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
391391
}

lldb/source/ValueObject/DILParser.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,14 @@ ASTNodeUP DILParser::ParsePostfixExpression() {
183183
// "(" expression ")"
184184
//
185185
ASTNodeUP DILParser::ParsePrimaryExpression() {
186-
if (CurToken().IsOneOf({Token::coloncolon, Token::identifier})) {
186+
if (CurToken().IsOneOf(
187+
{Token::coloncolon, Token::identifier, Token::l_paren})) {
187188
// Save the source location for the diagnostics message.
188189
uint32_t loc = CurToken().GetLocation();
189-
auto identifier = ParseIdExpression();
190+
std::string identifier = ParseIdExpression();
190191

191-
return std::make_unique<IdentifierNode>(loc, identifier);
192+
if (!identifier.empty())
193+
return std::make_unique<IdentifierNode>(loc, identifier);
192194
}
193195

194196
if (CurToken().Is(Token::l_paren)) {
@@ -232,16 +234,15 @@ std::string DILParser::ParseNestedNameSpecifier() {
232234
m_dil_lexer.LookAhead(4).Is(Token::coloncolon)) {
233235
m_dil_lexer.Advance(4);
234236

235-
assert(
236-
(CurToken().Is(Token::identifier) || CurToken().Is(Token::l_paren)) &&
237-
"Expected an identifier or anonymous namespace, but not found.");
237+
Expect(Token::coloncolon);
238+
m_dil_lexer.Advance();
239+
if (!CurToken().Is(Token::identifier) && !CurToken().Is(Token::l_paren)) {
240+
BailOut("Expected an identifier or anonymous namespace, but not found.",
241+
CurToken().GetLocation(), CurToken().GetSpelling().length());
242+
}
238243
// Continue parsing the nested_namespace_specifier.
239244
std::string identifier2 = ParseNestedNameSpecifier();
240-
if (identifier2.empty()) {
241-
Expect(Token::identifier);
242-
identifier2 = CurToken().GetSpelling();
243-
m_dil_lexer.Advance();
244-
}
245+
245246
return "(anonymous namespace)::" + identifier2;
246247
}
247248

@@ -301,6 +302,9 @@ std::string DILParser::ParseIdExpression() {
301302
nested_name_specifier, unqualified_id);
302303
}
303304

305+
if (!CurToken().Is(Token::identifier))
306+
return "";
307+
304308
// No nested_name_specifier, but with global scope -- this is also a
305309
// qualified_id production. Follow the second production rule.
306310
if (global_scope) {

lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,19 @@ def test_frame_var(self):
3131
self.expect_var_path("sp->x", value="1")
3232
self.expect_var_path("sp->r", type="int &")
3333

34-
self.expect("frame variable 'sp->foo'", error=True,
35-
substrs=["no member named 'foo' in 'Sx *'"])
36-
37-
self.expect("frame variable 'sp.x'", error=True,
38-
substrs=["member reference type 'Sx *' is a "
39-
"pointer; did you mean to use '->'"])
34+
self.expect(
35+
"frame variable 'sp->foo'",
36+
error=True,
37+
substrs=['"foo" is not a member of "(Sx *) sp"'],
38+
)
39+
40+
self.expect(
41+
"frame variable 'sp.x'",
42+
error=True,
43+
substrs=[
44+
"member reference type 'Sx *' is a pointer; did you mean to use '->'"
45+
],
46+
)
4047

4148
# Test for record typedefs.
4249
self.expect_var_path("sa.x", value="3")

lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ def test_frame_var(self):
2727
self.expect_var_path("a.x", value="1")
2828
self.expect_var_path("a.y", value="2")
2929

30-
self.expect("frame variable 'b.x'", error=True,
31-
substrs=["no member named 'x' in 'B'"])
30+
self.expect(
31+
"frame variable 'b.x'",
32+
error=True,
33+
substrs=['"x" is not a member of "(B) b"'],
34+
)
3235
#self.expect_var_path("b.y", value="0")
3336
self.expect_var_path("b.z", value="3")
3437
self.expect_var_path("b.w", value="4")
@@ -43,19 +46,31 @@ def test_frame_var(self):
4346
self.expect_var_path("d.z", value="9")
4447
self.expect_var_path("d.w", value="10")
4548

46-
self.expect("frame variable 'e.x'", error=True,
47-
substrs=["no member named 'x' in 'E'"])
48-
self.expect("frame variable 'f.x'", error=True,
49-
substrs=["no member named 'x' in 'F'"])
49+
self.expect(
50+
"frame variable 'e.x'",
51+
error=True,
52+
substrs=['"x" is not a member of "(E) e"'],
53+
)
54+
self.expect(
55+
"frame variable 'f.x'",
56+
error=True,
57+
substrs=['"x" is not a member of "(F) f"'],
58+
)
5059
self.expect_var_path("f.named_field.x", value="12")
5160

5261
self.expect_var_path("unnamed_derived.y", value="2")
5362
self.expect_var_path("unnamed_derived.z", value="13")
5463

55-
self.expect("frame variable 'derb.x'", error=True,
56-
substrs=["no member named 'x' in 'DerivedB'"])
57-
self.expect("frame variable 'derb.y'", error=True,
58-
substrs=["no member named 'y' in 'DerivedB'"])
64+
self.expect(
65+
"frame variable 'derb.x'",
66+
error=True,
67+
substrs=['"x" is not a member of "(DerivedB) derb"'],
68+
)
69+
self.expect(
70+
"frame variable 'derb.y'",
71+
error=True,
72+
substrs=['"y" is not a member of "(DerivedB) derb"'],
73+
)
5974
self.expect_var_path("derb.w", value="14")
6075
self.expect_var_path("derb.k", value="15")
6176
self.expect_var_path("derb.a.x", value="1")

0 commit comments

Comments
 (0)