MISRA 9.2 to 9.5 (#2954)
This commit is contained in:
parent
c9d2e55ea9
commit
d4860f500a
269
addons/misra.py
269
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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue