Skip to content

Commit c91e5c5

Browse files
committed
Finish the detection logic
1 parent c4179a0 commit c91e5c5

File tree

1 file changed

+44
-8
lines changed

1 file changed

+44
-8
lines changed

cpp/misra/src/rules/RULE-10-2-3/UnscopedEnumWithoutFixedUnderlyingTypeUsed.ql

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,6 @@ predicate compoundAssignmentUsesUnscopedUnfixedEnum(
106106
isUnscopedEnumWithoutFixedUnderlyingType(compoundAssignment.getAnOperand().getUnderlyingType())
107107
}
108108

109-
predicate assignmentSourceIsUnscopedUnfixedEnum(AssignExpr assign) {
110-
isUnscopedEnumWithoutFixedUnderlyingType(assign.getRValue().getUnderlyingType()) and
111-
not enumFitsInType(assign.getRValue().getUnderlyingType(), assign.getLValue().getUnderlyingType())
112-
}
113-
114109
/**
115110
* Gets the minimum number of bits required to hold all values of enum `e`.
116111
*/
@@ -156,20 +151,60 @@ int enumMinBits(Enum e, boolean signed) {
156151
*/
157152
predicate enumFitsInType(Enum e, IntegralType type) {
158153
exists(int minBits, boolean signed | minBits = enumMinBits(e, signed) |
154+
/* If it has exactly the minimum number of bits, then check its signedness. */
159155
type.getSize() * 8 = minBits and
160156
(
161157
signed = true and type.isSigned()
162158
or
163159
signed = false and type.isUnsigned()
164160
)
165161
or
162+
/* If it exceeds the minimum number of bits, signedness doesn't matter. */
166163
type.getSize() * 8 > minBits
167164
)
168165
}
169166

170-
predicate staticCastSourceIsUnscopedUnfixedEnumVariant(StaticCast cast) { none() }
167+
predicate assignmentSourceIsUnscopedUnfixedEnum(AssignExpr assign) {
168+
isUnscopedEnumWithoutFixedUnderlyingType(assign.getRValue().getUnderlyingType()) and
169+
(
170+
not enumFitsInType(assign.getRValue().getUnderlyingType(),
171+
assign.getLValue().getUnderlyingType()) and
172+
/* Exclude cases where the assignment's target type is the same enum. */
173+
not assign.getRValue().getUnderlyingType() = assign.getLValue().getUnderlyingType()
174+
)
175+
}
171176

172-
predicate switchCaseIsAnUnfixedEnumVariant(SwitchCase switchCase) { none() }
177+
predicate staticCastSourceIsUnscopedUnfixedEnumVariant(StaticCast cast) {
178+
isUnscopedEnumWithoutFixedUnderlyingType(cast.getExpr().getUnderlyingType()) and
179+
(
180+
not enumFitsInType(cast.getExpr().getUnderlyingType(), cast.getUnderlyingType()) and
181+
/* Exclude cases where the assignment's target type is the same enum. */
182+
not cast.getExpr().getUnderlyingType() = cast.getUnderlyingType()
183+
)
184+
}
185+
186+
predicate switchConditionIsAnUnfixedEnumVariant(SwitchStmt switch) {
187+
exists(Enum e |
188+
isUnscopedEnumWithoutFixedUnderlyingType(e) and
189+
e = switch.getExpr().getType() and
190+
exists(SwitchCase case | case = switch.getASwitchCase() |
191+
not case.getExpr().getUnderlyingType() = e
192+
)
193+
)
194+
}
195+
196+
/**
197+
* Holds if a `static_cast` expression has an enum with fixed underlying type but
198+
* the target type is not an unscoped enum.
199+
*/
200+
predicate staticCastTargetIsUnscopedUnfixedEnumVariant(StaticCast cast) {
201+
exists(Enum e |
202+
e = cast.getType() and
203+
isUnscopedEnumWithoutFixedUnderlyingType(e) and
204+
// Exclude same-type casts (allowed by the "from" rule)
205+
not cast.getExpr().getType() = e
206+
)
207+
}
173208

174209
from Element x
175210
where
@@ -180,6 +215,7 @@ where
180215
compoundAssignmentUsesUnscopedUnfixedEnum(x) or
181216
assignmentSourceIsUnscopedUnfixedEnum(x) or
182217
staticCastSourceIsUnscopedUnfixedEnumVariant(x) or
183-
switchCaseIsAnUnfixedEnumVariant(x)
218+
switchConditionIsAnUnfixedEnumVariant(x) or
219+
staticCastTargetIsUnscopedUnfixedEnumVariant(x)
184220
)
185221
select x, "TODO"

0 commit comments

Comments
 (0)