## @file # This file is used to be the c coding style checking of ECC tool # # Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
# 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', '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('
') == -1: PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'The ""
"" 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!')