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
This commit is contained in:
Georgy Komarov 2019-12-21 09:40:15 +03:00 committed by Daniel Marjamäki
parent fe23d017f3
commit 730ea4163b
2 changed files with 67 additions and 14 deletions

View File

@ -531,6 +531,28 @@ def isSimpleEscapeSequence(symbols):
return symbols[1] in ("'", '"', '?', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v')
def isTernaryOperator(token):
if not token:
return False
if not token.astOperand2:
return False
return token.str == '?' and token.astOperand2.str == ':'
def getTernaryOperandsRecursive(token):
"""Returns list of ternary operands including nested onces."""
if not isTernaryOperator(token):
return []
result = []
result += getTernaryOperandsRecursive(token.astOperand2.astOperand1)
if token.astOperand2.astOperand1 and not isTernaryOperator(token.astOperand2.astOperand1):
result += [token.astOperand2.astOperand1]
result += getTernaryOperandsRecursive(token.astOperand2.astOperand2)
if token.astOperand2.astOperand2 and not isTernaryOperator(token.astOperand2.astOperand2):
result += [token.astOperand2.astOperand2]
return result
def hasNumericEscapeSequence(symbols):
"""Check that given string contains octal or hexadecimal escape sequences."""
if '\\' not in symbols:
@ -1049,20 +1071,25 @@ class MisraChecker:
for token in data.tokenlist:
if not token.isOp:
continue
e1 = getEssentialTypeCategory(token.astOperand1)
e2 = getEssentialTypeCategory(token.astOperand2)
if not e1 or not e2:
continue
if token.str in ('<<', '>>'):
if e1 != 'unsigned':
self.reportError(token, 10, 1)
elif e2 != 'unsigned' and not token.astOperand2.isNumber:
self.reportError(token, 10, 1)
elif token.str in ('~', '&', '|', '^'):
e1_et = getEssentialType(token.astOperand1)
e2_et = getEssentialType(token.astOperand2)
if e1_et == 'char' and e2_et == 'char':
self.reportError(token, 10, 1)
for t1, t2 in itertools.product(
list(getTernaryOperandsRecursive(token.astOperand1) or [token.astOperand1]),
list(getTernaryOperandsRecursive(token.astOperand2) or [token.astOperand2]),
):
e1 = getEssentialTypeCategory(t1)
e2 = getEssentialTypeCategory(t2)
if not e1 or not e2:
continue
if token.str in ('<<', '>>'):
if e1 != 'unsigned':
self.reportError(token, 10, 1)
elif e2 != 'unsigned' and not token.astOperand2.isNumber:
self.reportError(token, 10, 1)
elif token.str in ('~', '&', '|', '^'):
e1_et = getEssentialType(token.astOperand1)
e2_et = getEssentialType(token.astOperand2)
if e1_et == 'char' and e2_et == 'char':
self.reportError(token, 10, 1)
def misra_10_4(self, data):
op = {'+', '-', '*', '/', '%', '&', '|', '^', '+=', '-=', ':'}

View File

@ -234,6 +234,32 @@ void misra_10_1(uint8_t u, char c1, char c2) {
MISRA_10_1_CHAR cd3;
cd3 = cd1 & cd2; // 10.1
}
void misra_10_1_ternary()
{
int a;
uint8_t ui8;
uint16_t ui16;
int8_t i8;
int16_t i16;
a = ui16 << ui16;
a = ui16 << (get_bool(42) ? ui16 : ui16);
a = ui16 << (get_bool(42) ? ui16 : (get_bool(34) ? ui16 : ui16)); // 10.4
a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui16) : ui16); // 10.4
a = ui16 << (get_bool(42) ? i16 : (get_bool(34) ? ui16 : ui16)); // 10.1
a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : i16) : ui16); // 10.1 10.4
a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui16) : i16); // 10.1
a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : ui8); // 10.4
a = ui16 << (get_bool(42) ? (get_bool(34) ? i16 : ui8) : ui8); // 10.1 10.4
a = (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : ui8) << ui16; // 10.4
a = (get_bool(42) ? (get_bool(34) ? i16 : ui8) : ui8) << ui16; // 10.1 10.4
a = (get_bool(42) ? (get_bool(34) ? ui16 : i8) : ui8) << ui16; // 10.1 10.4
a = (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : i8) << ui16; // 10.1
a = (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : ui8) << (get_bool(19) ? ui16 : ui8); // 10.4
a = (get_bool(42) ? (get_bool(34) ? i16 : ui8) : ui8) << (get_bool(19) ? ui16 : ui8); // 10.1 10.4
a = (get_bool(42) ? (get_bool(34) ? ui16 : ui8) : ui8) << (get_bool(19) ? i16 : ui8); // 10.1 10.4
}
void misra_10_4(u32 x, s32 y) {
z = x + 3; // 10.4