[lldb][NFC] Add some tests for function-local classes and document some bugs

This feature doesn't seem to have any dedicated test. Instead some random tests
(e.g. the bitfield tests) are declaring function-local classes for some reason.
This adds a dedicated test so we can clean up those other tests.

Also add FIXME's for some basic stuff that doesn't work. The first FIXME is a
good beginner bug which just requires prepending the function name (in case we
decide to fix it instead of documenting this behaviour). The second FIXME is
caused by LLDB searching for definitions by name (which also seems to miss the
function name so there is a conflict with the outer type).

Some more things that should be tested (and might not work):
* Local classes with member functions with local classes.
* Classes in different functions with same name.
* Classes with the same name in different TUs with internal linkage functions of
  the same name.
* Empty classes are parsed by the DWARF parser in a fast path, so that requires
  dedicated tests.
* Repeat some of the tested logic for C.
This commit is contained in:
Raphael Isemann 2021-08-31 13:02:39 +02:00
parent 6c8ff4032e
commit cda1450f1c
3 changed files with 105 additions and 0 deletions

View File

@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp
include Makefile.rules

View File

@ -0,0 +1,58 @@
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class TestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@no_debug_info_test
def test(self):
self.build()
lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.cpp"))
m_val = self.expect_expr("m", result_type="WithMember", result_children=[
ValueCheck(name="i", value="1")
])
# FIXME: The non-display name doesn't include the function, so users
# can't actually match specific classes by their name. Either document
# or fix this.
self.assertEqual(m_val.GetType().GetName(), "WithMember")
# Try accessing the type in the expression evaluator.
self.expect_expr("m.i", result_type="int", result_value="1")
self.expect_expr("typedef_unnamed", result_type="TypedefUnnamed", result_children=[
ValueCheck(name="a", value="2")
])
self.expect_expr("typedef_unnamed2", result_type="TypedefUnnamed2", result_children=[
ValueCheck(name="b", value="3")
])
self.expect_expr("unnamed", result_type="(unnamed struct)", result_children=[
ValueCheck(name="i", value="4")
])
self.expect_expr("unnamed2", result_type="(unnamed struct)", result_children=[
ValueCheck(name="j", value="5")
])
# Try a class that is only forward declared.
self.expect_expr("fwd", result_type="Forward *")
self.expect("expression -- fwd->i", error=True, substrs=[
"member access into incomplete type 'Forward'"
])
self.expect("expression -- *fwd", error=True, substrs=[
"incomplete type 'Forward' where a complete type is required"
])
# Try a class that has a name that matches a class in the global scope.
self.expect_expr("fwd_conflict", result_type="ForwardConflict *")
# FIXME: This pulls in the unrelated type with the same name from the
# global scope.
self.expect("expression -- fwd_conflict->i", error=True, substrs=[
# This should point out that ForwardConflict is incomplete.
"no member named 'i' in 'ForwardConflict'"
])
self.expect("expression -- *fwd_conflict", error=True, substrs=[
# This should fail to parse instead.
"couldn't read its memory"
])

View File

@ -0,0 +1,44 @@
// These declarations have intentionally the same name as the function-local
// class. LLDB should never pull in these definitions as this test only inspects
// the classes defined in the function below.
struct WithMember {
float false_def;
};
typedef struct {
float false_def;
} TypedefUnnamed;
struct ForwardConflict {
float false_def;
};
ForwardConflict conflict1;
WithMember conflict2;
struct {
float false_def;
} unnamed;
int main() {
struct WithMember {
int i;
};
typedef struct {
int a;
} TypedefUnnamed;
typedef struct {
int b;
} TypedefUnnamed2;
struct Forward;
struct ForwardConflict;
WithMember m = {1};
TypedefUnnamed typedef_unnamed = {2};
TypedefUnnamed2 typedef_unnamed2 = {3};
struct {
int i;
} unnamed = {4};
struct {
int j;
} unnamed2 = {5};
Forward *fwd = nullptr;
ForwardConflict *fwd_conflict = nullptr;
return 0; // break here
}