@@ -2,49 +2,98 @@ import cpp
2
2
import codingstandards.cpp.misra
3
3
4
4
/**
5
- * The signedness of a numeric type.
5
+ * A MISRA C++ 2023 type category .
6
6
*/
7
- newtype Signedness =
8
- Signed ( ) or
9
- Unsigned ( )
7
+ newtype TypeCategory =
8
+ Integral ( ) or
9
+ FloatingPoint ( ) or
10
+ Character ( ) or
11
+ Other ( )
10
12
11
13
/**
12
- * The type category of a numeric type - either integral or floating-point.
14
+ * Gets the type category of a built-in type.
15
+ *
16
+ * This does not apply the rules related to stripping specifiers or typedefs, or references.
13
17
*/
14
- newtype TypeCategory =
15
- Integral ( ) or
16
- FloatingPoint ( )
18
+ TypeCategory getTypeCategory ( BuiltInType t ) {
19
+ (
20
+ t instanceof CharType or
21
+ t instanceof WideCharType or
22
+ t instanceof Char16Type or
23
+ t instanceof Char32Type or
24
+ t instanceof Char8Type
25
+ ) and
26
+ result = Character ( )
27
+ or
28
+ (
29
+ // The 5 standard integral types, covering both signed/unsigned variants
30
+ // Explicitly list the signed/unsigned `char` to avoid capturing plain `char`, which is of character type category
31
+ t instanceof SignedCharType or
32
+ t instanceof UnsignedCharType or
33
+ t instanceof ShortType or
34
+ t instanceof IntType or
35
+ t instanceof LongType or
36
+ t instanceof LongLongType
37
+ ) and
38
+ result = Integral ( )
39
+ or
40
+ (
41
+ t instanceof FloatType or
42
+ t instanceof DoubleType or
43
+ t instanceof LongDoubleType
44
+ ) and
45
+ result = FloatingPoint ( )
46
+ or
47
+ (
48
+ t instanceof BoolType or
49
+ t instanceof VoidType or
50
+ t instanceof NullPointerType
51
+ ) and
52
+ result = Other ( )
53
+ }
17
54
18
55
/**
19
- * A numeric type is a type that represents a number, either an integral or a floating-point.
56
+ * The signedness of a MISRA C++ 2023 numeric type
57
+ */
58
+ newtype Signedness =
59
+ Signed ( ) or
60
+ Unsigned ( )
61
+
62
+ /**
63
+ * A MISRA C++ 2023 numeric type is a type that represents a number, either an integral or a floating-point.
20
64
*
21
65
* In addition to the basic integral and floating-point types, it includes:
22
66
* - Enum types with an explicit underlying type that is a numeric type.
23
67
* - Typedef'd types that are numeric types.
24
68
* - Numeric types with specifiers (e.g., `const`, `volatile`, `restrict`).
25
69
*/
26
70
class NumericType extends Type {
71
+ // The actual numeric type, which is either an integral or a floating-point type.
27
72
Type realType ;
28
73
29
74
NumericType ( ) {
30
- realType = this .getUnspecifiedType ( ) .( ReferenceType ) .getBaseType ( ) .( NumericType ) .getRealType ( ) or
31
- realType = this .getUnspecifiedType ( ) .( IntegralType ) or
32
- realType = this .getUnspecifiedType ( ) .( FloatingPointType ) or
33
- realType = this .getUnspecifiedType ( ) .( Enum ) .getExplicitUnderlyingType ( ) .getUnspecifiedType ( )
75
+ // A type which is either an integral or a floating-point type category
76
+ getTypeCategory ( this ) = [ Integral ( ) .( TypeCategory ) , FloatingPoint ( ) ] and
77
+ realType = this
78
+ or
79
+ // Any type which, after stripping specifiers and typedefs, is a numeric type
80
+ realType = this .getUnspecifiedType ( ) .( NumericType ) .getRealType ( )
81
+ or
82
+ // Any reference type where the base type is a numeric type
83
+ realType = this .( ReferenceType ) .getBaseType ( ) .( NumericType ) .getRealType ( )
84
+ or
85
+ // Any Enum type with an explicit underlying type that is a numeric type
86
+ realType = this .( Enum ) .getExplicitUnderlyingType ( ) .( NumericType ) .getRealType ( )
34
87
}
35
88
36
89
Signedness getSignedness ( ) {
37
90
if realType .( IntegralType ) .isUnsigned ( ) then result = Unsigned ( ) else result = Signed ( )
38
91
}
39
92
40
- /** Gets the size of the actual numeric type */
93
+ /** Gets the size of the actual numeric type. */
41
94
int getRealSize ( ) { result = realType .getSize ( ) }
42
95
43
- TypeCategory getTypeCategory ( ) {
44
- realType instanceof IntegralType and result = Integral ( )
45
- or
46
- realType instanceof FloatingPointType and result = FloatingPoint ( )
47
- }
96
+ TypeCategory getTypeCategory ( ) { result = getTypeCategory ( realType ) }
48
97
49
98
float getUpperBound ( ) { result = typeUpperBound ( realType ) }
50
99
@@ -53,6 +102,13 @@ class NumericType extends Type {
53
102
Type getRealType ( ) { result = realType }
54
103
}
55
104
105
+ /**
106
+ * One of the 10 canonical integer types, which are the standard integer types.
107
+ */
108
+ class CanonicalIntegerTypes extends NumericType , IntegralType {
109
+ CanonicalIntegerTypes ( ) { this = this .getCanonicalArithmeticType ( ) }
110
+ }
111
+
56
112
predicate isAssignment ( Expr source , NumericType targetType , string context ) {
57
113
// Assignment expression (which excludes compound assignments)
58
114
exists ( AssignExpr assign |
@@ -119,18 +175,24 @@ predicate isAssignment(Expr source, NumericType targetType, string context) {
119
175
*
120
176
* The type is determined by the signedness of the bit field and the number of bits.
121
177
*/
122
- NumericType getBitFieldType ( BitField bf ) {
178
+ CanonicalIntegerTypes getBitFieldType ( BitField bf ) {
123
179
exists ( NumericType bitfieldActualType |
124
180
bitfieldActualType = bf .getType ( ) and
125
181
// Integral type with the same signedness as the bit field, and big enough to hold the bit field value
126
- result instanceof IntegralType and
127
182
result .getSignedness ( ) = bitfieldActualType .getSignedness ( ) and
128
183
result .getSize ( ) * 8 >= bf .getNumBits ( ) and
129
184
// No smaller integral type can hold the bit field value
130
- not exists ( IntegralType other |
185
+ not exists ( CanonicalIntegerTypes other |
131
186
other .getSize ( ) * 8 >= bf .getNumBits ( ) and
132
- other .( NumericType ) .getSignedness ( ) = result .getSignedness ( ) and
187
+ other .getSignedness ( ) = result .getSignedness ( )
188
+ |
133
189
other .getSize ( ) < result .getRealSize ( )
190
+ or
191
+ // Where multiple types exist with the same size and signedness, prefer shorter names - mainly
192
+ // to disambiguate between `unsigned long` and `unsigned long long` on platforms where they
193
+ // are the same size
194
+ other .getSize ( ) = result .getRealSize ( ) and
195
+ other .getName ( ) .length ( ) < result .getName ( ) .length ( )
134
196
)
135
197
)
136
198
}
0 commit comments