CloverBootloader/BaseTools/Source/Python/Ecc/c.py

2652 lines
111 KiB
Python
Raw Normal View History

## @file
# This file is used to be the c coding style checking of ECC tool
#
# Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
from __future__ import print_function
from __future__ import absolute_import
import sys
import Common.LongFilePathOs as os
import re
import string
from Ecc import CodeFragmentCollector
from Ecc import FileProfile
from CommonDataClass import DataClass
from Ecc import Database
from Common import EdkLogger
from Ecc.EccToolError import *
from Ecc import EccGlobalData
from Ecc import MetaDataParser
IncludeFileListDict = {}
AllIncludeFileListDict = {}
IncludePathListDict = {}
ComplexTypeDict = {}
SUDict = {}
IgnoredKeywordList = ['EFI_ERROR']
def GetIgnoredDirListPattern():
skipList = list(EccGlobalData.gConfig.SkipDirList) + ['.svn']
DirString = '|'.join(skipList)
p = re.compile(r'.*[\\/](?:%s)[\\/]?.*' % DirString)
return p
def GetFuncDeclPattern():
p = re.compile(r'(?:EFIAPI|EFI_BOOT_SERVICE|EFI_RUNTIME_SERVICE)?\s*[_\w]+\s*\(.*\)$', re.DOTALL)
return p
def GetArrayPattern():
p = re.compile(r'[_\w]*\s*[\[.*\]]+')
return p
def GetTypedefFuncPointerPattern():
p = re.compile('[_\w\s]*\([\w\s]*\*+\s*[_\w]+\s*\)\s*\(.*\)', re.DOTALL)
return p
def GetDB():
return EccGlobalData.gDb
def GetConfig():
return EccGlobalData.gConfig
def PrintErrorMsg(ErrorType, Msg, TableName, ItemId):
Msg = Msg.replace('\n', '').replace('\r', '')
MsgPartList = Msg.split()
Msg = ''
for Part in MsgPartList:
Msg += Part
Msg += ' '
GetDB().TblReport.Insert(ErrorType, OtherMsg=Msg, BelongsToTable=TableName, BelongsToItem=ItemId)
def GetIdType(Str):
Type = DataClass.MODEL_UNKNOWN
Str = Str.replace('#', '# ')
List = Str.split()
if List[1] == 'include':
Type = DataClass.MODEL_IDENTIFIER_INCLUDE
elif List[1] == 'define':
Type = DataClass.MODEL_IDENTIFIER_MACRO_DEFINE
elif List[1] == 'ifdef':
Type = DataClass.MODEL_IDENTIFIER_MACRO_IFDEF
elif List[1] == 'ifndef':
Type = DataClass.MODEL_IDENTIFIER_MACRO_IFNDEF
elif List[1] == 'endif':
Type = DataClass.MODEL_IDENTIFIER_MACRO_ENDIF
elif List[1] == 'pragma':
Type = DataClass.MODEL_IDENTIFIER_MACRO_PROGMA
else:
Type = DataClass.MODEL_UNKNOWN
return Type
def SuOccurInTypedef (Su, TdList):
for Td in TdList:
if Su.StartPos[0] == Td.StartPos[0] and Su.EndPos[0] == Td.EndPos[0]:
return True
return False
def GetIdentifierList():
IdList = []
for comment in FileProfile.CommentList:
IdComment = DataClass.IdentifierClass(-1, '', '', '', comment.Content, DataClass.MODEL_IDENTIFIER_COMMENT, -1, -1, comment.StartPos[0], comment.StartPos[1], comment.EndPos[0], comment.EndPos[1])
IdList.append(IdComment)
for pp in FileProfile.PPDirectiveList:
Type = GetIdType(pp.Content)
IdPP = DataClass.IdentifierClass(-1, '', '', '', pp.Content, Type, -1, -1, pp.StartPos[0], pp.StartPos[1], pp.EndPos[0], pp.EndPos[1])
IdList.append(IdPP)
for pe in FileProfile.PredicateExpressionList:
IdPE = DataClass.IdentifierClass(-1, '', '', '', pe.Content, DataClass.MODEL_IDENTIFIER_PREDICATE_EXPRESSION, -1, -1, pe.StartPos[0], pe.StartPos[1], pe.EndPos[0], pe.EndPos[1])
IdList.append(IdPE)
FuncDeclPattern = GetFuncDeclPattern()
ArrayPattern = GetArrayPattern()
for var in FileProfile.VariableDeclarationList:
DeclText = var.Declarator.lstrip()
FuncPointerPattern = GetTypedefFuncPointerPattern()
if FuncPointerPattern.match(DeclText):
continue
VarNameStartLine = var.NameStartPos[0]
VarNameStartColumn = var.NameStartPos[1]
FirstChar = DeclText[0]
while not FirstChar.isalpha() and FirstChar != '_':
if FirstChar == '*':
var.Modifier += '*'
VarNameStartColumn += 1
DeclText = DeclText.lstrip('*')
elif FirstChar == '\r':
DeclText = DeclText.lstrip('\r\n').lstrip('\r')
VarNameStartLine += 1
VarNameStartColumn = 0
elif FirstChar == '\n':
DeclText = DeclText.lstrip('\n')
VarNameStartLine += 1
VarNameStartColumn = 0
elif FirstChar == ' ':
DeclText = DeclText.lstrip(' ')
VarNameStartColumn += 1
elif FirstChar == '\t':
DeclText = DeclText.lstrip('\t')
VarNameStartColumn += 8
else:
DeclText = DeclText[1:]
VarNameStartColumn += 1
FirstChar = DeclText[0]
var.Declarator = DeclText
if FuncDeclPattern.match(var.Declarator):
DeclSplitList = var.Declarator.split('(')
FuncName = DeclSplitList[0].strip()
FuncNamePartList = FuncName.split()
if len(FuncNamePartList) > 1:
FuncName = FuncNamePartList[-1].strip()
NameStart = DeclSplitList[0].rfind(FuncName)
var.Declarator = var.Declarator[NameStart:]
if NameStart > 0:
var.Modifier += ' ' + DeclSplitList[0][0:NameStart]
Index = 0
PreChar = ''
while Index < NameStart:
FirstChar = DeclSplitList[0][Index]
if DeclSplitList[0][Index:].startswith('EFIAPI'):
Index += 6
VarNameStartColumn += 6
PreChar = ''
continue
elif FirstChar == '\r':
Index += 1
VarNameStartLine += 1
VarNameStartColumn = 0
elif FirstChar == '\n':
Index += 1
if PreChar != '\r':
VarNameStartLine += 1
VarNameStartColumn = 0
elif FirstChar == ' ':
Index += 1
VarNameStartColumn += 1
elif FirstChar == '\t':
Index += 1
VarNameStartColumn += 8
else:
Index += 1
VarNameStartColumn += 1
PreChar = FirstChar
IdVar = DataClass.IdentifierClass(-1, var.Modifier, '', var.Declarator, FuncName, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION, -1, -1, var.StartPos[0], var.StartPos[1], VarNameStartLine, VarNameStartColumn)
IdList.append(IdVar)
continue
if var.Declarator.find('{') == -1:
for decl in var.Declarator.split(','):
DeclList = decl.split('=')
Name = DeclList[0].strip()
if ArrayPattern.match(Name):
LSBPos = var.Declarator.find('[')
var.Modifier += ' ' + Name[LSBPos:]
Name = Name[0:LSBPos]
IdVar = DataClass.IdentifierClass(-1, var.Modifier, '', Name, (len(DeclList) > 1 and [DeclList[1]]or [''])[0], DataClass.MODEL_IDENTIFIER_VARIABLE, -1, -1, var.StartPos[0], var.StartPos[1], VarNameStartLine, VarNameStartColumn)
IdList.append(IdVar)
else:
DeclList = var.Declarator.split('=')
Name = DeclList[0].strip()
if ArrayPattern.match(Name):
LSBPos = var.Declarator.find('[')
var.Modifier += ' ' + Name[LSBPos:]
Name = Name[0:LSBPos]
IdVar = DataClass.IdentifierClass(-1, var.Modifier, '', Name, (len(DeclList) > 1 and [DeclList[1]]or [''])[0], DataClass.MODEL_IDENTIFIER_VARIABLE, -1, -1, var.StartPos[0], var.StartPos[1], VarNameStartLine, VarNameStartColumn)
IdList.append(IdVar)
for enum in FileProfile.EnumerationDefinitionList:
LBPos = enum.Content.find('{')
RBPos = enum.Content.find('}')
Name = enum.Content[4:LBPos].strip()
Value = enum.Content[LBPos + 1:RBPos]
IdEnum = DataClass.IdentifierClass(-1, '', '', Name, Value, DataClass.MODEL_IDENTIFIER_ENUMERATE, -1, -1, enum.StartPos[0], enum.StartPos[1], enum.EndPos[0], enum.EndPos[1])
IdList.append(IdEnum)
for su in FileProfile.StructUnionDefinitionList:
if SuOccurInTypedef(su, FileProfile.TypedefDefinitionList):
continue
Type = DataClass.MODEL_IDENTIFIER_STRUCTURE
SkipLen = 6
if su.Content.startswith('union'):
Type = DataClass.MODEL_IDENTIFIER_UNION
SkipLen = 5
LBPos = su.Content.find('{')
RBPos = su.Content.find('}')
if LBPos == -1 or RBPos == -1:
Name = su.Content[SkipLen:].strip()
Value = ''
else:
Name = su.Content[SkipLen:LBPos].strip()
Value = su.Content[LBPos:RBPos + 1]
IdPE = DataClass.IdentifierClass(-1, '', '', Name, Value, Type, -1, -1, su.StartPos[0], su.StartPos[1], su.EndPos[0], su.EndPos[1])
IdList.append(IdPE)
TdFuncPointerPattern = GetTypedefFuncPointerPattern()
for td in FileProfile.TypedefDefinitionList:
Modifier = ''
Name = td.ToType
Value = td.FromType
if TdFuncPointerPattern.match(td.ToType):
Modifier = td.FromType
LBPos = td.ToType.find('(')
TmpStr = td.ToType[LBPos + 1:].strip()
StarPos = TmpStr.find('*')
if StarPos != -1:
Modifier += ' ' + TmpStr[0:StarPos]
while TmpStr[StarPos] == '*':
# Modifier += ' ' + '*'
StarPos += 1
TmpStr = TmpStr[StarPos:].strip()
RBPos = TmpStr.find(')')
Name = TmpStr[0:RBPos]
Value = 'FP' + TmpStr[RBPos + 1:]
else:
while Name.startswith('*'):
Value += ' ' + '*'
Name = Name.lstrip('*').strip()
if Name.find('[') != -1:
LBPos = Name.find('[')
RBPos = Name.rfind(']')
Value += Name[LBPos : RBPos + 1]
Name = Name[0 : LBPos]
IdTd = DataClass.IdentifierClass(-1, Modifier, '', Name, Value, DataClass.MODEL_IDENTIFIER_TYPEDEF, -1, -1, td.StartPos[0], td.StartPos[1], td.EndPos[0], td.EndPos[1])
IdList.append(IdTd)
for funcCall in FileProfile.FunctionCallingList:
IdFC = DataClass.IdentifierClass(-1, '', '', funcCall.FuncName, funcCall.ParamList, DataClass.MODEL_IDENTIFIER_FUNCTION_CALLING, -1, -1, funcCall.StartPos[0], funcCall.StartPos[1], funcCall.EndPos[0], funcCall.EndPos[1])
IdList.append(IdFC)
return IdList
def StripNonAlnumChars(Str):
StrippedStr = ''
for Char in Str:
if Char.isalnum() or Char == '_':
StrippedStr += Char
return StrippedStr
def GetParamList(FuncDeclarator, FuncNameLine=0, FuncNameOffset=0):
FuncDeclarator = StripComments(FuncDeclarator)
ParamIdList = []
#DeclSplitList = FuncDeclarator.split('(')
LBPos = FuncDeclarator.find('(')
#if len(DeclSplitList) < 2:
if LBPos == -1:
return ParamIdList
#FuncName = DeclSplitList[0]
FuncName = FuncDeclarator[0:LBPos]
#ParamStr = DeclSplitList[1].rstrip(')')
ParamStr = FuncDeclarator[LBPos + 1:].rstrip(')')
LineSkipped = 0
OffsetSkipped = 0
TailChar = FuncName[-1]
while not TailChar.isalpha() and TailChar != '_':
if TailChar == '\n':
FuncName = FuncName.rstrip('\r\n').rstrip('\n')
LineSkipped += 1
OffsetSkipped = 0
elif TailChar == '\r':
FuncName = FuncName.rstrip('\r')
LineSkipped += 1
OffsetSkipped = 0
elif TailChar == ' ':
FuncName = FuncName.rstrip(' ')
OffsetSkipped += 1
elif TailChar == '\t':
FuncName = FuncName.rstrip('\t')
OffsetSkipped += 8
else:
FuncName = FuncName[:-1]
TailChar = FuncName[-1]
OffsetSkipped += 1 #skip '('
for p in ParamStr.split(','):
ListP = p.split()
if len(ListP) == 0:
continue
ParamName = ListP[-1]
DeclText = ParamName.strip()
RightSpacePos = p.rfind(ParamName)
ParamModifier = p[0:RightSpacePos]
if ParamName == 'OPTIONAL':
if ParamModifier == '':
ParamModifier += ' ' + 'OPTIONAL'
DeclText = ''
else:
ParamName = ListP[-2]
DeclText = ParamName.strip()
RightSpacePos = p.rfind(ParamName)
ParamModifier = p[0:RightSpacePos]
ParamModifier += 'OPTIONAL'
while DeclText.startswith('*'):
ParamModifier += ' ' + '*'
DeclText = DeclText.lstrip('*').strip()
ParamName = DeclText
# ignore array length if exists.
LBIndex = ParamName.find('[')
if LBIndex != -1:
ParamName = ParamName[0:LBIndex]
Start = RightSpacePos
Index = 0
PreChar = ''
while Index < Start:
FirstChar = p[Index]
if FirstChar == '\r':
Index += 1
LineSkipped += 1
OffsetSkipped = 0
elif FirstChar == '\n':
Index += 1
if PreChar != '\r':
LineSkipped += 1
OffsetSkipped = 0
elif FirstChar == ' ':
Index += 1
OffsetSkipped += 1
elif FirstChar == '\t':
Index += 1
OffsetSkipped += 8
else:
Index += 1
OffsetSkipped += 1
PreChar = FirstChar
ParamBeginLine = FuncNameLine + LineSkipped
ParamBeginOffset = FuncNameOffset + OffsetSkipped
Index = Start + len(ParamName)
PreChar = ''
while Index < len(p):
FirstChar = p[Index]
if FirstChar == '\r':
Index += 1
LineSkipped += 1
OffsetSkipped = 0
elif FirstChar == '\n':
Index += 1
if PreChar != '\r':
LineSkipped += 1
OffsetSkipped = 0
elif FirstChar == ' ':
Index += 1
OffsetSkipped += 1
elif FirstChar == '\t':
Index += 1
OffsetSkipped += 8
else:
Index += 1
OffsetSkipped += 1
PreChar = FirstChar
ParamEndLine = FuncNameLine + LineSkipped
ParamEndOffset = FuncNameOffset + OffsetSkipped
if ParamName != '...':
ParamName = StripNonAlnumChars(ParamName)
IdParam = DataClass.IdentifierClass(-1, ParamModifier, '', ParamName, '', DataClass.MODEL_IDENTIFIER_PARAMETER, -1, -1, ParamBeginLine, ParamBeginOffset, ParamEndLine, ParamEndOffset)
ParamIdList.append(IdParam)
OffsetSkipped += 1 #skip ','
return ParamIdList
def GetFunctionList():
FuncObjList = []
for FuncDef in FileProfile.FunctionDefinitionList:
ParamIdList = []
DeclText = FuncDef.Declarator.lstrip()
FuncNameStartLine = FuncDef.NamePos[0]
FuncNameStartColumn = FuncDef.NamePos[1]
FirstChar = DeclText[0]
while not FirstChar.isalpha() and FirstChar != '_':
if FirstChar == '*':
FuncDef.Modifier += '*'
FuncNameStartColumn += 1
DeclText = DeclText.lstrip('*')
elif FirstChar == '\r':
DeclText = DeclText.lstrip('\r\n').lstrip('\r')
FuncNameStartLine += 1
FuncNameStartColumn = 0
elif FirstChar == '\n':
DeclText = DeclText.lstrip('\n')
FuncNameStartLine += 1
FuncNameStartColumn = 0
elif FirstChar == ' ':
DeclText = DeclText.lstrip(' ')
FuncNameStartColumn += 1
elif FirstChar == '\t':
DeclText = DeclText.lstrip('\t')
FuncNameStartColumn += 8
else:
DeclText = DeclText[1:]
FuncNameStartColumn += 1
FirstChar = DeclText[0]
FuncDef.Declarator = DeclText
DeclSplitList = FuncDef.Declarator.split('(')
if len(DeclSplitList) < 2:
continue
FuncName = DeclSplitList[0]
FuncNamePartList = FuncName.split()
if len(FuncNamePartList) > 1:
FuncName = FuncNamePartList[-1]
NameStart = DeclSplitList[0].rfind(FuncName)
if NameStart > 0:
FuncDef.Modifier += ' ' + DeclSplitList[0][0:NameStart]
Index = 0
PreChar = ''
while Index < NameStart:
FirstChar = DeclSplitList[0][Index]
if DeclSplitList[0][Index:].startswith('EFIAPI'):
Index += 6
FuncNameStartColumn += 6
PreChar = ''
continue
elif FirstChar == '\r':
Index += 1
FuncNameStartLine += 1
FuncNameStartColumn = 0
elif FirstChar == '\n':
Index += 1
if PreChar != '\r':
FuncNameStartLine += 1
FuncNameStartColumn = 0
elif FirstChar == ' ':
Index += 1
FuncNameStartColumn += 1
elif FirstChar == '\t':
Index += 1
FuncNameStartColumn += 8
else:
Index += 1
FuncNameStartColumn += 1
PreChar = FirstChar
FuncObj = DataClass.FunctionClass(-1, FuncDef.Declarator, FuncDef.Modifier, FuncName.strip(), '', FuncDef.StartPos[0], FuncDef.StartPos[1], FuncDef.EndPos[0], FuncDef.EndPos[1], FuncDef.LeftBracePos[0], FuncDef.LeftBracePos[1], -1, ParamIdList, [], FuncNameStartLine, FuncNameStartColumn)
FuncObjList.append(FuncObj)
return FuncObjList
def GetFileModificationTimeFromDB(FullFileName):
TimeValue = 0.0
Db = GetDB()
SqlStatement = """ select TimeStamp
from File
where FullPath = \'%s\'
""" % (FullFileName)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
TimeValue = Result[0]
return TimeValue
def CollectSourceCodeDataIntoDB(RootDir):
FileObjList = []
tuple = os.walk(RootDir)
IgnoredPattern = GetIgnoredDirListPattern()
ParseErrorFileList = []
TokenReleaceList = EccGlobalData.gConfig.TokenReleaceList
TokenReleaceList.extend(['L",\\\""'])
for dirpath, dirnames, filenames in tuple:
if IgnoredPattern.match(dirpath.upper()):
continue
for Dir in dirnames:
Dirname = os.path.join(dirpath, Dir)
if os.path.islink(Dirname):
Dirname = os.path.realpath(Dirname)
if os.path.isdir(Dirname):
# symlinks to directories are treated as directories
dirnames.remove(Dir)
dirnames.append(Dirname)
for f in filenames:
if f.lower() in EccGlobalData.gConfig.SkipFileList:
continue
collector = None
FullName = os.path.normpath(os.path.join(dirpath, f))
model = DataClass.MODEL_FILE_OTHERS
if os.path.splitext(f)[1] in ('.h', '.c'):
EdkLogger.info("Parsing " + FullName)
model = f.endswith('c') and DataClass.MODEL_FILE_C or DataClass.MODEL_FILE_H
collector = CodeFragmentCollector.CodeFragmentCollector(FullName)
collector.TokenReleaceList = TokenReleaceList
try:
collector.ParseFile()
except UnicodeError:
ParseErrorFileList.append(FullName)
collector.CleanFileProfileBuffer()
collector.ParseFileWithClearedPPDirective()
# collector.PrintFragments()
BaseName = os.path.basename(f)
DirName = os.path.dirname(FullName)
Ext = os.path.splitext(f)[1].lstrip('.')
ModifiedTime = os.path.getmtime(FullName)
FileObj = DataClass.FileClass(-1, BaseName, Ext, DirName, FullName, model, ModifiedTime, GetFunctionList(), GetIdentifierList(), [])
FileObjList.append(FileObj)
if collector:
collector.CleanFileProfileBuffer()
if len(ParseErrorFileList) > 0:
EdkLogger.info("Found unrecoverable error during parsing:\n\t%s\n" % "\n\t".join(ParseErrorFileList))
Db = GetDB()
for file in FileObjList:
if file.ExtName.upper() not in ['INF', 'DEC', 'DSC', 'FDF']:
Db.InsertOneFile(file)
Db.UpdateIdentifierBelongsToFunction()
def GetTableID(FullFileName, ErrorMsgList=None):
if ErrorMsgList is None:
ErrorMsgList = []
Db = GetDB()
SqlStatement = """ select ID
from File
where FullPath like '%s'
""" % FullFileName
ResultSet = Db.TblFile.Exec(SqlStatement)
FileID = -1
for Result in ResultSet:
if FileID != -1:
ErrorMsgList.append('Duplicate file ID found in DB for file %s' % FullFileName)
return - 2
FileID = Result[0]
if FileID == -1:
ErrorMsgList.append('NO file ID found in DB for file %s' % FullFileName)
return - 1
return FileID
def GetIncludeFileList(FullFileName):
if os.path.splitext(FullFileName)[1].upper() not in ('.H'):
return []
IFList = IncludeFileListDict.get(FullFileName)
if IFList is not None:
return IFList
FileID = GetTableID(FullFileName)
if FileID < 0:
return []
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Value
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_INCLUDE)
ResultSet = Db.TblFile.Exec(SqlStatement)
IncludeFileListDict[FullFileName] = ResultSet
return ResultSet
def GetFullPathOfIncludeFile(Str, IncludePathList):
for IncludePath in IncludePathList:
FullPath = os.path.join(IncludePath, Str)
FullPath = os.path.normpath(FullPath)
if os.path.exists(FullPath):
return FullPath
return None
def GetAllIncludeFiles(FullFileName):
if AllIncludeFileListDict.get(FullFileName) is not None:
return AllIncludeFileListDict.get(FullFileName)
FileDirName = os.path.dirname(FullFileName)
IncludePathList = IncludePathListDict.get(FileDirName)
if IncludePathList is None:
IncludePathList = MetaDataParser.GetIncludeListOfFile(EccGlobalData.gWorkspace, FullFileName, GetDB())
if FileDirName not in IncludePathList:
IncludePathList.insert(0, FileDirName)
IncludePathListDict[FileDirName] = IncludePathList
IncludeFileQueue = []
for IncludeFile in GetIncludeFileList(FullFileName):
FileName = IncludeFile[0].lstrip('#').strip()
FileName = FileName.lstrip('include').strip()
FileName = FileName.strip('\"')
FileName = FileName.lstrip('<').rstrip('>').strip()
FullPath = GetFullPathOfIncludeFile(FileName, IncludePathList)
if FullPath is not None:
IncludeFileQueue.append(FullPath)
i = 0
while i < len(IncludeFileQueue):
for IncludeFile in GetIncludeFileList(IncludeFileQueue[i]):
FileName = IncludeFile[0].lstrip('#').strip()
FileName = FileName.lstrip('include').strip()
FileName = FileName.strip('\"')
FileName = FileName.lstrip('<').rstrip('>').strip()
FullPath = GetFullPathOfIncludeFile(FileName, IncludePathList)
if FullPath is not None and FullPath not in IncludeFileQueue:
IncludeFileQueue.insert(i + 1, FullPath)
i += 1
AllIncludeFileListDict[FullFileName] = IncludeFileQueue
return IncludeFileQueue
def GetPredicateListFromPredicateExpStr(PES):
PredicateList = []
i = 0
PredicateBegin = 0
#PredicateEnd = 0
LogicOpPos = -1
p = GetFuncDeclPattern()
while i < len(PES) - 1:
if (PES[i].isalnum() or PES[i] == '_' or PES[i] == '*') and LogicOpPos > PredicateBegin:
PredicateBegin = i
if (PES[i] == '&' and PES[i + 1] == '&') or (PES[i] == '|' and PES[i + 1] == '|'):
LogicOpPos = i
Exp = PES[PredicateBegin:i].strip()
# Exp may contain '.' or '->'
TmpExp = Exp.replace('.', '').replace('->', '')
if p.match(TmpExp):
PredicateList.append(Exp)
else:
PredicateList.append(Exp.rstrip(';').rstrip(')').strip())
i += 1
if PredicateBegin > LogicOpPos:
while PredicateBegin < len(PES):
if PES[PredicateBegin].isalnum() or PES[PredicateBegin] == '_' or PES[PredicateBegin] == '*':
break
PredicateBegin += 1
Exp = PES[PredicateBegin:len(PES)].strip()
# Exp may contain '.' or '->'
TmpExp = Exp.replace('.', '').replace('->', '')
if p.match(TmpExp):
PredicateList.append(Exp)
else:
PredicateList.append(Exp.rstrip(';').rstrip(')').strip())
return PredicateList
def GetCNameList(Lvalue, StarList=[]):
Lvalue += ' '
i = 0
SearchBegin = 0
VarStart = -1
VarEnd = -1
VarList = []
while SearchBegin < len(Lvalue):
while i < len(Lvalue):
if Lvalue[i].isalnum() or Lvalue[i] == '_':
if VarStart == -1:
VarStart = i
VarEnd = i
i += 1
elif VarEnd != -1:
VarList.append(Lvalue[VarStart:VarEnd + 1])
i += 1
break
else:
if VarStart == -1 and Lvalue[i] == '*':
StarList.append('*')
i += 1
if VarEnd == -1:
break
DotIndex = Lvalue[VarEnd:].find('.')
ArrowIndex = Lvalue[VarEnd:].find('->')
if DotIndex == -1 and ArrowIndex == -1:
break
elif DotIndex == -1 and ArrowIndex != -1:
SearchBegin = VarEnd + ArrowIndex
elif ArrowIndex == -1 and DotIndex != -1:
SearchBegin = VarEnd + DotIndex
else:
SearchBegin = VarEnd + ((DotIndex < ArrowIndex) and DotIndex or ArrowIndex)
i = SearchBegin
VarStart = -1
VarEnd = -1
return VarList
def SplitPredicateByOp(Str, Op, IsFuncCalling=False):
Name = Str.strip()
Value = None
if IsFuncCalling:
Index = 0
LBFound = False
UnmatchedLBCount = 0
while Index < len(Str):
while not LBFound and Str[Index] != '_' and not Str[Index].isalnum():
Index += 1
while not LBFound and (Str[Index].isalnum() or Str[Index] == '_'):
Index += 1
# maybe type-cast at the beginning, skip it.
RemainingStr = Str[Index:].lstrip()
if RemainingStr.startswith(')') and not LBFound:
Index += 1
continue
if RemainingStr.startswith('(') and not LBFound:
LBFound = True
if Str[Index] == '(':
UnmatchedLBCount += 1
Index += 1
continue
if Str[Index] == ')':
UnmatchedLBCount -= 1
Index += 1
if UnmatchedLBCount == 0:
break
continue
Index += 1
if UnmatchedLBCount > 0:
return [Name]
IndexInRemainingStr = Str[Index:].find(Op)
if IndexInRemainingStr == -1:
return [Name]
Name = Str[0:Index + IndexInRemainingStr].strip()
Value = Str[Index + IndexInRemainingStr + len(Op):].strip().strip(')')
return [Name, Value]
TmpStr = Str.rstrip(';').rstrip(')')
while True:
Index = TmpStr.rfind(Op)
if Index == -1:
return [Name]
if Str[Index - 1].isalnum() or Str[Index - 1].isspace() or Str[Index - 1] == ')' or Str[Index - 1] == ']':
Name = Str[0:Index].strip()
Value = Str[Index + len(Op):].strip()
return [Name, Value]
TmpStr = Str[0:Index - 1]
def SplitPredicateStr(Str):
Str = Str.lstrip('(')
IsFuncCalling = False
p = GetFuncDeclPattern()
TmpStr = Str.replace('.', '').replace('->', '')
if p.match(TmpStr):
IsFuncCalling = True
PredPartList = SplitPredicateByOp(Str, '==', IsFuncCalling)
if len(PredPartList) > 1:
return [PredPartList, '==']
PredPartList = SplitPredicateByOp(Str, '!=', IsFuncCalling)
if len(PredPartList) > 1:
return [PredPartList, '!=']
PredPartList = SplitPredicateByOp(Str, '>=', IsFuncCalling)
if len(PredPartList) > 1:
return [PredPartList, '>=']
PredPartList = SplitPredicateByOp(Str, '<=', IsFuncCalling)
if len(PredPartList) > 1:
return [PredPartList, '<=']
PredPartList = SplitPredicateByOp(Str, '>', IsFuncCalling)
if len(PredPartList) > 1:
return [PredPartList, '>']
PredPartList = SplitPredicateByOp(Str, '<', IsFuncCalling)
if len(PredPartList) > 1:
return [PredPartList, '<']
return [[Str, None], None]
def GetFuncContainsPE(ExpLine, ResultSet):
for Result in ResultSet:
if Result[0] < ExpLine and Result[1] > ExpLine:
return Result
return None
def PatternInModifier(Modifier, SubStr):
PartList = Modifier.split()
for Part in PartList:
if Part == SubStr:
return True
return False
def GetDataTypeFromModifier(ModifierStr):
MList = ModifierStr.split()
ReturnType = ''
for M in MList:
if M in EccGlobalData.gConfig.ModifierSet:
continue
# remove array suffix
if M.startswith('[') or M.endswith(']'):
continue
ReturnType += M + ' '
ReturnType = ReturnType.strip()
if len(ReturnType) == 0:
ReturnType = 'VOID'
return ReturnType
def DiffModifier(Str1, Str2):
PartList1 = Str1.split()
PartList2 = Str2.split()
if PartList1 == PartList2:
return False
else:
return True
def GetTypedefDict(FullFileName):
Dict = ComplexTypeDict.get(FullFileName)
if Dict is not None:
return Dict
FileID = GetTableID(FullFileName)
FileTable = 'Identifier' + str(FileID)
Db = GetDB()
SqlStatement = """ select Modifier, Name, Value, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_TYPEDEF)
ResultSet = Db.TblFile.Exec(SqlStatement)
Dict = {}
for Result in ResultSet:
if len(Result[0]) == 0:
Dict[Result[1]] = Result[2]
IncludeFileList = GetAllIncludeFiles(FullFileName)
for F in IncludeFileList:
FileID = GetTableID(F)
if FileID < 0:
continue
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Modifier, Name, Value, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_TYPEDEF)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
if not Result[2].startswith('FP ('):
Dict[Result[1]] = Result[2]
else:
if len(Result[0]) == 0:
Dict[Result[1]] = 'VOID'
else:
Dict[Result[1]] = GetDataTypeFromModifier(Result[0])
ComplexTypeDict[FullFileName] = Dict
return Dict
def GetSUDict(FullFileName):
Dict = SUDict.get(FullFileName)
if Dict is not None:
return Dict
FileID = GetTableID(FullFileName)
FileTable = 'Identifier' + str(FileID)
Db = GetDB()
SqlStatement = """ select Name, Value, ID
from %s
where Model = %d or Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_STRUCTURE, DataClass.MODEL_IDENTIFIER_UNION)
ResultSet = Db.TblFile.Exec(SqlStatement)
Dict = {}
for Result in ResultSet:
if len(Result[1]) > 0:
Dict[Result[0]] = Result[1]
IncludeFileList = GetAllIncludeFiles(FullFileName)
for F in IncludeFileList:
FileID = GetTableID(F)
if FileID < 0:
continue
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Name, Value, ID
from %s
where Model = %d or Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_STRUCTURE, DataClass.MODEL_IDENTIFIER_UNION)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
if len(Result[1]) > 0:
Dict[Result[0]] = Result[1]
SUDict[FullFileName] = Dict
return Dict
def StripComments(Str):
Str += ' '
ListFromStr = list(Str)
InComment = False
DoubleSlashComment = False
Index = 0
while Index < len(ListFromStr):
# meet new line, then no longer in a comment for //
if ListFromStr[Index] == '\n':
if InComment and DoubleSlashComment:
InComment = False
DoubleSlashComment = False
Index += 1
# check for */ comment end
elif InComment and not DoubleSlashComment and ListFromStr[Index] == '*' and ListFromStr[Index + 1] == '/':
ListFromStr[Index] = ' '
Index += 1
ListFromStr[Index] = ' '
Index += 1
InComment = False
# set comments to spaces
elif InComment:
ListFromStr[Index] = ' '
Index += 1
# check for // comment
elif ListFromStr[Index] == '/' and ListFromStr[Index + 1] == '/':
InComment = True
DoubleSlashComment = True
# check for /* comment start
elif ListFromStr[Index] == '/' and ListFromStr[Index + 1] == '*':
ListFromStr[Index] = ' '
Index += 1
ListFromStr[Index] = ' '
Index += 1
InComment = True
else:
Index += 1
# restore from List to String
Str = "".join(ListFromStr)
Str = Str.rstrip(' ')
return Str
def GetFinalTypeValue(Type, FieldName, TypedefDict, SUDict):
Value = TypedefDict.get(Type)
if Value is None:
Value = SUDict.get(Type)
if Value is None:
return None
LBPos = Value.find('{')
while LBPos == -1:
FTList = Value.split()
for FT in FTList:
if FT not in ('struct', 'union'):
Value = TypedefDict.get(FT)
if Value is None:
Value = SUDict.get(FT)
break
if Value is None:
return None
LBPos = Value.find('{')
# RBPos = Value.find('}')
Fields = Value[LBPos + 1:]
Fields = StripComments(Fields)
FieldsList = Fields.split(';')
for Field in FieldsList:
Field = Field.strip()
Index = Field.rfind(FieldName)
if Index < 1:
continue
if not Field[Index - 1].isalnum():
if Index + len(FieldName) == len(Field):
Type = GetDataTypeFromModifier(Field[0:Index])
return Type.strip()
else:
# For the condition that the field in struct is an array with [] suffixes...
if not Field[Index + len(FieldName)].isalnum():
Type = GetDataTypeFromModifier(Field[0:Index])
return Type.strip()
return None
def GetRealType(Type, TypedefDict, TargetType=None):
if TargetType is not None and Type == TargetType:
return Type
while TypedefDict.get(Type):
Type = TypedefDict.get(Type)
if TargetType is not None and Type == TargetType:
return Type
return Type
def GetTypeInfo(RefList, Modifier, FullFileName, TargetType=None):
TypedefDict = GetTypedefDict(FullFileName)
SUDict = GetSUDict(FullFileName)
Type = GetDataTypeFromModifier(Modifier).replace('*', '').strip()
Type = Type.split()[-1]
Index = 0
while Index < len(RefList):
FieldName = RefList[Index]
FromType = GetFinalTypeValue(Type, FieldName, TypedefDict, SUDict)
if FromType is None:
return None
# we want to determine the exact type.
if TargetType is not None:
Type = FromType.split()[0]
# we only want to check if it is a pointer
else:
Type = FromType
if Type.find('*') != -1 and Index == len(RefList) - 1:
return Type
Type = FromType.split()[0]
Index += 1
Type = GetRealType(Type, TypedefDict, TargetType)
return Type
def GetVarInfo(PredVarList, FuncRecord, FullFileName, IsFuncCall=False, TargetType=None, StarList=None):
PredVar = PredVarList[0]
FileID = GetTableID(FullFileName)
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
# search variable in include files
# it is a function call, search function declarations and definitions
if IsFuncCall:
SqlStatement = """ select Modifier, ID
from %s
where Model = %d and Value = \'%s\'
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION, PredVar)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
Type = GetDataTypeFromModifier(Result[0]).split()[-1]
TypedefDict = GetTypedefDict(FullFileName)
Type = GetRealType(Type, TypedefDict, TargetType)
return Type
IncludeFileList = GetAllIncludeFiles(FullFileName)
for F in IncludeFileList:
FileID = GetTableID(F)
if FileID < 0:
continue
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Modifier, ID
from %s
where Model = %d and Value = \'%s\'
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION, PredVar)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
Type = GetDataTypeFromModifier(Result[0]).split()[-1]
TypedefDict = GetTypedefDict(FullFileName)
Type = GetRealType(Type, TypedefDict, TargetType)
return Type
FileID = GetTableID(FullFileName)
SqlStatement = """ select Modifier, ID
from Function
where BelongsToFile = %d and Name = \'%s\'
""" % (FileID, PredVar)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
Type = GetDataTypeFromModifier(Result[0]).split()[-1]
TypedefDict = GetTypedefDict(FullFileName)
Type = GetRealType(Type, TypedefDict, TargetType)
return Type
for F in IncludeFileList:
FileID = GetTableID(F)
if FileID < 0:
continue
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Modifier, ID
from Function
where BelongsToFile = %d and Name = \'%s\'
""" % (FileID, PredVar)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
Type = GetDataTypeFromModifier(Result[0]).split()[-1]
TypedefDict = GetTypedefDict(FullFileName)
Type = GetRealType(Type, TypedefDict, TargetType)
return Type
return None
# really variable, search local variable first
SqlStatement = """ select Modifier, ID
from %s
where Model = %d and Name = \'%s\' and StartLine >= %d and StartLine <= %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE, PredVar, FuncRecord[0], FuncRecord[1])
ResultSet = Db.TblFile.Exec(SqlStatement)
VarFound = False
for Result in ResultSet:
if len(PredVarList) > 1:
Type = GetTypeInfo(PredVarList[1:], Result[0], FullFileName, TargetType)
return Type
else:
# Type = GetDataTypeFromModifier(Result[0]).split()[-1]
TypeList = GetDataTypeFromModifier(Result[0]).split()
Type = TypeList[-1]
if len(TypeList) > 1 and StarList is not None:
for Star in StarList:
Type = Type.strip()
Type = Type.rstrip(Star)
# Get real type after de-reference pointers.
if len(Type.strip()) == 0:
Type = TypeList[-2]
TypedefDict = GetTypedefDict(FullFileName)
Type = GetRealType(Type, TypedefDict, TargetType)
return Type
# search function parameters second
ParamList = GetParamList(FuncRecord[2])
for Param in ParamList:
if Param.Name.strip() == PredVar:
if len(PredVarList) > 1:
Type = GetTypeInfo(PredVarList[1:], Param.Modifier, FullFileName, TargetType)
return Type
else:
TypeList = GetDataTypeFromModifier(Param.Modifier).split()
Type = TypeList[-1]
if Type == '*' and len(TypeList) >= 2:
Type = TypeList[-2]
if len(TypeList) > 1 and StarList is not None:
for Star in StarList:
Type = Type.strip()
Type = Type.rstrip(Star)
# Get real type after de-reference pointers.
if len(Type.strip()) == 0:
Type = TypeList[-2]
TypedefDict = GetTypedefDict(FullFileName)
Type = GetRealType(Type, TypedefDict, TargetType)
return Type
# search global variable next
SqlStatement = """ select Modifier, ID
from %s
where Model = %d and Name = \'%s\' and BelongsToFunction = -1
""" % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE, PredVar)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
if len(PredVarList) > 1:
Type = GetTypeInfo(PredVarList[1:], Result[0], FullFileName, TargetType)
return Type
else:
TypeList = GetDataTypeFromModifier(Result[0]).split()
Type = TypeList[-1]
if len(TypeList) > 1 and StarList is not None:
for Star in StarList:
Type = Type.strip()
Type = Type.rstrip(Star)
# Get real type after de-reference pointers.
if len(Type.strip()) == 0:
Type = TypeList[-2]
TypedefDict = GetTypedefDict(FullFileName)
Type = GetRealType(Type, TypedefDict, TargetType)
return Type
IncludeFileList = GetAllIncludeFiles(FullFileName)
for F in IncludeFileList:
FileID = GetTableID(F)
if FileID < 0:
continue
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Modifier, ID
from %s
where Model = %d and BelongsToFunction = -1 and Name = \'%s\'
""" % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE, PredVar)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
if len(PredVarList) > 1:
Type = GetTypeInfo(PredVarList[1:], Result[0], FullFileName, TargetType)
return Type
else:
TypeList = GetDataTypeFromModifier(Result[0]).split()
Type = TypeList[-1]
if len(TypeList) > 1 and StarList is not None:
for Star in StarList:
Type = Type.strip()
Type = Type.rstrip(Star)
# Get real type after de-reference pointers.
if len(Type.strip()) == 0:
Type = TypeList[-2]
TypedefDict = GetTypedefDict(FullFileName)
Type = GetRealType(Type, TypedefDict, TargetType)
return Type
def GetTypeFromArray(Type, Var):
Count = Var.count('[')
while Count > 0:
Type = Type.strip()
Type = Type.rstrip('*')
Count = Count - 1
return Type
def CheckFuncLayoutReturnType(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Modifier, ID, StartLine, StartColumn, EndLine, Value
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
ReturnType = GetDataTypeFromModifier(Result[0])
TypeStart = ReturnType.split()[0]
FuncName = Result[5]
if EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, FuncName):
continue
Result0 = Result[0]
if Result0.upper().startswith('STATIC'):
Result0 = Result0[6:].strip()
Index = Result0.find(TypeStart)
if Index != 0 or Result[3] != 0:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, '[%s] Return Type should appear at the start of line' % FuncName, FileTable, Result[1])
if Result[2] == Result[4]:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, '[%s] Return Type should appear on its own line' % FuncName, FileTable, Result[1])
SqlStatement = """ select Modifier, ID, StartLine, StartColumn, FunNameStartLine, Name
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
ReturnType = GetDataTypeFromModifier(Result[0])
TypeStart = ReturnType.split()[0]
FuncName = Result[5]
if EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, FuncName):
continue
Result0 = Result[0]
if Result0.upper().startswith('STATIC'):
Result0 = Result0[6:].strip()
Index = Result0.find(TypeStart)
if Index != 0 or Result[3] != 0:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, '[%s] Return Type should appear at the start of line' % FuncName, 'Function', Result[1])
def CheckFuncLayoutModifier(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Modifier, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
ReturnType = GetDataTypeFromModifier(Result[0])
TypeStart = ReturnType.split()[0]
Result0 = Result[0]
if Result0.upper().startswith('STATIC'):
Result0 = Result0[6:].strip()
Index = Result0.find(TypeStart)
if Index != 0:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_OPTIONAL_FUNCTIONAL_MODIFIER, '', FileTable, Result[1])
SqlStatement = """ select Modifier, ID
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
ReturnType = GetDataTypeFromModifier(Result[0])
TypeStart = ReturnType.split()[0]
Result0 = Result[0]
if Result0.upper().startswith('STATIC'):
Result0 = Result0[6:].strip()
Index = Result0.find(TypeStart)
if Index != 0:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_OPTIONAL_FUNCTIONAL_MODIFIER, '', 'Function', Result[1])
def CheckFuncLayoutName(FullFileName):
ErrorMsgList = []
# Parameter variable format pattern.
Pattern = re.compile(r'^[A-Z]+\S*[a-z]\S*$')
ParamIgnoreList = ('VOID', '...')
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Name, ID, EndColumn, Value
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
FuncName = Result[3]
if EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, FuncName):
continue
if Result[2] != 0:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Function name [%s] should appear at the start of a line' % FuncName, FileTable, Result[1])
ParamList = GetParamList(Result[0])
if len(ParamList) == 0:
continue
StartLine = 0
for Param in ParamList:
if Param.StartLine <= StartLine:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Parameter %s should be in its own line.' % Param.Name, FileTable, Result[1])
if Param.StartLine - StartLine > 1:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Empty line appears before Parameter %s.' % Param.Name, FileTable, Result[1])
if not Pattern.match(Param.Name) and not Param.Name in ParamIgnoreList and not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Param.Name):
PrintErrorMsg(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, 'Parameter [%s] NOT follow naming convention.' % Param.Name, FileTable, Result[1])
StartLine = Param.StartLine
if not Result[0].endswith('\n )') and not Result[0].endswith('\r )'):
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, '\')\' should be on a new line and indented two spaces', FileTable, Result[1])
SqlStatement = """ select Modifier, ID, FunNameStartColumn, Name
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
FuncName = Result[3]
if EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, FuncName):
continue
if Result[2] != 0:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Function name [%s] should appear at the start of a line' % FuncName, 'Function', Result[1])
ParamList = GetParamList(Result[0])
if len(ParamList) == 0:
continue
StartLine = 0
for Param in ParamList:
if Param.StartLine <= StartLine:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Parameter %s should be in its own line.' % Param.Name, 'Function', Result[1])
if Param.StartLine - StartLine > 1:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Empty line appears before Parameter %s.' % Param.Name, 'Function', Result[1])
if not Pattern.match(Param.Name) and not Param.Name in ParamIgnoreList and not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Param.Name):
PrintErrorMsg(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, 'Parameter [%s] NOT follow naming convention.' % Param.Name, FileTable, Result[1])
StartLine = Param.StartLine
if not Result[0].endswith('\n )') and not Result[0].endswith('\r )'):
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, '\')\' should be on a new line and indented two spaces', 'Function', Result[1])
def CheckFuncLayoutPrototype(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
FileTable = 'Identifier' + str(FileID)
Db = GetDB()
SqlStatement = """ select Modifier, Header, Name, ID
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
if len(ResultSet) == 0:
return ErrorMsgList
FuncDefList = []
for Result in ResultSet:
FuncDefList.append(Result)
SqlStatement = """ select Modifier, Name, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
ResultSet = Db.TblFile.Exec(SqlStatement)
FuncDeclList = []
for Result in ResultSet:
FuncDeclList.append(Result)
UndeclFuncList = []
for FuncDef in FuncDefList:
FuncName = FuncDef[2].strip()
FuncModifier = FuncDef[0]
FuncDefHeader = FuncDef[1]
for FuncDecl in FuncDeclList:
LBPos = FuncDecl[1].find('(')
DeclName = FuncDecl[1][0:LBPos].strip()
DeclModifier = FuncDecl[0]
if DeclName == FuncName:
if DiffModifier(FuncModifier, DeclModifier) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE, FuncName):
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE, 'Function [%s] modifier different with prototype.' % FuncName, 'Function', FuncDef[3])
ParamListOfDef = GetParamList(FuncDefHeader)
ParamListOfDecl = GetParamList(FuncDecl[1])
if len(ParamListOfDef) != len(ParamListOfDecl) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_2, FuncName):
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_2, 'Parameter number different in function [%s].' % FuncName, 'Function', FuncDef[3])
break
Index = 0
while Index < len(ParamListOfDef):
if DiffModifier(ParamListOfDef[Index].Modifier, ParamListOfDecl[Index].Modifier) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_3, FuncName):
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_3, 'Parameter %s has different modifier with prototype in function [%s].' % (ParamListOfDef[Index].Name, FuncName), 'Function', FuncDef[3])
Index += 1
break
else:
UndeclFuncList.append(FuncDef)
IncludeFileList = GetAllIncludeFiles(FullFileName)
FuncDeclList = []
for F in IncludeFileList:
FileID = GetTableID(F, ErrorMsgList)
if FileID < 0:
continue
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Modifier, Name, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
FuncDeclList.append(Result)
for FuncDef in UndeclFuncList:
FuncName = FuncDef[2].strip()
FuncModifier = FuncDef[0]
FuncDefHeader = FuncDef[1]
for FuncDecl in FuncDeclList:
LBPos = FuncDecl[1].find('(')
DeclName = FuncDecl[1][0:LBPos].strip()
DeclModifier = FuncDecl[0]
if DeclName == FuncName:
if DiffModifier(FuncModifier, DeclModifier) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE, FuncName):
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE, 'Function [%s] modifier different with prototype.' % FuncName, 'Function', FuncDef[3])
ParamListOfDef = GetParamList(FuncDefHeader)
ParamListOfDecl = GetParamList(FuncDecl[1])
if len(ParamListOfDef) != len(ParamListOfDecl) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_2, FuncName):
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_2, 'Parameter number different in function [%s].' % FuncName, 'Function', FuncDef[3])
break
Index = 0
while Index < len(ParamListOfDef):
if DiffModifier(ParamListOfDef[Index].Modifier, ParamListOfDecl[Index].Modifier) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_3, FuncName):
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_3, 'Parameter %s has different modifier with prototype in function [%s].' % (ParamListOfDef[Index].Name, FuncName), 'Function', FuncDef[3])
Index += 1
break
def CheckFuncLayoutBody(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
FileTable = 'Identifier' + str(FileID)
Db = GetDB()
SqlStatement = """ select BodyStartColumn, EndColumn, ID, Name
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
if len(ResultSet) == 0:
return ErrorMsgList
for Result in ResultSet:
if Result[0] != 0:
if not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_BODY, Result[3]):
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_BODY,
'The open brace should be at the very beginning of a line for the function [%s].' % Result[3],
'Function', Result[2])
if Result[1] != 0:
if not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_BODY, Result[3]):
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_BODY,
'The close brace should be at the very beginning of a line for the function [%s].' % Result[3],
'Function', Result[2])
def CheckFuncLayoutLocalVariable(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select ID
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
if len(ResultSet) == 0:
return ErrorMsgList
FL = []
for Result in ResultSet:
FL.append(Result)
for F in FL:
SqlStatement = """ select Name, Value, ID, Modifier
from %s
where Model = %d and BelongsToFunction = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE, F[0])
ResultSet = Db.TblFile.Exec(SqlStatement)
if len(ResultSet) == 0:
continue
for Result in ResultSet:
if len(Result[1]) > 0 and 'CONST' not in Result[3]:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_NO_INIT_OF_VARIABLE, 'Variable Name: %s' % Result[0], FileTable, Result[2])
def CheckMemberVariableFormat(Name, Value, FileTable, TdId, ModelId):
ErrMsgList = []
# Member variable format pattern.
Pattern = re.compile(r'^[A-Z]+\S*[a-z]\S*$')
LBPos = Value.find('{')
RBPos = Value.rfind('}')
if LBPos == -1 or RBPos == -1:
return ErrMsgList
Fields = Value[LBPos + 1 : RBPos]
Fields = StripComments(Fields).strip()
NestPos = Fields.find ('struct')
if NestPos != -1 and (NestPos + len('struct') < len(Fields)) and ModelId != DataClass.MODEL_IDENTIFIER_UNION:
if not Fields[NestPos + len('struct') + 1].isalnum():
if not EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, Name):
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, 'Nested struct in [%s].' % (Name), FileTable, TdId)
return ErrMsgList
NestPos = Fields.find ('union')
if NestPos != -1 and (NestPos + len('union') < len(Fields)):
if not Fields[NestPos + len('union') + 1].isalnum():
if not EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, Name):
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, 'Nested union in [%s].' % (Name), FileTable, TdId)
return ErrMsgList
NestPos = Fields.find ('enum')
if NestPos != -1 and (NestPos + len('enum') < len(Fields)):
if not Fields[NestPos + len('enum') + 1].isalnum():
if not EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, Name):
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, 'Nested enum in [%s].' % (Name), FileTable, TdId)
return ErrMsgList
if ModelId == DataClass.MODEL_IDENTIFIER_ENUMERATE:
FieldsList = Fields.split(',')
# deal with enum is pre-assigned a value by function call ( , , , ...)
QuoteCount = 0
Index = 0
RemoveCurrentElement = False
while Index < len(FieldsList):
Field = FieldsList[Index]
if Field.find('(') != -1:
QuoteCount += 1
RemoveCurrentElement = True
Index += 1
continue
if Field.find(')') != -1 and QuoteCount > 0:
QuoteCount -= 1
if RemoveCurrentElement:
FieldsList.remove(Field)
if QuoteCount == 0:
RemoveCurrentElement = False
continue
if QuoteCount == 0:
RemoveCurrentElement = False
Index += 1
else:
FieldsList = Fields.split(';')
for Field in FieldsList:
Field = Field.strip()
if Field == '':
continue
# For the condition that the field in struct is an array with [] suffixes...
if Field[-1] == ']':
LBPos = Field.find('[')
Field = Field[0:LBPos]
# For the condition that bit field ": Number"
if Field.find(':') != -1:
ColonPos = Field.find(':')
Field = Field[0:ColonPos]
Field = Field.strip()
if Field == '':
continue
if Field.startswith("#"):
continue
# Enum could directly assign value to variable
Field = Field.split('=')[0].strip()
TokenList = Field.split()
# Remove pointers before variable
Token = TokenList[-1]
if Token in ['OPTIONAL']:
Token = TokenList[-2]
if not Pattern.match(Token.lstrip('*')):
ErrMsgList.append(Token.lstrip('*'))
return ErrMsgList
def CheckDeclTypedefFormat(FullFileName, ModelId):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Name, StartLine, EndLine, ID, Value
from %s
where Model = %d
""" % (FileTable, ModelId)
ResultSet = Db.TblFile.Exec(SqlStatement)
ResultList = []
for Result in ResultSet:
ResultList.append(Result)
ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_ALL
if ModelId == DataClass.MODEL_IDENTIFIER_STRUCTURE:
ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_STRUCTURE_DECLARATION
elif ModelId == DataClass.MODEL_IDENTIFIER_ENUMERATE:
ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_ENUMERATED_TYPE
elif ModelId == DataClass.MODEL_IDENTIFIER_UNION:
ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_UNION_TYPE
SqlStatement = """ select Modifier, Name, Value, StartLine, EndLine, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_TYPEDEF)
TdSet = Db.TblFile.Exec(SqlStatement)
TdList = []
for Td in TdSet:
TdList.append(Td)
# Check member variable name format that from typedefs of ONLY this file.
for Td in TdList:
Name = Td[1].strip()
Value = Td[2].strip()
if Value.startswith('enum'):
ValueModelId = DataClass.MODEL_IDENTIFIER_ENUMERATE
elif Value.startswith('struct'):
ValueModelId = DataClass.MODEL_IDENTIFIER_STRUCTURE
elif Value.startswith('union'):
ValueModelId = DataClass.MODEL_IDENTIFIER_UNION
else:
continue
if ValueModelId != ModelId:
continue
# Check member variable format.
ErrMsgList = CheckMemberVariableFormat(Name, Value, FileTable, Td[5], ModelId)
for ErrMsg in ErrMsgList:
if EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Name + '.' + ErrMsg):
continue
PrintErrorMsg(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, 'Member variable [%s] NOT follow naming convention.' % (Name + '.' + ErrMsg), FileTable, Td[5])
# First check in current file to see whether struct/union/enum is typedef-ed.
UntypedefedList = []
for Result in ResultList:
# Check member variable format.
Name = Result[0].strip()
Value = Result[4].strip()
if Value.startswith('enum'):
ValueModelId = DataClass.MODEL_IDENTIFIER_ENUMERATE
elif Value.startswith('struct'):
ValueModelId = DataClass.MODEL_IDENTIFIER_STRUCTURE
elif Value.startswith('union'):
ValueModelId = DataClass.MODEL_IDENTIFIER_UNION
else:
continue
if ValueModelId != ModelId:
continue
ErrMsgList = CheckMemberVariableFormat(Name, Value, FileTable, Result[3], ModelId)
for ErrMsg in ErrMsgList:
if EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Result[0] + '.' + ErrMsg):
continue
PrintErrorMsg(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, 'Member variable [%s] NOT follow naming convention.' % (Result[0] + '.' + ErrMsg), FileTable, Result[3])
# Check whether it is typedefed.
Found = False
for Td in TdList:
# skip function pointer
if len(Td[0]) > 0:
continue
if Result[1] >= Td[3] and Td[4] >= Result[2]:
Found = True
if not Td[1].isupper():
PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5])
if Result[0] in Td[2].split():
Found = True
if not Td[1].isupper():
PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5])
if Found:
break
if not Found:
UntypedefedList.append(Result)
continue
if len(UntypedefedList) == 0:
return
IncludeFileList = GetAllIncludeFiles(FullFileName)
TdList = []
for F in IncludeFileList:
FileID = GetTableID(F, ErrorMsgList)
if FileID < 0:
continue
IncludeFileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Modifier, Name, Value, StartLine, EndLine, ID
from %s
where Model = %d
""" % (IncludeFileTable, DataClass.MODEL_IDENTIFIER_TYPEDEF)
ResultSet = Db.TblFile.Exec(SqlStatement)
TdList.extend(ResultSet)
for Result in UntypedefedList:
# Check whether it is typedefed.
Found = False
for Td in TdList:
if len(Td[0]) > 0:
continue
if Result[1] >= Td[3] and Td[4] >= Result[2]:
Found = True
if not Td[1].isupper():
PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5])
if Result[0] in Td[2].split():
Found = True
if not Td[1].isupper():
PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5])
if Found:
break
if not Found:
PrintErrorMsg(ErrorType, 'No Typedef for %s' % Result[0], FileTable, Result[3])
continue
def CheckDeclStructTypedef(FullFileName):
CheckDeclTypedefFormat(FullFileName, DataClass.MODEL_IDENTIFIER_STRUCTURE)
def CheckDeclEnumTypedef(FullFileName):
CheckDeclTypedefFormat(FullFileName, DataClass.MODEL_IDENTIFIER_ENUMERATE)
def CheckDeclUnionTypedef(FullFileName):
CheckDeclTypedefFormat(FullFileName, DataClass.MODEL_IDENTIFIER_UNION)
def CheckDeclArgModifier(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Modifier, Name, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE)
ResultSet = Db.TblFile.Exec(SqlStatement)
ModifierTuple = ('IN', 'OUT', 'OPTIONAL', 'UNALIGNED')
MAX_MODIFIER_LENGTH = 100
for Result in ResultSet:
for Modifier in ModifierTuple:
if PatternInModifier(Result[0], Modifier) and len(Result[0]) < MAX_MODIFIER_LENGTH:
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_IN_OUT_MODIFIER, 'Variable Modifier %s' % Result[0], FileTable, Result[2])
break
SqlStatement = """ select Modifier, Name, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
for Modifier in ModifierTuple:
if PatternInModifier(Result[0], Modifier):
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_IN_OUT_MODIFIER, 'Return Type Modifier %s' % Result[0], FileTable, Result[2])
break
SqlStatement = """ select Modifier, Header, ID
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
for Modifier in ModifierTuple:
if PatternInModifier(Result[0], Modifier):
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_IN_OUT_MODIFIER, 'Return Type Modifier %s' % Result[0], FileTable, Result[2])
break
def CheckDeclNoUseCType(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Modifier, Name, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE)
ResultSet = Db.TblFile.Exec(SqlStatement)
CTypeTuple = ('int', 'unsigned', 'char', 'void', 'static', 'long')
for Result in ResultSet:
for Type in CTypeTuple:
if PatternInModifier(Result[0], Type):
if EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE,
Result[0] + ' ' + Result[1]):
continue
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE,
'Invalid variable type (%s) in definition [%s]' % (Type, Result[0] + ' ' + Result[1]),
FileTable,
Result[2])
break
SqlStatement = """ select Modifier, Name, ID, Value
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
ParamList = GetParamList(Result[1])
FuncName = Result[3]
if EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, FuncName):
continue
for Type in CTypeTuple:
if PatternInModifier(Result[0], Type):
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, '%s Return type %s' % (FuncName, Result[0]), FileTable, Result[2])
for Param in ParamList:
if PatternInModifier(Param.Modifier, Type):
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, 'Parameter %s' % Param.Name, FileTable, Result[2])
SqlStatement = """ select Modifier, Header, ID, Name
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
ParamList = GetParamList(Result[1])
FuncName = Result[3]
if EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, FuncName):
continue
for Type in CTypeTuple:
if PatternInModifier(Result[0], Type):
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, '[%s] Return type %s' % (FuncName, Result[0]), FileTable, Result[2])
for Param in ParamList:
if PatternInModifier(Param.Modifier, Type):
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, 'Parameter %s' % Param.Name, FileTable, Result[2])
def CheckPointerNullComparison(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
# cache the found function return type to accelerate later checking in this file.
FuncReturnTypeDict = {}
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Value, StartLine, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_PREDICATE_EXPRESSION)
ResultSet = Db.TblFile.Exec(SqlStatement)
if len(ResultSet) == 0:
return
PSL = []
for Result in ResultSet:
PSL.append([Result[0], Result[1], Result[2]])
SqlStatement = """ select BodyStartLine, EndLine, Header, Modifier, ID
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
FL = []
for Result in ResultSet:
FL.append([Result[0], Result[1], Result[2], Result[3], Result[4]])
p = GetFuncDeclPattern()
for Str in PSL:
FuncRecord = GetFuncContainsPE(Str[1], FL)
if FuncRecord is None:
continue
for Exp in GetPredicateListFromPredicateExpStr(Str[0]):
PredInfo = SplitPredicateStr(Exp)
if PredInfo[1] is None:
PredVarStr = PredInfo[0][0].strip()
IsFuncCall = False
SearchInCache = False
# PredVarStr may contain '.' or '->'
TmpStr = PredVarStr.replace('.', '').replace('->', '')
if p.match(TmpStr):
PredVarStr = PredVarStr[0:PredVarStr.find('(')]
SearchInCache = True
# Only direct function call using IsFuncCall branch. Multi-level ref. function call is considered a variable.
if TmpStr.startswith(PredVarStr):
IsFuncCall = True
if PredVarStr.strip() in IgnoredKeywordList:
continue
StarList = []
PredVarList = GetCNameList(PredVarStr, StarList)
# No variable found, maybe value first? like (0 == VarName)
if len(PredVarList) == 0:
continue
if SearchInCache:
Type = FuncReturnTypeDict.get(PredVarStr)
if Type is not None:
if Type.find('*') != -1 and Type != 'BOOLEAN*':
PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_COMPARISON_NULL_TYPE, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
continue
if PredVarStr in FuncReturnTypeDict:
continue
Type = GetVarInfo(PredVarList, FuncRecord, FullFileName, IsFuncCall, None, StarList)
if SearchInCache:
FuncReturnTypeDict[PredVarStr] = Type
if Type is None:
continue
Type = GetTypeFromArray(Type, PredVarStr)
if Type.find('*') != -1 and Type != 'BOOLEAN*':
PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_COMPARISON_NULL_TYPE, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
def CheckNonBooleanValueComparison(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
# cache the found function return type to accelerate later checking in this file.
FuncReturnTypeDict = {}
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Value, StartLine, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_PREDICATE_EXPRESSION)
ResultSet = Db.TblFile.Exec(SqlStatement)
if len(ResultSet) == 0:
return
PSL = []
for Result in ResultSet:
PSL.append([Result[0], Result[1], Result[2]])
SqlStatement = """ select BodyStartLine, EndLine, Header, Modifier, ID
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
FL = []
for Result in ResultSet:
FL.append([Result[0], Result[1], Result[2], Result[3], Result[4]])
p = GetFuncDeclPattern()
for Str in PSL:
FuncRecord = GetFuncContainsPE(Str[1], FL)
if FuncRecord is None:
continue
for Exp in GetPredicateListFromPredicateExpStr(Str[0]):
PredInfo = SplitPredicateStr(Exp)
if PredInfo[1] is None:
PredVarStr = PredInfo[0][0].strip()
IsFuncCall = False
SearchInCache = False
# PredVarStr may contain '.' or '->'
TmpStr = PredVarStr.replace('.', '').replace('->', '')
if p.match(TmpStr):
PredVarStr = PredVarStr[0:PredVarStr.find('(')]
SearchInCache = True
# Only direct function call using IsFuncCall branch. Multi-level ref. function call is considered a variable.
if TmpStr.startswith(PredVarStr):
IsFuncCall = True
if PredVarStr.strip() in IgnoredKeywordList:
continue
StarList = []
PredVarList = GetCNameList(PredVarStr, StarList)
# No variable found, maybe value first? like (0 == VarName)
if len(PredVarList) == 0:
continue
if SearchInCache:
Type = FuncReturnTypeDict.get(PredVarStr)
if Type is not None:
if Type.find('BOOLEAN') == -1:
PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_NO_BOOLEAN_OPERATOR, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
continue
if PredVarStr in FuncReturnTypeDict:
continue
Type = GetVarInfo(PredVarList, FuncRecord, FullFileName, IsFuncCall, 'BOOLEAN', StarList)
if SearchInCache:
FuncReturnTypeDict[PredVarStr] = Type
if Type is None:
continue
if Type.find('BOOLEAN') == -1:
PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_NO_BOOLEAN_OPERATOR, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
def CheckBooleanValueComparison(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
# cache the found function return type to accelerate later checking in this file.
FuncReturnTypeDict = {}
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Value, StartLine, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_PREDICATE_EXPRESSION)
ResultSet = Db.TblFile.Exec(SqlStatement)
if len(ResultSet) == 0:
return
PSL = []
for Result in ResultSet:
PSL.append([Result[0], Result[1], Result[2]])
SqlStatement = """ select BodyStartLine, EndLine, Header, Modifier, ID
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
FL = []
for Result in ResultSet:
FL.append([Result[0], Result[1], Result[2], Result[3], Result[4]])
p = GetFuncDeclPattern()
for Str in PSL:
FuncRecord = GetFuncContainsPE(Str[1], FL)
if FuncRecord is None:
continue
for Exp in GetPredicateListFromPredicateExpStr(Str[0]):
PredInfo = SplitPredicateStr(Exp)
if PredInfo[1] in ('==', '!=') and PredInfo[0][1] in ('TRUE', 'FALSE'):
PredVarStr = PredInfo[0][0].strip()
IsFuncCall = False
SearchInCache = False
# PredVarStr may contain '.' or '->'
TmpStr = PredVarStr.replace('.', '').replace('->', '')
if p.match(TmpStr):
PredVarStr = PredVarStr[0:PredVarStr.find('(')]
SearchInCache = True
# Only direct function call using IsFuncCall branch. Multi-level ref. function call is considered a variable.
if TmpStr.startswith(PredVarStr):
IsFuncCall = True
if PredVarStr.strip() in IgnoredKeywordList:
continue
StarList = []
PredVarList = GetCNameList(PredVarStr, StarList)
# No variable found, maybe value first? like (0 == VarName)
if len(PredVarList) == 0:
continue
if SearchInCache:
Type = FuncReturnTypeDict.get(PredVarStr)
if Type is not None:
if Type.find('BOOLEAN') != -1:
PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_BOOLEAN_VALUE, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
continue
if PredVarStr in FuncReturnTypeDict:
continue
Type = GetVarInfo(PredVarList, FuncRecord, FullFileName, IsFuncCall, 'BOOLEAN', StarList)
if SearchInCache:
FuncReturnTypeDict[PredVarStr] = Type
if Type is None:
continue
if Type.find('BOOLEAN') != -1:
PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_BOOLEAN_VALUE, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
def CheckHeaderFileData(FullFileName, AllTypedefFun=[]):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select ID, Modifier
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
if not Result[1].startswith('extern'):
for Item in AllTypedefFun:
if '(%s)' % Result[1] in Item:
break
else:
PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_DATA, 'Variable definition appears in header file', FileTable, Result[0])
SqlStatement = """ select ID
from Function
where BelongsToFile = %d
""" % FileID
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_DATA, 'Function definition appears in header file', 'Function', Result[0])
return ErrorMsgList
def CheckHeaderFileIfndef(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Value, StartLine
from %s
where Model = %d order by StartLine
""" % (FileTable, DataClass.MODEL_IDENTIFIER_MACRO_IFNDEF)
ResultSet = Db.TblFile.Exec(SqlStatement)
if len(ResultSet) == 0:
PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_IFNDEF_STATEMENT_1, '', 'File', FileID)
return ErrorMsgList
for Result in ResultSet:
SqlStatement = """ select Value, EndLine
from %s
where EndLine < %d
""" % (FileTable, Result[1])
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
if not Result[0].startswith('/*') and not Result[0].startswith('//'):
PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_IFNDEF_STATEMENT_2, '', 'File', FileID)
break
SqlStatement = """ select Value
from %s
where StartLine > (select max(EndLine) from %s where Model = %d)
""" % (FileTable, FileTable, DataClass.MODEL_IDENTIFIER_MACRO_ENDIF)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
if not Result[0].startswith('/*') and not Result[0].startswith('//'):
PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_IFNDEF_STATEMENT_3, '', 'File', FileID)
return ErrorMsgList
def CheckDoxygenCommand(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Value, ID
from %s
where Model = %d or Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT, DataClass.MODEL_IDENTIFIER_FUNCTION_HEADER)
ResultSet = Db.TblFile.Exec(SqlStatement)
DoxygenCommandList = ['bug', 'todo', 'example', 'file', 'attention', 'param', 'post', 'pre', 'retval',
'return', 'sa', 'since', 'test', 'note', 'par', 'endcode', 'code']
for Result in ResultSet:
CommentStr = Result[0]
CommentPartList = CommentStr.split()
for Part in CommentPartList:
if Part.upper() == 'BUGBUG':
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Bug should be marked with doxygen tag @bug', FileTable, Result[1])
if Part.upper() == 'TODO':
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'ToDo should be marked with doxygen tag @todo', FileTable, Result[1])
if Part.startswith('@'):
if EccGlobalData.gException.IsException(ERROR_DOXYGEN_CHECK_COMMAND, Part):
continue
if not Part.replace('@', '').strip():
continue
if Part.lstrip('@') in ['{', '}']:
continue
if Part.lstrip('@').isalpha():
if Part.lstrip('@') not in DoxygenCommandList:
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Unknown doxygen command %s' % Part, FileTable, Result[1])
else:
Index = Part.find('[')
if Index == -1:
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Unknown doxygen command %s' % Part, FileTable, Result[1])
RealCmd = Part[1:Index]
if RealCmd not in DoxygenCommandList:
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Unknown doxygen command %s' % Part, FileTable, Result[1])
def CheckDoxygenTripleForwardSlash(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
SqlStatement = """ select ID, BodyStartLine, BodyStartColumn, EndLine, EndColumn
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
if len(ResultSet) == 0:
return
FuncDefSet = []
for Result in ResultSet:
FuncDefSet.append(Result)
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Value, ID, StartLine, StartColumn, EndLine, EndColumn
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT)
ResultSet = Db.TblFile.Exec(SqlStatement)
CommentSet = []
try:
for Result in ResultSet:
CommentSet.append(Result)
except:
print('Unrecognized chars in comment of file %s', FullFileName)
for Result in CommentSet:
CommentStr = Result[0]
StartLine = Result[2]
StartColumn = Result[3]
EndLine = Result[4]
EndColumn = Result[5]
if not CommentStr.startswith('///<'):
continue
Found = False
for FuncDef in FuncDefSet:
if StartLine == FuncDef[1] and StartColumn > FuncDef[2] and EndLine == FuncDef[3] and EndColumn < FuncDef[4]:
Found = True
break
if StartLine > FuncDef[1] and EndLine < FuncDef[3]:
Found = True
break
if StartLine == FuncDef[1] and StartColumn > FuncDef[2] and EndLine < FuncDef[3]:
Found = True
break
if StartLine > FuncDef[1] and EndLine == FuncDef[3] and EndColumn < FuncDef[4]:
Found = True
break
if Found:
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMENT_FORMAT, '', FileTable, Result[1])
def CheckFileHeaderDoxygenComments(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Value, ID
from %s
where Model = %d and (StartLine = 1 or StartLine = 7 or StartLine = 8) and StartColumn = 0
""" % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT)
ResultSet = Db.TblFile.Exec(SqlStatement)
if len(ResultSet) == 0:
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'No File License header appear at the very beginning of file.', 'File', FileID)
return ErrorMsgList
NoHeaderCommentStartFlag = True
NoHeaderCommentEndFlag = True
NoHeaderCommentPeriodFlag = True
NoCopyrightFlag = True
NoLicenseFlag = True
NoRevReferFlag = True
NextLineIndex = 0
for Result in ResultSet:
FileStartFlag = False
CommentStrList = []
CommentStr = Result[0].strip()
CommentStrListTemp = CommentStr.split('\n')
if (len(CommentStrListTemp) <= 1):
# For Mac
CommentStrListTemp = CommentStr.split('\r')
# Skip the content before the file header
for CommentLine in CommentStrListTemp:
if CommentLine.strip().startswith('/** @file'):
FileStartFlag = True
if FileStartFlag == True:
CommentStrList.append(CommentLine)
ID = Result[1]
Index = 0
if CommentStrList and CommentStrList[0].strip().startswith('/** @file'):
NoHeaderCommentStartFlag = False
else:
continue
if CommentStrList and CommentStrList[-1].strip().endswith('**/'):
NoHeaderCommentEndFlag = False
else:
continue
for CommentLine in CommentStrList:
Index = Index + 1
NextLineIndex = Index
if CommentLine.startswith('/** @file'):
continue
if CommentLine.startswith('**/'):
break
# Check whether C File header Comment content start with two spaces.
if EccGlobalData.gConfig.HeaderCheckCFileCommentStartSpacesNum == '1' or EccGlobalData.gConfig.HeaderCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
if CommentLine.startswith('/** @file') == False and CommentLine.startswith('**/') == False and CommentLine.strip() and CommentLine.startswith(' ') == False:
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment content should start with two spaces at each line', FileTable, ID)
CommentLine = CommentLine.strip()
if CommentLine.startswith('Copyright'):
NoCopyrightFlag = False
if CommentLine.find('All rights reserved') == -1:
for Copyright in EccGlobalData.gConfig.Copyright:
if CommentLine.find(Copyright) > -1:
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, '""All rights reserved"" announcement should be following the ""Copyright"" at the same line', FileTable, ID)
break
if CommentLine.endswith('<BR>') == -1:
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'The ""<BR>"" at the end of the Copyright line is required', FileTable, ID)
if NextLineIndex < len(CommentStrList) and CommentStrList[NextLineIndex].strip().startswith('Copyright') == False and CommentStrList[NextLineIndex].strip():
NoLicenseFlag = False
if CommentLine.startswith('@par Revision Reference:'):
NoRevReferFlag = False
RefListFlag = False
for RefLine in CommentStrList[NextLineIndex:]:
if RefLine.strip() and (NextLineIndex + 1) < len(CommentStrList) and CommentStrList[NextLineIndex+1].strip() and CommentStrList[NextLineIndex+1].strip().startswith('**/') == False:
RefListFlag = True
if RefLine.strip() == False or RefLine.strip().startswith('**/'):
RefListFlag = False
break
# Check whether C File header Comment's each reference at list should begin with a bullet character.
if EccGlobalData.gConfig.HeaderCheckCFileCommentReferenceFormat == '1' or EccGlobalData.gConfig.HeaderCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
if RefListFlag == True:
if RefLine.strip() and RefLine.strip().startswith('**/') == False and RefLine.startswith(' -') == False:
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'Each reference on a separate line should begin with a bullet character ""-"" ', FileTable, ID)
if NoHeaderCommentStartFlag:
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FILE_HEADER, 'File header comment should begin with ""/** @file""', FileTable, ID)
return
if NoHeaderCommentEndFlag:
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment should end with ""**/""', FileTable, ID)
return
if NoCopyrightFlag:
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment missing the ""Copyright""', FileTable, ID)
#Check whether C File header Comment have the License immediately after the ""Copyright"" line.
if EccGlobalData.gConfig.HeaderCheckCFileCommentLicenseFormat == '1' or EccGlobalData.gConfig.HeaderCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
if NoLicenseFlag:
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment should have the License immediately after the ""Copyright"" line', FileTable, ID)
def CheckFuncHeaderDoxygenComments(FullFileName):
ErrorMsgList = []
FileID = GetTableID(FullFileName, ErrorMsgList)
if FileID < 0:
return ErrorMsgList
Db = GetDB()
FileTable = 'Identifier' + str(FileID)
SqlStatement = """ select Value, StartLine, EndLine, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT)
ResultSet = Db.TblFile.Exec(SqlStatement)
CommentSet = []
try:
for Result in ResultSet:
CommentSet.append(Result)
except:
print('Unrecognized chars in comment of file %s', FullFileName)
# Func Decl check
SqlStatement = """ select Modifier, Name, StartLine, ID, Value
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
FuncName = Result[4]
FunctionHeaderComment = CheckCommentImmediatelyPrecedeFunctionHeader(Result[1], Result[2], CommentSet)
if FunctionHeaderComment:
CheckFunctionHeaderConsistentWithDoxygenComment(Result[0], Result[1], Result[2], FunctionHeaderComment[0], FunctionHeaderComment[1], ErrorMsgList, FunctionHeaderComment[3], FileTable)
else:
if EccGlobalData.gException.IsException(ERROR_HEADER_CHECK_FUNCTION, FuncName):
continue
ErrorMsgList.append('Line %d :Function %s has NO comment immediately preceding it.' % (Result[2], Result[1]))
PrintErrorMsg(ERROR_HEADER_CHECK_FUNCTION, 'Function [%s] has NO comment immediately preceding it.' % (FuncName), FileTable, Result[3])
# Func Def check
SqlStatement = """ select Value, StartLine, EndLine, ID
from %s
where Model = %d
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_HEADER)
ResultSet = Db.TblFile.Exec(SqlStatement)
CommentSet = []
try:
for Result in ResultSet:
CommentSet.append(Result)
except:
print('Unrecognized chars in comment of file %s', FullFileName)
SqlStatement = """ select Modifier, Header, StartLine, ID, Name
from Function
where BelongsToFile = %d
""" % (FileID)
ResultSet = Db.TblFile.Exec(SqlStatement)
for Result in ResultSet:
FuncName = Result[4]
FunctionHeaderComment = CheckCommentImmediatelyPrecedeFunctionHeader(Result[1], Result[2], CommentSet)
if FunctionHeaderComment:
CheckFunctionHeaderConsistentWithDoxygenComment(Result[0], Result[1], Result[2], FunctionHeaderComment[0], FunctionHeaderComment[1], ErrorMsgList, FunctionHeaderComment[3], FileTable)
else:
if EccGlobalData.gException.IsException(ERROR_HEADER_CHECK_FUNCTION, FuncName):
continue
ErrorMsgList.append('Line %d :Function [%s] has NO comment immediately preceding it.' % (Result[2], Result[1]))
PrintErrorMsg(ERROR_HEADER_CHECK_FUNCTION, 'Function [%s] has NO comment immediately preceding it.' % (FuncName), 'Function', Result[3])
return ErrorMsgList
def CheckCommentImmediatelyPrecedeFunctionHeader(FuncName, FuncStartLine, CommentSet):
for Comment in CommentSet:
if Comment[2] == FuncStartLine - 1:
return Comment
return None
def GetDoxygenStrFromComment(Str):
DoxygenStrList = []
ParamTagList = Str.split('@param')
if len(ParamTagList) > 1:
i = 1
while i < len(ParamTagList):
DoxygenStrList.append('@param' + ParamTagList[i])
i += 1
Str = ParamTagList[0]
RetvalTagList = ParamTagList[-1].split('@retval')
if len(RetvalTagList) > 1:
if len(ParamTagList) > 1:
DoxygenStrList[-1] = '@param' + RetvalTagList[0]
i = 1
while i < len(RetvalTagList):
DoxygenStrList.append('@retval' + RetvalTagList[i])
i += 1
ReturnTagList = RetvalTagList[-1].split('@return')
if len(ReturnTagList) > 1:
if len(RetvalTagList) > 1:
DoxygenStrList[-1] = '@retval' + ReturnTagList[0]
elif len(ParamTagList) > 1:
DoxygenStrList[-1] = '@param' + ReturnTagList[0]
i = 1
while i < len(ReturnTagList):
DoxygenStrList.append('@return' + ReturnTagList[i])
i += 1
if len(DoxygenStrList) > 0:
DoxygenStrList[-1] = DoxygenStrList[-1].rstrip('--*/')
return DoxygenStrList
def CheckGeneralDoxygenCommentLayout(Str, StartLine, ErrorMsgList, CommentId= -1, TableName=''):
#/** --*/ @retval after @param
if not Str.startswith('/**'):
ErrorMsgList.append('Line %d : Comment does NOT have prefix /** ' % StartLine)
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Comment does NOT have prefix /** ', TableName, CommentId)
if not Str.endswith('**/'):
ErrorMsgList.append('Line %d : Comment does NOT have tail **/ ' % StartLine)
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Comment does NOT have tail **/ ', TableName, CommentId)
FirstRetvalIndex = Str.find('@retval')
LastParamIndex = Str.rfind('@param')
if (FirstRetvalIndex > 0) and (LastParamIndex > 0) and (FirstRetvalIndex < LastParamIndex):
ErrorMsgList.append('Line %d : @retval appear before @param ' % StartLine)
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, @retval appear before @param ', TableName, CommentId)
def CheckFunctionHeaderConsistentWithDoxygenComment(FuncModifier, FuncHeader, FuncStartLine, CommentStr, CommentStartLine, ErrorMsgList, CommentId= -1, TableName=''):
ParamList = GetParamList(FuncHeader)
CheckGeneralDoxygenCommentLayout(CommentStr, CommentStartLine, ErrorMsgList, CommentId, TableName)
DescriptionStr = CommentStr
DoxygenStrList = GetDoxygenStrFromComment(DescriptionStr)
if DescriptionStr.find('.') == -1:
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMENT_DESCRIPTION, 'Comment description should end with period \'.\'', TableName, CommentId)
DoxygenTagNumber = len(DoxygenStrList)
ParamNumber = len(ParamList)
for Param in ParamList:
if Param.Name.upper() == 'VOID' and ParamNumber == 1:
ParamNumber -= 1
Index = 0
if ParamNumber > 0 and DoxygenTagNumber > 0:
while Index < ParamNumber and Index < DoxygenTagNumber:
ParamModifier = ParamList[Index].Modifier
ParamName = ParamList[Index].Name.strip()
Tag = DoxygenStrList[Index].strip(' ')
if (not Tag[-1] == ('\n')) and (not Tag[-1] == ('\r')):
ErrorMsgList.append('Line %d : in Comment, <%s> does NOT end with new line ' % (CommentStartLine, Tag.replace('\n', '').replace('\r', '')))
PrintErrorMsg(ERROR_HEADER_CHECK_FUNCTION, 'in Comment, <%s> does NOT end with new line ' % (Tag.replace('\n', '').replace('\r', '')), TableName, CommentId)
TagPartList = Tag.split()
if len(TagPartList) < 2:
ErrorMsgList.append('Line %d : in Comment, <%s> does NOT contain doxygen contents ' % (CommentStartLine, Tag.replace('\n', '').replace('\r', '')))
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT contain doxygen contents ' % (Tag.replace('\n', '').replace('\r', '')), TableName, CommentId)
Index += 1
continue
LBPos = Tag.find('[')
RBPos = Tag.find(']')
ParamToLBContent = Tag[len('@param'):LBPos].strip()
if LBPos > 0 and len(ParamToLBContent) == 0 and RBPos > LBPos:
InOutStr = ''
ModifierPartList = ParamModifier.split()
for Part in ModifierPartList:
if Part.strip() == 'IN':
InOutStr += 'in'
if Part.strip() == 'OUT':
if InOutStr != '':
InOutStr += ', out'
else:
InOutStr = 'out'
if InOutStr != '':
if Tag.find('[' + InOutStr + ']') == -1:
if InOutStr != 'in, out':
ErrorMsgList.append('Line %d : in Comment, <%s> does NOT have %s ' % (CommentStartLine, (TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']'))
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT have %s ' % ((TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']'), TableName, CommentId)
else:
if Tag.find('[in,out]') == -1:
ErrorMsgList.append('Line %d : in Comment, <%s> does NOT have %s ' % (CommentStartLine, (TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']'))
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT have %s ' % ((TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']'), TableName, CommentId)
if Tag.find(ParamName) == -1 and ParamName != 'VOID' and ParamName != 'void':
ErrorMsgList.append('Line %d : in Comment, <%s> does NOT consistent with parameter name %s ' % (CommentStartLine, (TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), ParamName))
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT consistent with parameter name %s ' % ((TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), ParamName), TableName, CommentId)
Index += 1
if Index < ParamNumber:
ErrorMsgList.append('Line %d : Number of doxygen tags in comment less than number of function parameters' % CommentStartLine)
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Number of doxygen tags in comment less than number of function parameters ', TableName, CommentId)
# VOID return type, NOT VOID*. VOID* should be matched with a doxygen tag.
if (FuncModifier.find('VOID') != -1 or FuncModifier.find('void') != -1) and FuncModifier.find('*') == -1:
# assume we allow a return description tag for void func. return. that's why 'DoxygenTagNumber - 1' is used instead of 'DoxygenTagNumber'
if Index < DoxygenTagNumber - 1 or (Index < DoxygenTagNumber and DoxygenStrList[Index].startswith('@retval')):
ErrorMsgList.append('Line %d : VOID return type need NO doxygen tags in comment' % CommentStartLine)
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'VOID return type need no doxygen tags in comment ', TableName, CommentId)
else:
if Index < DoxygenTagNumber and not DoxygenStrList[Index].startswith('@retval') and not DoxygenStrList[Index].startswith('@return'):
ErrorMsgList.append('Line %d : Number of @param doxygen tags in comment does NOT match number of function parameters' % CommentStartLine)
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Number of @param doxygen tags in comment does NOT match number of function parameters ', TableName, CommentId)
else:
if ParamNumber == 0 and DoxygenTagNumber != 0 and ((FuncModifier.find('VOID') != -1 or FuncModifier.find('void') != -1) and FuncModifier.find('*') == -1):
ErrorMsgList.append('Line %d : VOID return type need NO doxygen tags in comment' % CommentStartLine)
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'VOID return type need NO doxygen tags in comment ', TableName, CommentId)
if ParamNumber != 0 and DoxygenTagNumber == 0:
ErrorMsgList.append('Line %d : No doxygen tags in comment' % CommentStartLine)
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'No doxygen tags in comment ', TableName, CommentId)
if __name__ == '__main__':
# EdkLogger.Initialize()
# EdkLogger.SetLevel(EdkLogger.QUIET)
# CollectSourceCodeDataIntoDB(sys.argv[1])
try:
test_file = sys.argv[1]
except IndexError as v:
print("Usage: %s filename" % sys.argv[0])
sys.exit(1)
MsgList = CheckFuncHeaderDoxygenComments(test_file)
for Msg in MsgList:
print(Msg)
print('Done!')