@@ -40,7 +40,7 @@ class ArithmeticBitwiseLogicalBinaryOperation extends BinaryOperation {
4040 * `binOp.getLeftOperand().getExplicitlyConverted()` gives `int`.
4141 */
4242predicate arithmeticBitwiseLogicalOperationUsesUnscopedUnfixedEnum (
43- ArithmeticBitwiseLogicalBinaryOperation binOp
43+ ArithmeticBitwiseLogicalBinaryOperation binOp , Enum enum
4444) {
4545 /*
4646 * We want to strip explicit casts and not implicit ones. Without the
@@ -52,14 +52,11 @@ predicate arithmeticBitwiseLogicalOperationUsesUnscopedUnfixedEnum(
5252 * ```
5353 */
5454
55- isUnscopedEnumWithoutFixedUnderlyingType ( binOp
56- .getLeftOperand ( )
57- .getExplicitlyConverted ( )
58- .getUnderlyingType ( ) ) or
59- isUnscopedEnumWithoutFixedUnderlyingType ( binOp
60- .getRightOperand ( )
61- .getExplicitlyConverted ( )
62- .getUnderlyingType ( ) )
55+ isUnscopedEnumWithoutFixedUnderlyingType ( enum ) and
56+ (
57+ enum = binOp .getLeftOperand ( ) .getExplicitlyConverted ( ) .getUnderlyingType ( ) or
58+ enum = binOp .getRightOperand ( ) .getExplicitlyConverted ( ) .getUnderlyingType ( )
59+ )
6360}
6461
6562class RelationalEqualityBinaryOperation extends BinaryOperation {
@@ -69,7 +66,9 @@ class RelationalEqualityBinaryOperation extends BinaryOperation {
6966 }
7067}
7168
72- predicate relationalEqualityOperationUsesUnscopedUnfixedEnum ( RelationalEqualityBinaryOperation binOp ) {
69+ predicate relationalEqualityOperationUsesUnscopedUnfixedEnum (
70+ RelationalEqualityBinaryOperation binOp , Enum enum
71+ ) {
7372 exists ( Type leftOperandType , Type rightOperandType |
7473 /*
7574 * We want to strip explicit casts and not implicit ones. Without the
@@ -84,10 +83,10 @@ predicate relationalEqualityOperationUsesUnscopedUnfixedEnum(RelationalEqualityB
8483 leftOperandType = binOp .getLeftOperand ( ) .getExplicitlyConverted ( ) .getUnderlyingType ( ) and
8584 rightOperandType = binOp .getRightOperand ( ) .getExplicitlyConverted ( ) .getUnderlyingType ( )
8685 |
86+ isUnscopedEnumWithoutFixedUnderlyingType ( enum ) and
8787 (
88- isUnscopedEnumWithoutFixedUnderlyingType ( leftOperandType )
89- or
90- isUnscopedEnumWithoutFixedUnderlyingType ( rightOperandType )
88+ enum = leftOperandType or
89+ enum = rightOperandType
9190 ) and
9291 leftOperandType != rightOperandType
9392 )
@@ -101,9 +100,10 @@ class ArithmeticBitwiseCompoundAssignment extends AssignOperation {
101100}
102101
103102predicate compoundAssignmentUsesUnscopedUnfixedEnum (
104- ArithmeticBitwiseCompoundAssignment compoundAssignment
103+ ArithmeticBitwiseCompoundAssignment compoundAssignment , Enum enum
105104) {
106- isUnscopedEnumWithoutFixedUnderlyingType ( compoundAssignment .getAnOperand ( ) .getUnderlyingType ( ) )
105+ isUnscopedEnumWithoutFixedUnderlyingType ( enum ) and
106+ enum = compoundAssignment .getAnOperand ( ) .getUnderlyingType ( )
107107}
108108
109109/**
@@ -164,58 +164,75 @@ predicate enumFitsInType(Enum e, IntegralType type) {
164164 )
165165}
166166
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- )
167+ predicate assignmentSourceIsUnscopedUnfixedEnum ( AssignExpr assign , Enum enum , Type targetType ) {
168+ isUnscopedEnumWithoutFixedUnderlyingType ( enum ) and
169+ enum = assign .getRValue ( ) .getUnderlyingType ( ) and
170+ targetType = assign .getLValue ( ) .getUnderlyingType ( ) and
171+ not enumFitsInType ( enum , targetType ) and
172+ not enum = targetType
175173}
176174
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- )
175+ predicate staticCastSourceIsUnscopedUnfixedEnumVariant ( StaticCast cast , Enum enum , Type targetType ) {
176+ isUnscopedEnumWithoutFixedUnderlyingType ( enum ) and
177+ enum = cast .getExpr ( ) .getUnderlyingType ( ) and
178+ targetType = cast .getUnderlyingType ( ) and
179+ not enumFitsInType ( enum , targetType ) and
180+ not enum = targetType
184181}
185182
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- )
183+ predicate switchConditionIsAnUnfixedEnumVariant ( SwitchStmt switch , Enum enum , SwitchCase invalidCase ) {
184+ isUnscopedEnumWithoutFixedUnderlyingType ( enum ) and
185+ enum = switch .getExpr ( ) .getType ( ) and
186+ invalidCase = switch .getASwitchCase ( ) and
187+ not invalidCase .getExpr ( ) .getUnderlyingType ( ) = enum
194188}
195189
196190/**
197- * Holds if a `static_cast` expression has an enum with fixed underlying type but
198- * the target type is not an unscoped enum .
191+ * Holds if a `static_cast` expression has an unscoped enum without fixed
192+ * underlying type as the target type .
199193 */
200- predicate staticCastTargetIsUnscopedUnfixedEnumVariant ( StaticCast cast ) {
201- exists ( Enum e |
202- e = cast .getType ( ) and
203- isUnscopedEnumWithoutFixedUnderlyingType ( e ) and
204- /* Exclude cases where the assignment's target type is the same enum. */
205- not cast .getExpr ( ) .getType ( ) = e
206- )
194+ predicate staticCastTargetIsUnscopedUnfixedEnumVariant ( StaticCast cast , Enum enum ) {
195+ isUnscopedEnumWithoutFixedUnderlyingType ( enum ) and
196+ enum = cast .getType ( ) and
197+ not cast .getExpr ( ) .getType ( ) = enum
207198}
208199
209- from Element x
200+ from Element x , Enum enum , string message
210201where
211202 not isExcluded ( x , Banned3Package:: unscopedEnumWithoutFixedUnderlyingTypeUsedQuery ( ) ) and
212203 (
213- arithmeticBitwiseLogicalOperationUsesUnscopedUnfixedEnum ( x ) or
214- relationalEqualityOperationUsesUnscopedUnfixedEnum ( x ) or
215- compoundAssignmentUsesUnscopedUnfixedEnum ( x ) or
216- assignmentSourceIsUnscopedUnfixedEnum ( x ) or
217- staticCastSourceIsUnscopedUnfixedEnumVariant ( x ) or
218- switchConditionIsAnUnfixedEnumVariant ( x ) or
219- staticCastTargetIsUnscopedUnfixedEnumVariant ( x )
204+ arithmeticBitwiseLogicalOperationUsesUnscopedUnfixedEnum ( x , enum ) and
205+ message =
206+ "Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type."
207+ or
208+ relationalEqualityOperationUsesUnscopedUnfixedEnum ( x , enum ) and
209+ message =
210+ "Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type."
211+ or
212+ compoundAssignmentUsesUnscopedUnfixedEnum ( x , enum ) and
213+ message = "Compound assignment uses unscoped enum $@ without fixed underlying type."
214+ or
215+ exists ( Type targetType |
216+ assignmentSourceIsUnscopedUnfixedEnum ( x , enum , targetType ) and
217+ message =
218+ "Assignment from unscoped enum $@ without fixed underlying type to '" + targetType .getName ( )
219+ + "' which may not be large enough."
220+ )
221+ or
222+ exists ( Type targetType |
223+ staticCastSourceIsUnscopedUnfixedEnumVariant ( x , enum , targetType ) and
224+ message =
225+ "Static cast from unscoped enum $@ without fixed underlying type to '" +
226+ targetType .getName ( ) + "' which may not be large enough."
227+ )
228+ or
229+ exists ( SwitchStmt switch |
230+ switchConditionIsAnUnfixedEnumVariant ( switch , enum , x ) and
231+ message =
232+ "Switch on unscoped enum $@ without fixed underlying type has case not of the same enum type."
233+ )
234+ or
235+ staticCastTargetIsUnscopedUnfixedEnumVariant ( x , enum ) and
236+ message = "Static cast to unscoped enum $@ without fixed underlying type."
220237 )
221- select x , "TODO"
238+ select x , message , enum , enum . getName ( )
0 commit comments