diff options
Diffstat (limited to '')
-rwxr-xr-x | src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/c.py | 2654 |
1 files changed, 2654 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/c.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/c.py new file mode 100755 index 00000000..9c9c7dd0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/c.py @@ -0,0 +1,2654 @@ +## @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> +# Copyright (c) 2020, Arm Limited. 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 len(List) < 2: + pass + elif 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] and 'STATIC' 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', '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') or ('Copyright' in CommentLine and CommentLine.lower().startswith('(c)')): + 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!') |