|  | # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  |  | 
|  | """ Lint for IDL """ | 
|  |  | 
|  | import os | 
|  | import sys | 
|  |  | 
|  | from idl_log import ErrOut, InfoOut, WarnOut | 
|  | from idl_node import IDLAttribute, IDLNode | 
|  | from idl_ast import IDLAst | 
|  | from idl_option import GetOption, Option, ParseOptions | 
|  | from idl_outfile import IDLOutFile | 
|  | from idl_visitor import IDLVisitor | 
|  |  | 
|  |  | 
|  | Option('wcomment', 'Disable warning for missing comment.') | 
|  | Option('wenum', 'Disable warning for missing enum value.') | 
|  | Option('winline', 'Disable warning for inline blocks.') | 
|  | Option('wname', 'Disable warning for inconsistent interface name.') | 
|  | Option('wnone', 'Disable all warnings.') | 
|  | Option('wparam', 'Disable warning for missing [in|out|inout] on param.') | 
|  | Option('wpass', 'Disable warning for mixed passByValue and returnByValue.') | 
|  |  | 
|  | # | 
|  | # IDLLinter | 
|  | # | 
|  | # Once the AST is build, we need to resolve the namespace and version | 
|  | # information. | 
|  | # | 
|  | class IDLLinter(IDLVisitor): | 
|  | def VisitFilter(self, node, data): | 
|  | __pychecker__ = 'unusednames=node,data' | 
|  | return not node.IsA('Comment', 'Copyright') | 
|  |  | 
|  | def Arrive(self, node, errors): | 
|  | __pychecker__ = 'unusednames=node,errors' | 
|  | warnings = 0 | 
|  | if node.IsA('Interface', 'Member', 'Struct', 'Enum', 'EnumItem', 'Typedef'): | 
|  | comments = node.GetListOf('Comment') | 
|  | if not comments and not node.GetProperty('wcomment'): | 
|  | node.Warning('Expecting a comment.') | 
|  | warnings += 1 | 
|  |  | 
|  | if node.IsA('File'): | 
|  | labels = node.GetListOf('Label') | 
|  | interfaces = node.GetListOf('Interface') | 
|  | if interfaces and not labels: | 
|  | node.Warning('Expecting a label in a file containing interfaces.') | 
|  |  | 
|  | if node.IsA('Struct', 'Typedef') and not node.GetProperty('wpass'): | 
|  | if node.GetProperty('passByValue'): | 
|  | pbv = 'is' | 
|  | else: | 
|  | pbv = 'is not' | 
|  | if node.GetProperty('returnByValue'): | 
|  | ret = 'is' | 
|  | else: | 
|  | ret = 'is not' | 
|  | if pbv != ret: | 
|  | node.Warning('%s passByValue but %s returnByValue.' % (pbv, ret)) | 
|  | warnings += 1 | 
|  |  | 
|  | if node.IsA('EnumItem'): | 
|  | if not node.GetProperty('VALUE') and not node.GetProperty('wenum'): | 
|  | node.Warning('Expecting value for enumeration.') | 
|  | warnings += 1 | 
|  |  | 
|  | if node.IsA('Interface'): | 
|  | macro = node.GetProperty('macro') | 
|  | if macro and not node.GetProperty('wname'): | 
|  | node.Warning('Interface name inconsistent: %s' % macro) | 
|  | warnings += 1 | 
|  |  | 
|  | if node.IsA('Inline') and not node.GetProperty('winline'): | 
|  | inline_type = node.GetProperty('NAME') | 
|  | node.parent.Warning('Requires an inline %s block.' % inline_type) | 
|  | warnings += 1 | 
|  |  | 
|  | if node.IsA('Callspec') and not node.GetProperty('wparam'): | 
|  | out = False | 
|  | for arg in node.GetListOf('Param'): | 
|  | if arg.GetProperty('out'): | 
|  | out = True | 
|  | if arg.GetProperty('in') and out: | 
|  | arg.Warning('[in] parameter after [out] parameter') | 
|  | warnings += 1 | 
|  |  | 
|  | if node.IsA('Param') and not node.GetProperty('wparam'): | 
|  | found = False; | 
|  | for form in ['in', 'inout', 'out']: | 
|  | if node.GetProperty(form): found = True | 
|  | if not found: | 
|  | node.Warning('Missing argument type: [in|out|inout]') | 
|  | warnings += 1 | 
|  |  | 
|  | return warnings | 
|  |  | 
|  | def Depart(self, node, warnings, childdata): | 
|  | __pychecker__ = 'unusednames=node' | 
|  | for child in childdata: | 
|  | warnings += child | 
|  | return warnings | 
|  |  | 
|  | def Lint(ast): | 
|  | options = ['wcomment', 'wenum', 'winline', 'wparam', 'wpass', 'wname'] | 
|  | wnone = GetOption('wnone') | 
|  | for opt in options: | 
|  | if wnone or GetOption(opt): ast.SetProperty(opt, True) | 
|  |  | 
|  | skipList = [] | 
|  | for filenode in ast.GetListOf('File'): | 
|  | name = filenode.GetProperty('NAME') | 
|  | if filenode.GetProperty('ERRORS') > 0: | 
|  | ErrOut.Log('%s : Skipped due to errors.' % name) | 
|  | skipList.append(filenode) | 
|  | continue | 
|  | warnings = IDLLinter().Visit(filenode, 0) | 
|  | if warnings: | 
|  | WarnOut.Log('%s warning(s) for %s\n' % (warnings, name)) | 
|  | return skipList |