Skip to content

Commit 730ea41

Browse files
jubnzvdanmar
authored andcommitted
misra.py: Handle essential type categories for ternary operations (#2455)
This commit will add feature to detect essential type categories for operators of ternary operation. This fixes issues with rule 10.1 and close the following ticket: https://trac.cppcheck.net/ticket/9543
1 parent fe23d01 commit 730ea41

2 files changed

Lines changed: 67 additions & 14 deletions

File tree

addons/misra.py

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,28 @@ def isSimpleEscapeSequence(symbols):
531531
return symbols[1] in ("'", '"', '?', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v')
532532

533533

534+
def isTernaryOperator(token):
535+
if not token:
536+
return False
537+
if not token.astOperand2:
538+
return False
539+
return token.str == '?' and token.astOperand2.str == ':'
540+
541+
542+
def getTernaryOperandsRecursive(token):
543+
"""Returns list of ternary operands including nested onces."""
544+
if not isTernaryOperator(token):
545+
return []
546+
result = []
547+
result += getTernaryOperandsRecursive(token.astOperand2.astOperand1)
548+
if token.astOperand2.astOperand1 and not isTernaryOperator(token.astOperand2.astOperand1):
549+
result += [token.astOperand2.astOperand1]
550+
result += getTernaryOperandsRecursive(token.astOperand2.astOperand2)
551+
if token.astOperand2.astOperand2 and not isTernaryOperator(token.astOperand2.astOperand2):
552+
result += [token.astOperand2.astOperand2]
553+
return result
554+
555+
534556
def hasNumericEscapeSequence(symbols):
535557
"""Check that given string contains octal or hexadecimal escape sequences."""
536558
if '\\' not in symbols:
@@ -1049,20 +1071,25 @@ def misra_10_1(self, data):
10491071
for token in data.tokenlist:
10501072
if not token.isOp:
10511073
continue
1052-
e1 = getEssentialTypeCategory(token.astOperand1)
1053-
e2 = getEssentialTypeCategory(token.astOperand2)
1054-
if not e1 or not e2:
1055-
continue
1056-
if token.str in ('<<', '>>'):
1057-
if e1 != 'unsigned':
1058-
self.reportError(token, 10, 1)
1059-
elif e2 != 'unsigned' and not token.astOperand2.isNumber:
1060-
self.reportError(token, 10, 1)
1061-
elif token.str in ('~', '&', '|', '^'):
1062-
e1_et = getEssentialType(token.astOperand1)
1063-
e2_et = getEssentialType(token.astOperand2)
1064-
if e1_et == 'char' and e2_et == 'char':
1065-
self.reportError(token, 10, 1)
1074+
1075+
for t1, t2 in itertools.product(
1076+
list(getTernaryOperandsRecursive(token.astOperand1) or [token.astOperand1]),
1077+
list(getTernaryOperandsRecursive(token.astOperand2) or [token.astOperand2]),
1078+
):
1079+
e1 = getEssentialTypeCategory(t1)
1080+
e2 = getEssentialTypeCategory(t2)
1081+
if not e1 or not e2:
1082+
continue
1083+
if token.str in ('<<', '>>'):
1084+
if e1 != 'unsigned':
1085+
self.reportError(token, 10, 1)
1086+
elif e2 != 'unsigned' and not token.astOperand2.isNumber:
1087+
self.reportError(token, 10, 1)
1088+
elif token.str in ('~', '&', '|', '^'):
1089+
e1_et = getEssentialType(token.astOperand1)
1090+
e2_et = getEssentialType(token.astOperand2)
1091+
if e1_et == 'char' and e2_et == 'char':
1092+
self.reportError(token, 10, 1)
10661093

10671094
def misra_10_4(self, data):
10681095
op = {'+', '-', '*', '/', '%', '&', '|', '^', '+=', '-=', ':'}

addons/test/misra/misra-test.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,32 @@ void misra_10_1(uint8_t u, char c1, char c2) {
234234
MISRA_10_1_CHAR cd3;
235235
cd3 = cd1 & cd2; // 10.1
236236
}
237+
void misra_10_1_ternary()
238+
{
239+
int a;
240+
uint8_t ui8;
241+
uint16_t ui16;
242+
int8_t i8;
243+
int16_t i16;
244+
245+
a = ui16 << ui16;
246+
a = ui16 << (get_bool(42) ? ui16 : ui16);
247+
a = ui16 << (get_bool(42) ? ui16 : (get_bool(34) ? ui16 : ui16)); // 10.4
248+
a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui16) : ui16); // 10.4
249+
a = ui16 << (get_bool(42) ? i16 : (get_bool(34) ? ui16 : ui16)); // 10.1
250+
a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : i16) : ui16); // 10.1 10.4
251+
a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui16) : i16); // 10.1
252+
a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : ui8); // 10.4
253+
a = ui16 << (get_bool(42) ? (get_bool(34) ? i16 : ui8) : ui8); // 10.1 10.4
254+
a = (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : ui8) << ui16; // 10.4
255+
a = (get_bool(42) ? (get_bool(34) ? i16 : ui8) : ui8) << ui16; // 10.1 10.4
256+
a = (get_bool(42) ? (get_bool(34) ? ui16 : i8) : ui8) << ui16; // 10.1 10.4
257+
a = (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : i8) << ui16; // 10.1
258+
a = (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : ui8) << (get_bool(19) ? ui16 : ui8); // 10.4
259+
a = (get_bool(42) ? (get_bool(34) ? i16 : ui8) : ui8) << (get_bool(19) ? ui16 : ui8); // 10.1 10.4
260+
a = (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : ui8) << (get_bool(19) ? i16 : ui8); // 10.1 10.4
261+
262+
}
237263

238264
void misra_10_4(u32 x, s32 y) {
239265
z = x + 3; // 10.4

0 commit comments

Comments
 (0)