|
15 | 15 |
|
16 | 16 | import cpp |
17 | 17 | import codingstandards.cpp.misra |
| 18 | +import codingstandards.cpp.misra.ArithmeticConversions |
18 | 19 | import codingstandards.cpp.misra.BuiltInTypeRules |
19 | 20 |
|
20 | | -/** |
21 | | - * An expression that represents a integral promotion or usual arithmetic conversion. |
22 | | - * |
23 | | - * Such conversions are usual either explicitly described with a `Cast`, or, in the case |
24 | | - * of assign operations, implicitly applied to an lvalue. |
25 | | - */ |
26 | | -abstract class IntegerPromotionOrUsualArithmeticConversion extends Expr { |
27 | | - abstract MisraCpp23BuiltInTypes::NumericType getFromType(); |
28 | | - |
29 | | - abstract MisraCpp23BuiltInTypes::NumericType getToType(); |
30 | | - |
31 | | - abstract Expr getConvertedExpr(); |
32 | | - |
33 | | - abstract string getKindOfConversion(); |
34 | | -} |
35 | | - |
36 | | -/** |
37 | | - * A `Cast` which is either an integer promotion or usual arithmetic conversion. |
38 | | - */ |
39 | | -abstract class IntegerPromotionOrUsualArithmeticConversionAsCast extends IntegerPromotionOrUsualArithmeticConversion, |
40 | | - Cast |
41 | | -{ |
42 | | - MisraCpp23BuiltInTypes::NumericType fromType; |
43 | | - MisraCpp23BuiltInTypes::NumericType toType; |
44 | | - |
45 | | - IntegerPromotionOrUsualArithmeticConversionAsCast() { |
46 | | - fromType = this.getExpr().getType() and |
47 | | - toType = this.getType() and |
48 | | - this.isImplicit() |
49 | | - } |
50 | | - |
51 | | - override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } |
52 | | - |
53 | | - override MisraCpp23BuiltInTypes::NumericType getToType() { result = toType } |
54 | | - |
55 | | - override Expr getConvertedExpr() { result = this.getExpr() } |
56 | | -} |
57 | | - |
58 | | -class UsualArithmeticConversion extends IntegerPromotionOrUsualArithmeticConversionAsCast { |
59 | | - UsualArithmeticConversion() { |
60 | | - ( |
61 | | - // Most binary operations from and to numeric types participate in usual arithmetic conversions |
62 | | - exists(BinaryOperation op | |
63 | | - // Shifts do not participate in usual arithmetic conversions |
64 | | - not op instanceof LShiftExpr and |
65 | | - not op instanceof RShiftExpr and |
66 | | - op.getAnOperand().getFullyConverted() = this |
67 | | - ) |
68 | | - or |
69 | | - // Most binary assignment operations from and to numeric types participate in usual arithmetic |
70 | | - // conversions |
71 | | - exists(AssignOperation ao | |
72 | | - // Shifts do not participate in usual arithmetic conversions |
73 | | - not ao instanceof AssignLShiftExpr and |
74 | | - not ao instanceof AssignRShiftExpr and |
75 | | - ao.getRValue().getFullyConverted() = this |
76 | | - ) |
77 | | - ) |
78 | | - } |
79 | | - |
80 | | - override string getKindOfConversion() { result = "Usual arithmetic conversion" } |
81 | | -} |
82 | | - |
83 | | -class IntegerPromotion extends IntegerPromotionOrUsualArithmeticConversionAsCast { |
84 | | - IntegerPromotion() { |
85 | | - // In the case where a conversion involves both an integer promotion and a usual arithmetic conversion |
86 | | - // we only get a single `Conversion` which combines both. According to the rule, only the "final" type |
87 | | - // should be consider, so we handle these combined conversions as `UsualArithmeticConversion`s instead. |
88 | | - not this instanceof UsualArithmeticConversion and |
89 | | - // Only consider cases where the integer promotion is the last conversion applied |
90 | | - exists(Expr e | e.getFullyConverted() = this) and |
91 | | - // Integer promotion occurs where the from type is smaller than int |
92 | | - fromType.getBuiltInSize() < sizeOfInt() and |
93 | | - // To type is bigger than or equal to int |
94 | | - toType.getBuiltInSize() >= sizeOfInt() and |
95 | | - // An integer promotion is a conversion from an integral type to an integral type |
96 | | - // |
97 | | - // This deliberately excludes integer promotions from `bool` and unscoped enums which do not |
98 | | - // have a fixed underlying type, because neither of these are considered integral types in the |
99 | | - // MISRA C++ rules. |
100 | | - fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and |
101 | | - toType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() |
102 | | - } |
103 | | - |
104 | | - override string getKindOfConversion() { result = "Integer promotion" } |
105 | | -} |
106 | | - |
107 | | -class ImpliedUsualArithmeticConversion extends IntegerPromotionOrUsualArithmeticConversion { |
108 | | - MisraCpp23BuiltInTypes::NumericType fromType; |
109 | | - MisraCpp23BuiltInTypes::NumericType toType; |
110 | | - |
111 | | - ImpliedUsualArithmeticConversion() { |
112 | | - // The lvalue of an assignment operation does not have a `Conversion` in our model, but |
113 | | - // it is still subject to usual arithmetic conversions (excepting shifts). |
114 | | - // |
115 | | - // rvalues are handled separately in the `UsualArithmeticConversion` class. |
116 | | - exists(AssignOperation aop | |
117 | | - not aop instanceof AssignLShiftExpr and |
118 | | - not aop instanceof AssignRShiftExpr and |
119 | | - // lvalue subject to usual arithmetic conversions |
120 | | - aop.getLValue() = this and |
121 | | - // From type is the type of the lvalue, which should be a numeric type under the MISRA rule |
122 | | - fromType = this.getType() and |
123 | | - // Under usual arithmetic conversions, the converted types of both arguments will be the same, |
124 | | - // so even though we don't have an explicit conversion, we can still deduce that the target |
125 | | - // type will be the same as the converted type of the rvalue. |
126 | | - toType = aop.getRValue().getFullyConverted().getType() and |
127 | | - // Only consider cases where the conversion is not a no-op, for consistency with the `Conversion` class |
128 | | - not fromType.isSameType(toType) |
129 | | - ) |
130 | | - } |
131 | | - |
132 | | - override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } |
133 | | - |
134 | | - override MisraCpp23BuiltInTypes::NumericType getToType() { result = toType } |
135 | | - |
136 | | - override Expr getConvertedExpr() { result = this } |
137 | | - |
138 | | - override string getKindOfConversion() { result = "Usual arithmetic conversion" } |
139 | | -} |
140 | | - |
141 | | -class ImpliedIntegerPromotion extends IntegerPromotionOrUsualArithmeticConversion { |
142 | | - MisraCpp23BuiltInTypes::NumericType fromType; |
143 | | - |
144 | | - ImpliedIntegerPromotion() { |
145 | | - ( |
146 | | - exists(AssignLShiftExpr aop | aop.getLValue() = this) or |
147 | | - exists(AssignRShiftExpr aop | aop.getLValue() = this) |
148 | | - ) and |
149 | | - // The rule applies to integer promotions from and to MISRA C++ numeric types |
150 | | - // However, you cannot have an integer promotion on a float, so we restrict |
151 | | - // this to integral types only |
152 | | - fromType = this.getType() and |
153 | | - fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and |
154 | | - // If the size is less than int, then it is an implied integer promotion |
155 | | - fromType.getBuiltInSize() < sizeOfInt() |
156 | | - } |
157 | | - |
158 | | - override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } |
159 | | - |
160 | | - override MisraCpp23BuiltInTypes::CanonicalIntegerNumericType getToType() { |
161 | | - // Only report the canonical type - e.g. `int` not `signed int` |
162 | | - if result instanceof Char16Type or result instanceof Char32Type or result instanceof Wchar_t |
163 | | - then |
164 | | - // Smallest type that can hold the value of the `fromType` |
165 | | - result = |
166 | | - min(MisraCpp23BuiltInTypes::NumericType candidateType | |
167 | | - ( |
168 | | - candidateType instanceof IntType or |
169 | | - candidateType instanceof LongType or |
170 | | - candidateType instanceof LongLongType |
171 | | - ) and |
172 | | - fromType.getIntegralUpperBound() <= candidateType.getIntegralUpperBound() |
173 | | - | |
174 | | - candidateType order by candidateType.getIntegralUpperBound() |
175 | | - ) |
176 | | - else ( |
177 | | - if |
178 | | - // If the `fromType` is signed, the result must be signed |
179 | | - fromType.getSignedness() = MisraCpp23BuiltInTypes::Signed() |
180 | | - or |
181 | | - // If the `fromType` is unsigned, but the result can fit into the signed int type, then the |
182 | | - // result must be signed as well. |
183 | | - fromType.getIntegralUpperBound() <= |
184 | | - any(IntType t | t.isSigned()) |
185 | | - .(MisraCpp23BuiltInTypes::NumericType) |
186 | | - .getIntegralUpperBound() |
187 | | - then |
188 | | - // `int` is returned |
189 | | - result.(IntType).isSigned() |
190 | | - else |
191 | | - // Otherwise `unsigned int` is returned |
192 | | - result.(IntType).isUnsigned() |
193 | | - ) |
194 | | - } |
195 | | - |
196 | | - override Expr getConvertedExpr() { result = this } |
197 | | - |
198 | | - override string getKindOfConversion() { result = "Integer promotion" } |
199 | | -} |
200 | | - |
201 | 21 | from |
202 | 22 | Expr e, IntegerPromotionOrUsualArithmeticConversion c, |
203 | 23 | MisraCpp23BuiltInTypes::NumericType fromType, MisraCpp23BuiltInTypes::NumericType toType, |
|
0 commit comments