c.py revision 4fd606d1f5abe38e1f42c38de1d2e895166bd0f4
## @file
# This file is used to be the c coding style checking of ECC tool
#
# Copyright (c) 2009 - 2010, 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 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():
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:
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 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
Index = Result[0].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
Index = Result[0].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])
if Result[2] == Result[4]:
PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, '[%s] Return Type should appear on its own 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]
# if len(ReturnType) == 0:
# continue
Index = Result[0].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]
# if len(ReturnType) == 0:
# continue
Index = Result[0].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)):
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
# Enum could directly assign value to variable
Field = Field.split('=')[0].strip()
TokenList = Field.split()
# Remove pointers before variable
if not Pattern.match(TokenList[-1].lstrip('*')):
ErrMsgList.append(TokenList[-1].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']
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 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:
PrintErrorMsg(ERROR_HEADER_CHECK_FILE, '""All rights reserved"" announcement should be following the ""Copyright"" at the same line', FileTable, ID)
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!'