brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.4 KiB · 759b620 Raw
275 lines · python
1"""2Test the diagnostics emitted by our embeded Clang instance that parses expressions.3"""4 5import lldb6from lldbsuite.test.lldbtest import *7from lldbsuite.test import lldbutil8from lldbsuite.test.decorators import *9 10 11class ExprDiagnosticsTestCase(TestBase):12    def setUp(self):13        # Call super's setUp().14        TestBase.setUp(self)15 16        self.main_source = "main.cpp"17        self.main_source_spec = lldb.SBFileSpec(self.main_source)18 19    def test_source_and_caret_printing(self):20        """Test that the source and caret positions LLDB prints are correct"""21        self.build()22 23        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(24            self, "// Break here", self.main_source_spec25        )26        frame = thread.GetFrameAtIndex(0)27 28        # Test that source/caret are at the right position.29        value = frame.EvaluateExpression("unknown_identifier")30        self.assertFalse(value.GetError().Success())31        # We should get a nice diagnostic with a caret pointing at the start of32        # the identifier.33        self.assertIn(34            """35    1 | unknown_identifier36      | ^~~~~~~~~~~~~~~~~~37""",38            value.GetError().GetCString(),39        )40        self.assertIn("<user expression 0>:1:1", value.GetError().GetCString())41 42        # Same as above but with the identifier in the middle.43        value = frame.EvaluateExpression("1 + unknown_identifier")44        self.assertFalse(value.GetError().Success())45        self.assertIn(46            """47    1 | 1 + unknown_identifier48      |     ^~~~~~~~~~~~~~~~~~49""",50            value.GetError().GetCString(),51        )52 53        # Multiline expressions.54        value = frame.EvaluateExpression("int a = 0;\nfoobar +=1;\na")55        self.assertFalse(value.GetError().Success())56        # We should still get the right line information and caret position.57        self.assertIn(58            """59    2 | foobar +=1;60      | ^~~~~~61""",62            value.GetError().GetCString(),63        )64 65        # It's the second line of the user expression.66        self.assertIn("<user expression 2>:2:1", value.GetError().GetCString())67 68        # Top-level expressions.69        top_level_opts = lldb.SBExpressionOptions()70        top_level_opts.SetTopLevel(True)71 72        value = frame.EvaluateExpression("void foo(unknown_type x) {}", top_level_opts)73        self.assertFalse(value.GetError().Success())74        self.assertIn(75            """76    1 | void foo(unknown_type x) {}77      |          ^78""",79            value.GetError().GetCString(),80        )81 82        # Top-level expressions might use a different wrapper code, but the file name should still83        # be the same.84        self.assertIn("<user expression 3>:1:10", value.GetError().GetCString())85 86        # Multiline top-level expressions.87        value = frame.EvaluateExpression("void x() {}\nvoid foo;", top_level_opts)88        self.assertFalse(value.GetError().Success())89        self.assertIn(90            """91    2 | void foo;92      |      ^93""",94            value.GetError().GetCString(),95        )96 97        self.assertIn("<user expression 4>:2:6", value.GetError().GetCString())98 99        # Test that we render Clang's 'notes' correctly.100        value = frame.EvaluateExpression(101            "struct SFoo{}; struct SFoo { int x; };", top_level_opts102        )103        self.assertFalse(value.GetError().Success())104        self.assertIn(105            "<user expression 5>:1:8: previous definition is here\n",106            value.GetError().GetCString(),107        )108        self.assertIn(109            """110    1 | struct SFoo{}; struct SFoo { int x; };111      |        ^112""",113            value.GetError().GetCString(),114        )115 116        # Declarations from the debug information currently have no debug information. It's not clear what117        # we should do in this case, but we should at least not print anything that's wrong.118        # In the future our declarations should have valid source locations.119        value = frame.EvaluateExpression("struct FooBar { double x };", top_level_opts)120        self.assertFalse(value.GetError().Success())121        self.assertIn(122            "error: <user expression 6>:1:8: redefinition of 'FooBar'\n",123            value.GetError().GetCString(),124        )125        self.assertIn(126            """127    1 | struct FooBar { double x };128      |        ^129""",130            value.GetError().GetCString(),131        )132 133        value = frame.EvaluateExpression("foo(1, 2)")134        self.assertFalse(value.GetError().Success())135        self.assertIn(136            "error: <user expression 7>:1:1: no matching function for call to 'foo'\n",137            value.GetError().GetCString(),138        )139        self.assertIn(140            """141    1 | foo(1, 2)142      | ^~~143note: candidate function not viable: requires single argument 'x', but 2 arguments were provided144""",145            value.GetError().GetCString(),146        )147 148        # Redefine something that we defined in a user-expression. We should use the previous expression file name149        # for the original decl.150        value = frame.EvaluateExpression("struct Redef { double x; };", top_level_opts)151        value = frame.EvaluateExpression("struct Redef { float y; };", top_level_opts)152        self.assertFalse(value.GetError().Success())153        self.assertIn(154            """error: <user expression 9>:1:8: redefinition of 'Redef'155    1 | struct Redef { float y; };156      |        ^157<user expression 8>:1:8: previous definition is here158    1 | struct Redef { double x; };159      |        ^160""",161            value.GetError().GetCString(),162        )163 164    @add_test_categories(["objc"])165    def test_source_locations_from_objc_modules(self):166        self.build()167 168        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(169            self, "// Break here", self.main_source_spec170        )171        frame = thread.GetFrameAtIndex(0)172 173        # Import foundation so that the Obj-C module is loaded (which contains source locations174        # that can be used by LLDB).175        self.runCmd("expr --language objective-c++ -- @import Foundation")176        value = frame.EvaluateExpression("NSLog(1);")177        self.assertFalse(value.GetError().Success())178        # LLDB should print the source line that defines NSLog. To not rely on any179        # header paths/line numbers or the actual formatting of the Foundation headers, only look180        # for a few tokens in the output.181        # File path should come from Foundation framework.182        self.assertIn("/Foundation.framework/", value.GetError().GetCString())183        # The NSLog definition source line should be printed. Return value and184        # the first argument are probably stable enough that this test can check for them.185        self.assertIn("void NSLog(NSString *format", value.GetError().GetCString())186 187    def test_error_type(self):188        """Test the error reporting in the API"""189        self.build()190 191        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(192            self, "// Break here", self.main_source_spec193        )194        frame = thread.GetFrameAtIndex(0)195        value = frame.EvaluateExpression('#error("I am error.")')196        error = value.GetError()197        self.assertEqual(error.GetType(), lldb.eErrorTypeExpression)198        value = frame.FindVariable("f")199        self.assertTrue(value.IsValid())200        desc = value.GetObjectDescription()201        self.assertEqual(desc, None)202 203    def test_command_expr_sbdata(self):204        """Test the structured diagnostics data"""205        self.build()206 207        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(208            self, "// Break here", self.main_source_spec209        )210 211        def check_error(diags):212            # Version.213            version = diags.GetValueForKey("version")214            self.assertEqual(version.GetIntegerValue(), 1)215 216            details = diags.GetValueForKey("details")217 218            # Detail 1/3: note: requested expression language219            diag = details.GetItemAtIndex(0)220            self.assertEqual(str(diag.GetValueForKey("severity")), "note")221            self.assertIn("Ran expression as 'C++", str(diag.GetValueForKey("message")))222            self.assertIn(223                "Ran expression as 'C++", str(diag.GetValueForKey("rendered"))224            )225            self.assertEqual(str(diag.GetValueForKey("source_location")), "")226            self.assertEqual(str(diag.GetValueForKey("file")), "")227            self.assertFalse(diag.GetValueForKey("hidden").GetBooleanValue())228            self.assertFalse(diag.GetValueForKey("in_user_input").GetBooleanValue())229 230            # Detail 2/3: undeclared 'a'231            diag = details.GetItemAtIndex(1)232 233            severity = diag.GetValueForKey("severity")234            message = diag.GetValueForKey("message")235            rendered = diag.GetValueForKey("rendered")236            sloc = diag.GetValueForKey("source_location")237            filename = sloc.GetValueForKey("file")238            hidden = sloc.GetValueForKey("hidden")239            in_user_input = sloc.GetValueForKey("in_user_input")240 241            self.assertEqual(str(severity), "error")242            self.assertIn("undeclared identifier 'a'", str(message))243            # The rendered string should contain the source file.244            self.assertIn("user expression", str(rendered))245            self.assertIn("user expression", str(filename))246            self.assertFalse(hidden.GetBooleanValue())247            self.assertTrue(in_user_input.GetBooleanValue())248 249            # Detail 3/3: undeclared 'b'250            diag = details.GetItemAtIndex(2)251            message = diag.GetValueForKey("message")252            self.assertIn("undeclared identifier 'b'", str(message))253 254        # Test diagnostics in CommandReturnObject255        interp = self.dbg.GetCommandInterpreter()256        cro = lldb.SBCommandReturnObject()257        interp.HandleCommand("expression -- a+b", cro)258 259        diags = cro.GetErrorData()260        check_error(diags)261 262        # Test diagnostics in SBError263        frame = thread.GetSelectedFrame()264        value = frame.EvaluateExpression("a+b")265        error = value.GetError()266        self.assertTrue(error.Fail())267        self.assertEqual(error.GetType(), lldb.eErrorTypeExpression)268        data = error.GetErrorData()269        version = data.GetValueForKey("version")270        self.assertEqual(version.GetIntegerValue(), 1)271        err_ty = data.GetValueForKey("type")272        self.assertEqual(err_ty.GetIntegerValue(), lldb.eErrorTypeExpression)273        diags = data.GetValueForKey("errors").GetItemAtIndex(0)274        check_error(diags)275