Skip to content

Commit 8b999e9

Browse files
committed
BuiltInTypes: Refactor bitfield handling
Simplify the handling of bitfields.
1 parent 6110770 commit 8b999e9

File tree

3 files changed

+90
-104
lines changed

3 files changed

+90
-104
lines changed

cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll

Lines changed: 87 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -184,114 +184,95 @@ module MisraCpp23BuiltInTypes {
184184
}
185185

186186
predicate isPreConversionAssignment(Expr source, Type targetType, string context) {
187-
// Assignment expression (which excludes compound assignments)
188-
exists(AssignExpr assign |
189-
assign.getRValue() = source and
190-
context = "assignment"
191-
|
192-
if isAssignedToBitfield(source, _)
193-
then
194-
// For the MISRA type rules we treat bit fields as a special case
195-
exists(BitField bf |
196-
isAssignedToBitfield(source, bf) and
197-
targetType = getBitFieldType(bf)
198-
)
199-
else
187+
if isAssignedToBitfield(source, _)
188+
then
189+
// For the MISRA type rules we treat bit fields as a special case
190+
exists(BitField bf |
191+
isAssignedToBitfield(source, bf) and
192+
targetType = getBitFieldType(bf) and
193+
context = "assignment to bitfield"
194+
)
195+
else (
196+
// Assignment expression (which excludes compound assignments)
197+
exists(AssignExpr assign |
198+
assign.getRValue() = source and
199+
context = "assignment"
200+
|
200201
exists(Type t | t = assign.getLValue().getType() |
201202
// Unwrap PointerToMemberType e.g `l1.*l2 = x;`
202203
if t instanceof PointerToMemberType
203204
then targetType = t.(PointerToMemberType).getBaseType()
204205
else targetType = t
205206
)
206-
)
207-
or
208-
// Variable initialization
209-
exists(Variable v, Initializer init |
210-
init.getExpr() = source and
211-
v.getInitializer() = init and
212-
context = "initialization"
213-
|
214-
// For the MISRA type rules we treat bit fields as a special case
215-
if v instanceof BitField
216-
then targetType = getBitFieldType(v)
217-
else
218-
// Regular variable initialization
207+
)
208+
or
209+
// Variable initialization
210+
exists(Variable v, Initializer init |
211+
init.getExpr() = source and
212+
v.getInitializer() = init and
213+
context = "initialization"
214+
|
219215
targetType = v.getType()
220-
)
221-
or
222-
exists(ConstructorFieldInit fi |
223-
fi.getExpr() = source and
224-
context = "constructor field initialization"
225-
|
226-
// For the MISRA type rules we treat bit fields as a special case
227-
if fi.getTarget() instanceof BitField
228-
then targetType = getBitFieldType(fi.getTarget())
229-
else
230-
// Regular variable initialization
216+
)
217+
or
218+
exists(ConstructorFieldInit fi |
219+
fi.getExpr() = source and
220+
context = "constructor field initialization"
221+
|
231222
targetType = fi.getTarget().getType()
232-
)
233-
or
234-
// Passing a function parameter by value
235-
exists(Call call, int i |
236-
call.getArgument(i) = source and
237-
not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and
238-
context = "function argument"
239-
|
240-
// A regular function call
241-
targetType = call.getTarget().getParameter(i).getType()
223+
)
242224
or
243-
// A function call where the argument is passed as varargs
244-
call.getTarget().getNumberOfParameters() <= i and
245-
// The rule states that the type should match the "adjusted" type of the argument
246-
targetType = source.getFullyConverted().getType()
225+
// Passing a function parameter by value
226+
exists(Call call, int i |
227+
call.getArgument(i) = source and
228+
not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and
229+
context = "function argument"
230+
|
231+
// A regular function call
232+
targetType = call.getTarget().getParameter(i).getType()
233+
or
234+
// A function call where the argument is passed as varargs
235+
call.getTarget().getNumberOfParameters() <= i and
236+
// The rule states that the type should match the "adjusted" type of the argument
237+
targetType = source.getFullyConverted().getType()
238+
or
239+
// An expression call - get the function type, then the parameter type
240+
targetType = getExprCallFunctionType(call).getParameterType(i)
241+
)
247242
or
248-
// An expression call - get the function type, then the parameter type
249-
targetType = getExprCallFunctionType(call).getParameterType(i)
250-
)
251-
or
252-
// Return statement
253-
exists(ReturnStmt ret, Function f |
254-
ret.getExpr() = source and
255-
ret.getEnclosingFunction() = f and
256-
targetType = f.getType() and
257-
not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and
258-
context = "return"
259-
)
260-
or
261-
// Switch case
262-
exists(SwitchCase case, SwitchStmt switch |
263-
case.getExpr() = source and
264-
case.getSwitchStmt() = switch and
265-
context = "switch case"
266-
|
267-
if switch.getExpr().(FieldAccess).getTarget() instanceof BitField
268-
then
269-
// For the MISRA type rules we treat bit fields as a special case
270-
targetType = getBitFieldType(switch.getExpr().(FieldAccess).getTarget())
271-
else
272-
// Regular variable initialization
243+
// Return statement
244+
exists(ReturnStmt ret, Function f |
245+
ret.getExpr() = source and
246+
ret.getEnclosingFunction() = f and
247+
targetType = f.getType() and
248+
not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and
249+
context = "return"
250+
)
251+
or
252+
// Switch case
253+
exists(SwitchCase case, SwitchStmt switch |
254+
case.getExpr() = source and
255+
case.getSwitchStmt() = switch and
256+
context = "switch case"
257+
|
273258
// Get the type of the switch expression, which is the type of the case expression
274259
targetType = switch.getExpr().getFullyConverted().getType()
275-
)
276-
or
277-
// Class aggregate literal initialization
278-
exists(ClassAggregateLiteral al, Field f |
279-
source = al.getAFieldExpr(f) and
280-
context = "class aggregate literal"
281-
|
282-
// For the MISRA type rules we treat bit fields as a special case
283-
if f instanceof BitField
284-
then targetType = getBitFieldType(f)
285-
else
286-
// Regular variable initialization
260+
)
261+
or
262+
// Class aggregate literal initialization
263+
exists(ClassAggregateLiteral al, Field f |
264+
source = al.getAFieldExpr(f) and
265+
context = "class aggregate literal"
266+
|
287267
targetType = f.getType()
288-
)
289-
or
290-
// Array or vector aggregate literal initialization
291-
exists(ArrayOrVectorAggregateLiteral vl |
292-
source = vl.getAnElementExpr(_) and
293-
targetType = vl.getElementType() and
294-
context = "array or vector aggregate literal"
268+
)
269+
or
270+
// Array or vector aggregate literal initialization
271+
exists(ArrayOrVectorAggregateLiteral vl |
272+
source = vl.getAnElementExpr(_) and
273+
targetType = vl.getElementType() and
274+
context = "array or vector aggregate literal"
275+
)
295276
)
296277
}
297278

@@ -315,11 +296,16 @@ module MisraCpp23BuiltInTypes {
315296
)
316297
)
317298
}
318-
}
319299

