Skip to content

Commit 447d961

Browse files
committed
Draft out first three cases
1 parent 20f7399 commit 447d961

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* @id cpp/misra/unscoped-enum-without-fixed-underlying-type-used
3+
* @name RULE-10-2-3: The numeric value of an unscoped enumeration with no fixed underlying type shall not be used
4+
* @description Treating unscoped enumeration without a fixed underlying type as an integral type is
5+
* not portable and might cause unintended behaviors.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-10-2-3
10+
* scope/single-translation-unit
11+
* correctness
12+
* external/misra/enforcement/decidable
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.cpp.misra
18+
19+
private predicate isUnscopedEnum(Enum enum) { not enum instanceof ScopedEnum }
20+
21+
private predicate withoutFixedUnderlyingType(Enum enum) { not enum.hasExplicitUnderlyingType() }
22+
23+
private predicate isUnscopedEnumWithoutFixedUnderlyingType(Enum enum) {
24+
isUnscopedEnum(enum) and withoutFixedUnderlyingType(enum)
25+
}
26+
27+
class ArithmeticBitwiseLogicalBinaryOperation extends BinaryOperation {
28+
ArithmeticBitwiseLogicalBinaryOperation() {
29+
this instanceof BinaryArithmeticOperation or
30+
this instanceof BinaryBitwiseOperation or
31+
this instanceof BinaryLogicalOperation
32+
}
33+
}
34+
35+
/**
36+
* ``` C++
37+
* static_cast<int>(u) == static_cast<int>(s); // COMPLIANT: comparing ints
38+
* ```
39+
* ^^^ To solve this, we use `getExplicitlyConverted`:
40+
* `binOp.getLeftOperand().getExplicitlyConverted()` gives `int`.
41+
*/
42+
predicate arithmeticBitwiseLogicalOperationUsesUnscopedUnfixedEnum(
43+
ArithmeticBitwiseLogicalBinaryOperation binOp
44+
) {
45+
/*
46+
* We want to strip explicit casts and not implicit ones. Without the
47+
* stripping of explicit casts, our query would raise a false alarm on
48+
* cases such as below.
49+
*
50+
* ``` C++
51+
* static_cast<int>(u) + 1 // COMPLIANT
52+
* ```
53+
*/
54+
55+
isUnscopedEnumWithoutFixedUnderlyingType(binOp
56+
.getLeftOperand()
57+
.getExplicitlyConverted()
58+
.getUnderlyingType()) or
59+
isUnscopedEnumWithoutFixedUnderlyingType(binOp
60+
.getRightOperand()
61+
.getExplicitlyConverted()
62+
.getUnderlyingType())
63+
}
64+
65+
class RelationalEqualityBinaryOperation extends BinaryOperation {
66+
RelationalEqualityBinaryOperation() {
67+
this instanceof RelationalOperation or
68+
this instanceof EqualityOperation
69+
}
70+
}
71+
72+
predicate relationalEqualityOperationUsesUnscopedUnfixedEnum(RelationalEqualityBinaryOperation binOp) {
73+
exists(Type leftOperandType, Type rightOperandType |
74+
/*
75+
* We want to strip explicit casts and not implicit ones. Without the
76+
* stripping of explicit casts, our query would raise a false alarm on
77+
* cases such as below.
78+
*
79+
* ``` C++
80+
* static_cast<int>(u) == 1 // COMPLIANT
81+
* ```
82+
*/
83+
84+
leftOperandType = binOp.getLeftOperand().getExplicitlyConverted().getUnderlyingType() and
85+
rightOperandType = binOp.getRightOperand().getExplicitlyConverted().getUnderlyingType() and
86+
(
87+
isUnscopedEnumWithoutFixedUnderlyingType(leftOperandType)
88+
or
89+
isUnscopedEnumWithoutFixedUnderlyingType(rightOperandType)
90+
) and
91+
leftOperandType != rightOperandType
92+
)
93+
}
94+
95+
class ArithmeticBitwiseCompoundAssignment extends AssignOperation {
96+
ArithmeticBitwiseCompoundAssignment() {
97+
this instanceof AssignArithmeticOperation or
98+
this instanceof AssignBitwiseOperation
99+
}
100+
}
101+
102+
predicate compoundAssignmentUsesUnscopedUnfixedEnum(
103+
ArithmeticBitwiseCompoundAssignment compoundAssignment
104+
) {
105+
isUnscopedEnumWithoutFixedUnderlyingType(compoundAssignment.getAnOperand().getUnderlyingType())
106+
}
107+
108+
predicate assignmentSourceIsUnscopedUnfixedEnum(AssignExpr assign) { none() }
109+
110+
predicate staticCastSourceIsUnscopedUnfixedEnumVariant(StaticCast cast) { none() }
111+
112+
predicate switchCaseIsAnUnfixedEnumVariant(SwitchCase switchCase) { none() }
113+
114+
from Element x
115+
where
116+
not isExcluded(x, Banned3Package::unscopedEnumWithoutFixedUnderlyingTypeUsedQuery()) and
117+
(
118+
arithmeticBitwiseLogicalOperationUsesUnscopedUnfixedEnum(x) or
119+
relationalEqualityOperationUsesUnscopedUnfixedEnum(x) or
120+
compoundAssignmentUsesUnscopedUnfixedEnum(x) or
121+
assignmentSourceIsUnscopedUnfixedEnum(x) or
122+
staticCastSourceIsUnscopedUnfixedEnumVariant(x) or
123+
switchCaseIsAnUnfixedEnumVariant(x)
124+
)
125+
select x, "TODO"

0 commit comments

Comments
 (0)