1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 """ Lint for IDL """ 6 7 import os 8 import sys 9 10 from idl_log import ErrOut, InfoOut, WarnOut 11 from idl_node import IDLAttribute, IDLNode 12 from idl_ast import IDLAst 13 from idl_option import GetOption, Option, ParseOptions 14 from idl_outfile import IDLOutFile 15 from idl_visitor import IDLVisitor 16 17 18 Option('wcomment', 'Disable warning for missing comment.') 19 Option('wenum', 'Disable warning for missing enum value.') 20 Option('winline', 'Disable warning for inline blocks.') 21 Option('wname', 'Disable warning for inconsistent interface name.') 22 Option('wnone', 'Disable all warnings.') 23 Option('wparam', 'Disable warning for missing [in|out|inout] on param.') 24 Option('wpass', 'Disable warning for mixed passByValue and returnByValue.') 25 26 # 27 # IDLLinter 28 # 29 # Once the AST is build, we need to resolve the namespace and version 30 # information. 31 # 32 class IDLLinter(IDLVisitor): 33 def VisitFilter(self, node, data): 34 __pychecker__ = 'unusednames=node,data' 35 return not node.IsA('Comment', 'Copyright') 36 37 def Arrive(self, node, errors): 38 __pychecker__ = 'unusednames=node,errors' 39 warnings = 0 40 if node.IsA('Interface', 'Member', 'Struct', 'Enum', 'EnumItem', 'Typedef'): 41 comments = node.GetListOf('Comment') 42 if not comments and not node.GetProperty('wcomment'): 43 node.Warning('Expecting a comment.') 44 warnings += 1 45 46 if node.IsA('File'): 47 labels = node.GetListOf('Label') 48 interfaces = node.GetListOf('Interface') 49 if interfaces and not labels: 50 node.Warning('Expecting a label in a file containing interfaces.') 51 52 if node.IsA('Struct', 'Typedef') and not node.GetProperty('wpass'): 53 if node.GetProperty('passByValue'): 54 pbv = 'is' 55 else: 56 pbv = 'is not' 57 if node.GetProperty('returnByValue'): 58 ret = 'is' 59 else: 60 ret = 'is not' 61 if pbv != ret: 62 node.Warning('%s passByValue but %s returnByValue.' % (pbv, ret)) 63 warnings += 1 64 65 if node.IsA('EnumItem'): 66 if not node.GetProperty('VALUE') and not node.GetProperty('wenum'): 67 node.Warning('Expecting value for enumeration.') 68 warnings += 1 69 70 if node.IsA('Interface'): 71 macro = node.GetProperty('macro') 72 if macro and not node.GetProperty('wname'): 73 node.Warning('Interface name inconsistent: %s' % macro) 74 warnings += 1 75 76 if node.IsA('Inline') and not node.GetProperty('winline'): 77 inline_type = node.GetProperty('NAME') 78 node.parent.Warning('Requires an inline %s block.' % inline_type) 79 warnings += 1 80 81 if node.IsA('Callspec') and not node.GetProperty('wparam'): 82 out = False 83 for arg in node.GetListOf('Param'): 84 if arg.GetProperty('out'): 85 out = True 86 if arg.GetProperty('in') and out: 87 arg.Warning('[in] parameter after [out] parameter') 88 warnings += 1 89 90 if node.IsA('Param') and not node.GetProperty('wparam'): 91 found = False; 92 for form in ['in', 'inout', 'out']: 93 if node.GetProperty(form): found = True 94 if not found: 95 node.Warning('Missing argument type: [in|out|inout]') 96 warnings += 1 97 98 return warnings 99 100 def Depart(self, node, warnings, childdata): 101 __pychecker__ = 'unusednames=node' 102 for child in childdata: 103 warnings += child 104 return warnings 105 106 def Lint(ast): 107 options = ['wcomment', 'wenum', 'winline', 'wparam', 'wpass', 'wname'] 108 wnone = GetOption('wnone') 109 for opt in options: 110 if wnone or GetOption(opt): ast.SetProperty(opt, True) 111 112 skipList = [] 113 for filenode in ast.GetListOf('File'): 114 name = filenode.GetProperty('NAME') 115 if filenode.GetProperty('ERRORS') > 0: 116 ErrOut.Log('%s : Skipped due to errors.' % name) 117 skipList.append(filenode) 118 continue 119 warnings = IDLLinter().Visit(filenode, 0) 120 if warnings: 121 WarnOut.Log('%s warning(s) for %s\n' % (warnings, name)) 122 return skipList 123