xref: /llvm-project/lldb/test/API/commands/expression/fixits/TestFixIts.py (revision 2a436a07ae9749ed4d3f42c0d1e660eb4f7ca6e8)
1"""
2Test calling an expression with errors that a FixIt can fix.
3"""
4
5import lldb
6from lldbsuite.test.decorators import *
7from lldbsuite.test.lldbtest import *
8from lldbsuite.test import lldbutil
9
10
11class ExprCommandWithFixits(TestBase):
12
13    mydir = TestBase.compute_mydir(__file__)
14
15    def test_with_dummy_target(self):
16        """Test calling expressions in the dummy target with errors that can be fixed by the FixIts."""
17
18        # Enable fix-its as they were intentionally disabled by TestBase.setUp.
19        self.runCmd("settings set target.auto-apply-fixits true")
20
21        ret_val = lldb.SBCommandReturnObject()
22        result = self.dbg.GetCommandInterpreter().HandleCommand("expression ((1 << 16) - 1))", ret_val)
23        self.assertEqual(result, lldb.eReturnStatusSuccessFinishResult, "The expression was successful.")
24        self.assertTrue("Fix-it applied" in ret_val.GetError(), "Found the applied FixIt.")
25
26    @expectedFailureAll(archs=["aarch64"], oslist=["linux"])
27    def test_with_target(self):
28        """Test calling expressions with errors that can be fixed by the FixIts."""
29        self.build()
30        (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
31                                        'Stop here to evaluate expressions',
32                                         lldb.SBFileSpec("main.cpp"))
33
34        options = lldb.SBExpressionOptions()
35        options.SetAutoApplyFixIts(True)
36
37        top_level_options = lldb.SBExpressionOptions()
38        top_level_options.SetAutoApplyFixIts(True)
39        top_level_options.SetTopLevel(True)
40
41        frame = self.thread.GetFrameAtIndex(0)
42
43        # Try with one error:
44        value = frame.EvaluateExpression("my_pointer.first", options)
45        self.assertTrue(value.IsValid())
46        self.assertTrue(value.GetError().Success())
47        self.assertEquals(value.GetValueAsUnsigned(), 10)
48
49        # Try with one error in a top-level expression.
50        # The Fix-It changes "ptr.m" to "ptr->m".
51        expr = "struct X { int m; }; X x; X *ptr = &x; int m = ptr.m;"
52        value = frame.EvaluateExpression(expr, top_level_options)
53        # A successfully parsed top-level expression will yield an error
54        # that there is 'no value'. If a parsing error would have happened we
55        # would get a different error kind, so let's check the error kind here.
56        self.assertEquals(value.GetError().GetCString(), "error: No value")
57
58        # Try with two errors:
59        two_error_expression = "my_pointer.second->a"
60        value = frame.EvaluateExpression(two_error_expression, options)
61        self.assertTrue(value.IsValid())
62        self.assertTrue(value.GetError().Success())
63        self.assertEquals(value.GetValueAsUnsigned(), 20)
64
65        # Try a Fix-It that is stored in the 'note:' diagnostic of an error.
66        # The Fix-It here is adding parantheses around the ToStr parameters.
67        fixit_in_note_expr ="#define ToStr(x) #x\nToStr(0 {, })"
68        value = frame.EvaluateExpression(fixit_in_note_expr, options)
69        self.assertTrue(value.IsValid())
70        self.assertTrue(value.GetError().Success(), value.GetError())
71        self.assertEquals(value.GetSummary(), '"(0 {, })"')
72
73        # Now turn off the fixits, and the expression should fail:
74        options.SetAutoApplyFixIts(False)
75        value = frame.EvaluateExpression(two_error_expression, options)
76        self.assertTrue(value.IsValid())
77        self.assertTrue(value.GetError().Fail())
78        error_string = value.GetError().GetCString()
79        self.assertTrue(
80            error_string.find("fixed expression suggested:") != -1,
81            "Fix was suggested")
82        self.assertTrue(
83            error_string.find("my_pointer->second.a") != -1,
84            "Fix was right")
85
86
87        # Test repeatedly applying Fix-Its to expressions and reparsing them.
88        multiple_runs_options = lldb.SBExpressionOptions()
89        multiple_runs_options.SetAutoApplyFixIts(True)
90        multiple_runs_options.SetTopLevel(True)
91
92        # An expression that needs two parse attempts with one Fix-It each
93        # to be successfully parsed.
94        two_runs_expr = """
95        struct Data { int m; };
96
97        template<typename T>
98        struct S1 : public T {
99          using T::TypeDef;
100          int f() {
101            Data d;
102            d.m = 123;
103            // The first error as the using above requires a 'typename '.
104            // Will trigger a Fix-It that puts 'typename' in the right place.
105            typename S1<T>::TypeDef i = &d;
106            // i has the type "Data *", so this should be i.m.
107            // The second run will change the . to -> via the Fix-It.
108            return i.m;
109          }
110        };
111
112        struct ClassWithTypeDef {
113          typedef Data *TypeDef;
114        };
115
116        int test_X(int i) {
117          S1<ClassWithTypeDef> s1;
118          return s1.f();
119        }
120        """
121
122        # Disable retries which will fail.
123        multiple_runs_options.SetRetriesWithFixIts(0)
124        value = frame.EvaluateExpression(two_runs_expr, multiple_runs_options)
125        self.assertIn("expression failed to parse, fixed expression suggested:",
126                      value.GetError().GetCString())
127        self.assertIn("using typename T::TypeDef",
128                      value.GetError().GetCString())
129        # The second Fix-It shouldn't be suggested here as Clang should have
130        # aborted the parsing process.
131        self.assertNotIn("i->m",
132                      value.GetError().GetCString())
133
134        # Retry once, but the expression needs two retries.
135        multiple_runs_options.SetRetriesWithFixIts(1)
136        value = frame.EvaluateExpression(two_runs_expr, multiple_runs_options)
137        self.assertIn("expression failed to parse, fixed expression suggested:",
138                      value.GetError().GetCString())
139        # Both our fixed expressions should be in the suggested expression.
140        self.assertIn("using typename T::TypeDef",
141                      value.GetError().GetCString())
142        self.assertIn("i->m",
143                      value.GetError().GetCString())
144
145        # Retry twice, which will get the expression working.
146        multiple_runs_options.SetRetriesWithFixIts(2)
147        value = frame.EvaluateExpression(two_runs_expr, multiple_runs_options)
148        # This error signals success for top level expressions.
149        self.assertEquals(value.GetError().GetCString(), "error: No value")
150
151        # Test that the code above compiles to the right thing.
152        self.expect_expr("test_X(1)", result_type="int", result_value="123")
153