From 6fa2d68c0c9414bf426378479dd90d1c9f67ad18 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Wed, 11 Jul 2018 21:51:48 -0700 Subject: [PATCH] type: add Type.unqualified() --- drgn/type.py | 39 ++++++++++++++++++++++++++++----------- tests/test_type.py | 44 +++++++++++++++++++++++++++++++------------- 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/drgn/type.py b/drgn/type.py index 8ca24312..05bd51e1 100644 --- a/drgn/type.py +++ b/drgn/type.py @@ -164,12 +164,18 @@ class Type: """ return self + def unqualified(self) -> 'Type': + """ + Return this type without qualifiers. + """ + raise NotImplementedError() + def operand_type(self) -> 'Type': """ Return the type that this type is converted to when used in an expression. """ - raise NotImplementedError() + return self.unqualified() def is_arithmetic(self) -> bool: """ @@ -217,7 +223,7 @@ class VoidType(Type): def convert(self, value: Any) -> None: return None - def operand_type(self) -> 'VoidType': + def unqualified(self) -> 'VoidType': if self.qualifiers: return VoidType() return self @@ -310,7 +316,7 @@ class IntType(ArithmeticType): raise TypeError(f'cannot convert to {self}') return _int_convert(math.trunc(value), 8 * self.size, self.signed) - def operand_type(self) -> 'IntType': + def unqualified(self) -> 'IntType': if self.qualifiers: return IntType(self.name, self.size, self.signed) return self @@ -346,7 +352,7 @@ class BoolType(IntType): raise TypeError(f'cannot convert to {self}') return bool(value) - def operand_type(self) -> 'BoolType': + def unqualified(self) -> 'BoolType': if self.qualifiers: return BoolType(self.name, self.size) return self @@ -375,7 +381,7 @@ class FloatType(ArithmeticType): else: raise ValueError(f"can't convert to float of size {self.size}") - def operand_type(self) -> 'FloatType': + def unqualified(self) -> 'FloatType': if self.qualifiers: return FloatType(self.name, self.size) return self @@ -457,9 +463,9 @@ class BitFieldType(Type): raise TypeError(f'cannot convert to {self}') return _int_convert(math.trunc(value), self.bit_size, self.type.signed) - def operand_type(self) -> 'BitFieldType': + def unqualified(self) -> 'BitFieldType': if self.type.qualifiers: - return BitFieldType(self.type.operand_type(), self.bit_offset, + return BitFieldType(self.type.unqualified(), self.bit_offset, self.bit_size) return self @@ -656,7 +662,7 @@ class StructType(CompoundType): def type_name(self) -> StructTypeName: return StructTypeName(self.name, self.qualifiers) - def operand_type(self) -> 'StructType': + def unqualified(self) -> 'StructType': if self.qualifiers: return StructType(self.name, self.size, self._members) return self @@ -684,7 +690,7 @@ class UnionType(CompoundType): def type_name(self) -> UnionTypeName: return UnionTypeName(self.name, self.qualifiers) - def operand_type(self) -> 'UnionType': + def unqualified(self) -> 'UnionType': if self.qualifiers: return UnionType(self.name, self.size, self._members) return self @@ -806,7 +812,7 @@ class EnumType(Type): pass return value - def operand_type(self) -> 'EnumType': + def unqualified(self) -> 'EnumType': if self.qualifiers: return EnumType(self.name, self.type, None if self.enum is None else self.enum.__members__) @@ -883,6 +889,11 @@ class TypedefType(Type): type_ = type_.type return type_ + def unqualified(self) -> 'TypedefType': + if self.qualifiers: + return TypedefType(self.name, self.type) + return self + def operand_type(self) -> Type: type_ = self.type while isinstance(type_, TypedefType): @@ -957,7 +968,7 @@ class PointerType(Type): raise TypeError(f'cannot convert to {self}') return _int_convert(int(value), 8 * self.size, False) - def operand_type(self) -> 'PointerType': + def unqualified(self) -> 'PointerType': if self.qualifiers: return PointerType(self.size, self.type) return self @@ -1041,6 +1052,9 @@ class ArrayType(Type): parts.append('}') return ''.join(parts) + def unqualified(self) -> 'ArrayType': + return self + def operand_type(self) -> 'PointerType': return PointerType(self.pointer_size, self.type) @@ -1103,6 +1117,9 @@ class FunctionType(Type): def pretty(self, value: Any, cast: bool = True) -> str: raise ValueError("can't format function") + def unqualified(self) -> 'FunctionType': + return self + def operand_type(self) -> 'PointerType': return PointerType(self.pointer_size, self) diff --git a/tests/test_type.py b/tests/test_type.py index 12d492df..413255c9 100644 --- a/tests/test_type.py +++ b/tests/test_type.py @@ -545,37 +545,46 @@ class TestConvert(unittest.TestCase): self.assertEqual(type_.convert(2**64 + 1), 1) -class TestOperandType(TypeTestCase): +class TestUnqualifiedAndOperandType(TypeTestCase): + def assertUnqualifiedType(self, type_, expected): + for i in range(2): + type_ = type_.unqualified() + self.assertEqual(type_, expected) + def assertOperandType(self, type_, expected): for i in range(2): type_ = type_.operand_type() self.assertEqual(type_, expected) + def assertBoth(self, type_, expected): + self.assertUnqualifiedType(type_, expected) + self.assertOperandType(type_, expected) + def test_void(self): - self.assertOperandType(VoidType(frozenset({'const'})), VoidType()) + self.assertBoth(VoidType(frozenset({'const'})), VoidType()) def test_int(self): - self.assertOperandType(IntType('int', 4, True, frozenset({'const'})), - IntType('int', 4, True)) + self.assertBoth(IntType('int', 4, True, frozenset({'const'})), + IntType('int', 4, True)) def test_bool(self): - self.assertOperandType(BoolType('_Bool', 1, frozenset({'const'})), - BoolType('_Bool', 1)) + self.assertBoth(BoolType('_Bool', 1, frozenset({'const'})), + BoolType('_Bool', 1)) def test_float(self): - self.assertOperandType(FloatType('double', 8, frozenset({'const'})), - FloatType('double', 8)) + self.assertBoth(FloatType('double', 8, frozenset({'const'})), + FloatType('double', 8)) def test_bit_field(self): - self.assertOperandType(BitFieldType(IntType('int', 4, True, frozenset({'const'})), 0, 4), - BitFieldType(IntType('int', 4, True), 0, 4)) + self.assertBoth(BitFieldType(IntType('int', 4, True, frozenset({'const'})), 0, 4), + BitFieldType(IntType('int', 4, True), 0, 4)) def test_struct(self): const_point_type = StructType('point', 8, [ ('x', 0, lambda: IntType('int', 4, True)), ('y', 4, lambda: IntType('int', 4, True)), ], frozenset({'const'})) - self.assertOperandType(const_point_type, point_type) + self.assertBoth(const_point_type, point_type) def test_union(self): union_type = UnionType('value', 4, [ @@ -586,7 +595,7 @@ class TestOperandType(TypeTestCase): ('i', 0, lambda: IntType('int', 4, True)), ('f', 0, lambda: FloatType('float', 4)), ], frozenset({'const'})) - self.assertOperandType(const_union_type, union_type) + self.assertBoth(const_union_type, union_type) def test_enum(self): enum_type = EnumType(None, IntType('int', 4, True), [ @@ -599,7 +608,7 @@ class TestOperandType(TypeTestCase): ('GREEN', 11), ('BLUE', -1) ], frozenset({'const'})) - self.assertOperandType(const_enum_type, enum_type) + self.assertBoth(const_enum_type, enum_type) def test_typedef(self): const_typedef_type = TypedefType( @@ -610,9 +619,14 @@ class TestOperandType(TypeTestCase): frozenset({'const'})) typedef_type = TypedefType('u32', IntType('unsigned int', 4, False)) + self.assertUnqualifiedType(const_typedef_type, typedef_type) self.assertOperandType(const_typedef_type, typedef_type) + + self.assertUnqualifiedType(typedef_const_type, typedef_const_type) self.assertOperandType(typedef_const_type, IntType('unsigned int', 4, False)) + + self.assertUnqualifiedType(const_typedef_const_type, typedef_const_type) self.assertOperandType(const_typedef_const_type, IntType('unsigned int', 4, False)) @@ -630,16 +644,20 @@ class TestOperandType(TypeTestCase): def test_array(self): type_ = ArrayType(IntType('int', 4, True), 2, pointer_size) + self.assertUnqualifiedType(type_, type_) self.assertOperandType(type_, PointerType(pointer_size, type_.type)) typedef_type = TypedefType('pair_t', type_) + self.assertUnqualifiedType(typedef_type, typedef_type) self.assertOperandType(typedef_type, PointerType(pointer_size, type_.type)) def test_function(self): type_ = FunctionType(pointer_size, VoidType, []) + self.assertUnqualifiedType(type_, type_) self.assertOperandType(type_, PointerType(pointer_size, type_)) typedef_type = TypedefType('callback_t', type_) + self.assertUnqualifiedType(typedef_type, typedef_type) self.assertOperandType(typedef_type, PointerType(pointer_size, type_))