|
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