320-
/**
321-
* Holds if the `source` expression is assigned to a bit field.
322-
*/
323-
predicate isAssignedToBitfield(Expr source, BitField bf) {
324-
source = bf.getAnAssignedValue().getExplicitlyConverted()
300+
/**
301+
* Holds if the `source` expression is "assigned" to a bit field per MISRA C++ 2023.
302+
*/
303+
predicate isAssignedToBitfield(Expr source, BitField bf) {
304+
source = bf.getAnAssignedValue().getExplicitlyConverted()
305+
or
306+
exists(SwitchStmt switch, SwitchCase case |
307+
bf = switch.getExpr().(FieldAccess).getTarget() and
308+
source = case.getExpr()
309+
)
310+
}
325311
}

cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ where
3333
)
3434
or
3535
// Exception: assignment to bit-field of length 1
36-
isAssignedToBitfield(e, _)
36+
MisraCpp23BuiltInTypes::isAssignedToBitfield(e, _)
3737
// Note: conversions that result in a constructor call are not represented as `Conversion`s
3838
// in our model, so do not need to be excluded here.
3939
)

cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ predicate isValidConstantAssignment(
2626
exists(QlBuiltins::BigInt val | val = source.getConstantValue() |
2727
// Bit field assignment: check if the value fits in the bit field
2828
exists(BitField bf, int numBits |
29-
isAssignedToBitfield(source, bf) and
29+
MisraCpp23BuiltInTypes::isAssignedToBitfield(source, bf) and
3030
numBits = bf.getNumBits() and
3131
if targetType.getSignedness() = MisraCpp23BuiltInTypes::Signed()
3232
then
@@ -41,7 +41,7 @@ predicate isValidConstantAssignment(
4141
)
4242
or
4343
// Regular assignment: check if the value fits in the target type range
44-
not isAssignedToBitfield(source, _) and
44+
not MisraCpp23BuiltInTypes::isAssignedToBitfield(source, _) and
4545
(
4646
// Integer types: check if the value fits in the target type range
4747
targetType.getIntegralLowerBound() <= val and

0 commit comments

Comments
 (0)