1""" 2Test the diagnostics emitted by our embeded Clang instance that parses expressions. 3""" 4 5import lldb 6from lldbsuite.test.lldbtest import * 7from lldbsuite.test import lldbutil 8from lldbsuite.test.decorators import * 9 10class ExprDiagnosticsTestCase(TestBase): 11 12 mydir = TestBase.compute_mydir(__file__) 13 14 def setUp(self): 15 # Call super's setUp(). 16 TestBase.setUp(self) 17 18 self.main_source = "main.cpp" 19 self.main_source_spec = lldb.SBFileSpec(self.main_source) 20 21 def test_source_and_caret_printing(self): 22 """Test that the source and caret positions LLDB prints are correct""" 23 self.build() 24 25 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, 26 '// Break here', self.main_source_spec) 27 frame = thread.GetFrameAtIndex(0) 28 29 # Test that source/caret are at the right position. 30 value = frame.EvaluateExpression("unknown_identifier") 31 self.assertFalse(value.GetError().Success()) 32 # We should get a nice diagnostic with a caret pointing at the start of 33 # the identifier. 34 self.assertIn("\nunknown_identifier\n^\n", value.GetError().GetCString()) 35 self.assertIn("<user expression 0>:1:1", value.GetError().GetCString()) 36 37 # Same as above but with the identifier in the middle. 38 value = frame.EvaluateExpression("1 + unknown_identifier ") 39 self.assertFalse(value.GetError().Success()) 40 self.assertIn("\n1 + unknown_identifier", value.GetError().GetCString()) 41 self.assertIn("\n ^\n", value.GetError().GetCString()) 42 43 # Multiline expressions. 44 value = frame.EvaluateExpression("int a = 0;\nfoobar +=1;\na") 45 self.assertFalse(value.GetError().Success()) 46 # We should still get the right line information and caret position. 47 self.assertIn("\nfoobar +=1;\n^\n", value.GetError().GetCString()) 48 # It's the second line of the user expression. 49 self.assertIn("<user expression 2>:2:1", value.GetError().GetCString()) 50 51 # Top-level expressions. 52 top_level_opts = lldb.SBExpressionOptions(); 53 top_level_opts.SetTopLevel(True) 54 55 value = frame.EvaluateExpression("void foo(unknown_type x) {}", top_level_opts) 56 self.assertFalse(value.GetError().Success()) 57 self.assertIn("\nvoid foo(unknown_type x) {}\n ^\n", value.GetError().GetCString()) 58 # Top-level expressions might use a different wrapper code, but the file name should still 59 # be the same. 60 self.assertIn("<user expression 3>:1:10", value.GetError().GetCString()) 61 62 # Multiline top-level expressions. 63 value = frame.EvaluateExpression("void x() {}\nvoid foo;", top_level_opts) 64 self.assertFalse(value.GetError().Success()) 65 self.assertIn("\nvoid foo;\n ^", value.GetError().GetCString()) 66 self.assertIn("<user expression 4>:2:6", value.GetError().GetCString()) 67 68 # Test that we render Clang's 'notes' correctly. 69 value = frame.EvaluateExpression("struct SFoo{}; struct SFoo { int x; };", top_level_opts) 70 self.assertFalse(value.GetError().Success()) 71 self.assertIn("<user expression 5>:1:8: previous definition is here\nstruct SFoo{}; struct SFoo { int x; };\n ^\n", value.GetError().GetCString()) 72 73 # Declarations from the debug information currently have no debug information. It's not clear what 74 # we should do in this case, but we should at least not print anything that's wrong. 75 # In the future our declarations should have valid source locations. 76 value = frame.EvaluateExpression("struct FooBar { double x };", top_level_opts) 77 self.assertFalse(value.GetError().Success()) 78 self.assertEqual("error: <user expression 6>:1:8: redefinition of 'FooBar'\nstruct FooBar { double x };\n ^\n", value.GetError().GetCString()) 79 80 value = frame.EvaluateExpression("foo(1, 2)") 81 self.assertFalse(value.GetError().Success()) 82 self.assertEqual("error: <user expression 7>:1:1: no matching function for call to 'foo'\nfoo(1, 2)\n^~~\nnote: candidate function not viable: requires single argument 'x', but 2 arguments were provided\n\n", value.GetError().GetCString()) 83 84 # Redefine something that we defined in a user-expression. We should use the previous expression file name 85 # for the original decl. 86 value = frame.EvaluateExpression("struct Redef { double x; };", top_level_opts) 87 value = frame.EvaluateExpression("struct Redef { float y; };", top_level_opts) 88 self.assertFalse(value.GetError().Success()) 89 self.assertIn("error: <user expression 9>:1:8: redefinition of 'Redef'\nstruct Redef { float y; };\n ^\n<user expression 8>:1:8: previous definition is here\nstruct Redef { double x; };\n ^", value.GetError().GetCString()) 90 91 @add_test_categories(["objc"]) 92 def test_source_locations_from_objc_modules(self): 93 self.build() 94 95 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, 96 '// Break here', self.main_source_spec) 97 frame = thread.GetFrameAtIndex(0) 98 99 # Import foundation so that the Obj-C module is loaded (which contains source locations 100 # that can be used by LLDB). 101 self.runCmd("expr @import Foundation") 102 value = frame.EvaluateExpression("NSLog(1);") 103 self.assertFalse(value.GetError().Success()) 104 # LLDB should print the source line that defines NSLog. To not rely on any 105 # header paths/line numbers or the actual formatting of the Foundation headers, only look 106 # for a few tokens in the output. 107 # File path should come from Foundation framework. 108 self.assertIn("/Foundation.framework/", value.GetError().GetCString()) 109 # The NSLog definition source line should be printed. Return value and 110 # the first argument are probably stable enough that this test can check for them. 111 self.assertIn("void NSLog(NSString *format", value.GetError().GetCString()) 112 113