diff --git a/addons/misra.py b/addons/misra.py index db467588a..7c7d90348 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -2019,6 +2019,35 @@ class MisraChecker: self.reportError(token, 15, 3) break t = t.next + + def misra_15_4(self, data): + # Return a list of scopes affected by a break or goto + def getLoopsAffectedByBreak(knownLoops, scope, isGoto): + if scope and scope.type and scope.type not in ['Global', 'Function']: + if not isGoto and scope.type == 'Switch': + return + if scope.type in ['For', 'While', 'Do']: + knownLoops.append(scope) + if not isGoto: + return + getLoopsAffectedByBreak(knownLoops, scope.nestedIn, isGoto) + + loopWithBreaks = {} + for token in data.tokenlist: + if token.str not in ['break', 'goto']: + continue + + affectedLoopScopes = [] + getLoopsAffectedByBreak(affectedLoopScopes, token.scope, token.str == 'goto') + for scope in affectedLoopScopes: + if scope in loopWithBreaks: + loopWithBreaks[scope] += 1 + else: + loopWithBreaks[scope] = 1 + + for scope, breakCount in loopWithBreaks.items(): + if breakCount > 1: + self.reportError(scope.bodyStart, 15, 4) def misra_15_5(self, data): for token in data.tokenlist: @@ -3108,6 +3137,7 @@ class MisraChecker: self.executeCheck(1501, self.misra_15_1, cfg) self.executeCheck(1502, self.misra_15_2, cfg) self.executeCheck(1503, self.misra_15_3, cfg) + self.executeCheck(1504, self.misra_15_4, cfg) self.executeCheck(1505, self.misra_15_5, cfg) if cfgNumber == 0: self.executeCheck(1506, self.misra_15_6, data.rawTokens) diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 80f4ba297..364b8745b 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -796,6 +796,90 @@ void misra_15_3() { } } +void misra_15_4() { + misra_15_4_label: + return; + + int x = 0; + int y = 0; + int z = 0; + + // Break on different loop scopes + for (x = 0; x < 42; ++x) { + if (x==1) { + break; + } + for (y = 0; y < 42; ++y) { // 15.4 + if (y==1) { + break; + } + if (y==2) { + break; + } + for (z = 0; y < 42; ++z) { + if (z==1) { + break; + } + } + } + } + + // Break in while loop + do { // 15.4 + if(x == 1) { + break; + } + if(x == 2) { + break + } + x++; + } while(x != 42); + + // Break and goto in same loop + for (int x = 0; x < 10; ++x) { // 15.4 + if (x == 1) { + break; + } + if (x == 2) { + goto misra_15_4_label; // 15.1 15.2 + } + } + + // Inner loop uses goto + for (x = 0; x < 42; ++x) { // 15.4 + if (x==1) { + break; + } + for (y = 0; y < 42; ++y) { + if (y == 1) { + goto misra_15_4_label; // 15.1 15.2 + } + } + } + + // Allow switch with multiple breaks inside loop + for (x = 0; x < 42; ++x) { + switch (x) { + case 1: + break; + default: + break; + } + } + + // Do not allow switch with multiple gotos inside loop + for (x = 0; x < 42; ++x) { // 15.4 + switch (x) { + case 1: + goto misra_15_4_label; // 15.1 15.2 + break; + default: + goto misra_15_4_label; // 15.1 15.2 + break; + } + } +} + int misra_15_5() { if (x!=0) { return 1; // 15.5