From d4860f500a3626a75fd81ed1287d383dd1ab4a0c Mon Sep 17 00:00:00 2001 From: kskjerve <74188500+kskjerve@users.noreply.github.com> Date: Wed, 16 Dec 2020 17:28:54 +0100 Subject: [PATCH] MISRA 9.2 to 9.5 (#2954) --- addons/misra.py | 269 +----------------- addons/misra_9.py | 492 +++++++++++++++++++++++++++++++++ addons/test/misra/misra-test.c | 186 ++++++++++--- 3 files changed, 648 insertions(+), 299 deletions(-) create mode 100644 addons/misra_9.py diff --git a/addons/misra.py b/addons/misra.py index 5055a8222..e765d8516 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -30,6 +30,7 @@ try: except ImportError: pass +import misra_9 def grouped(iterable, n): """s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ...""" @@ -1496,263 +1497,19 @@ class MisraChecker: self.reportError(token, 8, 14) def misra_9_2(self, data): - # Holds information about a struct or union's element definition. - class ElementDef: - def __init__(self, elementType, name, valueType = None, dimensions = None): - self.elementType = elementType - self.name = name - self.valueType = valueType - self.dimensions = dimensions + misra_9.misra_9_x(self, data, 902) - # Return an array containing the size of each dimension of an array declaration, - # or coordinates of a designator in an array initializer, - # and the name token's valueType, if it exist. - # - # In the examples below, the ^ indicates the initial token passed to the function. - # - # Ex: int arr[1][2][3] = ..... - # ^ - # returns: [1,2,3], valueType - # - # Ex: int arr[3][4] = { [1][2] = 5 } - # ^ - # returns [1,2], None - def getArrayDimensionsAndValueType(token): - dimensions = [] + def misra_9_3(self, data): + misra_9.misra_9_x(self, data, 903) - while token.str == '*': - if token.astOperand2 is not None: - token = token.astOperand2 - else: - token = token.astOperand1 + def misra_9_4(self, data): + misra_9.misra_9_x(self, data, 904) - while token and token.str == '[': - if token.astOperand2 is not None: - dimensions.insert(0, token.astOperand2.getKnownIntValue()) - token = token.astOperand1 - elif token.astOperand1 is not None: - dimensions.insert(0, token.astOperand1.getKnownIntValue()) - break - else: - dimensions = None - break - - valueType = token.valueType if token else None - - return dimensions, valueType - - # Returns a list of the struct elements as StructElementDef in the order they are declared. - def getRecordElements(valueType): - if not valueType or not valueType.typeScope: - return [] - - elements = [] - for variable in valueType.typeScope.varlist: - if variable.isArray: - dimensions, arrayValueType = getArrayDimensionsAndValueType(variable.nameToken.astParent) - elements.append(ElementDef('array', variable.nameToken.str, arrayValueType, dimensions)) - elif variable.isClass: - elements.append(ElementDef('class', variable.nameToken.str, variable.nameToken.valueType)) - else: - elements.append(ElementDef('element', variable.nameToken.str)) - - return elements - - # Checks if the initializer conforms to the dimensions of the array declaration - # at a given level. - # Parameters: - # token: root node of the initializer tree - # dimensions: dimension sizes of the array declaration - # valueType: the array type - def checkArrayInitializer(token, dimensions, valueType): - level = 0 - levelOffsets = [] # Calculated when designators in initializers are used - elements = getRecordElements(valueType) if valueType.type == 'record' else None - - isFirstElement = False - while token: - if token.str == ',': - token = token.astOperand1 - isFirstElement = False - continue - - if token.isAssignmentOp and not token.valueType: - designator, _ = getArrayDimensionsAndValueType(token.astOperand1) - # Calculate level offset based on designator in initializer - levelOffsets[-1] = len(designator) - 1 - token = token.astOperand2 - isFirstElement = False - - effectiveLevel = sum(levelOffsets) + level - - # Zero initializer is ok at any level - isZeroInitializer = (isFirstElement and token.str == '0') - # String initializer is ok at one level below value level unless array to pointers - isStringInitializer = token.isString and effectiveLevel == len(dimensions) - 1 and valueType.pointer == len(dimensions) - - if effectiveLevel == len(dimensions) or isZeroInitializer or isStringInitializer: - if not isZeroInitializer and not isStringInitializer: - isFirstElement = False - if valueType.type == 'record': - if token.isName: - if not token.valueType.typeScope == valueType.typeScope: - self.reportError(token, 9, 2) - return False - else: - if not checkObjectInitializer(token, elements): - return False - elif token.str == '{': - self.reportError(token, 9, 2) - return False - # String initializer is not ok at this level, unless array to pointers - # (should be pointer to const-qualified char, but that check is out of scope for 9.2) - elif token.isString and valueType.pointer == len(dimensions): - self.reportError(token, 9, 2) - return False - - # Done evaluating leaf node - go back up to find next astOperand2 - while token: - # Done checking once level is back to 0 (or we run out of parents) - if level == 0 or not token.astParent: - return True - - if token.astParent.astOperand1 == token and token.astParent.astOperand2: - token = token.astParent.astOperand2 - break - else: - token = token.astParent - if token.str == '{': - level = level - 1 - levelOffsets.pop() - effectiveLevel = sum(levelOffsets) + level - - elif token.str == '{' : - if not token.astOperand1: - # Empty initializer - self.reportError(token, 9, 2) - return False - - token = token.astOperand1 - level = level + 1 - levelOffsets.append(0) - isFirstElement = True - else: - self.reportError(token, 9, 2) - return False - - return True - - # Checks if the initializer conforms to the elements of the struct or union - # Parameters: - # token: root node of the initializer tree - # elements: the elements as specified in the declaration - def checkObjectInitializer(token, elements): - if not token: - return True - - # Initializer must start with a curly bracket - if not token.str == '{': - self.reportError(token, 9, 2) - return False - - # Empty initializer is not ok { } - if not token.astOperand1: - self.reportError(token, 9, 2) - return False - - token = token.astOperand1 - - # Zero initializer is ok { 0 } - if token.str == '0' : - return True - - pos = None - while(token): - if token.str == ',': - token = token.astOperand1 - else: - if pos is None: - pos = 0 - - if token.isAssignmentOp: - if token.astOperand1.str == '.': - elementName = token.astOperand1.astOperand1.str - pos = next((i for i, element in enumerate(elements) if element.name == elementName), len(elements)) - token = token.astOperand2 - - if pos >= len(elements): - self.reportError(token, 9, 2) - return False - - element = elements[pos] - if element.elementType == 'class': - if token.isName: - if not token.valueType.typeScope == element.valueType.typeScope: - self.reportError(token, 9, 2) - return False - else: - subElements = getRecordElements(element.valueType) - if not checkObjectInitializer(token, subElements): - return False - elif element.elementType == 'array': - if not checkArrayInitializer(token, element.dimensions, element.valueType): - return False - elif token.str == '{': - self.reportError(token, 9, 2) - return False - - # The assignment represents the astOperand - if token.astParent.isAssignmentOp: - token = token.astParent - - if not token == token.astParent.astOperand2: - pos = pos + 1 - token = token.astParent.astOperand2 - else: - token = None - - return True - - # ------ - for variable in data.variables: - if not variable.nameToken: - continue - - nameToken = variable.nameToken - - # Check if declaration and initialization is - # split into two separate statements in ast. - if nameToken.next and nameToken.next.isSplittedVarDeclEq: - nameToken = nameToken.next.next - - # Find declarations with initializer assignment - eq = nameToken - while not eq.isAssignmentOp and eq.astParent: - eq = eq.astParent - - # We are only looking for initializers - if not eq.isAssignmentOp or eq.astOperand2.isName: - continue - - if variable.isArray : - dimensions, valueType = getArrayDimensionsAndValueType(eq.astOperand1) - if dimensions is None: - continue - - checkArrayInitializer(eq.astOperand2, dimensions, valueType) - elif variable.isClass: - if not nameToken.valueType: - continue - - valueType = nameToken.valueType - if valueType.type == 'record': - elements = getRecordElements(valueType) - checkObjectInitializer(eq.astOperand2, elements) - - def misra_9_5(self, rawTokens): - for token in rawTokens: - if simpleMatch(token, '[ ] = { ['): - self.reportError(token, 9, 5) + def misra_9_5(self, data, rawTokens): + misra_9.misra_9_x(self, data, 905, rawTokens) + #for token in rawTokens: + # if simpleMatch(token, '[ ] = { ['): + # self.reportError(token, 9, 5) def misra_10_1(self, data): for token in data.tokenlist: @@ -3365,8 +3122,10 @@ class MisraChecker: if cfgNumber == 0: self.executeCheck(814, self.misra_8_14, data.rawTokens) self.executeCheck(902, self.misra_9_2, cfg) + self.executeCheck(903, self.misra_9_3, cfg) + self.executeCheck(904, self.misra_9_4, cfg) if cfgNumber == 0: - self.executeCheck(905, self.misra_9_5, data.rawTokens) + self.executeCheck(905, self.misra_9_5, cfg, data.rawTokens) self.executeCheck(1001, self.misra_10_1, cfg) self.executeCheck(1002, self.misra_10_2, cfg) self.executeCheck(1004, self.misra_10_4, cfg) diff --git a/addons/misra_9.py b/addons/misra_9.py new file mode 100644 index 000000000..562ce95e1 --- /dev/null +++ b/addons/misra_9.py @@ -0,0 +1,492 @@ +# Holds information about an array, struct or union's element definition. +class ElementDef: + def __init__(self, elementType, name, valueType, dimensions = None): + self.elementType = elementType # 'array', 'record' or 'value' + self.name = str(name) + self.valueType = valueType + self.children = [] + self.dimensions = dimensions + self.parent = None + + self.isDesignated = False + self.isPositional = False + self.numInits = 0 + self.childIndex = -1 + + self.isFlexible = False + self.structureViolationToken = None + + def __repr__(self): + inits = "" + if self.isPositional: + inits += 'P' + if self.isDesignated: + inits += 'D' + if not (self.isPositional or self.isDesignated) and self.numInits == 0: + inits += '_' + if (self.numInits > 1): + inits += str(self.numInits) + + attrs = ["childIndex", "elementType", "valueType"] + return "{}({}, {}, {})".format( + "ED", + self.getLongName(), + inits, + ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs)) + ) + + @property + def isArray(self): + return self.elementType == 'array' + + @property + def isRecord(self): + return self.elementType == 'record' + + @property + def isValue(self): + return self.elementType == 'value' + + + def getLongName(self): + return self.parent.getLongName() + "." + self.name if self.parent else self.name + + def getInitDump(self): + t = [] + if self.isPositional: + t.append('P') + if self.isDesignated: + t.append('D') + if self.numInits == 0: + t.append('_') + if (self.numInits > 1): + t.append(str(self.numInits)) + + myDump = "".join(t) + + if len(self.children): + childDumps = [] + for c in self.children: + childDumps.append(c.getInitDump()) + if self.structureViolationToken is not None: + myDump += "!" + myDump += "{ " + ", ".join(childDumps) + " }" + + return myDump + + def addChild(self, child): + self.children.append(child) + child.parent = self + + def getNextChild(self): + self.childIndex += 1 + return self.getChildByIndex(self.childIndex) + + def getChildByIndex(self, index): + if self.isFlexible: + while len(self.children) <= index: + createChild(self, self.flexibleToken, len(self.children)) + return self.children[index] if index >= 0 and len(self.children) > index else None + + def getChildByName(self, name): + for c in self.children: + if c.name == name: + return c + return None + + def getNextValueElement(self, root): + current = self + while current != root: + # Get next index of parent + i = current.parent.children.index(current) + 1 + # Next index of parent exists + if i < len(current.parent.children): + current = current.parent.children[i] + return current.getFirstValueElement() + + # Next index of parent doesn't exist. Move up + current = current.parent + return None + + def getFirstValueElement(self): + current = self + + # Move to first child as long as children exists + next_child = current.getChildByIndex(0) + while next_child: + current = next_child + next_child = current.getChildByIndex(0) + return current + + def getLastValueElement(self): + current = self + # Move to last child as long as children exists + while len(current.children) > 0: + current = current.children[-1] + return current + + def getChildByValueElement(self, ed): + potentialChild = ed + while potentialChild and not potentialChild in self.children: + potentialChild = potentialChild.parent + + return self.children[self.children.index(potentialChild)] if potentialChild else None + + def getEffectiveLevel(self): + if self.parent and self.parent.elementType == "array": + return self.parent.getEffectiveLevel() + 1 + else: + return 0 + + def setInitialized(self, designated=False, positional=False): + if designated: + self.isDesignated = True + if positional or not designated: + self.isPositional = True + self.numInits += 1 + + def initializeChildren(self): + for child in self.children: + child.setInitialized(positional=True) + child.initializeChildren() + + def unset(self): + self.isDesignated = False + self.isPositional = False + + # Unset is always recursive + for child in self.children: + child.unset() + + def markStuctureViolation(self, token): + if self.name == '->': + self.children[0].markStuctureViolation(token) + elif not self.structureViolationToken: + self.structureViolationToken = token + + def markAsFlexibleArray(self, token): + self.flexibleToken = token; + self.isFlexible = True + + def markAsCurrent(self): + if self.parent: + if self.name == '<-': + self.parent.childIndex = self.parent.children.index(self.children[0]) + else: + self.parent.childIndex = self.parent.children.index(self) + + self.parent.markAsCurrent() + + def isAllChildrenSet(self): + myself = len(self.children) == 0 and (self.isDesignated or self.isPositional) + mychildren = len(self.children) > 0 and all([child.isAllChildrenSet() for child in self.children]) + return myself or mychildren + + def isAllSet(self): + return all([child.isPositional or child.isDesignated for child in self.children]) + + def isOnlyDesignated(self): + return all([not child.isPositional for child in self.children]) + + def isMisra92Compliant(self): + return self.structureViolationToken is None and all([child.isMisra92Compliant() for child in self.children]) + + def isMisra93Compliant(self): + if self.elementType == 'array': + result = self.isAllChildrenSet() or \ + ((self.isAllSet() or \ + self.isOnlyDesignated()) and \ + all([not (child.isDesignated or child.isPositional) or child.isMisra93Compliant() for child in self.children])) + return result + elif self.elementType == 'record': + result = all([child.isMisra93Compliant() for child in self.children]) + return result + else: + return True + + def isMisra94Compliant(self): + return self.numInits <= 1 and all([child.isMisra94Compliant() for child in self.children]) + + def isMisra95Compliant(self): + return not self.isFlexible or all([not child.isDesignated for child in self.children]) + +# Parses the initializers and uodate the ElementDefs status accordingly +class InitializerParser: + def __init__(self): + self.token = None + self.root = None + self.ed = None + self.rootStack = [] + + def parseInitializer(self, root, token): + self.root = root + self.token = token + dummyRoot = ElementDef('array', '->', self.root.valueType) + dummyRoot.children = [self.root] + + self.rootStack = [] + self.root = dummyRoot + self.ed = self.root.getFirstValueElement() + isFirstElement = False + isDesignated = False + + while self.token: + if self.token.str == ',': + self.token = self.token.astOperand1 + isFirstElement = False + + # Designated initializer ( [2]=... or .name=... ) + elif self.token.isAssignmentOp and not self.token.valueType: + self.popFromStackIfExitElement() + + self.ed = getElementByDesignator(self.root, self.token.astOperand1) + if self.ed: + # Update root + self.pushToRootStackAndMarkAsDesignated() + # Make sure ed points to valueElement + self.ed = self.ed.getFirstValueElement() + + self.token = self.token.astOperand2 + isFirstElement = False + isDesignated = True + + elif self.token.str == '{': + nextChild = self.root.getNextChild() + + if nextChild: + if nextChild.isArray or nextChild.isRecord: + nextChild.unset() + nextChild.setInitialized(isDesignated) + self.ed = nextChild.getFirstValueElement() + isDesignated = False + elif nextChild.valueType is None: + # No type information available - unable to check structure - assume correct initialization + nextChild.setInitialized(isDesignated) + self.unwindAndContinue() + continue + + elif self.token.astOperand1: + # Create dummy nextChild to represent excess levels in initializer + dummyRoot = ElementDef('array', '<-', self.root.valueType) + dummyRoot.parent = self.root + dummyRoot.childIndex = 0 + dummyRoot.children = [nextChild] + nextChild.parent = dummyRoot + + self.root.markStuctureViolation(self.token) + + # Fake dummy as nextChild (of current root) + nextChild = dummyRoot + + if self.token.astOperand1: + self.root = nextChild + self.token = self.token.astOperand1 + isFirstElement = True + else: + # {} + if self.root.name == '<-': + self.root.parent.markStuctureViolation(self.token) + else: + self.root.markStuctureViolation(self.token) + self.ed = None + self.unwindAndContinue() + + else: + if self.ed and self.ed.isValue: + if not isDesignated and len(self.rootStack) > 0 and self.rootStack[-1][1] == self.root: + self.rootStack[-1][0].markStuctureViolation(self.token) + + if isFirstElement and self.token.str == '0' and self.token.next.str == '}': + # Zero initializer causes recursive initialization + self.root.initializeChildren() + elif self.token.isString and self.ed.valueType.pointer > 0: + if self.ed.valueType.pointer - self.ed.getEffectiveLevel() == 1: + if self.ed.parent != self.root: + self.root.markStuctureViolation(self.token) + self.ed.setInitialized(isDesignated) + elif self.ed.valueType.pointer == self.ed.getEffectiveLevel(): + if(self.root.name != '->' and self.ed.parent.parent != self.root) or (self.root.name == '->' and self.root.children[0] != self.ed.parent): + self.root.markStuctureViolation(self.token) + else: + self.ed.parent.setInitialized(isDesignated) + self.ed.parent.initializeChildren() + else: + if self.ed.parent != self.root: + # Check if token is correct value type for self.root.children[?] + child = self.root.getChildByValueElement(self.ed) + if child.elementType != 'record' or self.token.valueType.type != 'record' or child.valueType.typeScope != self.token.valueType.typeScope: + self.root.markStuctureViolation(self.token) + + self.ed.setInitialized(isDesignated) + + # Mark all elements up to root with positional or designated + # (for complex designators, or missing structure) + parent = self.ed.parent + while parent and parent != self.root: + parent.isDesignated = isDesignated if isDesignated and not parent.isPositional else parent.isDesignated + parent.isPositional = not isDesignated if not isDesignated and not parent.isDesignated else parent.isPositional + parent = parent.parent + isDesignated = False + + self.unwindAndContinue() + + def pushToRootStackAndMarkAsDesignated(self): + new = self.ed.parent + if new != self.root: + # Mark all elements up to self.root root as designated + parent = new + while parent != self.root: + parent.isDesignated = True + parent = parent.parent + self.rootStack.append((self.root, new)) + new.markAsCurrent() + new.childIndex = new.children.index(self.ed) - 1 + self.root = new + + def popFromStackIfExitElement(self): + if len(self.rootStack) > 0 and self.rootStack[-1][1] == self.root: + old = self.rootStack.pop()[0] + old.markAsCurrent() + self.root = old + + def unwindAndContinue(self): + while self.token: + if self.token.astParent.astOperand1 == self.token and self.token.astParent.astOperand2: + if self.ed: + self.ed.markAsCurrent() + self.ed = self.ed.getNextValueElement(self.root) + + self.token = self.token.astParent.astOperand2 + break + else: + self.token = self.token.astParent + if self.token.str == '{': + self.ed = self.root.getLastValueElement() + self.ed.markAsCurrent() + + # Cleanup if root is dummy node representing excess levels in initializer + if self.root and self.root.name == '<-': + self.root.children[0].parent = self.root.parent + + self.root = self.root.parent + + if self.token.astParent == None: + self.token = None + break + +def misra_9_x(self, data, rule, rawTokens = None): + parser = InitializerParser() + + for variable in data.variables: + if not variable.nameToken: + continue + + nameToken = variable.nameToken + + # Check if declaration and initialization is + # split into two separate statements in ast. + if nameToken.next and nameToken.next.isSplittedVarDeclEq: + nameToken = nameToken.next.next + + # Find declarations with initializer assignment + eq = nameToken + while not eq.isAssignmentOp and eq.astParent: + eq = eq.astParent + + # We are only looking for initializers + if not eq.isAssignmentOp or eq.astOperand2.isName: + continue + + if variable.isArray or variable.isClass: + ed = getElementDef(nameToken, rawTokens) + parser.parseInitializer(ed, eq.astOperand2) + # print(rule, nameToken.str + '=', ed.getInitDump()) + if rule == 902 and not ed.isMisra92Compliant(): + self.reportError(nameToken, 9, 2) + if rule == 903 and not ed.isMisra93Compliant(): + self.reportError(nameToken, 9, 3) + if rule == 904 and not ed.isMisra94Compliant(): + self.reportError(nameToken, 9, 4) + if rule == 905 and not ed.isMisra95Compliant(): + self.reportError(nameToken, 9, 5) + +def getElementDef(nameToken, rawTokens = None): + if nameToken.variable.isArray: + ed = ElementDef("array", nameToken.str, nameToken.valueType) + createArrayChildrenDefs(ed, nameToken.astParent, rawTokens) + elif nameToken.variable.isClass: + ed = ElementDef("record", nameToken.str, nameToken.valueType) + createRecordChildrenDefs(ed) + else: + ed = ElementDef("value", nameToken.str, nameToken.valueType) + return ed + +def createArrayChildrenDefs(ed, token, rawTokens = None): + if token.str == '[': + if rawTokens is not None: + foundToken = next(rawToken for rawToken in rawTokens if rawToken.file == token.file and rawToken.linenr == token.linenr and rawToken.column == token.column) + + if foundToken and foundToken.next and foundToken.next.str == ']': + ed.markAsFlexibleArray(token) + + if token.astOperand2 is not None: + for i in range(token.astOperand2.getKnownIntValue()): + createChild(ed, token, i) + else: + ed.markAsFlexibleArray(token) + + +def createChild(ed, token, name): + if token.astParent and token.astParent.str == '[': + child = ElementDef("array", name, ed.valueType) + createArrayChildrenDefs(child, token.astParent) + else: + if ed.valueType and ed.valueType.type == "record": + child = ElementDef("record", name, ed.valueType) + createRecordChildrenDefs(child) + else: + child = ElementDef("value", name, ed.valueType) + + ed.addChild(child) + +def createRecordChildrenDefs(ed): + valueType = ed.valueType + if not valueType or not valueType.typeScope: + return + + for variable in valueType.typeScope.varlist: + child = getElementDef(variable.nameToken) + ed.addChild(child) + +def getElementByDesignator(ed, token): + while token.str in [ '.', '[' ]: + token = token.astOperand1 + + while ed and not token.isAssignmentOp: + token = token.astParent + + if token.str == '[': + chIndex = -1 + if token.astOperand2 is not None: + chIndex = token.astOperand2.getKnownIntValue() + elif token.astOperand1 is not None: + chIndex = token.astOperand1.getKnownIntValue() + + if not ed.isArray: + ed.markStuctureViolation(token) + + ed = ed.getChildByIndex(chIndex) + + elif token.str == '.': + name = "" + if token.astOperand2 is not None: + name = token.astOperand2.str + elif token.astOperand1 is not None: + name = token.astOperand1.str + + if not ed.isRecord: + ed.markStuctureViolation(token) + + ed = ed.getChildByName(name) + + return ed diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 3d49a6904..2e6a95ea6 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -295,38 +295,90 @@ enum misra_8_12_e { misra_e1 = sizeof(int), misra_e2}; // no-crash void misra_8_14(char * restrict str) {(void)str;} // 8.14 -void misra_9_2() { - int empty_init[2][2] = { }; // 9.2 - int empty_nested_init[2][2] = { { } }; // 9.2 - int zero_init_a[5] = { 0 }; - int zero_init_b[5][2] = { 0 }; - int zero_init_c[2][2] = { { 1, 2 }, { 0 } }; +void misra_9_empty_or_zero_initializers() { + int a[2] = {}; // 9.2 + int b[2][2] = {}; // 9.2 + int c[2][2] = { {} }; // 9.2 9.3 + int d[2][2] = { {}, {} }; // 9.2 + int e[2][2] = { { 1 , 2 }, {} }; // 9.2 - const char string_wrong_level_a[12] = { "Hello world" }; // 9.2 - const char string_wrong_level_b[2][20] = "Hello world"; // 9.2 - const char string_correct_level_a[] = "Hello world"; - const char string_correct_level_b[2][12] = { "Hello world" }; - const char *char_p_correct_level[2] = { "Hello", [1] = "world" }; - const char *char_p_incorrect_level[1] = "Hello world"; // 9.2 + int f[5] = { 0 }; + int g[5][2] = { 0 }; + int h[2][2] = { { 0 } }; // 9.3 + int i[2][2] = { { 0 }, { 0 } }; + int j[2][2] = { { 1, 2 }, { 0 } }; + int k[2][2] = { [0] = { 1 , 2 }, { 0 } }; + int l[1][2] = { { 0 }, [0] = { 1 } }; // 9.3 9.4 - char **str_p = &char_p_correct_level[0]; - char **str_p_array_correct_level[1] = { str_p }; - char **str_p_array_incorrect_level[1] = { { str_p } }; // 9.2 + typedef struct { + int a; + int b; + } struct1; - int array_init_incorrect_levels_a[3][2] = { 1, 2, 3, 4, 5, 6 }; // 9.2 - int array_init_correct_levels_a[3][2] = { { 1, 2 }, { 3, 4 }, { 5, 6 } }; - int array_init_incorrect_levels_b[6] = { { 1, 2 }, { 3, 4 }, { 5, 6 } }; // 9.2 - int array_init_correct_levels_b[6] = { 1, 2, 3, 4, 5, 6 }; + struct1 m = { }; // 9.2 + struct1 n = { 0 }; +} - int array_incorrect_designator_a[1] = { [0][1] = 1 }; // 9.2 - int array_incorrect_designator_b[1] = { [0] = { 1, 2 } }; // 9.2 - int array_incorrect_designator_c[1][2] = { [0] = 1 }; // 9.2 - int array_incorrect_designator_d[2][2] = { { 1, 2 }, [1][0] = {3, 4} }; // 9.2 - int array_correct_designator_a[2] = { [0] = 1, 2 }; - int array_correct_designator_b[2] = { [1] = 2, [0] = 1 }; - int array_correct_designator_c[2][2] = { { 1, 2 }, [1] = {3, 4} }; - int array_correct_designator_d[2][2] = { { 1, 2 }, [1][0] = 3, 4}; +void misra_9_string_initializers() { + const char a[12] = { "Hello world" }; // 9.2 + const char b[2][20] = "Hello world"; // 9.2 9.3 + const char c[] = "Hello world"; + const char d[15] = "Hello world"; + const char e[1][12] = { "Hello world" }; + const char *f[2] = { "Hello", [1] = "world" }; + const char *g[1] = "Hello world"; // 9.2 + const char h[2][15] = { { 0 }, "Hello world" }; + + char **str_p = &f[0]; + + char **i[1] = { str_p }; + char **j[1] = { { str_p } }; // 9.2 +} + +void misra_9_array_initializers() { + char a[4] = { 1, 2, 3, 4 }; + char b[2][2] = { {1, 2}, {3, 4} }; + char c[2][2] = { 1, 2, 3, 4 }; // 9.2 + char d[6] = { { 1, 2 }, { 3, 4 }, { 5, 6 } }; // 9.2 9.3 + + char e[2][2] = { {1, 2}, {4} }; // 9.3 + char f[2][2] = { 1, 2, 3 }; // 9.2 9.3 + char g[2][2] = { {1, 2, 3, 4} }; // 9.3 + + char h[2][2] = { { 1, { 2 } }, { 3, { 5 } } }; // 9.2 + char i[2][2] = { { 1, { 2 } }, { 3 } }; // 9.2 9.3 + char j[2][3] = { { 1, { 2 }, 3 }, { 4, { 5 }, 6 } }; // 9.2 + char k[2][3] = { { 1, { 2 }, 3 }, { 4, { 5 } } }; // 9.2 9.3 + char l[3] = { 1, { 2, 3 } }; // 9.2 9.3 +} + +void misra_9_array_initializers_with_designators() { + char a[1] = { [0][1] = 1 }; // 9.2 + char b[1] = { [0] = { 1, 2 } }; // 9.2 + char c[2][2] = { [0] = {1, 2, 3} }; + char d[1][2] = { [0] = 1 }; // 9.2 + char e[2][2] = { { 1, 2 }, [1][0] = {3, 4} }; // 9.2 + char f[2] = { [0] = 1, 2 }; + char g[2] = { [1] = 2, [0] = 1 }; + char h[2][2] = { { 1, 2 }, [1] = { 3 } }; // 9.3 + char i[2][2] = { { 1, 2 }, [1] = { 3, 4 } }; + char j[2][2] = { { 1, 2 }, [1] = { [0] = 3 } }; + char k[2][2] = { { 1, 2 }, [1][0] = 3 }; + char l[2][2] = { { 1, 2 }, [1][0] = 3, 4}; // 9.2 + char m[2][2] = { [0] = { [2] = 2 }, [1][5] = 4 }; + char n[2][2] = { [0] = { 1 } }; // 9.3 + char o[2][2] = { { 1 }, [1][0] = 3 }; // 9.3 + char p[2][2] = { { 1, 2 }, { 3, 4 }, [1] = { 3 } }; // 9.3 9.4 + char q[2][2] = { { 1, 2 }, { 1 }, [1] = { [1] = 3 } }; // 9.4 + char r[2][2][2] = { [0][0] = { 1, 2 }, [1] = { [0] = {5, 6} } }; + char s[2][2][2] = { [0][0] = { 1, 2 }, [1] = {5, 6, 7, 8}}; // 9.2 + char t[2][2][2] = { [0][0] = { 1, 2 }, {3, 4}, [1] = {5, 6}}; // 9.2 9.3 + char u[2][2][2] = { [0] = { 1, 2, {3, 4} } }; // 9.2 + char v[2][2][2] = { [0] = { 1, 2, [1] = {3, 4} }}; // 9.2 +} + +void misra_9_struct_initializers() { typedef struct { int i1; int i2; @@ -338,31 +390,77 @@ void misra_9_2() { char c2[4]; } struct2; + typedef struct { + struct1 s[2][2]; + } struct3; + + struct3 sa[2] = { [1].s[1][0].i1 = 3, 4 }; // 9.2 + + struct1 sa = 1; // 9.2 + + struct1 sb = { 1, 2 }; + struct2 sc = { 1, { 2 }, {4, 5, 6, 7} }; + struct2 sd = { 1, { 2, 3 }, {4, 5, 6} }; // 9.3 + struct2 se = { 1, 2, 3, 4, 5, 6, 7 }; // 9.2 + struct2 sf = { 1, { 2, 3 }, 4, 5, 6, 7 }; // 9.2 + struct2 sg = { 1, { 2 }, 4, 5, 6, 7 }; // 9.2 + struct2 sh = { 1, { 2, 3 }, 4, 5, 6 }; // 9.2 9.3 + struct2 si = { 1, 2, 3, {4,5,6,7} }; // 9.2 + int a; + struct1 sj = { a = 1, 2 }; // 13.1 - struct2 struct_empty_init = { }; // 9.2 - struct2 struct_zero_init = { 0 }; - struct1 struct_missing_brackets = 1; // 9.2 - struct2 struct_correct_init = { 1, {2, 3}, {0} }; - struct1 struct_array_incorrect_levels[2] = { 1, 2, 3, 4 }; // 9.2 - struct1 struct_array_correct_levels[2] = { {1, 2}, {3, 4} }; - struct1 struct_correct_designator_a = { .i2 = 2, .i1 = 1 }; - struct2 struct_correct_designator_b = { .is1 = {2, 3}, { 4 } }; - struct1 struct_correct_designator_c = { a = 1, 2 }; // 13.1 - struct2 struct_incorrect_type = { .is1 = struct_correct_designator_b }; // 9.2 - struct2 struct_correct_type = { .is1 = struct_correct_designator_a }; + // Struct types + struct2 sta = { .is1 = sc }; // 9.2 + struct2 stb = { .is1 = sb }; + struct1 stc[1] = { sc }; // 9.2 + struct1 std[1] = { sb }; - struct1 struct_array_incorrect_type[1] = { struct_correct_designator_b }; // 9.2 - struct1 struct_array_correct_type[1] = { struct_correct_designator_a }; + // Struct designators + struct1 sda = { 1, .i2 = 2 }; + struct2 sdb = { 1, { 2, .i2=3 }, .c2[1]=5 }; + struct2 sdc = { 1, { 2, .i2=3 }, .c2 = { 5 } }; // 9.3 + struct2 sdd = { 1, { 2, .i2=3 }, .c2 = 5 }; // 9.2 + struct2 sde = { .is1 = { 2, 3 }, { 4, 5, 6, 7 } }; - union misra_9_2_union { // 19.2 + // Struct arrays + struct1 asa[2] = { {1,2}, {3,4} }; + struct1 asb[2] = { {1}, {3,4} }; + struct1 asc[2] = { {1,2} }; // 9.3 + struct1 asd[2] = { 1,2, 3,4 }; // 9.2 + struct1 ase[2] = { 1,2, 3 }; // 9.2 + struct1 asf[2] = { 1,2 }; // 9.2 9.3 + struct1 asg[2] = { [1].i1 = 3 }; + struct3 ash[2] = { [1].s[1][0].i1 = 3 }; + struct3 asi[2] = { [0] = { .s[0] = { { 1, 2 } }}}; // 9.3 + struct3 asj[2] = { [0] = { .s[0] = { 1, 2 }}}; // 9.2 9.3 + + // Missing type information + dummy_struct dsa = { 1, .a = 2 }; + dummy_struct dsb[2] = { {1,2}, {3,4} }; + dummy_struct dsc[2][2] = { {1,2}, {3,4} }; + dummy_struct dsd[2][2] = { 1, 2, 3, 4 }; // 9.2 + dummy_struct dse[3] = { {1,2}, {3,4}, [1] = {5,6} }; // 9.3 9.4 + dummy_struct dsd[] = { [0] = 1 }; // 9.5 +} + +void misra_9_2() { + union misra_9_2_union { // 19.2 char c; struct1 i; - } u = { 3 }; // 19.2 + } u = { 3 }; // 19.2 } void misra_9_5() { - int x[] = {[0]=23}; // 9.5 + char a[] = { 1, 2, 3 }; + char b[] = { [2] = 5 }; // 9.5 + char c[] = { 1, [1] = 5 }; // 9.5 + char d[] = { [1] = 2, [0] = 1 }; // 9.5 + + char e[][2] = { { 1, 2 }, { 3, 4 } }; + char f[][2] = { [1] = { 3, 4 } }; // 9.5 + char g[][2] = { { 1, 2 }, [1] = { 3, 4 } }; // 9.5 + char h[][2] = { [1] = { 1, 2 }, [0] = { 3, 4 } }; // 9.5 } typedef char misra_10_1_char_t; @@ -658,7 +756,7 @@ void misra_13_1(int *p) { int a4[2] = { [0]=0, [1]=(v+=1) }; // 13.1 int a5[2] = { [0]=0, [1]=(v+1) }; int a6[2] = { v, 1 }; - int a6[2] = { v >>= 3 }; // 13.1 + int a6[2] = { v >>= 3 }; // 13.1 9.3 int a7[2] = { v, ++v }; // 13.1 int a8[1] = { vv }; // TODO: 13.1 Trac #9504