2009-07-17 11:10:31 +02:00
## @file
# This file is used to define checkpoints used by ECC tool
#
2010-05-18 07:04:32 +02:00
# Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
2009-07-17 11:10:31 +02:00
# 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 os
import re
from CommonDataClass . DataClass import *
from Common . DataType import SUP_MODULE_LIST_STRING , TAB_VALUE_SPLIT
from EccToolError import *
import EccGlobalData
import c
## Check
#
# This class is to define checkpoints used by ECC tool
#
# @param object: Inherited from object class
#
class Check ( object ) :
def __init__ ( self ) :
pass
# Check all required checkpoints
def Check ( self ) :
2010-09-06 03:58:00 +02:00
self . GeneralCheck ( )
2009-07-17 11:10:31 +02:00
self . MetaDataFileCheck ( )
self . DoxygenCheck ( )
self . IncludeFileCheck ( )
self . PredicateExpressionCheck ( )
self . DeclAndDataTypeCheck ( )
self . FunctionLayoutCheck ( )
self . NamingConventionCheck ( )
2010-09-06 03:58:00 +02:00
# General Checking
def GeneralCheck ( self ) :
self . GeneralCheckNonAcsii ( )
# Check whether file has non ACSII char
def GeneralCheckNonAcsii ( self ) :
if EccGlobalData . gConfig . GeneralCheckNonAcsii == ' 1 ' or EccGlobalData . gConfig . GeneralCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking Non-ACSII char in file ... " )
SqlCommand = """ select ID, FullPath, ExtName from File """
RecordSet = EccGlobalData . gDb . TblInf . Exec ( SqlCommand )
for Record in RecordSet :
if Record [ 2 ] . upper ( ) not in EccGlobalData . gConfig . BinaryExtList :
op = open ( Record [ 1 ] ) . readlines ( )
IndexOfLine = 0
for Line in op :
IndexOfLine + = 1
IndexOfChar = 0
for Char in Line :
IndexOfChar + = 1
if ord ( Char ) > 126 :
OtherMsg = " File %s has Non-ASCII char at line %s column %s " % ( Record [ 1 ] , IndexOfLine , IndexOfChar )
EccGlobalData . gDb . TblReport . Insert ( ERROR_GENERAL_CHECK_NON_ACSII , OtherMsg = OtherMsg , BelongsToTable = ' File ' , BelongsToItem = Record [ 0 ] )
2009-07-17 11:10:31 +02:00
# C Function Layout Checking
def FunctionLayoutCheck ( self ) :
self . FunctionLayoutCheckReturnType ( )
self . FunctionLayoutCheckModifier ( )
self . FunctionLayoutCheckName ( )
self . FunctionLayoutCheckPrototype ( )
self . FunctionLayoutCheckBody ( )
self . FunctionLayoutCheckLocalVariable ( )
def WalkTree ( self ) :
IgnoredPattern = c . GetIgnoredDirListPattern ( )
for Dirpath , Dirnames , Filenames in os . walk ( EccGlobalData . gTarget ) :
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 )
if IgnoredPattern . match ( Dirpath . upper ( ) ) :
continue
yield ( Dirpath , Dirnames , Filenames )
# Check whether return type exists and in the first line
def FunctionLayoutCheckReturnType ( self ) :
if EccGlobalData . gConfig . CFunctionLayoutCheckReturnType == ' 1 ' or EccGlobalData . gConfig . CFunctionLayoutCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking function layout return type ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.c', '.h'):
# FullName = os.path.join(Dirpath, F)
# c.CheckFuncLayoutReturnType(FullName)
for FullName in EccGlobalData . gCFileList + EccGlobalData . gHFileList :
c . CheckFuncLayoutReturnType ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether any optional functional modifiers exist and next to the return type
def FunctionLayoutCheckModifier ( self ) :
if EccGlobalData . gConfig . CFunctionLayoutCheckOptionalFunctionalModifier == ' 1 ' or EccGlobalData . gConfig . CFunctionLayoutCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking function layout modifier ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.c', '.h'):
# FullName = os.path.join(Dirpath, F)
# c.CheckFuncLayoutModifier(FullName)
for FullName in EccGlobalData . gCFileList + EccGlobalData . gHFileList :
c . CheckFuncLayoutModifier ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether the next line contains the function name, left justified, followed by the beginning of the parameter list
# Check whether the closing parenthesis is on its own line and also indented two spaces
def FunctionLayoutCheckName ( self ) :
if EccGlobalData . gConfig . CFunctionLayoutCheckFunctionName == ' 1 ' or EccGlobalData . gConfig . CFunctionLayoutCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking function layout function name ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.c', '.h'):
# FullName = os.path.join(Dirpath, F)
# c.CheckFuncLayoutName(FullName)
for FullName in EccGlobalData . gCFileList + EccGlobalData . gHFileList :
c . CheckFuncLayoutName ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether the function prototypes in include files have the same form as function definitions
def FunctionLayoutCheckPrototype ( self ) :
if EccGlobalData . gConfig . CFunctionLayoutCheckFunctionPrototype == ' 1 ' or EccGlobalData . gConfig . CFunctionLayoutCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking function layout function prototype ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.c'):
# FullName = os.path.join(Dirpath, F)
# EdkLogger.quiet("[PROTOTYPE]" + FullName)
# c.CheckFuncLayoutPrototype(FullName)
for FullName in EccGlobalData . gCFileList :
EdkLogger . quiet ( " [PROTOTYPE] " + FullName )
c . CheckFuncLayoutPrototype ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether the body of a function is contained by open and close braces that must be in the first column
def FunctionLayoutCheckBody ( self ) :
if EccGlobalData . gConfig . CFunctionLayoutCheckFunctionBody == ' 1 ' or EccGlobalData . gConfig . CFunctionLayoutCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking function layout function body ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.c'):
# FullName = os.path.join(Dirpath, F)
# c.CheckFuncLayoutBody(FullName)
for FullName in EccGlobalData . gCFileList :
c . CheckFuncLayoutBody ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether the data declarations is the first code in a module.
# self.CFunctionLayoutCheckDataDeclaration = 1
# Check whether no initialization of a variable as part of its declaration
def FunctionLayoutCheckLocalVariable ( self ) :
if EccGlobalData . gConfig . CFunctionLayoutCheckNoInitOfVariable == ' 1 ' or EccGlobalData . gConfig . CFunctionLayoutCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking function layout local variables ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.c'):
# FullName = os.path.join(Dirpath, F)
# c.CheckFuncLayoutLocalVariable(FullName)
for FullName in EccGlobalData . gCFileList :
c . CheckFuncLayoutLocalVariable ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether no use of STATIC for functions
# self.CFunctionLayoutCheckNoStatic = 1
# Declarations and Data Types Checking
def DeclAndDataTypeCheck ( self ) :
self . DeclCheckNoUseCType ( )
self . DeclCheckInOutModifier ( )
self . DeclCheckEFIAPIModifier ( )
self . DeclCheckEnumeratedType ( )
self . DeclCheckStructureDeclaration ( )
self . DeclCheckSameStructure ( )
self . DeclCheckUnionType ( )
# Check whether no use of int, unsigned, char, void, static, long in any .c, .h or .asl files.
def DeclCheckNoUseCType ( self ) :
if EccGlobalData . gConfig . DeclarationDataTypeCheckNoUseCType == ' 1 ' or EccGlobalData . gConfig . DeclarationDataTypeCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking Declaration No use C type ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.h', '.c'):
# FullName = os.path.join(Dirpath, F)
# c.CheckDeclNoUseCType(FullName)
for FullName in EccGlobalData . gCFileList + EccGlobalData . gHFileList :
c . CheckDeclNoUseCType ( FullName )
2009-07-17 11:10:31 +02:00
# 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
def DeclCheckInOutModifier ( self ) :
if EccGlobalData . gConfig . DeclarationDataTypeCheckInOutModifier == ' 1 ' or EccGlobalData . gConfig . DeclarationDataTypeCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking Declaration argument modifier ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.h', '.c'):
# FullName = os.path.join(Dirpath, F)
# c.CheckDeclArgModifier(FullName)
for FullName in EccGlobalData . gCFileList + EccGlobalData . gHFileList :
c . CheckDeclArgModifier ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether the EFIAPI modifier should be used at the entry of drivers, events, and member functions of protocols
def DeclCheckEFIAPIModifier ( self ) :
if EccGlobalData . gConfig . DeclarationDataTypeCheckEFIAPIModifier == ' 1 ' or EccGlobalData . gConfig . DeclarationDataTypeCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
pass
# Check whether Enumerated Type has a 'typedef' and the name is capital
def DeclCheckEnumeratedType ( self ) :
if EccGlobalData . gConfig . DeclarationDataTypeCheckEnumeratedType == ' 1 ' or EccGlobalData . gConfig . DeclarationDataTypeCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking Declaration enum typedef ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.h', '.c'):
# FullName = os.path.join(Dirpath, F)
# EdkLogger.quiet("[ENUM]" + FullName)
# c.CheckDeclEnumTypedef(FullName)
for FullName in EccGlobalData . gCFileList + EccGlobalData . gHFileList :
EdkLogger . quiet ( " [ENUM] " + FullName )
c . CheckDeclEnumTypedef ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether Structure Type has a 'typedef' and the name is capital
def DeclCheckStructureDeclaration ( self ) :
if EccGlobalData . gConfig . DeclarationDataTypeCheckStructureDeclaration == ' 1 ' or EccGlobalData . gConfig . DeclarationDataTypeCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking Declaration struct typedef ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.h', '.c'):
# FullName = os.path.join(Dirpath, F)
# EdkLogger.quiet("[STRUCT]" + FullName)
# c.CheckDeclStructTypedef(FullName)
for FullName in EccGlobalData . gCFileList + EccGlobalData . gHFileList :
EdkLogger . quiet ( " [STRUCT] " + FullName )
c . CheckDeclStructTypedef ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether having same Structure
def DeclCheckSameStructure ( self ) :
if EccGlobalData . gConfig . DeclarationDataTypeCheckSameStructure == ' 1 ' or EccGlobalData . gConfig . DeclarationDataTypeCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking same struct ... " )
AllStructure = { }
for IdentifierTable in EccGlobalData . gIdentifierTableList :
SqlCommand = """ select ID, Name, BelongsToFile from %s where Model = %s """ % ( IdentifierTable , MODEL_IDENTIFIER_STRUCTURE )
RecordSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
for Record in RecordSet :
if Record [ 1 ] != ' ' :
if Record [ 1 ] not in AllStructure . keys ( ) :
AllStructure [ Record [ 1 ] ] = Record [ 2 ]
else :
ID = AllStructure [ Record [ 1 ] ]
SqlCommand = """ select FullPath from File where ID = %s """ % ID
NewRecordSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
OtherMsg = " The structure name ' %s ' is duplicate " % Record [ 1 ]
if NewRecordSet != [ ] :
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 ] )
if not EccGlobalData . gException . IsException ( ERROR_DECLARATION_DATA_TYPE_CHECK_SAME_STRUCTURE , Record [ 1 ] ) :
EccGlobalData . gDb . TblReport . Insert ( ERROR_DECLARATION_DATA_TYPE_CHECK_SAME_STRUCTURE , OtherMsg = OtherMsg , BelongsToTable = IdentifierTable , BelongsToItem = Record [ 0 ] )
# Check whether Union Type has a 'typedef' and the name is capital
def DeclCheckUnionType ( self ) :
if EccGlobalData . gConfig . DeclarationDataTypeCheckUnionType == ' 1 ' or EccGlobalData . gConfig . DeclarationDataTypeCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking Declaration union typedef ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.h', '.c'):
# FullName = os.path.join(Dirpath, F)
# EdkLogger.quiet("[UNION]" + FullName)
# c.CheckDeclUnionTypedef(FullName)
for FullName in EccGlobalData . gCFileList + EccGlobalData . gHFileList :
EdkLogger . quiet ( " [UNION] " + FullName )
c . CheckDeclUnionTypedef ( FullName )
2009-07-17 11:10:31 +02:00
# Predicate Expression Checking
def PredicateExpressionCheck ( self ) :
self . PredicateExpressionCheckBooleanValue ( )
self . PredicateExpressionCheckNonBooleanOperator ( )
self . PredicateExpressionCheckComparisonNullType ( )
# Check whether Boolean values, variable type BOOLEAN not use explicit comparisons to TRUE or FALSE
def PredicateExpressionCheckBooleanValue ( self ) :
if EccGlobalData . gConfig . PredicateExpressionCheckBooleanValue == ' 1 ' or EccGlobalData . gConfig . PredicateExpressionCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking predicate expression Boolean value ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.c'):
# FullName = os.path.join(Dirpath, F)
# EdkLogger.quiet("[BOOLEAN]" + FullName)
# c.CheckBooleanValueComparison(FullName)
for FullName in EccGlobalData . gCFileList :
EdkLogger . quiet ( " [BOOLEAN] " + FullName )
c . CheckBooleanValueComparison ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether Non-Boolean comparisons use a compare operator (==, !=, >, < >=, <=).
def PredicateExpressionCheckNonBooleanOperator ( self ) :
if EccGlobalData . gConfig . PredicateExpressionCheckNonBooleanOperator == ' 1 ' or EccGlobalData . gConfig . PredicateExpressionCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking predicate expression Non-Boolean variable... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.c'):
# FullName = os.path.join(Dirpath, F)
# EdkLogger.quiet("[NON-BOOLEAN]" + FullName)
# c.CheckNonBooleanValueComparison(FullName)
for FullName in EccGlobalData . gCFileList :
EdkLogger . quiet ( " [NON-BOOLEAN] " + FullName )
c . CheckNonBooleanValueComparison ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether a comparison of any pointer to zero must be done via the NULL type
def PredicateExpressionCheckComparisonNullType ( self ) :
if EccGlobalData . gConfig . PredicateExpressionCheckComparisonNullType == ' 1 ' or EccGlobalData . gConfig . PredicateExpressionCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking predicate expression NULL pointer ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.c'):
# FullName = os.path.join(Dirpath, F)
# EdkLogger.quiet("[POINTER]" + FullName)
# c.CheckPointerNullComparison(FullName)
for FullName in EccGlobalData . gCFileList :
EdkLogger . quiet ( " [POINTER] " + FullName )
c . CheckPointerNullComparison ( FullName )
2009-07-17 11:10:31 +02:00
# Include file checking
def IncludeFileCheck ( self ) :
self . IncludeFileCheckIfndef ( )
self . IncludeFileCheckData ( )
self . IncludeFileCheckSameName ( )
# Check whether having include files with same name
def IncludeFileCheckSameName ( self ) :
if EccGlobalData . gConfig . IncludeFileCheckSameName == ' 1 ' or EccGlobalData . gConfig . IncludeFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking same header file name ... " )
SqlCommand = """ select ID, FullPath from File
where Model = 1002 order by Name """
RecordDict = { }
RecordSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
for Record in RecordSet :
List = Record [ 1 ] . replace ( ' / ' , ' \\ ' ) . split ( ' \\ ' )
if len ( List ) > = 2 :
Key = List [ - 2 ] + ' \\ ' + List [ - 1 ]
else :
Key = List [ 0 ]
if Key not in RecordDict :
RecordDict [ Key ] = [ Record ]
else :
RecordDict [ Key ] . append ( Record )
for Key in RecordDict :
if len ( RecordDict [ Key ] ) > 1 :
for Item in RecordDict [ Key ] :
2010-03-01 00:39:39 +01:00
Path = Item [ 1 ] . replace ( EccGlobalData . gWorkspace , ' ' )
if Path . startswith ( ' \\ ' ) or Path . startswith ( ' / ' ) :
Path = Path [ 1 : ]
if not EccGlobalData . gException . IsException ( ERROR_INCLUDE_FILE_CHECK_NAME , Path ) :
EccGlobalData . gDb . TblReport . Insert ( ERROR_INCLUDE_FILE_CHECK_NAME , OtherMsg = " The file name for [ %s ] is duplicate " % Path , BelongsToTable = ' File ' , BelongsToItem = Item [ 0 ] )
2009-07-17 11:10:31 +02:00
# Check whether all include file contents is guarded by a #ifndef statement.
def IncludeFileCheckIfndef ( self ) :
if EccGlobalData . gConfig . IncludeFileCheckIfndefStatement == ' 1 ' or EccGlobalData . gConfig . IncludeFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking header file ifndef ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.h'):
# FullName = os.path.join(Dirpath, F)
# MsgList = c.CheckHeaderFileIfndef(FullName)
for FullName in EccGlobalData . gHFileList :
MsgList = c . CheckHeaderFileIfndef ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether include files NOT contain code or define data variables
def IncludeFileCheckData ( self ) :
if EccGlobalData . gConfig . IncludeFileCheckData == ' 1 ' or EccGlobalData . gConfig . IncludeFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking header file data ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.h'):
# FullName = os.path.join(Dirpath, F)
# MsgList = c.CheckHeaderFileData(FullName)
for FullName in EccGlobalData . gHFileList :
MsgList = c . CheckHeaderFileData ( FullName )
2009-07-17 11:10:31 +02:00
# Doxygen document checking
def DoxygenCheck ( self ) :
self . DoxygenCheckFileHeader ( )
self . DoxygenCheckFunctionHeader ( )
self . DoxygenCheckCommentDescription ( )
self . DoxygenCheckCommentFormat ( )
self . DoxygenCheckCommand ( )
# Check whether the file headers are followed Doxygen special documentation blocks in section 2.3.5
def DoxygenCheckFileHeader ( self ) :
if EccGlobalData . gConfig . DoxygenCheckFileHeader == ' 1 ' or EccGlobalData . gConfig . DoxygenCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking Doxygen file header ... " )
for Dirpath , Dirnames , Filenames in self . WalkTree ( ) :
for F in Filenames :
2010-05-18 07:04:32 +02:00
Ext = os . path . splitext ( F ) [ 1 ]
if Ext in ( ' .h ' , ' .c ' ) :
2009-07-17 11:10:31 +02:00
FullName = os . path . join ( Dirpath , F )
MsgList = c . CheckFileHeaderDoxygenComments ( FullName )
2010-05-18 07:04:32 +02:00
elif Ext in ( ' .inf ' , ' .dec ' , ' .dsc ' , ' .fdf ' ) :
FullName = os . path . join ( Dirpath , F )
2010-09-06 03:58:00 +02:00
op = open ( FullName ) . readlines ( )
if not op [ 0 ] . startswith ( ' ## @file ' ) and op [ 6 ] . startswith ( ' ## @file ' ) and op [ 7 ] . startswith ( ' ## @file ' ) :
2010-05-18 07:04:32 +02:00
SqlStatement = """ select ID from File where FullPath like ' %s ' """ % FullName
ResultSet = EccGlobalData . gDb . TblFile . Exec ( SqlStatement )
for Result in ResultSet :
Msg = ' INF/DEC/DSC/FDF file header comment should begin with " " ## @file " " '
EccGlobalData . gDb . TblReport . Insert ( ERROR_DOXYGEN_CHECK_FILE_HEADER , Msg , " File " , Result [ 0 ] )
2010-09-06 03:58:00 +02:00
2009-07-17 11:10:31 +02:00
# Check whether the function headers are followed Doxygen special documentation blocks in section 2.3.5
def DoxygenCheckFunctionHeader ( self ) :
if EccGlobalData . gConfig . DoxygenCheckFunctionHeader == ' 1 ' or EccGlobalData . gConfig . DoxygenCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking Doxygen function header ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.h', '.c'):
# FullName = os.path.join(Dirpath, F)
# MsgList = c.CheckFuncHeaderDoxygenComments(FullName)
for FullName in EccGlobalData . gCFileList + EccGlobalData . gHFileList :
MsgList = c . CheckFuncHeaderDoxygenComments ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether the first line of text in a comment block is a brief description of the element being documented.
# The brief description must end with a period.
def DoxygenCheckCommentDescription ( self ) :
if EccGlobalData . gConfig . DoxygenCheckCommentDescription == ' 1 ' or EccGlobalData . gConfig . DoxygenCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
pass
# Check whether comment lines with '///< ... text ...' format, if it is used, it should be after the code section.
def DoxygenCheckCommentFormat ( self ) :
if EccGlobalData . gConfig . DoxygenCheckCommentFormat == ' 1 ' or EccGlobalData . gConfig . DoxygenCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking Doxygen comment ///< ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.h', '.c'):
# FullName = os.path.join(Dirpath, F)
# MsgList = c.CheckDoxygenTripleForwardSlash(FullName)
for FullName in EccGlobalData . gCFileList + EccGlobalData . gHFileList :
MsgList = c . CheckDoxygenTripleForwardSlash ( FullName )
2009-07-17 11:10:31 +02:00
# Check whether only Doxygen commands allowed to mark the code are @bug and @todo.
def DoxygenCheckCommand ( self ) :
if EccGlobalData . gConfig . DoxygenCheckCommand == ' 1 ' or EccGlobalData . gConfig . DoxygenCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking Doxygen command ... " )
2010-09-06 03:58:00 +02:00
# for Dirpath, Dirnames, Filenames in self.WalkTree():
# for F in Filenames:
# if os.path.splitext(F)[1] in ('.h', '.c'):
# FullName = os.path.join(Dirpath, F)
# MsgList = c.CheckDoxygenCommand(FullName)
for FullName in EccGlobalData . gCFileList + EccGlobalData . gHFileList :
MsgList = c . CheckDoxygenCommand ( FullName )
2009-07-17 11:10:31 +02:00
# Meta-Data File Processing Checking
def MetaDataFileCheck ( self ) :
self . MetaDataFileCheckPathName ( )
self . MetaDataFileCheckGenerateFileList ( )
self . MetaDataFileCheckLibraryInstance ( )
self . MetaDataFileCheckLibraryInstanceDependent ( )
self . MetaDataFileCheckLibraryInstanceOrder ( )
self . MetaDataFileCheckLibraryNoUse ( )
self . MetaDataFileCheckBinaryInfInFdf ( )
self . MetaDataFileCheckPcdDuplicate ( )
self . MetaDataFileCheckPcdFlash ( )
self . MetaDataFileCheckPcdNoUse ( )
self . MetaDataFileCheckGuidDuplicate ( )
self . MetaDataFileCheckModuleFileNoUse ( )
self . MetaDataFileCheckPcdType ( )
2010-05-18 07:04:32 +02:00
self . MetaDataFileCheckModuleFileGuidDuplication ( )
2009-07-17 11:10:31 +02:00
# Check whether each file defined in meta-data exists
def MetaDataFileCheckPathName ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckPathName == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
# This item is covered when parsing Inf/Dec/Dsc files
pass
# Generate a list for all files defined in meta-data files
def MetaDataFileCheckGenerateFileList ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckGenerateFileList == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
# This item is covered when parsing Inf/Dec/Dsc files
pass
# Check whether all Library Instances defined for a given module (or dependent library instance) match the module's type.
# Each Library Instance must specify the Supported Module Types in its Inf file,
# and any module specifying the library instance must be one of the supported types.
def MetaDataFileCheckLibraryInstance ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckLibraryInstance == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking for library instance type issue ... " )
SqlCommand = """ select A.ID, A.Value2, B.Value2 from Inf as A left join Inf as B
where A . Value1 = ' LIBRARY_CLASS ' and A . Model = % s
and B . Value1 = ' MODULE_TYPE ' and B . Model = % s and A . BelongsToFile = B . BelongsToFile
group by A . BelongsToFile """ % (MODEL_META_DATA_HEADER, MODEL_META_DATA_HEADER)
RecordSet = EccGlobalData . gDb . TblInf . Exec ( SqlCommand )
LibraryClasses = { }
for Record in RecordSet :
List = Record [ 1 ] . split ( ' | ' , 1 )
SupModType = [ ]
if len ( List ) == 1 :
SupModType = SUP_MODULE_LIST_STRING . split ( TAB_VALUE_SPLIT )
elif len ( List ) == 2 :
SupModType = List [ 1 ] . split ( )
if List [ 0 ] not in LibraryClasses :
LibraryClasses [ List [ 0 ] ] = SupModType
else :
for Item in SupModType :
if Item not in LibraryClasses [ List [ 0 ] ] :
LibraryClasses [ List [ 0 ] ] . append ( Item )
if Record [ 2 ] != ' BASE ' and Record [ 2 ] not in SupModType :
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 ] )
SqlCommand = """ select A.ID, A.Value1, B.Value2 from Inf as A left join Inf as B
where A . Model = % s and B . Value1 = ' %s ' and B . Model = % s
and B . BelongsToFile = A . BelongsToFile """ \
% ( MODEL_EFI_LIBRARY_CLASS , ' MODULE_TYPE ' , MODEL_META_DATA_HEADER )
RecordSet = EccGlobalData . gDb . TblInf . Exec ( SqlCommand )
# Merge all LibraryClasses' supmodlist
RecordDict = { }
for Record in RecordSet :
if Record [ 1 ] not in RecordDict :
RecordDict [ Record [ 1 ] ] = [ str ( Record [ 2 ] ) ]
else :
if Record [ 2 ] not in RecordDict [ Record [ 1 ] ] :
RecordDict [ Record [ 1 ] ] . append ( Record [ 2 ] )
for Record in RecordSet :
if Record [ 1 ] in LibraryClasses :
if Record [ 2 ] not in LibraryClasses [ Record [ 1 ] ] and ' BASE ' not in RecordDict [ Record [ 1 ] ] :
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_LIBRARY_INSTANCE_1 , Record [ 1 ] ) :
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 ] )
else :
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_LIBRARY_INSTANCE_1 , Record [ 1 ] ) :
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 ] )
# Check whether a Library Instance has been defined for all dependent library classes
def MetaDataFileCheckLibraryInstanceDependent ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckLibraryInstanceDependent == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking for library instance dependent issue ... " )
SqlCommand = """ select ID, Value1, Value2 from Dsc where Model = %s """ % MODEL_EFI_LIBRARY_CLASS
LibraryClasses = EccGlobalData . gDb . TblDsc . Exec ( SqlCommand )
for LibraryClass in LibraryClasses :
if LibraryClass [ 1 ] . upper ( ) != ' NULL ' :
LibraryIns = os . path . normpath ( os . path . join ( EccGlobalData . gWorkspace , LibraryClass [ 2 ] ) )
SqlCommand = """ select Value2 from Inf where BelongsToFile =
( select ID from File where lower ( FullPath ) = lower ( ' %s ' ) )
and Value1 = ' %s ' """ % (LibraryIns, ' LIBRARY_CLASS ' )
RecordSet = EccGlobalData . gDb . TblInf . Exec ( SqlCommand )
IsFound = False
for Record in RecordSet :
LibName = Record [ 0 ] . split ( ' | ' , 1 ) [ 0 ]
if LibraryClass [ 1 ] == LibName :
IsFound = True
if not IsFound :
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_LIBRARY_INSTANCE_DEPENDENT , LibraryClass [ 1 ] ) :
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 ] )
# Check whether the Library Instances specified by the LibraryClasses sections are listed in order of dependencies
def MetaDataFileCheckLibraryInstanceOrder ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckLibraryInstanceOrder == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
# This checkpoint is not necessary for Ecc check
pass
# Check whether the unnecessary inclusion of library classes in the Inf file
def MetaDataFileCheckLibraryNoUse ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckLibraryNoUse == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking for library instance not used ... " )
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 )
RecordSet = EccGlobalData . gDb . TblInf . Exec ( SqlCommand )
for Record in RecordSet :
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_LIBRARY_NO_USE , Record [ 1 ] ) :
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 ] )
# 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
def MetaDataFileCheckBinaryInfInFdf ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckBinaryInfInFdf == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking for non-binary modules defined in FDF files ... " )
SqlCommand = """ select A.ID, A.Value1 from Fdf as A
where A . Model = % s
and A . Enabled > - 1
and A . Value1 not in
( select B . Value1 from Dsc as B
where B . Model = % s
and B . Enabled > - 1 ) """ % (MODEL_META_DATA_COMPONENT, MODEL_META_DATA_COMPONENT)
RecordSet = EccGlobalData . gDb . TblFdf . Exec ( SqlCommand )
for Record in RecordSet :
FdfID = Record [ 0 ]
FilePath = Record [ 1 ]
FilePath = os . path . normpath ( os . path . join ( EccGlobalData . gWorkspace , FilePath ) )
SqlCommand = """ select ID from Inf where Model = %s and BelongsToFile = (select ID from File where FullPath like ' %s ' )
""" % (MODEL_EFI_SOURCE_FILE, FilePath)
NewRecordSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
if NewRecordSet != [ ] :
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_BINARY_INF_IN_FDF , FilePath ) :
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 )
# Check whether a PCD is set in a Dsc file or the FDF file, but not in both.
def MetaDataFileCheckPcdDuplicate ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckPcdDuplicate == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking for duplicate PCDs defined in both DSC and FDF files ... " )
SqlCommand = """
2010-03-01 00:39:39 +01:00
select A . ID , A . Value2 , A . BelongsToFile , B . ID , B . Value2 , B . BelongsToFile from Dsc as A , Fdf as B
2009-07-17 11:10:31 +02:00
where A . Model > = % s and A . Model < % s
and B . Model > = % s and B . Model < % s
and A . Value2 = B . Value2
and A . Enabled > - 1
and B . Enabled > - 1
group by A . ID
""" % (MODEL_PCD, MODEL_META_DATA_HEADER, MODEL_PCD, MODEL_META_DATA_HEADER)
RecordSet = EccGlobalData . gDb . TblDsc . Exec ( SqlCommand )
for Record in RecordSet :
2010-03-01 00:39:39 +01:00
SqlCommand1 = """ select Name from File where ID = %s """ % Record [ 2 ]
SqlCommand2 = """ select Name from File where ID = %s """ % Record [ 5 ]
DscFileName = os . path . splitext ( EccGlobalData . gDb . TblDsc . Exec ( SqlCommand1 ) [ 0 ] [ 0 ] ) [ 0 ]
FdfFileName = os . path . splitext ( EccGlobalData . gDb . TblDsc . Exec ( SqlCommand2 ) [ 0 ] [ 0 ] ) [ 0 ]
if DscFileName != FdfFileName :
continue
2009-07-17 11:10:31 +02:00
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_PCD_DUPLICATE , Record [ 1 ] ) :
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 ] ) , BelongsToTable = ' Dsc ' , BelongsToItem = Record [ 0 ] )
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_PCD_DUPLICATE , Record [ 3 ] ) :
2010-03-01 00:39:39 +01:00
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 [ 4 ] ) , BelongsToTable = ' Fdf ' , BelongsToItem = Record [ 3 ] )
2009-07-17 11:10:31 +02:00
EdkLogger . quiet ( " Checking for duplicate PCDs defined in DEC files ... " )
SqlCommand = """
select A . ID , A . Value2 from Dec as A , Dec as B
where A . Model > = % s and A . Model < % s
and B . Model > = % s and B . Model < % s
and A . Value2 = B . Value2
and ( ( A . Arch = B . Arch ) and ( A . Arch != ' COMMON ' or B . Arch != ' COMMON ' ) )
and A . ID != B . ID
and A . Enabled > - 1
and B . Enabled > - 1
and A . BelongsToFile = B . BelongsToFile
group by A . ID
""" % (MODEL_PCD, MODEL_META_DATA_HEADER, MODEL_PCD, MODEL_META_DATA_HEADER)
RecordSet = EccGlobalData . gDb . TblDsc . Exec ( SqlCommand )
for Record in RecordSet :
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_PCD_DUPLICATE , Record [ 1 ] ) :
EccGlobalData . gDb . TblReport . Insert ( ERROR_META_DATA_FILE_CHECK_PCD_DUPLICATE , OtherMsg = " The PCD [ %s ] is defined duplicated in DEC file " % ( Record [ 1 ] ) , BelongsToTable = ' Dec ' , BelongsToItem = Record [ 0 ] )
# Check whether PCD settings in the FDF file can only be related to flash.
def MetaDataFileCheckPcdFlash ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckPcdFlash == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking only Flash related PCDs are used in FDF ... " )
SqlCommand = """
select ID , Value2 , BelongsToFile from Fdf as A
where A . Model > = % s and Model < % s
and A . Enabled > - 1
and A . Value2 not like ' %% Flash %% '
""" % (MODEL_PCD, MODEL_META_DATA_HEADER)
RecordSet = EccGlobalData . gDb . TblFdf . Exec ( SqlCommand )
for Record in RecordSet :
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_PCD_FLASH , Record [ 1 ] ) :
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 ] ) , BelongsToTable = ' Fdf ' , BelongsToItem = Record [ 0 ] )
# Check whether PCDs used in Inf files but not specified in Dsc or FDF files
def MetaDataFileCheckPcdNoUse ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckPcdNoUse == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking for non-specified PCDs ... " )
SqlCommand = """
select ID , Value2 , BelongsToFile from Inf as A
where A . Model > = % s and Model < % s
and A . Enabled > - 1
and A . Value2 not in
( select Value2 from Dsc as B
where B . Model > = % s and B . Model < % s
and B . Enabled > - 1 )
and A . Value2 not in
( select Value2 from Fdf as C
where C . Model > = % s and C . Model < % s
and C . Enabled > - 1 )
""" % (MODEL_PCD, MODEL_META_DATA_HEADER, MODEL_PCD, MODEL_META_DATA_HEADER, MODEL_PCD, MODEL_META_DATA_HEADER)
RecordSet = EccGlobalData . gDb . TblInf . Exec ( SqlCommand )
for Record in RecordSet :
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_PCD_NO_USE , Record [ 1 ] ) :
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 ] ) , BelongsToTable = ' Inf ' , BelongsToItem = Record [ 0 ] )
# Check whether having duplicate guids defined for Guid/Protocol/Ppi
def MetaDataFileCheckGuidDuplicate ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckGuidDuplicate == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking for duplicate GUID/PPI/PROTOCOL ... " )
# Check Guid
self . CheckGuidProtocolPpi ( ERROR_META_DATA_FILE_CHECK_DUPLICATE_GUID , MODEL_EFI_GUID , EccGlobalData . gDb . TblDec )
self . CheckGuidProtocolPpi ( ERROR_META_DATA_FILE_CHECK_DUPLICATE_GUID , MODEL_EFI_GUID , EccGlobalData . gDb . TblDsc )
self . CheckGuidProtocolPpiValue ( ERROR_META_DATA_FILE_CHECK_DUPLICATE_GUID , MODEL_EFI_GUID )
# Check protocol
self . CheckGuidProtocolPpi ( ERROR_META_DATA_FILE_CHECK_DUPLICATE_PROTOCOL , MODEL_EFI_PROTOCOL , EccGlobalData . gDb . TblDec )
self . CheckGuidProtocolPpi ( ERROR_META_DATA_FILE_CHECK_DUPLICATE_PROTOCOL , MODEL_EFI_PROTOCOL , EccGlobalData . gDb . TblDsc )
self . CheckGuidProtocolPpiValue ( ERROR_META_DATA_FILE_CHECK_DUPLICATE_PROTOCOL , MODEL_EFI_PROTOCOL )
# Check ppi
self . CheckGuidProtocolPpi ( ERROR_META_DATA_FILE_CHECK_DUPLICATE_PPI , MODEL_EFI_PPI , EccGlobalData . gDb . TblDec )
self . CheckGuidProtocolPpi ( ERROR_META_DATA_FILE_CHECK_DUPLICATE_PPI , MODEL_EFI_PPI , EccGlobalData . gDb . TblDsc )
self . CheckGuidProtocolPpiValue ( ERROR_META_DATA_FILE_CHECK_DUPLICATE_PPI , MODEL_EFI_PPI )
# Check whether all files under module directory are described in INF files
def MetaDataFileCheckModuleFileNoUse ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckModuleFileNoUse == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking for no used module files ... " )
SqlCommand = """
select upper ( Path ) from File where ID in ( select BelongsToFile from INF where BelongsToFile != - 1 )
"""
InfPathSet = EccGlobalData . gDb . TblInf . Exec ( SqlCommand )
InfPathList = [ ]
for Item in InfPathSet :
if Item [ 0 ] not in InfPathList :
InfPathList . append ( Item [ 0 ] )
SqlCommand = """
select ID , Path , FullPath from File where upper ( FullPath ) not in
( select upper ( A . Path ) | | ' \\ ' | | upper ( B . Value1 ) from File as A , INF as B
where A . ID in ( select BelongsToFile from INF where Model = % s group by BelongsToFile ) and
B . BelongsToFile = A . ID and B . Model = % s )
and ( Model = % s or Model = % s )
""" % (MODEL_EFI_SOURCE_FILE, MODEL_EFI_SOURCE_FILE, MODEL_FILE_C, MODEL_FILE_H)
RecordSet = EccGlobalData . gDb . TblInf . Exec ( SqlCommand )
for Record in RecordSet :
Path = Record [ 1 ]
Path = Path . upper ( ) . replace ( ' \ X64 ' , ' ' ) . replace ( ' \ IA32 ' , ' ' ) . replace ( ' \ EBC ' , ' ' ) . replace ( ' \ IPF ' , ' ' ) . replace ( ' \ ARM ' , ' ' )
if Path in InfPathList :
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_MODULE_FILE_NO_USE , Record [ 2 ] ) :
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 ] )
# Check whether the PCD is correctly used in C function via its type
def MetaDataFileCheckPcdType ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckPcdType == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking for pcd type in c code function usage ... " )
SqlCommand = """
select ID , Model , Value1 , BelongsToFile from INF where Model > % s and Model < % s
""" % (MODEL_PCD, MODEL_META_DATA_HEADER)
PcdSet = EccGlobalData . gDb . TblInf . Exec ( SqlCommand )
for Pcd in PcdSet :
Model = Pcd [ 1 ]
PcdName = Pcd [ 2 ]
if len ( Pcd [ 2 ] . split ( " . " ) ) > 1 :
PcdName = Pcd [ 2 ] . split ( " . " ) [ 1 ]
BelongsToFile = Pcd [ 3 ]
SqlCommand = """
select ID from File where FullPath in
( select B . Path | | ' \\ ' | | A . Value1 from INF as A , File as B where A . Model = % s and A . BelongsToFile = % s
2010-09-06 03:58:00 +02:00
and B . ID = % s and ( B . Model = % s or B . Model = % s ) )
""" % (MODEL_EFI_SOURCE_FILE, BelongsToFile, BelongsToFile, MODEL_FILE_C, MODEL_FILE_H)
2009-07-17 11:10:31 +02:00
TableSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
for Tbl in TableSet :
TblName = ' Identifier ' + str ( Tbl [ 0 ] )
SqlCommand = """
2010-03-01 00:39:39 +01:00
select Name , ID from % s where value like ' %s ' and Model = % s
2009-07-17 11:10:31 +02:00
""" % (TblName, PcdName, MODEL_IDENTIFIER_FUNCTION_CALLING)
RecordSet = EccGlobalData . gDb . TblInf . Exec ( SqlCommand )
TblNumber = TblName . replace ( ' Identifier ' , ' ' )
for Record in RecordSet :
FunName = Record [ 0 ]
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_PCD_TYPE , FunName ) :
if Model in [ MODEL_PCD_FIXED_AT_BUILD ] and not FunName . startswith ( ' FixedPcdGet ' ) :
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 ] )
if Model in [ MODEL_PCD_FEATURE_FLAG ] and ( not FunName . startswith ( ' FeaturePcdGet ' ) and not FunName . startswith ( ' FeaturePcdSet ' ) ) :
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 ] )
if Model in [ MODEL_PCD_PATCHABLE_IN_MODULE ] and ( not FunName . startswith ( ' PatchablePcdGet ' ) and not FunName . startswith ( ' PatchablePcdSet ' ) ) :
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 ] )
#ERROR_META_DATA_FILE_CHECK_PCD_TYPE
pass
2010-05-18 07:04:32 +02:00
# Internal worker function to get the INF workspace relative path from FileID
def GetInfFilePathFromID ( self , FileID ) :
Table = EccGlobalData . gDb . TblFile
SqlCommand = """ select A.FullPath from %s as A where A.ID = %s """ % ( Table . Table , FileID )
RecordSet = Table . Exec ( SqlCommand )
Path = " "
for Record in RecordSet :
Path = Record [ 0 ] . replace ( EccGlobalData . gWorkspace , ' ' )
if Path . startswith ( ' \\ ' ) or Path . startswith ( ' / ' ) :
Path = Path [ 1 : ]
return Path
2010-09-06 03:58:00 +02:00
2010-05-18 07:04:32 +02:00
# Check whether two module INFs under one workspace has the same FILE_GUID value
def MetaDataFileCheckModuleFileGuidDuplication ( self ) :
if EccGlobalData . gConfig . MetaDataFileCheckModuleFileGuidDuplication == ' 1 ' or EccGlobalData . gConfig . MetaDataFileCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking for pcd type in c code function usage ... " )
Table = EccGlobalData . gDb . TblInf
SqlCommand = """
select A . ID , A . Value2 , A . BelongsToFile , B . BelongsToFile from % s as A , % s as B
where A . Value1 = ' FILE_GUID ' and B . Value1 = ' FILE_GUID ' and
A . Value2 = B . Value2 and A . ID < > B . ID group by A . ID
""" % (Table.Table, Table.Table)
RecordSet = Table . Exec ( SqlCommand )
for Record in RecordSet :
InfPath1 = self . GetInfFilePathFromID ( Record [ 2 ] )
InfPath2 = self . GetInfFilePathFromID ( Record [ 3 ] )
if InfPath1 and InfPath2 :
if not EccGlobalData . gException . IsException ( ERROR_META_DATA_FILE_CHECK_MODULE_FILE_GUID_DUPLICATION , InfPath1 ) :
Msg = " The FILE_GUID of INF file [ %s ] is duplicated with that of %s " % ( InfPath1 , InfPath2 )
EccGlobalData . gDb . TblReport . Insert ( ERROR_META_DATA_FILE_CHECK_MODULE_FILE_GUID_DUPLICATION , OtherMsg = Msg , BelongsToTable = Table . Table , BelongsToItem = Record [ 0 ] )
2010-09-06 03:58:00 +02:00
2010-05-18 07:04:32 +02:00
2009-07-17 11:10:31 +02:00
# Check whether these is duplicate Guid/Ppi/Protocol name
def CheckGuidProtocolPpi ( self , ErrorID , Model , Table ) :
Name = ' '
if Model == MODEL_EFI_GUID :
Name = ' guid '
if Model == MODEL_EFI_PROTOCOL :
Name = ' protocol '
if Model == MODEL_EFI_PPI :
Name = ' ppi '
SqlCommand = """
select A . ID , A . Value1 from % s as A , % s as B
where A . Model = % s and B . Model = % s
and A . Value1 = B . Value1 and A . ID < > B . ID
and A . Enabled > - 1
and B . Enabled > - 1
group by A . ID
""" % (Table.Table, Table.Table, Model, Model)
RecordSet = Table . Exec ( SqlCommand )
for Record in RecordSet :
if not EccGlobalData . gException . IsException ( ErrorID , Record [ 1 ] ) :
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 ] )
# Check whether these is duplicate Guid/Ppi/Protocol value
def CheckGuidProtocolPpiValue ( self , ErrorID , Model ) :
Name = ' '
Table = EccGlobalData . gDb . TblDec
if Model == MODEL_EFI_GUID :
Name = ' guid '
if Model == MODEL_EFI_PROTOCOL :
Name = ' protocol '
if Model == MODEL_EFI_PPI :
Name = ' ppi '
SqlCommand = """
select A . ID , A . Value2 from % s as A , % s as B
where A . Model = % s and B . Model = % s
and A . Value2 = B . Value2 and A . ID < > B . ID
group by A . ID
""" % (Table.Table, Table.Table, Model, Model)
RecordSet = Table . Exec ( SqlCommand )
for Record in RecordSet :
if not EccGlobalData . gException . IsException ( ErrorID , Record [ 1 ] ) :
EccGlobalData . gDb . TblReport . Insert ( ErrorID , OtherMsg = " The %s value [ %s ] is used more than one time " % ( Name . upper ( ) , Record [ 1 ] ) , BelongsToTable = Table . Table , BelongsToItem = Record [ 0 ] )
# Naming Convention Check
def NamingConventionCheck ( self ) :
2010-03-01 00:39:39 +01:00
if EccGlobalData . gConfig . NamingConventionCheckDefineStatement == ' 1 ' \
or EccGlobalData . gConfig . NamingConventionCheckTypedefStatement == ' 1 ' \
or EccGlobalData . gConfig . NamingConventionCheckIfndefStatement == ' 1 ' \
or EccGlobalData . gConfig . NamingConventionCheckVariableName == ' 1 ' \
or EccGlobalData . gConfig . NamingConventionCheckSingleCharacterVariable == ' 1 ' \
or EccGlobalData . gConfig . NamingConventionCheckAll == ' 1 ' \
or EccGlobalData . gConfig . CheckAll == ' 1 ' :
for Dirpath , Dirnames , Filenames in self . WalkTree ( ) :
for F in Filenames :
if os . path . splitext ( F ) [ 1 ] in ( ' .h ' , ' .c ' ) :
FullName = os . path . join ( Dirpath , F )
Id = c . GetTableID ( FullName )
if Id < 0 :
continue
FileTable = ' Identifier ' + str ( Id )
self . NamingConventionCheckDefineStatement ( FileTable )
self . NamingConventionCheckTypedefStatement ( FileTable )
self . NamingConventionCheckIfndefStatement ( FileTable )
self . NamingConventionCheckVariableName ( FileTable )
self . NamingConventionCheckSingleCharacterVariable ( FileTable )
2009-07-17 11:10:31 +02:00
self . NamingConventionCheckPathName ( )
self . NamingConventionCheckFunctionName ( )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
# Check whether only capital letters are used for #define declarations
def NamingConventionCheckDefineStatement ( self , FileTable ) :
if EccGlobalData . gConfig . NamingConventionCheckDefineStatement == ' 1 ' or EccGlobalData . gConfig . NamingConventionCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking naming covention of #define statement ... " )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
SqlCommand = """ select ID, Value from %s where Model = %s """ % ( FileTable , MODEL_IDENTIFIER_MACRO_DEFINE )
RecordSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
for Record in RecordSet :
Name = Record [ 1 ] . strip ( ) . split ( ) [ 1 ]
if Name . find ( ' ( ' ) != - 1 :
Name = Name [ 0 : Name . find ( ' ( ' ) ]
if Name . upper ( ) != Name :
if not EccGlobalData . gException . IsException ( ERROR_NAMING_CONVENTION_CHECK_DEFINE_STATEMENT , Name ) :
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 ] )
# Check whether only capital letters are used for typedef declarations
def NamingConventionCheckTypedefStatement ( self , FileTable ) :
if EccGlobalData . gConfig . NamingConventionCheckTypedefStatement == ' 1 ' or EccGlobalData . gConfig . NamingConventionCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking naming covention of #typedef statement ... " )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
SqlCommand = """ select ID, Name from %s where Model = %s """ % ( FileTable , MODEL_IDENTIFIER_TYPEDEF )
RecordSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
for Record in RecordSet :
Name = Record [ 1 ] . strip ( )
if Name != ' ' and Name != None :
if Name [ 0 ] == ' ( ' :
Name = Name [ 1 : Name . find ( ' ) ' ) ]
if Name . find ( ' ( ' ) > - 1 :
Name = Name [ Name . find ( ' ( ' ) + 1 : Name . find ( ' ) ' ) ]
Name = Name . replace ( ' WINAPI ' , ' ' )
Name = Name . replace ( ' * ' , ' ' ) . strip ( )
if Name . upper ( ) != Name :
if not EccGlobalData . gException . IsException ( ERROR_NAMING_CONVENTION_CHECK_TYPEDEF_STATEMENT , Name ) :
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 ] )
# Check whether the #ifndef at the start of an include file uses both prefix and postfix underscore characters, '_'.
def NamingConventionCheckIfndefStatement ( self , FileTable ) :
if EccGlobalData . gConfig . NamingConventionCheckTypedefStatement == ' 1 ' or EccGlobalData . gConfig . NamingConventionCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking naming covention of #ifndef statement ... " )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
SqlCommand = """ select ID, Value from %s where Model = %s """ % ( FileTable , MODEL_IDENTIFIER_MACRO_IFNDEF )
RecordSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
for Record in RecordSet :
Name = Record [ 1 ] . replace ( ' #ifndef ' , ' ' ) . strip ( )
if Name [ 0 ] != ' _ ' or Name [ - 1 ] != ' _ ' :
if not EccGlobalData . gException . IsException ( ERROR_NAMING_CONVENTION_CHECK_IFNDEF_STATEMENT , Name ) :
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 ] )
# Rule for path name, variable name and function name
# 1. First character should be upper case
# 2. Existing lower case in a word
# 3. No space existence
# Check whether the path name followed the rule
def NamingConventionCheckPathName ( self ) :
if EccGlobalData . gConfig . NamingConventionCheckPathName == ' 1 ' or EccGlobalData . gConfig . NamingConventionCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking naming covention of file path name ... " )
Pattern = re . compile ( r ' ^[A-Z]+ \ S*[a-z] \ S*$ ' )
SqlCommand = """ select ID, Name from File """
RecordSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
for Record in RecordSet :
if not Pattern . match ( Record [ 1 ] ) :
if not EccGlobalData . gException . IsException ( ERROR_NAMING_CONVENTION_CHECK_PATH_NAME , Record [ 1 ] ) :
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 ] )
# Rule for path name, variable name and function name
# 1. First character should be upper case
# 2. Existing lower case in a word
# 3. No space existence
# 4. Global variable name must start with a 'g'
# Check whether the variable name followed the rule
def NamingConventionCheckVariableName ( self , FileTable ) :
if EccGlobalData . gConfig . NamingConventionCheckVariableName == ' 1 ' or EccGlobalData . gConfig . NamingConventionCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking naming covention of variable name ... " )
Pattern = re . compile ( r ' ^[A-Zgm]+ \ S*[a-z] \ S*$ ' )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
SqlCommand = """ select ID, Name from %s where Model = %s """ % ( FileTable , MODEL_IDENTIFIER_VARIABLE )
RecordSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
for Record in RecordSet :
if not Pattern . match ( Record [ 1 ] ) :
if not EccGlobalData . gException . IsException ( ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME , Record [ 1 ] ) :
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 ] )
# Rule for path name, variable name and function name
# 1. First character should be upper case
# 2. Existing lower case in a word
# 3. No space existence
# Check whether the function name followed the rule
def NamingConventionCheckFunctionName ( self ) :
if EccGlobalData . gConfig . NamingConventionCheckFunctionName == ' 1 ' or EccGlobalData . gConfig . NamingConventionCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking naming covention of function name ... " )
Pattern = re . compile ( r ' ^[A-Z]+ \ S*[a-z] \ S*$ ' )
SqlCommand = """ select ID, Name from Function """
RecordSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
for Record in RecordSet :
if not Pattern . match ( Record [ 1 ] ) :
if not EccGlobalData . gException . IsException ( ERROR_NAMING_CONVENTION_CHECK_FUNCTION_NAME , Record [ 1 ] ) :
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 ] )
# Check whether NO use short variable name with single character
def NamingConventionCheckSingleCharacterVariable ( self , FileTable ) :
if EccGlobalData . gConfig . NamingConventionCheckSingleCharacterVariable == ' 1 ' or EccGlobalData . gConfig . NamingConventionCheckAll == ' 1 ' or EccGlobalData . gConfig . CheckAll == ' 1 ' :
EdkLogger . quiet ( " Checking naming covention of single character variable name ... " )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
SqlCommand = """ select ID, Name from %s where Model = %s """ % ( FileTable , MODEL_IDENTIFIER_VARIABLE )
RecordSet = EccGlobalData . gDb . TblFile . Exec ( SqlCommand )
for Record in RecordSet :
Variable = Record [ 1 ] . replace ( ' * ' , ' ' )
if len ( Variable ) == 1 :
if not EccGlobalData . gException . IsException ( ERROR_NAMING_CONVENTION_CHECK_SINGLE_CHARACTER_VARIABLE , Record [ 1 ] ) :
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 ] )
##
#
# This acts like the main() function for the script, unless it is 'import'ed into another
# script.
#
if __name__ == ' __main__ ' :
Check = Check ( )
Check . Check ( )