Skip to content

Commit 258dadf

Browse files
committed
Create MISRA arithmetic conversions library
1 parent 8b999e9 commit 258dadf

File tree

2 files changed

+184
-181
lines changed

2 files changed

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

cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql

Lines changed: 1 addition & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -15,189 +15,9 @@
1515

1616
import cpp
1717
import codingstandards.cpp.misra
18+
import codingstandards.cpp.misra.ArithmeticConversions
1819
import codingstandards.cpp.misra.BuiltInTypeRules
1920

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-
20121
from
20222
Expr e, IntegerPromotionOrUsualArithmeticConversion c,
20323
MisraCpp23BuiltInTypes::NumericType fromType, MisraCpp23BuiltInTypes::NumericType toType,

0 commit comments

Comments
 (0)