]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Ecc/Check.py
There is a limitation on WINDOWS OS for the length of entire file path can’t be large...
[mirror_edk2.git] / BaseTools / Source / Python / Ecc / Check.py
1 ## @file
2 # This file is used to define checkpoints used by ECC tool
3 #
4 # Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
9 #
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 #
13 import Common.LongFilePathOs as os
14 import re
15 from CommonDataClass.DataClass import *
16 from Common.DataType import SUP_MODULE_LIST_STRING, TAB_VALUE_SPLIT
17 from EccToolError import *
18 from MetaDataParser import ParseHeaderCommentSection
19 import EccGlobalData
20 import c
21
22 ## Check
23 #
24 # This class is to define checkpoints used by ECC tool
25 #
26 # @param object: Inherited from object class
27 #
28 class Check(object):
29 def __init__(self):
30 pass
31
32 # Check all required checkpoints
33 def Check(self):
34 self.GeneralCheck()
35 self.MetaDataFileCheck()
36 self.DoxygenCheck()
37 self.IncludeFileCheck()
38 self.PredicateExpressionCheck()
39 self.DeclAndDataTypeCheck()
40 self.FunctionLayoutCheck()
41 self.NamingConventionCheck()
42
43 # General Checking
44 def GeneralCheck(self):
45 self.GeneralCheckNonAcsii()
46
47 # Check whether file has non ACSII char
48 def GeneralCheckNonAcsii(self):
49 if EccGlobalData.gConfig.GeneralCheckNonAcsii == '1' or EccGlobalData.gConfig.GeneralCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
50 EdkLogger.quiet("Checking Non-ACSII char in file ...")
51 SqlCommand = """select ID, FullPath, ExtName from File"""
52 RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
53 for Record in RecordSet:
54 if Record[2].upper() not in EccGlobalData.gConfig.BinaryExtList:
55 op = open(Record[1]).readlines()
56 IndexOfLine = 0
57 for Line in op:
58 IndexOfLine += 1
59 IndexOfChar = 0
60 for Char in Line:
61 IndexOfChar += 1
62 if ord(Char) > 126:
63 OtherMsg = "File %s has Non-ASCII char at line %s column %s" % (Record[1], IndexOfLine, IndexOfChar)
64 EccGlobalData.gDb.TblReport.Insert(ERROR_GENERAL_CHECK_NON_ACSII, OtherMsg=OtherMsg, BelongsToTable='File', BelongsToItem=Record[0])
65
66 # C Function Layout Checking
67 def FunctionLayoutCheck(self):
68 self.FunctionLayoutCheckReturnType()
69 self.FunctionLayoutCheckModifier()
70 self.FunctionLayoutCheckName()
71 self.FunctionLayoutCheckPrototype()
72 self.FunctionLayoutCheckBody()
73 self.FunctionLayoutCheckLocalVariable()
74
75 def WalkTree(self):
76 IgnoredPattern = c.GetIgnoredDirListPattern()
77 for Dirpath, Dirnames, Filenames in os.walk(EccGlobalData.gTarget):
78 for Dir in Dirnames:
79 Dirname = os.path.join(Dirpath, Dir)
80 if os.path.islink(Dirname):
81 Dirname = os.path.realpath(Dirname)
82 if os.path.isdir(Dirname):
83 # symlinks to directories are treated as directories
84 Dirnames.remove(Dir)
85 Dirnames.append(Dirname)
86 if IgnoredPattern.match(Dirpath.upper()):
87 continue
88 yield (Dirpath, Dirnames, Filenames)
89
90 # Check whether return type exists and in the first line
91 def FunctionLayoutCheckReturnType(self):
92 if EccGlobalData.gConfig.CFunctionLayoutCheckReturnType == '1' or EccGlobalData.gConfig.CFunctionLayoutCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
93 EdkLogger.quiet("Checking function layout return type ...")
94
95 # for Dirpath, Dirnames, Filenames in self.WalkTree():
96 # for F in Filenames:
97 # if os.path.splitext(F)[1] in ('.c', '.h'):
98 # FullName = os.path.join(Dirpath, F)
99 # c.CheckFuncLayoutReturnType(FullName)
100 for FullName in EccGlobalData.gCFileList + EccGlobalData.gHFileList:
101 c.CheckFuncLayoutReturnType(FullName)
102
103 # Check whether any optional functional modifiers exist and next to the return type
104 def FunctionLayoutCheckModifier(self):
105 if EccGlobalData.gConfig.CFunctionLayoutCheckOptionalFunctionalModifier == '1' or EccGlobalData.gConfig.CFunctionLayoutCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
106 EdkLogger.quiet("Checking function layout modifier ...")
107
108 # for Dirpath, Dirnames, Filenames in self.WalkTree():
109 # for F in Filenames:
110 # if os.path.splitext(F)[1] in ('.c', '.h'):
111 # FullName = os.path.join(Dirpath, F)
112 # c.CheckFuncLayoutModifier(FullName)
113 for FullName in EccGlobalData.gCFileList + EccGlobalData.gHFileList:
114 c.CheckFuncLayoutModifier(FullName)
115
116 # Check whether the next line contains the function name, left justified, followed by the beginning of the parameter list
117 # Check whether the closing parenthesis is on its own line and also indented two spaces
118 def FunctionLayoutCheckName(self):
119 if EccGlobalData.gConfig.CFunctionLayoutCheckFunctionName == '1' or EccGlobalData.gConfig.CFunctionLayoutCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
120 EdkLogger.quiet("Checking function layout function name ...")
121
122 # for Dirpath, Dirnames, Filenames in self.WalkTree():
123 # for F in Filenames:
124 # if os.path.splitext(F)[1] in ('.c', '.h'):
125 # FullName = os.path.join(Dirpath, F)
126 # c.CheckFuncLayoutName(FullName)
127 for FullName in EccGlobalData.gCFileList + EccGlobalData.gHFileList:
128 c.CheckFuncLayoutName(FullName)
129
130 # Check whether the function prototypes in include files have the same form as function definitions
131 def FunctionLayoutCheckPrototype(self):
132 if EccGlobalData.gConfig.CFunctionLayoutCheckFunctionPrototype == '1' or EccGlobalData.gConfig.CFunctionLayoutCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
133 EdkLogger.quiet("Checking function layout function prototype ...")
134
135 # for Dirpath, Dirnames, Filenames in self.WalkTree():
136 # for F in Filenames:
137 # if os.path.splitext(F)[1] in ('.c'):
138 # FullName = os.path.join(Dirpath, F)
139 # EdkLogger.quiet("[PROTOTYPE]" + FullName)
140 # c.CheckFuncLayoutPrototype(FullName)
141 for FullName in EccGlobalData.gCFileList:
142 EdkLogger.quiet("[PROTOTYPE]" + FullName)
143 c.CheckFuncLayoutPrototype(FullName)
144
145 # Check whether the body of a function is contained by open and close braces that must be in the first column
146 def FunctionLayoutCheckBody(self):
147 if EccGlobalData.gConfig.CFunctionLayoutCheckFunctionBody == '1' or EccGlobalData.gConfig.CFunctionLayoutCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
148 EdkLogger.quiet("Checking function layout function body ...")
149
150 # for Dirpath, Dirnames, Filenames in self.WalkTree():
151 # for F in Filenames:
152 # if os.path.splitext(F)[1] in ('.c'):
153 # FullName = os.path.join(Dirpath, F)
154 # c.CheckFuncLayoutBody(FullName)
155 for FullName in EccGlobalData.gCFileList:
156 c.CheckFuncLayoutBody(FullName)
157
158 # Check whether the data declarations is the first code in a module.
159 # self.CFunctionLayoutCheckDataDeclaration = 1
160 # Check whether no initialization of a variable as part of its declaration
161 def FunctionLayoutCheckLocalVariable(self):
162 if EccGlobalData.gConfig.CFunctionLayoutCheckNoInitOfVariable == '1' or EccGlobalData.gConfig.CFunctionLayoutCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
163 EdkLogger.quiet("Checking function layout local variables ...")
164
165 # for Dirpath, Dirnames, Filenames in self.WalkTree():
166 # for F in Filenames:
167 # if os.path.splitext(F)[1] in ('.c'):
168 # FullName = os.path.join(Dirpath, F)
169 # c.CheckFuncLayoutLocalVariable(FullName)
170
171 for FullName in EccGlobalData.gCFileList:
172 c.CheckFuncLayoutLocalVariable(FullName)
173
174 # Check whether no use of STATIC for functions
175 # self.CFunctionLayoutCheckNoStatic = 1
176
177 # Declarations and Data Types Checking
178 def DeclAndDataTypeCheck(self):
179 self.DeclCheckNoUseCType()
180 self.DeclCheckInOutModifier()
181 self.DeclCheckEFIAPIModifier()
182 self.DeclCheckEnumeratedType()
183 self.DeclCheckStructureDeclaration()
184 self.DeclCheckSameStructure()
185 self.DeclCheckUnionType()
186
187
188 # Check whether no use of int, unsigned, char, void, static, long in any .c, .h or .asl files.
189 def DeclCheckNoUseCType(self):
190 if EccGlobalData.gConfig.DeclarationDataTypeCheckNoUseCType == '1' or EccGlobalData.gConfig.DeclarationDataTypeCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
191 EdkLogger.quiet("Checking Declaration No use C type ...")
192
193 # for Dirpath, Dirnames, Filenames in self.WalkTree():
194 # for F in Filenames:
195 # if os.path.splitext(F)[1] in ('.h', '.c'):
196 # FullName = os.path.join(Dirpath, F)
197 # c.CheckDeclNoUseCType(FullName)
198 for FullName in EccGlobalData.gCFileList + EccGlobalData.gHFileList:
199 c.CheckDeclNoUseCType(FullName)
200
201 # Check whether the modifiers IN, OUT, OPTIONAL, and UNALIGNED are used only to qualify arguments to a function and should not appear in a data type declaration
202 def DeclCheckInOutModifier(self):
203 if EccGlobalData.gConfig.DeclarationDataTypeCheckInOutModifier == '1' or EccGlobalData.gConfig.DeclarationDataTypeCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
204 EdkLogger.quiet("Checking Declaration argument modifier ...")
205
206 # for Dirpath, Dirnames, Filenames in self.WalkTree():
207 # for F in Filenames:
208 # if os.path.splitext(F)[1] in ('.h', '.c'):
209 # FullName = os.path.join(Dirpath, F)
210 # c.CheckDeclArgModifier(FullName)
211 for FullName in EccGlobalData.gCFileList + EccGlobalData.gHFileList:
212 c.CheckDeclArgModifier(FullName)
213
214 # Check whether the EFIAPI modifier should be used at the entry of drivers, events, and member functions of protocols
215 def DeclCheckEFIAPIModifier(self):
216 if EccGlobalData.gConfig.DeclarationDataTypeCheckEFIAPIModifier == '1' or EccGlobalData.gConfig.DeclarationDataTypeCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
217 pass
218
219 # Check whether Enumerated Type has a 'typedef' and the name is capital
220 def DeclCheckEnumeratedType(self):
221 if EccGlobalData.gConfig.DeclarationDataTypeCheckEnumeratedType == '1' or EccGlobalData.gConfig.DeclarationDataTypeCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
222 EdkLogger.quiet("Checking Declaration enum typedef ...")
223
224 # for Dirpath, Dirnames, Filenames in self.WalkTree():
225 # for F in Filenames:
226 # if os.path.splitext(F)[1] in ('.h', '.c'):
227 # FullName = os.path.join(Dirpath, F)
228 # EdkLogger.quiet("[ENUM]" + FullName)
229 # c.CheckDeclEnumTypedef(FullName)
230 for FullName in EccGlobalData.gCFileList + EccGlobalData.gHFileList:
231 EdkLogger.quiet("[ENUM]" + FullName)
232 c.CheckDeclEnumTypedef(FullName)
233
234 # Check whether Structure Type has a 'typedef' and the name is capital
235 def DeclCheckStructureDeclaration(self):
236 if EccGlobalData.gConfig.DeclarationDataTypeCheckStructureDeclaration == '1' or EccGlobalData.gConfig.DeclarationDataTypeCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
237 EdkLogger.quiet("Checking Declaration struct typedef ...")
238
239 # for Dirpath, Dirnames, Filenames in self.WalkTree():
240 # for F in Filenames:
241 # if os.path.splitext(F)[1] in ('.h', '.c'):
242 # FullName = os.path.join(Dirpath, F)
243 # EdkLogger.quiet("[STRUCT]" + FullName)
244 # c.CheckDeclStructTypedef(FullName)
245 for FullName in EccGlobalData.gCFileList + EccGlobalData.gHFileList:
246 EdkLogger.quiet("[STRUCT]" + FullName)
247 c.CheckDeclStructTypedef(FullName)
248
249 # Check whether having same Structure
250 def DeclCheckSameStructure(self):
251 if EccGlobalData.gConfig.DeclarationDataTypeCheckSameStructure == '1' or EccGlobalData.gConfig.DeclarationDataTypeCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
252 EdkLogger.quiet("Checking same struct ...")
253 AllStructure = {}
254 for IdentifierTable in EccGlobalData.gIdentifierTableList:
255 SqlCommand = """select ID, Name, BelongsToFile from %s where Model = %s""" % (IdentifierTable, MODEL_IDENTIFIER_STRUCTURE)
256 RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
257 for Record in RecordSet:
258 if Record[1] != '':
259 if Record[1] not in AllStructure.keys():
260 AllStructure[Record[1]] = Record[2]
261 else:
262 ID = AllStructure[Record[1]]
263 SqlCommand = """select FullPath from File where ID = %s """ % ID
264 NewRecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
265 OtherMsg = "The structure name '%s' is duplicate" % Record[1]
266 if NewRecordSet != []:
267 OtherMsg = "The structure name [%s] is duplicate with the one defined in %s, maybe struct NOT typedefed or the typedef new type NOT used to qualify variables" % (Record[1], NewRecordSet[0][0])
268 if not EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_SAME_STRUCTURE, Record[1]):
269 EccGlobalData.gDb.TblReport.Insert(ERROR_DECLARATION_DATA_TYPE_CHECK_SAME_STRUCTURE, OtherMsg=OtherMsg, BelongsToTable=IdentifierTable, BelongsToItem=Record[0])
270
271 # Check whether Union Type has a 'typedef' and the name is capital
272 def DeclCheckUnionType(self):
273 if EccGlobalData.gConfig.DeclarationDataTypeCheckUnionType == '1' or EccGlobalData.gConfig.DeclarationDataTypeCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
274 EdkLogger.quiet("Checking Declaration union typedef ...")
275
276 # for Dirpath, Dirnames, Filenames in self.WalkTree():
277 # for F in Filenames:
278 # if os.path.splitext(F)[1] in ('.h', '.c'):
279 # FullName = os.path.join(Dirpath, F)
280 # EdkLogger.quiet("[UNION]" + FullName)
281 # c.CheckDeclUnionTypedef(FullName)
282 for FullName in EccGlobalData.gCFileList + EccGlobalData.gHFileList:
283 EdkLogger.quiet("[UNION]" + FullName)
284 c.CheckDeclUnionTypedef(FullName)
285
286 # Predicate Expression Checking
287 def PredicateExpressionCheck(self):
288 self.PredicateExpressionCheckBooleanValue()
289 self.PredicateExpressionCheckNonBooleanOperator()
290 self.PredicateExpressionCheckComparisonNullType()
291
292 # Check whether Boolean values, variable type BOOLEAN not use explicit comparisons to TRUE or FALSE
293 def PredicateExpressionCheckBooleanValue(self):
294 if EccGlobalData.gConfig.PredicateExpressionCheckBooleanValue == '1' or EccGlobalData.gConfig.PredicateExpressionCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
295 EdkLogger.quiet("Checking predicate expression Boolean value ...")
296
297 # for Dirpath, Dirnames, Filenames in self.WalkTree():
298 # for F in Filenames:
299 # if os.path.splitext(F)[1] in ('.c'):
300 # FullName = os.path.join(Dirpath, F)
301 # EdkLogger.quiet("[BOOLEAN]" + FullName)
302 # c.CheckBooleanValueComparison(FullName)
303 for FullName in EccGlobalData.gCFileList:
304 EdkLogger.quiet("[BOOLEAN]" + FullName)
305 c.CheckBooleanValueComparison(FullName)
306
307 # Check whether Non-Boolean comparisons use a compare operator (==, !=, >, < >=, <=).
308 def PredicateExpressionCheckNonBooleanOperator(self):
309 if EccGlobalData.gConfig.PredicateExpressionCheckNonBooleanOperator == '1' or EccGlobalData.gConfig.PredicateExpressionCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
310 EdkLogger.quiet("Checking predicate expression Non-Boolean variable...")
311
312 # for Dirpath, Dirnames, Filenames in self.WalkTree():
313 # for F in Filenames:
314 # if os.path.splitext(F)[1] in ('.c'):
315 # FullName = os.path.join(Dirpath, F)
316 # EdkLogger.quiet("[NON-BOOLEAN]" + FullName)
317 # c.CheckNonBooleanValueComparison(FullName)
318 for FullName in EccGlobalData.gCFileList:
319 EdkLogger.quiet("[NON-BOOLEAN]" + FullName)
320 c.CheckNonBooleanValueComparison(FullName)
321
322 # Check whether a comparison of any pointer to zero must be done via the NULL type
323 def PredicateExpressionCheckComparisonNullType(self):
324 if EccGlobalData.gConfig.PredicateExpressionCheckComparisonNullType == '1' or EccGlobalData.gConfig.PredicateExpressionCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
325 EdkLogger.quiet("Checking predicate expression NULL pointer ...")
326
327 # for Dirpath, Dirnames, Filenames in self.WalkTree():
328 # for F in Filenames:
329 # if os.path.splitext(F)[1] in ('.c'):
330 # FullName = os.path.join(Dirpath, F)
331 # EdkLogger.quiet("[POINTER]" + FullName)
332 # c.CheckPointerNullComparison(FullName)
333 for FullName in EccGlobalData.gCFileList:
334 EdkLogger.quiet("[POINTER]" + FullName)
335 c.CheckPointerNullComparison(FullName)
336
337 # Include file checking
338 def IncludeFileCheck(self):
339 self.IncludeFileCheckIfndef()
340 self.IncludeFileCheckData()
341 self.IncludeFileCheckSameName()
342
343 # Check whether having include files with same name
344 def IncludeFileCheckSameName(self):
345 if EccGlobalData.gConfig.IncludeFileCheckSameName == '1' or EccGlobalData.gConfig.IncludeFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
346 EdkLogger.quiet("Checking same header file name ...")
347 SqlCommand = """select ID, FullPath from File
348 where Model = 1002 order by Name """
349 RecordDict = {}
350 RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
351 for Record in RecordSet:
352 List = Record[1].replace('/', '\\').split('\\')
353 if len(List) >= 2:
354 Key = List[-2] + '\\' + List[-1]
355 else:
356 Key = List[0]
357 if Key not in RecordDict:
358 RecordDict[Key] = [Record]
359 else:
360 RecordDict[Key].append(Record)
361
362 for Key in RecordDict:
363 if len(RecordDict[Key]) > 1:
364 for Item in RecordDict[Key]:
365 Path = Item[1].replace(EccGlobalData.gWorkspace, '')
366 if Path.startswith('\\') or Path.startswith('/'):
367 Path = Path[1:]
368 if not EccGlobalData.gException.IsException(ERROR_INCLUDE_FILE_CHECK_NAME, Path):
369 EccGlobalData.gDb.TblReport.Insert(ERROR_INCLUDE_FILE_CHECK_NAME, OtherMsg="The file name for [%s] is duplicate" % Path, BelongsToTable='File', BelongsToItem=Item[0])
370
371 # Check whether all include file contents is guarded by a #ifndef statement.
372 def IncludeFileCheckIfndef(self):
373 if EccGlobalData.gConfig.IncludeFileCheckIfndefStatement == '1' or EccGlobalData.gConfig.IncludeFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
374 EdkLogger.quiet("Checking header file ifndef ...")
375
376 # for Dirpath, Dirnames, Filenames in self.WalkTree():
377 # for F in Filenames:
378 # if os.path.splitext(F)[1] in ('.h'):
379 # FullName = os.path.join(Dirpath, F)
380 # MsgList = c.CheckHeaderFileIfndef(FullName)
381 for FullName in EccGlobalData.gHFileList:
382 MsgList = c.CheckHeaderFileIfndef(FullName)
383
384 # Check whether include files NOT contain code or define data variables
385 def IncludeFileCheckData(self):
386 if EccGlobalData.gConfig.IncludeFileCheckData == '1' or EccGlobalData.gConfig.IncludeFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
387 EdkLogger.quiet("Checking header file data ...")
388
389 # for Dirpath, Dirnames, Filenames in self.WalkTree():
390 # for F in Filenames:
391 # if os.path.splitext(F)[1] in ('.h'):
392 # FullName = os.path.join(Dirpath, F)
393 # MsgList = c.CheckHeaderFileData(FullName)
394 for FullName in EccGlobalData.gHFileList:
395 MsgList = c.CheckHeaderFileData(FullName)
396
397 # Doxygen document checking
398 def DoxygenCheck(self):
399 self.DoxygenCheckFileHeader()
400 self.DoxygenCheckFunctionHeader()
401 self.DoxygenCheckCommentDescription()
402 self.DoxygenCheckCommentFormat()
403 self.DoxygenCheckCommand()
404
405 # Check whether the file headers are followed Doxygen special documentation blocks in section 2.3.5
406 def DoxygenCheckFileHeader(self):
407 if EccGlobalData.gConfig.DoxygenCheckFileHeader == '1' or EccGlobalData.gConfig.DoxygenCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
408 EdkLogger.quiet("Checking Doxygen file header ...")
409
410 for Dirpath, Dirnames, Filenames in self.WalkTree():
411 for F in Filenames:
412 Ext = os.path.splitext(F)[1]
413 if Ext in ('.h', '.c'):
414 FullName = os.path.join(Dirpath, F)
415 MsgList = c.CheckFileHeaderDoxygenComments(FullName)
416 elif Ext in ('.inf', '.dec', '.dsc', '.fdf'):
417 FullName = os.path.join(Dirpath, F)
418 op = open(FullName).readlines()
419 FileLinesList = op
420 LineNo = 0
421 CurrentSection = MODEL_UNKNOWN
422 HeaderSectionLines = []
423 HeaderCommentStart = False
424 HeaderCommentEnd = False
425
426 for Line in FileLinesList:
427 LineNo = LineNo + 1
428 Line = Line.strip()
429 if (LineNo < len(FileLinesList) - 1):
430 NextLine = FileLinesList[LineNo].strip()
431
432 #
433 # blank line
434 #
435 if (Line == '' or not Line) and LineNo == len(FileLinesList):
436 LastSectionFalg = True
437
438 #
439 # check whether file header comment section started
440 #
441 if Line.startswith('#') and \
442 (Line.find('@file') > -1) and \
443 not HeaderCommentStart:
444 if CurrentSection != MODEL_UNKNOWN:
445 SqlStatement = """ select ID from File where FullPath like '%s'""" % FullName
446 ResultSet = EccGlobalData.gDb.TblFile.Exec(SqlStatement)
447 for Result in ResultSet:
448 Msg = 'INF/DEC/DSC/FDF file header comment should begin with ""## @file"" or ""# @file""at the very top file'
449 EccGlobalData.gDb.TblReport.Insert(ERROR_DOXYGEN_CHECK_FILE_HEADER, Msg, "File", Result[0])
450
451 else:
452 CurrentSection = MODEL_IDENTIFIER_FILE_HEADER
453 #
454 # Append the first line to section lines.
455 #
456 HeaderSectionLines.append((Line, LineNo))
457 HeaderCommentStart = True
458 continue
459
460 #
461 # Collect Header content.
462 #
463 if (Line.startswith('#') and CurrentSection == MODEL_IDENTIFIER_FILE_HEADER) and\
464 HeaderCommentStart and not Line.startswith('##') and not\
465 HeaderCommentEnd and NextLine != '':
466 HeaderSectionLines.append((Line, LineNo))
467 continue
468 #
469 # Header content end
470 #
471 if (Line.startswith('##') or not Line.strip().startswith("#")) and HeaderCommentStart \
472 and not HeaderCommentEnd:
473 if Line.startswith('##'):
474 HeaderCommentEnd = True
475 HeaderSectionLines.append((Line, LineNo))
476 ParseHeaderCommentSection(HeaderSectionLines, FullName)
477 break
478 if HeaderCommentStart == False:
479 SqlStatement = """ select ID from File where FullPath like '%s'""" % FullName
480 ResultSet = EccGlobalData.gDb.TblFile.Exec(SqlStatement)
481 for Result in ResultSet:
482 Msg = 'INF/DEC/DSC/FDF file header comment should begin with ""## @file"" or ""# @file"" at the very top file'
483 EccGlobalData.gDb.TblReport.Insert(ERROR_DOXYGEN_CHECK_FILE_HEADER, Msg, "File", Result[0])
484 if HeaderCommentEnd == False:
485 SqlStatement = """ select ID from File where FullPath like '%s'""" % FullName
486 ResultSet = EccGlobalData.gDb.TblFile.Exec(SqlStatement)
487 for Result in ResultSet:
488 Msg = 'INF/DEC/DSC/FDF file header comment should end with ""##"" at the end of file header comment block'
489 # Check whether File header Comment End with '##'
490 if EccGlobalData.gConfig.HeaderCheckFileCommentEnd == '1' or EccGlobalData.gConfig.HeaderCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
491 EccGlobalData.gDb.TblReport.Insert(ERROR_DOXYGEN_CHECK_FILE_HEADER, Msg, "File", Result[0])
492
493
494
495 # Check whether the function headers are followed Doxygen special documentation blocks in section 2.3.5
496 def DoxygenCheckFunctionHeader(self):
497 if EccGlobalData.gConfig.DoxygenCheckFunctionHeader == '1' or EccGlobalData.gConfig.DoxygenCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
498 EdkLogger.quiet("Checking Doxygen function header ...")
499
500 # for Dirpath, Dirnames, Filenames in self.WalkTree():
501 # for F in Filenames:
502 # if os.path.splitext(F)[1] in ('.h', '.c'):
503 # FullName = os.path.join(Dirpath, F)
504 # MsgList = c.CheckFuncHeaderDoxygenComments(FullName)
505 for FullName in EccGlobalData.gCFileList + EccGlobalData.gHFileList:
506 MsgList = c.CheckFuncHeaderDoxygenComments(FullName)
507
508
509 # Check whether the first line of text in a comment block is a brief description of the element being documented.
510 # The brief description must end with a period.
511 def DoxygenCheckCommentDescription(self):
512 if EccGlobalData.gConfig.DoxygenCheckCommentDescription == '1' or EccGlobalData.gConfig.DoxygenCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
513 pass
514
515 # Check whether comment lines with '///< ... text ...' format, if it is used, it should be after the code section.
516 def DoxygenCheckCommentFormat(self):
517 if EccGlobalData.gConfig.DoxygenCheckCommentFormat == '1' or EccGlobalData.gConfig.DoxygenCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
518 EdkLogger.quiet("Checking Doxygen comment ///< ...")
519
520 # for Dirpath, Dirnames, Filenames in self.WalkTree():
521 # for F in Filenames:
522 # if os.path.splitext(F)[1] in ('.h', '.c'):
523 # FullName = os.path.join(Dirpath, F)
524 # MsgList = c.CheckDoxygenTripleForwardSlash(FullName)
525 for FullName in EccGlobalData.gCFileList + EccGlobalData.gHFileList:
526 MsgList = c.CheckDoxygenTripleForwardSlash(FullName)
527
528 # Check whether only Doxygen commands allowed to mark the code are @bug and @todo.
529 def DoxygenCheckCommand(self):
530 if EccGlobalData.gConfig.DoxygenCheckCommand == '1' or EccGlobalData.gConfig.DoxygenCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
531 EdkLogger.quiet("Checking Doxygen command ...")
532
533 # for Dirpath, Dirnames, Filenames in self.WalkTree():
534 # for F in Filenames:
535 # if os.path.splitext(F)[1] in ('.h', '.c'):
536 # FullName = os.path.join(Dirpath, F)
537 # MsgList = c.CheckDoxygenCommand(FullName)
538 for FullName in EccGlobalData.gCFileList + EccGlobalData.gHFileList:
539 MsgList = c.CheckDoxygenCommand(FullName)
540
541 # Meta-Data File Processing Checking
542 def MetaDataFileCheck(self):
543 self.MetaDataFileCheckPathName()
544 self.MetaDataFileCheckGenerateFileList()
545 self.MetaDataFileCheckLibraryInstance()
546 self.MetaDataFileCheckLibraryInstanceDependent()
547 self.MetaDataFileCheckLibraryInstanceOrder()
548 self.MetaDataFileCheckLibraryNoUse()
549 self.MetaDataFileCheckBinaryInfInFdf()
550 self.MetaDataFileCheckPcdDuplicate()
551 self.MetaDataFileCheckPcdFlash()
552 self.MetaDataFileCheckPcdNoUse()
553 self.MetaDataFileCheckGuidDuplicate()
554 self.MetaDataFileCheckModuleFileNoUse()
555 self.MetaDataFileCheckPcdType()
556 self.MetaDataFileCheckModuleFileGuidDuplication()
557
558 # Check whether each file defined in meta-data exists
559 def MetaDataFileCheckPathName(self):
560 if EccGlobalData.gConfig.MetaDataFileCheckPathName == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
561 # This item is covered when parsing Inf/Dec/Dsc files
562 pass
563
564 # Generate a list for all files defined in meta-data files
565 def MetaDataFileCheckGenerateFileList(self):
566 if EccGlobalData.gConfig.MetaDataFileCheckGenerateFileList == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
567 # This item is covered when parsing Inf/Dec/Dsc files
568 pass
569
570 # Check whether all Library Instances defined for a given module (or dependent library instance) match the module's type.
571 # Each Library Instance must specify the Supported Module Types in its Inf file,
572 # and any module specifying the library instance must be one of the supported types.
573 def MetaDataFileCheckLibraryInstance(self):
574 if EccGlobalData.gConfig.MetaDataFileCheckLibraryInstance == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
575 EdkLogger.quiet("Checking for library instance type issue ...")
576 SqlCommand = """select A.ID, A.Value3, B.Value3 from Inf as A left join Inf as B
577 where A.Value2 = 'LIBRARY_CLASS' and A.Model = %s
578 and B.Value2 = 'MODULE_TYPE' and B.Model = %s and A.BelongsToFile = B.BelongsToFile
579 group by A.BelongsToFile""" % (MODEL_META_DATA_HEADER, MODEL_META_DATA_HEADER)
580 RecordSet = EccGlobalData.gDb.TblInf.Exec(SqlCommand)
581 LibraryClasses = {}
582 for Record in RecordSet:
583 List = Record[1].split('|', 1)
584 SupModType = []
585 if len(List) == 1:
586 SupModType = SUP_MODULE_LIST_STRING.split(TAB_VALUE_SPLIT)
587 elif len(List) == 2:
588 SupModType = List[1].split()
589
590 if List[0] not in LibraryClasses:
591 LibraryClasses[List[0]] = SupModType
592 else:
593 for Item in SupModType:
594 if Item not in LibraryClasses[List[0]]:
595 LibraryClasses[List[0]].append(Item)
596
597 if Record[2] != 'BASE' and Record[2] not in SupModType:
598 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_LIBRARY_INSTANCE_2, OtherMsg="The Library Class '%s' does not specify its supported module types" % (List[0]), BelongsToTable='Inf', BelongsToItem=Record[0])
599
600 SqlCommand = """select A.ID, A.Value1, B.Value3 from Inf as A left join Inf as B
601 where A.Model = %s and B.Value2 = '%s' and B.Model = %s
602 and B.BelongsToFile = A.BelongsToFile""" \
603 % (MODEL_EFI_LIBRARY_CLASS, 'MODULE_TYPE', MODEL_META_DATA_HEADER)
604 RecordSet = EccGlobalData.gDb.TblInf.Exec(SqlCommand)
605 # Merge all LibraryClasses' supmodlist
606 RecordDict = {}
607 for Record in RecordSet:
608 if Record[1] not in RecordDict:
609 RecordDict[Record[1]] = [str(Record[2])]
610 else:
611 if Record[2] not in RecordDict[Record[1]]:
612 RecordDict[Record[1]].append(Record[2])
613
614 for Record in RecordSet:
615 if Record[1] in LibraryClasses:
616 if Record[2] not in LibraryClasses[Record[1]] and 'BASE' not in RecordDict[Record[1]]:
617 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_LIBRARY_INSTANCE_1, Record[1]):
618 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_LIBRARY_INSTANCE_1, OtherMsg="The type of Library Class [%s] defined in Inf file does not match the type of the module" % (Record[1]), BelongsToTable='Inf', BelongsToItem=Record[0])
619 else:
620 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_LIBRARY_INSTANCE_1, Record[1]):
621 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_LIBRARY_INSTANCE_1, OtherMsg="The type of Library Class [%s] defined in Inf file does not match the type of the module" % (Record[1]), BelongsToTable='Inf', BelongsToItem=Record[0])
622
623 # Check whether a Library Instance has been defined for all dependent library classes
624 def MetaDataFileCheckLibraryInstanceDependent(self):
625 if EccGlobalData.gConfig.MetaDataFileCheckLibraryInstanceDependent == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
626 EdkLogger.quiet("Checking for library instance dependent issue ...")
627 SqlCommand = """select ID, Value1, Value2 from Dsc where Model = %s""" % MODEL_EFI_LIBRARY_CLASS
628 LibraryClasses = EccGlobalData.gDb.TblDsc.Exec(SqlCommand)
629 for LibraryClass in LibraryClasses:
630 if LibraryClass[1].upper() == 'NULL' or LibraryClass[1].startswith('!ifdef') or LibraryClass[1].startswith('!ifndef') or LibraryClass[1].endswith('!endif'):
631 continue
632 else:
633 LibraryIns = os.path.normpath(os.path.join(EccGlobalData.gWorkspace, LibraryClass[2]))
634 SqlCommand = """select Value3 from Inf where BelongsToFile =
635 (select ID from File where lower(FullPath) = lower('%s'))
636 and Value2 = '%s'""" % (LibraryIns, 'LIBRARY_CLASS')
637 RecordSet = EccGlobalData.gDb.TblInf.Exec(SqlCommand)
638 IsFound = False
639 for Record in RecordSet:
640 LibName = Record[0].split('|', 1)[0]
641 if LibraryClass[1] == LibName:
642 IsFound = True
643 if not IsFound:
644 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_LIBRARY_INSTANCE_DEPENDENT, LibraryClass[1]):
645 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_LIBRARY_INSTANCE_DEPENDENT, OtherMsg="The Library Class [%s] is not specified in '%s'" % (LibraryClass[1], LibraryClass[2]), BelongsToTable='Dsc', BelongsToItem=LibraryClass[0])
646
647 # Check whether the Library Instances specified by the LibraryClasses sections are listed in order of dependencies
648 def MetaDataFileCheckLibraryInstanceOrder(self):
649 if EccGlobalData.gConfig.MetaDataFileCheckLibraryInstanceOrder == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
650 # This checkpoint is not necessary for Ecc check
651 pass
652
653 # Check whether the unnecessary inclusion of library classes in the Inf file
654 # Check whether the unnecessary duplication of library classe names in the DSC file
655 def MetaDataFileCheckLibraryNoUse(self):
656 if EccGlobalData.gConfig.MetaDataFileCheckLibraryNoUse == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
657 EdkLogger.quiet("Checking for library instance not used ...")
658 SqlCommand = """select ID, Value1 from Inf as A where A.Model = %s and A.Value1 not in (select B.Value1 from Dsc as B where Model = %s)""" % (MODEL_EFI_LIBRARY_CLASS, MODEL_EFI_LIBRARY_CLASS)
659 RecordSet = EccGlobalData.gDb.TblInf.Exec(SqlCommand)
660 for Record in RecordSet:
661 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_LIBRARY_NO_USE, Record[1]):
662 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_LIBRARY_NO_USE, OtherMsg="The Library Class [%s] is not used in any platform" % (Record[1]), BelongsToTable='Inf', BelongsToItem=Record[0])
663 SqlCommand = """
664 select A.ID, A.Value1, A.BelongsToFile, A.StartLine, B.StartLine from Dsc as A left join Dsc as B
665 where A.Model = %s and B.Model = %s and A.Scope1 = B.Scope1 and A.Scope2 = B.Scope2 and A.ID <> B.ID
666 and A.Value1 = B.Value1 and A.Value2 <> B.Value2 and A.BelongsToItem = -1 and B.BelongsToItem = -1 and A.StartLine <> B.StartLine and B.BelongsToFile = A.BelongsToFile""" \
667 % (MODEL_EFI_LIBRARY_CLASS, MODEL_EFI_LIBRARY_CLASS)
668 RecordSet = EccGlobalData.gDb.TblDsc.Exec(SqlCommand)
669 for Record in RecordSet:
670 if Record[3] and Record[4] and Record[3] != Record[4]:
671 SqlCommand = """select FullPath from File where ID = %s""" % (Record[2])
672 FilePathList = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
673 for FilePath in FilePathList:
674 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_LIBRARY_NAME_DUPLICATE, Record[1]):
675 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_LIBRARY_NAME_DUPLICATE, OtherMsg="The Library Class [%s] is duplicated in '%s' line %s and line %s." % (Record[1], FilePath, Record[3], Record[4]), BelongsToTable='Dsc', BelongsToItem=Record[0])
676
677 # Check whether an Inf file is specified in the FDF file, but not in the Dsc file, then the Inf file must be for a Binary module only
678 def MetaDataFileCheckBinaryInfInFdf(self):
679 if EccGlobalData.gConfig.MetaDataFileCheckBinaryInfInFdf == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
680 EdkLogger.quiet("Checking for non-binary modules defined in FDF files ...")
681 SqlCommand = """select A.ID, A.Value1 from Fdf as A
682 where A.Model = %s
683 and A.Enabled > -1
684 and A.Value1 not in
685 (select B.Value1 from Dsc as B
686 where B.Model = %s
687 and B.Enabled > -1)""" % (MODEL_META_DATA_COMPONENT, MODEL_META_DATA_COMPONENT)
688 RecordSet = EccGlobalData.gDb.TblFdf.Exec(SqlCommand)
689 for Record in RecordSet:
690 FdfID = Record[0]
691 FilePath = Record[1]
692 FilePath = os.path.normpath(os.path.join(EccGlobalData.gWorkspace, FilePath))
693 SqlCommand = """select ID from Inf where Model = %s and BelongsToFile = (select ID from File where FullPath like '%s')
694 """ % (MODEL_EFI_SOURCE_FILE, FilePath)
695 NewRecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
696 if NewRecordSet != []:
697 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_BINARY_INF_IN_FDF, FilePath):
698 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_BINARY_INF_IN_FDF, OtherMsg="File [%s] defined in FDF file and not in DSC file must be a binary module" % (FilePath), BelongsToTable='Fdf', BelongsToItem=FdfID)
699
700 # Check whether a PCD is set in a Dsc file or the FDF file, but not in both.
701 def MetaDataFileCheckPcdDuplicate(self):
702 if EccGlobalData.gConfig.MetaDataFileCheckPcdDuplicate == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
703 EdkLogger.quiet("Checking for duplicate PCDs defined in both DSC and FDF files ...")
704 SqlCommand = """
705 select A.ID, A.Value1, A.Value2, A.BelongsToFile, B.ID, B.Value1, B.Value2, B.BelongsToFile from Dsc as A, Fdf as B
706 where A.Model >= %s and A.Model < %s
707 and B.Model >= %s and B.Model < %s
708 and A.Value1 = B.Value1
709 and A.Value2 = B.Value2
710 and A.Enabled > -1
711 and B.Enabled > -1
712 group by A.ID
713 """ % (MODEL_PCD, MODEL_META_DATA_HEADER, MODEL_PCD, MODEL_META_DATA_HEADER)
714 RecordSet = EccGlobalData.gDb.TblDsc.Exec(SqlCommand)
715 for Record in RecordSet:
716 SqlCommand1 = """select Name from File where ID = %s""" % Record[3]
717 SqlCommand2 = """select Name from File where ID = %s""" % Record[7]
718 DscFileName = os.path.splitext(EccGlobalData.gDb.TblDsc.Exec(SqlCommand1)[0][0])[0]
719 FdfFileName = os.path.splitext(EccGlobalData.gDb.TblDsc.Exec(SqlCommand2)[0][0])[0]
720 if DscFileName != FdfFileName:
721 continue
722 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_PCD_DUPLICATE, Record[1] + '.' + Record[2]):
723 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_PCD_DUPLICATE, OtherMsg="The PCD [%s] is defined in both FDF file and DSC file" % (Record[1] + '.' + Record[2]), BelongsToTable='Dsc', BelongsToItem=Record[0])
724 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_PCD_DUPLICATE, Record[5] + '.' + Record[6]):
725 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_PCD_DUPLICATE, OtherMsg="The PCD [%s] is defined in both FDF file and DSC file" % (Record[5] + '.' + Record[6]), BelongsToTable='Fdf', BelongsToItem=Record[4])
726
727 EdkLogger.quiet("Checking for duplicate PCDs defined in DEC files ...")
728 SqlCommand = """
729 select A.ID, A.Value1, A.Value2, A.Model, B.Model from Dec as A left join Dec as B
730 where A.Model >= %s and A.Model < %s
731 and B.Model >= %s and B.Model < %s
732 and A.Value1 = B.Value1
733 and A.Value2 = B.Value2
734 and A.Scope1 = B.Scope1
735 and A.ID <> B.ID
736 and A.Model = B.Model
737 and A.Enabled > -1
738 and B.Enabled > -1
739 and A.BelongsToFile = B.BelongsToFile
740 group by A.ID
741 """ % (MODEL_PCD, MODEL_META_DATA_HEADER, MODEL_PCD, MODEL_META_DATA_HEADER)
742 RecordSet = EccGlobalData.gDb.TblDec.Exec(SqlCommand)
743 for Record in RecordSet:
744 RecordCat = Record[1] + '.' + Record[2]
745 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_PCD_DUPLICATE, RecordCat):
746 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_PCD_DUPLICATE, OtherMsg="The PCD [%s] is defined duplicated in DEC file" % RecordCat, BelongsToTable='Dec', BelongsToItem=Record[0])
747
748 # Check whether PCD settings in the FDF file can only be related to flash.
749 def MetaDataFileCheckPcdFlash(self):
750 if EccGlobalData.gConfig.MetaDataFileCheckPcdFlash == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
751 EdkLogger.quiet("Checking only Flash related PCDs are used in FDF ...")
752 SqlCommand = """
753 select ID, Value1, Value2, BelongsToFile from Fdf as A
754 where A.Model >= %s and Model < %s
755 and A.Enabled > -1
756 and A.Value2 not like '%%Flash%%'
757 """ % (MODEL_PCD, MODEL_META_DATA_HEADER)
758 RecordSet = EccGlobalData.gDb.TblFdf.Exec(SqlCommand)
759 for Record in RecordSet:
760 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_PCD_FLASH, Record[1] + '.' + Record[2]):
761 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_PCD_FLASH, OtherMsg="The PCD [%s] defined in FDF file is not related to Flash" % (Record[1] + '.' + Record[2]), BelongsToTable='Fdf', BelongsToItem=Record[0])
762
763 # Check whether PCDs used in Inf files but not specified in Dsc or FDF files
764 def MetaDataFileCheckPcdNoUse(self):
765 if EccGlobalData.gConfig.MetaDataFileCheckPcdNoUse == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
766 EdkLogger.quiet("Checking for non-specified PCDs ...")
767 SqlCommand = """
768 select ID, Value1, Value2, BelongsToFile from Inf as A
769 where A.Model >= %s and Model < %s
770 and A.Enabled > -1
771 and (A.Value1, A.Value2) not in
772 (select Value1, Value2 from Dsc as B
773 where B.Model >= %s and B.Model < %s
774 and B.Enabled > -1)
775 and (A.Value1, A.Value2) not in
776 (select Value1, Value2 from Fdf as C
777 where C.Model >= %s and C.Model < %s
778 and C.Enabled > -1)
779 """ % (MODEL_PCD, MODEL_META_DATA_HEADER, MODEL_PCD, MODEL_META_DATA_HEADER, MODEL_PCD, MODEL_META_DATA_HEADER)
780 RecordSet = EccGlobalData.gDb.TblInf.Exec(SqlCommand)
781 for Record in RecordSet:
782 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_PCD_NO_USE, Record[1] + '.' + Record[2]):
783 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_PCD_NO_USE, OtherMsg="The PCD [%s] defined in INF file is not specified in either DSC or FDF files" % (Record[1] + '.' + Record[2]), BelongsToTable='Inf', BelongsToItem=Record[0])
784
785 # Check whether having duplicate guids defined for Guid/Protocol/Ppi
786 def MetaDataFileCheckGuidDuplicate(self):
787 if EccGlobalData.gConfig.MetaDataFileCheckGuidDuplicate == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
788 EdkLogger.quiet("Checking for duplicate GUID/PPI/PROTOCOL ...")
789 # Check Guid
790 self.CheckGuidProtocolPpi(ERROR_META_DATA_FILE_CHECK_DUPLICATE_GUID, MODEL_EFI_GUID, EccGlobalData.gDb.TblDec)
791 self.CheckGuidProtocolPpi(ERROR_META_DATA_FILE_CHECK_DUPLICATE_GUID, MODEL_EFI_GUID, EccGlobalData.gDb.TblDsc)
792 self.CheckGuidProtocolPpiValue(ERROR_META_DATA_FILE_CHECK_DUPLICATE_GUID, MODEL_EFI_GUID)
793 # Check protocol
794 self.CheckGuidProtocolPpi(ERROR_META_DATA_FILE_CHECK_DUPLICATE_PROTOCOL, MODEL_EFI_PROTOCOL, EccGlobalData.gDb.TblDec)
795 self.CheckGuidProtocolPpi(ERROR_META_DATA_FILE_CHECK_DUPLICATE_PROTOCOL, MODEL_EFI_PROTOCOL, EccGlobalData.gDb.TblDsc)
796 self.CheckGuidProtocolPpiValue(ERROR_META_DATA_FILE_CHECK_DUPLICATE_PROTOCOL, MODEL_EFI_PROTOCOL)
797 # Check ppi
798 self.CheckGuidProtocolPpi(ERROR_META_DATA_FILE_CHECK_DUPLICATE_PPI, MODEL_EFI_PPI, EccGlobalData.gDb.TblDec)
799 self.CheckGuidProtocolPpi(ERROR_META_DATA_FILE_CHECK_DUPLICATE_PPI, MODEL_EFI_PPI, EccGlobalData.gDb.TblDsc)
800 self.CheckGuidProtocolPpiValue(ERROR_META_DATA_FILE_CHECK_DUPLICATE_PPI, MODEL_EFI_PPI)
801
802 # Check whether all files under module directory are described in INF files
803 def MetaDataFileCheckModuleFileNoUse(self):
804 if EccGlobalData.gConfig.MetaDataFileCheckModuleFileNoUse == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
805 EdkLogger.quiet("Checking for no used module files ...")
806 SqlCommand = """
807 select upper(Path) from File where ID in (select BelongsToFile from Inf where BelongsToFile != -1)
808 """
809 InfPathSet = EccGlobalData.gDb.TblInf.Exec(SqlCommand)
810 InfPathList = []
811 for Item in InfPathSet:
812 if Item[0] not in InfPathList:
813 InfPathList.append(Item[0])
814 SqlCommand = """
815 select ID, Path, FullPath from File where upper(FullPath) not in
816 (select upper(A.Path) || '\\' || upper(B.Value1) from File as A, INF as B
817 where A.ID in (select BelongsToFile from INF where Model = %s group by BelongsToFile) and
818 B.BelongsToFile = A.ID and B.Model = %s)
819 and (Model = %s or Model = %s)
820 """ % (MODEL_EFI_SOURCE_FILE, MODEL_EFI_SOURCE_FILE, MODEL_FILE_C, MODEL_FILE_H)
821 RecordSet = EccGlobalData.gDb.TblInf.Exec(SqlCommand)
822 for Record in RecordSet:
823 Path = Record[1]
824 Path = Path.upper().replace('\X64', '').replace('\IA32', '').replace('\EBC', '').replace('\IPF', '').replace('\ARM', '').replace('\AARCH64', '')
825 if Path in InfPathList:
826 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_MODULE_FILE_NO_USE, Record[2]):
827 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_MODULE_FILE_NO_USE, OtherMsg="The source file [%s] is existing in module directory but it is not described in INF file." % (Record[2]), BelongsToTable='File', BelongsToItem=Record[0])
828
829 # Check whether the PCD is correctly used in C function via its type
830 def MetaDataFileCheckPcdType(self):
831 if EccGlobalData.gConfig.MetaDataFileCheckPcdType == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
832 EdkLogger.quiet("Checking for pcd type in c code function usage ...")
833 SqlCommand = """
834 select ID, Model, Value1, Value2, BelongsToFile from INF where Model > %s and Model < %s
835 """ % (MODEL_PCD, MODEL_META_DATA_HEADER)
836 PcdSet = EccGlobalData.gDb.TblInf.Exec(SqlCommand)
837 for Pcd in PcdSet:
838 Model = Pcd[1]
839 PcdName = Pcd[2]
840 if Pcd[3]:
841 PcdName = Pcd[3]
842 BelongsToFile = Pcd[4]
843 SqlCommand = """
844 select ID from File where FullPath in
845 (select B.Path || '\\' || A.Value1 from INF as A, File as B where A.Model = %s and A.BelongsToFile = %s
846 and B.ID = %s and (B.Model = %s or B.Model = %s))
847 """ % (MODEL_EFI_SOURCE_FILE, BelongsToFile, BelongsToFile, MODEL_FILE_C, MODEL_FILE_H)
848 TableSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
849 for Tbl in TableSet:
850 TblName = 'Identifier' + str(Tbl[0])
851 SqlCommand = """
852 select Name, ID from %s where value like '%s' and Model = %s
853 """ % (TblName, PcdName, MODEL_IDENTIFIER_FUNCTION_CALLING)
854 RecordSet = EccGlobalData.gDb.TblInf.Exec(SqlCommand)
855 TblNumber = TblName.replace('Identifier', '')
856 for Record in RecordSet:
857 FunName = Record[0]
858 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_PCD_TYPE, FunName):
859 if Model in [MODEL_PCD_FIXED_AT_BUILD] and not FunName.startswith('FixedPcdGet'):
860 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_PCD_TYPE, OtherMsg="The pcd '%s' is defined as a FixPcd but now it is called by c function [%s]" % (PcdName, FunName), BelongsToTable=TblName, BelongsToItem=Record[1])
861 if Model in [MODEL_PCD_FEATURE_FLAG] and (not FunName.startswith('FeaturePcdGet') and not FunName.startswith('FeaturePcdSet')):
862 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_PCD_TYPE, OtherMsg="The pcd '%s' is defined as a FeaturePcd but now it is called by c function [%s]" % (PcdName, FunName), BelongsToTable=TblName, BelongsToItem=Record[1])
863 if Model in [MODEL_PCD_PATCHABLE_IN_MODULE] and (not FunName.startswith('PatchablePcdGet') and not FunName.startswith('PatchablePcdSet')):
864 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_PCD_TYPE, OtherMsg="The pcd '%s' is defined as a PatchablePcd but now it is called by c function [%s]" % (PcdName, FunName), BelongsToTable=TblName, BelongsToItem=Record[1])
865
866 #ERROR_META_DATA_FILE_CHECK_PCD_TYPE
867 pass
868
869 # Internal worker function to get the INF workspace relative path from FileID
870 def GetInfFilePathFromID(self, FileID):
871 Table = EccGlobalData.gDb.TblFile
872 SqlCommand = """select A.FullPath from %s as A where A.ID = %s""" % (Table.Table, FileID)
873 RecordSet = Table.Exec(SqlCommand)
874 Path = ""
875 for Record in RecordSet:
876 Path = Record[0].replace(EccGlobalData.gWorkspace, '')
877 if Path.startswith('\\') or Path.startswith('/'):
878 Path = Path[1:]
879 return Path
880
881 # Check whether two module INFs under one workspace has the same FILE_GUID value
882 def MetaDataFileCheckModuleFileGuidDuplication(self):
883 if EccGlobalData.gConfig.MetaDataFileCheckModuleFileGuidDuplication == '1' or EccGlobalData.gConfig.MetaDataFileCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
884 EdkLogger.quiet("Checking for pcd type in c code function usage ...")
885 Table = EccGlobalData.gDb.TblInf
886 SqlCommand = """
887 select A.ID, A.Value3, A.BelongsToFile, B.BelongsToFile from %s as A, %s as B
888 where A.Value2 = 'FILE_GUID' and B.Value2 = 'FILE_GUID' and
889 A.Value3 = B.Value3 and A.ID <> B.ID group by A.ID
890 """ % (Table.Table, Table.Table)
891 RecordSet = Table.Exec(SqlCommand)
892 for Record in RecordSet:
893 InfPath1 = self.GetInfFilePathFromID(Record[2])
894 InfPath2 = self.GetInfFilePathFromID(Record[3])
895 if InfPath1 and InfPath2:
896 if not EccGlobalData.gException.IsException(ERROR_META_DATA_FILE_CHECK_MODULE_FILE_GUID_DUPLICATION, InfPath1):
897 Msg = "The FILE_GUID of INF file [%s] is duplicated with that of %s" % (InfPath1, InfPath2)
898 EccGlobalData.gDb.TblReport.Insert(ERROR_META_DATA_FILE_CHECK_MODULE_FILE_GUID_DUPLICATION, OtherMsg=Msg, BelongsToTable=Table.Table, BelongsToItem=Record[0])
899
900
901 # Check whether these is duplicate Guid/Ppi/Protocol name
902 def CheckGuidProtocolPpi(self, ErrorID, Model, Table):
903 Name = ''
904 if Model == MODEL_EFI_GUID:
905 Name = 'guid'
906 if Model == MODEL_EFI_PROTOCOL:
907 Name = 'protocol'
908 if Model == MODEL_EFI_PPI:
909 Name = 'ppi'
910 SqlCommand = """
911 select A.ID, A.Value1 from %s as A, %s as B
912 where A.Model = %s and B.Model = %s
913 and A.Value1 = B.Value1 and A.ID <> B.ID
914 and A.Scope1 = B.Scope1
915 and A.Enabled > -1
916 and B.Enabled > -1
917 group by A.ID
918 """ % (Table.Table, Table.Table, Model, Model)
919 RecordSet = Table.Exec(SqlCommand)
920 for Record in RecordSet:
921 if not EccGlobalData.gException.IsException(ErrorID, Record[1]):
922 EccGlobalData.gDb.TblReport.Insert(ErrorID, OtherMsg="The %s name [%s] is defined more than one time" % (Name.upper(), Record[1]), BelongsToTable=Table.Table, BelongsToItem=Record[0])
923
924 # Check whether these is duplicate Guid/Ppi/Protocol value
925 def CheckGuidProtocolPpiValue(self, ErrorID, Model):
926 Name = ''
927 Table = EccGlobalData.gDb.TblDec
928 if Model == MODEL_EFI_GUID:
929 Name = 'guid'
930 if Model == MODEL_EFI_PROTOCOL:
931 Name = 'protocol'
932 if Model == MODEL_EFI_PPI:
933 Name = 'ppi'
934 SqlCommand = """
935 select A.ID, A.Value1, A.Value2 from %s as A, %s as B
936 where A.Model = %s and B.Model = %s
937 and A.Value2 = B.Value2 and A.ID <> B.ID
938 and A.Scope1 = B.Scope1 and A.Value1 <> B.Value1
939 group by A.ID
940 """ % (Table.Table, Table.Table, Model, Model)
941 RecordSet = Table.Exec(SqlCommand)
942 for Record in RecordSet:
943 if not EccGlobalData.gException.IsException(ErrorID, Record[1] + ':' + Record[2]):
944 EccGlobalData.gDb.TblReport.Insert(ErrorID, OtherMsg="The %s value [%s] is used more than one time" % (Name.upper(), Record[2]), BelongsToTable=Table.Table, BelongsToItem=Record[0])
945
946 # Naming Convention Check
947 def NamingConventionCheck(self):
948 if EccGlobalData.gConfig.NamingConventionCheckDefineStatement == '1' \
949 or EccGlobalData.gConfig.NamingConventionCheckTypedefStatement == '1' \
950 or EccGlobalData.gConfig.NamingConventionCheckIfndefStatement == '1' \
951 or EccGlobalData.gConfig.NamingConventionCheckVariableName == '1' \
952 or EccGlobalData.gConfig.NamingConventionCheckSingleCharacterVariable == '1' \
953 or EccGlobalData.gConfig.NamingConventionCheckAll == '1'\
954 or EccGlobalData.gConfig.CheckAll == '1':
955 for Dirpath, Dirnames, Filenames in self.WalkTree():
956 for F in Filenames:
957 if os.path.splitext(F)[1] in ('.h', '.c'):
958 FullName = os.path.join(Dirpath, F)
959 Id = c.GetTableID(FullName)
960 if Id < 0:
961 continue
962 FileTable = 'Identifier' + str(Id)
963 self.NamingConventionCheckDefineStatement(FileTable)
964 self.NamingConventionCheckTypedefStatement(FileTable)
965 self.NamingConventionCheckIfndefStatement(FileTable)
966 self.NamingConventionCheckVariableName(FileTable)
967 self.NamingConventionCheckSingleCharacterVariable(FileTable)
968
969 self.NamingConventionCheckPathName()
970 self.NamingConventionCheckFunctionName()
971
972 # Check whether only capital letters are used for #define declarations
973 def NamingConventionCheckDefineStatement(self, FileTable):
974 if EccGlobalData.gConfig.NamingConventionCheckDefineStatement == '1' or EccGlobalData.gConfig.NamingConventionCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
975 EdkLogger.quiet("Checking naming covention of #define statement ...")
976
977 SqlCommand = """select ID, Value from %s where Model = %s""" % (FileTable, MODEL_IDENTIFIER_MACRO_DEFINE)
978 RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
979 for Record in RecordSet:
980 Name = Record[1].strip().split()[1]
981 if Name.find('(') != -1:
982 Name = Name[0:Name.find('(')]
983 if Name.upper() != Name:
984 if not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_DEFINE_STATEMENT, Name):
985 EccGlobalData.gDb.TblReport.Insert(ERROR_NAMING_CONVENTION_CHECK_DEFINE_STATEMENT, OtherMsg="The #define name [%s] does not follow the rules" % (Name), BelongsToTable=FileTable, BelongsToItem=Record[0])
986
987 # Check whether only capital letters are used for typedef declarations
988 def NamingConventionCheckTypedefStatement(self, FileTable):
989 if EccGlobalData.gConfig.NamingConventionCheckTypedefStatement == '1' or EccGlobalData.gConfig.NamingConventionCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
990 EdkLogger.quiet("Checking naming covention of #typedef statement ...")
991
992 SqlCommand = """select ID, Name from %s where Model = %s""" % (FileTable, MODEL_IDENTIFIER_TYPEDEF)
993 RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
994 for Record in RecordSet:
995 Name = Record[1].strip()
996 if Name != '' and Name != None:
997 if Name[0] == '(':
998 Name = Name[1:Name.find(')')]
999 if Name.find('(') > -1:
1000 Name = Name[Name.find('(') + 1 : Name.find(')')]
1001 Name = Name.replace('WINAPI', '')
1002 Name = Name.replace('*', '').strip()
1003 if Name.upper() != Name:
1004 if not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_TYPEDEF_STATEMENT, Name):
1005 EccGlobalData.gDb.TblReport.Insert(ERROR_NAMING_CONVENTION_CHECK_TYPEDEF_STATEMENT, OtherMsg="The #typedef name [%s] does not follow the rules" % (Name), BelongsToTable=FileTable, BelongsToItem=Record[0])
1006
1007 # Check whether the #ifndef at the start of an include file uses both prefix and postfix underscore characters, '_'.
1008 def NamingConventionCheckIfndefStatement(self, FileTable):
1009 if EccGlobalData.gConfig.NamingConventionCheckTypedefStatement == '1' or EccGlobalData.gConfig.NamingConventionCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
1010 EdkLogger.quiet("Checking naming covention of #ifndef statement ...")
1011
1012 SqlCommand = """select ID, Value from %s where Model = %s""" % (FileTable, MODEL_IDENTIFIER_MACRO_IFNDEF)
1013 RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
1014 for Record in RecordSet:
1015 Name = Record[1].replace('#ifndef', '').strip()
1016 if Name[0] != '_' or Name[-1] != '_':
1017 if not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_IFNDEF_STATEMENT, Name):
1018 EccGlobalData.gDb.TblReport.Insert(ERROR_NAMING_CONVENTION_CHECK_IFNDEF_STATEMENT, OtherMsg="The #ifndef name [%s] does not follow the rules" % (Name), BelongsToTable=FileTable, BelongsToItem=Record[0])
1019
1020 # Rule for path name, variable name and function name
1021 # 1. First character should be upper case
1022 # 2. Existing lower case in a word
1023 # 3. No space existence
1024 # Check whether the path name followed the rule
1025 def NamingConventionCheckPathName(self):
1026 if EccGlobalData.gConfig.NamingConventionCheckPathName == '1' or EccGlobalData.gConfig.NamingConventionCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
1027 EdkLogger.quiet("Checking naming covention of file path name ...")
1028 Pattern = re.compile(r'^[A-Z]+\S*[a-z]\S*$')
1029 SqlCommand = """select ID, Name from File"""
1030 RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
1031 for Record in RecordSet:
1032 if not Pattern.match(Record[1]):
1033 if not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_PATH_NAME, Record[1]):
1034 EccGlobalData.gDb.TblReport.Insert(ERROR_NAMING_CONVENTION_CHECK_PATH_NAME, OtherMsg="The file path [%s] does not follow the rules" % (Record[1]), BelongsToTable='File', BelongsToItem=Record[0])
1035
1036 # Rule for path name, variable name and function name
1037 # 1. First character should be upper case
1038 # 2. Existing lower case in a word
1039 # 3. No space existence
1040 # 4. Global variable name must start with a 'g'
1041 # Check whether the variable name followed the rule
1042 def NamingConventionCheckVariableName(self, FileTable):
1043 if EccGlobalData.gConfig.NamingConventionCheckVariableName == '1' or EccGlobalData.gConfig.NamingConventionCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
1044 EdkLogger.quiet("Checking naming covention of variable name ...")
1045 Pattern = re.compile(r'^[A-Zgm]+\S*[a-z]\S*$')
1046
1047 SqlCommand = """select ID, Name from %s where Model = %s""" % (FileTable, MODEL_IDENTIFIER_VARIABLE)
1048 RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
1049 for Record in RecordSet:
1050 if not Pattern.match(Record[1]):
1051 if not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Record[1]):
1052 EccGlobalData.gDb.TblReport.Insert(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, OtherMsg="The variable name [%s] does not follow the rules" % (Record[1]), BelongsToTable=FileTable, BelongsToItem=Record[0])
1053
1054 # Rule for path name, variable name and function name
1055 # 1. First character should be upper case
1056 # 2. Existing lower case in a word
1057 # 3. No space existence
1058 # Check whether the function name followed the rule
1059 def NamingConventionCheckFunctionName(self):
1060 if EccGlobalData.gConfig.NamingConventionCheckFunctionName == '1' or EccGlobalData.gConfig.NamingConventionCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
1061 EdkLogger.quiet("Checking naming covention of function name ...")
1062 Pattern = re.compile(r'^[A-Z]+\S*[a-z]\S*$')
1063 SqlCommand = """select ID, Name from Function"""
1064 RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
1065 for Record in RecordSet:
1066 if not Pattern.match(Record[1]):
1067 if not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_FUNCTION_NAME, Record[1]):
1068 EccGlobalData.gDb.TblReport.Insert(ERROR_NAMING_CONVENTION_CHECK_FUNCTION_NAME, OtherMsg="The function name [%s] does not follow the rules" % (Record[1]), BelongsToTable='Function', BelongsToItem=Record[0])
1069
1070 # Check whether NO use short variable name with single character
1071 def NamingConventionCheckSingleCharacterVariable(self, FileTable):
1072 if EccGlobalData.gConfig.NamingConventionCheckSingleCharacterVariable == '1' or EccGlobalData.gConfig.NamingConventionCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
1073 EdkLogger.quiet("Checking naming covention of single character variable name ...")
1074
1075 SqlCommand = """select ID, Name from %s where Model = %s""" % (FileTable, MODEL_IDENTIFIER_VARIABLE)
1076 RecordSet = EccGlobalData.gDb.TblFile.Exec(SqlCommand)
1077 for Record in RecordSet:
1078 Variable = Record[1].replace('*', '')
1079 if len(Variable) == 1:
1080 if not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_SINGLE_CHARACTER_VARIABLE, Record[1]):
1081 EccGlobalData.gDb.TblReport.Insert(ERROR_NAMING_CONVENTION_CHECK_SINGLE_CHARACTER_VARIABLE, OtherMsg="The variable name [%s] does not follow the rules" % (Record[1]), BelongsToTable=FileTable, BelongsToItem=Record[0])
1082
1083 ##
1084 #
1085 # This acts like the main() function for the script, unless it is 'import'ed into another
1086 # script.
1087 #
1088 if __name__ == '__main__':
1089 Check = Check()
1090 Check.Check()