From 730ea4163b27df1c0b3f2bfa71bd05c343c1db9f Mon Sep 17 00:00:00 2001 From: Georgy Komarov Date: Sat, 21 Dec 2019 09:40:15 +0300 Subject: [PATCH] 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 --- addons/misra.py | 55 +++++++++++++++++++++++++--------- addons/test/misra/misra-test.c | 26 ++++++++++++++++ 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/addons/misra.py b/addons/misra.py index 144f7aa85..6f2201eec 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -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 = {'+', '-', '*', '/', '%', '&', '|', '^', '+=', '-=', ':'} diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index c6760c878..6db2ec273 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -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