## @file | |
# This file is used to be the c coding style checking of ECC tool | |
# | |
# Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR> | |
# This program and the accompanying materials | |
# are licensed and made available under the terms and conditions of the BSD License | |
# which accompanies this distribution. The full text of the license may be found at | |
# http://opensource.org/licenses/bsd-license.php | |
# | |
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
# | |
import sys | |
import Common.LongFilePathOs as os | |
import re | |
import string | |
import CodeFragmentCollector | |
import FileProfile | |
from CommonDataClass import DataClass | |
import Database | |
from Common import EdkLogger | |
from EccToolError import * | |
import EccGlobalData | |
import MetaDataParser | |
IncludeFileListDict = {} | |
AllIncludeFileListDict = {} | |
IncludePathListDict = {} | |
ComplexTypeDict = {} | |
SUDict = {} | |
IgnoredKeywordList = ['EFI_ERROR'] | |
def GetIgnoredDirListPattern(): | |
skipList = list(EccGlobalData.gConfig.SkipDirList) + ['.svn'] | |
DirString = string.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 = [] | |
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) | |
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 == 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 != 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) != None: | |
return AllIncludeFileListDict.get(FullFileName) | |
FileDirName = os.path.dirname(FullFileName) | |
IncludePathList = IncludePathListDict.get(FileDirName) | |
if IncludePathList == 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 != 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 != 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 begining, 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.ModifierList: | |
continue | |
# remove array sufix | |
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 != 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 != 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] == '/' and ListFromStr[Index + 2] != '\n': | |
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 == None: | |
Value = SUDict.get(Type) | |
if Value == 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 == None: | |
Value = SUDict.get(FT) | |
break | |
if Value == 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 [] sufixes... | |
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 != None and Type == TargetType: | |
return Type | |
while TypedefDict.get(Type): | |
Type = TypedefDict.get(Type) | |
if TargetType != 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 == None: | |
return None | |
# we want to determine the exact type. | |
if TargetType != 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 != 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 != 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 != 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 != 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(ReturnType) | |
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 | |
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: | |
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_BODY, 'open brace should be at the very beginning of a line.', 'Function', Result[2]) | |
if Result[1] != 0: | |
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_BODY, 'close brace should be at the very beginning of a line.', '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 [] sufixes... | |
if Field[-1] == ']': | |
LBPos = Field.find('[') | |
Field = Field[0:LBPos] | |
# For the condition that bit field ": Number" | |
if Field.find(':') != -1: | |
ColonPos = Field.find(':') | |
Field = Field[0:ColonPos] | |
Field = Field.strip() | |
if Field == '': | |
continue | |
if Field.startswith("#"): | |
continue | |
# Enum could directly assign value to variable | |
Field = Field.split('=')[0].strip() | |
TokenList = Field.split() | |
# Remove pointers before variable | |
Token = TokenList[-1] | |
if Token in ['OPTIONAL']: | |
Token = TokenList[-2] | |
if not Pattern.match(Token.lstrip('*')): | |
ErrMsgList.append(Token.lstrip('*')) | |
return ErrMsgList | |
def CheckDeclTypedefFormat(FullFileName, ModelId): | |
ErrorMsgList = [] | |
FileID = GetTableID(FullFileName, ErrorMsgList) | |
if FileID < 0: | |
return ErrorMsgList | |
Db = GetDB() | |
FileTable = 'Identifier' + str(FileID) | |
SqlStatement = """ select Name, StartLine, EndLine, ID, Value | |
from %s | |
where Model = %d | |
""" % (FileTable, ModelId) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
ResultList = [] | |
for Result in ResultSet: | |
ResultList.append(Result) | |
ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_ALL | |
if ModelId == DataClass.MODEL_IDENTIFIER_STRUCTURE: | |
ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_STRUCTURE_DECLARATION | |
elif ModelId == DataClass.MODEL_IDENTIFIER_ENUMERATE: | |
ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_ENUMERATED_TYPE | |
elif ModelId == DataClass.MODEL_IDENTIFIER_UNION: | |
ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_UNION_TYPE | |
SqlStatement = """ select Modifier, Name, Value, StartLine, EndLine, ID | |
from %s | |
where Model = %d | |
""" % (FileTable, DataClass.MODEL_IDENTIFIER_TYPEDEF) | |
TdSet = Db.TblFile.Exec(SqlStatement) | |
TdList = [] | |
for Td in TdSet: | |
TdList.append(Td) | |
# Check member variable name format that from typedefs of ONLY this file. | |
for Td in TdList: | |
Name = Td[1].strip() | |
Value = Td[2].strip() | |
if Value.startswith('enum'): | |
ValueModelId = DataClass.MODEL_IDENTIFIER_ENUMERATE | |
elif Value.startswith('struct'): | |
ValueModelId = DataClass.MODEL_IDENTIFIER_STRUCTURE | |
elif Value.startswith('union'): | |
ValueModelId = DataClass.MODEL_IDENTIFIER_UNION | |
else: | |
continue | |
if ValueModelId != ModelId: | |
continue | |
# Check member variable format. | |
ErrMsgList = CheckMemberVariableFormat(Name, Value, FileTable, Td[5], ModelId) | |
for ErrMsg in ErrMsgList: | |
if EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Name + '.' + ErrMsg): | |
continue | |
PrintErrorMsg(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, 'Member variable [%s] NOT follow naming convention.' % (Name + '.' + ErrMsg), FileTable, Td[5]) | |
# First check in current file to see whether struct/union/enum is typedef-ed. | |
UntypedefedList = [] | |
for Result in ResultList: | |
# Check member variable format. | |
Name = Result[0].strip() | |
Value = Result[4].strip() | |
if Value.startswith('enum'): | |
ValueModelId = DataClass.MODEL_IDENTIFIER_ENUMERATE | |
elif Value.startswith('struct'): | |
ValueModelId = DataClass.MODEL_IDENTIFIER_STRUCTURE | |
elif Value.startswith('union'): | |
ValueModelId = DataClass.MODEL_IDENTIFIER_UNION | |
else: | |
continue | |
if ValueModelId != ModelId: | |
continue | |
ErrMsgList = CheckMemberVariableFormat(Name, Value, FileTable, Result[3], ModelId) | |
for ErrMsg in ErrMsgList: | |
if EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Result[0] + '.' + ErrMsg): | |
continue | |
PrintErrorMsg(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, 'Member variable [%s] NOT follow naming convention.' % (Result[0] + '.' + ErrMsg), FileTable, Result[3]) | |
# Check whether it is typedefed. | |
Found = False | |
for Td in TdList: | |
# skip function pointer | |
if len(Td[0]) > 0: | |
continue | |
if Result[1] >= Td[3] and Td[4] >= Result[2]: | |
Found = True | |
if not Td[1].isupper(): | |
PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5]) | |
if Result[0] in Td[2].split(): | |
Found = True | |
if not Td[1].isupper(): | |
PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5]) | |
if Found: | |
break | |
if not Found: | |
UntypedefedList.append(Result) | |
continue | |
if len(UntypedefedList) == 0: | |
return | |
IncludeFileList = GetAllIncludeFiles(FullFileName) | |
TdList = [] | |
for F in IncludeFileList: | |
FileID = GetTableID(F, ErrorMsgList) | |
if FileID < 0: | |
continue | |
IncludeFileTable = 'Identifier' + str(FileID) | |
SqlStatement = """ select Modifier, Name, Value, StartLine, EndLine, ID | |
from %s | |
where Model = %d | |
""" % (IncludeFileTable, DataClass.MODEL_IDENTIFIER_TYPEDEF) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
TdList.extend(ResultSet) | |
for Result in UntypedefedList: | |
# Check whether it is typedefed. | |
Found = False | |
for Td in TdList: | |
if len(Td[0]) > 0: | |
continue | |
if Result[1] >= Td[3] and Td[4] >= Result[2]: | |
Found = True | |
if not Td[1].isupper(): | |
PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5]) | |
if Result[0] in Td[2].split(): | |
Found = True | |
if not Td[1].isupper(): | |
PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5]) | |
if Found: | |
break | |
if not Found: | |
PrintErrorMsg(ErrorType, 'No Typedef for %s' % Result[0], FileTable, Result[3]) | |
continue | |
def CheckDeclStructTypedef(FullFileName): | |
CheckDeclTypedefFormat(FullFileName, DataClass.MODEL_IDENTIFIER_STRUCTURE) | |
def CheckDeclEnumTypedef(FullFileName): | |
CheckDeclTypedefFormat(FullFileName, DataClass.MODEL_IDENTIFIER_ENUMERATE) | |
def CheckDeclUnionTypedef(FullFileName): | |
CheckDeclTypedefFormat(FullFileName, DataClass.MODEL_IDENTIFIER_UNION) | |
def CheckDeclArgModifier(FullFileName): | |
ErrorMsgList = [] | |
FileID = GetTableID(FullFileName, ErrorMsgList) | |
if FileID < 0: | |
return ErrorMsgList | |
Db = GetDB() | |
FileTable = 'Identifier' + str(FileID) | |
SqlStatement = """ select Modifier, Name, ID | |
from %s | |
where Model = %d | |
""" % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
ModifierTuple = ('IN', 'OUT', 'OPTIONAL', 'UNALIGNED') | |
MAX_MODIFIER_LENGTH = 100 | |
for Result in ResultSet: | |
for Modifier in ModifierTuple: | |
if PatternInModifier(Result[0], Modifier) and len(Result[0]) < MAX_MODIFIER_LENGTH: | |
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_IN_OUT_MODIFIER, 'Variable Modifier %s' % Result[0], FileTable, Result[2]) | |
break | |
SqlStatement = """ select Modifier, Name, ID | |
from %s | |
where Model = %d | |
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
for Result in ResultSet: | |
for Modifier in ModifierTuple: | |
if PatternInModifier(Result[0], Modifier): | |
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_IN_OUT_MODIFIER, 'Return Type Modifier %s' % Result[0], FileTable, Result[2]) | |
break | |
SqlStatement = """ select Modifier, Header, ID | |
from Function | |
where BelongsToFile = %d | |
""" % (FileID) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
for Result in ResultSet: | |
for Modifier in ModifierTuple: | |
if PatternInModifier(Result[0], Modifier): | |
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_IN_OUT_MODIFIER, 'Return Type Modifier %s' % Result[0], FileTable, Result[2]) | |
break | |
def CheckDeclNoUseCType(FullFileName): | |
ErrorMsgList = [] | |
FileID = GetTableID(FullFileName, ErrorMsgList) | |
if FileID < 0: | |
return ErrorMsgList | |
Db = GetDB() | |
FileTable = 'Identifier' + str(FileID) | |
SqlStatement = """ select Modifier, Name, ID | |
from %s | |
where Model = %d | |
""" % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
CTypeTuple = ('int', 'unsigned', 'char', 'void', 'static', 'long') | |
for Result in ResultSet: | |
for Type in CTypeTuple: | |
if PatternInModifier(Result[0], Type): | |
PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, 'Variable type %s' % Type, 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 == None: | |
continue | |
for Exp in GetPredicateListFromPredicateExpStr(Str[0]): | |
PredInfo = SplitPredicateStr(Exp) | |
if PredInfo[1] == 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 != 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 == 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 == None: | |
continue | |
for Exp in GetPredicateListFromPredicateExpStr(Str[0]): | |
PredInfo = SplitPredicateStr(Exp) | |
if PredInfo[1] == 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 != 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 == 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 == 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 != 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 == None: | |
continue | |
if Type.find('BOOLEAN') != -1: | |
PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_BOOLEAN_VALUE, 'Predicate Expression: %s' % Exp, FileTable, Str[2]) | |
def CheckHeaderFileData(FullFileName): | |
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'): | |
PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_DATA, 'Variable definition appears in header file', FileTable, Result[0]) | |
SqlStatement = """ select ID | |
from Function | |
where BelongsToFile = %d | |
""" % FileID | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
for Result in ResultSet: | |
PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_DATA, 'Function definition appears in header file', 'Function', Result[0]) | |
return ErrorMsgList | |
def CheckHeaderFileIfndef(FullFileName): | |
ErrorMsgList = [] | |
FileID = GetTableID(FullFileName, ErrorMsgList) | |
if FileID < 0: | |
return ErrorMsgList | |
Db = GetDB() | |
FileTable = 'Identifier' + str(FileID) | |
SqlStatement = """ select Value, StartLine | |
from %s | |
where Model = %d order by StartLine | |
""" % (FileTable, DataClass.MODEL_IDENTIFIER_MACRO_IFNDEF) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
if len(ResultSet) == 0: | |
PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_IFNDEF_STATEMENT_1, '', 'File', FileID) | |
return ErrorMsgList | |
for Result in ResultSet: | |
SqlStatement = """ select Value, EndLine | |
from %s | |
where EndLine < %d | |
""" % (FileTable, Result[1]) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
for Result in ResultSet: | |
if not Result[0].startswith('/*') and not Result[0].startswith('//'): | |
PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_IFNDEF_STATEMENT_2, '', 'File', FileID) | |
break | |
SqlStatement = """ select Value | |
from %s | |
where StartLine > (select max(EndLine) from %s where Model = %d) | |
""" % (FileTable, FileTable, DataClass.MODEL_IDENTIFIER_MACRO_ENDIF) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
for Result in ResultSet: | |
if not Result[0].startswith('/*') and not Result[0].startswith('//'): | |
PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_IFNDEF_STATEMENT_3, '', 'File', FileID) | |
return ErrorMsgList | |
def CheckDoxygenCommand(FullFileName): | |
ErrorMsgList = [] | |
FileID = GetTableID(FullFileName, ErrorMsgList) | |
if FileID < 0: | |
return ErrorMsgList | |
Db = GetDB() | |
FileTable = 'Identifier' + str(FileID) | |
SqlStatement = """ select Value, ID | |
from %s | |
where Model = %d or Model = %d | |
""" % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT, DataClass.MODEL_IDENTIFIER_FUNCTION_HEADER) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
DoxygenCommandList = ['bug', 'todo', 'example', 'file', 'attention', 'param', 'post', 'pre', 'retval', | |
'return', 'sa', 'since', 'test', 'note', 'par', 'endcode', 'code'] | |
for Result in ResultSet: | |
CommentStr = Result[0] | |
CommentPartList = CommentStr.split() | |
for Part in CommentPartList: | |
if Part.upper() == 'BUGBUG': | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Bug should be marked with doxygen tag @bug', FileTable, Result[1]) | |
if Part.upper() == 'TODO': | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'ToDo should be marked with doxygen tag @todo', FileTable, Result[1]) | |
if Part.startswith('@'): | |
if EccGlobalData.gException.IsException(ERROR_DOXYGEN_CHECK_COMMAND, Part): | |
continue | |
if not Part.replace('@', '').strip(): | |
continue | |
if Part.lstrip('@') in ['{', '}']: | |
continue | |
if Part.lstrip('@').isalpha(): | |
if Part.lstrip('@') not in DoxygenCommandList: | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Unknown doxygen command %s' % Part, FileTable, Result[1]) | |
else: | |
Index = Part.find('[') | |
if Index == -1: | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Unknown doxygen command %s' % Part, FileTable, Result[1]) | |
RealCmd = Part[1:Index] | |
if RealCmd not in DoxygenCommandList: | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Unknown doxygen command %s' % Part, FileTable, Result[1]) | |
def CheckDoxygenTripleForwardSlash(FullFileName): | |
ErrorMsgList = [] | |
FileID = GetTableID(FullFileName, ErrorMsgList) | |
if FileID < 0: | |
return ErrorMsgList | |
Db = GetDB() | |
SqlStatement = """ select ID, BodyStartLine, BodyStartColumn, EndLine, EndColumn | |
from Function | |
where BelongsToFile = %d | |
""" % (FileID) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
if len(ResultSet) == 0: | |
return | |
FuncDefSet = [] | |
for Result in ResultSet: | |
FuncDefSet.append(Result) | |
FileTable = 'Identifier' + str(FileID) | |
SqlStatement = """ select Value, ID, StartLine, StartColumn, EndLine, EndColumn | |
from %s | |
where Model = %d | |
""" % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
CommentSet = [] | |
try: | |
for Result in ResultSet: | |
CommentSet.append(Result) | |
except: | |
print 'Unrecognized chars in comment of file %s', FullFileName | |
for Result in CommentSet: | |
CommentStr = Result[0] | |
StartLine = Result[2] | |
StartColumn = Result[3] | |
EndLine = Result[4] | |
EndColumn = Result[5] | |
if not CommentStr.startswith('///<'): | |
continue | |
Found = False | |
for FuncDef in FuncDefSet: | |
if StartLine == FuncDef[1] and StartColumn > FuncDef[2] and EndLine == FuncDef[3] and EndColumn < FuncDef[4]: | |
Found = True | |
break | |
if StartLine > FuncDef[1] and EndLine < FuncDef[3]: | |
Found = True | |
break | |
if StartLine == FuncDef[1] and StartColumn > FuncDef[2] and EndLine < FuncDef[3]: | |
Found = True | |
break | |
if StartLine > FuncDef[1] and EndLine == FuncDef[3] and EndColumn < FuncDef[4]: | |
Found = True | |
break | |
if Found: | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMENT_FORMAT, '', FileTable, Result[1]) | |
def CheckFileHeaderDoxygenComments(FullFileName): | |
ErrorMsgList = [] | |
FileID = GetTableID(FullFileName, ErrorMsgList) | |
if FileID < 0: | |
return ErrorMsgList | |
Db = GetDB() | |
FileTable = 'Identifier' + str(FileID) | |
SqlStatement = """ select Value, ID | |
from %s | |
where Model = %d and (StartLine = 1 or StartLine = 7 or StartLine = 8) and StartColumn = 0 | |
""" % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
if len(ResultSet) == 0: | |
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'No File License header appear at the very beginning of file.', 'File', FileID) | |
return ErrorMsgList | |
NoHeaderCommentStartFlag = True | |
NoHeaderCommentEndFlag = True | |
NoHeaderCommentPeriodFlag = True | |
NoCopyrightFlag = True | |
NoLicenseFlag = True | |
NoRevReferFlag = True | |
NextLineIndex = 0 | |
for Result in ResultSet: | |
FileStartFlag = False | |
CommentStrList = [] | |
CommentStr = Result[0].strip() | |
CommentStrListTemp = CommentStr.split('\n') | |
if (len(CommentStrListTemp) <= 1): | |
# For Mac | |
CommentStrListTemp = CommentStr.split('\r') | |
# Skip the content before the file header | |
for CommentLine in CommentStrListTemp: | |
if CommentLine.strip().startswith('/** @file'): | |
FileStartFlag = True | |
if FileStartFlag == True: | |
CommentStrList.append(CommentLine) | |
ID = Result[1] | |
Index = 0 | |
if CommentStrList and CommentStrList[0].strip().startswith('/** @file'): | |
NoHeaderCommentStartFlag = False | |
else: | |
continue | |
if CommentStrList and CommentStrList[-1].strip().endswith('**/'): | |
NoHeaderCommentEndFlag = False | |
else: | |
continue | |
for CommentLine in CommentStrList: | |
Index = Index + 1 | |
NextLineIndex = Index | |
if CommentLine.startswith('/** @file'): | |
continue | |
if CommentLine.startswith('**/'): | |
break | |
# Check whether C File header Comment content start with two spaces. | |
if EccGlobalData.gConfig.HeaderCheckCFileCommentStartSpacesNum == '1' or EccGlobalData.gConfig.HeaderCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1': | |
if CommentLine.startswith('/** @file') == False and CommentLine.startswith('**/') == False and CommentLine.strip() and CommentLine.startswith(' ') == False: | |
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment content should start with two spaces at each line', FileTable, ID) | |
CommentLine = CommentLine.strip() | |
if CommentLine.startswith('Copyright'): | |
NoCopyrightFlag = False | |
if CommentLine.find('All rights reserved') == -1: | |
for Copyright in EccGlobalData.gConfig.Copyright: | |
if CommentLine.find(Copyright) > -1: | |
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, '""All rights reserved"" announcement should be following the ""Copyright"" at the same line', FileTable, ID) | |
break | |
if CommentLine.endswith('<BR>') == -1: | |
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'The ""<BR>"" at the end of the Copyright line is required', FileTable, ID) | |
if NextLineIndex < len(CommentStrList) and CommentStrList[NextLineIndex].strip().startswith('Copyright') == False and CommentStrList[NextLineIndex].strip(): | |
NoLicenseFlag = False | |
if CommentLine.startswith('@par Revision Reference:'): | |
NoRevReferFlag = False | |
RefListFlag = False | |
for RefLine in CommentStrList[NextLineIndex:]: | |
if RefLine.strip() and (NextLineIndex + 1) < len(CommentStrList) and CommentStrList[NextLineIndex+1].strip() and CommentStrList[NextLineIndex+1].strip().startswith('**/') == False: | |
RefListFlag = True | |
if RefLine.strip() == False or RefLine.strip().startswith('**/'): | |
RefListFlag = False | |
break | |
# Check whether C File header Comment's each reference at list should begin with a bullet character. | |
if EccGlobalData.gConfig.HeaderCheckCFileCommentReferenceFormat == '1' or EccGlobalData.gConfig.HeaderCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1': | |
if RefListFlag == True: | |
if RefLine.strip() and RefLine.strip().startswith('**/') == False and RefLine.startswith(' -') == False: | |
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'Each reference on a separate line should begin with a bullet character ""-"" ', FileTable, ID) | |
if NoHeaderCommentStartFlag: | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FILE_HEADER, 'File header comment should begin with ""/** @file""', FileTable, ID) | |
return | |
if NoHeaderCommentEndFlag: | |
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment should end with ""**/""', FileTable, ID) | |
return | |
if NoCopyrightFlag: | |
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment missing the ""Copyright""', FileTable, ID) | |
#Check whether C File header Comment have the License immediately after the ""Copyright"" line. | |
if EccGlobalData.gConfig.HeaderCheckCFileCommentLicenseFormat == '1' or EccGlobalData.gConfig.HeaderCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1': | |
if NoLicenseFlag: | |
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment should have the License immediately after the ""Copyright"" line', FileTable, ID) | |
def CheckFuncHeaderDoxygenComments(FullFileName): | |
ErrorMsgList = [] | |
FileID = GetTableID(FullFileName, ErrorMsgList) | |
if FileID < 0: | |
return ErrorMsgList | |
Db = GetDB() | |
FileTable = 'Identifier' + str(FileID) | |
SqlStatement = """ select Value, StartLine, EndLine, ID | |
from %s | |
where Model = %d | |
""" % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
CommentSet = [] | |
try: | |
for Result in ResultSet: | |
CommentSet.append(Result) | |
except: | |
print 'Unrecognized chars in comment of file %s', FullFileName | |
# Func Decl check | |
SqlStatement = """ select Modifier, Name, StartLine, ID, Value | |
from %s | |
where Model = %d | |
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
for Result in ResultSet: | |
FuncName = Result[4] | |
FunctionHeaderComment = CheckCommentImmediatelyPrecedeFunctionHeader(Result[1], Result[2], CommentSet) | |
if FunctionHeaderComment: | |
CheckFunctionHeaderConsistentWithDoxygenComment(Result[0], Result[1], Result[2], FunctionHeaderComment[0], FunctionHeaderComment[1], ErrorMsgList, FunctionHeaderComment[3], FileTable) | |
else: | |
if EccGlobalData.gException.IsException(ERROR_HEADER_CHECK_FUNCTION, FuncName): | |
continue | |
ErrorMsgList.append('Line %d :Function %s has NO comment immediately preceding it.' % (Result[2], Result[1])) | |
PrintErrorMsg(ERROR_HEADER_CHECK_FUNCTION, 'Function [%s] has NO comment immediately preceding it.' % (FuncName), FileTable, Result[3]) | |
# Func Def check | |
SqlStatement = """ select Value, StartLine, EndLine, ID | |
from %s | |
where Model = %d | |
""" % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_HEADER) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
CommentSet = [] | |
try: | |
for Result in ResultSet: | |
CommentSet.append(Result) | |
except: | |
print 'Unrecognized chars in comment of file %s', FullFileName | |
SqlStatement = """ select Modifier, Header, StartLine, ID, Name | |
from Function | |
where BelongsToFile = %d | |
""" % (FileID) | |
ResultSet = Db.TblFile.Exec(SqlStatement) | |
for Result in ResultSet: | |
FuncName = Result[4] | |
FunctionHeaderComment = CheckCommentImmediatelyPrecedeFunctionHeader(Result[1], Result[2], CommentSet) | |
if FunctionHeaderComment: | |
CheckFunctionHeaderConsistentWithDoxygenComment(Result[0], Result[1], Result[2], FunctionHeaderComment[0], FunctionHeaderComment[1], ErrorMsgList, FunctionHeaderComment[3], FileTable) | |
else: | |
if EccGlobalData.gException.IsException(ERROR_HEADER_CHECK_FUNCTION, FuncName): | |
continue | |
ErrorMsgList.append('Line %d :Function [%s] has NO comment immediately preceding it.' % (Result[2], Result[1])) | |
PrintErrorMsg(ERROR_HEADER_CHECK_FUNCTION, 'Function [%s] has NO comment immediately preceding it.' % (FuncName), 'Function', Result[3]) | |
return ErrorMsgList | |
def CheckCommentImmediatelyPrecedeFunctionHeader(FuncName, FuncStartLine, CommentSet): | |
for Comment in CommentSet: | |
if Comment[2] == FuncStartLine - 1: | |
return Comment | |
return None | |
def GetDoxygenStrFromComment(Str): | |
DoxygenStrList = [] | |
ParamTagList = Str.split('@param') | |
if len(ParamTagList) > 1: | |
i = 1 | |
while i < len(ParamTagList): | |
DoxygenStrList.append('@param' + ParamTagList[i]) | |
i += 1 | |
Str = ParamTagList[0] | |
RetvalTagList = ParamTagList[-1].split('@retval') | |
if len(RetvalTagList) > 1: | |
if len(ParamTagList) > 1: | |
DoxygenStrList[-1] = '@param' + RetvalTagList[0] | |
i = 1 | |
while i < len(RetvalTagList): | |
DoxygenStrList.append('@retval' + RetvalTagList[i]) | |
i += 1 | |
ReturnTagList = RetvalTagList[-1].split('@return') | |
if len(ReturnTagList) > 1: | |
if len(RetvalTagList) > 1: | |
DoxygenStrList[-1] = '@retval' + ReturnTagList[0] | |
elif len(ParamTagList) > 1: | |
DoxygenStrList[-1] = '@param' + ReturnTagList[0] | |
i = 1 | |
while i < len(ReturnTagList): | |
DoxygenStrList.append('@return' + ReturnTagList[i]) | |
i += 1 | |
if len(DoxygenStrList) > 0: | |
DoxygenStrList[-1] = DoxygenStrList[-1].rstrip('--*/') | |
return DoxygenStrList | |
def CheckGeneralDoxygenCommentLayout(Str, StartLine, ErrorMsgList, CommentId= -1, TableName=''): | |
#/** --*/ @retval after @param | |
if not Str.startswith('/**'): | |
ErrorMsgList.append('Line %d : Comment does NOT have prefix /** ' % StartLine) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Comment does NOT have prefix /** ', TableName, CommentId) | |
if not Str.endswith('**/'): | |
ErrorMsgList.append('Line %d : Comment does NOT have tail **/ ' % StartLine) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Comment does NOT have tail **/ ', TableName, CommentId) | |
FirstRetvalIndex = Str.find('@retval') | |
LastParamIndex = Str.rfind('@param') | |
if (FirstRetvalIndex > 0) and (LastParamIndex > 0) and (FirstRetvalIndex < LastParamIndex): | |
ErrorMsgList.append('Line %d : @retval appear before @param ' % StartLine) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, @retval appear before @param ', TableName, CommentId) | |
def CheckFunctionHeaderConsistentWithDoxygenComment(FuncModifier, FuncHeader, FuncStartLine, CommentStr, CommentStartLine, ErrorMsgList, CommentId= -1, TableName=''): | |
ParamList = GetParamList(FuncHeader) | |
CheckGeneralDoxygenCommentLayout(CommentStr, CommentStartLine, ErrorMsgList, CommentId, TableName) | |
DescriptionStr = CommentStr | |
DoxygenStrList = GetDoxygenStrFromComment(DescriptionStr) | |
if DescriptionStr.find('.') == -1: | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMENT_DESCRIPTION, 'Comment description should end with period \'.\'', TableName, CommentId) | |
DoxygenTagNumber = len(DoxygenStrList) | |
ParamNumber = len(ParamList) | |
for Param in ParamList: | |
if Param.Name.upper() == 'VOID' and ParamNumber == 1: | |
ParamNumber -= 1 | |
Index = 0 | |
if ParamNumber > 0 and DoxygenTagNumber > 0: | |
while Index < ParamNumber and Index < DoxygenTagNumber: | |
ParamModifier = ParamList[Index].Modifier | |
ParamName = ParamList[Index].Name.strip() | |
Tag = DoxygenStrList[Index].strip(' ') | |
if (not Tag[-1] == ('\n')) and (not Tag[-1] == ('\r')): | |
ErrorMsgList.append('Line %d : in Comment, <%s> does NOT end with new line ' % (CommentStartLine, Tag.replace('\n', '').replace('\r', ''))) | |
PrintErrorMsg(ERROR_HEADER_CHECK_FUNCTION, 'in Comment, <%s> does NOT end with new line ' % (Tag.replace('\n', '').replace('\r', '')), TableName, CommentId) | |
TagPartList = Tag.split() | |
if len(TagPartList) < 2: | |
ErrorMsgList.append('Line %d : in Comment, <%s> does NOT contain doxygen contents ' % (CommentStartLine, Tag.replace('\n', '').replace('\r', ''))) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT contain doxygen contents ' % (Tag.replace('\n', '').replace('\r', '')), TableName, CommentId) | |
Index += 1 | |
continue | |
LBPos = Tag.find('[') | |
RBPos = Tag.find(']') | |
ParamToLBContent = Tag[len('@param'):LBPos].strip() | |
if LBPos > 0 and len(ParamToLBContent) == 0 and RBPos > LBPos: | |
InOutStr = '' | |
ModifierPartList = ParamModifier.split() | |
for Part in ModifierPartList: | |
if Part.strip() == 'IN': | |
InOutStr += 'in' | |
if Part.strip() == 'OUT': | |
if InOutStr != '': | |
InOutStr += ', out' | |
else: | |
InOutStr = 'out' | |
if InOutStr != '': | |
if Tag.find('[' + InOutStr + ']') == -1: | |
if InOutStr != 'in, out': | |
ErrorMsgList.append('Line %d : in Comment, <%s> does NOT have %s ' % (CommentStartLine, (TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']')) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT have %s ' % ((TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']'), TableName, CommentId) | |
else: | |
if Tag.find('[in,out]') == -1: | |
ErrorMsgList.append('Line %d : in Comment, <%s> does NOT have %s ' % (CommentStartLine, (TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']')) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT have %s ' % ((TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']'), TableName, CommentId) | |
if Tag.find(ParamName) == -1 and ParamName != 'VOID' and ParamName != 'void': | |
ErrorMsgList.append('Line %d : in Comment, <%s> does NOT consistent with parameter name %s ' % (CommentStartLine, (TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), ParamName)) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT consistent with parameter name %s ' % ((TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), ParamName), TableName, CommentId) | |
Index += 1 | |
if Index < ParamNumber: | |
ErrorMsgList.append('Line %d : Number of doxygen tags in comment less than number of function parameters' % CommentStartLine) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Number of doxygen tags in comment less than number of function parameters ', TableName, CommentId) | |
# VOID return type, NOT VOID*. VOID* should be matched with a doxygen tag. | |
if (FuncModifier.find('VOID') != -1 or FuncModifier.find('void') != -1) and FuncModifier.find('*') == -1: | |
# assume we allow a return description tag for void func. return. that's why 'DoxygenTagNumber - 1' is used instead of 'DoxygenTagNumber' | |
if Index < DoxygenTagNumber - 1 or (Index < DoxygenTagNumber and DoxygenStrList[Index].startswith('@retval')): | |
ErrorMsgList.append('Line %d : VOID return type need NO doxygen tags in comment' % CommentStartLine) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'VOID return type need no doxygen tags in comment ', TableName, CommentId) | |
else: | |
if Index < DoxygenTagNumber and not DoxygenStrList[Index].startswith('@retval') and not DoxygenStrList[Index].startswith('@return'): | |
ErrorMsgList.append('Line %d : Number of @param doxygen tags in comment does NOT match number of function parameters' % CommentStartLine) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Number of @param doxygen tags in comment does NOT match number of function parameters ', TableName, CommentId) | |
else: | |
if ParamNumber == 0 and DoxygenTagNumber != 0 and ((FuncModifier.find('VOID') != -1 or FuncModifier.find('void') != -1) and FuncModifier.find('*') == -1): | |
ErrorMsgList.append('Line %d : VOID return type need NO doxygen tags in comment' % CommentStartLine) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'VOID return type need NO doxygen tags in comment ', TableName, CommentId) | |
if ParamNumber != 0 and DoxygenTagNumber == 0: | |
ErrorMsgList.append('Line %d : No doxygen tags in comment' % CommentStartLine) | |
PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'No doxygen tags in comment ', TableName, CommentId) | |
if __name__ == '__main__': | |
# EdkLogger.Initialize() | |
# EdkLogger.SetLevel(EdkLogger.QUIET) | |
# CollectSourceCodeDataIntoDB(sys.argv[1]) | |
try: | |
test_file = sys.argv[1] | |
except IndexError, v: | |
print "Usage: %s filename" % sys.argv[0] | |
sys.exit(1) | |
MsgList = CheckFuncHeaderDoxygenComments(test_file) | |
for Msg in MsgList: | |
print Msg | |
print 'Done!' |